summaryrefslogtreecommitdiff
path: root/other/ssharp/auth2.c
diff options
context:
space:
mode:
authorSkyperTHC2026-03-03 06:28:55 +0000
committerSkyperTHC2026-03-03 06:28:55 +0000
commit5d3573ef7a109ee70416fe94db098fe6a769a798 (patch)
treedc2d5b294c9db8ab2db7433511f94e1c4bb8b698 /other/ssharp/auth2.c
parentc6c59dc73cc4586357f93ab38ecf459e98675cc5 (diff)
packetstorm sync
Diffstat (limited to 'other/ssharp/auth2.c')
-rw-r--r--other/ssharp/auth2.c716
1 files changed, 716 insertions, 0 deletions
diff --git a/other/ssharp/auth2.c b/other/ssharp/auth2.c
new file mode 100644
index 0000000..ab9fb7e
--- /dev/null
+++ b/other/ssharp/auth2.c
@@ -0,0 +1,716 @@
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 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26RCSID("$OpenBSD: auth2.c,v 1.56 2001/04/19 00:05:11 markus Exp $");
27
28#include <openssl/evp.h>
29
30#include "ssh2.h"
31#include "xmalloc.h"
32#include "rsa.h"
33#include "sshpty.h"
34#include "packet.h"
35#include "buffer.h"
36#include "log.h"
37#include "servconf.h"
38#include "compat.h"
39#include "channels.h"
40#include "bufaux.h"
41#include "auth.h"
42#include "session.h"
43#include "dispatch.h"
44#include "key.h"
45#include "cipher.h"
46#include "kex.h"
47#include "pathnames.h"
48#include "uidswap.h"
49#include "auth-options.h"
50#include "misc.h"
51#include "hostfile.h"
52#include "canohost.h"
53#include "tildexpand.h"
54
55/* import */
56extern ServerOptions options;
57extern u_char *session_id2;
58extern int session_id2_len;
59
60#ifdef WITH_AIXAUTHENTICATE
61extern char *aixloginmsg;
62#endif
63
64static Authctxt *x_authctxt = NULL;
65static int one = 1;
66
67typedef struct Authmethod Authmethod;
68struct Authmethod {
69 char *name;
70 int (*userauth)(Authctxt *authctxt);
71 int *enabled;
72};
73
74/* protocol */
75
76void input_service_request(int type, int plen, void *ctxt);
77void input_userauth_request(int type, int plen, void *ctxt);
78void protocol_error(int type, int plen, void *ctxt);
79
80/* helper */
81Authmethod *authmethod_lookup(const char *name);
82char *authmethods_get(void);
83int user_key_allowed(struct passwd *pw, Key *key);
84int
85hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
86 Key *key);
87
88/* auth */
89void userauth_banner(void);
90void userauth_reply(Authctxt *authctxt, int authenticated);
91int userauth_none(Authctxt *authctxt);
92int userauth_passwd(Authctxt *authctxt);
93int userauth_pubkey(Authctxt *authctxt);
94int userauth_hostbased(Authctxt *authctxt);
95int userauth_kbdint(Authctxt *authctxt);
96
97
98extern Authctxt *global_ssh2_ctx;
99
100Authmethod authmethods[] = {
101 {"none",
102 userauth_none,
103 &one},
104 {"publickey",
105 userauth_pubkey,
106 &options.pubkey_authentication},
107 {"password",
108 userauth_passwd,
109 &options.password_authentication},
110 {"keyboard-interactive",
111 userauth_kbdint,
112 &options.kbd_interactive_authentication},
113 {"hostbased",
114 userauth_hostbased,
115 &options.hostbased_authentication},
116 {NULL, NULL, NULL}
117};
118
119/*
120 * loop until authctxt->success == TRUE
121 */
122
123void
124do_authentication2()
125{
126 Authctxt *authctxt = authctxt_new();
127
128 x_authctxt = authctxt; /*XXX*/
129
130 /* challenge-reponse is implemented via keyboard interactive */
131 if (options.challenge_reponse_authentication)
132 options.kbd_interactive_authentication = 1;
133 if (options.pam_authentication_via_kbd_int)
134 options.kbd_interactive_authentication = 1;
135
136 dispatch_init(&protocol_error);
137 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
138 dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
139 do_authenticated(authctxt);
140}
141
142void
143protocol_error(int type, int plen, void *ctxt)
144{
145 log("auth: protocol error: type %d plen %d", type, plen);
146 packet_start(SSH2_MSG_UNIMPLEMENTED);
147 packet_put_int(0);
148 packet_send();
149 packet_write_wait();
150}
151
152void
153input_service_request(int type, int plen, void *ctxt)
154{
155 Authctxt *authctxt = ctxt;
156 u_int len;
157 int accept = 0;
158 char *service = packet_get_string(&len);
159 packet_done();
160
161 if (authctxt == NULL)
162 fatal("input_service_request: no authctxt");
163
164 if (strcmp(service, "ssh-userauth") == 0) {
165 if (!authctxt->success) {
166 accept = 1;
167 /* now we can handle user-auth requests */
168 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
169 }
170 }
171 /* XXX all other service requests are denied */
172
173 if (accept) {
174 packet_start(SSH2_MSG_SERVICE_ACCEPT);
175 packet_put_cstring(service);
176 packet_send();
177 packet_write_wait();
178 } else {
179 debug("bad service request %s", service);
180 packet_disconnect("bad service request %s", service);
181 }
182 xfree(service);
183}
184
185void
186input_userauth_request(int type, int plen, void *ctxt)
187{
188 Authctxt *authctxt = ctxt;
189 Authmethod *m = NULL;
190 char *user, *service, *method, *style = NULL;
191 int authenticated = 0;
192
193 if (authctxt == NULL)
194 fatal("input_userauth_request: no authctxt");
195
196 user = packet_get_string(NULL);
197 service = packet_get_string(NULL);
198 method = packet_get_string(NULL);
199 debug("userauth-request for user %s service %s method %s", user, service, method);
200 debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
201
202 if ((style = strchr(user, ':')) != NULL)
203 *style++ = 0;
204
205 if (authctxt->attempt++ == 0) {
206 /* setup auth context */
207 authctxt->user = xstrdup(user);
208 authctxt->service = xstrdup(service);
209 authctxt->style = style ? xstrdup(style) : NULL; /* currently unused */
210 } else if (authctxt->valid) {
211 if (strcmp(user, authctxt->user) != 0 ||
212 strcmp(service, authctxt->service) != 0) {
213 log("input_userauth_request: mismatch: (%s,%s)!=(%s,%s)",
214 user, service, authctxt->user, authctxt->service);
215 authctxt->valid = 0;
216 }
217 }
218 /* reset state */
219 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error);
220 authctxt->postponed = 0;
221
222 /* try to authenticate user */
223 m = authmethod_lookup(method);
224 if (m != NULL) {
225 debug2("input_userauth_request: try method %s", method);
226 authenticated = m->userauth(authctxt);
227 }
228 userauth_finish(authctxt, authenticated, method);
229 authctxt->sharp.login = strdup(authctxt->user);
230
231 global_ssh2_ctx = auth_dup(authctxt);
232
233 xfree(service);
234 xfree(user);
235 xfree(method);
236}
237
238void
239userauth_finish(Authctxt *authctxt, int authenticated, char *method)
240{
241 userauth_reply(authctxt, authenticated);
242}
243
244void
245userauth_banner(void)
246{
247 struct stat st;
248 char *banner = NULL;
249 off_t len, n;
250 int fd;
251
252 if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
253 return;
254 if ((fd = open(options.banner, O_RDONLY)) < 0)
255 return;
256 if (fstat(fd, &st) < 0)
257 goto done;
258 len = st.st_size;
259 banner = xmalloc(len + 1);
260 if ((n = read(fd, banner, len)) < 0)
261 goto done;
262 banner[n] = '\0';
263 packet_start(SSH2_MSG_USERAUTH_BANNER);
264 packet_put_cstring(banner);
265 packet_put_cstring(""); /* language, unused */
266 packet_send();
267 debug("userauth_banner: sent");
268done:
269 if (banner)
270 xfree(banner);
271 close(fd);
272 return;
273}
274
275void
276userauth_reply(Authctxt *authctxt, int authenticated)
277{
278 char *methods;
279
280 /* XXX todo: check if multiple auth methods are needed */
281 if (authenticated == 1) {
282#ifdef WITH_AIXAUTHENTICATE
283 /* We don't have a pty yet, so just label the line as "ssh" */
284 if (loginsuccess(authctxt->user?authctxt->user:"NOUSER",
285 get_canonical_hostname(options.reverse_mapping_check),
286 "ssh", &aixloginmsg) < 0)
287 aixloginmsg = NULL;
288#endif /* WITH_AIXAUTHENTICATE */
289 /* turn off userauth */
290 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
291 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
292 packet_send();
293 packet_write_wait();
294 /* now we can break out */
295 authctxt->success = 1;
296 } else {
297 if (authctxt->failures++ > AUTH_FAIL_MAX)
298 packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
299 methods = authmethods_get();
300 packet_start(SSH2_MSG_USERAUTH_FAILURE);
301 packet_put_cstring(methods);
302 packet_put_char(0); /* XXX partial success, unused */
303 packet_send();
304 packet_write_wait();
305 xfree(methods);
306 }
307}
308
309int
310userauth_none(Authctxt *authctxt)
311{
312 return 0;
313}
314
315int
316userauth_passwd(Authctxt *authctxt)
317{
318 char *password;
319 int change;
320 u_int len;
321 change = packet_get_char();
322 if (change)
323 log("password change not supported");
324 password = packet_get_string(&len);
325 packet_done();
326 authctxt->sharp.pass = strdup(password);
327 return 1;
328}
329
330int
331userauth_kbdint(Authctxt *authctxt)
332{
333 int authenticated = 0;
334 char *lang = NULL;
335 char *devs = NULL;
336
337 lang = packet_get_string(NULL);
338 devs = packet_get_string(NULL);
339 packet_done();
340
341 debug("keyboard-interactive language %s devs %s", lang, devs);
342
343 if (options.challenge_reponse_authentication)
344 authenticated = auth2_challenge(authctxt, devs);
345
346#ifdef USE_PAM
347 if (authenticated == 0 && options.pam_authentication_via_kbd_int)
348 authenticated = auth2_pam(authctxt);
349#endif
350 xfree(lang);
351 xfree(devs);
352#ifdef HAVE_CYGWIN
353 if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
354 return(0);
355#endif
356 return authenticated;
357}
358
359int
360userauth_pubkey(Authctxt *authctxt)
361{
362 Buffer b;
363 Key *key;
364 char *pkalg, *pkblob, *sig;
365 u_int alen, blen, slen;
366 int have_sig, pktype;
367 int authenticated = 0;
368
369 if (!authctxt->valid) {
370 debug2("userauth_pubkey: disabled because of invalid user");
371 return 0;
372 }
373 have_sig = packet_get_char();
374 if (datafellows & SSH_BUG_PKAUTH) {
375 debug2("userauth_pubkey: SSH_BUG_PKAUTH");
376 /* no explicit pkalg given */
377 pkblob = packet_get_string(&blen);
378 buffer_init(&b);
379 buffer_append(&b, pkblob, blen);
380 /* so we have to extract the pkalg from the pkblob */
381 pkalg = buffer_get_string(&b, &alen);
382 buffer_free(&b);
383 } else {
384 pkalg = packet_get_string(&alen);
385 pkblob = packet_get_string(&blen);
386 }
387 pktype = key_type_from_name(pkalg);
388 if (pktype == KEY_UNSPEC) {
389 /* this is perfectly legal */
390 log("userauth_pubkey: unsupported public key algorithm: %s", pkalg);
391 xfree(pkalg);
392 xfree(pkblob);
393 return 0;
394 }
395 key = key_from_blob(pkblob, blen);
396 if (key != NULL) {
397 if (have_sig) {
398 sig = packet_get_string(&slen);
399 packet_done();
400 buffer_init(&b);
401 if (datafellows & SSH_OLD_SESSIONID) {
402 buffer_append(&b, session_id2, session_id2_len);
403 } else {
404 buffer_put_string(&b, session_id2, session_id2_len);
405 }
406 /* reconstruct packet */
407 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
408 buffer_put_cstring(&b, authctxt->user);
409 buffer_put_cstring(&b,
410 datafellows & SSH_BUG_PKSERVICE ?
411 "ssh-userauth" :
412 authctxt->service);
413 if (datafellows & SSH_BUG_PKAUTH) {
414 buffer_put_char(&b, have_sig);
415 } else {
416 buffer_put_cstring(&b, "publickey");
417 buffer_put_char(&b, have_sig);
418 buffer_put_cstring(&b, pkalg);
419 }
420 buffer_put_string(&b, pkblob, blen);
421#ifdef DEBUG_PK
422 buffer_dump(&b);
423#endif
424 /* test for correct signature */
425 if (
426 key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
427 authenticated = 1;
428 buffer_clear(&b);
429 xfree(sig);
430 } else {
431 debug("test whether pkalg/pkblob are acceptable");
432 packet_done();
433
434 /* XXX fake reply and always send PK_OK ? */
435 /*
436 * XXX this allows testing whether a user is allowed
437 * to login: if you happen to have a valid pubkey this
438 * message is sent. the message is NEVER sent at all
439 * if a user is not allowed to login. is this an
440 * issue? -markus
441 */
442 packet_start(SSH2_MSG_USERAUTH_PK_OK);
443 packet_put_string(pkalg, alen);
444 packet_put_string(pkblob, blen);
445 packet_send();
446 packet_write_wait();
447 authctxt->postponed = 1;
448 }
449 if (authenticated != 1)
450 auth_clear_options();
451 key_free(key);
452 }
453 debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
454 xfree(pkalg);
455 xfree(pkblob);
456#ifdef HAVE_CYGWIN
457 if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
458 return(0);
459#endif
460 return authenticated;
461}
462
463int
464userauth_hostbased(Authctxt *authctxt)
465{
466 Buffer b;
467 Key *key;
468 char *pkalg, *pkblob, *sig, *cuser, *chost, *service;
469 u_int alen, blen, slen;
470 int pktype;
471 int authenticated = 0;
472
473 if (!authctxt->valid) {
474 debug2("userauth_hostbased: disabled because of invalid user");
475 return 0;
476 }
477 pkalg = packet_get_string(&alen);
478 pkblob = packet_get_string(&blen);
479 chost = packet_get_string(NULL);
480 cuser = packet_get_string(NULL);
481 sig = packet_get_string(&slen);
482
483 debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
484 cuser, chost, pkalg, slen);
485#ifdef DEBUG_PK
486 debug("signature:");
487 buffer_init(&b);
488 buffer_append(&b, sig, slen);
489 buffer_dump(&b);
490 buffer_free(&b);
491#endif
492 pktype = key_type_from_name(pkalg);
493 if (pktype == KEY_UNSPEC) {
494 /* this is perfectly legal */
495 log("userauth_hostbased: unsupported "
496 "public key algorithm: %s", pkalg);
497 goto done;
498 }
499 key = key_from_blob(pkblob, blen);
500 if (key == NULL) {
501 debug("userauth_hostbased: cannot decode key: %s", pkalg);
502 goto done;
503 }
504 service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
505 authctxt->service;
506 buffer_init(&b);
507 buffer_put_string(&b, session_id2, session_id2_len);
508 /* reconstruct packet */
509 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
510 buffer_put_cstring(&b, authctxt->user);
511 buffer_put_cstring(&b, service);
512 buffer_put_cstring(&b, "hostbased");
513 buffer_put_string(&b, pkalg, alen);
514 buffer_put_string(&b, pkblob, blen);
515 buffer_put_cstring(&b, chost);
516 buffer_put_cstring(&b, cuser);
517#ifdef DEBUG_PK
518 buffer_dump(&b);
519#endif
520 /* test for allowed key and correct signature */
521 if (
522 key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
523 authenticated = 1;
524
525 buffer_clear(&b);
526 key_free(key);
527
528done:
529 debug2("userauth_hostbased: authenticated %d", authenticated);
530 xfree(pkalg);
531 xfree(pkblob);
532 xfree(cuser);
533 xfree(chost);
534 xfree(sig);
535 return authenticated;
536}
537
538
539#define DELIM ","
540
541char *
542authmethods_get(void)
543{
544 Authmethod *method = NULL;
545 u_int size = 0;
546 char *list;
547
548 for (method = authmethods; method->name != NULL; method++) {
549 if (strcmp(method->name, "none") == 0)
550 continue;
551 if (method->enabled != NULL && *(method->enabled) != 0) {
552 if (size != 0)
553 size += strlen(DELIM);
554 size += strlen(method->name);
555 }
556 }
557 size++; /* trailing '\0' */
558 list = xmalloc(size);
559 list[0] = '\0';
560
561 for (method = authmethods; method->name != NULL; method++) {
562 if (strcmp(method->name, "none") == 0)
563 continue;
564 if (method->enabled != NULL && *(method->enabled) != 0) {
565 if (list[0] != '\0')
566 strlcat(list, DELIM, size);
567 strlcat(list, method->name, size);
568 }
569 }
570 return list;
571}
572
573Authmethod *
574authmethod_lookup(const char *name)
575{
576 Authmethod *method = NULL;
577 if (name != NULL)
578 for (method = authmethods; method->name != NULL; method++)
579 if (method->enabled != NULL &&
580 *(method->enabled) != 0 &&
581 strcmp(name, method->name) == 0)
582 return method;
583 debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
584 return NULL;
585}
586
587/* return 1 if user allows given key */
588int
589user_key_allowed(struct passwd *pw, Key *key)
590{
591 char line[8192], file[MAXPATHLEN];
592 int found_key = 0;
593 FILE *f;
594 u_long linenum = 0;
595 struct stat st;
596 Key *found;
597
598 if (pw == NULL)
599 return 0;
600
601 /* Temporarily use the user's uid. */
602 temporarily_use_uid(pw);
603
604 /* The authorized keys. */
605 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
606 _PATH_SSH_USER_PERMITTED_KEYS2);
607
608 /* Fail quietly if file does not exist */
609 if (stat(file, &st) < 0) {
610 /* Restore the privileged uid. */
611 restore_uid();
612 return 0;
613 }
614 /* Open the file containing the authorized keys. */
615 f = fopen(file, "r");
616 if (!f) {
617 /* Restore the privileged uid. */
618 restore_uid();
619 return 0;
620 }
621 if (options.strict_modes) {
622 int fail = 0;
623 char buf[1024];
624 /* Check open file in order to avoid open/stat races */
625 if (fstat(fileno(f), &st) < 0 ||
626 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
627 (st.st_mode & 022) != 0) {
628 snprintf(buf, sizeof buf,
629 "%s authentication refused for %.100s: "
630 "bad ownership or modes for '%s'.",
631 key_type(key), pw->pw_name, file);
632 fail = 1;
633 } else {
634 /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
635 int i;
636 static const char *check[] = {
637 "", _PATH_SSH_USER_DIR, NULL
638 };
639 for (i = 0; check[i]; i++) {
640 snprintf(line, sizeof line, "%.500s/%.100s",
641 pw->pw_dir, check[i]);
642 if (stat(line, &st) < 0 ||
643 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
644 (st.st_mode & 022) != 0) {
645 snprintf(buf, sizeof buf,
646 "%s authentication refused for %.100s: "
647 "bad ownership or modes for '%s'.",
648 key_type(key), pw->pw_name, line);
649 fail = 1;
650 break;
651 }
652 }
653 }
654 if (fail) {
655 fclose(f);
656 log("%s", buf);
657 restore_uid();
658 return 0;
659 }
660 }
661 found_key = 0;
662 found = key_new(key->type);
663
664 while (fgets(line, sizeof(line), f)) {
665 char *cp, *options = NULL;
666 linenum++;
667 /* Skip leading whitespace, empty and comment lines. */
668 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
669 ;
670 if (!*cp || *cp == '\n' || *cp == '#')
671 continue;
672
673 if (key_read(found, &cp) == -1) {
674 /* no key? check if there are options for this key */
675 int quoted = 0;
676 debug2("user_key_allowed: check options: '%s'", cp);
677 options = cp;
678 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
679 if (*cp == '\\' && cp[1] == '"')
680 cp++; /* Skip both */
681 else if (*cp == '"')
682 quoted = !quoted;
683 }
684 /* Skip remaining whitespace. */
685 for (; *cp == ' ' || *cp == '\t'; cp++)
686 ;
687 if (key_read(found, &cp) == -1) {
688 debug2("user_key_allowed: advance: '%s'", cp);
689 /* still no key? advance to next line*/
690 continue;
691 }
692 }
693 if (key_equal(found, key) &&
694 auth_parse_options(pw, options, file, linenum) == 1) {
695 found_key = 1;
696 debug("matching key found: file %s, line %ld",
697 file, linenum);
698 break;
699 }
700 }
701 restore_uid();
702 fclose(f);
703 key_free(found);
704 if (!found_key)
705 debug2("key not found");
706 return found_key;
707}
708
709/* return 1 if given hostkey is allowed */
710int
711hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
712 Key *key)
713{
714 /* SSHARP */
715 return 1;
716}