Annotation of src/usr.bin/ssh/sshconnect2.c, Revision 1.21
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.21 ! markus 26: RCSID("$OpenBSD: sshconnect2.c,v 1.20 2000/09/21 11:25:07 markus Exp $");
1.1 markus 27:
28: #include <openssl/bn.h>
29: #include <openssl/rsa.h>
30: #include <openssl/dsa.h>
31: #include <openssl/md5.h>
32: #include <openssl/dh.h>
33: #include <openssl/hmac.h>
34:
35: #include "ssh.h"
36: #include "xmalloc.h"
37: #include "rsa.h"
38: #include "buffer.h"
39: #include "packet.h"
40: #include "cipher.h"
41: #include "uidswap.h"
42: #include "compat.h"
43: #include "readconf.h"
44: #include "bufaux.h"
45: #include "ssh2.h"
46: #include "kex.h"
47: #include "myproposal.h"
48: #include "key.h"
49: #include "dsa.h"
50: #include "sshconnect.h"
51: #include "authfile.h"
1.20 markus 52: #include "dispatch.h"
1.17 markus 53: #include "authfd.h"
1.1 markus 54:
55: /* import */
56: extern char *client_version_string;
57: extern char *server_version_string;
58: extern Options options;
59:
60: /*
61: * SSH2 key exchange
62: */
63:
64: unsigned char *session_id2 = NULL;
65: int session_id2_len = 0;
66:
67: void
1.11 markus 68: ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr,
69: Buffer *client_kexinit, Buffer *server_kexinit)
1.1 markus 70: {
1.19 markus 71: #ifdef DEBUG_KEXDH
72: int i;
73: #endif
1.11 markus 74: int plen, dlen;
1.1 markus 75: unsigned int klen, kout;
76: char *signature = NULL;
77: unsigned int slen;
78: char *server_host_key_blob = NULL;
79: Key *server_host_key;
80: unsigned int sbloblen;
81: DH *dh;
82: BIGNUM *dh_server_pub = 0;
83: BIGNUM *shared_secret = 0;
84: unsigned char *kbuf;
85: unsigned char *hash;
86:
87: debug("Sending SSH2_MSG_KEXDH_INIT.");
88: /* generate and send 'e', client DH public key */
89: dh = dh_new_group1();
90: packet_start(SSH2_MSG_KEXDH_INIT);
91: packet_put_bignum2(dh->pub_key);
92: packet_send();
93: packet_write_wait();
94:
95: #ifdef DEBUG_KEXDH
96: fprintf(stderr, "\np= ");
1.19 markus 97: BN_print_fp(stderr, dh->p);
1.1 markus 98: fprintf(stderr, "\ng= ");
1.19 markus 99: BN_print_fp(stderr, dh->g);
1.1 markus 100: fprintf(stderr, "\npub= ");
1.19 markus 101: BN_print_fp(stderr, dh->pub_key);
1.1 markus 102: fprintf(stderr, "\n");
103: DHparams_print_fp(stderr, dh);
104: #endif
105:
106: debug("Wait SSH2_MSG_KEXDH_REPLY.");
107:
1.11 markus 108: packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY);
1.1 markus 109:
110: debug("Got SSH2_MSG_KEXDH_REPLY.");
111:
112: /* key, cert */
113: server_host_key_blob = packet_get_string(&sbloblen);
114: server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen);
115: if (server_host_key == NULL)
116: fatal("cannot decode server_host_key_blob");
117:
118: check_host_key(host, hostaddr, server_host_key,
119: options.user_hostfile2, options.system_hostfile2);
120:
121: /* DH paramter f, server public DH key */
122: dh_server_pub = BN_new();
123: if (dh_server_pub == NULL)
124: fatal("dh_server_pub == NULL");
125: packet_get_bignum2(dh_server_pub, &dlen);
126:
127: #ifdef DEBUG_KEXDH
128: fprintf(stderr, "\ndh_server_pub= ");
1.19 markus 129: BN_print_fp(stderr, dh_server_pub);
1.1 markus 130: fprintf(stderr, "\n");
131: debug("bits %d", BN_num_bits(dh_server_pub));
132: #endif
133:
134: /* signed H */
135: signature = packet_get_string(&slen);
136: packet_done();
137:
138: if (!dh_pub_is_valid(dh, dh_server_pub))
139: packet_disconnect("bad server public DH value");
140:
141: klen = DH_size(dh);
142: kbuf = xmalloc(klen);
143: kout = DH_compute_key(kbuf, dh_server_pub, dh);
144: #ifdef DEBUG_KEXDH
145: debug("shared secret: len %d/%d", klen, kout);
146: fprintf(stderr, "shared secret == ");
147: for (i = 0; i< kout; i++)
148: fprintf(stderr, "%02x", (kbuf[i])&0xff);
149: fprintf(stderr, "\n");
150: #endif
151: shared_secret = BN_new();
152:
153: BN_bin2bn(kbuf, kout, shared_secret);
154: memset(kbuf, 0, klen);
155: xfree(kbuf);
156:
157: /* calc and verify H */
158: hash = kex_hash(
159: client_version_string,
160: server_version_string,
161: buffer_ptr(client_kexinit), buffer_len(client_kexinit),
162: buffer_ptr(server_kexinit), buffer_len(server_kexinit),
163: server_host_key_blob, sbloblen,
164: dh->pub_key,
165: dh_server_pub,
166: shared_secret
167: );
1.3 markus 168: xfree(server_host_key_blob);
1.11 markus 169: DH_free(dh);
1.1 markus 170: #ifdef DEBUG_KEXDH
171: fprintf(stderr, "hash == ");
172: for (i = 0; i< 20; i++)
173: fprintf(stderr, "%02x", (hash[i])&0xff);
174: fprintf(stderr, "\n");
175: #endif
176: if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
177: fatal("dsa_verify failed for server_host_key");
178: key_free(server_host_key);
179:
180: kex_derive_keys(kex, hash, shared_secret);
181: packet_set_kex(kex);
182:
183: /* save session id */
184: session_id2_len = 20;
185: session_id2 = xmalloc(session_id2_len);
186: memcpy(session_id2, hash, session_id2_len);
1.11 markus 187: }
188:
189: void
190: ssh_kex2(char *host, struct sockaddr *hostaddr)
191: {
192: int i, plen;
193: Kex *kex;
194: Buffer *client_kexinit, *server_kexinit;
195: char *sprop[PROPOSAL_MAX];
196:
197: if (options.ciphers != NULL) {
198: myproposal[PROPOSAL_ENC_ALGS_CTOS] =
199: myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
200: } else if (options.cipher == SSH_CIPHER_3DES) {
201: myproposal[PROPOSAL_ENC_ALGS_CTOS] =
202: myproposal[PROPOSAL_ENC_ALGS_STOC] =
203: (char *) cipher_name(SSH_CIPHER_3DES_CBC);
204: } else if (options.cipher == SSH_CIPHER_BLOWFISH) {
205: myproposal[PROPOSAL_ENC_ALGS_CTOS] =
206: myproposal[PROPOSAL_ENC_ALGS_STOC] =
207: (char *) cipher_name(SSH_CIPHER_BLOWFISH_CBC);
208: }
209: if (options.compression) {
210: myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
211: myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
212: } else {
213: myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
214: myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
215: }
216:
217: /* buffers with raw kexinit messages */
218: server_kexinit = xmalloc(sizeof(*server_kexinit));
219: buffer_init(server_kexinit);
220: client_kexinit = kex_init(myproposal);
221:
222: /* algorithm negotiation */
223: kex_exchange_kexinit(client_kexinit, server_kexinit, sprop);
224: kex = kex_choose_conf(myproposal, sprop, 0);
225: for (i = 0; i < PROPOSAL_MAX; i++)
226: xfree(sprop[i]);
227:
228: /* server authentication and session key agreement */
229: ssh_kex_dh(kex, host, hostaddr, client_kexinit, server_kexinit);
230:
231: buffer_free(client_kexinit);
232: buffer_free(server_kexinit);
233: xfree(client_kexinit);
234: xfree(server_kexinit);
1.1 markus 235:
236: debug("Wait SSH2_MSG_NEWKEYS.");
1.11 markus 237: packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
1.1 markus 238: packet_done();
239: debug("GOT SSH2_MSG_NEWKEYS.");
240:
241: debug("send SSH2_MSG_NEWKEYS.");
242: packet_start(SSH2_MSG_NEWKEYS);
243: packet_send();
244: packet_write_wait();
245: debug("done: send SSH2_MSG_NEWKEYS.");
246:
247: #ifdef DEBUG_KEXDH
248: /* send 1st encrypted/maced/compressed message */
249: packet_start(SSH2_MSG_IGNORE);
250: packet_put_cstring("markus");
251: packet_send();
252: packet_write_wait();
253: #endif
254: debug("done: KEX2.");
255: }
1.11 markus 256:
1.1 markus 257: /*
258: * Authenticate user
259: */
1.20 markus 260:
261: typedef struct Authctxt Authctxt;
262: typedef struct Authmethod Authmethod;
263:
264: typedef int sign_cb_fn(
265: Authctxt *authctxt, Key *key,
266: unsigned char **sigp, int *lenp, unsigned char *data, int datalen);
267:
268: struct Authctxt {
269: const char *server_user;
270: const char *host;
271: const char *service;
272: AuthenticationConnection *agent;
273: int success;
274: Authmethod *method;
275: };
276: struct Authmethod {
277: char *name; /* string to compare against server's list */
278: int (*userauth)(Authctxt *authctxt);
279: int *enabled; /* flag in option struct that enables method */
280: int *batch_flag; /* flag in option struct that disables method */
281: };
282:
283: void input_userauth_success(int type, int plen, void *ctxt);
284: void input_userauth_failure(int type, int plen, void *ctxt);
285: void input_userauth_error(int type, int plen, void *ctxt);
286: int userauth_pubkey(Authctxt *authctxt);
287: int userauth_passwd(Authctxt *authctxt);
288:
289: void authmethod_clear();
290: Authmethod *authmethod_get(char *auth_list);
291:
292: Authmethod authmethods[] = {
293: {"publickey",
294: userauth_pubkey,
295: &options.dsa_authentication,
296: NULL},
297: {"password",
298: userauth_passwd,
299: &options.password_authentication,
300: &options.batch_mode},
301: {NULL, NULL, NULL, NULL}
302: };
303:
304: void
305: ssh_userauth2(const char *server_user, char *host)
306: {
307: Authctxt authctxt;
308: int type;
309: int plen;
310:
311: debug("send SSH2_MSG_SERVICE_REQUEST");
312: packet_start(SSH2_MSG_SERVICE_REQUEST);
313: packet_put_cstring("ssh-userauth");
314: packet_send();
315: packet_write_wait();
316: type = packet_read(&plen);
317: if (type != SSH2_MSG_SERVICE_ACCEPT) {
318: fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
319: }
320: if (packet_remaining() > 0) {
321: char *reply = packet_get_string(&plen);
322: debug("service_accept: %s", reply);
323: xfree(reply);
324: packet_done();
325: } else {
326: debug("buggy server: service_accept w/o service");
327: }
328: packet_done();
329: debug("got SSH2_MSG_SERVICE_ACCEPT");
330:
331: /* setup authentication context */
332: authctxt.agent = ssh_get_authentication_connection();
333: authctxt.server_user = server_user;
334: authctxt.host = host;
335: authctxt.service = "ssh-connection"; /* service name */
336: authctxt.success = 0;
337: authctxt.method = NULL;
338:
339: /* initial userauth request */
340: packet_start(SSH2_MSG_USERAUTH_REQUEST);
341: packet_put_cstring(authctxt.server_user);
342: packet_put_cstring(authctxt.service);
343: packet_put_cstring("none");
344: packet_send();
345: packet_write_wait();
346:
347: authmethod_clear();
348:
349: dispatch_init(&input_userauth_error);
350: dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
351: dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
352: dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */
353:
354: if (authctxt.agent != NULL)
355: ssh_close_authentication_connection(authctxt.agent);
356:
357: debug("ssh-userauth2 successfull");
358: }
359: void
360: input_userauth_error(int type, int plen, void *ctxt)
361: {
362: fatal("input_userauth_error: bad message during authentication");
363: }
364: void
365: input_userauth_success(int type, int plen, void *ctxt)
366: {
367: Authctxt *authctxt = ctxt;
368: if (authctxt == NULL)
369: fatal("input_userauth_success: no authentication context");
370: authctxt->success = 1; /* break out */
371: }
372: void
373: input_userauth_failure(int type, int plen, void *ctxt)
374: {
375: Authmethod *method = NULL;
376: Authctxt *authctxt = ctxt;
377: char *authlist = NULL;
378: int partial;
379: int dlen;
380:
381: if (authctxt == NULL)
382: fatal("input_userauth_failure: no authentication context");
383:
384: authlist = packet_get_string(&dlen);
385: partial = packet_get_char();
386: packet_done();
387:
388: if (partial != 0)
389: debug("partial success");
390: debug("authentications that can continue: %s", authlist);
391:
392: for (;;) {
393: /* try old method or get next method */
394: method = authmethod_get(authlist);
395: if (method == NULL)
396: fatal("Unable to find an authentication method");
397: if (method->userauth(authctxt) != 0) {
398: debug2("we sent a packet, wait for reply");
399: break;
400: } else {
401: debug2("we did not send a packet, disable method");
402: method->enabled = NULL;
403: }
404: }
405: xfree(authlist);
406: }
407:
1.1 markus 408: int
1.20 markus 409: userauth_passwd(Authctxt *authctxt)
1.1 markus 410: {
1.6 markus 411: static int attempt = 0;
1.1 markus 412: char prompt[80];
413: char *password;
1.6 markus 414:
1.13 todd 415: if (attempt++ >= options.number_of_password_prompts)
1.6 markus 416: return 0;
1.13 todd 417:
418: if(attempt != 1)
419: error("Permission denied, please try again.");
1.1 markus 420:
421: snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
1.20 markus 422: authctxt->server_user, authctxt->host);
1.1 markus 423: password = read_passphrase(prompt, 0);
424: packet_start(SSH2_MSG_USERAUTH_REQUEST);
1.20 markus 425: packet_put_cstring(authctxt->server_user);
426: packet_put_cstring(authctxt->service);
1.1 markus 427: packet_put_cstring("password");
428: packet_put_char(0);
429: packet_put_cstring(password);
430: memset(password, 0, strlen(password));
431: xfree(password);
432: packet_send();
433: packet_write_wait();
434: return 1;
435: }
436:
1.17 markus 437: int
1.20 markus 438: sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
1.1 markus 439: {
440: Buffer b;
441: unsigned char *blob, *signature;
442: int bloblen, slen;
1.14 markus 443: int skip = 0;
1.17 markus 444: int ret = -1;
1.1 markus 445:
446: dsa_make_key_blob(k, &blob, &bloblen);
447:
448: /* data to be signed */
449: buffer_init(&b);
1.14 markus 450: if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
451: buffer_put_string(&b, session_id2, session_id2_len);
452: skip = buffer_len(&b);
453: } else {
454: buffer_append(&b, session_id2, session_id2_len);
455: skip = session_id2_len;
456: }
1.1 markus 457: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.20 markus 458: buffer_put_cstring(&b, authctxt->server_user);
1.10 markus 459: buffer_put_cstring(&b,
460: datafellows & SSH_BUG_PUBKEYAUTH ?
461: "ssh-userauth" :
1.20 markus 462: authctxt->service);
1.1 markus 463: buffer_put_cstring(&b, "publickey");
464: buffer_put_char(&b, 1);
465: buffer_put_cstring(&b, KEX_DSS);
466: buffer_put_string(&b, blob, bloblen);
467:
468: /* generate signature */
1.20 markus 469: ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
1.17 markus 470: if (ret == -1) {
471: xfree(blob);
472: buffer_free(&b);
473: return 0;
474: }
1.1 markus 475: #ifdef DEBUG_DSS
476: buffer_dump(&b);
477: #endif
1.10 markus 478: if (datafellows & SSH_BUG_PUBKEYAUTH) {
479: buffer_clear(&b);
480: buffer_append(&b, session_id2, session_id2_len);
481: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.20 markus 482: buffer_put_cstring(&b, authctxt->server_user);
483: buffer_put_cstring(&b, authctxt->service);
1.10 markus 484: buffer_put_cstring(&b, "publickey");
485: buffer_put_char(&b, 1);
486: buffer_put_cstring(&b, KEX_DSS);
487: buffer_put_string(&b, blob, bloblen);
488: }
489: xfree(blob);
1.1 markus 490: /* append signature */
491: buffer_put_string(&b, signature, slen);
492: xfree(signature);
493:
494: /* skip session id and packet type */
1.14 markus 495: if (buffer_len(&b) < skip + 1)
1.20 markus 496: fatal("userauth_pubkey: internal error");
1.14 markus 497: buffer_consume(&b, skip + 1);
1.1 markus 498:
499: /* put remaining data from buffer into packet */
500: packet_start(SSH2_MSG_USERAUTH_REQUEST);
501: packet_put_raw(buffer_ptr(&b), buffer_len(&b));
502: buffer_free(&b);
503:
504: /* send */
505: packet_send();
506: packet_write_wait();
1.17 markus 507:
508: return 1;
1.16 markus 509: }
510:
1.20 markus 511: /* sign callback */
512: int dsa_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp,
513: unsigned char *data, int datalen)
514: {
515: return dsa_sign(key, sigp, lenp, data, datalen);
516: }
517:
1.16 markus 518: int
1.20 markus 519: userauth_pubkey_identity(Authctxt *authctxt, char *filename)
1.16 markus 520: {
521: Key *k;
1.20 markus 522: int i, ret, try_next;
1.16 markus 523: struct stat st;
524:
525: if (stat(filename, &st) != 0) {
526: debug("key does not exist: %s", filename);
527: return 0;
528: }
529: debug("try pubkey: %s", filename);
530:
531: k = key_new(KEY_DSA);
532: if (!load_private_key(filename, "", k, NULL)) {
533: int success = 0;
534: char *passphrase;
535: char prompt[300];
536: snprintf(prompt, sizeof prompt,
1.21 ! markus 537: "Enter passphrase for %s key '%.100s': ",
! 538: key_type(k), filename);
1.20 markus 539: for (i = 0; i < options.number_of_password_prompts; i++) {
540: passphrase = read_passphrase(prompt, 0);
541: if (strcmp(passphrase, "") != 0) {
542: success = load_private_key(filename, passphrase, k, NULL);
543: try_next = 0;
544: } else {
545: debug2("no passphrase given, try next key");
546: try_next = 1;
547: }
548: memset(passphrase, 0, strlen(passphrase));
549: xfree(passphrase);
550: if (success || try_next)
551: break;
552: debug2("bad passphrase given, try again...");
553: }
1.16 markus 554: if (!success) {
555: key_free(k);
556: return 0;
557: }
558: }
1.20 markus 559: ret = sign_and_send_pubkey(authctxt, k, dsa_sign_cb);
1.17 markus 560: key_free(k);
561: return ret;
562: }
563:
1.20 markus 564: /* sign callback */
565: int agent_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp,
1.17 markus 566: unsigned char *data, int datalen)
567: {
1.20 markus 568: return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
1.17 markus 569: }
570:
571: int
1.20 markus 572: userauth_pubkey_agent(Authctxt *authctxt)
1.17 markus 573: {
574: static int called = 0;
575: char *comment;
576: Key *k;
577: int ret;
578:
579: if (called == 0) {
1.20 markus 580: k = ssh_get_first_identity(authctxt->agent, &comment, 2);
581: called = 1;
1.17 markus 582: } else {
1.20 markus 583: k = ssh_get_next_identity(authctxt->agent, &comment, 2);
1.17 markus 584: }
1.20 markus 585: if (k == NULL) {
586: debug2("no more DSA keys from agent");
1.17 markus 587: return 0;
1.20 markus 588: }
1.17 markus 589: debug("trying DSA agent key %s", comment);
590: xfree(comment);
1.20 markus 591: ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb);
1.17 markus 592: key_free(k);
593: return ret;
1.1 markus 594: }
595:
1.20 markus 596: int
597: userauth_pubkey(Authctxt *authctxt)
598: {
599: static int idx = 0;
600: int sent = 0;
601:
602: if (authctxt->agent != NULL)
603: sent = userauth_pubkey_agent(authctxt);
604: while (sent == 0 && idx < options.num_identity_files2)
605: sent = userauth_pubkey_identity(authctxt, options.identity_files2[idx++]);
606: return sent;
607: }
608:
609:
610: /* find auth method */
611:
612: #define DELIM ","
613:
614: static char *def_authlist = "publickey,password";
615: static char *authlist_current = NULL; /* clean copy used for comparison */
616: static char *authname_current = NULL; /* last used auth method */
617: static char *authlist_working = NULL; /* copy that gets modified by strtok_r() */
618: static char *authlist_state = NULL; /* state variable for strtok_r() */
619:
620: /*
621: * Before starting to use a new authentication method list sent by the
622: * server, reset internal variables. This should also be called when
623: * finished processing server list to free resources.
624: */
1.1 markus 625: void
1.20 markus 626: authmethod_clear()
627: {
628: if (authlist_current != NULL) {
629: xfree(authlist_current);
630: authlist_current = NULL;
631: }
632: if (authlist_working != NULL) {
633: xfree(authlist_working);
634: authlist_working = NULL;
635: }
636: if (authname_current != NULL) {
637: xfree(authname_current);
638: authlist_state = NULL;
639: }
640: if (authlist_state != NULL)
641: authlist_state = NULL;
642: return;
643: }
644:
645: /*
646: * given auth method name, if configurable options permit this method fill
647: * in auth_ident field and return true, otherwise return false.
648: */
649: int
650: authmethod_is_enabled(Authmethod *method)
651: {
652: if (method == NULL)
653: return 0;
654: /* return false if options indicate this method is disabled */
655: if (method->enabled == NULL || *method->enabled == 0)
656: return 0;
657: /* return false if batch mode is enabled but method needs interactive mode */
658: if (method->batch_flag != NULL && *method->batch_flag != 0)
659: return 0;
660: return 1;
661: }
662:
663: Authmethod *
664: authmethod_lookup(const char *name)
1.1 markus 665: {
1.20 markus 666: Authmethod *method = NULL;
667: if (name != NULL)
668: for (method = authmethods; method->name != NULL; method++)
669: if (strcmp(name, method->name) == 0)
670: return method;
671: debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
672: return NULL;
673: }
1.1 markus 674:
1.20 markus 675: /*
676: * Given the authentication method list sent by the server, return the
677: * next method we should try. If the server initially sends a nil list,
678: * use a built-in default list. If the server sends a nil list after
679: * previously sending a valid list, continue using the list originally
680: * sent.
681: */
1.1 markus 682:
1.20 markus 683: Authmethod *
684: authmethod_get(char *authlist)
685: {
686: char *name = NULL;
687: Authmethod *method = NULL;
688:
689: /* Use a suitable default if we're passed a nil list. */
690: if (authlist == NULL || strlen(authlist) == 0)
691: authlist = def_authlist;
692:
693: if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) {
694: /* start over if passed a different list */
695: authmethod_clear();
696: authlist_current = xstrdup(authlist);
697: authlist_working = xstrdup(authlist);
698: name = strtok_r(authlist_working, DELIM, &authlist_state);
699: } else {
700: /*
701: * try to use previously used authentication method
702: * or continue to use previously passed list
703: */
704: name = (authname_current != NULL) ?
705: authname_current : strtok_r(NULL, DELIM, &authlist_state);
1.1 markus 706: }
1.20 markus 707:
708: while (name != NULL) {
709: method = authmethod_lookup(name);
710: if (method != NULL && authmethod_is_enabled(method))
711: break;
712: name = strtok_r(NULL, DELIM, &authlist_state);
1.1 markus 713: }
714:
1.20 markus 715: if (authname_current != NULL)
716: xfree(authname_current);
1.1 markus 717:
1.20 markus 718: if (name != NULL) {
719: debug("next auth method to try is %s", name);
720: authname_current = xstrdup(name);
721: return method;
722: } else {
723: debug("no more auth methods to try");
724: authname_current = NULL;
725: return NULL;
1.1 markus 726: }
727: }