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