]>
Commit | Line | Data |
---|---|---|
7368a6c8 | 1 | /* |
2 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | |
3 | * All rights reserved | |
e78a59f5 | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
7368a6c8 | 5 | */ |
6 | ||
7 | #include "includes.h" | |
6ae2364d | 8 | RCSID("$OpenBSD: auth.c,v 1.4 2000/04/14 10:30:29 markus Exp $"); |
7368a6c8 | 9 | |
10 | #include "xmalloc.h" | |
11 | #include "rsa.h" | |
12 | #include "ssh.h" | |
13 | #include "pty.h" | |
14 | #include "packet.h" | |
15 | #include "buffer.h" | |
16 | #include "cipher.h" | |
17 | #include "mpaux.h" | |
18 | #include "servconf.h" | |
e78a59f5 | 19 | #include "compat.h" |
7368a6c8 | 20 | #include "channels.h" |
21 | #include "match.h" | |
22 | ||
e78a59f5 | 23 | #include "bufaux.h" |
24 | #include "ssh2.h" | |
25 | #include "auth.h" | |
7368a6c8 | 26 | #include "session.h" |
27 | #include "dispatch.h" | |
28 | ||
e78a59f5 | 29 | |
7368a6c8 | 30 | /* import */ |
31 | extern ServerOptions options; | |
32 | extern char *forced_command; | |
33 | ||
34 | /* | |
35 | * Check if the user is allowed to log in via ssh. If user is listed in | |
36 | * DenyUsers or user's primary group is listed in DenyGroups, false will | |
37 | * be returned. If AllowUsers isn't empty and user isn't listed there, or | |
38 | * if AllowGroups isn't empty and user isn't listed there, false will be | |
6ae2364d | 39 | * returned. |
7368a6c8 | 40 | * If the user's shell is not executable, false will be returned. |
6ae2364d | 41 | * Otherwise true is returned. |
7368a6c8 | 42 | */ |
43 | static int | |
44 | allowed_user(struct passwd * pw) | |
45 | { | |
46 | struct stat st; | |
47 | struct group *grp; | |
48 | int i; | |
49 | #ifdef WITH_AIXAUTHENTICATE | |
50 | char *loginmsg; | |
51 | #endif /* WITH_AIXAUTHENTICATE */ | |
52 | ||
53 | /* Shouldn't be called if pw is NULL, but better safe than sorry... */ | |
54 | if (!pw) | |
55 | return 0; | |
56 | ||
57 | /* deny if shell does not exists or is not executable */ | |
58 | if (stat(pw->pw_shell, &st) != 0) | |
59 | return 0; | |
60 | if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) | |
61 | return 0; | |
62 | ||
63 | /* Return false if user is listed in DenyUsers */ | |
64 | if (options.num_deny_users > 0) { | |
65 | if (!pw->pw_name) | |
66 | return 0; | |
67 | for (i = 0; i < options.num_deny_users; i++) | |
68 | if (match_pattern(pw->pw_name, options.deny_users[i])) | |
69 | return 0; | |
70 | } | |
71 | /* Return false if AllowUsers isn't empty and user isn't listed there */ | |
72 | if (options.num_allow_users > 0) { | |
73 | if (!pw->pw_name) | |
74 | return 0; | |
75 | for (i = 0; i < options.num_allow_users; i++) | |
76 | if (match_pattern(pw->pw_name, options.allow_users[i])) | |
77 | break; | |
78 | /* i < options.num_allow_users iff we break for loop */ | |
79 | if (i >= options.num_allow_users) | |
80 | return 0; | |
81 | } | |
82 | /* Get the primary group name if we need it. Return false if it fails */ | |
83 | if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { | |
84 | grp = getgrgid(pw->pw_gid); | |
85 | if (!grp) | |
86 | return 0; | |
87 | ||
88 | /* Return false if user's group is listed in DenyGroups */ | |
89 | if (options.num_deny_groups > 0) { | |
90 | if (!grp->gr_name) | |
91 | return 0; | |
92 | for (i = 0; i < options.num_deny_groups; i++) | |
93 | if (match_pattern(grp->gr_name, options.deny_groups[i])) | |
94 | return 0; | |
95 | } | |
96 | /* | |
97 | * Return false if AllowGroups isn't empty and user's group | |
98 | * isn't listed there | |
99 | */ | |
100 | if (options.num_allow_groups > 0) { | |
101 | if (!grp->gr_name) | |
102 | return 0; | |
103 | for (i = 0; i < options.num_allow_groups; i++) | |
104 | if (match_pattern(grp->gr_name, options.allow_groups[i])) | |
105 | break; | |
106 | /* i < options.num_allow_groups iff we break for | |
107 | loop */ | |
108 | if (i >= options.num_allow_groups) | |
109 | return 0; | |
110 | } | |
111 | } | |
112 | ||
113 | #ifdef WITH_AIXAUTHENTICATE | |
114 | if (loginrestrictions(pw->pw_name,S_LOGIN,NULL,&loginmsg) != 0) | |
115 | return 0; | |
116 | #endif /* WITH_AIXAUTHENTICATE */ | |
117 | ||
118 | /* We found no reason not to let this user try to log on... */ | |
119 | return 1; | |
120 | } | |
121 | ||
122 | /* | |
123 | * convert ssh auth msg type into description | |
124 | */ | |
125 | char * | |
126 | get_authname(int type) | |
127 | { | |
128 | static char buf[1024]; | |
129 | switch (type) { | |
130 | case SSH_CMSG_AUTH_PASSWORD: | |
131 | return "password"; | |
132 | case SSH_CMSG_AUTH_RSA: | |
133 | return "rsa"; | |
134 | case SSH_CMSG_AUTH_RHOSTS_RSA: | |
135 | return "rhosts-rsa"; | |
136 | case SSH_CMSG_AUTH_RHOSTS: | |
137 | return "rhosts"; | |
138 | #ifdef KRB4 | |
139 | case SSH_CMSG_AUTH_KERBEROS: | |
140 | return "kerberos"; | |
141 | #endif | |
142 | #ifdef SKEY | |
143 | case SSH_CMSG_AUTH_TIS_RESPONSE: | |
144 | return "s/key"; | |
145 | #endif | |
146 | } | |
147 | snprintf(buf, sizeof buf, "bad-auth-msg-%d", type); | |
148 | return buf; | |
149 | } | |
150 | ||
151 | #define AUTH_FAIL_MAX 6 | |
152 | #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) | |
153 | #define AUTH_FAIL_MSG "Too many authentication failures for %.100s" | |
154 | ||
155 | /* | |
156 | * The user does not exist or access is denied, | |
157 | * but fake indication that authentication is needed. | |
158 | */ | |
159 | void | |
160 | do_fake_authloop1(char *user) | |
161 | { | |
162 | int attempt = 0; | |
163 | ||
164 | log("Faking authloop for illegal user %.200s from %.200s port %d", | |
165 | user, | |
166 | get_remote_ipaddr(), | |
167 | get_remote_port()); | |
168 | ||
169 | #ifdef WITH_AIXAUTHENTICATE | |
170 | if (strncmp(get_authname(type),"password", | |
171 | strlen(get_authname(type))) == 0) | |
172 | loginfailed(pw->pw_name,get_canonical_hostname(),"ssh"); | |
173 | #endif /* WITH_AIXAUTHENTICATE */ | |
174 | ||
175 | /* Indicate that authentication is needed. */ | |
176 | packet_start(SSH_SMSG_FAILURE); | |
177 | packet_send(); | |
178 | packet_write_wait(); | |
179 | ||
180 | /* | |
181 | * Keep reading packets, and always respond with a failure. This is | |
182 | * to avoid disclosing whether such a user really exists. | |
183 | */ | |
184 | for (attempt = 1;; attempt++) { | |
185 | /* Read a packet. This will not return if the client disconnects. */ | |
186 | int plen; | |
187 | #ifndef SKEY | |
188 | (void)packet_read(&plen); | |
189 | #else /* SKEY */ | |
190 | int type = packet_read(&plen); | |
191 | unsigned int dlen; | |
192 | char *password, *skeyinfo; | |
193 | /* Try to send a fake s/key challenge. */ | |
194 | if (options.skey_authentication == 1 && | |
195 | (skeyinfo = skey_fake_keyinfo(user)) != NULL) { | |
196 | password = NULL; | |
197 | if (type == SSH_CMSG_AUTH_TIS) { | |
198 | packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); | |
199 | packet_put_string(skeyinfo, strlen(skeyinfo)); | |
200 | packet_send(); | |
201 | packet_write_wait(); | |
202 | continue; | |
203 | } else if (type == SSH_CMSG_AUTH_PASSWORD && | |
6ae2364d | 204 | options.password_authentication && |
205 | (password = packet_get_string(&dlen)) != NULL && | |
206 | dlen == 5 && | |
207 | strncasecmp(password, "s/key", 5) == 0 ) { | |
7368a6c8 | 208 | packet_send_debug(skeyinfo); |
209 | } | |
210 | if (password != NULL) | |
211 | xfree(password); | |
212 | } | |
213 | #endif | |
214 | if (attempt > AUTH_FAIL_MAX) | |
215 | packet_disconnect(AUTH_FAIL_MSG, user); | |
216 | ||
217 | /* | |
218 | * Send failure. This should be indistinguishable from a | |
219 | * failed authentication. | |
220 | */ | |
221 | packet_start(SSH_SMSG_FAILURE); | |
222 | packet_send(); | |
223 | packet_write_wait(); | |
224 | } | |
225 | /* NOTREACHED */ | |
226 | abort(); | |
227 | } | |
228 | ||
229 | /* | |
230 | * read packets and try to authenticate local user *pw. | |
231 | * return if authentication is successfull | |
232 | */ | |
233 | void | |
234 | do_authloop(struct passwd * pw) | |
235 | { | |
236 | int attempt = 0; | |
237 | unsigned int bits; | |
238 | RSA *client_host_key; | |
239 | BIGNUM *n; | |
240 | char *client_user = NULL, *password = NULL; | |
241 | char user[1024]; | |
242 | unsigned int dlen; | |
243 | int plen, nlen, elen; | |
244 | unsigned int ulen; | |
245 | int type = 0; | |
246 | void (*authlog) (const char *fmt,...) = verbose; | |
247 | ||
248 | /* Indicate that authentication is needed. */ | |
249 | packet_start(SSH_SMSG_FAILURE); | |
250 | packet_send(); | |
251 | packet_write_wait(); | |
252 | ||
253 | for (attempt = 1;; attempt++) { | |
254 | int authenticated = 0; | |
255 | strlcpy(user, "", sizeof user); | |
256 | ||
257 | /* Get a packet from the client. */ | |
258 | type = packet_read(&plen); | |
259 | ||
260 | /* Process the packet. */ | |
261 | switch (type) { | |
262 | #ifdef AFS | |
263 | case SSH_CMSG_HAVE_KERBEROS_TGT: | |
264 | if (!options.kerberos_tgt_passing) { | |
265 | /* packet_get_all(); */ | |
266 | verbose("Kerberos tgt passing disabled."); | |
267 | break; | |
268 | } else { | |
269 | /* Accept Kerberos tgt. */ | |
270 | char *tgt = packet_get_string(&dlen); | |
271 | packet_integrity_check(plen, 4 + dlen, type); | |
272 | if (!auth_kerberos_tgt(pw, tgt)) | |
273 | verbose("Kerberos tgt REFUSED for %s", pw->pw_name); | |
274 | xfree(tgt); | |
275 | } | |
276 | continue; | |
277 | ||
278 | case SSH_CMSG_HAVE_AFS_TOKEN: | |
279 | if (!options.afs_token_passing || !k_hasafs()) { | |
280 | /* packet_get_all(); */ | |
281 | verbose("AFS token passing disabled."); | |
282 | break; | |
283 | } else { | |
284 | /* Accept AFS token. */ | |
285 | char *token_string = packet_get_string(&dlen); | |
286 | packet_integrity_check(plen, 4 + dlen, type); | |
287 | if (!auth_afs_token(pw, token_string)) | |
288 | verbose("AFS token REFUSED for %s", pw->pw_name); | |
289 | xfree(token_string); | |
290 | } | |
291 | continue; | |
292 | #endif /* AFS */ | |
293 | #ifdef KRB4 | |
294 | case SSH_CMSG_AUTH_KERBEROS: | |
295 | if (!options.kerberos_authentication) { | |
296 | /* packet_get_all(); */ | |
297 | verbose("Kerberos authentication disabled."); | |
298 | break; | |
299 | } else { | |
300 | /* Try Kerberos v4 authentication. */ | |
301 | KTEXT_ST auth; | |
302 | char *tkt_user = NULL; | |
303 | char *kdata = packet_get_string((unsigned int *) &auth.length); | |
304 | packet_integrity_check(plen, 4 + auth.length, type); | |
305 | ||
306 | if (auth.length < MAX_KTXT_LEN) | |
307 | memcpy(auth.dat, kdata, auth.length); | |
308 | xfree(kdata); | |
309 | ||
310 | authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user); | |
311 | ||
312 | if (authenticated) { | |
313 | snprintf(user, sizeof user, " tktuser %s", tkt_user); | |
314 | xfree(tkt_user); | |
315 | } | |
316 | } | |
317 | break; | |
318 | #endif /* KRB4 */ | |
319 | ||
320 | case SSH_CMSG_AUTH_RHOSTS: | |
321 | if (!options.rhosts_authentication) { | |
322 | verbose("Rhosts authentication disabled."); | |
323 | break; | |
324 | } | |
325 | /* | |
326 | * Get client user name. Note that we just have to | |
327 | * trust the client; this is one reason why rhosts | |
328 | * authentication is insecure. (Another is | |
329 | * IP-spoofing on a local network.) | |
330 | */ | |
331 | client_user = packet_get_string(&ulen); | |
332 | packet_integrity_check(plen, 4 + ulen, type); | |
333 | ||
334 | /* Try to authenticate using /etc/hosts.equiv and | |
335 | .rhosts. */ | |
336 | authenticated = auth_rhosts(pw, client_user); | |
337 | ||
338 | snprintf(user, sizeof user, " ruser %s", client_user); | |
339 | break; | |
340 | ||
341 | case SSH_CMSG_AUTH_RHOSTS_RSA: | |
342 | if (!options.rhosts_rsa_authentication) { | |
343 | verbose("Rhosts with RSA authentication disabled."); | |
344 | break; | |
345 | } | |
346 | /* | |
347 | * Get client user name. Note that we just have to | |
348 | * trust the client; root on the client machine can | |
349 | * claim to be any user. | |
350 | */ | |
351 | client_user = packet_get_string(&ulen); | |
352 | ||
353 | /* Get the client host key. */ | |
354 | client_host_key = RSA_new(); | |
355 | if (client_host_key == NULL) | |
356 | fatal("RSA_new failed"); | |
357 | client_host_key->e = BN_new(); | |
358 | client_host_key->n = BN_new(); | |
359 | if (client_host_key->e == NULL || client_host_key->n == NULL) | |
360 | fatal("BN_new failed"); | |
361 | bits = packet_get_int(); | |
362 | packet_get_bignum(client_host_key->e, &elen); | |
363 | packet_get_bignum(client_host_key->n, &nlen); | |
364 | ||
365 | if (bits != BN_num_bits(client_host_key->n)) | |
366 | error("Warning: keysize mismatch for client_host_key: " | |
367 | "actual %d, announced %d", BN_num_bits(client_host_key->n), bits); | |
368 | packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type); | |
369 | ||
370 | authenticated = auth_rhosts_rsa(pw, client_user, client_host_key); | |
371 | RSA_free(client_host_key); | |
372 | ||
373 | snprintf(user, sizeof user, " ruser %s", client_user); | |
374 | break; | |
375 | ||
376 | case SSH_CMSG_AUTH_RSA: | |
377 | if (!options.rsa_authentication) { | |
378 | verbose("RSA authentication disabled."); | |
379 | break; | |
380 | } | |
381 | /* RSA authentication requested. */ | |
382 | n = BN_new(); | |
383 | packet_get_bignum(n, &nlen); | |
384 | packet_integrity_check(plen, nlen, type); | |
385 | authenticated = auth_rsa(pw, n); | |
386 | BN_clear_free(n); | |
387 | break; | |
388 | ||
389 | case SSH_CMSG_AUTH_PASSWORD: | |
390 | if (!options.password_authentication) { | |
391 | verbose("Password authentication disabled."); | |
392 | break; | |
393 | } | |
394 | /* | |
395 | * Read user password. It is in plain text, but was | |
396 | * transmitted over the encrypted channel so it is | |
397 | * not visible to an outside observer. | |
398 | */ | |
399 | password = packet_get_string(&dlen); | |
400 | packet_integrity_check(plen, 4 + dlen, type); | |
401 | ||
402 | #ifdef USE_PAM | |
403 | /* Do PAM auth with password */ | |
404 | authenticated = auth_pam_password(pw, password); | |
405 | #else /* USE_PAM */ | |
406 | /* Try authentication with the password. */ | |
407 | authenticated = auth_password(pw, password); | |
408 | #endif /* USE_PAM */ | |
409 | memset(password, 0, strlen(password)); | |
410 | xfree(password); | |
411 | break; | |
412 | ||
413 | #ifdef SKEY | |
414 | case SSH_CMSG_AUTH_TIS: | |
415 | debug("rcvd SSH_CMSG_AUTH_TIS"); | |
416 | if (options.skey_authentication == 1) { | |
417 | char *skeyinfo = skey_keyinfo(pw->pw_name); | |
418 | if (skeyinfo == NULL) { | |
419 | debug("generating fake skeyinfo for %.100s.", pw->pw_name); | |
420 | skeyinfo = skey_fake_keyinfo(pw->pw_name); | |
421 | } | |
422 | if (skeyinfo != NULL) { | |
423 | /* we send our s/key- in tis-challenge messages */ | |
424 | debug("sending challenge '%s'", skeyinfo); | |
425 | packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); | |
426 | packet_put_string(skeyinfo, strlen(skeyinfo)); | |
427 | packet_send(); | |
428 | packet_write_wait(); | |
429 | continue; | |
430 | } | |
431 | } | |
432 | break; | |
433 | case SSH_CMSG_AUTH_TIS_RESPONSE: | |
434 | debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE"); | |
435 | if (options.skey_authentication == 1) { | |
436 | char *response = packet_get_string(&dlen); | |
437 | debug("skey response == '%s'", response); | |
438 | packet_integrity_check(plen, 4 + dlen, type); | |
439 | authenticated = (skey_haskey(pw->pw_name) == 0 && | |
440 | skey_passcheck(pw->pw_name, response) != -1); | |
441 | xfree(response); | |
442 | } | |
443 | break; | |
444 | #else | |
445 | case SSH_CMSG_AUTH_TIS: | |
446 | /* TIS Authentication is unsupported */ | |
447 | log("TIS authentication unsupported."); | |
448 | break; | |
449 | #endif | |
450 | ||
451 | default: | |
452 | /* | |
453 | * Any unknown messages will be ignored (and failure | |
454 | * returned) during authentication. | |
455 | */ | |
456 | log("Unknown message during authentication: type %d", type); | |
457 | break; | |
458 | } | |
459 | ||
6ae2364d | 460 | /* |
461 | * Check if the user is logging in as root and root logins | |
462 | * are disallowed. | |
463 | * Note that root login is allowed for forced commands. | |
464 | */ | |
465 | if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) { | |
466 | if (forced_command) { | |
467 | log("Root login accepted for forced command."); | |
468 | } else { | |
469 | authenticated = 0; | |
470 | log("ROOT LOGIN REFUSED FROM %.200s", | |
471 | get_canonical_hostname()); | |
472 | } | |
473 | } | |
7368a6c8 | 474 | |
475 | /* Raise logging level */ | |
476 | if (authenticated || | |
477 | attempt == AUTH_FAIL_LOG || | |
478 | type == SSH_CMSG_AUTH_PASSWORD) | |
479 | authlog = log; | |
480 | ||
481 | authlog("%s %s for %.200s from %.200s port %d%s", | |
482 | authenticated ? "Accepted" : "Failed", | |
483 | get_authname(type), | |
484 | pw->pw_uid == 0 ? "ROOT" : pw->pw_name, | |
485 | get_remote_ipaddr(), | |
486 | get_remote_port(), | |
487 | user); | |
488 | ||
489 | #ifdef USE_PAM | |
490 | if (authenticated) { | |
491 | if (!do_pam_account(pw->pw_name, client_user)) { | |
492 | if (client_user != NULL) { | |
493 | xfree(client_user); | |
494 | client_user = NULL; | |
495 | } | |
496 | do_fake_authloop1(pw->pw_name); | |
497 | } | |
498 | return; | |
499 | } | |
500 | #else /* USE_PAM */ | |
501 | if (authenticated) { | |
502 | return; | |
503 | } | |
504 | #endif /* USE_PAM */ | |
505 | ||
506 | if (client_user != NULL) { | |
507 | xfree(client_user); | |
508 | client_user = NULL; | |
509 | } | |
510 | ||
511 | if (attempt > AUTH_FAIL_MAX) | |
512 | packet_disconnect(AUTH_FAIL_MSG, pw->pw_name); | |
513 | ||
514 | /* Send a message indicating that the authentication attempt failed. */ | |
515 | packet_start(SSH_SMSG_FAILURE); | |
516 | packet_send(); | |
517 | packet_write_wait(); | |
518 | } | |
519 | } | |
520 | ||
521 | /* | |
522 | * Performs authentication of an incoming connection. Session key has already | |
523 | * been exchanged and encryption is enabled. | |
524 | */ | |
525 | void | |
526 | do_authentication() | |
527 | { | |
528 | struct passwd *pw, pwcopy; | |
529 | int plen; | |
530 | unsigned int ulen; | |
531 | char *user; | |
532 | #ifdef WITH_AIXAUTHENTICATE | |
533 | char *loginmsg; | |
534 | #endif /* WITH_AIXAUTHENTICATE */ | |
535 | ||
536 | /* Get the name of the user that we wish to log in as. */ | |
537 | packet_read_expect(&plen, SSH_CMSG_USER); | |
538 | ||
539 | /* Get the user name. */ | |
540 | user = packet_get_string(&ulen); | |
541 | packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); | |
542 | ||
543 | setproctitle("%s", user); | |
544 | ||
545 | #ifdef AFS | |
546 | /* If machine has AFS, set process authentication group. */ | |
547 | if (k_hasafs()) { | |
548 | k_setpag(); | |
549 | k_unlog(); | |
550 | } | |
551 | #endif /* AFS */ | |
552 | ||
553 | /* Verify that the user is a valid user. */ | |
554 | pw = getpwnam(user); | |
555 | if (!pw || !allowed_user(pw)) | |
556 | do_fake_authloop1(user); | |
557 | xfree(user); | |
558 | ||
559 | /* Take a copy of the returned structure. */ | |
560 | memset(&pwcopy, 0, sizeof(pwcopy)); | |
561 | pwcopy.pw_name = xstrdup(pw->pw_name); | |
562 | pwcopy.pw_passwd = xstrdup(pw->pw_passwd); | |
563 | pwcopy.pw_uid = pw->pw_uid; | |
564 | pwcopy.pw_gid = pw->pw_gid; | |
565 | pwcopy.pw_dir = xstrdup(pw->pw_dir); | |
566 | pwcopy.pw_shell = xstrdup(pw->pw_shell); | |
567 | pw = &pwcopy; | |
568 | ||
569 | #ifdef USE_PAM | |
570 | start_pam(pw); | |
571 | #endif | |
572 | ||
573 | /* | |
574 | * If we are not running as root, the user must have the same uid as | |
575 | * the server. | |
576 | */ | |
577 | if (getuid() != 0 && pw->pw_uid != getuid()) | |
578 | packet_disconnect("Cannot change user when server not running as root."); | |
579 | ||
580 | debug("Attempting authentication for %.100s.", pw->pw_name); | |
581 | ||
582 | /* If the user has no password, accept authentication immediately. */ | |
583 | if (options.password_authentication && | |
584 | #ifdef KRB4 | |
585 | (!options.kerberos_authentication || options.kerberos_or_local_passwd) && | |
586 | #endif /* KRB4 */ | |
587 | #ifdef USE_PAM | |
588 | auth_pam_password(pw, "")) { | |
589 | #else /* USE_PAM */ | |
590 | auth_password(pw, "")) { | |
591 | #endif /* USE_PAM */ | |
592 | /* Authentication with empty password succeeded. */ | |
593 | log("Login for user %s from %.100s, accepted without authentication.", | |
594 | pw->pw_name, get_remote_ipaddr()); | |
595 | } else { | |
596 | /* Loop until the user has been authenticated or the | |
597 | connection is closed, do_authloop() returns only if | |
598 | authentication is successfull */ | |
599 | do_authloop(pw); | |
600 | } | |
601 | ||
602 | /* The user has been authenticated and accepted. */ | |
603 | #ifdef WITH_AIXAUTHENTICATE | |
604 | loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg); | |
605 | #endif /* WITH_AIXAUTHENTICATE */ | |
606 | packet_start(SSH_SMSG_SUCCESS); | |
607 | packet_send(); | |
608 | packet_write_wait(); | |
609 | ||
610 | /* Perform session preparation. */ | |
611 | do_authenticated(pw); | |
612 | } | |
e78a59f5 | 613 | |
614 | ||
615 | void input_service_request(int type, int plen); | |
616 | void input_userauth_request(int type, int plen); | |
617 | void ssh2_pty_cleanup(void); | |
618 | ||
619 | typedef struct Authctxt Authctxt; | |
620 | struct Authctxt { | |
621 | char *user; | |
622 | char *service; | |
623 | struct passwd pw; | |
624 | int valid; | |
625 | }; | |
626 | static Authctxt *authctxt = NULL; | |
627 | static int userauth_success = 0; | |
628 | ||
629 | struct passwd* | |
630 | auth_get_user(void) | |
631 | { | |
632 | return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL; | |
633 | } | |
634 | struct passwd* | |
635 | auth_set_user(char *u, char *s) | |
636 | { | |
637 | struct passwd *pw, *copy; | |
638 | ||
639 | if (authctxt == NULL) { | |
640 | authctxt = xmalloc(sizeof(*authctxt)); | |
641 | authctxt->valid = 0; | |
642 | authctxt->user = xstrdup(u); | |
643 | authctxt->service = xstrdup(s); | |
644 | setproctitle("%s", u); | |
645 | pw = getpwnam(u); | |
646 | if (!pw || !allowed_user(pw)) { | |
647 | log("auth_set_user: bad user %s", u); | |
648 | return NULL; | |
649 | } | |
650 | #ifdef USE_PAM | |
651 | start_pam(pw); | |
652 | #endif | |
653 | copy = &authctxt->pw; | |
654 | memset(copy, 0, sizeof(*copy)); | |
655 | copy->pw_name = xstrdup(pw->pw_name); | |
656 | copy->pw_passwd = xstrdup(pw->pw_passwd); | |
657 | copy->pw_uid = pw->pw_uid; | |
658 | copy->pw_gid = pw->pw_gid; | |
659 | copy->pw_dir = xstrdup(pw->pw_dir); | |
660 | copy->pw_shell = xstrdup(pw->pw_shell); | |
661 | authctxt->valid = 1; | |
662 | } else { | |
663 | if (strcmp(u, authctxt->user) != 0 || | |
664 | strcmp(s, authctxt->service) != 0) { | |
665 | log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)", | |
666 | u, s, authctxt->user, authctxt->service); | |
667 | return NULL; | |
668 | } | |
669 | } | |
670 | return auth_get_user(); | |
671 | } | |
672 | ||
673 | static void | |
674 | protocol_error(int type, int plen) | |
675 | { | |
676 | log("auth: protocol error: type %d plen %d", type, plen); | |
677 | packet_start(SSH2_MSG_UNIMPLEMENTED); | |
678 | packet_put_int(0); | |
679 | packet_send(); | |
680 | packet_write_wait(); | |
681 | } | |
682 | void | |
683 | input_service_request(int type, int plen) | |
684 | { | |
685 | unsigned int len; | |
686 | int accept = 0; | |
687 | char *service = packet_get_string(&len); | |
6ae2364d | 688 | packet_done(); |
e78a59f5 | 689 | |
690 | if (strcmp(service, "ssh-userauth") == 0) { | |
691 | if (!userauth_success) { | |
692 | accept = 1; | |
693 | /* now we can handle user-auth requests */ | |
694 | dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); | |
695 | } | |
696 | } | |
697 | /* XXX all other service requests are denied */ | |
698 | ||
699 | if (accept) { | |
700 | packet_start(SSH2_MSG_SERVICE_ACCEPT); | |
701 | packet_put_cstring(service); | |
702 | packet_send(); | |
703 | packet_write_wait(); | |
704 | } else { | |
705 | debug("bad service request %s", service); | |
706 | packet_disconnect("bad service request %s", service); | |
707 | } | |
708 | xfree(service); | |
709 | } | |
710 | void | |
711 | input_userauth_request(int type, int plen) | |
712 | { | |
713 | static int try = 0; | |
714 | unsigned int len; | |
715 | int c, authenticated = 0; | |
716 | char *user, *service, *method; | |
717 | struct passwd *pw; | |
718 | ||
719 | if (++try == AUTH_FAIL_MAX) | |
720 | packet_disconnect("too many failed userauth_requests"); | |
721 | ||
722 | user = packet_get_string(&len); | |
723 | service = packet_get_string(&len); | |
724 | method = packet_get_string(&len); | |
725 | debug("userauth-request for user %s service %s method %s", user, service, method); | |
726 | ||
727 | /* XXX we only allow the ssh-connection service */ | |
728 | pw = auth_set_user(user, service); | |
729 | if (pw && strcmp(service, "ssh-connection")==0) { | |
730 | if (strcmp(method, "none") == 0 && try == 1) { | |
6ae2364d | 731 | packet_done(); |
e78a59f5 | 732 | #ifdef USE_PAM |
733 | /* Do PAM auth with password */ | |
734 | authenticated = auth_pam_password(pw, ""); | |
735 | #else /* USE_PAM */ | |
736 | /* Try authentication with the password. */ | |
737 | authenticated = auth_password(pw, ""); | |
738 | #endif /* USE_PAM */ | |
739 | } else if (strcmp(method, "password") == 0) { | |
740 | char *password; | |
741 | c = packet_get_char(); | |
742 | if (c) | |
743 | debug("password change not supported"); | |
744 | password = packet_get_string(&len); | |
6ae2364d | 745 | packet_done(); |
e78a59f5 | 746 | #ifdef USE_PAM |
747 | /* Do PAM auth with password */ | |
748 | authenticated = auth_pam_password(pw, password); | |
749 | #else /* USE_PAM */ | |
750 | /* Try authentication with the password. */ | |
751 | authenticated = auth_password(pw, password); | |
752 | #endif /* USE_PAM */ | |
753 | memset(password, 0, len); | |
754 | xfree(password); | |
755 | } else if (strcmp(method, "publickey") == 0) { | |
756 | /* XXX TODO */ | |
6ae2364d | 757 | char *pkalg, *pkblob, *sig; |
758 | int have_sig = packet_get_char(); | |
e78a59f5 | 759 | pkalg = packet_get_string(&len); |
760 | pkblob = packet_get_string(&len); | |
6ae2364d | 761 | if (have_sig) { |
762 | sig = packet_get_string(&len); | |
763 | /* test for correct signature */ | |
764 | packet_done(); | |
765 | xfree(sig); | |
766 | } else { | |
767 | packet_done(); | |
768 | /* test whether pkalg/pkblob are acceptable */ | |
769 | } | |
e78a59f5 | 770 | xfree(pkalg); |
771 | xfree(pkblob); | |
772 | } | |
773 | } | |
774 | /* XXX check if other auth methods are needed */ | |
775 | if (authenticated) { | |
776 | /* turn off userauth */ | |
777 | dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error); | |
e78a59f5 | 778 | packet_start(SSH2_MSG_USERAUTH_SUCCESS); |
779 | packet_send(); | |
780 | packet_write_wait(); | |
781 | log("userauth success for %s", user); | |
782 | /* now we can break out */ | |
783 | userauth_success = 1; | |
784 | } else { | |
785 | packet_start(SSH2_MSG_USERAUTH_FAILURE); | |
786 | packet_put_cstring("password"); | |
787 | packet_put_char(0); /* partial success */ | |
788 | packet_send(); | |
789 | packet_write_wait(); | |
790 | } | |
791 | xfree(service); | |
792 | xfree(user); | |
793 | xfree(method); | |
794 | } | |
6ae2364d | 795 | void |
e78a59f5 | 796 | do_authentication2() |
797 | { | |
798 | dispatch_init(&protocol_error); | |
799 | dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); | |
800 | dispatch_run(DISPATCH_BLOCK, &userauth_success); | |
801 | do_authenticated2(); | |
802 | } |