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