Annotation of src/usr.bin/ssh/sshconnect2.c, Revision 1.10.2.5
1.1 markus 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"
1.10.2.5! jason 26: RCSID("$OpenBSD: sshconnect2.c,v 1.54 2001/03/12 22:02:02 markus Exp $");
1.1 markus 27:
28: #include <openssl/bn.h>
29: #include <openssl/md5.h>
30: #include <openssl/dh.h>
31: #include <openssl/hmac.h>
32:
33: #include "ssh.h"
1.10.2.4 jason 34: #include "ssh2.h"
1.1 markus 35: #include "xmalloc.h"
36: #include "rsa.h"
37: #include "buffer.h"
38: #include "packet.h"
39: #include "uidswap.h"
40: #include "compat.h"
41: #include "bufaux.h"
1.10.2.4 jason 42: #include "cipher.h"
1.1 markus 43: #include "kex.h"
44: #include "myproposal.h"
45: #include "key.h"
46: #include "sshconnect.h"
47: #include "authfile.h"
1.10.2.3 jason 48: #include "cli.h"
49: #include "dispatch.h"
1.10.2.2 jason 50: #include "authfd.h"
1.10.2.4 jason 51: #include "log.h"
52: #include "readconf.h"
53: #include "readpass.h"
1.10.2.5! jason 54: #include "match.h"
1.1 markus 55:
1.10.2.3 jason 56: void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
57: void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
58:
1.1 markus 59: /* import */
60: extern char *client_version_string;
61: extern char *server_version_string;
62: extern Options options;
63:
64: /*
65: * SSH2 key exchange
66: */
67:
1.10.2.4 jason 68: u_char *session_id2 = NULL;
1.1 markus 69: int session_id2_len = 0;
70:
71: void
1.10.2.3 jason 72: ssh_kex2(char *host, struct sockaddr *hostaddr)
1.1 markus 73: {
1.10.2.3 jason 74: int i, plen;
75: Kex *kex;
76: Buffer *client_kexinit, *server_kexinit;
77: char *sprop[PROPOSAL_MAX];
78:
1.10.2.4 jason 79: if (options.ciphers == (char *)-1) {
80: log("No valid ciphers for protocol version 2 given, using defaults.");
81: options.ciphers = NULL;
1.10.2.3 jason 82: }
83: if (options.ciphers != NULL) {
84: myproposal[PROPOSAL_ENC_ALGS_CTOS] =
85: myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
86: }
87: if (options.compression) {
1.10.2.4 jason 88: myproposal[PROPOSAL_COMP_ALGS_CTOS] =
1.10.2.3 jason 89: myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
90: } else {
1.10.2.4 jason 91: myproposal[PROPOSAL_COMP_ALGS_CTOS] =
1.10.2.3 jason 92: myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
93: }
1.10.2.4 jason 94: if (options.macs != NULL) {
95: myproposal[PROPOSAL_MAC_ALGS_CTOS] =
96: myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
97: }
1.10.2.3 jason 98:
99: /* buffers with raw kexinit messages */
100: server_kexinit = xmalloc(sizeof(*server_kexinit));
101: buffer_init(server_kexinit);
102: client_kexinit = kex_init(myproposal);
103:
104: /* algorithm negotiation */
105: kex_exchange_kexinit(client_kexinit, server_kexinit, sprop);
106: kex = kex_choose_conf(myproposal, sprop, 0);
107: for (i = 0; i < PROPOSAL_MAX; i++)
108: xfree(sprop[i]);
109:
110: /* server authentication and session key agreement */
111: switch(kex->kex_type) {
112: case DH_GRP1_SHA1:
113: ssh_dh1_client(kex, host, hostaddr,
114: client_kexinit, server_kexinit);
115: break;
116: case DH_GEX_SHA1:
117: ssh_dhgex_client(kex, host, hostaddr, client_kexinit,
118: server_kexinit);
119: break;
120: default:
121: fatal("Unsupported key exchange %d", kex->kex_type);
122: }
123:
124: buffer_free(client_kexinit);
125: buffer_free(server_kexinit);
126: xfree(client_kexinit);
127: xfree(server_kexinit);
128:
129: debug("Wait SSH2_MSG_NEWKEYS.");
130: packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
131: packet_done();
132: debug("GOT SSH2_MSG_NEWKEYS.");
133:
134: debug("send SSH2_MSG_NEWKEYS.");
135: packet_start(SSH2_MSG_NEWKEYS);
136: packet_send();
137: packet_write_wait();
138: debug("done: send SSH2_MSG_NEWKEYS.");
139:
140: #ifdef DEBUG_KEXDH
141: /* send 1st encrypted/maced/compressed message */
142: packet_start(SSH2_MSG_IGNORE);
143: packet_put_cstring("markus");
144: packet_send();
145: packet_write_wait();
146: #endif
147: debug("done: KEX2.");
148: }
149:
150: /* diffie-hellman-group1-sha1 */
151:
152: void
1.10.2.4 jason 153: ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr,
1.10.2.3 jason 154: Buffer *client_kexinit, Buffer *server_kexinit)
155: {
156: #ifdef DEBUG_KEXDH
157: int i;
158: #endif
1.10.2.1 jason 159: int plen, dlen;
1.10.2.4 jason 160: u_int klen, kout;
1.1 markus 161: char *signature = NULL;
1.10.2.4 jason 162: u_int slen;
1.1 markus 163: char *server_host_key_blob = NULL;
164: Key *server_host_key;
1.10.2.4 jason 165: u_int sbloblen;
1.1 markus 166: DH *dh;
167: BIGNUM *dh_server_pub = 0;
168: BIGNUM *shared_secret = 0;
1.10.2.4 jason 169: u_char *kbuf;
170: u_char *hash;
1.1 markus 171:
172: debug("Sending SSH2_MSG_KEXDH_INIT.");
173: /* generate and send 'e', client DH public key */
174: dh = dh_new_group1();
1.10.2.5! jason 175: dh_gen_key(dh, kex->we_need * 8);
1.1 markus 176: packet_start(SSH2_MSG_KEXDH_INIT);
177: packet_put_bignum2(dh->pub_key);
178: packet_send();
179: packet_write_wait();
180:
181: #ifdef DEBUG_KEXDH
182: fprintf(stderr, "\np= ");
1.10.2.3 jason 183: BN_print_fp(stderr, dh->p);
1.1 markus 184: fprintf(stderr, "\ng= ");
1.10.2.3 jason 185: BN_print_fp(stderr, dh->g);
1.1 markus 186: fprintf(stderr, "\npub= ");
1.10.2.3 jason 187: BN_print_fp(stderr, dh->pub_key);
1.1 markus 188: fprintf(stderr, "\n");
189: DHparams_print_fp(stderr, dh);
190: #endif
191:
192: debug("Wait SSH2_MSG_KEXDH_REPLY.");
193:
1.10.2.1 jason 194: packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY);
1.1 markus 195:
196: debug("Got SSH2_MSG_KEXDH_REPLY.");
197:
198: /* key, cert */
199: server_host_key_blob = packet_get_string(&sbloblen);
1.10.2.4 jason 200: server_host_key = key_from_blob(server_host_key_blob, sbloblen);
1.1 markus 201: if (server_host_key == NULL)
202: fatal("cannot decode server_host_key_blob");
203:
204: check_host_key(host, hostaddr, server_host_key,
1.10.2.3 jason 205: options.user_hostfile2, options.system_hostfile2);
1.1 markus 206:
207: /* DH paramter f, server public DH key */
208: dh_server_pub = BN_new();
209: if (dh_server_pub == NULL)
210: fatal("dh_server_pub == NULL");
211: packet_get_bignum2(dh_server_pub, &dlen);
212:
213: #ifdef DEBUG_KEXDH
214: fprintf(stderr, "\ndh_server_pub= ");
1.10.2.3 jason 215: BN_print_fp(stderr, dh_server_pub);
1.1 markus 216: fprintf(stderr, "\n");
217: debug("bits %d", BN_num_bits(dh_server_pub));
218: #endif
219:
220: /* signed H */
221: signature = packet_get_string(&slen);
222: packet_done();
223:
224: if (!dh_pub_is_valid(dh, dh_server_pub))
225: packet_disconnect("bad server public DH value");
226:
227: klen = DH_size(dh);
228: kbuf = xmalloc(klen);
229: kout = DH_compute_key(kbuf, dh_server_pub, dh);
230: #ifdef DEBUG_KEXDH
231: debug("shared secret: len %d/%d", klen, kout);
232: fprintf(stderr, "shared secret == ");
233: for (i = 0; i< kout; i++)
234: fprintf(stderr, "%02x", (kbuf[i])&0xff);
235: fprintf(stderr, "\n");
236: #endif
237: shared_secret = BN_new();
238:
239: BN_bin2bn(kbuf, kout, shared_secret);
240: memset(kbuf, 0, klen);
241: xfree(kbuf);
242:
243: /* calc and verify H */
244: hash = kex_hash(
245: client_version_string,
246: server_version_string,
247: buffer_ptr(client_kexinit), buffer_len(client_kexinit),
248: buffer_ptr(server_kexinit), buffer_len(server_kexinit),
249: server_host_key_blob, sbloblen,
250: dh->pub_key,
251: dh_server_pub,
252: shared_secret
253: );
1.3 markus 254: xfree(server_host_key_blob);
1.10.2.1 jason 255: DH_free(dh);
1.10.2.4 jason 256: BN_free(dh_server_pub);
1.1 markus 257: #ifdef DEBUG_KEXDH
258: fprintf(stderr, "hash == ");
259: for (i = 0; i< 20; i++)
260: fprintf(stderr, "%02x", (hash[i])&0xff);
261: fprintf(stderr, "\n");
262: #endif
1.10.2.4 jason 263: if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
264: fatal("key_verify failed for server_host_key");
1.1 markus 265: key_free(server_host_key);
1.10.2.4 jason 266: xfree(signature);
1.1 markus 267:
268: kex_derive_keys(kex, hash, shared_secret);
1.10.2.4 jason 269: BN_clear_free(shared_secret);
1.1 markus 270: packet_set_kex(kex);
271:
272: /* save session id */
273: session_id2_len = 20;
274: session_id2 = xmalloc(session_id2_len);
275: memcpy(session_id2, hash, session_id2_len);
1.10.2.1 jason 276: }
277:
1.10.2.3 jason 278: /* diffie-hellman-group-exchange-sha1 */
279:
280: /*
281: * Estimates the group order for a Diffie-Hellman group that has an
282: * attack complexity approximately the same as O(2**bits). Estimate
283: * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
284: */
285:
286: int
287: dh_estimate(int bits)
288: {
1.10.2.4 jason 289:
1.10.2.3 jason 290: if (bits < 64)
291: return (512); /* O(2**63) */
292: if (bits < 128)
293: return (1024); /* O(2**86) */
294: if (bits < 192)
295: return (2048); /* O(2**116) */
296: return (4096); /* O(2**156) */
297: }
298:
1.10.2.1 jason 299: void
1.10.2.3 jason 300: ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr,
301: Buffer *client_kexinit, Buffer *server_kexinit)
1.10.2.1 jason 302: {
1.10.2.3 jason 303: #ifdef DEBUG_KEXDH
304: int i;
305: #endif
306: int plen, dlen;
1.10.2.4 jason 307: u_int klen, kout;
1.10.2.3 jason 308: char *signature = NULL;
1.10.2.4 jason 309: u_int slen, nbits;
1.10.2.3 jason 310: char *server_host_key_blob = NULL;
311: Key *server_host_key;
1.10.2.4 jason 312: u_int sbloblen;
1.10.2.3 jason 313: DH *dh;
314: BIGNUM *dh_server_pub = 0;
315: BIGNUM *shared_secret = 0;
316: BIGNUM *p = 0, *g = 0;
1.10.2.4 jason 317: u_char *kbuf;
318: u_char *hash;
1.10.2.1 jason 319:
1.10.2.5! jason 320: nbits = dh_estimate(kex->we_need * 8);
1.10.2.1 jason 321:
1.10.2.3 jason 322: debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST.");
323: packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
324: packet_put_int(nbits);
325: packet_send();
326: packet_write_wait();
1.10.2.1 jason 327:
1.10.2.3 jason 328: #ifdef DEBUG_KEXDH
329: fprintf(stderr, "\nnbits = %d", nbits);
330: #endif
1.10.2.1 jason 331:
1.10.2.3 jason 332: debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP.");
1.10.2.1 jason 333:
1.10.2.3 jason 334: packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
1.1 markus 335:
1.10.2.3 jason 336: debug("Got SSH2_MSG_KEX_DH_GEX_GROUP.");
1.1 markus 337:
1.10.2.3 jason 338: if ((p = BN_new()) == NULL)
339: fatal("BN_new");
340: packet_get_bignum2(p, &dlen);
341: if ((g = BN_new()) == NULL)
342: fatal("BN_new");
343: packet_get_bignum2(g, &dlen);
1.10.2.4 jason 344: dh = dh_new_group(g, p);
345:
1.10.2.5! jason 346: dh_gen_key(dh, kex->we_need * 8);
1.1 markus 347:
348: #ifdef DEBUG_KEXDH
1.10.2.3 jason 349: fprintf(stderr, "\np= ");
350: BN_print_fp(stderr, dh->p);
351: fprintf(stderr, "\ng= ");
352: BN_print_fp(stderr, dh->g);
353: fprintf(stderr, "\npub= ");
354: BN_print_fp(stderr, dh->pub_key);
355: fprintf(stderr, "\n");
356: DHparams_print_fp(stderr, dh);
357: #endif
358:
359: debug("Sending SSH2_MSG_KEX_DH_GEX_INIT.");
360: /* generate and send 'e', client DH public key */
361: packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
362: packet_put_bignum2(dh->pub_key);
1.1 markus 363: packet_send();
364: packet_write_wait();
1.10.2.3 jason 365:
366: debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY.");
367:
368: packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
369:
370: debug("Got SSH2_MSG_KEXDH_REPLY.");
371:
372: /* key, cert */
373: server_host_key_blob = packet_get_string(&sbloblen);
1.10.2.4 jason 374: server_host_key = key_from_blob(server_host_key_blob, sbloblen);
1.10.2.3 jason 375: if (server_host_key == NULL)
376: fatal("cannot decode server_host_key_blob");
377:
378: check_host_key(host, hostaddr, server_host_key,
379: options.user_hostfile2, options.system_hostfile2);
380:
381: /* DH paramter f, server public DH key */
382: dh_server_pub = BN_new();
383: if (dh_server_pub == NULL)
384: fatal("dh_server_pub == NULL");
385: packet_get_bignum2(dh_server_pub, &dlen);
386:
387: #ifdef DEBUG_KEXDH
388: fprintf(stderr, "\ndh_server_pub= ");
389: BN_print_fp(stderr, dh_server_pub);
390: fprintf(stderr, "\n");
391: debug("bits %d", BN_num_bits(dh_server_pub));
1.1 markus 392: #endif
1.10.2.3 jason 393:
394: /* signed H */
395: signature = packet_get_string(&slen);
396: packet_done();
397:
398: if (!dh_pub_is_valid(dh, dh_server_pub))
399: packet_disconnect("bad server public DH value");
400:
401: klen = DH_size(dh);
402: kbuf = xmalloc(klen);
403: kout = DH_compute_key(kbuf, dh_server_pub, dh);
404: #ifdef DEBUG_KEXDH
405: debug("shared secret: len %d/%d", klen, kout);
406: fprintf(stderr, "shared secret == ");
407: for (i = 0; i< kout; i++)
408: fprintf(stderr, "%02x", (kbuf[i])&0xff);
409: fprintf(stderr, "\n");
410: #endif
411: shared_secret = BN_new();
412:
413: BN_bin2bn(kbuf, kout, shared_secret);
414: memset(kbuf, 0, klen);
415: xfree(kbuf);
416:
417: /* calc and verify H */
418: hash = kex_hash_gex(
419: client_version_string,
420: server_version_string,
421: buffer_ptr(client_kexinit), buffer_len(client_kexinit),
422: buffer_ptr(server_kexinit), buffer_len(server_kexinit),
423: server_host_key_blob, sbloblen,
1.10.2.4 jason 424: nbits, dh->p, dh->g,
1.10.2.3 jason 425: dh->pub_key,
426: dh_server_pub,
427: shared_secret
428: );
429: xfree(server_host_key_blob);
430: DH_free(dh);
1.10.2.4 jason 431: BN_free(dh_server_pub);
1.10.2.3 jason 432: #ifdef DEBUG_KEXDH
433: fprintf(stderr, "hash == ");
434: for (i = 0; i< 20; i++)
435: fprintf(stderr, "%02x", (hash[i])&0xff);
436: fprintf(stderr, "\n");
437: #endif
1.10.2.4 jason 438: if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
439: fatal("key_verify failed for server_host_key");
1.10.2.3 jason 440: key_free(server_host_key);
1.10.2.4 jason 441: xfree(signature);
1.10.2.3 jason 442:
443: kex_derive_keys(kex, hash, shared_secret);
1.10.2.4 jason 444: BN_clear_free(shared_secret);
1.10.2.3 jason 445: packet_set_kex(kex);
446:
447: /* save session id */
448: session_id2_len = 20;
449: session_id2 = xmalloc(session_id2_len);
450: memcpy(session_id2, hash, session_id2_len);
1.1 markus 451: }
1.10.2.1 jason 452:
1.1 markus 453: /*
454: * Authenticate user
455: */
1.10.2.3 jason 456:
457: typedef struct Authctxt Authctxt;
458: typedef struct Authmethod Authmethod;
459:
460: typedef int sign_cb_fn(
461: Authctxt *authctxt, Key *key,
1.10.2.4 jason 462: u_char **sigp, int *lenp, u_char *data, int datalen);
1.10.2.3 jason 463:
464: struct Authctxt {
465: const char *server_user;
466: const char *host;
467: const char *service;
468: AuthenticationConnection *agent;
469: Authmethod *method;
470: int success;
1.10.2.5! jason 471: char *authlist;
! 472: Key *last_key;
! 473: sign_cb_fn *last_key_sign;
! 474: int last_key_hint;
1.10.2.3 jason 475: };
476: struct Authmethod {
477: char *name; /* string to compare against server's list */
478: int (*userauth)(Authctxt *authctxt);
479: int *enabled; /* flag in option struct that enables method */
480: int *batch_flag; /* flag in option struct that disables method */
481: };
482:
483: void input_userauth_success(int type, int plen, void *ctxt);
484: void input_userauth_failure(int type, int plen, void *ctxt);
1.10.2.4 jason 485: void input_userauth_banner(int type, int plen, void *ctxt);
1.10.2.3 jason 486: void input_userauth_error(int type, int plen, void *ctxt);
487: void input_userauth_info_req(int type, int plen, void *ctxt);
1.10.2.5! jason 488: void input_userauth_pk_ok(int type, int plen, void *ctxt);
1.10.2.3 jason 489:
490: int userauth_none(Authctxt *authctxt);
491: int userauth_pubkey(Authctxt *authctxt);
492: int userauth_passwd(Authctxt *authctxt);
493: int userauth_kbdint(Authctxt *authctxt);
494:
1.10.2.5! jason 495: void userauth(Authctxt *authctxt, char *authlist);
! 496:
! 497: int
! 498: sign_and_send_pubkey(Authctxt *authctxt, Key *k,
! 499: sign_cb_fn *sign_callback);
! 500: void clear_auth_state(Authctxt *authctxt);
! 501:
1.10.2.3 jason 502: Authmethod *authmethod_get(char *authlist);
503: Authmethod *authmethod_lookup(const char *name);
1.10.2.5! jason 504: char *authmethods_get(void);
1.10.2.3 jason 505:
506: Authmethod authmethods[] = {
507: {"publickey",
508: userauth_pubkey,
1.10.2.4 jason 509: &options.pubkey_authentication,
1.10.2.3 jason 510: NULL},
511: {"password",
512: userauth_passwd,
513: &options.password_authentication,
514: &options.batch_mode},
515: {"keyboard-interactive",
516: userauth_kbdint,
517: &options.kbd_interactive_authentication,
518: &options.batch_mode},
519: {"none",
520: userauth_none,
521: NULL,
522: NULL},
523: {NULL, NULL, NULL, NULL}
524: };
525:
526: void
527: ssh_userauth2(const char *server_user, char *host)
528: {
529: Authctxt authctxt;
530: int type;
531: int plen;
532:
1.10.2.4 jason 533: if (options.challenge_reponse_authentication)
534: options.kbd_interactive_authentication = 1;
535:
1.10.2.3 jason 536: debug("send SSH2_MSG_SERVICE_REQUEST");
537: packet_start(SSH2_MSG_SERVICE_REQUEST);
538: packet_put_cstring("ssh-userauth");
539: packet_send();
540: packet_write_wait();
541: type = packet_read(&plen);
542: if (type != SSH2_MSG_SERVICE_ACCEPT) {
543: fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
544: }
545: if (packet_remaining() > 0) {
546: char *reply = packet_get_string(&plen);
547: debug("service_accept: %s", reply);
548: xfree(reply);
549: } else {
550: debug("buggy server: service_accept w/o service");
551: }
552: packet_done();
553: debug("got SSH2_MSG_SERVICE_ACCEPT");
554:
1.10.2.5! jason 555: if (options.preferred_authentications == NULL)
! 556: options.preferred_authentications = authmethods_get();
! 557:
1.10.2.3 jason 558: /* setup authentication context */
559: authctxt.agent = ssh_get_authentication_connection();
560: authctxt.server_user = server_user;
561: authctxt.host = host;
562: authctxt.service = "ssh-connection"; /* service name */
563: authctxt.success = 0;
564: authctxt.method = authmethod_lookup("none");
1.10.2.5! jason 565: authctxt.authlist = NULL;
1.10.2.3 jason 566: if (authctxt.method == NULL)
567: fatal("ssh_userauth2: internal error: cannot send userauth none request");
568:
569: /* initial userauth request */
570: userauth_none(&authctxt);
571:
572: dispatch_init(&input_userauth_error);
573: dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
574: dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
1.10.2.4 jason 575: dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
1.10.2.3 jason 576: dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */
577:
578: if (authctxt.agent != NULL)
579: ssh_close_authentication_connection(authctxt.agent);
580:
1.10.2.4 jason 581: debug("ssh-userauth2 successful: method %s", authctxt.method->name);
1.10.2.3 jason 582: }
583: void
1.10.2.5! jason 584: userauth(Authctxt *authctxt, char *authlist)
! 585: {
! 586: if (authlist == NULL) {
! 587: authlist = authctxt->authlist;
! 588: } else {
! 589: if (authctxt->authlist)
! 590: xfree(authctxt->authlist);
! 591: authctxt->authlist = authlist;
! 592: }
! 593: for (;;) {
! 594: Authmethod *method = authmethod_get(authlist);
! 595: if (method == NULL)
! 596: fatal("Permission denied (%s).", authlist);
! 597: authctxt->method = method;
! 598: if (method->userauth(authctxt) != 0) {
! 599: debug2("we sent a %s packet, wait for reply", method->name);
! 600: break;
! 601: } else {
! 602: debug2("we did not send a packet, disable method");
! 603: method->enabled = NULL;
! 604: }
! 605: }
! 606: }
! 607: void
1.10.2.3 jason 608: input_userauth_error(int type, int plen, void *ctxt)
609: {
1.10.2.4 jason 610: fatal("input_userauth_error: bad message during authentication: "
611: "type %d", type);
612: }
613: void
614: input_userauth_banner(int type, int plen, void *ctxt)
615: {
616: char *msg, *lang;
617: debug3("input_userauth_banner");
618: msg = packet_get_string(NULL);
619: lang = packet_get_string(NULL);
620: fprintf(stderr, "%s", msg);
621: xfree(msg);
622: xfree(lang);
1.10.2.3 jason 623: }
624: void
625: input_userauth_success(int type, int plen, void *ctxt)
626: {
627: Authctxt *authctxt = ctxt;
628: if (authctxt == NULL)
629: fatal("input_userauth_success: no authentication context");
1.10.2.5! jason 630: if (authctxt->authlist)
! 631: xfree(authctxt->authlist);
! 632: clear_auth_state(authctxt);
1.10.2.3 jason 633: authctxt->success = 1; /* break out */
634: }
635: void
636: input_userauth_failure(int type, int plen, void *ctxt)
637: {
638: Authctxt *authctxt = ctxt;
639: char *authlist = NULL;
640: int partial;
641:
642: if (authctxt == NULL)
643: fatal("input_userauth_failure: no authentication context");
644:
645: authlist = packet_get_string(NULL);
646: partial = packet_get_char();
647: packet_done();
648:
649: if (partial != 0)
1.10.2.4 jason 650: log("Authenticated with partial success.");
1.10.2.3 jason 651: debug("authentications that can continue: %s", authlist);
652:
1.10.2.5! jason 653: clear_auth_state(authctxt);
! 654: userauth(authctxt, authlist);
! 655: }
! 656: void
! 657: input_userauth_pk_ok(int type, int plen, void *ctxt)
! 658: {
! 659: Authctxt *authctxt = ctxt;
! 660: Key *key = NULL;
! 661: Buffer b;
! 662: int alen, blen, pktype, sent = 0;
! 663: char *pkalg, *pkblob, *fp;
! 664:
! 665: if (authctxt == NULL)
! 666: fatal("input_userauth_pk_ok: no authentication context");
! 667: if (datafellows & SSH_BUG_PKOK) {
! 668: /* this is similar to SSH_BUG_PKAUTH */
! 669: debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
! 670: pkblob = packet_get_string(&blen);
! 671: buffer_init(&b);
! 672: buffer_append(&b, pkblob, blen);
! 673: pkalg = buffer_get_string(&b, &alen);
! 674: buffer_free(&b);
! 675: } else {
! 676: pkalg = packet_get_string(&alen);
! 677: pkblob = packet_get_string(&blen);
! 678: }
! 679: packet_done();
! 680:
! 681: debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d",
! 682: pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
! 683:
! 684: do {
! 685: if (authctxt->last_key == NULL ||
! 686: authctxt->last_key_sign == NULL) {
! 687: debug("no last key or no sign cb");
1.10.2.3 jason 688: break;
689: }
1.10.2.5! jason 690: if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
! 691: debug("unknown pkalg %s", pkalg);
! 692: break;
! 693: }
! 694: if ((key = key_from_blob(pkblob, blen)) == NULL) {
! 695: debug("no key from blob. pkalg %s", pkalg);
! 696: break;
! 697: }
! 698: fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
! 699: debug2("input_userauth_pk_ok: fp %s", fp);
! 700: xfree(fp);
! 701: if (!key_equal(key, authctxt->last_key)) {
! 702: debug("key != last_key");
! 703: break;
! 704: }
! 705: sent = sign_and_send_pubkey(authctxt, key,
! 706: authctxt->last_key_sign);
! 707: } while(0);
! 708:
! 709: if (key != NULL)
! 710: key_free(key);
! 711: xfree(pkalg);
! 712: xfree(pkblob);
! 713:
! 714: /* unregister */
! 715: clear_auth_state(authctxt);
! 716: dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);
! 717:
! 718: /* try another method if we did not send a packet*/
! 719: if (sent == 0)
! 720: userauth(authctxt, NULL);
! 721:
1.10.2.3 jason 722: }
723:
1.1 markus 724: int
1.10.2.3 jason 725: userauth_none(Authctxt *authctxt)
726: {
727: /* initial userauth request */
728: packet_start(SSH2_MSG_USERAUTH_REQUEST);
729: packet_put_cstring(authctxt->server_user);
730: packet_put_cstring(authctxt->service);
731: packet_put_cstring(authctxt->method->name);
732: packet_send();
733: return 1;
734: }
735:
736: int
737: userauth_passwd(Authctxt *authctxt)
1.1 markus 738: {
1.6 markus 739: static int attempt = 0;
1.1 markus 740: char prompt[80];
741: char *password;
1.6 markus 742:
1.10.2.1 jason 743: if (attempt++ >= options.number_of_password_prompts)
1.6 markus 744: return 0;
1.10.2.1 jason 745:
746: if(attempt != 1)
747: error("Permission denied, please try again.");
1.1 markus 748:
1.10.2.4 jason 749: snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
1.10.2.3 jason 750: authctxt->server_user, authctxt->host);
1.1 markus 751: password = read_passphrase(prompt, 0);
752: packet_start(SSH2_MSG_USERAUTH_REQUEST);
1.10.2.3 jason 753: packet_put_cstring(authctxt->server_user);
754: packet_put_cstring(authctxt->service);
755: packet_put_cstring(authctxt->method->name);
1.1 markus 756: packet_put_char(0);
1.10.2.5! jason 757: packet_put_cstring(password);
1.1 markus 758: memset(password, 0, strlen(password));
759: xfree(password);
1.10.2.5! jason 760: packet_inject_ignore(64);
1.1 markus 761: packet_send();
762: return 1;
763: }
764:
1.10.2.5! jason 765: void
! 766: clear_auth_state(Authctxt *authctxt)
! 767: {
! 768: /* XXX clear authentication state */
! 769: if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
! 770: debug3("clear_auth_state: key_free %p", authctxt->last_key);
! 771: key_free(authctxt->last_key);
! 772: }
! 773: authctxt->last_key = NULL;
! 774: authctxt->last_key_hint = -2;
! 775: authctxt->last_key_sign = NULL;
! 776: }
! 777:
1.1 markus 778: int
1.10.2.3 jason 779: sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
1.1 markus 780: {
781: Buffer b;
1.10.2.4 jason 782: u_char *blob, *signature;
1.1 markus 783: int bloblen, slen;
1.10.2.2 jason 784: int skip = 0;
785: int ret = -1;
1.10.2.3 jason 786: int have_sig = 1;
1.1 markus 787:
1.10.2.4 jason 788: debug3("sign_and_send_pubkey");
1.10.2.5! jason 789:
1.10.2.4 jason 790: if (key_to_blob(k, &blob, &bloblen) == 0) {
791: /* we cannot handle this key */
792: debug3("sign_and_send_pubkey: cannot handle key");
793: return 0;
794: }
1.1 markus 795: /* data to be signed */
796: buffer_init(&b);
1.10.2.3 jason 797: if (datafellows & SSH_OLD_SESSIONID) {
1.10.2.2 jason 798: buffer_append(&b, session_id2, session_id2_len);
1.10.2.4 jason 799: skip = session_id2_len;
1.10.2.3 jason 800: } else {
801: buffer_put_string(&b, session_id2, session_id2_len);
802: skip = buffer_len(&b);
1.10.2.2 jason 803: }
1.1 markus 804: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.10.2.3 jason 805: buffer_put_cstring(&b, authctxt->server_user);
1.10 markus 806: buffer_put_cstring(&b,
1.10.2.4 jason 807: datafellows & SSH_BUG_PKSERVICE ?
1.10 markus 808: "ssh-userauth" :
1.10.2.3 jason 809: authctxt->service);
1.10.2.4 jason 810: if (datafellows & SSH_BUG_PKAUTH) {
811: buffer_put_char(&b, have_sig);
812: } else {
813: buffer_put_cstring(&b, authctxt->method->name);
814: buffer_put_char(&b, have_sig);
815: buffer_put_cstring(&b, key_ssh_name(k));
816: }
1.1 markus 817: buffer_put_string(&b, blob, bloblen);
818:
819: /* generate signature */
1.10.2.5! jason 820: ret = (*sign_callback)(authctxt, k, &signature, &slen,
! 821: buffer_ptr(&b), buffer_len(&b));
1.10.2.2 jason 822: if (ret == -1) {
823: xfree(blob);
824: buffer_free(&b);
825: return 0;
826: }
1.10.2.4 jason 827: #ifdef DEBUG_PK
1.1 markus 828: buffer_dump(&b);
829: #endif
1.10.2.4 jason 830: if (datafellows & SSH_BUG_PKSERVICE) {
1.10 markus 831: buffer_clear(&b);
832: buffer_append(&b, session_id2, session_id2_len);
1.10.2.5! jason 833: skip = session_id2_len;
1.10 markus 834: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.10.2.3 jason 835: buffer_put_cstring(&b, authctxt->server_user);
836: buffer_put_cstring(&b, authctxt->service);
837: buffer_put_cstring(&b, authctxt->method->name);
838: buffer_put_char(&b, have_sig);
1.10.2.4 jason 839: if (!(datafellows & SSH_BUG_PKAUTH))
840: buffer_put_cstring(&b, key_ssh_name(k));
1.10 markus 841: buffer_put_string(&b, blob, bloblen);
842: }
843: xfree(blob);
1.10.2.5! jason 844:
1.1 markus 845: /* append signature */
846: buffer_put_string(&b, signature, slen);
847: xfree(signature);
848:
849: /* skip session id and packet type */
1.10.2.2 jason 850: if (buffer_len(&b) < skip + 1)
1.10.2.3 jason 851: fatal("userauth_pubkey: internal error");
1.10.2.2 jason 852: buffer_consume(&b, skip + 1);
1.1 markus 853:
854: /* put remaining data from buffer into packet */
855: packet_start(SSH2_MSG_USERAUTH_REQUEST);
856: packet_put_raw(buffer_ptr(&b), buffer_len(&b));
857: buffer_free(&b);
858: packet_send();
1.10.2.2 jason 859:
1.1 markus 860: return 1;
861: }
862:
1.10.2.5! jason 863: int
! 864: send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
! 865: int hint)
1.10.2.3 jason 866: {
1.10.2.5! jason 867: u_char *blob;
! 868: int bloblen, have_sig = 0;
! 869:
! 870: debug3("send_pubkey_test");
! 871:
! 872: if (key_to_blob(k, &blob, &bloblen) == 0) {
! 873: /* we cannot handle this key */
! 874: debug3("send_pubkey_test: cannot handle key");
! 875: return 0;
! 876: }
! 877: /* register callback for USERAUTH_PK_OK message */
! 878: authctxt->last_key_sign = sign_callback;
! 879: authctxt->last_key_hint = hint;
! 880: authctxt->last_key = k;
! 881: dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
! 882:
! 883: packet_start(SSH2_MSG_USERAUTH_REQUEST);
! 884: packet_put_cstring(authctxt->server_user);
! 885: packet_put_cstring(authctxt->service);
! 886: packet_put_cstring(authctxt->method->name);
! 887: packet_put_char(have_sig);
! 888: if (!(datafellows & SSH_BUG_PKAUTH))
! 889: packet_put_cstring(key_ssh_name(k));
! 890: packet_put_string(blob, bloblen);
! 891: xfree(blob);
! 892: packet_send();
! 893: return 1;
1.10.2.3 jason 894: }
895:
1.10.2.5! jason 896: Key *
! 897: load_identity_file(char *filename)
1.10.2.2 jason 898: {
1.10.2.5! jason 899: Key *private;
! 900: char prompt[300], *passphrase;
! 901: int success = 0, quit, i;
1.10.2.2 jason 902: struct stat st;
903:
1.10.2.5! jason 904: if (stat(filename, &st) < 0) {
! 905: debug3("no such identity: %s", filename);
! 906: return NULL;
1.10.2.2 jason 907: }
1.10.2.5! jason 908: private = key_new(KEY_UNSPEC);
! 909: if (!load_private_key(filename, "", private, NULL)) {
1.10.2.4 jason 910: if (options.batch_mode) {
1.10.2.5! jason 911: key_free(private);
! 912: return NULL;
1.10.2.4 jason 913: }
1.10.2.2 jason 914: snprintf(prompt, sizeof prompt,
1.10.2.4 jason 915: "Enter passphrase for key '%.100s': ", filename);
1.10.2.3 jason 916: for (i = 0; i < options.number_of_password_prompts; i++) {
917: passphrase = read_passphrase(prompt, 0);
918: if (strcmp(passphrase, "") != 0) {
1.10.2.5! jason 919: success = load_private_key(filename,
! 920: passphrase, private, NULL);
! 921: quit = 0;
1.10.2.3 jason 922: } else {
923: debug2("no passphrase given, try next key");
1.10.2.5! jason 924: quit = 1;
1.10.2.3 jason 925: }
926: memset(passphrase, 0, strlen(passphrase));
927: xfree(passphrase);
1.10.2.5! jason 928: if (success || quit)
1.10.2.3 jason 929: break;
930: debug2("bad passphrase given, try again...");
931: }
1.10.2.2 jason 932: if (!success) {
1.10.2.5! jason 933: key_free(private);
! 934: return NULL;
1.10.2.2 jason 935: }
936: }
1.10.2.5! jason 937: return private;
! 938: }
! 939:
! 940: int
! 941: identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
! 942: u_char *data, int datalen)
! 943: {
! 944: Key *private;
! 945: int idx, ret;
! 946:
! 947: idx = authctxt->last_key_hint;
! 948: if (idx < 0)
! 949: return -1;
! 950: private = load_identity_file(options.identity_files[idx]);
! 951: if (private == NULL)
! 952: return -1;
! 953: ret = key_sign(private, sigp, lenp, data, datalen);
! 954: key_free(private);
1.10.2.2 jason 955: return ret;
956: }
957:
1.10.2.4 jason 958: int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
959: u_char *data, int datalen)
1.10.2.2 jason 960: {
1.10.2.3 jason 961: return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
1.10.2.2 jason 962: }
963:
1.10.2.5! jason 964: int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
! 965: u_char *data, int datalen)
! 966: {
! 967: return key_sign(key, sigp, lenp, data, datalen);
! 968: }
! 969:
1.10.2.2 jason 970: int
1.10.2.3 jason 971: userauth_pubkey_agent(Authctxt *authctxt)
1.10.2.2 jason 972: {
973: static int called = 0;
1.10.2.4 jason 974: int ret = 0;
1.10.2.2 jason 975: char *comment;
976: Key *k;
977:
978: if (called == 0) {
1.10.2.4 jason 979: if (ssh_get_num_identities(authctxt->agent, 2) == 0)
980: debug2("userauth_pubkey_agent: no keys at all");
1.10.2.3 jason 981: called = 1;
1.10.2.2 jason 982: }
1.10.2.4 jason 983: k = ssh_get_next_identity(authctxt->agent, &comment, 2);
1.10.2.3 jason 984: if (k == NULL) {
1.10.2.4 jason 985: debug2("userauth_pubkey_agent: no more keys");
986: } else {
1.10.2.5! jason 987: debug("userauth_pubkey_agent: testing agent key %s", comment);
1.10.2.4 jason 988: xfree(comment);
1.10.2.5! jason 989: ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
! 990: if (ret == 0)
! 991: key_free(k);
1.10.2.3 jason 992: }
1.10.2.4 jason 993: if (ret == 0)
994: debug2("userauth_pubkey_agent: no message sent");
1.10.2.2 jason 995: return ret;
996: }
997:
1.10.2.3 jason 998: int
999: userauth_pubkey(Authctxt *authctxt)
1.1 markus 1000: {
1.10.2.3 jason 1001: static int idx = 0;
1002: int sent = 0;
1.10.2.5! jason 1003: Key *key;
! 1004: char *filename;
1.1 markus 1005:
1.10.2.4 jason 1006: if (authctxt->agent != NULL) {
1007: do {
1008: sent = userauth_pubkey_agent(authctxt);
1009: } while(!sent && authctxt->agent->howmany > 0);
1010: }
1011: while (!sent && idx < options.num_identity_files) {
1.10.2.5! jason 1012: key = options.identity_keys[idx];
! 1013: filename = options.identity_files[idx];
! 1014: if (key == NULL) {
! 1015: debug("try privkey: %s", filename);
! 1016: key = load_identity_file(filename);
! 1017: if (key != NULL) {
! 1018: sent = sign_and_send_pubkey(authctxt, key,
! 1019: key_sign_cb);
! 1020: key_free(key);
! 1021: }
! 1022: } else if (key->type != KEY_RSA1) {
! 1023: debug("try pubkey: %s", filename);
! 1024: sent = send_pubkey_test(authctxt, key,
! 1025: identity_sign_cb, idx);
! 1026: }
1.10.2.4 jason 1027: idx++;
1028: }
1.10.2.3 jason 1029: return sent;
1030: }
1031:
1032: /*
1033: * Send userauth request message specifying keyboard-interactive method.
1034: */
1035: int
1036: userauth_kbdint(Authctxt *authctxt)
1037: {
1038: static int attempt = 0;
1039:
1040: if (attempt++ >= options.number_of_password_prompts)
1041: return 0;
1042:
1043: debug2("userauth_kbdint");
1044: packet_start(SSH2_MSG_USERAUTH_REQUEST);
1045: packet_put_cstring(authctxt->server_user);
1046: packet_put_cstring(authctxt->service);
1047: packet_put_cstring(authctxt->method->name);
1048: packet_put_cstring(""); /* lang */
1049: packet_put_cstring(options.kbd_interactive_devices ?
1050: options.kbd_interactive_devices : "");
1.1 markus 1051: packet_send();
1052:
1.10.2.3 jason 1053: dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
1054: return 1;
1055: }
1056:
1057: /*
1.10.2.4 jason 1058: * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
1.10.2.3 jason 1059: */
1060: void
1061: input_userauth_info_req(int type, int plen, void *ctxt)
1062: {
1063: Authctxt *authctxt = ctxt;
1.10.2.4 jason 1064: char *name, *inst, *lang, *prompt, *response;
1065: u_int num_prompts, i;
1.10.2.3 jason 1066: int echo = 0;
1067:
1068: debug2("input_userauth_info_req");
1069:
1070: if (authctxt == NULL)
1071: fatal("input_userauth_info_req: no authentication context");
1072:
1073: name = packet_get_string(NULL);
1074: inst = packet_get_string(NULL);
1075: lang = packet_get_string(NULL);
1076: if (strlen(name) > 0)
1077: cli_mesg(name);
1078: if (strlen(inst) > 0)
1079: cli_mesg(inst);
1.10.2.4 jason 1080: xfree(name);
1.10.2.3 jason 1081: xfree(inst);
1.10.2.4 jason 1082: xfree(lang);
1.10.2.3 jason 1083:
1084: num_prompts = packet_get_int();
1085: /*
1086: * Begin to build info response packet based on prompts requested.
1087: * We commit to providing the correct number of responses, so if
1088: * further on we run into a problem that prevents this, we have to
1089: * be sure and clean this up and send a correct error response.
1090: */
1091: packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
1092: packet_put_int(num_prompts);
1093:
1094: for (i = 0; i < num_prompts; i++) {
1095: prompt = packet_get_string(NULL);
1096: echo = packet_get_char();
1097:
1098: response = cli_prompt(prompt, echo);
1099:
1.10.2.5! jason 1100: packet_put_cstring(response);
1.10.2.3 jason 1101: memset(response, 0, strlen(response));
1102: xfree(response);
1103: xfree(prompt);
1.1 markus 1104: }
1.10.2.3 jason 1105: packet_done(); /* done with parsing incoming message. */
1.1 markus 1106:
1.10.2.5! jason 1107: packet_inject_ignore(64);
1.1 markus 1108: packet_send();
1.10.2.3 jason 1109: }
1.1 markus 1110:
1.10.2.3 jason 1111: /* find auth method */
1112:
1113: /*
1114: * given auth method name, if configurable options permit this method fill
1115: * in auth_ident field and return true, otherwise return false.
1116: */
1117: int
1118: authmethod_is_enabled(Authmethod *method)
1119: {
1120: if (method == NULL)
1121: return 0;
1122: /* return false if options indicate this method is disabled */
1123: if (method->enabled == NULL || *method->enabled == 0)
1124: return 0;
1125: /* return false if batch mode is enabled but method needs interactive mode */
1126: if (method->batch_flag != NULL && *method->batch_flag != 0)
1127: return 0;
1128: return 1;
1129: }
1130:
1131: Authmethod *
1132: authmethod_lookup(const char *name)
1133: {
1134: Authmethod *method = NULL;
1135: if (name != NULL)
1136: for (method = authmethods; method->name != NULL; method++)
1137: if (strcmp(name, method->name) == 0)
1138: return method;
1139: debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
1140: return NULL;
1141: }
1142:
1.10.2.5! jason 1143: /* XXX internal state */
! 1144: static Authmethod *current = NULL;
! 1145: static char *supported = NULL;
! 1146: static char *preferred = NULL;
1.10.2.3 jason 1147: /*
1148: * Given the authentication method list sent by the server, return the
1149: * next method we should try. If the server initially sends a nil list,
1.10.2.5! jason 1150: * use a built-in default list.
1.10.2.4 jason 1151: */
1.10.2.3 jason 1152: Authmethod *
1153: authmethod_get(char *authlist)
1154: {
1.10.2.5! jason 1155:
! 1156: char *name = NULL;
! 1157: int next;
1.10.2.4 jason 1158:
1.10.2.3 jason 1159: /* Use a suitable default if we're passed a nil list. */
1160: if (authlist == NULL || strlen(authlist) == 0)
1.10.2.5! jason 1161: authlist = options.preferred_authentications;
1.10.2.3 jason 1162:
1.10.2.5! jason 1163: if (supported == NULL || strcmp(authlist, supported) != 0) {
! 1164: debug3("start over, passed a different list %s", authlist);
! 1165: if (supported != NULL)
! 1166: xfree(supported);
! 1167: supported = xstrdup(authlist);
! 1168: preferred = options.preferred_authentications;
! 1169: debug3("preferred %s", preferred);
! 1170: current = NULL;
! 1171: } else if (current != NULL && authmethod_is_enabled(current))
! 1172: return current;
1.10.2.3 jason 1173:
1.10.2.5! jason 1174: for (;;) {
! 1175: if ((name = match_list(preferred, supported, &next)) == NULL) {
! 1176: debug("no more auth methods to try");
! 1177: current = NULL;
! 1178: return NULL;
! 1179: }
! 1180: preferred += next;
1.10.2.3 jason 1181: debug3("authmethod_lookup %s", name);
1.10.2.5! jason 1182: debug3("remaining preferred: %s", preferred);
! 1183: if ((current = authmethod_lookup(name)) != NULL &&
! 1184: authmethod_is_enabled(current)) {
1.10.2.3 jason 1185: debug3("authmethod_is_enabled %s", name);
1.10.2.5! jason 1186: debug("next auth method to try is %s", name);
! 1187: return current;
1.1 markus 1188: }
1189: }
1.10.2.5! jason 1190: }
1.10.2.3 jason 1191:
1192:
1.10.2.5! jason 1193: #define DELIM ","
! 1194: char *
! 1195: authmethods_get(void)
! 1196: {
! 1197: Authmethod *method = NULL;
! 1198: char buf[1024];
1.10.2.3 jason 1199:
1.10.2.5! jason 1200: buf[0] = '\0';
! 1201: for (method = authmethods; method->name != NULL; method++) {
! 1202: if (authmethod_is_enabled(method)) {
! 1203: if (buf[0] != '\0')
! 1204: strlcat(buf, DELIM, sizeof buf);
! 1205: strlcat(buf, method->name, sizeof buf);
! 1206: }
! 1207: }
! 1208: return xstrdup(buf);
1.1 markus 1209: }