]> andersk Git - openssh.git/blame - auth2.c
- (djm) Use a real struct sockaddr inside the fake struct sockaddr_storage.
[openssh.git] / auth2.c
CommitLineData
a306f2dd 1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
a306f2dd 12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
bcbf86ec 24
a306f2dd 25#include "includes.h"
bcbf86ec 26RCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $");
a306f2dd 27
28#include <openssl/dsa.h>
29#include <openssl/rsa.h>
30#include <openssl/evp.h>
31
32#include "xmalloc.h"
33#include "rsa.h"
34#include "ssh.h"
35#include "pty.h"
36#include "packet.h"
37#include "buffer.h"
38#include "cipher.h"
39#include "servconf.h"
40#include "compat.h"
41#include "channels.h"
42#include "bufaux.h"
43#include "ssh2.h"
44#include "auth.h"
45#include "session.h"
46#include "dispatch.h"
47#include "auth.h"
48#include "key.h"
49#include "kex.h"
50
51#include "dsa.h"
52#include "uidswap.h"
38c295d6 53#include "auth-options.h"
a306f2dd 54
4d33e531 55#ifdef HAVE_OSF_SIA
56# include <sia.h>
57# include <siad.h>
58#endif
59
a306f2dd 60/* import */
61extern ServerOptions options;
62extern unsigned char *session_id2;
63extern int session_id2_len;
64
65/* protocol */
66
67void input_service_request(int type, int plen);
68void input_userauth_request(int type, int plen);
69void protocol_error(int type, int plen);
70
71/* auth */
72int ssh2_auth_none(struct passwd *pw);
73int ssh2_auth_password(struct passwd *pw);
38c295d6 74int ssh2_auth_pubkey(struct passwd *pw, char *service);
a306f2dd 75
76/* helper */
77struct passwd* auth_set_user(char *u, char *s);
78int user_dsa_key_allowed(struct passwd *pw, Key *key);
79
80typedef struct Authctxt Authctxt;
81struct Authctxt {
82 char *user;
83 char *service;
84 struct passwd pw;
85 int valid;
86};
87static Authctxt *authctxt = NULL;
88static int userauth_success = 0;
89
90/*
91 * loop until userauth_success == TRUE
92 */
93
94void
95do_authentication2()
96{
3189621b 97 /* turn off skey/kerberos, not supported by SSH2 */
8cb940db 98#ifdef SKEY
3189621b 99 options.skey_authentication = 0;
8cb940db 100#endif
101#ifdef KRB4
3189621b 102 options.kerberos_authentication = 0;
8cb940db 103#endif
3189621b 104
a306f2dd 105 dispatch_init(&protocol_error);
106 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
107 dispatch_run(DISPATCH_BLOCK, &userauth_success);
108 do_authenticated2();
109}
110
111void
112protocol_error(int type, int plen)
113{
114 log("auth: protocol error: type %d plen %d", type, plen);
115 packet_start(SSH2_MSG_UNIMPLEMENTED);
116 packet_put_int(0);
117 packet_send();
118 packet_write_wait();
119}
120
121void
122input_service_request(int type, int plen)
123{
124 unsigned int len;
125 int accept = 0;
126 char *service = packet_get_string(&len);
127 packet_done();
128
129 if (strcmp(service, "ssh-userauth") == 0) {
130 if (!userauth_success) {
131 accept = 1;
132 /* now we can handle user-auth requests */
133 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
134 }
135 }
136 /* XXX all other service requests are denied */
137
138 if (accept) {
139 packet_start(SSH2_MSG_SERVICE_ACCEPT);
140 packet_put_cstring(service);
141 packet_send();
142 packet_write_wait();
143 } else {
144 debug("bad service request %s", service);
145 packet_disconnect("bad service request %s", service);
146 }
147 xfree(service);
148}
149
150void
151input_userauth_request(int type, int plen)
152{
153 static void (*authlog) (const char *fmt,...) = verbose;
154 static int attempt = 0;
38c295d6 155 unsigned int len;
a306f2dd 156 int authenticated = 0;
38c295d6 157 char *user, *service, *method, *authmsg = NULL;
a306f2dd 158 struct passwd *pw;
c1ef8333 159#ifdef WITH_AIXAUTHENTICATE
160 extern char *aixloginmsg;
161#endif /* WITH_AIXAUTHENTICATE */
a306f2dd 162
a306f2dd 163 user = packet_get_string(&len);
164 service = packet_get_string(&len);
165 method = packet_get_string(&len);
c1ef8333 166 if (++attempt == AUTH_FAIL_MAX) {
167#ifdef WITH_AIXAUTHENTICATE
168 loginfailed(user,get_canonical_hostname(),"ssh");
169#endif /* WITH_AIXAUTHENTICATE */
170 packet_disconnect("too many failed userauth_requests");
171 }
a306f2dd 172 debug("userauth-request for user %s service %s method %s", user, service, method);
173
174 /* XXX we only allow the ssh-connection service */
175 pw = auth_set_user(user, service);
176 if (pw && strcmp(service, "ssh-connection")==0) {
177 if (strcmp(method, "none") == 0) {
178 authenticated = ssh2_auth_none(pw);
179 } else if (strcmp(method, "password") == 0) {
180 authenticated = ssh2_auth_password(pw);
181 } else if (strcmp(method, "publickey") == 0) {
38c295d6 182 authenticated = ssh2_auth_pubkey(pw, service);
a306f2dd 183 }
184 }
185 if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
186 authenticated = 0;
187 log("ROOT LOGIN REFUSED FROM %.200s",
188 get_canonical_hostname());
189 }
190
191#ifdef USE_PAM
192 if (authenticated && !do_pam_account(pw->pw_name, NULL))
193 authenticated = 0;
194#endif /* USE_PAM */
195
1d1ffb87 196 /* Raise logging level */
197 if (authenticated == 1 ||
198 attempt == AUTH_FAIL_LOG ||
199 strcmp(method, "password") == 0)
200 authlog = log;
201
202 /* Log before sending the reply */
a306f2dd 203 if (authenticated == 1) {
204 authmsg = "Accepted";
1d1ffb87 205 } else if (authenticated == 0) {
206 authmsg = "Failed";
207 } else {
208 authmsg = "Postponed";
209 }
210 authlog("%s %s for %.200s from %.200s port %d ssh2",
211 authmsg,
212 method,
213 pw && pw->pw_uid == 0 ? "ROOT" : user,
214 get_remote_ipaddr(),
215 get_remote_port());
216
217 /* XXX todo: check if multiple auth methods are needed */
218 if (authenticated == 1) {
c1ef8333 219#ifdef WITH_AIXAUTHENTICATE
220 /* We don't have a pty yet, so just label the line as "ssh" */
221 if (loginsuccess(user,get_canonical_hostname(),"ssh",
222 &aixloginmsg) < 0)
223 aixloginmsg = NULL;
224#endif /* WITH_AIXAUTHENTICATE */
a306f2dd 225 /* turn off userauth */
226 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
227 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
228 packet_send();
229 packet_write_wait();
230 /* now we can break out */
231 userauth_success = 1;
232 } else if (authenticated == 0) {
a306f2dd 233 packet_start(SSH2_MSG_USERAUTH_FAILURE);
234 packet_put_cstring("publickey,password"); /* XXX dynamic */
235 packet_put_char(0); /* XXX partial success, unused */
236 packet_send();
237 packet_write_wait();
a306f2dd 238 }
a306f2dd 239
240 xfree(service);
241 xfree(user);
242 xfree(method);
243}
244
245int
246ssh2_auth_none(struct passwd *pw)
247{
4d33e531 248#ifdef HAVE_OSF_SIA
249 extern int saved_argc;
250 extern char **saved_argv;
251#endif
252
a306f2dd 253 packet_done();
4d33e531 254
a306f2dd 255#ifdef USE_PAM
256 return auth_pam_password(pw, "");
4d33e531 257#elif defined(HAVE_OSF_SIA)
258 return(sia_validate_user(NULL, saved_argc, saved_argv,
259 get_canonical_hostname(), pw->pw_name, NULL, 0, NULL,
260 "") == SIASUCCESS);
261#else /* !HAVE_OSF_SIA && !USE_PAM */
a306f2dd 262 return auth_password(pw, "");
263#endif /* USE_PAM */
264}
265int
266ssh2_auth_password(struct passwd *pw)
267{
268 char *password;
269 int authenticated = 0;
270 int change;
271 unsigned int len;
4d33e531 272#ifdef HAVE_OSF_SIA
273 extern int saved_argc;
274 extern char **saved_argv;
275#endif
a306f2dd 276 change = packet_get_char();
277 if (change)
278 log("password change not supported");
279 password = packet_get_string(&len);
280 packet_done();
281 if (options.password_authentication &&
282#ifdef USE_PAM
283 auth_pam_password(pw, password) == 1)
4d33e531 284#elif defined(HAVE_OSF_SIA)
285 sia_validate_user(NULL, saved_argc, saved_argv,
286 get_canonical_hostname(), pw->pw_name, NULL, 0,
287 NULL, password) == SIASUCCESS)
288#else /* !USE_PAM && !HAVE_OSF_SIA */
a306f2dd 289 auth_password(pw, password) == 1)
290#endif /* USE_PAM */
291 authenticated = 1;
292 memset(password, 0, len);
293 xfree(password);
294 return authenticated;
295}
296int
38c295d6 297ssh2_auth_pubkey(struct passwd *pw, char *service)
a306f2dd 298{
299 Buffer b;
300 Key *key;
301 char *pkalg, *pkblob, *sig;
302 unsigned int alen, blen, slen;
303 int have_sig;
304 int authenticated = 0;
305
1d1ffb87 306 if (options.dsa_authentication == 0) {
a306f2dd 307 debug("pubkey auth disabled");
308 return 0;
309 }
310 have_sig = packet_get_char();
311 pkalg = packet_get_string(&alen);
312 if (strcmp(pkalg, KEX_DSS) != 0) {
313 xfree(pkalg);
314 log("bad pkalg %s", pkalg); /*XXX*/
315 return 0;
316 }
317 pkblob = packet_get_string(&blen);
318 key = dsa_key_from_blob(pkblob, blen);
319 if (key != NULL) {
320 if (have_sig) {
321 sig = packet_get_string(&slen);
322 packet_done();
323 buffer_init(&b);
74fc9186 324 if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
325 buffer_put_string(&b, session_id2, session_id2_len);
326 } else {
327 buffer_append(&b, session_id2, session_id2_len);
328 }
38c295d6 329 /* reconstruct packet */
a306f2dd 330 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
38c295d6 331 buffer_put_cstring(&b, pw->pw_name);
332 buffer_put_cstring(&b,
333 datafellows & SSH_BUG_PUBKEYAUTH ?
334 "ssh-userauth" :
335 service);
336 buffer_put_cstring(&b, "publickey");
337 buffer_put_char(&b, have_sig);
338 buffer_put_cstring(&b, KEX_DSS);
339 buffer_put_string(&b, pkblob, blen);
a306f2dd 340#ifdef DEBUG_DSS
341 buffer_dump(&b);
342#endif
343 /* test for correct signature */
344 if (user_dsa_key_allowed(pw, key) &&
345 dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
346 authenticated = 1;
347 buffer_clear(&b);
348 xfree(sig);
349 } else {
350 packet_done();
351 debug("test key...");
352 /* test whether pkalg/pkblob are acceptable */
353 /* XXX fake reply and always send PK_OK ? */
1d1ffb87 354 /*
355 * XXX this allows testing whether a user is allowed
356 * to login: if you happen to have a valid pubkey this
357 * message is sent. the message is NEVER sent at all
358 * if a user is not allowed to login. is this an
359 * issue? -markus
360 */
a306f2dd 361 if (user_dsa_key_allowed(pw, key)) {
362 packet_start(SSH2_MSG_USERAUTH_PK_OK);
363 packet_put_string(pkalg, alen);
364 packet_put_string(pkblob, blen);
365 packet_send();
366 packet_write_wait();
367 authenticated = -1;
368 }
369 }
370 key_free(key);
371 }
372 xfree(pkalg);
373 xfree(pkblob);
374 return authenticated;
375}
376
377/* set and get current user */
378
379struct passwd*
380auth_get_user(void)
381{
382 return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
383}
384
385struct passwd*
386auth_set_user(char *u, char *s)
387{
388 struct passwd *pw, *copy;
389
390 if (authctxt == NULL) {
391 authctxt = xmalloc(sizeof(*authctxt));
392 authctxt->valid = 0;
393 authctxt->user = xstrdup(u);
394 authctxt->service = xstrdup(s);
395 setproctitle("%s", u);
396 pw = getpwnam(u);
397 if (!pw || !allowed_user(pw)) {
398 log("auth_set_user: illegal user %s", u);
399 return NULL;
400 }
401#ifdef USE_PAM
402 start_pam(pw);
403#endif
404 copy = &authctxt->pw;
405 memset(copy, 0, sizeof(*copy));
406 copy->pw_name = xstrdup(pw->pw_name);
407 copy->pw_passwd = xstrdup(pw->pw_passwd);
408 copy->pw_uid = pw->pw_uid;
409 copy->pw_gid = pw->pw_gid;
2e73a022 410#ifdef HAVE_PW_CLASS_IN_PASSWD
411 copy->pw_class = xstrdup(pw->pw_class);
412#endif
a306f2dd 413 copy->pw_dir = xstrdup(pw->pw_dir);
414 copy->pw_shell = xstrdup(pw->pw_shell);
415 authctxt->valid = 1;
416 } else {
417 if (strcmp(u, authctxt->user) != 0 ||
418 strcmp(s, authctxt->service) != 0) {
419 log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
420 u, s, authctxt->user, authctxt->service);
421 return NULL;
422 }
423 }
424 return auth_get_user();
425}
426
427/* return 1 if user allows given key */
428int
429user_dsa_key_allowed(struct passwd *pw, Key *key)
430{
431 char line[8192], file[1024];
432 int found_key = 0;
433 unsigned int bits = -1;
434 FILE *f;
435 unsigned long linenum = 0;
436 struct stat st;
437 Key *found;
438
439 /* Temporarily use the user's uid. */
440 temporarily_use_uid(pw->pw_uid);
441
442 /* The authorized keys. */
443 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
444 SSH_USER_PERMITTED_KEYS2);
445
446 /* Fail quietly if file does not exist */
447 if (stat(file, &st) < 0) {
448 /* Restore the privileged uid. */
449 restore_uid();
450 return 0;
451 }
452 /* Open the file containing the authorized keys. */
453 f = fopen(file, "r");
454 if (!f) {
455 /* Restore the privileged uid. */
456 restore_uid();
457 return 0;
458 }
459 if (options.strict_modes) {
460 int fail = 0;
461 char buf[1024];
462 /* Check open file in order to avoid open/stat races */
463 if (fstat(fileno(f), &st) < 0 ||
464 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
465 (st.st_mode & 022) != 0) {
466 snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
467 "bad ownership or modes for '%s'.", pw->pw_name, file);
468 fail = 1;
469 } else {
470 /* Check path to SSH_USER_PERMITTED_KEYS */
471 int i;
472 static const char *check[] = {
473 "", SSH_USER_DIR, NULL
474 };
475 for (i = 0; check[i]; i++) {
476 snprintf(line, sizeof line, "%.500s/%.100s",
477 pw->pw_dir, check[i]);
478 if (stat(line, &st) < 0 ||
479 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
480 (st.st_mode & 022) != 0) {
481 snprintf(buf, sizeof buf,
482 "DSA authentication refused for %.100s: "
483 "bad ownership or modes for '%s'.",
484 pw->pw_name, line);
485 fail = 1;
486 break;
487 }
488 }
489 }
490 if (fail) {
a306f2dd 491 fclose(f);
089fbbd2 492 log("%s",buf);
a306f2dd 493 restore_uid();
494 return 0;
495 }
496 }
497 found_key = 0;
498 found = key_new(KEY_DSA);
499
500 while (fgets(line, sizeof(line), f)) {
38c295d6 501 char *cp, *options = NULL;
a306f2dd 502 linenum++;
503 /* Skip leading whitespace, empty and comment lines. */
504 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
505 ;
506 if (!*cp || *cp == '\n' || *cp == '#')
507 continue;
38c295d6 508
a306f2dd 509 bits = key_read(found, &cp);
38c295d6 510 if (bits == 0) {
511 /* no key? check if there are options for this key */
512 int quoted = 0;
513 options = cp;
514 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
515 if (*cp == '\\' && cp[1] == '"')
516 cp++; /* Skip both */
517 else if (*cp == '"')
518 quoted = !quoted;
519 }
520 /* Skip remaining whitespace. */
521 for (; *cp == ' ' || *cp == '\t'; cp++)
522 ;
523 bits = key_read(found, &cp);
524 if (bits == 0) {
525 /* still no key? advance to next line*/
526 continue;
527 }
528 }
529 if (key_equal(found, key) &&
530 auth_parse_options(pw, options, linenum) == 1) {
a306f2dd 531 found_key = 1;
532 debug("matching key found: file %s, line %ld",
533 file, linenum);
534 break;
535 }
536 }
537 restore_uid();
538 fclose(f);
539 key_free(found);
540 return found_key;
541}
This page took 0.637413 seconds and 5 git commands to generate.