Mercurial > dropbear
comparison svr-auth.c @ 33:f789045062e6
Progressing client support
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 27 Jul 2004 16:30:46 +0000 |
parents | 469950e86d0f |
children | 0ad5fb979f42 |
comparison
equal
deleted
inserted
replaced
32:8fd0cdbb5b1b | 33:f789045062e6 |
---|---|
39 static void authclear(); | 39 static void authclear(); |
40 static int checkusername(unsigned char *username, unsigned int userlen); | 40 static int checkusername(unsigned char *username, unsigned int userlen); |
41 static void send_msg_userauth_banner(); | 41 static void send_msg_userauth_banner(); |
42 | 42 |
43 /* initialise the first time for a session, resetting all parameters */ | 43 /* initialise the first time for a session, resetting all parameters */ |
44 void authinitialise() { | 44 void svr_authinitialise() { |
45 | 45 |
46 svr_ses.authstate.failcount = 0; | 46 ses.authstate.failcount = 0; |
47 authclear(); | 47 authclear(); |
48 | 48 |
49 } | 49 } |
50 | 50 |
51 /* Reset the auth state, but don't reset the failcount. This is for if the | 51 /* Reset the auth state, but don't reset the failcount. This is for if the |
52 * user decides to try with a different username etc, and is also invoked | 52 * user decides to try with a different username etc, and is also invoked |
53 * on initialisation */ | 53 * on initialisation */ |
54 static void authclear() { | 54 static void authclear() { |
55 | 55 |
56 ses.authdone = 0; | 56 memset(&ses.authstate, 0, sizeof(ses.authstate)); |
57 svr_ses.authstate.pw = NULL; | |
58 svr_ses.authstate.username = NULL; | |
59 svr_ses.authstate.printableuser = NULL; | |
60 svr_ses.authstate.authtypes = 0; | |
61 #ifdef DROPBEAR_PUBKEY_AUTH | 57 #ifdef DROPBEAR_PUBKEY_AUTH |
62 svr_ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; | 58 ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; |
63 #endif | 59 #endif |
64 #ifdef DROPBEAR_PASSWORD_AUTH | 60 #ifdef DROPBEAR_PASSWORD_AUTH |
65 if (svr_opts.noauthpass) { | 61 if (svr_opts.noauthpass) { |
66 svr_ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; | 62 ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; |
67 } | 63 } |
68 #endif | 64 #endif |
69 | 65 |
70 } | 66 } |
71 | 67 |
101 unsigned int userlen, servicelen, methodlen; | 97 unsigned int userlen, servicelen, methodlen; |
102 | 98 |
103 TRACE(("enter recv_msg_userauth_request")); | 99 TRACE(("enter recv_msg_userauth_request")); |
104 | 100 |
105 /* ignore packets if auth is already done */ | 101 /* ignore packets if auth is already done */ |
106 if (ses.authdone == 1) { | 102 if (ses.authstate.authdone == 1) { |
107 return; | 103 return; |
108 } | 104 } |
109 | 105 |
110 /* send the banner if it exists, it will only exist once */ | 106 /* send the banner if it exists, it will only exist once */ |
111 if (svr_opts.banner) { | 107 if (svr_opts.banner) { |
145 goto out; | 141 goto out; |
146 } | 142 } |
147 | 143 |
148 #ifdef DROPBEAR_PASSWORD_AUTH | 144 #ifdef DROPBEAR_PASSWORD_AUTH |
149 if (!svr_opts.noauthpass && | 145 if (!svr_opts.noauthpass && |
150 !(svr_opts.norootpass && svr_ses.authstate.pw->pw_uid == 0) ) { | 146 !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { |
151 /* user wants to try password auth */ | 147 /* user wants to try password auth */ |
152 if (methodlen == AUTH_METHOD_PASSWORD_LEN && | 148 if (methodlen == AUTH_METHOD_PASSWORD_LEN && |
153 strncmp(methodname, AUTH_METHOD_PASSWORD, | 149 strncmp(methodname, AUTH_METHOD_PASSWORD, |
154 AUTH_METHOD_PASSWORD_LEN) == 0) { | 150 AUTH_METHOD_PASSWORD_LEN) == 0) { |
155 passwordauth(); | 151 svr_auth_password(); |
156 goto out; | 152 goto out; |
157 } | 153 } |
158 } | 154 } |
159 #endif | 155 #endif |
160 | 156 |
161 #ifdef DROPBEAR_PUBKEY_AUTH | 157 #ifdef DROPBEAR_PUBKEY_AUTH |
162 /* user wants to try pubkey auth */ | 158 /* user wants to try pubkey auth */ |
163 if (methodlen == AUTH_METHOD_PUBKEY_LEN && | 159 if (methodlen == AUTH_METHOD_PUBKEY_LEN && |
164 strncmp(methodname, AUTH_METHOD_PUBKEY, | 160 strncmp(methodname, AUTH_METHOD_PUBKEY, |
165 AUTH_METHOD_PUBKEY_LEN) == 0) { | 161 AUTH_METHOD_PUBKEY_LEN) == 0) { |
166 pubkeyauth(); | 162 svr_auth_pubkey(); |
167 goto out; | 163 goto out; |
168 } | 164 } |
169 #endif | 165 #endif |
170 | 166 |
171 /* nothing matched, we just fail */ | 167 /* nothing matched, we just fail */ |
190 if (userlen > MAX_USERNAME_LEN) { | 186 if (userlen > MAX_USERNAME_LEN) { |
191 return DROPBEAR_FAILURE; | 187 return DROPBEAR_FAILURE; |
192 } | 188 } |
193 | 189 |
194 /* new user or username has changed */ | 190 /* new user or username has changed */ |
195 if (svr_ses.authstate.username == NULL || | 191 if (ses.authstate.username == NULL || |
196 strcmp(username, svr_ses.authstate.username) != 0) { | 192 strcmp(username, ses.authstate.username) != 0) { |
197 /* the username needs resetting */ | 193 /* the username needs resetting */ |
198 if (svr_ses.authstate.username != NULL) { | 194 if (ses.authstate.username != NULL) { |
199 dropbear_log(LOG_WARNING, "client trying multiple usernames"); | 195 dropbear_log(LOG_WARNING, "client trying multiple usernames"); |
200 m_free(svr_ses.authstate.username); | 196 m_free(ses.authstate.username); |
201 } | 197 } |
202 authclear(); | 198 authclear(); |
203 svr_ses.authstate.pw = getpwnam((char*)username); | 199 ses.authstate.pw = getpwnam((char*)username); |
204 svr_ses.authstate.username = m_strdup(username); | 200 ses.authstate.username = m_strdup(username); |
205 m_free(svr_ses.authstate.printableuser); | 201 m_free(ses.authstate.printableuser); |
206 } | 202 } |
207 | 203 |
208 /* check that user exists */ | 204 /* check that user exists */ |
209 if (svr_ses.authstate.pw == NULL) { | 205 if (ses.authstate.pw == NULL) { |
210 TRACE(("leave checkusername: user '%s' doesn't exist", username)); | 206 TRACE(("leave checkusername: user '%s' doesn't exist", username)); |
211 dropbear_log(LOG_WARNING, | 207 dropbear_log(LOG_WARNING, |
212 "login attempt for nonexistent user"); | 208 "login attempt for nonexistent user"); |
213 send_msg_userauth_failure(0, 1); | 209 send_msg_userauth_failure(0, 1); |
214 return DROPBEAR_FAILURE; | 210 return DROPBEAR_FAILURE; |
215 } | 211 } |
216 | 212 |
217 /* We can set it once we know its a real user */ | 213 /* We can set it once we know its a real user */ |
218 svr_ses.authstate.printableuser = m_strdup(svr_ses.authstate.pw->pw_name); | 214 ses.authstate.printableuser = m_strdup(ses.authstate.pw->pw_name); |
219 | 215 |
220 /* check for non-root if desired */ | 216 /* check for non-root if desired */ |
221 if (svr_opts.norootlogin && svr_ses.authstate.pw->pw_uid == 0) { | 217 if (svr_opts.norootlogin && ses.authstate.pw->pw_uid == 0) { |
222 TRACE(("leave checkusername: root login disabled")); | 218 TRACE(("leave checkusername: root login disabled")); |
223 dropbear_log(LOG_WARNING, "root login rejected"); | 219 dropbear_log(LOG_WARNING, "root login rejected"); |
224 send_msg_userauth_failure(0, 1); | 220 send_msg_userauth_failure(0, 1); |
225 return DROPBEAR_FAILURE; | 221 return DROPBEAR_FAILURE; |
226 } | 222 } |
227 | 223 |
228 /* check for an empty password */ | 224 /* check for an empty password */ |
229 if (svr_ses.authstate.pw->pw_passwd[0] == '\0') { | 225 if (ses.authstate.pw->pw_passwd[0] == '\0') { |
230 TRACE(("leave checkusername: empty pword")); | 226 TRACE(("leave checkusername: empty pword")); |
231 dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected", | 227 dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected", |
232 svr_ses.authstate.printableuser); | 228 ses.authstate.printableuser); |
233 send_msg_userauth_failure(0, 1); | 229 send_msg_userauth_failure(0, 1); |
234 return DROPBEAR_FAILURE; | 230 return DROPBEAR_FAILURE; |
235 } | 231 } |
236 | 232 |
237 TRACE(("shell is %s", svr_ses.authstate.pw->pw_shell)); | 233 TRACE(("shell is %s", ses.authstate.pw->pw_shell)); |
238 | 234 |
239 /* check that the shell is set */ | 235 /* check that the shell is set */ |
240 usershell = svr_ses.authstate.pw->pw_shell; | 236 usershell = ses.authstate.pw->pw_shell; |
241 if (usershell[0] == '\0') { | 237 if (usershell[0] == '\0') { |
242 /* empty shell in /etc/passwd means /bin/sh according to passwd(5) */ | 238 /* empty shell in /etc/passwd means /bin/sh according to passwd(5) */ |
243 usershell = "/bin/sh"; | 239 usershell = "/bin/sh"; |
244 } | 240 } |
245 | 241 |
256 } | 252 } |
257 /* no matching shell */ | 253 /* no matching shell */ |
258 endusershell(); | 254 endusershell(); |
259 TRACE(("no matching shell")); | 255 TRACE(("no matching shell")); |
260 dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected", | 256 dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected", |
261 svr_ses.authstate.printableuser); | 257 ses.authstate.printableuser); |
262 send_msg_userauth_failure(0, 1); | 258 send_msg_userauth_failure(0, 1); |
263 return DROPBEAR_FAILURE; | 259 return DROPBEAR_FAILURE; |
264 | 260 |
265 goodshell: | 261 goodshell: |
266 endusershell(); | 262 endusershell(); |
267 TRACE(("matching shell")); | 263 TRACE(("matching shell")); |
268 | 264 |
269 TRACE(("uid = %d", svr_ses.authstate.pw->pw_uid)); | 265 TRACE(("uid = %d", ses.authstate.pw->pw_uid)); |
270 TRACE(("leave checkusername")); | 266 TRACE(("leave checkusername")); |
271 return DROPBEAR_SUCCESS; | 267 return DROPBEAR_SUCCESS; |
272 | 268 |
273 } | 269 } |
274 | 270 |
288 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_FAILURE); | 284 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_FAILURE); |
289 | 285 |
290 /* put a list of allowed types */ | 286 /* put a list of allowed types */ |
291 typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */ | 287 typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */ |
292 | 288 |
293 if (svr_ses.authstate.authtypes & AUTH_TYPE_PUBKEY) { | 289 if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) { |
294 buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN); | 290 buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN); |
295 if (svr_ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { | 291 if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { |
296 buf_putbyte(typebuf, ','); | 292 buf_putbyte(typebuf, ','); |
297 } | 293 } |
298 } | 294 } |
299 | 295 |
300 if (svr_ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { | 296 if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { |
301 buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN); | 297 buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN); |
302 } | 298 } |
303 | 299 |
304 buf_setpos(typebuf, 0); | 300 buf_setpos(typebuf, 0); |
305 buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len), | 301 buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len), |
309 buf_putbyte(ses.writepayload, partial ? 1 : 0); | 305 buf_putbyte(ses.writepayload, partial ? 1 : 0); |
310 encrypt_packet(); | 306 encrypt_packet(); |
311 | 307 |
312 if (incrfail) { | 308 if (incrfail) { |
313 usleep(300000); /* XXX improve this */ | 309 usleep(300000); /* XXX improve this */ |
314 svr_ses.authstate.failcount++; | 310 ses.authstate.failcount++; |
315 } | 311 } |
316 | 312 |
317 if (svr_ses.authstate.failcount >= MAX_AUTH_TRIES) { | 313 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { |
318 char * userstr; | 314 char * userstr; |
319 /* XXX - send disconnect ? */ | 315 /* XXX - send disconnect ? */ |
320 TRACE(("Max auth tries reached, exiting")); | 316 TRACE(("Max auth tries reached, exiting")); |
321 | 317 |
322 if (svr_ses.authstate.printableuser == NULL) { | 318 if (ses.authstate.printableuser == NULL) { |
323 userstr = "is invalid"; | 319 userstr = "is invalid"; |
324 } else { | 320 } else { |
325 userstr = svr_ses.authstate.printableuser; | 321 userstr = ses.authstate.printableuser; |
326 } | 322 } |
327 dropbear_exit("Max auth tries reached - user %s", userstr); | 323 dropbear_exit("Max auth tries reached - user %s", userstr); |
328 } | 324 } |
329 | 325 |
330 TRACE(("leave send_msg_userauth_failure")); | 326 TRACE(("leave send_msg_userauth_failure")); |
338 CHECKCLEARTOWRITE(); | 334 CHECKCLEARTOWRITE(); |
339 | 335 |
340 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS); | 336 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS); |
341 encrypt_packet(); | 337 encrypt_packet(); |
342 | 338 |
343 ses.authdone = 1; | 339 ses.authstate.authdone = 1; |
344 | 340 |
345 if (svr_ses.authstate.pw->pw_uid == 0) { | 341 if (ses.authstate.pw->pw_uid == 0) { |
346 ses.allowprivport = 1; | 342 ses.allowprivport = 1; |
347 } | 343 } |
348 | 344 |
349 /* Remove from the list of pre-auth sockets. Should be m_close(), since if | 345 /* Remove from the list of pre-auth sockets. Should be m_close(), since if |
350 * we fail, we might end up leaking connection slots, and disallow new | 346 * we fail, we might end up leaking connection slots, and disallow new |