]> andersk Git - openssh.git/blame - auth2.c
- markus@cvs.openbsd.org 2002/05/31 10:30:33
[openssh.git] / auth2.c
CommitLineData
a306f2dd 1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
a306f2dd 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 */
bcbf86ec 24
a306f2dd 25#include "includes.h"
013eab17 26RCSID("$OpenBSD: auth2.c,v 1.92 2002/05/25 18:51:07 markus Exp $");
a306f2dd 27
42f11eb2 28#include "ssh2.h"
a306f2dd 29#include "xmalloc.h"
a306f2dd 30#include "packet.h"
42f11eb2 31#include "log.h"
a306f2dd 32#include "servconf.h"
33#include "compat.h"
a306f2dd 34#include "auth.h"
a306f2dd 35#include "dispatch.h"
42f11eb2 36#include "pathnames.h"
1853d1ef 37#include "monitor_wrap.h"
a306f2dd 38
39/* import */
40extern ServerOptions options;
1e3b8b07 41extern u_char *session_id2;
a306f2dd 42extern int session_id2_len;
43
1853d1ef 44Authctxt *x_authctxt = NULL;
94ec8c6b 45static int one = 1;
46
47typedef struct Authmethod Authmethod;
48struct Authmethod {
49 char *name;
50 int (*userauth)(Authctxt *authctxt);
51 int *enabled;
52};
53
a306f2dd 54/* protocol */
55
7819b5c3 56static void input_service_request(int, u_int32_t, void *);
57static void input_userauth_request(int, u_int32_t, void *);
a306f2dd 58
a306f2dd 59/* helper */
396c147e 60static Authmethod *authmethod_lookup(const char *);
ffb215be 61static char *authmethods_get(void);
1853d1ef 62int user_key_allowed(struct passwd *, Key *);
63int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
a306f2dd 64
94ec8c6b 65/* auth */
94ec8c6b 66
67Authmethod authmethods[] = {
68 {"none",
69 userauth_none,
70 &one},
71 {"publickey",
72 userauth_pubkey,
fa08c86b 73 &options.pubkey_authentication},
94ec8c6b 74 {"password",
75 userauth_passwd,
76 &options.password_authentication},
c845316f 77 {"keyboard-interactive",
78 userauth_kbdint,
79 &options.kbd_interactive_authentication},
8002af61 80 {"hostbased",
81 userauth_hostbased,
82 &options.hostbased_authentication},
94ec8c6b 83 {NULL, NULL, NULL}
a306f2dd 84};
a306f2dd 85
86/*
94ec8c6b 87 * loop until authctxt->success == TRUE
a306f2dd 88 */
89
1b34c1b3 90Authctxt *
d5bb9418 91do_authentication2(void)
a306f2dd 92{
59c97189 93 Authctxt *authctxt = authctxt_new();
94
94ec8c6b 95 x_authctxt = authctxt; /*XXX*/
96
aa8003d6 97 /* challenge-response is implemented via keyboard interactive */
5ba55ada 98 if (options.challenge_response_authentication)
d464095c 99 options.kbd_interactive_authentication = 1;
10f72868 100 if (options.pam_authentication_via_kbd_int)
101 options.kbd_interactive_authentication = 1;
fea8a8e8 102 if (use_privsep)
103 options.pam_authentication_via_kbd_int = 0;
d464095c 104
6367063f 105 dispatch_init(&dispatch_protocol_error);
a306f2dd 106 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
94ec8c6b 107 dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
1b34c1b3 108
109 return (authctxt);
a306f2dd 110}
111
396c147e 112static void
7819b5c3 113input_service_request(int type, u_int32_t seq, void *ctxt)
a306f2dd 114{
94ec8c6b 115 Authctxt *authctxt = ctxt;
1e3b8b07 116 u_int len;
a306f2dd 117 int accept = 0;
118 char *service = packet_get_string(&len);
95500969 119 packet_check_eom();
a306f2dd 120
94ec8c6b 121 if (authctxt == NULL)
122 fatal("input_service_request: no authctxt");
123
a306f2dd 124 if (strcmp(service, "ssh-userauth") == 0) {
94ec8c6b 125 if (!authctxt->success) {
a306f2dd 126 accept = 1;
127 /* now we can handle user-auth requests */
128 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
129 }
130 }
131 /* XXX all other service requests are denied */
132
133 if (accept) {
134 packet_start(SSH2_MSG_SERVICE_ACCEPT);
135 packet_put_cstring(service);
136 packet_send();
137 packet_write_wait();
138 } else {
139 debug("bad service request %s", service);
140 packet_disconnect("bad service request %s", service);
141 }
142 xfree(service);
143}
144
396c147e 145static void
7819b5c3 146input_userauth_request(int type, u_int32_t seq, void *ctxt)
a306f2dd 147{
94ec8c6b 148 Authctxt *authctxt = ctxt;
149 Authmethod *m = NULL;
59c97189 150 char *user, *service, *method, *style = NULL;
a306f2dd 151 int authenticated = 0;
a306f2dd 152
94ec8c6b 153 if (authctxt == NULL)
154 fatal("input_userauth_request: no authctxt");
a306f2dd 155
94ec8c6b 156 user = packet_get_string(NULL);
157 service = packet_get_string(NULL);
158 method = packet_get_string(NULL);
159 debug("userauth-request for user %s service %s method %s", user, service, method);
8abcdba4 160 debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
94ec8c6b 161
59c97189 162 if ((style = strchr(user, ':')) != NULL)
163 *style++ = 0;
164
2b87da3b 165 if (authctxt->attempt++ == 0) {
63284fbb 166 /* setup auth context */
f7ed12f1 167 authctxt->pw = PRIVSEP(getpwnamallow(user));
168 if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
94ec8c6b 169 authctxt->valid = 1;
170 debug2("input_userauth_request: setting up authctxt for %s", user);
171#ifdef USE_PAM
ad200abb 172 PRIVSEP(start_pam(authctxt->pw->pw_name));
94ec8c6b 173#endif
174 } else {
175 log("input_userauth_request: illegal user %s", user);
04fc7a67 176#ifdef USE_PAM
ad200abb 177 PRIVSEP(start_pam("NOUSER"));
04fc7a67 178#endif
94ec8c6b 179 }
5f1f36b5 180 setproctitle("%s%s", authctxt->pw ? user : "unknown",
1853d1ef 181 use_privsep ? " [net]" : "");
94ec8c6b 182 authctxt->user = xstrdup(user);
183 authctxt->service = xstrdup(service);
2a6a054e 184 authctxt->style = style ? xstrdup(style) : NULL;
1853d1ef 185 if (use_privsep)
186 mm_inform_authserv(service, style);
2a6a054e 187 } else if (strcmp(user, authctxt->user) != 0 ||
188 strcmp(service, authctxt->service) != 0) {
189 packet_disconnect("Change of username or service not allowed: "
190 "(%s,%s) -> (%s,%s)",
191 authctxt->user, authctxt->service, user, service);
a306f2dd 192 }
59c97189 193 /* reset state */
2f293d43 194 auth2_challenge_stop(authctxt);
59c97189 195 authctxt->postponed = 0;
9cd45ea4 196
59c97189 197 /* try to authenticate user */
94ec8c6b 198 m = authmethod_lookup(method);
199 if (m != NULL) {
200 debug2("input_userauth_request: try method %s", method);
201 authenticated = m->userauth(authctxt);
9cd45ea4 202 }
d9cd3575 203 userauth_finish(authctxt, authenticated, method);
204
205 xfree(service);
206 xfree(user);
207 xfree(method);
208}
209
210void
211userauth_finish(Authctxt *authctxt, int authenticated, char *method)
212{
4e81159c 213 char *methods;
214
59c97189 215 if (!authctxt->valid && authenticated)
216 fatal("INTERNAL ERROR: authenticated invalid user %s",
217 authctxt->user);
9cd45ea4 218
94ec8c6b 219 /* Special handling for root */
15853e93 220 if (authenticated && authctxt->pw->pw_uid == 0 &&
221 !auth_root_allowed(method))
a306f2dd 222 authenticated = 0;
a306f2dd 223
224#ifdef USE_PAM
ad200abb 225 if (!use_privsep && authenticated && authctxt->user &&
226 !do_pam_account(authctxt->user, NULL))
9cd45ea4 227 authenticated = 0;
a306f2dd 228#endif /* USE_PAM */
229
94ec8c6b 230 /* Log before sending the reply */
59c97189 231 auth_log(authctxt, authenticated, method, " ssh2");
232
4e81159c 233 if (authctxt->postponed)
234 return;
235
236 /* XXX todo: check if multiple auth methods are needed */
237 if (authenticated == 1) {
238 /* turn off userauth */
6367063f 239 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
4e81159c 240 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
241 packet_send();
242 packet_write_wait();
243 /* now we can break out */
244 authctxt->success = 1;
245 } else {
19e810f6 246 if (authctxt->failures++ > AUTH_FAIL_MAX) {
247#ifdef WITH_AIXAUTHENTICATE
248 loginfailed(authctxt->user,
983784a1 249 get_canonical_hostname(options.verify_reverse_mapping),
19e810f6 250 "ssh");
251#endif /* WITH_AIXAUTHENTICATE */
4e81159c 252 packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
19e810f6 253 }
4e81159c 254 methods = authmethods_get();
255 packet_start(SSH2_MSG_USERAUTH_FAILURE);
256 packet_put_cstring(methods);
257 packet_put_char(0); /* XXX partial success, unused */
258 packet_send();
259 packet_write_wait();
260 xfree(methods);
261 }
94ec8c6b 262}
263
94a73cdc 264char *
265auth2_read_banner(void)
eea39c02 266{
267 struct stat st;
268 char *banner = NULL;
269 off_t len, n;
270 int fd;
271
94a73cdc 272 if ((fd = open(options.banner, O_RDONLY)) == -1)
273 return (NULL);
274 if (fstat(fd, &st) == -1) {
275 close(fd);
276 return (NULL);
277 }
eea39c02 278 len = st.st_size;
279 banner = xmalloc(len + 1);
94a73cdc 280 n = atomicio(read, fd, banner, len);
281 close(fd);
282
283 if (n != len) {
284 free(banner);
285 return (NULL);
286 }
eea39c02 287 banner[n] = '\0';
94a73cdc 288
289 return (banner);
290}
291
292static void
293userauth_banner(void)
294{
295 char *banner = NULL;
296
297 if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
298 return;
299
300 if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
301 goto done;
302
eea39c02 303 packet_start(SSH2_MSG_USERAUTH_BANNER);
304 packet_put_cstring(banner);
305 packet_put_cstring(""); /* language, unused */
306 packet_send();
307 debug("userauth_banner: sent");
308done:
309 if (banner)
310 xfree(banner);
eea39c02 311 return;
312}
94ec8c6b 313
396c147e 314static int
94ec8c6b 315userauth_none(Authctxt *authctxt)
a306f2dd 316{
94ec8c6b 317 /* disable method "none", only allowed one time */
318 Authmethod *m = authmethod_lookup("none");
319 if (m != NULL)
320 m->enabled = NULL;
95500969 321 packet_check_eom();
2b87da3b 322 userauth_banner();
4d33e531 323
94ec8c6b 324 if (authctxt->valid == 0)
325 return(0);
63284fbb 326
327#ifdef HAVE_CYGWIN
328 if (check_nt_auth(1, authctxt->pw) == 0)
329 return(0);
94ec8c6b 330#endif
1853d1ef 331 return PRIVSEP(auth_password(authctxt, ""));
a306f2dd 332}
94ec8c6b 333
396c147e 334static int
94ec8c6b 335userauth_passwd(Authctxt *authctxt)
a306f2dd 336{
337 char *password;
338 int authenticated = 0;
339 int change;
1e3b8b07 340 u_int len;
a306f2dd 341 change = packet_get_char();
342 if (change)
343 log("password change not supported");
344 password = packet_get_string(&len);
95500969 345 packet_check_eom();
63284fbb 346 if (authctxt->valid &&
347#ifdef HAVE_CYGWIN
348 check_nt_auth(1, authctxt->pw) &&
94ec8c6b 349#endif
1853d1ef 350 PRIVSEP(auth_password(authctxt, password)) == 1)
63284fbb 351 authenticated = 1;
a306f2dd 352 memset(password, 0, len);
353 xfree(password);
354 return authenticated;
355}
94ec8c6b 356
396c147e 357static int
94ec8c6b 358userauth_kbdint(Authctxt *authctxt)
359{
360 int authenticated = 0;
5ba55ada 361 char *lang, *devs;
94ec8c6b 362
363 lang = packet_get_string(NULL);
364 devs = packet_get_string(NULL);
95500969 365 packet_check_eom();
94ec8c6b 366
5ba55ada 367 debug("keyboard-interactive devs %s", devs);
59c97189 368
5ba55ada 369 if (options.challenge_response_authentication)
d464095c 370 authenticated = auth2_challenge(authctxt, devs);
59c97189 371
8c9fe09e 372#ifdef USE_PAM
10f72868 373 if (authenticated == 0 && options.pam_authentication_via_kbd_int)
8c9fe09e 374 authenticated = auth2_pam(authctxt);
94ec8c6b 375#endif
94ec8c6b 376 xfree(devs);
5ba55ada 377 xfree(lang);
94ec8c6b 378#ifdef HAVE_CYGWIN
e9571a2c 379 if (check_nt_auth(0, authctxt->pw) == 0)
94ec8c6b 380 return(0);
381#endif
382 return authenticated;
383}
384
396c147e 385static int
94ec8c6b 386userauth_pubkey(Authctxt *authctxt)
a306f2dd 387{
388 Buffer b;
67fa09f5 389 Key *key = NULL;
c66f9d0e 390 char *pkalg;
391 u_char *pkblob, *sig;
1e3b8b07 392 u_int alen, blen, slen;
fa08c86b 393 int have_sig, pktype;
a306f2dd 394 int authenticated = 0;
395
94ec8c6b 396 if (!authctxt->valid) {
397 debug2("userauth_pubkey: disabled because of invalid user");
a306f2dd 398 return 0;
399 }
400 have_sig = packet_get_char();
cbc5abf9 401 if (datafellows & SSH_BUG_PKAUTH) {
402 debug2("userauth_pubkey: SSH_BUG_PKAUTH");
403 /* no explicit pkalg given */
404 pkblob = packet_get_string(&blen);
405 buffer_init(&b);
406 buffer_append(&b, pkblob, blen);
407 /* so we have to extract the pkalg from the pkblob */
408 pkalg = buffer_get_string(&b, &alen);
409 buffer_free(&b);
410 } else {
411 pkalg = packet_get_string(&alen);
412 pkblob = packet_get_string(&blen);
413 }
fa08c86b 414 pktype = key_type_from_name(pkalg);
415 if (pktype == KEY_UNSPEC) {
cbc5abf9 416 /* this is perfectly legal */
67fa09f5 417 log("userauth_pubkey: unsupported public key algorithm: %s",
418 pkalg);
419 goto done;
a306f2dd 420 }
fa08c86b 421 key = key_from_blob(pkblob, blen);
67fa09f5 422 if (key == NULL) {
423 error("userauth_pubkey: cannot decode key: %s", pkalg);
424 goto done;
425 }
426 if (key->type != pktype) {
427 error("userauth_pubkey: type mismatch for decoded key "
428 "(received %d, expected %d)", key->type, pktype);
429 goto done;
430 }
431 if (have_sig) {
432 sig = packet_get_string(&slen);
433 packet_check_eom();
434 buffer_init(&b);
435 if (datafellows & SSH_OLD_SESSIONID) {
436 buffer_append(&b, session_id2, session_id2_len);
437 } else {
438 buffer_put_string(&b, session_id2, session_id2_len);
439 }
440 /* reconstruct packet */
441 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
442 buffer_put_cstring(&b, authctxt->user);
443 buffer_put_cstring(&b,
444 datafellows & SSH_BUG_PKSERVICE ?
445 "ssh-userauth" :
446 authctxt->service);
447 if (datafellows & SSH_BUG_PKAUTH) {
448 buffer_put_char(&b, have_sig);
449 } else {
450 buffer_put_cstring(&b, "publickey");
451 buffer_put_char(&b, have_sig);
452 buffer_put_cstring(&b, pkalg);
453 }
454 buffer_put_string(&b, pkblob, blen);
fa08c86b 455#ifdef DEBUG_PK
67fa09f5 456 buffer_dump(&b);
a306f2dd 457#endif
67fa09f5 458 /* test for correct signature */
1853d1ef 459 authenticated = 0;
460 if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
461 PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
462 buffer_len(&b))) == 1)
63284fbb 463 authenticated = 1;
67fa09f5 464 buffer_clear(&b);
465 xfree(sig);
466 } else {
467 debug("test whether pkalg/pkblob are acceptable");
468 packet_check_eom();
469
470 /* XXX fake reply and always send PK_OK ? */
471 /*
472 * XXX this allows testing whether a user is allowed
473 * to login: if you happen to have a valid pubkey this
474 * message is sent. the message is NEVER sent at all
475 * if a user is not allowed to login. is this an
476 * issue? -markus
477 */
1853d1ef 478 if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
67fa09f5 479 packet_start(SSH2_MSG_USERAUTH_PK_OK);
480 packet_put_string(pkalg, alen);
481 packet_put_string(pkblob, blen);
482 packet_send();
483 packet_write_wait();
484 authctxt->postponed = 1;
a306f2dd 485 }
a306f2dd 486 }
67fa09f5 487 if (authenticated != 1)
488 auth_clear_options();
489done:
fa08c86b 490 debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
67fa09f5 491 if (key != NULL)
492 key_free(key);
a306f2dd 493 xfree(pkalg);
494 xfree(pkblob);
94ec8c6b 495#ifdef HAVE_CYGWIN
e9571a2c 496 if (check_nt_auth(0, authctxt->pw) == 0)
94ec8c6b 497 return(0);
498#endif
a306f2dd 499 return authenticated;
500}
501
396c147e 502static int
8002af61 503userauth_hostbased(Authctxt *authctxt)
504{
505 Buffer b;
67fa09f5 506 Key *key = NULL;
c66f9d0e 507 char *pkalg, *cuser, *chost, *service;
508 u_char *pkblob, *sig;
8002af61 509 u_int alen, blen, slen;
510 int pktype;
511 int authenticated = 0;
512
513 if (!authctxt->valid) {
514 debug2("userauth_hostbased: disabled because of invalid user");
515 return 0;
516 }
517 pkalg = packet_get_string(&alen);
518 pkblob = packet_get_string(&blen);
519 chost = packet_get_string(NULL);
520 cuser = packet_get_string(NULL);
521 sig = packet_get_string(&slen);
522
523 debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
524 cuser, chost, pkalg, slen);
525#ifdef DEBUG_PK
526 debug("signature:");
527 buffer_init(&b);
528 buffer_append(&b, sig, slen);
529 buffer_dump(&b);
530 buffer_free(&b);
531#endif
532 pktype = key_type_from_name(pkalg);
533 if (pktype == KEY_UNSPEC) {
534 /* this is perfectly legal */
535 log("userauth_hostbased: unsupported "
536 "public key algorithm: %s", pkalg);
537 goto done;
538 }
539 key = key_from_blob(pkblob, blen);
540 if (key == NULL) {
67fa09f5 541 error("userauth_hostbased: cannot decode key: %s", pkalg);
542 goto done;
543 }
544 if (key->type != pktype) {
545 error("userauth_hostbased: type mismatch for decoded key "
546 "(received %d, expected %d)", key->type, pktype);
8002af61 547 goto done;
548 }
8dddf799 549 service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
550 authctxt->service;
8002af61 551 buffer_init(&b);
8dddf799 552 buffer_put_string(&b, session_id2, session_id2_len);
8002af61 553 /* reconstruct packet */
554 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
555 buffer_put_cstring(&b, authctxt->user);
8dddf799 556 buffer_put_cstring(&b, service);
8002af61 557 buffer_put_cstring(&b, "hostbased");
558 buffer_put_string(&b, pkalg, alen);
559 buffer_put_string(&b, pkblob, blen);
560 buffer_put_cstring(&b, chost);
561 buffer_put_cstring(&b, cuser);
562#ifdef DEBUG_PK
563 buffer_dump(&b);
564#endif
565 /* test for allowed key and correct signature */
1853d1ef 566 authenticated = 0;
567 if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
568 PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
569 buffer_len(&b))) == 1)
63284fbb 570 authenticated = 1;
8002af61 571
572 buffer_clear(&b);
8002af61 573done:
574 debug2("userauth_hostbased: authenticated %d", authenticated);
67fa09f5 575 if (key != NULL)
576 key_free(key);
8002af61 577 xfree(pkalg);
578 xfree(pkblob);
579 xfree(cuser);
580 xfree(chost);
581 xfree(sig);
582 return authenticated;
583}
584
94ec8c6b 585/* get current user */
a306f2dd 586
587struct passwd*
588auth_get_user(void)
589{
94ec8c6b 590 return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
a306f2dd 591}
592
94ec8c6b 593#define DELIM ","
594
ffb215be 595static char *
94ec8c6b 596authmethods_get(void)
a306f2dd 597{
94ec8c6b 598 Authmethod *method = NULL;
3469eac4 599 Buffer b;
94ec8c6b 600 char *list;
601
3469eac4 602 buffer_init(&b);
94ec8c6b 603 for (method = authmethods; method->name != NULL; method++) {
604 if (strcmp(method->name, "none") == 0)
605 continue;
606 if (method->enabled != NULL && *(method->enabled) != 0) {
3469eac4 607 if (buffer_len(&b) > 0)
608 buffer_append(&b, ",", 1);
609 buffer_append(&b, method->name, strlen(method->name));
a306f2dd 610 }
611 }
3469eac4 612 buffer_append(&b, "\0", 1);
613 list = xstrdup(buffer_ptr(&b));
614 buffer_free(&b);
94ec8c6b 615 return list;
616}
617
396c147e 618static Authmethod *
94ec8c6b 619authmethod_lookup(const char *name)
620{
621 Authmethod *method = NULL;
622 if (name != NULL)
623 for (method = authmethods; method->name != NULL; method++)
624 if (method->enabled != NULL &&
625 *(method->enabled) != 0 &&
626 strcmp(name, method->name) == 0)
627 return method;
628 debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
629 return NULL;
a306f2dd 630}
This page took 0.337555 seconds and 5 git commands to generate.