]> andersk Git - gssapi-openssh.git/blame - openssh/sshconnect2.c
o Merge changes from OPENSSH_3_5P1_GSI_20021018.
[gssapi-openssh.git] / openssh / sshconnect2.c
CommitLineData
3c0ef626 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"
e54b3d7c 26RCSID("$OpenBSD: sshconnect2.c,v 1.107 2002/07/01 19:48:46 markus Exp $");
3c0ef626 27
28#include "ssh.h"
29#include "ssh2.h"
30#include "xmalloc.h"
3c0ef626 31#include "buffer.h"
32#include "packet.h"
3c0ef626 33#include "compat.h"
34#include "bufaux.h"
35#include "cipher.h"
36#include "kex.h"
37#include "myproposal.h"
3c0ef626 38#include "sshconnect.h"
39#include "authfile.h"
40#include "dh.h"
41#include "authfd.h"
42#include "log.h"
43#include "readconf.h"
44#include "readpass.h"
45#include "match.h"
46#include "dispatch.h"
47#include "canohost.h"
ff2d7a98 48#include "msg.h"
49#include "pathnames.h"
3c0ef626 50
b9a54c29 51#ifdef GSSAPI
52#include "ssh-gss.h"
53#endif
54
3c0ef626 55/* import */
56extern char *client_version_string;
57extern char *server_version_string;
58extern Options options;
59
60/*
61 * SSH2 key exchange
62 */
63
64u_char *session_id2 = NULL;
65int session_id2_len = 0;
66
67char *xxx_host;
68struct sockaddr *xxx_hostaddr;
69
70Kex *xxx_kex = NULL;
71
72static int
73verify_host_key_callback(Key *hostkey)
74{
75 if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
76 fatal("Host key verification failed.");
77 return 0;
78}
79
80void
81ssh_kex2(char *host, struct sockaddr *hostaddr)
82{
83 Kex *kex;
b9a54c29 84#ifdef GSSAPI
85 char *orig, *gss;
86 int len;
87#endif
3c0ef626 88
89 xxx_host = host;
90 xxx_hostaddr = hostaddr;
91
b9a54c29 92#ifdef GSSAPI
98f19977 93 if (options.gss_keyex) {
b9a54c29 94 /* Add the GSSAPI mechanisms currently supported on this client to
95 * the key exchange algorithm proposal */
96 orig = myproposal[PROPOSAL_KEX_ALGS];
97 gss = ssh_gssapi_mechanisms(0,host);
98 if (gss) {
99 len = strlen(orig)+strlen(gss)+2;
100 myproposal[PROPOSAL_KEX_ALGS]=xmalloc(len);
101 snprintf(myproposal[PROPOSAL_KEX_ALGS],len,"%s,%s",gss,orig);
102 }
98f19977 103 }
b9a54c29 104#endif
105
3c0ef626 106 if (options.ciphers == (char *)-1) {
107 log("No valid ciphers for protocol version 2 given, using defaults.");
108 options.ciphers = NULL;
109 }
110 if (options.ciphers != NULL) {
111 myproposal[PROPOSAL_ENC_ALGS_CTOS] =
112 myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
113 }
114 myproposal[PROPOSAL_ENC_ALGS_CTOS] =
115 compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
116 myproposal[PROPOSAL_ENC_ALGS_STOC] =
117 compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
118 if (options.compression) {
119 myproposal[PROPOSAL_COMP_ALGS_CTOS] =
e54b3d7c 120 myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib,none";
3c0ef626 121 } else {
122 myproposal[PROPOSAL_COMP_ALGS_CTOS] =
e54b3d7c 123 myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib";
3c0ef626 124 }
125 if (options.macs != NULL) {
126 myproposal[PROPOSAL_MAC_ALGS_CTOS] =
127 myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
128 }
129 if (options.hostkeyalgorithms != NULL)
e9a17296 130 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
3c0ef626 131 options.hostkeyalgorithms;
132
b9a54c29 133#ifdef GSSAPI
134 /* If we've got GSSAPI algorithms, then we also support the
135 * 'null' hostkey, as a last resort */
98f19977 136 if (options.gss_keyex && gss) {
b9a54c29 137 orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
138 len = strlen(orig)+sizeof(",null");
139 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(len);
140 snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],len,"%s,null",orig);
141 }
142#endif
143
3c0ef626 144 /* start key exchange */
145 kex = kex_setup(myproposal);
146 kex->client_version_string=client_version_string;
147 kex->server_version_string=server_version_string;
148 kex->verify_host_key=&verify_host_key_callback;
b9a54c29 149 kex->host=host;
150
151#ifdef GSSAPI
152 kex->options.gss_deleg_creds=options.gss_deleg_creds;
153#endif
3c0ef626 154
155 xxx_kex = kex;
156
157 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
158
159 session_id2 = kex->session_id;
160 session_id2_len = kex->session_id_len;
161
162#ifdef DEBUG_KEXDH
163 /* send 1st encrypted/maced/compressed message */
164 packet_start(SSH2_MSG_IGNORE);
165 packet_put_cstring("markus");
166 packet_send();
167 packet_write_wait();
168#endif
169 debug("done: ssh_kex2.");
170}
171
172/*
173 * Authenticate user
174 */
175
176typedef struct Authctxt Authctxt;
177typedef struct Authmethod Authmethod;
178
179typedef int sign_cb_fn(
180 Authctxt *authctxt, Key *key,
e9a17296 181 u_char **sigp, u_int *lenp, u_char *data, u_int datalen);
3c0ef626 182
183struct Authctxt {
184 const char *server_user;
185 const char *local_user;
186 const char *host;
187 const char *service;
188 Authmethod *method;
189 int success;
190 char *authlist;
191 /* pubkey */
192 Key *last_key;
193 sign_cb_fn *last_key_sign;
194 int last_key_hint;
195 AuthenticationConnection *agent;
196 /* hostbased */
ff2d7a98 197 Sensitive *sensitive;
3c0ef626 198 /* kbd-interactive */
199 int info_req_seen;
b9a54c29 200 /* generic */
201 void *methoddata;
3c0ef626 202};
203struct Authmethod {
204 char *name; /* string to compare against server's list */
205 int (*userauth)(Authctxt *authctxt);
206 int *enabled; /* flag in option struct that enables method */
207 int *batch_flag; /* flag in option struct that disables method */
208};
209
e9a17296 210void input_userauth_success(int, u_int32_t, void *);
211void input_userauth_failure(int, u_int32_t, void *);
212void input_userauth_banner(int, u_int32_t, void *);
213void input_userauth_error(int, u_int32_t, void *);
214void input_userauth_info_req(int, u_int32_t, void *);
215void input_userauth_pk_ok(int, u_int32_t, void *);
2980ea68 216void input_userauth_passwd_changereq(int, u_int32_t, void *);
3c0ef626 217
e9a17296 218int userauth_none(Authctxt *);
219int userauth_pubkey(Authctxt *);
220int userauth_passwd(Authctxt *);
221int userauth_kbdint(Authctxt *);
222int userauth_hostbased(Authctxt *);
3c0ef626 223
b9a54c29 224#ifdef GSSAPI
225int userauth_external(Authctxt *authctxt);
226int userauth_gssapi(Authctxt *authctxt);
227void input_gssapi_response(int type, u_int32_t plen, void *ctxt);
228void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
229void input_gssapi_hash(int type, u_int32_t plen, void *ctxt);
230#endif
231
e9a17296 232void userauth(Authctxt *, char *);
3c0ef626 233
234static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
235static void clear_auth_state(Authctxt *);
236
237static Authmethod *authmethod_get(char *authlist);
238static Authmethod *authmethod_lookup(const char *name);
239static char *authmethods_get(void);
240
241Authmethod authmethods[] = {
b9a54c29 242#ifdef GSSAPI
243 {"external-keyx",
244 userauth_external,
245 &options.gss_authentication,
246 NULL},
247 {"gssapi",
248 userauth_gssapi,
249 &options.gss_authentication,
250 NULL},
251#endif
3c0ef626 252 {"hostbased",
253 userauth_hostbased,
254 &options.hostbased_authentication,
255 NULL},
256 {"publickey",
257 userauth_pubkey,
258 &options.pubkey_authentication,
259 NULL},
260 {"keyboard-interactive",
261 userauth_kbdint,
262 &options.kbd_interactive_authentication,
263 &options.batch_mode},
264 {"password",
265 userauth_passwd,
266 &options.password_authentication,
267 &options.batch_mode},
268 {"none",
269 userauth_none,
270 NULL,
271 NULL},
272 {NULL, NULL, NULL, NULL}
273};
274
275void
276ssh_userauth2(const char *local_user, const char *server_user, char *host,
ff2d7a98 277 Sensitive *sensitive)
3c0ef626 278{
279 Authctxt authctxt;
280 int type;
3c0ef626 281
282 if (options.challenge_response_authentication)
283 options.kbd_interactive_authentication = 1;
284
285 debug("send SSH2_MSG_SERVICE_REQUEST");
286 packet_start(SSH2_MSG_SERVICE_REQUEST);
287 packet_put_cstring("ssh-userauth");
288 packet_send();
289 packet_write_wait();
e9a17296 290 type = packet_read();
3c0ef626 291 if (type != SSH2_MSG_SERVICE_ACCEPT) {
292 fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
293 }
294 if (packet_remaining() > 0) {
e9a17296 295 char *reply = packet_get_string(NULL);
3c0ef626 296 debug("service_accept: %s", reply);
297 xfree(reply);
298 } else {
299 debug("buggy server: service_accept w/o service");
300 }
e9a17296 301 packet_check_eom();
3c0ef626 302 debug("got SSH2_MSG_SERVICE_ACCEPT");
303
304 if (options.preferred_authentications == NULL)
305 options.preferred_authentications = authmethods_get();
306
307 /* setup authentication context */
308 memset(&authctxt, 0, sizeof(authctxt));
309 authctxt.agent = ssh_get_authentication_connection();
310 authctxt.server_user = server_user;
311 authctxt.local_user = local_user;
312 authctxt.host = host;
313 authctxt.service = "ssh-connection"; /* service name */
314 authctxt.success = 0;
315 authctxt.method = authmethod_lookup("none");
316 authctxt.authlist = NULL;
b9a54c29 317 authctxt.methoddata = NULL;
ff2d7a98 318 authctxt.sensitive = sensitive;
3c0ef626 319 authctxt.info_req_seen = 0;
320 if (authctxt.method == NULL)
321 fatal("ssh_userauth2: internal error: cannot send userauth none request");
322
323 /* initial userauth request */
324 userauth_none(&authctxt);
325
326 dispatch_init(&input_userauth_error);
327 dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
328 dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
329 dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
330 dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */
331
332 if (authctxt.agent != NULL)
333 ssh_close_authentication_connection(authctxt.agent);
334
335 debug("ssh-userauth2 successful: method %s", authctxt.method->name);
336}
337void
338userauth(Authctxt *authctxt, char *authlist)
339{
b9a54c29 340 if (authctxt->methoddata!=NULL) {
341 xfree(authctxt->methoddata);
342 authctxt->methoddata=NULL;
343 }
344
3c0ef626 345 if (authlist == NULL) {
346 authlist = authctxt->authlist;
347 } else {
348 if (authctxt->authlist)
349 xfree(authctxt->authlist);
350 authctxt->authlist = authlist;
351 }
352 for (;;) {
353 Authmethod *method = authmethod_get(authlist);
354 if (method == NULL)
355 fatal("Permission denied (%s).", authlist);
356 authctxt->method = method;
357 if (method->userauth(authctxt) != 0) {
358 debug2("we sent a %s packet, wait for reply", method->name);
359 break;
360 } else {
361 debug2("we did not send a packet, disable method");
362 method->enabled = NULL;
363 }
364 }
365}
ff2d7a98 366
3c0ef626 367void
e9a17296 368input_userauth_error(int type, u_int32_t seq, void *ctxt)
3c0ef626 369{
370 fatal("input_userauth_error: bad message during authentication: "
371 "type %d", type);
372}
ff2d7a98 373
3c0ef626 374void
e9a17296 375input_userauth_banner(int type, u_int32_t seq, void *ctxt)
3c0ef626 376{
377 char *msg, *lang;
378 debug3("input_userauth_banner");
379 msg = packet_get_string(NULL);
380 lang = packet_get_string(NULL);
381 fprintf(stderr, "%s", msg);
382 xfree(msg);
383 xfree(lang);
384}
ff2d7a98 385
3c0ef626 386void
e9a17296 387input_userauth_success(int type, u_int32_t seq, void *ctxt)
3c0ef626 388{
389 Authctxt *authctxt = ctxt;
390 if (authctxt == NULL)
391 fatal("input_userauth_success: no authentication context");
392 if (authctxt->authlist)
393 xfree(authctxt->authlist);
b9a54c29 394 if (authctxt->methoddata)
395 xfree(authctxt->methoddata);
3c0ef626 396 clear_auth_state(authctxt);
397 authctxt->success = 1; /* break out */
398}
ff2d7a98 399
3c0ef626 400void
e9a17296 401input_userauth_failure(int type, u_int32_t seq, void *ctxt)
3c0ef626 402{
403 Authctxt *authctxt = ctxt;
404 char *authlist = NULL;
405 int partial;
406
407 if (authctxt == NULL)
408 fatal("input_userauth_failure: no authentication context");
409
410 authlist = packet_get_string(NULL);
411 partial = packet_get_char();
e9a17296 412 packet_check_eom();
3c0ef626 413
414 if (partial != 0)
415 log("Authenticated with partial success.");
416 debug("authentications that can continue: %s", authlist);
417
418 clear_auth_state(authctxt);
419 userauth(authctxt, authlist);
420}
421void
e9a17296 422input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
3c0ef626 423{
424 Authctxt *authctxt = ctxt;
425 Key *key = NULL;
426 Buffer b;
e9a17296 427 int pktype, sent = 0;
428 u_int alen, blen;
429 char *pkalg, *fp;
430 u_char *pkblob;
3c0ef626 431
432 if (authctxt == NULL)
433 fatal("input_userauth_pk_ok: no authentication context");
434 if (datafellows & SSH_BUG_PKOK) {
435 /* this is similar to SSH_BUG_PKAUTH */
436 debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
437 pkblob = packet_get_string(&blen);
438 buffer_init(&b);
439 buffer_append(&b, pkblob, blen);
440 pkalg = buffer_get_string(&b, &alen);
441 buffer_free(&b);
442 } else {
443 pkalg = packet_get_string(&alen);
444 pkblob = packet_get_string(&blen);
445 }
e9a17296 446 packet_check_eom();
3c0ef626 447
ff2d7a98 448 debug("input_userauth_pk_ok: pkalg %s blen %u lastkey %p hint %d",
3c0ef626 449 pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
450
451 do {
452 if (authctxt->last_key == NULL ||
453 authctxt->last_key_sign == NULL) {
454 debug("no last key or no sign cb");
455 break;
456 }
e9a17296 457 if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
3c0ef626 458 debug("unknown pkalg %s", pkalg);
459 break;
460 }
461 if ((key = key_from_blob(pkblob, blen)) == NULL) {
462 debug("no key from blob. pkalg %s", pkalg);
463 break;
464 }
2980ea68 465 if (key->type != pktype) {
e9a17296 466 error("input_userauth_pk_ok: type mismatch "
467 "for decoded key (received %d, expected %d)",
ff2d7a98 468 key->type, pktype);
e9a17296 469 break;
470 }
3c0ef626 471 fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
472 debug2("input_userauth_pk_ok: fp %s", fp);
473 xfree(fp);
474 if (!key_equal(key, authctxt->last_key)) {
475 debug("key != last_key");
476 break;
477 }
478 sent = sign_and_send_pubkey(authctxt, key,
479 authctxt->last_key_sign);
e9a17296 480 } while (0);
3c0ef626 481
482 if (key != NULL)
483 key_free(key);
484 xfree(pkalg);
485 xfree(pkblob);
486
487 /* unregister */
488 clear_auth_state(authctxt);
489 dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);
490
e54b3d7c 491 /* try another method if we did not send a packet */
3c0ef626 492 if (sent == 0)
493 userauth(authctxt, NULL);
494
495}
496
b9a54c29 497#ifdef GSSAPI
498int
499userauth_gssapi(Authctxt *authctxt)
500{
b9a54c29 501 Gssctxt *gssctxt;
98f19977 502 static int mech=0;
b9a54c29 503
504 if (datafellows & SSH_OLD_GSSAPI) return 0;
505
98f19977 506 /* Try each mechanism in turn. Give up if we've tried all
507 supported mechanisms.
508 */
509 if (mech==GSS_LAST_ENTRY) return 0;
510
b9a54c29 511 /* Initialise as much of our context as we can, so failures can be
512 * trapped before sending any packets.
513 */
ff2d7a98 514 ssh_gssapi_build_ctx(&gssctxt);
515
b9a54c29 516 if (ssh_gssapi_import_name(gssctxt,authctxt->host)) {
517 return(0);
518 }
ff2d7a98 519
b9a54c29 520 authctxt->methoddata=(void *)gssctxt;
521
522 packet_start(SSH2_MSG_USERAUTH_REQUEST);
c2397a66 523#ifdef GSI
2980ea68 524 if(options.implicit && !(datafellows & SSH_BUG_GSS_EMPTYUSER)) {
525 packet_put_cstring("");
526 } else {
c2397a66 527#endif
2980ea68 528 packet_put_cstring(authctxt->server_user);
c2397a66 529#ifdef GSI
2980ea68 530 }
c2397a66 531#endif
b9a54c29 532 packet_put_cstring(authctxt->service);
533 packet_put_cstring(authctxt->method->name);
534
535 /* FIXME: This assumes that our current GSSAPI implementation
536 * supports all of the mechanisms listed in supported_mechs.
537 * This may not be the case - we should use something along
538 * the lines of the code in gss_genr to remove the ones that
539 * aren't supported */
98f19977 540
541 /* Try one GSSAPI mechanism at a time. */
542 packet_put_int(1);
543 packet_put_string(supported_mechs[mech].oid.elements,
544 supported_mechs[mech].oid.length);
b9a54c29 545 packet_send();
546 packet_write_wait();
547
548 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response);
549 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token);
550
98f19977 551 mech++; /* Move to next mechanism for next time. */
552
b9a54c29 553 return 1;
554}
555
556void
557input_gssapi_response(int type, u_int32_t plen, void *ctxt)
558{
559 Authctxt *authctxt = ctxt;
560 Gssctxt *gssctxt;
561 OM_uint32 status,ms;
562 int oidlen;
563 char *oidv;
564 gss_buffer_desc send_tok;
565
566 if (authctxt == NULL)
567 fatal("input_gssapi_response: no authentication context");
568 gssctxt = authctxt->methoddata;
569
570 /* Setup our OID */
571 oidv=packet_get_string(&oidlen);
572 ssh_gssapi_set_oid_data(gssctxt,oidv,oidlen);
573
574 packet_check_eom();
575
576 status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
577 GSS_C_NO_BUFFER, &send_tok,
578 NULL);
579 if (GSS_ERROR(status)) {
580 /* Start again with next method on list */
581 debug("Trying to start again");
582 userauth(authctxt,NULL);
583 return;
584 }
585
586 /* We must have data to send */
587 packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
588 packet_put_string(send_tok.value,send_tok.length);
589 packet_send();
590 packet_write_wait();
591 gss_release_buffer(&ms, &send_tok);
592}
593
594void
595input_gssapi_token(int type, u_int32_t plen, void *ctxt)
596{
597 Authctxt *authctxt = ctxt;
598 Gssctxt *gssctxt;
599 gss_buffer_desc send_tok,recv_tok;
600 OM_uint32 status;
c2397a66 601 u_int slen;
b9a54c29 602
603 if (authctxt == NULL)
98f19977 604 fatal("input_gssapi_token: no authentication context");
b9a54c29 605 gssctxt = authctxt->methoddata;
606
c2397a66 607 recv_tok.value=packet_get_string(&slen);
608 recv_tok.length=slen; /* safe typecast */
b9a54c29 609
610 status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
611 &recv_tok, &send_tok, NULL);
612
613 packet_check_eom();
614
615 if (GSS_ERROR(status)) {
616 /* Start again with the next method in the list */
617 userauth(authctxt,NULL);
618 return;
619 }
620
621 if (send_tok.length>0) {
622 packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
623 packet_put_string(send_tok.value,send_tok.length);
624 packet_send();
625 packet_write_wait();
626 }
627
628 if (status == GSS_S_COMPLETE) {
629 /* If that succeeded, send a exchange complete message */
630 packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
631 packet_send();
632 packet_write_wait();
633 }
634}
635
636int
637userauth_external(Authctxt *authctxt)
638{
639 static int attempt =0;
640
641 if (attempt++ >= 1)
642 return 0;
643
644 debug2("userauth_external");
645 packet_start(SSH2_MSG_USERAUTH_REQUEST);
c2397a66 646#ifdef GSI
2980ea68 647 if(options.implicit && !(datafellows & SSH_BUG_GSS_EMPTYUSER)) {
648 packet_put_cstring("");
649 } else {
c2397a66 650#endif
2980ea68 651 packet_put_cstring(authctxt->server_user);
c2397a66 652#ifdef GSI
2980ea68 653 }
c2397a66 654#endif
b9a54c29 655 packet_put_cstring(authctxt->service);
656 packet_put_cstring(authctxt->method->name);
657 packet_send();
658 packet_write_wait();
659 return 1;
660}
661#endif /* GSSAPI */
662
3c0ef626 663int
664userauth_none(Authctxt *authctxt)
665{
666 /* initial userauth request */
667 packet_start(SSH2_MSG_USERAUTH_REQUEST);
668 packet_put_cstring(authctxt->server_user);
669 packet_put_cstring(authctxt->service);
670 packet_put_cstring(authctxt->method->name);
671 packet_send();
672 return 1;
b9a54c29 673
3c0ef626 674}
675
676int
677userauth_passwd(Authctxt *authctxt)
678{
679 static int attempt = 0;
2980ea68 680 char prompt[150];
3c0ef626 681 char *password;
682
683 if (attempt++ >= options.number_of_password_prompts)
684 return 0;
685
e9a17296 686 if (attempt != 1)
3c0ef626 687 error("Permission denied, please try again.");
688
689 snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
690 authctxt->server_user, authctxt->host);
691 password = read_passphrase(prompt, 0);
692 packet_start(SSH2_MSG_USERAUTH_REQUEST);
693 packet_put_cstring(authctxt->server_user);
694 packet_put_cstring(authctxt->service);
695 packet_put_cstring(authctxt->method->name);
696 packet_put_char(0);
697 packet_put_cstring(password);
698 memset(password, 0, strlen(password));
699 xfree(password);
700 packet_add_padding(64);
701 packet_send();
2980ea68 702
ff2d7a98 703 dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
2980ea68 704 &input_userauth_passwd_changereq);
705
3c0ef626 706 return 1;
707}
2980ea68 708/*
709 * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
710 */
711void
712input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
713{
714 Authctxt *authctxt = ctxt;
715 char *info, *lang, *password = NULL, *retype = NULL;
716 char prompt[150];
717
718 debug2("input_userauth_passwd_changereq");
719
720 if (authctxt == NULL)
721 fatal("input_userauth_passwd_changereq: "
722 "no authentication context");
723
724 info = packet_get_string(NULL);
725 lang = packet_get_string(NULL);
726 if (strlen(info) > 0)
727 log("%s", info);
728 xfree(info);
729 xfree(lang);
730 packet_start(SSH2_MSG_USERAUTH_REQUEST);
731 packet_put_cstring(authctxt->server_user);
732 packet_put_cstring(authctxt->service);
733 packet_put_cstring(authctxt->method->name);
734 packet_put_char(1); /* additional info */
ff2d7a98 735 snprintf(prompt, sizeof(prompt),
2980ea68 736 "Enter %.30s@%.128s's old password: ",
737 authctxt->server_user, authctxt->host);
738 password = read_passphrase(prompt, 0);
739 packet_put_cstring(password);
740 memset(password, 0, strlen(password));
741 xfree(password);
742 password = NULL;
743 while (password == NULL) {
ff2d7a98 744 snprintf(prompt, sizeof(prompt),
2980ea68 745 "Enter %.30s@%.128s's new password: ",
746 authctxt->server_user, authctxt->host);
747 password = read_passphrase(prompt, RP_ALLOW_EOF);
748 if (password == NULL) {
749 /* bail out */
750 return;
751 }
ff2d7a98 752 snprintf(prompt, sizeof(prompt),
2980ea68 753 "Retype %.30s@%.128s's new password: ",
754 authctxt->server_user, authctxt->host);
755 retype = read_passphrase(prompt, 0);
756 if (strcmp(password, retype) != 0) {
757 memset(password, 0, strlen(password));
758 xfree(password);
759 log("Mismatch; try again, EOF to quit.");
760 password = NULL;
761 }
762 memset(retype, 0, strlen(retype));
763 xfree(retype);
764 }
765 packet_put_cstring(password);
766 memset(password, 0, strlen(password));
767 xfree(password);
768 packet_add_padding(64);
769 packet_send();
ff2d7a98 770
771 dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
2980ea68 772 &input_userauth_passwd_changereq);
773}
3c0ef626 774
775static void
776clear_auth_state(Authctxt *authctxt)
777{
778 /* XXX clear authentication state */
2980ea68 779 dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
780
3c0ef626 781 if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
782 debug3("clear_auth_state: key_free %p", authctxt->last_key);
783 key_free(authctxt->last_key);
784 }
785 authctxt->last_key = NULL;
786 authctxt->last_key_hint = -2;
787 authctxt->last_key_sign = NULL;
788}
789
790static int
791sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
792{
793 Buffer b;
794 u_char *blob, *signature;
e9a17296 795 u_int bloblen, slen;
3c0ef626 796 int skip = 0;
797 int ret = -1;
798 int have_sig = 1;
799
800 debug3("sign_and_send_pubkey");
801
802 if (key_to_blob(k, &blob, &bloblen) == 0) {
803 /* we cannot handle this key */
804 debug3("sign_and_send_pubkey: cannot handle key");
805 return 0;
806 }
807 /* data to be signed */
808 buffer_init(&b);
809 if (datafellows & SSH_OLD_SESSIONID) {
810 buffer_append(&b, session_id2, session_id2_len);
811 skip = session_id2_len;
812 } else {
813 buffer_put_string(&b, session_id2, session_id2_len);
814 skip = buffer_len(&b);
815 }
816 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
817 buffer_put_cstring(&b, authctxt->server_user);
818 buffer_put_cstring(&b,
819 datafellows & SSH_BUG_PKSERVICE ?
820 "ssh-userauth" :
821 authctxt->service);
822 if (datafellows & SSH_BUG_PKAUTH) {
823 buffer_put_char(&b, have_sig);
824 } else {
825 buffer_put_cstring(&b, authctxt->method->name);
826 buffer_put_char(&b, have_sig);
827 buffer_put_cstring(&b, key_ssh_name(k));
828 }
829 buffer_put_string(&b, blob, bloblen);
830
831 /* generate signature */
832 ret = (*sign_callback)(authctxt, k, &signature, &slen,
833 buffer_ptr(&b), buffer_len(&b));
834 if (ret == -1) {
835 xfree(blob);
836 buffer_free(&b);
837 return 0;
838 }
839#ifdef DEBUG_PK
840 buffer_dump(&b);
841#endif
842 if (datafellows & SSH_BUG_PKSERVICE) {
843 buffer_clear(&b);
844 buffer_append(&b, session_id2, session_id2_len);
845 skip = session_id2_len;
846 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
847 buffer_put_cstring(&b, authctxt->server_user);
848 buffer_put_cstring(&b, authctxt->service);
849 buffer_put_cstring(&b, authctxt->method->name);
850 buffer_put_char(&b, have_sig);
851 if (!(datafellows & SSH_BUG_PKAUTH))
852 buffer_put_cstring(&b, key_ssh_name(k));
853 buffer_put_string(&b, blob, bloblen);
854 }
855 xfree(blob);
856
857 /* append signature */
858 buffer_put_string(&b, signature, slen);
859 xfree(signature);
860
861 /* skip session id and packet type */
862 if (buffer_len(&b) < skip + 1)
863 fatal("userauth_pubkey: internal error");
864 buffer_consume(&b, skip + 1);
865
866 /* put remaining data from buffer into packet */
867 packet_start(SSH2_MSG_USERAUTH_REQUEST);
868 packet_put_raw(buffer_ptr(&b), buffer_len(&b));
869 buffer_free(&b);
870 packet_send();
871
872 return 1;
873}
874
875static int
876send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
877 int hint)
878{
879 u_char *blob;
e9a17296 880 u_int bloblen, have_sig = 0;
3c0ef626 881
882 debug3("send_pubkey_test");
883
884 if (key_to_blob(k, &blob, &bloblen) == 0) {
885 /* we cannot handle this key */
886 debug3("send_pubkey_test: cannot handle key");
887 return 0;
888 }
889 /* register callback for USERAUTH_PK_OK message */
890 authctxt->last_key_sign = sign_callback;
891 authctxt->last_key_hint = hint;
892 authctxt->last_key = k;
893 dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
894
895 packet_start(SSH2_MSG_USERAUTH_REQUEST);
896 packet_put_cstring(authctxt->server_user);
897 packet_put_cstring(authctxt->service);
898 packet_put_cstring(authctxt->method->name);
899 packet_put_char(have_sig);
900 if (!(datafellows & SSH_BUG_PKAUTH))
901 packet_put_cstring(key_ssh_name(k));
902 packet_put_string(blob, bloblen);
903 xfree(blob);
904 packet_send();
905 return 1;
906}
907
908static Key *
909load_identity_file(char *filename)
910{
911 Key *private;
912 char prompt[300], *passphrase;
913 int quit, i;
914 struct stat st;
915
916 if (stat(filename, &st) < 0) {
917 debug3("no such identity: %s", filename);
918 return NULL;
919 }
920 private = key_load_private_type(KEY_UNSPEC, filename, "", NULL);
921 if (private == NULL) {
922 if (options.batch_mode)
923 return NULL;
924 snprintf(prompt, sizeof prompt,
e9a17296 925 "Enter passphrase for key '%.100s': ", filename);
3c0ef626 926 for (i = 0; i < options.number_of_password_prompts; i++) {
927 passphrase = read_passphrase(prompt, 0);
928 if (strcmp(passphrase, "") != 0) {
929 private = key_load_private_type(KEY_UNSPEC, filename,
930 passphrase, NULL);
931 quit = 0;
932 } else {
933 debug2("no passphrase given, try next key");
934 quit = 1;
935 }
936 memset(passphrase, 0, strlen(passphrase));
937 xfree(passphrase);
938 if (private != NULL || quit)
939 break;
940 debug2("bad passphrase given, try again...");
941 }
942 }
943 return private;
944}
945
946static int
e9a17296 947identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
948 u_char *data, u_int datalen)
3c0ef626 949{
950 Key *private;
951 int idx, ret;
952
953 idx = authctxt->last_key_hint;
954 if (idx < 0)
955 return -1;
956
957 /* private key is stored in external hardware */
e9a17296 958 if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)
3c0ef626 959 return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
960
961 private = load_identity_file(options.identity_files[idx]);
962 if (private == NULL)
963 return -1;
964 ret = key_sign(private, sigp, lenp, data, datalen);
965 key_free(private);
966 return ret;
967}
968
969static int
e9a17296 970agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
971 u_char *data, u_int datalen)
3c0ef626 972{
973 return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
974}
975
976static int
e9a17296 977key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
978 u_char *data, u_int datalen)
3c0ef626 979{
980 return key_sign(key, sigp, lenp, data, datalen);
981}
982
983static int
984userauth_pubkey_agent(Authctxt *authctxt)
985{
986 static int called = 0;
987 int ret = 0;
988 char *comment;
989 Key *k;
990
991 if (called == 0) {
992 if (ssh_get_num_identities(authctxt->agent, 2) == 0)
993 debug2("userauth_pubkey_agent: no keys at all");
994 called = 1;
995 }
996 k = ssh_get_next_identity(authctxt->agent, &comment, 2);
997 if (k == NULL) {
998 debug2("userauth_pubkey_agent: no more keys");
999 } else {
1000 debug("userauth_pubkey_agent: testing agent key %s", comment);
1001 xfree(comment);
1002 ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
1003 if (ret == 0)
1004 key_free(k);
1005 }
1006 if (ret == 0)
1007 debug2("userauth_pubkey_agent: no message sent");
1008 return ret;
1009}
1010
1011int
1012userauth_pubkey(Authctxt *authctxt)
1013{
1014 static int idx = 0;
1015 int sent = 0;
1016 Key *key;
1017 char *filename;
1018
1019 if (authctxt->agent != NULL) {
1020 do {
1021 sent = userauth_pubkey_agent(authctxt);
e9a17296 1022 } while (!sent && authctxt->agent->howmany > 0);
3c0ef626 1023 }
1024 while (!sent && idx < options.num_identity_files) {
1025 key = options.identity_keys[idx];
1026 filename = options.identity_files[idx];
1027 if (key == NULL) {
1028 debug("try privkey: %s", filename);
1029 key = load_identity_file(filename);
1030 if (key != NULL) {
1031 sent = sign_and_send_pubkey(authctxt, key,
1032 key_sign_cb);
1033 key_free(key);
1034 }
1035 } else if (key->type != KEY_RSA1) {
1036 debug("try pubkey: %s", filename);
1037 sent = send_pubkey_test(authctxt, key,
1038 identity_sign_cb, idx);
1039 }
1040 idx++;
1041 }
1042 return sent;
1043}
1044
1045/*
1046 * Send userauth request message specifying keyboard-interactive method.
1047 */
1048int
1049userauth_kbdint(Authctxt *authctxt)
1050{
1051 static int attempt = 0;
1052
1053 if (attempt++ >= options.number_of_password_prompts)
1054 return 0;
1055 /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
1056 if (attempt > 1 && !authctxt->info_req_seen) {
1057 debug3("userauth_kbdint: disable: no info_req_seen");
1058 dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
1059 return 0;
1060 }
1061
1062 debug2("userauth_kbdint");
1063 packet_start(SSH2_MSG_USERAUTH_REQUEST);
1064 packet_put_cstring(authctxt->server_user);
1065 packet_put_cstring(authctxt->service);
1066 packet_put_cstring(authctxt->method->name);
1067 packet_put_cstring(""); /* lang */
1068 packet_put_cstring(options.kbd_interactive_devices ?
1069 options.kbd_interactive_devices : "");
1070 packet_send();
1071
1072 dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
1073 return 1;
1074}
1075
1076/*
1077 * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
1078 */
1079void
e9a17296 1080input_userauth_info_req(int type, u_int32_t seq, void *ctxt)
3c0ef626 1081{
1082 Authctxt *authctxt = ctxt;
1083 char *name, *inst, *lang, *prompt, *response;
1084 u_int num_prompts, i;
1085 int echo = 0;
1086
1087 debug2("input_userauth_info_req");
1088
1089 if (authctxt == NULL)
1090 fatal("input_userauth_info_req: no authentication context");
1091
1092 authctxt->info_req_seen = 1;
1093
1094 name = packet_get_string(NULL);
1095 inst = packet_get_string(NULL);
1096 lang = packet_get_string(NULL);
1097 if (strlen(name) > 0)
1098 log("%s", name);
1099 if (strlen(inst) > 0)
1100 log("%s", inst);
1101 xfree(name);
1102 xfree(inst);
1103 xfree(lang);
1104
1105 num_prompts = packet_get_int();
1106 /*
1107 * Begin to build info response packet based on prompts requested.
1108 * We commit to providing the correct number of responses, so if
1109 * further on we run into a problem that prevents this, we have to
1110 * be sure and clean this up and send a correct error response.
1111 */
1112 packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
1113 packet_put_int(num_prompts);
1114
1115 debug2("input_userauth_info_req: num_prompts %d", num_prompts);
1116 for (i = 0; i < num_prompts; i++) {
1117 prompt = packet_get_string(NULL);
1118 echo = packet_get_char();
1119
1120 response = read_passphrase(prompt, echo ? RP_ECHO : 0);
1121
1122 packet_put_cstring(response);
1123 memset(response, 0, strlen(response));
1124 xfree(response);
1125 xfree(prompt);
1126 }
e9a17296 1127 packet_check_eom(); /* done with parsing incoming message. */
3c0ef626 1128
1129 packet_add_padding(64);
1130 packet_send();
1131}
1132
ff2d7a98 1133static int
1134ssh_keysign(Key *key, u_char **sigp, u_int *lenp,
1135 u_char *data, u_int datalen)
1136{
1137 Buffer b;
1138 struct stat st;
1139 pid_t pid;
1140 int to[2], from[2], status, version = 2;
1141
1142 debug("ssh_keysign called");
1143
1144 if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
1145 error("ssh_keysign: no installed: %s", strerror(errno));
1146 return -1;
1147 }
1148 if (fflush(stdout) != 0)
1149 error("ssh_keysign: fflush: %s", strerror(errno));
1150 if (pipe(to) < 0) {
1151 error("ssh_keysign: pipe: %s", strerror(errno));
1152 return -1;
1153 }
1154 if (pipe(from) < 0) {
1155 error("ssh_keysign: pipe: %s", strerror(errno));
1156 return -1;
1157 }
1158 if ((pid = fork()) < 0) {
1159 error("ssh_keysign: fork: %s", strerror(errno));
1160 return -1;
1161 }
1162 if (pid == 0) {
1163 seteuid(getuid());
1164 setuid(getuid());
1165 close(from[0]);
1166 if (dup2(from[1], STDOUT_FILENO) < 0)
1167 fatal("ssh_keysign: dup2: %s", strerror(errno));
1168 close(to[1]);
1169 if (dup2(to[0], STDIN_FILENO) < 0)
1170 fatal("ssh_keysign: dup2: %s", strerror(errno));
1171 close(from[1]);
1172 close(to[0]);
1173 execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0);
1174 fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN,
1175 strerror(errno));
1176 }
1177 close(from[1]);
1178 close(to[0]);
1179
1180 buffer_init(&b);
1181 buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */
1182 buffer_put_string(&b, data, datalen);
e54b3d7c 1183 ssh_msg_send(to[1], version, &b);
ff2d7a98 1184
e54b3d7c 1185 if (ssh_msg_recv(from[0], &b) < 0) {
ff2d7a98 1186 error("ssh_keysign: no reply");
1187 buffer_clear(&b);
1188 return -1;
1189 }
1190 close(from[0]);
1191 close(to[1]);
1192
1193 while (waitpid(pid, &status, 0) < 0)
1194 if (errno != EINTR)
1195 break;
1196
1197 if (buffer_get_char(&b) != version) {
1198 error("ssh_keysign: bad version");
1199 buffer_clear(&b);
1200 return -1;
1201 }
1202 *sigp = buffer_get_string(&b, lenp);
1203 buffer_clear(&b);
1204
1205 return 0;
1206}
1207
3c0ef626 1208int
1209userauth_hostbased(Authctxt *authctxt)
1210{
1211 Key *private = NULL;
ff2d7a98 1212 Sensitive *sensitive = authctxt->sensitive;
3c0ef626 1213 Buffer b;
1214 u_char *signature, *blob;
1215 char *chost, *pkalg, *p;
1216 const char *service;
1217 u_int blen, slen;
1218 int ok, i, len, found = 0;
1219
1220 /* check for a useful key */
ff2d7a98 1221 for (i = 0; i < sensitive->nkeys; i++) {
1222 private = sensitive->keys[i];
3c0ef626 1223 if (private && private->type != KEY_RSA1) {
1224 found = 1;
1225 /* we take and free the key */
ff2d7a98 1226 sensitive->keys[i] = NULL;
3c0ef626 1227 break;
1228 }
1229 }
1230 if (!found) {
1231 debug("userauth_hostbased: no more client hostkeys");
1232 return 0;
1233 }
1234 if (key_to_blob(private, &blob, &blen) == 0) {
1235 key_free(private);
1236 return 0;
1237 }
1238 /* figure out a name for the client host */
1239 p = get_local_name(packet_get_connection_in());
1240 if (p == NULL) {
1241 error("userauth_hostbased: cannot get local ipaddr/name");
1242 key_free(private);
1243 return 0;
1244 }
1245 len = strlen(p) + 2;
1246 chost = xmalloc(len);
1247 strlcpy(chost, p, len);
1248 strlcat(chost, ".", len);
1249 debug2("userauth_hostbased: chost %s", chost);
1250
1251 service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
1252 authctxt->service;
1253 pkalg = xstrdup(key_ssh_name(private));
1254 buffer_init(&b);
1255 /* construct data */
1256 buffer_put_string(&b, session_id2, session_id2_len);
1257 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1258 buffer_put_cstring(&b, authctxt->server_user);
1259 buffer_put_cstring(&b, service);
1260 buffer_put_cstring(&b, authctxt->method->name);
1261 buffer_put_cstring(&b, pkalg);
1262 buffer_put_string(&b, blob, blen);
1263 buffer_put_cstring(&b, chost);
1264 buffer_put_cstring(&b, authctxt->local_user);
1265#ifdef DEBUG_PK
1266 buffer_dump(&b);
1267#endif
ff2d7a98 1268 if (sensitive->external_keysign)
1269 ok = ssh_keysign(private, &signature, &slen,
1270 buffer_ptr(&b), buffer_len(&b));
1271 else
1272 ok = key_sign(private, &signature, &slen,
1273 buffer_ptr(&b), buffer_len(&b));
3c0ef626 1274 key_free(private);
1275 buffer_free(&b);
1276 if (ok != 0) {
1277 error("key_sign failed");
1278 xfree(chost);
1279 xfree(pkalg);
1280 return 0;
1281 }
1282 packet_start(SSH2_MSG_USERAUTH_REQUEST);
1283 packet_put_cstring(authctxt->server_user);
1284 packet_put_cstring(authctxt->service);
1285 packet_put_cstring(authctxt->method->name);
1286 packet_put_cstring(pkalg);
1287 packet_put_string(blob, blen);
1288 packet_put_cstring(chost);
1289 packet_put_cstring(authctxt->local_user);
1290 packet_put_string(signature, slen);
1291 memset(signature, 's', slen);
1292 xfree(signature);
1293 xfree(chost);
1294 xfree(pkalg);
1295
1296 packet_send();
1297 return 1;
1298}
1299
1300/* find auth method */
1301
1302/*
1303 * given auth method name, if configurable options permit this method fill
1304 * in auth_ident field and return true, otherwise return false.
1305 */
1306static int
1307authmethod_is_enabled(Authmethod *method)
1308{
1309 if (method == NULL)
1310 return 0;
1311 /* return false if options indicate this method is disabled */
1312 if (method->enabled == NULL || *method->enabled == 0)
1313 return 0;
1314 /* return false if batch mode is enabled but method needs interactive mode */
1315 if (method->batch_flag != NULL && *method->batch_flag != 0)
1316 return 0;
1317 return 1;
1318}
1319
1320static Authmethod *
1321authmethod_lookup(const char *name)
1322{
1323 Authmethod *method = NULL;
1324 if (name != NULL)
1325 for (method = authmethods; method->name != NULL; method++)
1326 if (strcmp(name, method->name) == 0)
1327 return method;
1328 debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
1329 return NULL;
1330}
1331
1332/* XXX internal state */
1333static Authmethod *current = NULL;
1334static char *supported = NULL;
1335static char *preferred = NULL;
ff2d7a98 1336
3c0ef626 1337/*
1338 * Given the authentication method list sent by the server, return the
1339 * next method we should try. If the server initially sends a nil list,
1340 * use a built-in default list.
1341 */
1342static Authmethod *
1343authmethod_get(char *authlist)
1344{
1345
1346 char *name = NULL;
e9a17296 1347 u_int next;
3c0ef626 1348
1349 /* Use a suitable default if we're passed a nil list. */
1350 if (authlist == NULL || strlen(authlist) == 0)
1351 authlist = options.preferred_authentications;
1352
1353 if (supported == NULL || strcmp(authlist, supported) != 0) {
1354 debug3("start over, passed a different list %s", authlist);
1355 if (supported != NULL)
1356 xfree(supported);
1357 supported = xstrdup(authlist);
1358 preferred = options.preferred_authentications;
1359 debug3("preferred %s", preferred);
1360 current = NULL;
1361 } else if (current != NULL && authmethod_is_enabled(current))
1362 return current;
1363
1364 for (;;) {
1365 if ((name = match_list(preferred, supported, &next)) == NULL) {
1366 debug("no more auth methods to try");
1367 current = NULL;
1368 return NULL;
1369 }
1370 preferred += next;
1371 debug3("authmethod_lookup %s", name);
1372 debug3("remaining preferred: %s", preferred);
1373 if ((current = authmethod_lookup(name)) != NULL &&
1374 authmethod_is_enabled(current)) {
1375 debug3("authmethod_is_enabled %s", name);
1376 debug("next auth method to try is %s", name);
1377 return current;
1378 }
1379 }
1380}
1381
3c0ef626 1382static char *
1383authmethods_get(void)
1384{
1385 Authmethod *method = NULL;
e9a17296 1386 Buffer b;
1387 char *list;
3c0ef626 1388
e9a17296 1389 buffer_init(&b);
3c0ef626 1390 for (method = authmethods; method->name != NULL; method++) {
1391 if (authmethod_is_enabled(method)) {
e9a17296 1392 if (buffer_len(&b) > 0)
1393 buffer_append(&b, ",", 1);
1394 buffer_append(&b, method->name, strlen(method->name));
3c0ef626 1395 }
1396 }
e9a17296 1397 buffer_append(&b, "\0", 1);
1398 list = xstrdup(buffer_ptr(&b));
1399 buffer_free(&b);
1400 return list;
3c0ef626 1401}
This page took 0.306257 seconds and 5 git commands to generate.