]> andersk Git - openssh.git/blob - auth2.c
- (djm) Update CygWin support from Corinna Vinschen <vinschen@cygnus.com>
[openssh.git] / auth2.c
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.
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  */
24
25 #include "includes.h"
26 RCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $");
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"
53 #include "auth-options.h"
54
55 #ifdef HAVE_OSF_SIA
56 # include <sia.h>
57 # include <siad.h>
58 #endif
59
60 /* import */
61 extern ServerOptions options;
62 extern unsigned char *session_id2;
63 extern int session_id2_len;
64
65 /* protocol */
66
67 void    input_service_request(int type, int plen);
68 void    input_userauth_request(int type, int plen);
69 void    protocol_error(int type, int plen);
70
71 /* auth */
72 int     ssh2_auth_none(struct passwd *pw);
73 int     ssh2_auth_password(struct passwd *pw);
74 int     ssh2_auth_pubkey(struct passwd *pw, char *service);
75
76 /* helper */
77 struct passwd*   auth_set_user(char *u, char *s);
78 int     user_dsa_key_allowed(struct passwd *pw, Key *key);
79
80 typedef struct Authctxt Authctxt;
81 struct Authctxt {
82         char *user;
83         char *service;
84         struct passwd pw;
85         int valid;
86 };
87 static Authctxt *authctxt = NULL;
88 static int userauth_success = 0;
89
90 /*
91  * loop until userauth_success == TRUE
92  */
93
94 void
95 do_authentication2()
96 {
97         /* turn off skey/kerberos, not supported by SSH2 */
98 #ifdef SKEY
99         options.skey_authentication = 0;
100 #endif
101 #ifdef KRB4
102         options.kerberos_authentication = 0;
103 #endif
104
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
111 void
112 protocol_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
121 void
122 input_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
150 void
151 input_userauth_request(int type, int plen)
152 {
153         static void (*authlog) (const char *fmt,...) = verbose;
154         static int attempt = 0;
155         unsigned int len;
156         int authenticated = 0;
157         char *user, *service, *method, *authmsg = NULL;
158         struct passwd *pw;
159 #ifdef WITH_AIXAUTHENTICATE
160         extern char *aixloginmsg;
161 #endif /* WITH_AIXAUTHENTICATE */
162
163         user = packet_get_string(&len);
164         service = packet_get_string(&len);
165         method = packet_get_string(&len);
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         }
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) {
182                         authenticated = ssh2_auth_pubkey(pw, service);
183                 }
184         }
185
186 #ifdef HAVE_CYGWIN
187         if (authenticated && !check_nt_auth(strcmp(method, "password") == 0, pw->pw_uid)) {
188                 packet_disconnect("Authentication rejected for uid %d.",
189                                   (int) pw->pw_uid);
190                 authenticated = 0;
191         }
192 #endif
193
194         if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
195                 authenticated = 0;
196                 log("ROOT LOGIN REFUSED FROM %.200s",
197                     get_canonical_hostname());
198         }
199
200 #ifdef USE_PAM
201         if (authenticated && !do_pam_account(pw->pw_name, NULL))
202                 authenticated = 0;
203 #endif /* USE_PAM */
204
205         /* Raise logging level */
206         if (authenticated == 1 ||
207             attempt == AUTH_FAIL_LOG ||
208             strcmp(method, "password") == 0)
209                 authlog = log;
210
211         /* Log before sending the reply */
212         if (authenticated == 1) {
213                 authmsg = "Accepted";
214         } else if (authenticated == 0) {
215                 authmsg = "Failed";
216         } else {
217                 authmsg = "Postponed";
218         }
219         authlog("%s %s for %.200s from %.200s port %d ssh2",
220                 authmsg,
221                 method,
222                 pw && pw->pw_uid == 0 ? "ROOT" : user,
223                 get_remote_ipaddr(),
224                 get_remote_port());
225
226         /* XXX todo: check if multiple auth methods are needed */
227         if (authenticated == 1) {
228 #ifdef WITH_AIXAUTHENTICATE
229                 /* We don't have a pty yet, so just label the line as "ssh" */
230                 if (loginsuccess(user,get_canonical_hostname(),"ssh",
231                                 &aixloginmsg) < 0)
232                         aixloginmsg = NULL;
233 #endif /* WITH_AIXAUTHENTICATE */
234                 /* turn off userauth */
235                 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
236                 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
237                 packet_send();
238                 packet_write_wait();
239                 /* now we can break out */
240                 userauth_success = 1;
241         } else if (authenticated == 0) {
242                 packet_start(SSH2_MSG_USERAUTH_FAILURE);
243                 packet_put_cstring("publickey,password");       /* XXX dynamic */
244                 packet_put_char(0);                             /* XXX partial success, unused */
245                 packet_send();
246                 packet_write_wait();
247         }
248
249         xfree(service);
250         xfree(user);
251         xfree(method);
252 }
253
254 int
255 ssh2_auth_none(struct passwd *pw)
256 {
257 #ifdef HAVE_OSF_SIA
258         extern int saved_argc;
259         extern char **saved_argv;
260 #endif
261
262         packet_done();
263
264 #ifdef USE_PAM
265         return auth_pam_password(pw, "");
266 #elif defined(HAVE_OSF_SIA)
267         return(sia_validate_user(NULL, saved_argc, saved_argv, 
268                 get_canonical_hostname(), pw->pw_name, NULL, 0, NULL, 
269                 "") == SIASUCCESS);
270 #else /* !HAVE_OSF_SIA && !USE_PAM */
271         return auth_password(pw, "");
272 #endif /* USE_PAM */
273 }
274 int
275 ssh2_auth_password(struct passwd *pw)
276 {
277         char *password;
278         int authenticated = 0;
279         int change;
280         unsigned int len;
281 #ifdef HAVE_OSF_SIA
282         extern int saved_argc;
283         extern char **saved_argv;
284 #endif
285         change = packet_get_char();
286         if (change)
287                 log("password change not supported");
288         password = packet_get_string(&len);
289         packet_done();
290         if (options.password_authentication &&
291 #ifdef USE_PAM
292             auth_pam_password(pw, password) == 1)
293 #elif defined(HAVE_OSF_SIA)
294             sia_validate_user(NULL, saved_argc, saved_argv, 
295                         get_canonical_hostname(), pw->pw_name, NULL, 0, 
296                         NULL, password) == SIASUCCESS)
297 #else /* !USE_PAM && !HAVE_OSF_SIA */
298             auth_password(pw, password) == 1)
299 #endif /* USE_PAM */
300                 authenticated = 1;
301         memset(password, 0, len);
302         xfree(password);
303         return authenticated;
304 }
305 int
306 ssh2_auth_pubkey(struct passwd *pw, char *service)
307 {
308         Buffer b;
309         Key *key;
310         char *pkalg, *pkblob, *sig;
311         unsigned int alen, blen, slen;
312         int have_sig;
313         int authenticated = 0;
314
315         if (options.dsa_authentication == 0) {
316                 debug("pubkey auth disabled");
317                 return 0;
318         }
319         have_sig = packet_get_char();
320         pkalg = packet_get_string(&alen);
321         if (strcmp(pkalg, KEX_DSS) != 0) {
322                 xfree(pkalg);
323                 log("bad pkalg %s", pkalg);     /*XXX*/
324                 return 0;
325         }
326         pkblob = packet_get_string(&blen);
327         key = dsa_key_from_blob(pkblob, blen);
328         if (key != NULL) {
329                 if (have_sig) {
330                         sig = packet_get_string(&slen);
331                         packet_done();
332                         buffer_init(&b);
333                         if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
334                                 buffer_put_string(&b, session_id2, session_id2_len);
335                         } else {
336                                 buffer_append(&b, session_id2, session_id2_len);
337                         }
338                         /* reconstruct packet */
339                         buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
340                         buffer_put_cstring(&b, pw->pw_name);
341                         buffer_put_cstring(&b,
342                             datafellows & SSH_BUG_PUBKEYAUTH ?
343                             "ssh-userauth" :
344                             service);
345                         buffer_put_cstring(&b, "publickey");
346                         buffer_put_char(&b, have_sig);
347                         buffer_put_cstring(&b, KEX_DSS);
348                         buffer_put_string(&b, pkblob, blen);
349 #ifdef DEBUG_DSS
350                         buffer_dump(&b);
351 #endif
352                         /* test for correct signature */
353                         if (user_dsa_key_allowed(pw, key) &&
354                             dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
355                                 authenticated = 1;
356                         buffer_clear(&b);
357                         xfree(sig);
358                 } else {
359                         packet_done();
360                         debug("test key...");
361                         /* test whether pkalg/pkblob are acceptable */
362                         /* XXX fake reply and always send PK_OK ? */
363                         /*
364                          * XXX this allows testing whether a user is allowed
365                          * to login: if you happen to have a valid pubkey this
366                          * message is sent. the message is NEVER sent at all
367                          * if a user is not allowed to login. is this an
368                          * issue? -markus
369                          */
370                         if (user_dsa_key_allowed(pw, key)) {
371                                 packet_start(SSH2_MSG_USERAUTH_PK_OK);
372                                 packet_put_string(pkalg, alen);
373                                 packet_put_string(pkblob, blen);
374                                 packet_send();
375                                 packet_write_wait();
376                                 authenticated = -1;
377                         }
378                 }
379                 key_free(key);
380         }
381         xfree(pkalg);
382         xfree(pkblob);
383         return authenticated;
384 }
385
386 /* set and get current user */
387
388 struct passwd*
389 auth_get_user(void)
390 {
391         return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
392 }
393
394 struct passwd*
395 auth_set_user(char *u, char *s)
396 {
397         struct passwd *pw, *copy;
398
399         if (authctxt == NULL) {
400                 authctxt = xmalloc(sizeof(*authctxt));
401                 authctxt->valid = 0;
402                 authctxt->user = xstrdup(u);
403                 authctxt->service = xstrdup(s);
404                 setproctitle("%s", u);
405                 pw = getpwnam(u);
406                 if (!pw || !allowed_user(pw)) {
407                         log("auth_set_user: illegal user %s", u);
408                         return NULL;
409                 }
410 #ifdef USE_PAM
411                 start_pam(pw);
412 #endif
413                 copy = &authctxt->pw;
414                 memset(copy, 0, sizeof(*copy));
415                 copy->pw_name = xstrdup(pw->pw_name);
416                 copy->pw_passwd = xstrdup(pw->pw_passwd);
417                 copy->pw_uid = pw->pw_uid;
418                 copy->pw_gid = pw->pw_gid;
419 #ifdef HAVE_PW_CLASS_IN_PASSWD
420                 copy->pw_class = xstrdup(pw->pw_class);
421 #endif
422                 copy->pw_dir = xstrdup(pw->pw_dir);
423                 copy->pw_shell = xstrdup(pw->pw_shell);
424                 authctxt->valid = 1;
425         } else {
426                 if (strcmp(u, authctxt->user) != 0 ||
427                     strcmp(s, authctxt->service) != 0) {
428                         log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
429                             u, s, authctxt->user, authctxt->service);
430                         return NULL;
431                 }
432         }
433         return auth_get_user();
434 }
435
436 /* return 1 if user allows given key */
437 int
438 user_dsa_key_allowed(struct passwd *pw, Key *key)
439 {
440         char line[8192], file[1024];
441         int found_key = 0;
442         unsigned int bits = -1;
443         FILE *f;
444         unsigned long linenum = 0;
445         struct stat st;
446         Key *found;
447
448         /* Temporarily use the user's uid. */
449         temporarily_use_uid(pw->pw_uid);
450
451         /* The authorized keys. */
452         snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
453             SSH_USER_PERMITTED_KEYS2);
454
455         /* Fail quietly if file does not exist */
456         if (stat(file, &st) < 0) {
457                 /* Restore the privileged uid. */
458                 restore_uid();
459                 return 0;
460         }
461         /* Open the file containing the authorized keys. */
462         f = fopen(file, "r");
463         if (!f) {
464                 /* Restore the privileged uid. */
465                 restore_uid();
466                 return 0;
467         }
468         if (options.strict_modes) {
469                 int fail = 0;
470                 char buf[1024];
471                 /* Check open file in order to avoid open/stat races */
472                 if (fstat(fileno(f), &st) < 0 ||
473                     (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
474                     (st.st_mode & 022) != 0) {
475                         snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
476                             "bad ownership or modes for '%s'.", pw->pw_name, file);
477                         fail = 1;
478                 } else {
479                         /* Check path to SSH_USER_PERMITTED_KEYS */
480                         int i;
481                         static const char *check[] = {
482                                 "", SSH_USER_DIR, NULL
483                         };
484                         for (i = 0; check[i]; i++) {
485                                 snprintf(line, sizeof line, "%.500s/%.100s",
486                                     pw->pw_dir, check[i]);
487                                 if (stat(line, &st) < 0 ||
488                                     (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
489                                     (st.st_mode & 022) != 0) {
490                                         snprintf(buf, sizeof buf,
491                                             "DSA authentication refused for %.100s: "
492                                             "bad ownership or modes for '%s'.",
493                                             pw->pw_name, line);
494                                         fail = 1;
495                                         break;
496                                 }
497                         }
498                 }
499                 if (fail) {
500                         fclose(f);
501                         log("%s",buf);
502                         restore_uid();
503                         return 0;
504                 }
505         }
506         found_key = 0;
507         found = key_new(KEY_DSA);
508
509         while (fgets(line, sizeof(line), f)) {
510                 char *cp, *options = NULL;
511                 linenum++;
512                 /* Skip leading whitespace, empty and comment lines. */
513                 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
514                         ;
515                 if (!*cp || *cp == '\n' || *cp == '#')
516                         continue;
517
518                 bits = key_read(found, &cp);
519                 if (bits == 0) {
520                         /* no key?  check if there are options for this key */
521                         int quoted = 0;
522                         options = cp;
523                         for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
524                                 if (*cp == '\\' && cp[1] == '"')
525                                         cp++;   /* Skip both */
526                                 else if (*cp == '"')
527                                         quoted = !quoted;
528                         }
529                         /* Skip remaining whitespace. */
530                         for (; *cp == ' ' || *cp == '\t'; cp++)
531                                 ;
532                         bits = key_read(found, &cp);
533                         if (bits == 0) {
534                                 /* still no key?  advance to next line*/
535                                 continue;
536                         }
537                 }
538                 if (key_equal(found, key) &&
539                     auth_parse_options(pw, options, linenum) == 1) {
540                         found_key = 1;
541                         debug("matching key found: file %s, line %ld",
542                             file, linenum);
543                         break;
544                 }
545         }
546         restore_uid();
547         fclose(f);
548         key_free(found);
549         return found_key;
550 }
This page took 0.099339 seconds and 5 git commands to generate.