]> andersk Git - openssh.git/blob - auth2.c
doc
[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.8 2000/05/08 17:42:24 markus 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
58 /* import */
59 extern ServerOptions options;
60 extern unsigned char *session_id2;
61 extern int session_id2_len;
62
63 /* protocol */
64
65 void    input_service_request(int type, int plen);
66 void    input_userauth_request(int type, int plen);
67 void    protocol_error(int type, int plen);
68
69 /* auth */
70 int     ssh2_auth_none(struct passwd *pw);
71 int     ssh2_auth_password(struct passwd *pw);
72 int     ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
73
74 /* helper */
75 struct passwd*   auth_set_user(char *u, char *s);
76 int     user_dsa_key_allowed(struct passwd *pw, Key *key);
77
78 typedef struct Authctxt Authctxt;
79 struct Authctxt {
80         char *user;
81         char *service;
82         struct passwd pw;
83         int valid;
84 };
85 static Authctxt *authctxt = NULL;
86 static int userauth_success = 0;
87
88 /*
89  * loop until userauth_success == TRUE
90  */
91
92 void
93 do_authentication2()
94 {
95         /* turn off skey/kerberos, not supported by SSH2 */
96 #ifdef SKEY
97         options.skey_authentication = 0;
98 #endif
99 #ifdef KRB4
100         options.kerberos_authentication = 0;
101 #endif
102
103         dispatch_init(&protocol_error);
104         dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
105         dispatch_run(DISPATCH_BLOCK, &userauth_success);
106         do_authenticated2();
107 }
108
109 void
110 protocol_error(int type, int plen)
111 {
112         log("auth: protocol error: type %d plen %d", type, plen);
113         packet_start(SSH2_MSG_UNIMPLEMENTED);
114         packet_put_int(0);
115         packet_send();
116         packet_write_wait();
117 }
118
119 void
120 input_service_request(int type, int plen)
121 {
122         unsigned int len;
123         int accept = 0;
124         char *service = packet_get_string(&len);
125         packet_done();
126
127         if (strcmp(service, "ssh-userauth") == 0) {
128                 if (!userauth_success) {
129                         accept = 1;
130                         /* now we can handle user-auth requests */
131                         dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
132                 }
133         }
134         /* XXX all other service requests are denied */
135
136         if (accept) {
137                 packet_start(SSH2_MSG_SERVICE_ACCEPT);
138                 packet_put_cstring(service);
139                 packet_send();
140                 packet_write_wait();
141         } else {
142                 debug("bad service request %s", service);
143                 packet_disconnect("bad service request %s", service);
144         }
145         xfree(service);
146 }
147
148 void
149 input_userauth_request(int type, int plen)
150 {
151         static void (*authlog) (const char *fmt,...) = verbose;
152         static int attempt = 0;
153         unsigned int len, rlen;
154         int authenticated = 0;
155         char *raw, *user, *service, *method, *authmsg = NULL;
156         struct passwd *pw;
157 #ifdef WITH_AIXAUTHENTICATE
158         extern char *aixloginmsg;
159 #endif /* WITH_AIXAUTHENTICATE */
160
161         raw = packet_get_raw(&rlen);
162         if (plen != rlen)
163                 fatal("plen != rlen");
164         user = packet_get_string(&len);
165         service = packet_get_string(&len);
166         method = packet_get_string(&len);
167         if (++attempt == AUTH_FAIL_MAX) {
168 #ifdef WITH_AIXAUTHENTICATE 
169                 loginfailed(user,get_canonical_hostname(),"ssh");
170 #endif /* WITH_AIXAUTHENTICATE */
171                 packet_disconnect("too many failed userauth_requests");
172         }
173         debug("userauth-request for user %s service %s method %s", user, service, method);
174
175         /* XXX we only allow the ssh-connection service */
176         pw = auth_set_user(user, service);
177         if (pw && strcmp(service, "ssh-connection")==0) {
178                 if (strcmp(method, "none") == 0) {
179                         authenticated = ssh2_auth_none(pw);
180                 } else if (strcmp(method, "password") == 0) {
181                         authenticated = ssh2_auth_password(pw);
182                 } else if (strcmp(method, "publickey") == 0) {
183                         authenticated = ssh2_auth_pubkey(pw, raw, rlen);
184                 }
185         }
186         if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
187                 authenticated = 0;
188                 log("ROOT LOGIN REFUSED FROM %.200s",
189                     get_canonical_hostname());
190         }
191
192 #ifdef USE_PAM
193                 if (authenticated && !do_pam_account(pw->pw_name, NULL))
194                         authenticated = 0;
195 #endif /* USE_PAM */
196
197         /* Raise logging level */
198         if (authenticated == 1 ||
199             attempt == AUTH_FAIL_LOG ||
200             strcmp(method, "password") == 0)
201                 authlog = log;
202
203         /* Log before sending the reply */
204         if (authenticated == 1) {
205                 authmsg = "Accepted";
206         } else if (authenticated == 0) {
207                 authmsg = "Failed";
208         } else {
209                 authmsg = "Postponed";
210         }
211         authlog("%s %s for %.200s from %.200s port %d ssh2",
212                 authmsg,
213                 method,
214                 pw && pw->pw_uid == 0 ? "ROOT" : user,
215                 get_remote_ipaddr(),
216                 get_remote_port());
217
218         /* XXX todo: check if multiple auth methods are needed */
219         if (authenticated == 1) {
220 #ifdef WITH_AIXAUTHENTICATE
221                 /* We don't have a pty yet, so just label the line as "ssh" */
222                 if (loginsuccess(user,get_canonical_hostname(),"ssh",
223                                 &aixloginmsg) < 0)
224                         aixloginmsg = NULL;
225 #endif /* WITH_AIXAUTHENTICATE */
226                 /* turn off userauth */
227                 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
228                 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
229                 packet_send();
230                 packet_write_wait();
231                 /* now we can break out */
232                 userauth_success = 1;
233         } else if (authenticated == 0) {
234                 packet_start(SSH2_MSG_USERAUTH_FAILURE);
235                 packet_put_cstring("publickey,password");       /* XXX dynamic */
236                 packet_put_char(0);                             /* XXX partial success, unused */
237                 packet_send();
238                 packet_write_wait();
239         }
240
241         xfree(service);
242         xfree(user);
243         xfree(method);
244 }
245
246 int
247 ssh2_auth_none(struct passwd *pw)
248 {
249         packet_done();
250 #ifdef USE_PAM
251         return auth_pam_password(pw, "");
252 #else /* USE_PAM */
253         return auth_password(pw, "");
254 #endif /* USE_PAM */
255 }
256 int
257 ssh2_auth_password(struct passwd *pw)
258 {
259         char *password;
260         int authenticated = 0;
261         int change;
262         unsigned int len;
263         change = packet_get_char();
264         if (change)
265                 log("password change not supported");
266         password = packet_get_string(&len);
267         packet_done();
268         if (options.password_authentication &&
269 #ifdef USE_PAM
270             auth_pam_password(pw, password) == 1)
271 #else /* USE_PAM */
272             auth_password(pw, password) == 1)
273 #endif /* USE_PAM */
274                 authenticated = 1;
275         memset(password, 0, len);
276         xfree(password);
277         return authenticated;
278 }
279 int
280 ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
281 {
282         Buffer b;
283         Key *key;
284         char *pkalg, *pkblob, *sig;
285         unsigned int alen, blen, slen;
286         int have_sig;
287         int authenticated = 0;
288
289         if (options.dsa_authentication == 0) {
290                 debug("pubkey auth disabled");
291                 return 0;
292         }
293         if (datafellows & SSH_BUG_PUBKEYAUTH) {
294                 log("bug compatibility with ssh-2.0.13 pubkey not implemented");
295                 return 0;
296         }
297         have_sig = packet_get_char();
298         pkalg = packet_get_string(&alen);
299         if (strcmp(pkalg, KEX_DSS) != 0) {
300                 xfree(pkalg);
301                 log("bad pkalg %s", pkalg);     /*XXX*/
302                 return 0;
303         }
304         pkblob = packet_get_string(&blen);
305         key = dsa_key_from_blob(pkblob, blen);
306         if (key != NULL) {
307                 if (have_sig) {
308                         sig = packet_get_string(&slen);
309                         packet_done();
310                         buffer_init(&b);
311                         buffer_append(&b, session_id2, session_id2_len);
312                         buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
313                         if (slen + 4 > rlen)
314                                 fatal("bad rlen/slen");
315                         buffer_append(&b, raw, rlen - slen - 4);
316 #ifdef DEBUG_DSS
317                         buffer_dump(&b);
318 #endif
319                         /* test for correct signature */
320                         if (user_dsa_key_allowed(pw, key) &&
321                             dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
322                                 authenticated = 1;
323                         buffer_clear(&b);
324                         xfree(sig);
325                 } else {
326                         packet_done();
327                         debug("test key...");
328                         /* test whether pkalg/pkblob are acceptable */
329                         /* XXX fake reply and always send PK_OK ? */
330                         /*
331                          * XXX this allows testing whether a user is allowed
332                          * to login: if you happen to have a valid pubkey this
333                          * message is sent. the message is NEVER sent at all
334                          * if a user is not allowed to login. is this an
335                          * issue? -markus
336                          */
337                         if (user_dsa_key_allowed(pw, key)) {
338                                 packet_start(SSH2_MSG_USERAUTH_PK_OK);
339                                 packet_put_string(pkalg, alen);
340                                 packet_put_string(pkblob, blen);
341                                 packet_send();
342                                 packet_write_wait();
343                                 authenticated = -1;
344                         }
345                 }
346                 key_free(key);
347         }
348         xfree(pkalg);
349         xfree(pkblob);
350         return authenticated;
351 }
352
353 /* set and get current user */
354
355 struct passwd*
356 auth_get_user(void)
357 {
358         return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
359 }
360
361 struct passwd*
362 auth_set_user(char *u, char *s)
363 {
364         struct passwd *pw, *copy;
365
366         if (authctxt == NULL) {
367                 authctxt = xmalloc(sizeof(*authctxt));
368                 authctxt->valid = 0;
369                 authctxt->user = xstrdup(u);
370                 authctxt->service = xstrdup(s);
371                 setproctitle("%s", u);
372                 pw = getpwnam(u);
373                 if (!pw || !allowed_user(pw)) {
374                         log("auth_set_user: illegal user %s", u);
375                         return NULL;
376                 }
377 #ifdef USE_PAM
378                 start_pam(pw);
379 #endif
380                 copy = &authctxt->pw;
381                 memset(copy, 0, sizeof(*copy));
382                 copy->pw_name = xstrdup(pw->pw_name);
383                 copy->pw_passwd = xstrdup(pw->pw_passwd);
384                 copy->pw_uid = pw->pw_uid;
385                 copy->pw_gid = pw->pw_gid;
386                 copy->pw_dir = xstrdup(pw->pw_dir);
387                 copy->pw_shell = xstrdup(pw->pw_shell);
388                 authctxt->valid = 1;
389         } else {
390                 if (strcmp(u, authctxt->user) != 0 ||
391                     strcmp(s, authctxt->service) != 0) {
392                         log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
393                             u, s, authctxt->user, authctxt->service);
394                         return NULL;
395                 }
396         }
397         return auth_get_user();
398 }
399
400 /* return 1 if user allows given key */
401 int
402 user_dsa_key_allowed(struct passwd *pw, Key *key)
403 {
404         char line[8192], file[1024];
405         int found_key = 0;
406         unsigned int bits = -1;
407         FILE *f;
408         unsigned long linenum = 0;
409         struct stat st;
410         Key *found;
411
412         /* Temporarily use the user's uid. */
413         temporarily_use_uid(pw->pw_uid);
414
415         /* The authorized keys. */
416         snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
417             SSH_USER_PERMITTED_KEYS2);
418
419         /* Fail quietly if file does not exist */
420         if (stat(file, &st) < 0) {
421                 /* Restore the privileged uid. */
422                 restore_uid();
423                 return 0;
424         }
425         /* Open the file containing the authorized keys. */
426         f = fopen(file, "r");
427         if (!f) {
428                 /* Restore the privileged uid. */
429                 restore_uid();
430                 return 0;
431         }
432         if (options.strict_modes) {
433                 int fail = 0;
434                 char buf[1024];
435                 /* Check open file in order to avoid open/stat races */
436                 if (fstat(fileno(f), &st) < 0 ||
437                     (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
438                     (st.st_mode & 022) != 0) {
439                         snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
440                             "bad ownership or modes for '%s'.", pw->pw_name, file);
441                         fail = 1;
442                 } else {
443                         /* Check path to SSH_USER_PERMITTED_KEYS */
444                         int i;
445                         static const char *check[] = {
446                                 "", SSH_USER_DIR, NULL
447                         };
448                         for (i = 0; check[i]; i++) {
449                                 snprintf(line, sizeof line, "%.500s/%.100s",
450                                     pw->pw_dir, check[i]);
451                                 if (stat(line, &st) < 0 ||
452                                     (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
453                                     (st.st_mode & 022) != 0) {
454                                         snprintf(buf, sizeof buf,
455                                             "DSA authentication refused for %.100s: "
456                                             "bad ownership or modes for '%s'.",
457                                             pw->pw_name, line);
458                                         fail = 1;
459                                         break;
460                                 }
461                         }
462                 }
463                 if (fail) {
464                         log(buf);
465                         fclose(f);
466                         restore_uid();
467                         return 0;
468                 }
469         }
470         found_key = 0;
471         found = key_new(KEY_DSA);
472
473         while (fgets(line, sizeof(line), f)) {
474                 char *cp;
475                 linenum++;
476                 /* Skip leading whitespace, empty and comment lines. */
477                 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
478                         ;
479                 if (!*cp || *cp == '\n' || *cp == '#')
480                         continue;
481                 bits = key_read(found, &cp);
482                 if (bits == 0)
483                         continue;
484                 if (key_equal(found, key)) {
485                         found_key = 1;
486                         debug("matching key found: file %s, line %ld",
487                             file, linenum);
488                         break;
489                 }
490         }
491         restore_uid();
492         fclose(f);
493         key_free(found);
494         return found_key;
495 }
This page took 0.094531 seconds and 5 git commands to generate.