diff options
author | Colin Watson <cjwatson@debian.org> | 2010-08-23 23:52:36 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2010-08-23 23:52:36 +0100 |
commit | 78799892cb1858927be02be9737c594052e3f910 (patch) | |
tree | ac3dc2e848ab9dc62fe4252e01e52c3d456f628f /auth2-pubkey.c | |
parent | 3875951bb76a9ec62634ae4026c9cc885d933477 (diff) | |
parent | 31e30b835fd9695d3b6647cab4867001b092e28f (diff) |
* New upstream release (http://www.openssh.com/txt/release-5.6):
- Added a ControlPersist option to ssh_config(5) that automatically
starts a background ssh(1) multiplex master when connecting. This
connection can stay alive indefinitely, or can be set to automatically
close after a user-specified duration of inactivity (closes: #335697,
#350898, #454787, #500573, #550262).
- Support AuthorizedKeysFile, AuthorizedPrincipalsFile,
HostbasedUsesNameFromPacketOnly, and PermitTunnel in sshd_config(5)
Match blocks (closes: #549858).
- sftp(1): fix ls in working directories that contain globbing
characters in their pathnames (LP: #530714).
Diffstat (limited to 'auth2-pubkey.c')
-rw-r--r-- | auth2-pubkey.c | 145 |
1 files changed, 128 insertions, 17 deletions
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 49bb062af..2e15424e1 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.22 2010/03/10 23:27:17 djm Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.26 2010/06/29 23:16:46 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,83 @@ 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(char *file, struct passwd *pw, struct KeyCert *cert) | ||
202 | { | ||
203 | FILE *f; | ||
204 | char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; | ||
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. */ | ||
216 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) | ||
217 | ; | ||
218 | /* Skip blank and comment lines. */ | ||
219 | if ((ep = strchr(cp, '#')) != NULL) | ||
220 | *ep = '\0'; | ||
221 | if (!*cp || *cp == '\n') | ||
222 | continue; | ||
223 | /* Trim trailing whitespace. */ | ||
224 | ep = cp + strlen(cp) - 1; | ||
225 | while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) | ||
226 | *ep-- = '\0'; | ||
227 | /* | ||
228 | * If the line has internal whitespace then assume it has | ||
229 | * key options. | ||
230 | */ | ||
231 | line_opts = NULL; | ||
232 | if ((ep = strrchr(cp, ' ')) != NULL || | ||
233 | (ep = strrchr(cp, '\t')) != NULL) { | ||
234 | for (; *ep == ' ' || *ep == '\t'; ep++) | ||
235 | ;; | ||
236 | line_opts = cp; | ||
237 | cp = ep; | ||
238 | } | ||
239 | for (i = 0; i < cert->nprincipals; i++) { | ||
240 | if (strcmp(cp, cert->principals[i]) == 0) { | ||
241 | debug3("matched principal from file \"%.100s\"", | ||
242 | cert->principals[i]); | ||
243 | if (auth_parse_options(pw, line_opts, | ||
244 | file, linenum) != 1) | ||
245 | continue; | ||
246 | fclose(f); | ||
247 | restore_uid(); | ||
248 | return 1; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | fclose(f); | ||
253 | restore_uid(); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
179 | /* return 1 if user allows given key */ | 257 | /* return 1 if user allows given key */ |
180 | static int | 258 | static int |
181 | user_key_allowed2(struct passwd *pw, Key *key, char *file) | 259 | user_key_allowed2(struct passwd *pw, Key *key, char *file) |
@@ -233,26 +311,39 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) | |||
233 | continue; | 311 | continue; |
234 | } | 312 | } |
235 | } | 313 | } |
236 | if (auth_parse_options(pw, key_options, file, linenum) != 1) | 314 | if (key_is_cert(key)) { |
237 | continue; | ||
238 | if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) { | ||
239 | if (!key_is_cert_authority) | ||
240 | continue; | ||
241 | if (!key_equal(found, key->cert->signature_key)) | 315 | if (!key_equal(found, key->cert->signature_key)) |
242 | continue; | 316 | continue; |
317 | if (auth_parse_options(pw, key_options, file, | ||
318 | linenum) != 1) | ||
319 | continue; | ||
320 | if (!key_is_cert_authority) | ||
321 | continue; | ||
243 | fp = key_fingerprint(found, SSH_FP_MD5, | 322 | fp = key_fingerprint(found, SSH_FP_MD5, |
244 | SSH_FP_HEX); | 323 | SSH_FP_HEX); |
245 | debug("matching CA found: file %s, line %lu, %s %s", | 324 | debug("matching CA found: file %s, line %lu, %s %s", |
246 | file, linenum, key_type(found), fp); | 325 | file, linenum, key_type(found), fp); |
247 | if (key_cert_check_authority(key, 0, 0, pw->pw_name, | 326 | /* |
248 | &reason) != 0) { | 327 | * If the user has specified a list of principals as |
328 | * a key option, then prefer that list to matching | ||
329 | * their username in the certificate principals list. | ||
330 | */ | ||
331 | if (authorized_principals != NULL && | ||
332 | !match_principals_option(authorized_principals, | ||
333 | key->cert)) { | ||
334 | reason = "Certificate does not contain an " | ||
335 | "authorized principal"; | ||
336 | fail_reason: | ||
249 | xfree(fp); | 337 | xfree(fp); |
250 | error("%s", reason); | 338 | error("%s", reason); |
251 | auth_debug_add("%s", reason); | 339 | auth_debug_add("%s", reason); |
252 | continue; | 340 | continue; |
253 | } | 341 | } |
254 | if (auth_cert_constraints(&key->cert->constraints, | 342 | if (key_cert_check_authority(key, 0, 0, |
255 | pw) != 0) { | 343 | authorized_principals == NULL ? pw->pw_name : NULL, |
344 | &reason) != 0) | ||
345 | goto fail_reason; | ||
346 | if (auth_cert_options(key, pw) != 0) { | ||
256 | xfree(fp); | 347 | xfree(fp); |
257 | continue; | 348 | continue; |
258 | } | 349 | } |
@@ -262,7 +353,12 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) | |||
262 | xfree(fp); | 353 | xfree(fp); |
263 | found_key = 1; | 354 | found_key = 1; |
264 | break; | 355 | break; |
265 | } else if (!key_is_cert_authority && key_equal(found, key)) { | 356 | } else if (key_equal(found, key)) { |
357 | if (auth_parse_options(pw, key_options, file, | ||
358 | linenum) != 1) | ||
359 | continue; | ||
360 | if (key_is_cert_authority) | ||
361 | continue; | ||
266 | found_key = 1; | 362 | found_key = 1; |
267 | debug("matching key found: file %s, line %lu", | 363 | debug("matching key found: file %s, line %lu", |
268 | file, linenum); | 364 | file, linenum); |
@@ -285,7 +381,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) | |||
285 | static int | 381 | static int |
286 | user_cert_trusted_ca(struct passwd *pw, Key *key) | 382 | user_cert_trusted_ca(struct passwd *pw, Key *key) |
287 | { | 383 | { |
288 | char *ca_fp; | 384 | char *ca_fp, *principals_file = NULL; |
289 | const char *reason; | 385 | const char *reason; |
290 | int ret = 0; | 386 | int ret = 0; |
291 | 387 | ||
@@ -302,12 +398,25 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
302 | options.trusted_user_ca_keys); | 398 | options.trusted_user_ca_keys); |
303 | goto out; | 399 | goto out; |
304 | } | 400 | } |
305 | if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) { | 401 | /* |
306 | error("%s", reason); | 402 | * If AuthorizedPrincipals is in use, then compare the certificate |
307 | auth_debug_add("%s", reason); | 403 | * principals against the names in that file rather than matching |
308 | goto out; | 404 | * against the username. |
405 | */ | ||
406 | if ((principals_file = authorized_principals_file(pw)) != NULL) { | ||
407 | if (!match_principals_file(principals_file, pw, key->cert)) { | ||
408 | reason = "Certificate does not contain an " | ||
409 | "authorized principal"; | ||
410 | fail_reason: | ||
411 | error("%s", reason); | ||
412 | auth_debug_add("%s", reason); | ||
413 | goto out; | ||
414 | } | ||
309 | } | 415 | } |
310 | if (auth_cert_constraints(&key->cert->constraints, pw) != 0) | 416 | if (key_cert_check_authority(key, 0, 1, |
417 | principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) | ||
418 | goto fail_reason; | ||
419 | if (auth_cert_options(key, pw) != 0) | ||
311 | goto out; | 420 | goto out; |
312 | 421 | ||
313 | verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s", | 422 | verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s", |
@@ -316,6 +425,8 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
316 | ret = 1; | 425 | ret = 1; |
317 | 426 | ||
318 | out: | 427 | out: |
428 | if (principals_file != NULL) | ||
429 | xfree(principals_file); | ||
319 | if (ca_fp != NULL) | 430 | if (ca_fp != NULL) |
320 | xfree(ca_fp); | 431 | xfree(ca_fp); |
321 | return ret; | 432 | return ret; |