Merge from vendor branch OPENSSH:
[dragonfly.git] / crypto / openssh-3.8.1p1 / 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.55 2003/11/08 16:02:40 jakob Exp $");
14
15 #include "xmalloc.h"
16 #include "rsa.h"
17 #include "ssh1.h"
18 #include "packet.h"
19 #include "buffer.h"
20 #include "mpaux.h"
21 #include "log.h"
22 #include "servconf.h"
23 #include "compat.h"
24 #include "auth.h"
25 #include "channels.h"
26 #include "session.h"
27 #include "uidswap.h"
28 #include "monitor_wrap.h"
29
30 /* import */
31 extern ServerOptions options;
32
33 /*
34  * convert ssh auth msg type into description
35  */
36 static char *
37 get_authname(int type)
38 {
39         static char buf[1024];
40         switch (type) {
41         case SSH_CMSG_AUTH_PASSWORD:
42                 return "password";
43         case SSH_CMSG_AUTH_RSA:
44                 return "rsa";
45         case SSH_CMSG_AUTH_RHOSTS_RSA:
46                 return "rhosts-rsa";
47         case SSH_CMSG_AUTH_RHOSTS:
48                 return "rhosts";
49         case SSH_CMSG_AUTH_TIS:
50         case SSH_CMSG_AUTH_TIS_RESPONSE:
51                 return "challenge-response";
52         }
53         snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
54         return buf;
55 }
56
57 /*
58  * read packets, try to authenticate the user and
59  * return only if authentication is successful
60  */
61 static void
62 do_authloop(Authctxt *authctxt)
63 {
64         int authenticated = 0;
65         u_int bits;
66         Key *client_host_key;
67         BIGNUM *n;
68         char *client_user, *password;
69         char info[1024];
70         u_int dlen;
71         u_int ulen;
72         int prev, type = 0;
73         struct passwd *pw = authctxt->pw;
74
75         debug("Attempting authentication for %s%.100s.",
76             authctxt->valid ? "" : "illegal user ", authctxt->user);
77
78         /* If the user has no password, accept authentication immediately. */
79         if (options.password_authentication &&
80 #ifdef KRB5
81             (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
82 #endif
83             PRIVSEP(auth_password(authctxt, ""))) {
84                 auth_log(authctxt, 1, "without authentication", "");
85                 return;
86         }
87
88         /* Indicate that authentication is needed. */
89         packet_start(SSH_SMSG_FAILURE);
90         packet_send();
91         packet_write_wait();
92
93         client_user = NULL;
94
95         for (;;) {
96                 /* default to fail */
97                 authenticated = 0;
98
99                 info[0] = '\0';
100
101                 /* Get a packet from the client. */
102                 prev = type;
103                 type = packet_read();
104
105                 /*
106                  * If we started challenge-response authentication but the
107                  * next packet is not a response to our challenge, release
108                  * the resources allocated by get_challenge() (which would
109                  * normally have been released by verify_response() had we
110                  * received such a response)
111                  */
112                 if (prev == SSH_CMSG_AUTH_TIS &&
113                     type != SSH_CMSG_AUTH_TIS_RESPONSE)
114                         abandon_challenge_response(authctxt);
115
116                 /* Process the packet. */
117                 switch (type) {
118                 case SSH_CMSG_AUTH_RHOSTS_RSA:
119                         if (!options.rhosts_rsa_authentication) {
120                                 verbose("Rhosts with RSA authentication disabled.");
121                                 break;
122                         }
123                         /*
124                          * Get client user name.  Note that we just have to
125                          * trust the client; root on the client machine can
126                          * claim to be any user.
127                          */
128                         client_user = packet_get_string(&ulen);
129
130                         /* Get the client host key. */
131                         client_host_key = key_new(KEY_RSA1);
132                         bits = packet_get_int();
133                         packet_get_bignum(client_host_key->rsa->e);
134                         packet_get_bignum(client_host_key->rsa->n);
135
136                         if (bits != BN_num_bits(client_host_key->rsa->n))
137                                 verbose("Warning: keysize mismatch for client_host_key: "
138                                     "actual %d, announced %d",
139                                     BN_num_bits(client_host_key->rsa->n), bits);
140                         packet_check_eom();
141
142                         authenticated = auth_rhosts_rsa(authctxt, client_user,
143                             client_host_key);
144                         key_free(client_host_key);
145
146                         snprintf(info, sizeof info, " ruser %.100s", client_user);
147                         break;
148
149                 case SSH_CMSG_AUTH_RSA:
150                         if (!options.rsa_authentication) {
151                                 verbose("RSA authentication disabled.");
152                                 break;
153                         }
154                         /* RSA authentication requested. */
155                         if ((n = BN_new()) == NULL)
156                                 fatal("do_authloop: BN_new failed");
157                         packet_get_bignum(n);
158                         packet_check_eom();
159                         authenticated = auth_rsa(authctxt, n);
160                         BN_clear_free(n);
161                         break;
162
163                 case SSH_CMSG_AUTH_PASSWORD:
164                         if (!options.password_authentication) {
165                                 verbose("Password authentication disabled.");
166                                 break;
167                         }
168                         /*
169                          * Read user password.  It is in plain text, but was
170                          * transmitted over the encrypted channel so it is
171                          * not visible to an outside observer.
172                          */
173                         password = packet_get_string(&dlen);
174                         packet_check_eom();
175
176                         /* Try authentication with the password. */
177                         authenticated = PRIVSEP(auth_password(authctxt, password));
178
179                         memset(password, 0, strlen(password));
180                         xfree(password);
181                         break;
182
183                 case SSH_CMSG_AUTH_TIS:
184                         debug("rcvd SSH_CMSG_AUTH_TIS");
185                         if (options.challenge_response_authentication == 1) {
186                                 char *challenge = get_challenge(authctxt);
187                                 if (challenge != NULL) {
188                                         debug("sending challenge '%s'", challenge);
189                                         packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
190                                         packet_put_cstring(challenge);
191                                         xfree(challenge);
192                                         packet_send();
193                                         packet_write_wait();
194                                         continue;
195                                 }
196                         }
197                         break;
198                 case SSH_CMSG_AUTH_TIS_RESPONSE:
199                         debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
200                         if (options.challenge_response_authentication == 1) {
201                                 char *response = packet_get_string(&dlen);
202                                 packet_check_eom();
203                                 authenticated = verify_response(authctxt, response);
204                                 memset(response, 'r', dlen);
205                                 xfree(response);
206                         }
207                         break;
208
209                 default:
210                         /*
211                          * Any unknown messages will be ignored (and failure
212                          * returned) during authentication.
213                          */
214                         logit("Unknown message during authentication: type %d", type);
215                         break;
216                 }
217 #ifdef BSD_AUTH
218                 if (authctxt->as) {
219                         auth_close(authctxt->as);
220                         authctxt->as = NULL;
221                 }
222 #endif
223                 if (!authctxt->valid && authenticated)
224                         fatal("INTERNAL ERROR: authenticated invalid user %s",
225                             authctxt->user);
226
227 #ifdef _UNICOS
228                 if (authenticated && cray_access_denied(authctxt->user)) {
229                         authenticated = 0;
230                         fatal("Access denied for user %s.",authctxt->user);
231                 }
232 #endif /* _UNICOS */
233
234 #ifdef HAVE_CYGWIN
235                 if (authenticated &&
236                     !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, pw)) {
237                         packet_disconnect("Authentication rejected for uid %d.",
238                             pw == NULL ? -1 : pw->pw_uid);
239                         authenticated = 0;
240                 }
241 #else
242                 /* Special handling for root */
243                 if (authenticated && authctxt->pw->pw_uid == 0 &&
244                     !auth_root_allowed(get_authname(type)))
245                         authenticated = 0;
246 #endif
247
248 #ifdef USE_PAM
249                 if (options.use_pam && authenticated &&
250                     !PRIVSEP(do_pam_account()))
251                         authenticated = 0;
252 #endif
253
254                 /* Log before sending the reply */
255                 auth_log(authctxt, authenticated, get_authname(type), info);
256
257                 if (client_user != NULL) {
258                         xfree(client_user);
259                         client_user = NULL;
260                 }
261
262                 if (authenticated)
263                         return;
264
265                 if (authctxt->failures++ > AUTH_FAIL_MAX)
266                         packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
267
268                 packet_start(SSH_SMSG_FAILURE);
269                 packet_send();
270                 packet_write_wait();
271         }
272 }
273
274 /*
275  * Performs authentication of an incoming connection.  Session key has already
276  * been exchanged and encryption is enabled.
277  */
278 void
279 do_authentication(Authctxt *authctxt)
280 {
281         u_int ulen;
282         char *user, *style = NULL;
283
284         /* Get the name of the user that we wish to log in as. */
285         packet_read_expect(SSH_CMSG_USER);
286
287         /* Get the user name. */
288         user = packet_get_string(&ulen);
289         packet_check_eom();
290
291         if ((style = strchr(user, ':')) != NULL)
292                 *style++ = '\0';
293
294         authctxt->user = user;
295         authctxt->style = style;
296
297         /* Verify that the user is a valid user. */
298         if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
299                 authctxt->valid = 1;
300         else {
301                 debug("do_authentication: illegal user %s", user);
302                 authctxt->pw = fakepw();
303         }
304
305         setproctitle("%s%s", authctxt->pw ? user : "unknown",
306             use_privsep ? " [net]" : "");
307
308 #ifdef USE_PAM
309         if (options.use_pam)
310                 PRIVSEP(start_pam(authctxt));
311 #endif
312
313         /*
314          * If we are not running as root, the user must have the same uid as
315          * the server. (Unless you are running Windows)
316          */
317 #ifndef HAVE_CYGWIN
318         if (!use_privsep && getuid() != 0 && authctxt->pw &&
319             authctxt->pw->pw_uid != getuid())
320                 packet_disconnect("Cannot change user when server not running as root.");
321 #endif
322
323         /*
324          * Loop until the user has been authenticated or the connection is
325          * closed, do_authloop() returns only if authentication is successful
326          */
327         do_authloop(authctxt);
328
329         /* The user has been authenticated and accepted. */
330         packet_start(SSH_SMSG_SUCCESS);
331         packet_send();
332         packet_write_wait();
333 }