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