diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | auth-options.c | 43 | ||||
-rw-r--r-- | auth-options.h | 3 | ||||
-rw-r--r-- | auth.c | 41 | ||||
-rw-r--r-- | auth.h | 4 | ||||
-rw-r--r-- | auth2-pubkey.c | 102 | ||||
-rw-r--r-- | key.c | 4 | ||||
-rw-r--r-- | servconf.c | 18 | ||||
-rw-r--r-- | servconf.h | 3 | ||||
-rw-r--r-- | sshd.8 | 15 | ||||
-rw-r--r-- | sshd_config.5 | 41 |
11 files changed, 262 insertions, 34 deletions
@@ -31,6 +31,28 @@ | |||
31 | [sftp.c] | 31 | [sftp.c] |
32 | restore mput and mget which got lost in the tab-completion changes. | 32 | restore mput and mget which got lost in the tab-completion changes. |
33 | found by Kenneth Whitaker, ok djm@ | 33 | found by Kenneth Whitaker, ok djm@ |
34 | - djm@cvs.openbsd.org 2010/05/07 11:30:30 | ||
35 | [auth-options.c auth-options.h auth.c auth.h auth2-pubkey.c] | ||
36 | [key.c servconf.c servconf.h sshd.8 sshd_config.5] | ||
37 | add some optional indirection to matching of principal names listed | ||
38 | in certificates. Currently, a certificate must include the a user's name | ||
39 | to be accepted for authentication. This change adds the ability to | ||
40 | specify a list of certificate principal names that are acceptable. | ||
41 | |||
42 | When authenticating using a CA trusted through ~/.ssh/authorized_keys, | ||
43 | this adds a new principals="name1[,name2,...]" key option. | ||
44 | |||
45 | For CAs listed through sshd_config's TrustedCAKeys option, a new config | ||
46 | option "AuthorizedPrincipalsFile" specifies a per-user file containing | ||
47 | the list of acceptable names. | ||
48 | |||
49 | If either option is absent, the current behaviour of requiring the | ||
50 | username to appear in principals continues to apply. | ||
51 | |||
52 | These options are useful for role accounts, disjoint account namespaces | ||
53 | and "user@realm"-style naming policies in certificates. | ||
54 | |||
55 | feedback and ok markus@ | ||
34 | 56 | ||
35 | 20100423 | 57 | 20100423 |
36 | - (dtucker) [configure.ac] Bug #1756: Check for the existence of a lib64 dir | 58 | - (dtucker) [configure.ac] Bug #1756: Check for the existence of a lib64 dir |
diff --git a/auth-options.c b/auth-options.c index 60d5f749b..57a67ec79 100644 --- a/auth-options.c +++ b/auth-options.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth-options.c,v 1.50 2010/04/16 01:47:26 djm Exp $ */ | 1 | /* $OpenBSD: auth-options.c,v 1.51 2010/05/07 11:30:29 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 |
@@ -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) { |
diff --git a/auth-options.h b/auth-options.h index 20f0dbe3e..7455c9454 100644 --- a/auth-options.h +++ b/auth-options.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth-options.h,v 1.19 2010/04/16 01:47:26 djm Exp $ */ | 1 | /* $OpenBSD: auth-options.h,v 1.20 2010/05/07 11:30:29 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -31,6 +31,7 @@ extern char *forced_command; | |||
31 | extern struct envstring *custom_environment; | 31 | extern struct envstring *custom_environment; |
32 | extern int forced_tun_device; | 32 | extern int forced_tun_device; |
33 | extern int key_is_cert_authority; | 33 | extern int key_is_cert_authority; |
34 | extern char *authorized_principals; | ||
34 | 35 | ||
35 | int auth_parse_options(struct passwd *, char *, char *, u_long); | 36 | int auth_parse_options(struct passwd *, char *, char *, u_long); |
36 | void auth_clear_options(void); | 37 | void auth_clear_options(void); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.c,v 1.86 2010/03/05 02:58:11 djm Exp $ */ | 1 | /* $OpenBSD: auth.c,v 1.87 2010/05/07 11:30:29 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -366,6 +366,14 @@ authorized_keys_file2(struct passwd *pw) | |||
366 | return expand_authorized_keys(options.authorized_keys_file2, pw); | 366 | return expand_authorized_keys(options.authorized_keys_file2, pw); |
367 | } | 367 | } |
368 | 368 | ||
369 | char * | ||
370 | authorized_principals_file(struct passwd *pw) | ||
371 | { | ||
372 | if (options.authorized_principals_file == NULL) | ||
373 | return NULL; | ||
374 | return expand_authorized_keys(options.authorized_principals_file, pw); | ||
375 | } | ||
376 | |||
369 | /* return ok if key exists in sysfile or userfile */ | 377 | /* return ok if key exists in sysfile or userfile */ |
370 | HostStatus | 378 | HostStatus |
371 | check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, | 379 | check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, |
@@ -477,21 +485,18 @@ secure_filename(FILE *f, const char *file, struct passwd *pw, | |||
477 | return 0; | 485 | return 0; |
478 | } | 486 | } |
479 | 487 | ||
480 | FILE * | 488 | static FILE * |
481 | auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) | 489 | auth_openfile(const char *file, struct passwd *pw, int strict_modes, |
490 | int log_missing, char *file_type) | ||
482 | { | 491 | { |
483 | char line[1024]; | 492 | char line[1024]; |
484 | struct stat st; | 493 | struct stat st; |
485 | int fd; | 494 | int fd; |
486 | FILE *f; | 495 | FILE *f; |
487 | 496 | ||
488 | /* | ||
489 | * Open the file containing the authorized keys | ||
490 | * Fail quietly if file does not exist | ||
491 | */ | ||
492 | if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { | 497 | if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { |
493 | if (errno != ENOENT) | 498 | if (log_missing || errno != ENOENT) |
494 | debug("Could not open keyfile '%s': %s", file, | 499 | debug("Could not open %s '%s': %s", file_type, file, |
495 | strerror(errno)); | 500 | strerror(errno)); |
496 | return NULL; | 501 | return NULL; |
497 | } | 502 | } |
@@ -501,8 +506,8 @@ auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) | |||
501 | return NULL; | 506 | return NULL; |
502 | } | 507 | } |
503 | if (!S_ISREG(st.st_mode)) { | 508 | if (!S_ISREG(st.st_mode)) { |
504 | logit("User %s authorized keys %s is not a regular file", | 509 | logit("User %s %s %s is not a regular file", |
505 | pw->pw_name, file); | 510 | pw->pw_name, file_type, file); |
506 | close(fd); | 511 | close(fd); |
507 | return NULL; | 512 | return NULL; |
508 | } | 513 | } |
@@ -521,6 +526,20 @@ auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) | |||
521 | return f; | 526 | return f; |
522 | } | 527 | } |
523 | 528 | ||
529 | |||
530 | FILE * | ||
531 | auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) | ||
532 | { | ||
533 | return auth_openfile(file, pw, strict_modes, 1, "authorized keys"); | ||
534 | } | ||
535 | |||
536 | FILE * | ||
537 | auth_openprincipals(const char *file, struct passwd *pw, int strict_modes) | ||
538 | { | ||
539 | return auth_openfile(file, pw, strict_modes, 0, | ||
540 | "authorized principals"); | ||
541 | } | ||
542 | |||
524 | struct passwd * | 543 | struct passwd * |
525 | getpwnamallow(const char *user) | 544 | getpwnamallow(const char *user) |
526 | { | 545 | { |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.h,v 1.65 2010/03/04 10:36:03 djm Exp $ */ | 1 | /* $OpenBSD: auth.h,v 1.66 2010/05/07 11:30:29 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -169,8 +169,10 @@ void abandon_challenge_response(Authctxt *); | |||
169 | 169 | ||
170 | char *authorized_keys_file(struct passwd *); | 170 | char *authorized_keys_file(struct passwd *); |
171 | char *authorized_keys_file2(struct passwd *); | 171 | char *authorized_keys_file2(struct passwd *); |
172 | char *authorized_principals_file(struct passwd *); | ||
172 | 173 | ||
173 | FILE *auth_openkeyfile(const char *, struct passwd *, int); | 174 | FILE *auth_openkeyfile(const char *, struct passwd *, int); |
175 | FILE *auth_openprincipals(const char *, struct passwd *, int); | ||
174 | int auth_key_is_revoked(Key *); | 176 | int auth_key_is_revoked(Key *); |
175 | 177 | ||
176 | HostStatus | 178 | HostStatus |
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 83ecd6590..6b4a99725 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.23 2010/04/16 01:47:26 djm Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.24 2010/05/07 11:30:29 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -57,6 +57,7 @@ | |||
57 | #include "monitor_wrap.h" | 57 | #include "monitor_wrap.h" |
58 | #include "misc.h" | 58 | #include "misc.h" |
59 | #include "authfile.h" | 59 | #include "authfile.h" |
60 | #include "match.h" | ||
60 | 61 | ||
61 | /* import */ | 62 | /* import */ |
62 | extern ServerOptions options; | 63 | extern ServerOptions options; |
@@ -176,6 +177,63 @@ done: | |||
176 | return authenticated; | 177 | return authenticated; |
177 | } | 178 | } |
178 | 179 | ||
180 | static int | ||
181 | match_principals_option(const char *principal_list, struct KeyCert *cert) | ||
182 | { | ||
183 | char *result; | ||
184 | u_int i; | ||
185 | |||
186 | /* XXX percent_expand() sequences for authorized_principals? */ | ||
187 | |||
188 | for (i = 0; i < cert->nprincipals; i++) { | ||
189 | if ((result = match_list(cert->principals[i], | ||
190 | principal_list, NULL)) != NULL) { | ||
191 | debug3("matched principal from key options \"%.100s\"", | ||
192 | result); | ||
193 | xfree(result); | ||
194 | return 1; | ||
195 | } | ||
196 | } | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int | ||
201 | match_principals_file(const char *file, struct passwd *pw, struct KeyCert *cert) | ||
202 | { | ||
203 | FILE *f; | ||
204 | char line[SSH_MAX_PUBKEY_BYTES], *cp; | ||
205 | u_long linenum = 0; | ||
206 | u_int i; | ||
207 | |||
208 | temporarily_use_uid(pw); | ||
209 | debug("trying authorized principals file %s", file); | ||
210 | if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { | ||
211 | restore_uid(); | ||
212 | return 0; | ||
213 | } | ||
214 | while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { | ||
215 | /* Skip leading whitespace, empty and comment lines. */ | ||
216 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) | ||
217 | ; | ||
218 | if (!*cp || *cp == '\n' || *cp == '#') | ||
219 | continue; | ||
220 | line[strcspn(line, "\n")] = '\0'; | ||
221 | |||
222 | for (i = 0; i < cert->nprincipals; i++) { | ||
223 | if (strcmp(cp, cert->principals[i]) == 0) { | ||
224 | debug3("matched principal from file \"%.100s\"", | ||
225 | cert->principals[i]); | ||
226 | fclose(f); | ||
227 | restore_uid(); | ||
228 | return 1; | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | fclose(f); | ||
233 | restore_uid(); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
179 | /* return 1 if user allows given key */ | 237 | /* return 1 if user allows given key */ |
180 | static int | 238 | static int |
181 | user_key_allowed2(struct passwd *pw, Key *key, char *file) | 239 | user_key_allowed2(struct passwd *pw, Key *key, char *file) |
@@ -244,13 +302,26 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) | |||
244 | SSH_FP_HEX); | 302 | SSH_FP_HEX); |
245 | debug("matching CA found: file %s, line %lu, %s %s", | 303 | debug("matching CA found: file %s, line %lu, %s %s", |
246 | file, linenum, key_type(found), fp); | 304 | file, linenum, key_type(found), fp); |
247 | if (key_cert_check_authority(key, 0, 0, pw->pw_name, | 305 | /* |
248 | &reason) != 0) { | 306 | * If the user has specified a list of principals as |
307 | * a key option, then prefer that list to matching | ||
308 | * their username in the certificate principals list. | ||
309 | */ | ||
310 | if (authorized_principals != NULL && | ||
311 | !match_principals_option(authorized_principals, | ||
312 | key->cert)) { | ||
313 | reason = "Certificate does not contain an " | ||
314 | "authorized principal"; | ||
315 | fail_reason: | ||
249 | xfree(fp); | 316 | xfree(fp); |
250 | error("%s", reason); | 317 | error("%s", reason); |
251 | auth_debug_add("%s", reason); | 318 | auth_debug_add("%s", reason); |
252 | continue; | 319 | continue; |
253 | } | 320 | } |
321 | if (key_cert_check_authority(key, 0, 0, | ||
322 | authorized_principals == NULL ? pw->pw_name : NULL, | ||
323 | &reason) != 0) | ||
324 | goto fail_reason; | ||
254 | if (auth_cert_options(key, pw) != 0) { | 325 | if (auth_cert_options(key, pw) != 0) { |
255 | xfree(fp); | 326 | xfree(fp); |
256 | continue; | 327 | continue; |
@@ -284,7 +355,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) | |||
284 | static int | 355 | static int |
285 | user_cert_trusted_ca(struct passwd *pw, Key *key) | 356 | user_cert_trusted_ca(struct passwd *pw, Key *key) |
286 | { | 357 | { |
287 | char *ca_fp; | 358 | char *ca_fp, *principals_file = NULL; |
288 | const char *reason; | 359 | const char *reason; |
289 | int ret = 0; | 360 | int ret = 0; |
290 | 361 | ||
@@ -301,11 +372,24 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
301 | options.trusted_user_ca_keys); | 372 | options.trusted_user_ca_keys); |
302 | goto out; | 373 | goto out; |
303 | } | 374 | } |
304 | if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) { | 375 | /* |
305 | error("%s", reason); | 376 | * If AuthorizedPrincipals is in use, then compare the certificate |
306 | auth_debug_add("%s", reason); | 377 | * principals against the names in that file rather than matching |
307 | goto out; | 378 | * against the username. |
379 | */ | ||
380 | if ((principals_file = authorized_principals_file(pw)) != NULL) { | ||
381 | if (!match_principals_file(principals_file, pw, key->cert)) { | ||
382 | reason = "Certificate does not contain an " | ||
383 | "authorized principal"; | ||
384 | fail_reason: | ||
385 | error("%s", reason); | ||
386 | auth_debug_add("%s", reason); | ||
387 | goto out; | ||
388 | } | ||
308 | } | 389 | } |
390 | if (key_cert_check_authority(key, 0, 1, | ||
391 | principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) | ||
392 | goto fail_reason; | ||
309 | if (auth_cert_options(key, pw) != 0) | 393 | if (auth_cert_options(key, pw) != 0) |
310 | goto out; | 394 | goto out; |
311 | 395 | ||
@@ -315,6 +399,8 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
315 | ret = 1; | 399 | ret = 1; |
316 | 400 | ||
317 | out: | 401 | out: |
402 | if (principals_file != NULL) | ||
403 | xfree(principals_file); | ||
318 | if (ca_fp != NULL) | 404 | if (ca_fp != NULL) |
319 | xfree(ca_fp); | 405 | xfree(ca_fp); |
320 | return ret; | 406 | return ret; |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: key.c,v 1.87 2010/04/16 01:47:26 djm Exp $ */ | 1 | /* $OpenBSD: key.c,v 1.88 2010/05/07 11:30:29 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * read_bignum(): | 3 | * read_bignum(): |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -1623,7 +1623,7 @@ key_cert_check_authority(const Key *k, int want_host, int require_principal, | |||
1623 | *reason = "Certificate lacks principal list"; | 1623 | *reason = "Certificate lacks principal list"; |
1624 | return -1; | 1624 | return -1; |
1625 | } | 1625 | } |
1626 | } else { | 1626 | } else if (name != NULL) { |
1627 | principal_matches = 0; | 1627 | principal_matches = 0; |
1628 | for (i = 0; i < k->cert->nprincipals; i++) { | 1628 | for (i = 0; i < k->cert->nprincipals; i++) { |
1629 | if (strcmp(name, k->cert->principals[i]) == 0) { | 1629 | if (strcmp(name, k->cert->principals[i]) == 0) { |
diff --git a/servconf.c b/servconf.c index 7d027ddb9..c556986e3 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.c,v 1.207 2010/03/25 23:38:28 djm Exp $ */ | 1 | /* $OpenBSD: servconf.c,v 1.208 2010/05/07 11:30:29 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -131,6 +131,7 @@ initialize_server_options(ServerOptions *options) | |||
131 | options->zero_knowledge_password_authentication = -1; | 131 | options->zero_knowledge_password_authentication = -1; |
132 | options->revoked_keys_file = NULL; | 132 | options->revoked_keys_file = NULL; |
133 | options->trusted_user_ca_keys = NULL; | 133 | options->trusted_user_ca_keys = NULL; |
134 | options->authorized_principals_file = NULL; | ||
134 | } | 135 | } |
135 | 136 | ||
136 | void | 137 | void |
@@ -310,7 +311,7 @@ typedef enum { | |||
310 | sMatch, sPermitOpen, sForceCommand, sChrootDirectory, | 311 | sMatch, sPermitOpen, sForceCommand, sChrootDirectory, |
311 | sUsePrivilegeSeparation, sAllowAgentForwarding, | 312 | sUsePrivilegeSeparation, sAllowAgentForwarding, |
312 | sZeroKnowledgePasswordAuthentication, sHostCertificate, | 313 | sZeroKnowledgePasswordAuthentication, sHostCertificate, |
313 | sRevokedKeys, sTrustedUserCAKeys, | 314 | sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, |
314 | sDeprecated, sUnsupported | 315 | sDeprecated, sUnsupported |
315 | } ServerOpCodes; | 316 | } ServerOpCodes; |
316 | 317 | ||
@@ -432,6 +433,7 @@ static struct { | |||
432 | { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, | 433 | { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, |
433 | { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, | 434 | { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, |
434 | { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, | 435 | { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, |
436 | { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_GLOBAL }, | ||
435 | { NULL, sBadOption, 0 } | 437 | { NULL, sBadOption, 0 } |
436 | }; | 438 | }; |
437 | 439 | ||
@@ -1218,10 +1220,14 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1218 | * AuthorizedKeysFile /etc/ssh_keys/%u | 1220 | * AuthorizedKeysFile /etc/ssh_keys/%u |
1219 | */ | 1221 | */ |
1220 | case sAuthorizedKeysFile: | 1222 | case sAuthorizedKeysFile: |
1223 | charptr = &options->authorized_keys_file; | ||
1224 | goto parse_tilde_filename; | ||
1221 | case sAuthorizedKeysFile2: | 1225 | case sAuthorizedKeysFile2: |
1222 | charptr = (opcode == sAuthorizedKeysFile) ? | 1226 | charptr = &options->authorized_keys_file2; |
1223 | &options->authorized_keys_file : | 1227 | goto parse_tilde_filename; |
1224 | &options->authorized_keys_file2; | 1228 | case sAuthorizedPrincipalsFile: |
1229 | charptr = &options->authorized_principals_file; | ||
1230 | parse_tilde_filename: | ||
1225 | arg = strdelim(&cp); | 1231 | arg = strdelim(&cp); |
1226 | if (!arg || *arg == '\0') | 1232 | if (!arg || *arg == '\0') |
1227 | fatal("%s line %d: missing file name.", | 1233 | fatal("%s line %d: missing file name.", |
@@ -1682,6 +1688,8 @@ dump_config(ServerOptions *o) | |||
1682 | dump_cfg_string(sChrootDirectory, o->chroot_directory); | 1688 | dump_cfg_string(sChrootDirectory, o->chroot_directory); |
1683 | dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); | 1689 | dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); |
1684 | dump_cfg_string(sRevokedKeys, o->revoked_keys_file); | 1690 | dump_cfg_string(sRevokedKeys, o->revoked_keys_file); |
1691 | dump_cfg_string(sAuthorizedPrincipalsFile, | ||
1692 | o->authorized_principals_file); | ||
1685 | 1693 | ||
1686 | /* string arguments requiring a lookup */ | 1694 | /* string arguments requiring a lookup */ |
1687 | dump_cfg_string(sLogLevel, log_level_name(o->log_level)); | 1695 | dump_cfg_string(sLogLevel, log_level_name(o->log_level)); |
diff --git a/servconf.h b/servconf.h index 860009f9c..45d2a2ae3 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.h,v 1.92 2010/03/04 10:36:03 djm Exp $ */ | 1 | /* $OpenBSD: servconf.h,v 1.93 2010/05/07 11:30:30 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -156,6 +156,7 @@ typedef struct { | |||
156 | char *chroot_directory; | 156 | char *chroot_directory; |
157 | char *revoked_keys_file; | 157 | char *revoked_keys_file; |
158 | char *trusted_user_ca_keys; | 158 | char *trusted_user_ca_keys; |
159 | char *authorized_principals_file; | ||
159 | } ServerOptions; | 160 | } ServerOptions; |
160 | 161 | ||
161 | void initialize_server_options(ServerOptions *); | 162 | void initialize_server_options(ServerOptions *); |
@@ -34,8 +34,8 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: sshd.8,v 1.255 2010/03/05 06:50:35 jmc Exp $ | 37 | .\" $OpenBSD: sshd.8,v 1.256 2010/05/07 11:30:30 djm Exp $ |
38 | .Dd $Mdocdate: March 5 2010 $ | 38 | .Dd $Mdocdate: May 7 2010 $ |
39 | .Dt SSHD 8 | 39 | .Dt SSHD 8 |
40 | .Os | 40 | .Os |
41 | .Sh NAME | 41 | .Sh NAME |
@@ -602,6 +602,17 @@ Multiple | |||
602 | options may be applied separated by commas. | 602 | options may be applied separated by commas. |
603 | No pattern matching is performed on the specified hostnames, | 603 | No pattern matching is performed on the specified hostnames, |
604 | they must be literal domains or addresses. | 604 | they must be literal domains or addresses. |
605 | .It Cm principals="principals" | ||
606 | On a | ||
607 | .Cm cert-authority | ||
608 | line, specifies allowed principals for certificate authentication as a | ||
609 | comma-separated list. | ||
610 | At least one name from the list must appear in the certificate's | ||
611 | list of principals for the certificate to be accepted. | ||
612 | This option is ignored for keys that are not marked as trusted certificate | ||
613 | signers using the | ||
614 | .Cm cert-authority | ||
615 | option. | ||
605 | .It Cm tunnel="n" | 616 | .It Cm tunnel="n" |
606 | Force a | 617 | Force a |
607 | .Xr tun 4 | 618 | .Xr tun 4 |
diff --git a/sshd_config.5 b/sshd_config.5 index 2f5410281..a5260d358 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -34,8 +34,8 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: sshd_config.5,v 1.120 2010/03/04 23:17:25 djm Exp $ | 37 | .\" $OpenBSD: sshd_config.5,v 1.121 2010/05/07 11:30:30 djm Exp $ |
38 | .Dd $Mdocdate: March 4 2010 $ | 38 | .Dd $Mdocdate: May 7 2010 $ |
39 | .Dt SSHD_CONFIG 5 | 39 | .Dt SSHD_CONFIG 5 |
40 | .Os | 40 | .Os |
41 | .Sh NAME | 41 | .Sh NAME |
@@ -167,6 +167,43 @@ is taken to be an absolute path or one relative to the user's home | |||
167 | directory. | 167 | directory. |
168 | The default is | 168 | The default is |
169 | .Dq .ssh/authorized_keys . | 169 | .Dq .ssh/authorized_keys . |
170 | .It Cm AuthorizedPrincipalsFile | ||
171 | Specifies a file that lists principal names that are accepted for | ||
172 | certificate authentication. | ||
173 | When using certificates signed by a key listed in | ||
174 | .Cm TrustedUserCAKeys , | ||
175 | this file lists names, one of which must appear in the certificate for it | ||
176 | to be accepted for authentication. | ||
177 | Names are listed one per line; empty lines and comments starting with | ||
178 | .Ql # | ||
179 | are ignored. | ||
180 | .Pp | ||
181 | .Cm AuthorizedPrincipalsFile | ||
182 | may contain tokens of the form %T which are substituted during connection | ||
183 | setup. | ||
184 | The following tokens are defined: %% is replaced by a literal '%', | ||
185 | %h is replaced by the home directory of the user being authenticated, and | ||
186 | %u is replaced by the username of that user. | ||
187 | After expansion, | ||
188 | .Cm AuthorizedPrincipalsFile | ||
189 | is taken to be an absolute path or one relative to the user's home | ||
190 | directory. | ||
191 | .Pp | ||
192 | The default is not to use a principals file - in this case, the username | ||
193 | of the user must appear in a certificate's principals list for it to be | ||
194 | accepted. | ||
195 | Note that | ||
196 | .Cm AuthorizedPrincipalsFile | ||
197 | is only used when authentication proceeds using a CA listed in | ||
198 | .Cm TrustedUserCAKeys | ||
199 | and is not consulted for certification authorities trusted via | ||
200 | .Pa ~/.ssh/authorized_keys , | ||
201 | though the | ||
202 | .Cm principals= | ||
203 | key option offers a similar facility (see | ||
204 | .Xr sshd 8 | ||
205 | for details). | ||
206 | .Pp | ||
170 | .It Cm Banner | 207 | .It Cm Banner |
171 | The contents of the specified file are sent to the remote user before | 208 | The contents of the specified file are sent to the remote user before |
172 | authentication is allowed. | 209 | authentication is allowed. |