Merge from vendor branch CVS:
[dragonfly.git] / crypto / openssh-4 / auth1.c
1 /*
2  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3  *                    All rights reserved
4  *
5  * As far as I am concerned, the code I have written for this software
6  * can be used freely for any purpose.  Any derived versions of this
7  * software must be clearly marked as such, and if the derived work is
8  * incompatible with the protocol description in the RFC file, it must be
9  * called by a name other than "ssh" or "Secure Shell".
10  */
11
12 #include "includes.h"
13 RCSID("$OpenBSD: auth1.c,v 1.62 2005/07/16 01:35:24 djm Exp $");
14
15 #include "xmalloc.h"
16 #include "rsa.h"
17 #include "ssh1.h"
18 #include "packet.h"
19 #include "buffer.h"
20 #include "log.h"
21 #include "servconf.h"
22 #include "compat.h"
23 #include "auth.h"
24 #include "channels.h"
25 #include "session.h"
26 #include "uidswap.h"
27 #include "monitor_wrap.h"
28 #include "buffer.h"
29
30 /* import */
31 extern ServerOptions options;
32 extern Buffer loginmsg;
33
34 static int auth1_process_password(Authctxt *, char *, size_t);
35 static int auth1_process_rsa(Authctxt *, char *, size_t);
36 static int auth1_process_rhosts_rsa(Authctxt *, char *, size_t);
37 static int auth1_process_tis_challenge(Authctxt *, char *, size_t);
38 static int auth1_process_tis_response(Authctxt *, char *, size_t);
39
40 static char *client_user = NULL;    /* Used to fill in remote user for PAM */
41
42 struct AuthMethod1 {
43         int type;
44         char *name;
45         int *enabled;
46         int (*method)(Authctxt *, char *, size_t);
47 };
48
49 const struct AuthMethod1 auth1_methods[] = {
50         {
51                 SSH_CMSG_AUTH_PASSWORD, "password",
52                 &options.password_authentication, auth1_process_password
53         },
54         {
55                 SSH_CMSG_AUTH_RSA, "rsa",
56                 &options.rsa_authentication, auth1_process_rsa
57         },
58         {
59                 SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa",
60                 &options.rhosts_rsa_authentication, auth1_process_rhosts_rsa
61         },
62         {
63                 SSH_CMSG_AUTH_TIS, "challenge-response",
64                 &options.challenge_response_authentication,
65                 auth1_process_tis_challenge
66         },
67         {
68                 SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response",
69                 &options.challenge_response_authentication,
70                 auth1_process_tis_response
71         },
72         { -1, NULL, NULL, NULL}
73 };
74
75 static const struct AuthMethod1
76 *lookup_authmethod1(int type)
77 {
78         int i;
79
80         for(i = 0; auth1_methods[i].name != NULL; i++)
81                 if (auth1_methods[i].type == type)
82                         return (&(auth1_methods[i]));
83
84         return (NULL);
85 }
86
87 static char *
88 get_authname(int type)
89 {
90         const struct AuthMethod1 *a;
91         static char buf[64];
92
93         if ((a = lookup_authmethod1(type)) != NULL)
94                 return (a->name);
95         snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type);
96         return (buf);
97 }
98
99 static int
100 auth1_process_password(Authctxt *authctxt, char *info, size_t infolen)
101 {
102         int authenticated = 0;
103         char *password;
104         u_int dlen;
105
106         /*
107          * Read user password.  It is in plain text, but was
108          * transmitted over the encrypted channel so it is
109          * not visible to an outside observer.
110          */
111         password = packet_get_string(&dlen);
112         packet_check_eom();
113
114         /* Try authentication with the password. */
115         authenticated = PRIVSEP(auth_password(authctxt, password));
116
117         memset(password, 0, dlen);
118         xfree(password);
119
120         return (authenticated);
121 }
122
123 static int
124 auth1_process_rsa(Authctxt *authctxt, char *info, size_t infolen)
125 {
126         int authenticated = 0;
127         BIGNUM *n;
128
129         /* RSA authentication requested. */
130         if ((n = BN_new()) == NULL)
131                 fatal("do_authloop: BN_new failed");
132         packet_get_bignum(n);
133         packet_check_eom();
134         authenticated = auth_rsa(authctxt, n);
135         BN_clear_free(n);
136
137         return (authenticated);
138 }
139
140 static int
141 auth1_process_rhosts_rsa(Authctxt *authctxt, char *info, size_t infolen)
142 {
143         int keybits, authenticated = 0;
144         u_int bits;
145         Key *client_host_key;
146         u_int ulen;
147
148         /*
149          * Get client user name.  Note that we just have to
150          * trust the client; root on the client machine can
151          * claim to be any user.
152          */
153         client_user = packet_get_string(&ulen);
154
155         /* Get the client host key. */
156         client_host_key = key_new(KEY_RSA1);
157         bits = packet_get_int();
158         packet_get_bignum(client_host_key->rsa->e);
159         packet_get_bignum(client_host_key->rsa->n);
160
161         keybits = BN_num_bits(client_host_key->rsa->n);
162         if (keybits < 0 || bits != (u_int)keybits) {
163                 verbose("Warning: keysize mismatch for client_host_key: "
164                     "actual %d, announced %d",
165                     BN_num_bits(client_host_key->rsa->n), bits);
166         }
167         packet_check_eom();
168
169         authenticated = auth_rhosts_rsa(authctxt, client_user,
170             client_host_key);
171         key_free(client_host_key);
172
173         snprintf(info, infolen, " ruser %.100s", client_user);
174
175         return (authenticated);
176 }
177
178 static int
179 auth1_process_tis_challenge(Authctxt *authctxt, char *info, size_t infolen)
180 {
181         char *challenge;
182
183         if ((challenge = get_challenge(authctxt)) == NULL)
184                 return (0);
185
186         debug("sending challenge '%s'", challenge);
187         packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
188         packet_put_cstring(challenge);
189         xfree(challenge);
190         packet_send();
191         packet_write_wait();
192
193         return (-1);
194 }
195
196 static int
197 auth1_process_tis_response(Authctxt *authctxt, char *info, size_t infolen)
198 {
199         int authenticated = 0;
200         char *response;
201         u_int dlen;
202
203         response = packet_get_string(&dlen);
204         packet_check_eom();
205         authenticated = verify_response(authctxt, response);
206         memset(response, 'r', dlen);
207         xfree(response);
208
209         return (authenticated);
210 }
211
212 /*
213  * read packets, try to authenticate the user and
214  * return only if authentication is successful
215  */
216 static void
217 do_authloop(Authctxt *authctxt)
218 {
219         int authenticated = 0;
220         char info[1024];
221         int prev = 0, type = 0;
222         const struct AuthMethod1 *meth;
223
224         debug("Attempting authentication for %s%.100s.",
225             authctxt->valid ? "" : "invalid user ", authctxt->user);
226
227         /* If the user has no password, accept authentication immediately. */
228         if (options.password_authentication &&
229 #ifdef KRB5
230             (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
231 #endif
232             PRIVSEP(auth_password(authctxt, ""))) {
233 #ifdef USE_PAM
234                 if (options.use_pam && (PRIVSEP(do_pam_account())))
235 #endif
236                 {
237                         auth_log(authctxt, 1, "without authentication", "");
238                         return;
239                 }
240         }
241
242         /* Indicate that authentication is needed. */
243         packet_start(SSH_SMSG_FAILURE);
244         packet_send();
245         packet_write_wait();
246
247         for (;;) {
248                 /* default to fail */
249                 authenticated = 0;
250
251                 info[0] = '\0';
252
253                 /* Get a packet from the client. */
254                 prev = type;
255                 type = packet_read();
256
257                 /*
258                  * If we started challenge-response authentication but the
259                  * next packet is not a response to our challenge, release
260                  * the resources allocated by get_challenge() (which would
261                  * normally have been released by verify_response() had we
262                  * received such a response)
263                  */
264                 if (prev == SSH_CMSG_AUTH_TIS &&
265                     type != SSH_CMSG_AUTH_TIS_RESPONSE)
266                         abandon_challenge_response(authctxt);
267
268                 if ((meth = lookup_authmethod1(type)) == NULL) {
269                         logit("Unknown message during authentication: "
270                             "type %d", type);
271                         goto skip;
272                 }
273
274                 if (!*(meth->enabled)) {
275                         verbose("%s authentication disabled.", meth->name);
276                         goto skip;
277                 }
278
279                 authenticated = meth->method(authctxt, info, sizeof(info));
280                 if (authenticated == -1)
281                         continue; /* "postponed" */
282
283 #ifdef BSD_AUTH
284                 if (authctxt->as) {
285                         auth_close(authctxt->as);
286                         authctxt->as = NULL;
287                 }
288 #endif
289                 if (!authctxt->valid && authenticated)
290                         fatal("INTERNAL ERROR: authenticated invalid user %s",
291                             authctxt->user);
292
293 #ifdef _UNICOS
294                 if (authenticated && cray_access_denied(authctxt->user)) {
295                         authenticated = 0;
296                         fatal("Access denied for user %s.",authctxt->user);
297                 }
298 #endif /* _UNICOS */
299
300 #ifdef HAVE_CYGWIN
301                 if (authenticated &&
302                     !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD,
303                     authctxt->pw)) {
304                         packet_disconnect("Authentication rejected for uid %d.",
305                             authctxt->pw == NULL ? -1 : authctxt->pw->pw_uid);
306                         authenticated = 0;
307                 }
308 #else
309                 /* Special handling for root */
310                 if (authenticated && authctxt->pw->pw_uid == 0 &&
311                     !auth_root_allowed(meth->name)) {
312                         authenticated = 0;
313 # ifdef SSH_AUDIT_EVENTS
314                         PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
315 # endif
316                 }
317 #endif
318
319 #ifdef USE_PAM
320                 if (options.use_pam && authenticated &&
321                     !PRIVSEP(do_pam_account())) {
322                         char *msg;
323                         size_t len;
324
325                         error("Access denied for user %s by PAM account "
326                             "configuration", authctxt->user);
327                         len = buffer_len(&loginmsg);
328                         buffer_append(&loginmsg, "\0", 1);
329                         msg = buffer_ptr(&loginmsg);
330                         /* strip trailing newlines */
331                         if (len > 0)
332                                 while (len > 0 && msg[--len] == '\n')
333                                         msg[len] = '\0';
334                         else
335                                 msg = "Access denied.";
336                         packet_disconnect(msg);
337                 }
338 #endif
339
340  skip:
341                 /* Log before sending the reply */
342                 auth_log(authctxt, authenticated, get_authname(type), info);
343
344                 if (client_user != NULL) {
345                         xfree(client_user);
346                         client_user = NULL;
347                 }
348
349                 if (authenticated)
350                         return;
351
352                 if (authctxt->failures++ > options.max_authtries) {
353 #ifdef SSH_AUDIT_EVENTS
354                         PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
355 #endif
356                         packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
357                 }
358
359                 packet_start(SSH_SMSG_FAILURE);
360                 packet_send();
361                 packet_write_wait();
362         }
363 }
364
365 /*
366  * Performs authentication of an incoming connection.  Session key has already
367  * been exchanged and encryption is enabled.
368  */
369 void
370 do_authentication(Authctxt *authctxt)
371 {
372         u_int ulen;
373         char *user, *style = NULL;
374
375         /* Get the name of the user that we wish to log in as. */
376         packet_read_expect(SSH_CMSG_USER);
377
378         /* Get the user name. */
379         user = packet_get_string(&ulen);
380         packet_check_eom();
381
382         if ((style = strchr(user, ':')) != NULL)
383                 *style++ = '\0';
384
385         authctxt->user = user;
386         authctxt->style = style;
387
388         /* Verify that the user is a valid user. */
389         if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
390                 authctxt->valid = 1;
391         else {
392                 debug("do_authentication: invalid user %s", user);
393                 authctxt->pw = fakepw();
394         }
395
396         setproctitle("%s%s", authctxt->valid ? user : "unknown",
397             use_privsep ? " [net]" : "");
398
399 #ifdef USE_PAM
400         if (options.use_pam)
401                 PRIVSEP(start_pam(authctxt));
402 #endif
403
404         /*
405          * If we are not running as root, the user must have the same uid as
406          * the server.
407          */
408 #ifndef HAVE_CYGWIN
409         if (!use_privsep && getuid() != 0 && authctxt->pw &&
410             authctxt->pw->pw_uid != getuid())
411                 packet_disconnect("Cannot change user when server not running as root.");
412 #endif
413
414         /*
415          * Loop until the user has been authenticated or the connection is
416          * closed, do_authloop() returns only if authentication is successful
417          */
418         do_authloop(authctxt);
419
420         /* The user has been authenticated and accepted. */
421         packet_start(SSH_SMSG_SUCCESS);
422         packet_send();
423         packet_write_wait();
424 }