1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
//! `AUTH`, the one password behind it, and the gate every other command passes.
//!
//! # One password and no users
//!
//! A real server has an ACL system with users, rules and per command
//! permissions, and `requirepass` is a thin layer over it: setting it gives the
//! user called `default` that password, and clearing it puts the `nopass` flag
//! back. There is no ACL here yet, so this file is the other half of that
//! sentence written on its own. There is one password, it belongs to a user
//! called `default`, and any other user name is refused the way a real server
//! refuses a name it has never heard of.
//!
//! That means every message a client can see is the message a real server
//! sends, and the day the ACL arrives this becomes what it already looks like:
//! the default user's password.
//!
//! # Who starts out let in
//!
//! A connection carries a flag saying whether it has authenticated, and the
//! flag is decided when the connection is accepted rather than when it sends
//! its first command. A connection accepted while no password is set is let in
//! at once, because the default user is `nopass` and there is nothing to ask
//! it for, and it stays let in if a password is set later. A connection
//! accepted while a password is set has to send `AUTH` first.
//!
//! That is a real server's rule and it is worth being clear about, because it
//! is not the rule anybody would guess. `CONFIG SET requirepass` does not lock
//! out the clients that are already connected, including the one that just set
//! it, and it does lock out every client that connects after it.
//!
//! `RESET` puts the connection back to how it was accepted, and that includes
//! this: a connection that authenticated and then sent `RESET` has to
//! authenticate again on a server with a password, and does not on a server
//! without one.
//!
//! # Why the compare is written out
//!
//! Comparing two passwords with `==` gives away how much of the guess was right
//! by how long the compare took, and a wrong guess that took longer is a wrong
//! guess that got further. So the compare here looks at every byte of both
//! whatever it finds, and folds the lengths in rather than returning early on
//! them, which is what a real server does with the hashes it keeps.
//!
//! What is not done here is the hashing. A real server keeps a SHA-256 of the
//! password and never the password, and the reason that matters is `ACL
//! GETUSER` and the config file rewrite, neither of which exists yet. It is
//! written down in D-127 rather than half done.
use Mutex;
use AtomicBool;
use ;
use ;
use ;
use ;
use crateOut;
/// The one line a command refused for want of a password is answered with.
///
/// The whole line and not the part after the code, because it goes two places:
/// straight into the reply, and spliced into the `EXECABORT` an `EXEC` gets, and
/// the reference puts the code in both.
pub const NOAUTH: &str = "NOAUTH Authentication required.";
/// The line `HELLO` gets instead, which says what to do about it.
///
/// A client that speaks RESP3 has to send `HELLO` before it can send `AUTH`, or
/// it would be speaking RESP2 by the time it authenticated, so the reference
/// spends a sentence here pointing at the option that solves it.
pub const HELLO_NOAUTH: &str = "NOAUTH HELLO must be called with the client already authenticated, otherwise the HELLO <proto> AUTH <user> <pass> option can be used to authenticate the client and select the RESP protocol version at the same time";
/// The only user there is.
const DEFAULT_USER: & = b"default";
/// The password the default user has, if it has one.
///
/// The flag is separate from the password rather than read out of it because
/// every command on the server asks the question once, and on nearly every
/// server the answer is that there is no password. That is one relaxed load
/// against a word that is already warm, instead of a lock.
pub
/// Whether two byte strings are equal, in time that does not depend on where
/// they stop being equal.
///
/// The loop runs over the longer of the two and folds a byte that is not there
/// in as a difference, so neither the contents nor the length is readable from
/// how long this took. Returning early on the length would give away the length,
/// which on a password is a real thing to give away.
/// Whether this user and password get in, without saying anything to the client.
///
/// Shared by `AUTH` and by `HELLO`'s `AUTH` option, which take the same pair and
/// make the same decision about it. The one thing they do not share is what an
/// unguarded server says to a one argument `AUTH`, which is `AUTH`'s own problem
/// because `HELLO` has no one argument form.
pub
/// `AUTH password` or `AUTH username password`.
pub