diff options
author | Damien Miller <djm@mindrot.org> | 2010-05-10 11:58:03 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2010-05-10 11:58:03 +1000 |
commit | 30da3447d2ef3329cb0eb083cdddf84532659454 (patch) | |
tree | 02537d2355d77cc15d1bf9d266d474e660848012 /auth2-pubkey.c | |
parent | 099fc1634e1cc0f96b77a811e554bf9d796def8f (diff) |
- djm@cvs.openbsd.org 2010/05/07 11:30:30
[auth-options.c auth-options.h auth.c auth.h auth2-pubkey.c]
[key.c servconf.c servconf.h sshd.8 sshd_config.5]
add some optional indirection to matching of principal names listed
in certificates. Currently, a certificate must include the a user's name
to be accepted for authentication. This change adds the ability to
specify a list of certificate principal names that are acceptable.
When authenticating using a CA trusted through ~/.ssh/authorized_keys,
this adds a new principals="name1[,name2,...]" key option.
For CAs listed through sshd_config's TrustedCAKeys option, a new config
option "AuthorizedPrincipalsFile" specifies a per-user file containing
the list of acceptable names.
If either option is absent, the current behaviour of requiring the
username to appear in principals continues to apply.
These options are useful for role accounts, disjoint account namespaces
and "user@realm"-style naming policies in certificates.
feedback and ok markus@
Diffstat (limited to 'auth2-pubkey.c')
-rw-r--r-- | auth2-pubkey.c | 102 |
1 files changed, 94 insertions, 8 deletions
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; |