]> andersk Git - openssh.git/blob - auth2.c
- (djm) Use a real struct sockaddr inside the fake struct sockaddr_storage.
[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         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
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 */
203         if (authenticated == 1) {
204                 authmsg = "Accepted";
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) {
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 */
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) {
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();
238         }
239
240         xfree(service);
241         xfree(user);
242         xfree(method);
243 }
244
245 int
246 ssh2_auth_none(struct passwd *pw)
247 {
248 #ifdef HAVE_OSF_SIA
249         extern int saved_argc;
250         extern char **saved_argv;
251 #endif
252
253         packet_done();
254
255 #ifdef USE_PAM
256         return auth_pam_password(pw, "");
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 */
262         return auth_password(pw, "");
263 #endif /* USE_PAM */
264 }
265 int
266 ssh2_auth_password(struct passwd *pw)
267 {
268         char *password;
269         int authenticated = 0;
270         int change;
271         unsigned int len;
272 #ifdef HAVE_OSF_SIA
273         extern int saved_argc;
274         extern char **saved_argv;
275 #endif
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)
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 */
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 }
296 int
297 ssh2_auth_pubkey(struct passwd *pw, char *service)
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
306         if (options.dsa_authentication == 0) {
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);
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                         }
329                         /* reconstruct packet */
330                         buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
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);
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 ? */
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                          */
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
379 struct passwd*
380 auth_get_user(void)
381 {
382         return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
383 }
384
385 struct passwd*
386 auth_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;
410 #ifdef HAVE_PW_CLASS_IN_PASSWD
411                 copy->pw_class = xstrdup(pw->pw_class);
412 #endif
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 */
428 int
429 user_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) {
491                         fclose(f);
492                         log("%s",buf);
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)) {
501                 char *cp, *options = NULL;
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;
508
509                 bits = key_read(found, &cp);
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) {
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.078156 seconds and 5 git commands to generate.