]> andersk Git - openssh.git/blame - auth2.c
- OpenBSD CVS update
[openssh.git] / auth2.c
CommitLineData
a306f2dd 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"
0fbe8c74 30RCSID("$OpenBSD: auth2.c,v 1.5 2000/05/01 23:13:39 djm Exp $");
a306f2dd 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 */
59extern ServerOptions options;
60extern unsigned char *session_id2;
61extern int session_id2_len;
62
63/* protocol */
64
65void input_service_request(int type, int plen);
66void input_userauth_request(int type, int plen);
67void protocol_error(int type, int plen);
68
69/* auth */
70int ssh2_auth_none(struct passwd *pw);
71int ssh2_auth_password(struct passwd *pw);
72int ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
73
74/* helper */
75struct passwd* auth_set_user(char *u, char *s);
76int user_dsa_key_allowed(struct passwd *pw, Key *key);
77
78typedef struct Authctxt Authctxt;
79struct Authctxt {
80 char *user;
81 char *service;
82 struct passwd pw;
83 int valid;
84};
85static Authctxt *authctxt = NULL;
86static int userauth_success = 0;
87
88/*
89 * loop until userauth_success == TRUE
90 */
91
92void
93do_authentication2()
94{
3189621b 95 /* turn off skey/kerberos, not supported by SSH2 */
8cb940db 96#ifdef SKEY
3189621b 97 options.skey_authentication = 0;
8cb940db 98#endif
99#ifdef KRB4
3189621b 100 options.kerberos_authentication = 0;
8cb940db 101#endif
3189621b 102
a306f2dd 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
109void
110protocol_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
119void
120input_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
148void
149input_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
158 if (++attempt == AUTH_FAIL_MAX)
159 packet_disconnect("too many failed userauth_requests");
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 debug("userauth-request for user %s service %s method %s", user, service, method);
168
169 /* XXX we only allow the ssh-connection service */
170 pw = auth_set_user(user, service);
171 if (pw && strcmp(service, "ssh-connection")==0) {
172 if (strcmp(method, "none") == 0) {
173 authenticated = ssh2_auth_none(pw);
174 } else if (strcmp(method, "password") == 0) {
175 authenticated = ssh2_auth_password(pw);
176 } else if (strcmp(method, "publickey") == 0) {
177 authenticated = ssh2_auth_pubkey(pw, raw, rlen);
178 }
179 }
180 if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
181 authenticated = 0;
182 log("ROOT LOGIN REFUSED FROM %.200s",
183 get_canonical_hostname());
184 }
185
186#ifdef USE_PAM
187 if (authenticated && !do_pam_account(pw->pw_name, NULL))
188 authenticated = 0;
189#endif /* USE_PAM */
190
191 /* XXX todo: check if multiple auth methods are needed */
192 if (authenticated == 1) {
193 authmsg = "Accepted";
194 /* turn off userauth */
195 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
196 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
197 packet_send();
198 packet_write_wait();
199 /* now we can break out */
200 userauth_success = 1;
201 } else if (authenticated == 0) {
202 authmsg = "Failed";
203 packet_start(SSH2_MSG_USERAUTH_FAILURE);
204 packet_put_cstring("publickey,password"); /* XXX dynamic */
205 packet_put_char(0); /* XXX partial success, unused */
206 packet_send();
207 packet_write_wait();
208 } else {
209 authmsg = "Postponed";
210 }
211 /* Raise logging level */
212 if (authenticated == 1||
213 attempt == AUTH_FAIL_LOG ||
214 strcmp(method, "password") == 0)
215 authlog = log;
216
217 authlog("%s %s for %.200s from %.200s port %d ssh2",
218 authmsg,
219 method,
220 pw && pw->pw_uid == 0 ? "ROOT" : user,
221 get_remote_ipaddr(),
222 get_remote_port());
223
224 xfree(service);
225 xfree(user);
226 xfree(method);
227}
228
229int
230ssh2_auth_none(struct passwd *pw)
231{
232 packet_done();
233#ifdef USE_PAM
234 return auth_pam_password(pw, "");
235#else /* USE_PAM */
236 return auth_password(pw, "");
237#endif /* USE_PAM */
238}
239int
240ssh2_auth_password(struct passwd *pw)
241{
242 char *password;
243 int authenticated = 0;
244 int change;
245 unsigned int len;
246 change = packet_get_char();
247 if (change)
248 log("password change not supported");
249 password = packet_get_string(&len);
250 packet_done();
251 if (options.password_authentication &&
252#ifdef USE_PAM
253 auth_pam_password(pw, password) == 1)
254#else /* USE_PAM */
255 auth_password(pw, password) == 1)
256#endif /* USE_PAM */
257 authenticated = 1;
258 memset(password, 0, len);
259 xfree(password);
260 return authenticated;
261}
262int
263ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
264{
265 Buffer b;
266 Key *key;
267 char *pkalg, *pkblob, *sig;
268 unsigned int alen, blen, slen;
269 int have_sig;
270 int authenticated = 0;
271
272 if (options.rsa_authentication == 0) {
273 debug("pubkey auth disabled");
274 return 0;
275 }
276 have_sig = packet_get_char();
277 pkalg = packet_get_string(&alen);
278 if (strcmp(pkalg, KEX_DSS) != 0) {
279 xfree(pkalg);
280 log("bad pkalg %s", pkalg); /*XXX*/
281 return 0;
282 }
283 pkblob = packet_get_string(&blen);
284 key = dsa_key_from_blob(pkblob, blen);
285 if (key != NULL) {
286 if (have_sig) {
287 sig = packet_get_string(&slen);
288 packet_done();
289 buffer_init(&b);
290 buffer_append(&b, session_id2, session_id2_len);
291 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
292 if (slen + 4 > rlen)
293 fatal("bad rlen/slen");
294 buffer_append(&b, raw, rlen - slen - 4);
295#ifdef DEBUG_DSS
296 buffer_dump(&b);
297#endif
298 /* test for correct signature */
299 if (user_dsa_key_allowed(pw, key) &&
300 dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
301 authenticated = 1;
302 buffer_clear(&b);
303 xfree(sig);
304 } else {
305 packet_done();
306 debug("test key...");
307 /* test whether pkalg/pkblob are acceptable */
308 /* XXX fake reply and always send PK_OK ? */
309 if (user_dsa_key_allowed(pw, key)) {
310 packet_start(SSH2_MSG_USERAUTH_PK_OK);
311 packet_put_string(pkalg, alen);
312 packet_put_string(pkblob, blen);
313 packet_send();
314 packet_write_wait();
315 authenticated = -1;
316 }
317 }
318 key_free(key);
319 }
320 xfree(pkalg);
321 xfree(pkblob);
322 return authenticated;
323}
324
325/* set and get current user */
326
327struct passwd*
328auth_get_user(void)
329{
330 return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
331}
332
333struct passwd*
334auth_set_user(char *u, char *s)
335{
336 struct passwd *pw, *copy;
337
338 if (authctxt == NULL) {
339 authctxt = xmalloc(sizeof(*authctxt));
340 authctxt->valid = 0;
341 authctxt->user = xstrdup(u);
342 authctxt->service = xstrdup(s);
343 setproctitle("%s", u);
344 pw = getpwnam(u);
345 if (!pw || !allowed_user(pw)) {
346 log("auth_set_user: illegal user %s", u);
347 return NULL;
348 }
349#ifdef USE_PAM
350 start_pam(pw);
351#endif
352 copy = &authctxt->pw;
353 memset(copy, 0, sizeof(*copy));
354 copy->pw_name = xstrdup(pw->pw_name);
355 copy->pw_passwd = xstrdup(pw->pw_passwd);
356 copy->pw_uid = pw->pw_uid;
357 copy->pw_gid = pw->pw_gid;
358 copy->pw_dir = xstrdup(pw->pw_dir);
359 copy->pw_shell = xstrdup(pw->pw_shell);
360 authctxt->valid = 1;
361 } else {
362 if (strcmp(u, authctxt->user) != 0 ||
363 strcmp(s, authctxt->service) != 0) {
364 log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
365 u, s, authctxt->user, authctxt->service);
366 return NULL;
367 }
368 }
369 return auth_get_user();
370}
371
372/* return 1 if user allows given key */
373int
374user_dsa_key_allowed(struct passwd *pw, Key *key)
375{
376 char line[8192], file[1024];
377 int found_key = 0;
378 unsigned int bits = -1;
379 FILE *f;
380 unsigned long linenum = 0;
381 struct stat st;
382 Key *found;
383
384 /* Temporarily use the user's uid. */
385 temporarily_use_uid(pw->pw_uid);
386
387 /* The authorized keys. */
388 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
389 SSH_USER_PERMITTED_KEYS2);
390
391 /* Fail quietly if file does not exist */
392 if (stat(file, &st) < 0) {
393 /* Restore the privileged uid. */
394 restore_uid();
395 return 0;
396 }
397 /* Open the file containing the authorized keys. */
398 f = fopen(file, "r");
399 if (!f) {
400 /* Restore the privileged uid. */
401 restore_uid();
402 return 0;
403 }
404 if (options.strict_modes) {
405 int fail = 0;
406 char buf[1024];
407 /* Check open file in order to avoid open/stat races */
408 if (fstat(fileno(f), &st) < 0 ||
409 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
410 (st.st_mode & 022) != 0) {
411 snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
412 "bad ownership or modes for '%s'.", pw->pw_name, file);
413 fail = 1;
414 } else {
415 /* Check path to SSH_USER_PERMITTED_KEYS */
416 int i;
417 static const char *check[] = {
418 "", SSH_USER_DIR, NULL
419 };
420 for (i = 0; check[i]; i++) {
421 snprintf(line, sizeof line, "%.500s/%.100s",
422 pw->pw_dir, check[i]);
423 if (stat(line, &st) < 0 ||
424 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
425 (st.st_mode & 022) != 0) {
426 snprintf(buf, sizeof buf,
427 "DSA authentication refused for %.100s: "
428 "bad ownership or modes for '%s'.",
429 pw->pw_name, line);
430 fail = 1;
431 break;
432 }
433 }
434 }
435 if (fail) {
436 log(buf);
437 fclose(f);
438 restore_uid();
439 return 0;
440 }
441 }
442 found_key = 0;
443 found = key_new(KEY_DSA);
444
445 while (fgets(line, sizeof(line), f)) {
446 char *cp;
447 linenum++;
448 /* Skip leading whitespace, empty and comment lines. */
449 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
450 ;
451 if (!*cp || *cp == '\n' || *cp == '#')
452 continue;
453 bits = key_read(found, &cp);
454 if (bits == 0)
455 continue;
456 if (key_equal(found, key)) {
457 found_key = 1;
458 debug("matching key found: file %s, line %ld",
459 file, linenum);
460 break;
461 }
462 }
463 restore_uid();
464 fclose(f);
465 key_free(found);
466 return found_key;
467}
This page took 0.107461 seconds and 5 git commands to generate.