diff options
Diffstat (limited to 'auth-options.c')
-rw-r--r-- | auth-options.c | 328 |
1 files changed, 224 insertions, 104 deletions
diff --git a/auth-options.c b/auth-options.c index 69b314fbd..a7040247f 100644 --- a/auth-options.c +++ b/auth-options.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth-options.c,v 1.49 2010/03/16 15:46:52 stevesk Exp $ */ | 1 | /* $OpenBSD: auth-options.c,v 1.52 2010/05/20 23:46:02 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -27,10 +27,10 @@ | |||
27 | #include "canohost.h" | 27 | #include "canohost.h" |
28 | #include "buffer.h" | 28 | #include "buffer.h" |
29 | #include "channels.h" | 29 | #include "channels.h" |
30 | #include "auth-options.h" | ||
31 | #include "servconf.h" | 30 | #include "servconf.h" |
32 | #include "misc.h" | 31 | #include "misc.h" |
33 | #include "key.h" | 32 | #include "key.h" |
33 | #include "auth-options.h" | ||
34 | #include "hostfile.h" | 34 | #include "hostfile.h" |
35 | #include "auth.h" | 35 | #include "auth.h" |
36 | #ifdef GSSAPI | 36 | #ifdef GSSAPI |
@@ -55,6 +55,9 @@ struct envstring *custom_environment = NULL; | |||
55 | /* "tunnel=" option. */ | 55 | /* "tunnel=" option. */ |
56 | int forced_tun_device = -1; | 56 | int forced_tun_device = -1; |
57 | 57 | ||
58 | /* "principals=" option. */ | ||
59 | char *authorized_principals = NULL; | ||
60 | |||
58 | extern ServerOptions options; | 61 | extern ServerOptions options; |
59 | 62 | ||
60 | void | 63 | void |
@@ -76,6 +79,10 @@ auth_clear_options(void) | |||
76 | xfree(forced_command); | 79 | xfree(forced_command); |
77 | forced_command = NULL; | 80 | forced_command = NULL; |
78 | } | 81 | } |
82 | if (authorized_principals) { | ||
83 | xfree(authorized_principals); | ||
84 | authorized_principals = NULL; | ||
85 | } | ||
79 | forced_tun_device = -1; | 86 | forced_tun_device = -1; |
80 | channel_clear_permitted_opens(); | 87 | channel_clear_permitted_opens(); |
81 | } | 88 | } |
@@ -141,6 +148,8 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
141 | cp = "command=\""; | 148 | cp = "command=\""; |
142 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { | 149 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { |
143 | opts += strlen(cp); | 150 | opts += strlen(cp); |
151 | if (forced_command != NULL) | ||
152 | xfree(forced_command); | ||
144 | forced_command = xmalloc(strlen(opts) + 1); | 153 | forced_command = xmalloc(strlen(opts) + 1); |
145 | i = 0; | 154 | i = 0; |
146 | while (*opts) { | 155 | while (*opts) { |
@@ -167,6 +176,38 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | |||
167 | opts++; | 176 | opts++; |
168 | goto next_option; | 177 | goto next_option; |
169 | } | 178 | } |
179 | cp = "principals=\""; | ||
180 | if (strncasecmp(opts, cp, strlen(cp)) == 0) { | ||
181 | opts += strlen(cp); | ||
182 | if (authorized_principals != NULL) | ||
183 | xfree(authorized_principals); | ||
184 | authorized_principals = xmalloc(strlen(opts) + 1); | ||
185 | i = 0; | ||
186 | while (*opts) { | ||
187 | if (*opts == '"') | ||
188 | break; | ||
189 | if (*opts == '\\' && opts[1] == '"') { | ||
190 | opts += 2; | ||
191 | authorized_principals[i++] = '"'; | ||
192 | continue; | ||
193 | } | ||
194 | authorized_principals[i++] = *opts++; | ||
195 | } | ||
196 | if (!*opts) { | ||
197 | debug("%.100s, line %lu: missing end quote", | ||
198 | file, linenum); | ||
199 | auth_debug_add("%.100s, line %lu: missing end quote", | ||
200 | file, linenum); | ||
201 | xfree(authorized_principals); | ||
202 | authorized_principals = NULL; | ||
203 | goto bad_option; | ||
204 | } | ||
205 | authorized_principals[i] = '\0'; | ||
206 | auth_debug_add("principals: %.900s", | ||
207 | authorized_principals); | ||
208 | opts++; | ||
209 | goto next_option; | ||
210 | } | ||
170 | cp = "environment=\""; | 211 | cp = "environment=\""; |
171 | if (options.permit_user_env && | 212 | if (options.permit_user_env && |
172 | strncasecmp(opts, cp, strlen(cp)) == 0) { | 213 | strncasecmp(opts, cp, strlen(cp)) == 0) { |
@@ -376,123 +417,147 @@ bad_option: | |||
376 | return 0; | 417 | return 0; |
377 | } | 418 | } |
378 | 419 | ||
379 | /* | 420 | #define OPTIONS_CRITICAL 1 |
380 | * Set options from certificate constraints. These supersede user key options | 421 | #define OPTIONS_EXTENSIONS 2 |
381 | * so this must be called after auth_parse_options(). | 422 | static int |
382 | */ | 423 | parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw, |
383 | int | 424 | u_int which, int crit, |
384 | auth_cert_constraints(Buffer *c_orig, struct passwd *pw) | 425 | int *cert_no_port_forwarding_flag, |
426 | int *cert_no_agent_forwarding_flag, | ||
427 | int *cert_no_x11_forwarding_flag, | ||
428 | int *cert_no_pty_flag, | ||
429 | int *cert_no_user_rc, | ||
430 | char **cert_forced_command, | ||
431 | int *cert_source_address_done) | ||
385 | { | 432 | { |
433 | char *command, *allowed; | ||
434 | const char *remote_ip; | ||
386 | u_char *name = NULL, *data_blob = NULL; | 435 | u_char *name = NULL, *data_blob = NULL; |
387 | u_int nlen, dlen, clen; | 436 | u_int nlen, dlen, clen; |
388 | Buffer c, data; | 437 | Buffer c, data; |
389 | int ret = -1; | 438 | int ret = -1, found; |
390 | |||
391 | int cert_no_port_forwarding_flag = 1; | ||
392 | int cert_no_agent_forwarding_flag = 1; | ||
393 | int cert_no_x11_forwarding_flag = 1; | ||
394 | int cert_no_pty_flag = 1; | ||
395 | int cert_no_user_rc = 1; | ||
396 | char *cert_forced_command = NULL; | ||
397 | int cert_source_address_done = 0; | ||
398 | 439 | ||
399 | buffer_init(&data); | 440 | buffer_init(&data); |
400 | 441 | ||
401 | /* Make copy to avoid altering original */ | 442 | /* Make copy to avoid altering original */ |
402 | buffer_init(&c); | 443 | buffer_init(&c); |
403 | buffer_append(&c, buffer_ptr(c_orig), buffer_len(c_orig)); | 444 | buffer_append(&c, optblob, optblob_len); |
404 | 445 | ||
405 | while (buffer_len(&c) > 0) { | 446 | while (buffer_len(&c) > 0) { |
406 | if ((name = buffer_get_string_ret(&c, &nlen)) == NULL || | 447 | if ((name = buffer_get_string_ret(&c, &nlen)) == NULL || |
407 | (data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) { | 448 | (data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) { |
408 | error("Certificate constraints corrupt"); | 449 | error("Certificate options corrupt"); |
409 | goto out; | 450 | goto out; |
410 | } | 451 | } |
411 | buffer_append(&data, data_blob, dlen); | 452 | buffer_append(&data, data_blob, dlen); |
412 | debug3("found certificate constraint \"%.100s\" len %u", | 453 | debug3("found certificate option \"%.100s\" len %u", |
413 | name, dlen); | 454 | name, dlen); |
414 | if (strlen(name) != nlen) { | 455 | if (strlen(name) != nlen) { |
415 | error("Certificate constraint name contains \\0"); | 456 | error("Certificate constraint name contains \\0"); |
416 | goto out; | 457 | goto out; |
417 | } | 458 | } |
418 | if (strcmp(name, "permit-X11-forwarding") == 0) | 459 | found = 0; |
419 | cert_no_x11_forwarding_flag = 0; | 460 | if ((which & OPTIONS_EXTENSIONS) != 0) { |
420 | else if (strcmp(name, "permit-agent-forwarding") == 0) | 461 | if (strcmp(name, "permit-X11-forwarding") == 0) { |
421 | cert_no_agent_forwarding_flag = 0; | 462 | *cert_no_x11_forwarding_flag = 0; |
422 | else if (strcmp(name, "permit-port-forwarding") == 0) | 463 | found = 1; |
423 | cert_no_port_forwarding_flag = 0; | 464 | } else if (strcmp(name, |
424 | else if (strcmp(name, "permit-pty") == 0) | 465 | "permit-agent-forwarding") == 0) { |
425 | cert_no_pty_flag = 0; | 466 | *cert_no_agent_forwarding_flag = 0; |
426 | else if (strcmp(name, "permit-user-rc") == 0) | 467 | found = 1; |
427 | cert_no_user_rc = 0; | 468 | } else if (strcmp(name, |
428 | else if (strcmp(name, "force-command") == 0) { | 469 | "permit-port-forwarding") == 0) { |
429 | char *command = buffer_get_string_ret(&data, &clen); | 470 | *cert_no_port_forwarding_flag = 0; |
430 | 471 | found = 1; | |
431 | if (command == NULL) { | 472 | } else if (strcmp(name, "permit-pty") == 0) { |
432 | error("Certificate constraint \"%s\" corrupt", | 473 | *cert_no_pty_flag = 0; |
433 | name); | 474 | found = 1; |
434 | goto out; | 475 | } else if (strcmp(name, "permit-user-rc") == 0) { |
476 | *cert_no_user_rc = 0; | ||
477 | found = 1; | ||
435 | } | 478 | } |
436 | if (strlen(command) != clen) { | 479 | } |
437 | error("force-command constraint contains \\0"); | 480 | if (!found && (which & OPTIONS_CRITICAL) != 0) { |
438 | goto out; | 481 | if (strcmp(name, "force-command") == 0) { |
439 | } | 482 | if ((command = buffer_get_string_ret(&data, |
440 | if (cert_forced_command != NULL) { | 483 | &clen)) == NULL) { |
441 | error("Certificate has multiple " | 484 | error("Certificate constraint \"%s\" " |
442 | "force-command constraints"); | 485 | "corrupt", name); |
443 | xfree(command); | 486 | goto out; |
444 | goto out; | 487 | } |
445 | } | 488 | if (strlen(command) != clen) { |
446 | cert_forced_command = command; | 489 | error("force-command constraint " |
447 | } else if (strcmp(name, "source-address") == 0) { | 490 | "contains \\0"); |
448 | char *allowed = buffer_get_string_ret(&data, &clen); | 491 | goto out; |
449 | const char *remote_ip = get_remote_ipaddr(); | 492 | } |
450 | 493 | if (*cert_forced_command != NULL) { | |
451 | if (allowed == NULL) { | 494 | error("Certificate has multiple " |
452 | error("Certificate constraint \"%s\" corrupt", | 495 | "force-command options"); |
453 | name); | 496 | xfree(command); |
454 | goto out; | 497 | goto out; |
455 | } | 498 | } |
456 | if (strlen(allowed) != clen) { | 499 | *cert_forced_command = command; |
457 | error("source-address constraint contains \\0"); | 500 | found = 1; |
458 | goto out; | ||
459 | } | ||
460 | if (cert_source_address_done++) { | ||
461 | error("Certificate has multiple " | ||
462 | "source-address constraints"); | ||
463 | xfree(allowed); | ||
464 | goto out; | ||
465 | } | 501 | } |
466 | switch (addr_match_cidr_list(remote_ip, allowed)) { | 502 | if (strcmp(name, "source-address") == 0) { |
467 | case 1: | 503 | if ((allowed = buffer_get_string_ret(&data, |
468 | /* accepted */ | 504 | &clen)) == NULL) { |
469 | xfree(allowed); | 505 | error("Certificate constraint " |
470 | break; | 506 | "\"%s\" corrupt", name); |
471 | case 0: | 507 | goto out; |
472 | /* no match */ | 508 | } |
473 | logit("Authentication tried for %.100s with " | 509 | if (strlen(allowed) != clen) { |
474 | "valid certificate but not from a " | 510 | error("source-address constraint " |
475 | "permitted host (ip=%.200s).", | 511 | "contains \\0"); |
476 | pw->pw_name, remote_ip); | 512 | goto out; |
477 | auth_debug_add("Your address '%.200s' is not " | 513 | } |
478 | "permitted to use this certificate for " | 514 | if ((*cert_source_address_done)++) { |
479 | "login.", remote_ip); | 515 | error("Certificate has multiple " |
480 | xfree(allowed); | 516 | "source-address options"); |
481 | goto out; | 517 | xfree(allowed); |
482 | case -1: | 518 | goto out; |
483 | error("Certificate source-address contents " | 519 | } |
484 | "invalid"); | 520 | remote_ip = get_remote_ipaddr(); |
485 | xfree(allowed); | 521 | switch (addr_match_cidr_list(remote_ip, |
486 | goto out; | 522 | allowed)) { |
523 | case 1: | ||
524 | /* accepted */ | ||
525 | xfree(allowed); | ||
526 | break; | ||
527 | case 0: | ||
528 | /* no match */ | ||
529 | logit("Authentication tried for %.100s " | ||
530 | "with valid certificate but not " | ||
531 | "from a permitted host " | ||
532 | "(ip=%.200s).", pw->pw_name, | ||
533 | remote_ip); | ||
534 | auth_debug_add("Your address '%.200s' " | ||
535 | "is not permitted to use this " | ||
536 | "certificate for login.", | ||
537 | remote_ip); | ||
538 | xfree(allowed); | ||
539 | goto out; | ||
540 | case -1: | ||
541 | error("Certificate source-address " | ||
542 | "contents invalid"); | ||
543 | xfree(allowed); | ||
544 | goto out; | ||
545 | } | ||
546 | found = 1; | ||
487 | } | 547 | } |
488 | } else { | ||
489 | error("Certificate constraint \"%s\" is not supported", | ||
490 | name); | ||
491 | goto out; | ||
492 | } | 548 | } |
493 | 549 | ||
494 | if (buffer_len(&data) != 0) { | 550 | if (!found) { |
495 | error("Certificate constraint \"%s\" corrupt " | 551 | if (crit) { |
552 | error("Certificate critical option \"%s\" " | ||
553 | "is not supported", name); | ||
554 | goto out; | ||
555 | } else { | ||
556 | logit("Certificate extension \"%s\" " | ||
557 | "is not supported", name); | ||
558 | } | ||
559 | } else if (buffer_len(&data) != 0) { | ||
560 | error("Certificate option \"%s\" corrupt " | ||
496 | "(extra data)", name); | 561 | "(extra data)", name); |
497 | goto out; | 562 | goto out; |
498 | } | 563 | } |
@@ -501,10 +566,73 @@ auth_cert_constraints(Buffer *c_orig, struct passwd *pw) | |||
501 | xfree(data_blob); | 566 | xfree(data_blob); |
502 | name = data_blob = NULL; | 567 | name = data_blob = NULL; |
503 | } | 568 | } |
504 | 569 | /* successfully parsed all options */ | |
505 | /* successfully parsed all constraints */ | ||
506 | ret = 0; | 570 | ret = 0; |
507 | 571 | ||
572 | out: | ||
573 | if (ret != 0 && | ||
574 | cert_forced_command != NULL && | ||
575 | *cert_forced_command != NULL) { | ||
576 | xfree(*cert_forced_command); | ||
577 | *cert_forced_command = NULL; | ||
578 | } | ||
579 | if (name != NULL) | ||
580 | xfree(name); | ||
581 | if (data_blob != NULL) | ||
582 | xfree(data_blob); | ||
583 | buffer_free(&data); | ||
584 | buffer_free(&c); | ||
585 | return ret; | ||
586 | } | ||
587 | |||
588 | /* | ||
589 | * Set options from critical certificate options. These supersede user key | ||
590 | * options so this must be called after auth_parse_options(). | ||
591 | */ | ||
592 | int | ||
593 | auth_cert_options(Key *k, struct passwd *pw) | ||
594 | { | ||
595 | int cert_no_port_forwarding_flag = 1; | ||
596 | int cert_no_agent_forwarding_flag = 1; | ||
597 | int cert_no_x11_forwarding_flag = 1; | ||
598 | int cert_no_pty_flag = 1; | ||
599 | int cert_no_user_rc = 1; | ||
600 | char *cert_forced_command = NULL; | ||
601 | int cert_source_address_done = 0; | ||
602 | |||
603 | if (key_cert_is_legacy(k)) { | ||
604 | /* All options are in the one field for v00 certs */ | ||
605 | if (parse_option_list(buffer_ptr(&k->cert->critical), | ||
606 | buffer_len(&k->cert->critical), pw, | ||
607 | OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1, | ||
608 | &cert_no_port_forwarding_flag, | ||
609 | &cert_no_agent_forwarding_flag, | ||
610 | &cert_no_x11_forwarding_flag, | ||
611 | &cert_no_pty_flag, | ||
612 | &cert_no_user_rc, | ||
613 | &cert_forced_command, | ||
614 | &cert_source_address_done) == -1) | ||
615 | return -1; | ||
616 | } else { | ||
617 | /* Separate options and extensions for v01 certs */ | ||
618 | if (parse_option_list(buffer_ptr(&k->cert->critical), | ||
619 | buffer_len(&k->cert->critical), pw, | ||
620 | OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, | ||
621 | &cert_forced_command, | ||
622 | &cert_source_address_done) == -1) | ||
623 | return -1; | ||
624 | if (parse_option_list(buffer_ptr(&k->cert->extensions), | ||
625 | buffer_len(&k->cert->extensions), pw, | ||
626 | OPTIONS_EXTENSIONS, 1, | ||
627 | &cert_no_port_forwarding_flag, | ||
628 | &cert_no_agent_forwarding_flag, | ||
629 | &cert_no_x11_forwarding_flag, | ||
630 | &cert_no_pty_flag, | ||
631 | &cert_no_user_rc, | ||
632 | NULL, NULL) == -1) | ||
633 | return -1; | ||
634 | } | ||
635 | |||
508 | no_port_forwarding_flag |= cert_no_port_forwarding_flag; | 636 | no_port_forwarding_flag |= cert_no_port_forwarding_flag; |
509 | no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; | 637 | no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; |
510 | no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; | 638 | no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; |
@@ -516,14 +644,6 @@ auth_cert_constraints(Buffer *c_orig, struct passwd *pw) | |||
516 | xfree(forced_command); | 644 | xfree(forced_command); |
517 | forced_command = cert_forced_command; | 645 | forced_command = cert_forced_command; |
518 | } | 646 | } |
519 | 647 | return 0; | |
520 | out: | ||
521 | if (name != NULL) | ||
522 | xfree(name); | ||
523 | if (data_blob != NULL) | ||
524 | xfree(data_blob); | ||
525 | buffer_free(&data); | ||
526 | buffer_free(&c); | ||
527 | return ret; | ||
528 | } | 648 | } |
529 | 649 | ||