summaryrefslogtreecommitdiff
path: root/auth2-pubkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'auth2-pubkey.c')
-rw-r--r--auth2-pubkey.c615
1 files changed, 402 insertions, 213 deletions
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 169839b01..8024b1d6a 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 djm Exp $ */ 1/* $OpenBSD: auth2-pubkey.c,v 1.77 2018/03/03 03:15:51 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -73,42 +73,39 @@ extern ServerOptions options;
73extern u_char *session_id2; 73extern u_char *session_id2;
74extern u_int session_id2_len; 74extern u_int session_id2_len;
75 75
76static char *
77format_key(const struct sshkey *key)
78{
79 char *ret, *fp = sshkey_fingerprint(key,
80 options.fingerprint_hash, SSH_FP_DEFAULT);
81
82 xasprintf(&ret, "%s %s", sshkey_type(key), fp);
83 free(fp);
84 return ret;
85}
86
76static int 87static int
77userauth_pubkey(struct ssh *ssh) 88userauth_pubkey(struct ssh *ssh)
78{ 89{
79 Authctxt *authctxt = ssh->authctxt; 90 Authctxt *authctxt = ssh->authctxt;
91 struct passwd *pw = authctxt->pw;
80 struct sshbuf *b; 92 struct sshbuf *b;
81 struct sshkey *key = NULL; 93 struct sshkey *key = NULL;
82 char *pkalg, *userstyle = NULL, *fp = NULL; 94 char *pkalg, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
83 u_char *pkblob, *sig, have_sig; 95 u_char *pkblob, *sig, have_sig;
84 size_t blen, slen; 96 size_t blen, slen;
85 int r, pktype; 97 int r, pktype;
86 int authenticated = 0; 98 int authenticated = 0;
99 struct sshauthopt *authopts = NULL;
87 100
88 if (!authctxt->valid) { 101 if (!authctxt->valid) {
89 debug2("%s: disabled because of invalid user", __func__); 102 debug2("%s: disabled because of invalid user", __func__);
90 return 0; 103 return 0;
91 } 104 }
92 if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0) 105 if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
93 fatal("%s: sshpkt_get_u8 failed: %s", __func__, ssh_err(r)); 106 (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
94 if (ssh->compat & SSH_BUG_PKAUTH) { 107 (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
95 debug2("%s: SSH_BUG_PKAUTH", __func__); 108 fatal("%s: parse request failed: %s", __func__, ssh_err(r));
96 if ((b = sshbuf_new()) == NULL)
97 fatal("%s: sshbuf_new failed", __func__);
98 /* no explicit pkalg given */
99 /* so we have to extract the pkalg from the pkblob */
100 /* XXX use sshbuf_from() */
101 if ((r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
102 (r = sshbuf_put(b, pkblob, blen)) != 0 ||
103 (r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0)
104 fatal("%s: failed: %s", __func__, ssh_err(r));
105 sshbuf_free(b);
106 } else {
107 if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
108 (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
109 fatal("%s: sshpkt_get_cstring failed: %s",
110 __func__, ssh_err(r));
111 }
112 pktype = sshkey_type_from_name(pkalg); 109 pktype = sshkey_type_from_name(pkalg);
113 if (pktype == KEY_UNSPEC) { 110 if (pktype == KEY_UNSPEC) {
114 /* this is perfectly legal */ 111 /* this is perfectly legal */
@@ -135,7 +132,6 @@ userauth_pubkey(struct ssh *ssh)
135 "signature scheme"); 132 "signature scheme");
136 goto done; 133 goto done;
137 } 134 }
138 fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
139 if (auth2_key_already_used(authctxt, key)) { 135 if (auth2_key_already_used(authctxt, key)) {
140 logit("refusing previously-used %s key", sshkey_type(key)); 136 logit("refusing previously-used %s key", sshkey_type(key));
141 goto done; 137 goto done;
@@ -147,9 +143,15 @@ userauth_pubkey(struct ssh *ssh)
147 goto done; 143 goto done;
148 } 144 }
149 145
146 key_s = format_key(key);
147 if (sshkey_is_cert(key))
148 ca_s = format_key(key->cert->signature_key);
149
150 if (have_sig) { 150 if (have_sig) {
151 debug3("%s: have signature for %s %s", 151 debug3("%s: have %s signature for %s%s%s",
152 __func__, sshkey_type(key), fp); 152 __func__, pkalg, key_s,
153 ca_s == NULL ? "" : " CA ",
154 ca_s == NULL ? "" : ca_s);
153 if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 || 155 if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
154 (r = sshpkt_get_end(ssh)) != 0) 156 (r = sshpkt_get_end(ssh)) != 0)
155 fatal("%s: %s", __func__, ssh_err(r)); 157 fatal("%s: %s", __func__, ssh_err(r));
@@ -172,22 +174,11 @@ userauth_pubkey(struct ssh *ssh)
172 authctxt->style ? authctxt->style : ""); 174 authctxt->style ? authctxt->style : "");
173 if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 175 if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
174 (r = sshbuf_put_cstring(b, userstyle)) != 0 || 176 (r = sshbuf_put_cstring(b, userstyle)) != 0 ||
175 (r = sshbuf_put_cstring(b, ssh->compat & SSH_BUG_PKSERVICE ? 177 (r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
176 "ssh-userauth" : authctxt->service)) != 0) 178 (r = sshbuf_put_cstring(b, "publickey")) != 0 ||
177 fatal("%s: build packet failed: %s", 179 (r = sshbuf_put_u8(b, have_sig)) != 0 ||
178 __func__, ssh_err(r)); 180 (r = sshbuf_put_cstring(b, pkalg) != 0) ||
179 if (ssh->compat & SSH_BUG_PKAUTH) { 181 (r = sshbuf_put_string(b, pkblob, blen)) != 0)
180 if ((r = sshbuf_put_u8(b, have_sig)) != 0)
181 fatal("%s: build packet failed: %s",
182 __func__, ssh_err(r));
183 } else {
184 if ((r = sshbuf_put_cstring(b, "publickey")) != 0 ||
185 (r = sshbuf_put_u8(b, have_sig)) != 0 ||
186 (r = sshbuf_put_cstring(b, pkalg) != 0))
187 fatal("%s: build packet failed: %s",
188 __func__, ssh_err(r));
189 }
190 if ((r = sshbuf_put_string(b, pkblob, blen)) != 0)
191 fatal("%s: build packet failed: %s", 182 fatal("%s: build packet failed: %s",
192 __func__, ssh_err(r)); 183 __func__, ssh_err(r));
193#ifdef DEBUG_PK 184#ifdef DEBUG_PK
@@ -196,17 +187,20 @@ userauth_pubkey(struct ssh *ssh)
196 187
197 /* test for correct signature */ 188 /* test for correct signature */
198 authenticated = 0; 189 authenticated = 0;
199 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && 190 if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
200 PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), 191 PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
201 sshbuf_len(b), ssh->compat)) == 0) { 192 sshbuf_len(b), NULL, ssh->compat)) == 0) {
202 authenticated = 1; 193 authenticated = 1;
203 } 194 }
204 sshbuf_free(b); 195 sshbuf_free(b);
205 free(sig); 196 free(sig);
206 auth2_record_key(authctxt, authenticated, key); 197 auth2_record_key(authctxt, authenticated, key);
207 } else { 198 } else {
208 debug("%s: test whether pkalg/pkblob are acceptable for %s %s", 199 debug("%s: test pkalg %s pkblob %s%s%s",
209 __func__, sshkey_type(key), fp); 200 __func__, pkalg, key_s,
201 ca_s == NULL ? "" : " CA ",
202 ca_s == NULL ? "" : ca_s);
203
210 if ((r = sshpkt_get_end(ssh)) != 0) 204 if ((r = sshpkt_get_end(ssh)) != 0)
211 fatal("%s: %s", __func__, ssh_err(r)); 205 fatal("%s: %s", __func__, ssh_err(r));
212 206
@@ -218,7 +212,7 @@ userauth_pubkey(struct ssh *ssh)
218 * if a user is not allowed to login. is this an 212 * if a user is not allowed to login. is this an
219 * issue? -markus 213 * issue? -markus
220 */ 214 */
221 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { 215 if (PRIVSEP(user_key_allowed(ssh, pw, key, 0, NULL))) {
222 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK)) 216 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
223 != 0 || 217 != 0 ||
224 (r = sshpkt_put_cstring(ssh, pkalg)) != 0 || 218 (r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
@@ -229,15 +223,20 @@ userauth_pubkey(struct ssh *ssh)
229 authctxt->postponed = 1; 223 authctxt->postponed = 1;
230 } 224 }
231 } 225 }
232 if (authenticated != 1)
233 auth_clear_options();
234done: 226done:
227 if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) {
228 debug("%s: key options inconsistent with existing", __func__);
229 authenticated = 0;
230 }
235 debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); 231 debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
232
233 sshauthopt_free(authopts);
236 sshkey_free(key); 234 sshkey_free(key);
237 free(userstyle); 235 free(userstyle);
238 free(pkalg); 236 free(pkalg);
239 free(pkblob); 237 free(pkblob);
240 free(fp); 238 free(key_s);
239 free(ca_s);
241 return authenticated; 240 return authenticated;
242} 241}
243 242
@@ -261,18 +260,77 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert)
261 return 0; 260 return 0;
262} 261}
263 262
263/*
264 * Process a single authorized_principals format line. Returns 0 and sets
265 * authoptsp is principal is authorised, -1 otherwise. "loc" is used as a
266 * log preamble for file/line information.
267 */
268static int
269check_principals_line(struct ssh *ssh, char *cp, const struct sshkey_cert *cert,
270 const char *loc, struct sshauthopt **authoptsp)
271{
272 u_int i, found = 0;
273 char *ep, *line_opts;
274 const char *reason = NULL;
275 struct sshauthopt *opts = NULL;
276
277 if (authoptsp != NULL)
278 *authoptsp = NULL;
279
280 /* Trim trailing whitespace. */
281 ep = cp + strlen(cp) - 1;
282 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
283 *ep-- = '\0';
284
285 /*
286 * If the line has internal whitespace then assume it has
287 * key options.
288 */
289 line_opts = NULL;
290 if ((ep = strrchr(cp, ' ')) != NULL ||
291 (ep = strrchr(cp, '\t')) != NULL) {
292 for (; *ep == ' ' || *ep == '\t'; ep++)
293 ;
294 line_opts = cp;
295 cp = ep;
296 }
297 if ((opts = sshauthopt_parse(line_opts, &reason)) == NULL) {
298 debug("%s: bad principals options: %s", loc, reason);
299 auth_debug_add("%s: bad principals options: %s", loc, reason);
300 return -1;
301 }
302 /* Check principals in cert against those on line */
303 for (i = 0; i < cert->nprincipals; i++) {
304 if (strcmp(cp, cert->principals[i]) != 0)
305 continue;
306 debug3("%s: matched principal \"%.100s\"",
307 loc, cert->principals[i]);
308 found = 1;
309 }
310 if (found && authoptsp != NULL) {
311 *authoptsp = opts;
312 opts = NULL;
313 }
314 sshauthopt_free(opts);
315 return found ? 0 : -1;
316}
317
264static int 318static int
265process_principals(FILE *f, const char *file, struct passwd *pw, 319process_principals(struct ssh *ssh, FILE *f, const char *file,
266 const struct sshkey_cert *cert) 320 const struct sshkey_cert *cert, struct sshauthopt **authoptsp)
267{ 321{
268 char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; 322 char loc[256], line[SSH_MAX_PUBKEY_BYTES], *cp, *ep;
269 u_long linenum = 0; 323 u_long linenum = 0;
270 u_int i, found_principal = 0; 324 u_int found_principal = 0;
325
326 if (authoptsp != NULL)
327 *authoptsp = NULL;
271 328
272 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 329 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
273 /* Always consume entire input */ 330 /* Always consume entire input */
274 if (found_principal) 331 if (found_principal)
275 continue; 332 continue;
333
276 /* Skip leading whitespace. */ 334 /* Skip leading whitespace. */
277 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 335 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
278 ; 336 ;
@@ -281,50 +339,33 @@ process_principals(FILE *f, const char *file, struct passwd *pw,
281 *ep = '\0'; 339 *ep = '\0';
282 if (!*cp || *cp == '\n') 340 if (!*cp || *cp == '\n')
283 continue; 341 continue;
284 /* Trim trailing whitespace. */ 342
285 ep = cp + strlen(cp) - 1; 343 snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
286 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) 344 if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0)
287 *ep-- = '\0'; 345 found_principal = 1;
288 /*
289 * If the line has internal whitespace then assume it has
290 * key options.
291 */
292 line_opts = NULL;
293 if ((ep = strrchr(cp, ' ')) != NULL ||
294 (ep = strrchr(cp, '\t')) != NULL) {
295 for (; *ep == ' ' || *ep == '\t'; ep++)
296 ;
297 line_opts = cp;
298 cp = ep;
299 }
300 for (i = 0; i < cert->nprincipals; i++) {
301 if (strcmp(cp, cert->principals[i]) == 0) {
302 debug3("%s:%lu: matched principal \"%.100s\"",
303 file, linenum, cert->principals[i]);
304 if (auth_parse_options(pw, line_opts,
305 file, linenum) != 1)
306 continue;
307 found_principal = 1;
308 continue;
309 }
310 }
311 } 346 }
312 return found_principal; 347 return found_principal;
313} 348}
314 349
350/* XXX remove pw args here and elsewhere once ssh->authctxt is guaranteed */
351
315static int 352static int
316match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) 353match_principals_file(struct ssh *ssh, struct passwd *pw, char *file,
354 struct sshkey_cert *cert, struct sshauthopt **authoptsp)
317{ 355{
318 FILE *f; 356 FILE *f;
319 int success; 357 int success;
320 358
359 if (authoptsp != NULL)
360 *authoptsp = NULL;
361
321 temporarily_use_uid(pw); 362 temporarily_use_uid(pw);
322 debug("trying authorized principals file %s", file); 363 debug("trying authorized principals file %s", file);
323 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { 364 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
324 restore_uid(); 365 restore_uid();
325 return 0; 366 return 0;
326 } 367 }
327 success = process_principals(f, file, pw, cert); 368 success = process_principals(ssh, f, file, cert, authoptsp);
328 fclose(f); 369 fclose(f);
329 restore_uid(); 370 restore_uid();
330 return success; 371 return success;
@@ -335,12 +376,13 @@ match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
335 * returns 1 if the principal is allowed or 0 otherwise. 376 * returns 1 if the principal is allowed or 0 otherwise.
336 */ 377 */
337static int 378static int
338match_principals_command(struct passwd *user_pw, const struct sshkey *key) 379match_principals_command(struct ssh *ssh, struct passwd *user_pw,
380 const struct sshkey *key, struct sshauthopt **authoptsp)
339{ 381{
382 struct passwd *runas_pw = NULL;
340 const struct sshkey_cert *cert = key->cert; 383 const struct sshkey_cert *cert = key->cert;
341 FILE *f = NULL; 384 FILE *f = NULL;
342 int r, ok, found_principal = 0; 385 int r, ok, found_principal = 0;
343 struct passwd *pw;
344 int i, ac = 0, uid_swapped = 0; 386 int i, ac = 0, uid_swapped = 0;
345 pid_t pid; 387 pid_t pid;
346 char *tmp, *username = NULL, *command = NULL, **av = NULL; 388 char *tmp, *username = NULL, *command = NULL, **av = NULL;
@@ -348,6 +390,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
348 char serial_s[16]; 390 char serial_s[16];
349 void (*osigchld)(int); 391 void (*osigchld)(int);
350 392
393 if (authoptsp != NULL)
394 *authoptsp = NULL;
351 if (options.authorized_principals_command == NULL) 395 if (options.authorized_principals_command == NULL)
352 return 0; 396 return 0;
353 if (options.authorized_principals_command_user == NULL) { 397 if (options.authorized_principals_command_user == NULL) {
@@ -365,8 +409,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
365 /* Prepare and verify the user for the command */ 409 /* Prepare and verify the user for the command */
366 username = percent_expand(options.authorized_principals_command_user, 410 username = percent_expand(options.authorized_principals_command_user,
367 "u", user_pw->pw_name, (char *)NULL); 411 "u", user_pw->pw_name, (char *)NULL);
368 pw = getpwnam(username); 412 runas_pw = getpwnam(username);
369 if (pw == NULL) { 413 if (runas_pw == NULL) {
370 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", 414 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
371 username, strerror(errno)); 415 username, strerror(errno));
372 goto out; 416 goto out;
@@ -424,15 +468,15 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
424 /* Prepare a printable command for logs, etc. */ 468 /* Prepare a printable command for logs, etc. */
425 command = argv_assemble(ac, av); 469 command = argv_assemble(ac, av);
426 470
427 if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, 471 if ((pid = subprocess("AuthorizedPrincipalsCommand", runas_pw, command,
428 ac, av, &f, 472 ac, av, &f,
429 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) 473 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
430 goto out; 474 goto out;
431 475
432 uid_swapped = 1; 476 uid_swapped = 1;
433 temporarily_use_uid(pw); 477 temporarily_use_uid(runas_pw);
434 478
435 ok = process_principals(f, "(command)", pw, cert); 479 ok = process_principals(ssh, f, "(command)", cert, authoptsp);
436 480
437 fclose(f); 481 fclose(f);
438 f = NULL; 482 f = NULL;
@@ -459,132 +503,225 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
459 free(keytext); 503 free(keytext);
460 return found_principal; 504 return found_principal;
461} 505}
506
507static void
508skip_space(char **cpp)
509{
510 char *cp;
511
512 for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
513 ;
514 *cpp = cp;
515}
516
517/*
518 * Advanced *cpp past the end of key options, defined as the first unquoted
519 * whitespace character. Returns 0 on success or -1 on failure (e.g.
520 * unterminated quotes).
521 */
522static int
523advance_past_options(char **cpp)
524{
525 char *cp = *cpp;
526 int quoted = 0;
527
528 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
529 if (*cp == '\\' && cp[1] == '"')
530 cp++; /* Skip both */
531 else if (*cp == '"')
532 quoted = !quoted;
533 }
534 *cpp = cp;
535 /* return failure for unterminated quotes */
536 return (*cp == '\0' && quoted) ? -1 : 0;
537}
538
539/*
540 * Check a single line of an authorized_keys-format file. Returns 0 if key
541 * matches, -1 otherwise. Will return key/cert options via *authoptsp
542 * on success. "loc" is used as file/line location in log messages.
543 */
544static int
545check_authkey_line(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
546 char *cp, const char *loc, struct sshauthopt **authoptsp)
547{
548 int want_keytype = sshkey_is_cert(key) ? KEY_UNSPEC : key->type;
549 struct sshkey *found = NULL;
550 struct sshauthopt *keyopts = NULL, *certopts = NULL, *finalopts = NULL;
551 char *key_options = NULL, *fp = NULL;
552 const char *reason = NULL;
553 int ret = -1;
554
555 if (authoptsp != NULL)
556 *authoptsp = NULL;
557
558 if ((found = sshkey_new(want_keytype)) == NULL) {
559 debug3("%s: keytype %d failed", __func__, want_keytype);
560 goto out;
561 }
562
563 /* XXX djm: peek at key type in line and skip if unwanted */
564
565 if (sshkey_read(found, &cp) != 0) {
566 /* no key? check for options */
567 debug2("%s: check options: '%s'", loc, cp);
568 key_options = cp;
569 if (advance_past_options(&cp) != 0) {
570 reason = "invalid key option string";
571 goto fail_reason;
572 }
573 skip_space(&cp);
574 if (sshkey_read(found, &cp) != 0) {
575 /* still no key? advance to next line*/
576 debug2("%s: advance: '%s'", loc, cp);
577 goto out;
578 }
579 }
580 /* Parse key options now; we need to know if this is a CA key */
581 if ((keyopts = sshauthopt_parse(key_options, &reason)) == NULL) {
582 debug("%s: bad key options: %s", loc, reason);
583 auth_debug_add("%s: bad key options: %s", loc, reason);
584 goto out;
585 }
586 /* Ignore keys that don't match or incorrectly marked as CAs */
587 if (sshkey_is_cert(key)) {
588 /* Certificate; check signature key against CA */
589 if (!sshkey_equal(found, key->cert->signature_key) ||
590 !keyopts->cert_authority)
591 goto out;
592 } else {
593 /* Plain key: check it against key found in file */
594 if (!sshkey_equal(found, key) || keyopts->cert_authority)
595 goto out;
596 }
597
598 /* We have a candidate key, perform authorisation checks */
599 if ((fp = sshkey_fingerprint(found,
600 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
601 fatal("%s: fingerprint failed", __func__);
602
603 debug("%s: matching %s found: %s %s", loc,
604 sshkey_is_cert(key) ? "CA" : "key", sshkey_type(found), fp);
605
606 if (auth_authorise_keyopts(ssh, pw, keyopts,
607 sshkey_is_cert(key), loc) != 0) {
608 reason = "Refused by key options";
609 goto fail_reason;
610 }
611 /* That's all we need for plain keys. */
612 if (!sshkey_is_cert(key)) {
613 verbose("Accepted key %s %s found at %s",
614 sshkey_type(found), fp, loc);
615 finalopts = keyopts;
616 keyopts = NULL;
617 goto success;
618 }
619
620 /*
621 * Additional authorisation for certificates.
622 */
623
624 /* Parse and check options present in certificate */
625 if ((certopts = sshauthopt_from_cert(key)) == NULL) {
626 reason = "Invalid certificate options";
627 goto fail_reason;
628 }
629 if (auth_authorise_keyopts(ssh, pw, certopts, 0, loc) != 0) {
630 reason = "Refused by certificate options";
631 goto fail_reason;
632 }
633 if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL)
634 goto fail_reason;
635
636 /*
637 * If the user has specified a list of principals as
638 * a key option, then prefer that list to matching
639 * their username in the certificate principals list.
640 */
641 if (keyopts->cert_principals != NULL &&
642 !match_principals_option(keyopts->cert_principals, key->cert)) {
643 reason = "Certificate does not contain an authorized principal";
644 goto fail_reason;
645 }
646 if (sshkey_cert_check_authority(key, 0, 0,
647 keyopts->cert_principals == NULL ? pw->pw_name : NULL, &reason) != 0)
648 goto fail_reason;
649
650 verbose("Accepted certificate ID \"%s\" (serial %llu) "
651 "signed by CA %s %s found at %s",
652 key->cert->key_id,
653 (unsigned long long)key->cert->serial,
654 sshkey_type(found), fp, loc);
655
656 success:
657 if (finalopts == NULL)
658 fatal("%s: internal error: missing options", __func__);
659 if (authoptsp != NULL) {
660 *authoptsp = finalopts;
661 finalopts = NULL;
662 }
663 /* success */
664 ret = 0;
665 goto out;
666
667 fail_reason:
668 error("%s", reason);
669 auth_debug_add("%s", reason);
670 out:
671 free(fp);
672 sshauthopt_free(keyopts);
673 sshauthopt_free(certopts);
674 sshauthopt_free(finalopts);
675 sshkey_free(found);
676 return ret;
677}
678
462/* 679/*
463 * Checks whether key is allowed in authorized_keys-format file, 680 * Checks whether key is allowed in authorized_keys-format file,
464 * returns 1 if the key is allowed or 0 otherwise. 681 * returns 1 if the key is allowed or 0 otherwise.
465 */ 682 */
466static int 683static int
467check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw) 684check_authkeys_file(struct ssh *ssh, struct passwd *pw, FILE *f,
685 char *file, struct sshkey *key, struct sshauthopt **authoptsp)
468{ 686{
469 char line[SSH_MAX_PUBKEY_BYTES]; 687 char *cp, line[SSH_MAX_PUBKEY_BYTES], loc[256];
470 int found_key = 0; 688 int found_key = 0;
471 u_long linenum = 0; 689 u_long linenum = 0;
472 struct sshkey *found = NULL;
473 690
474 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 691 if (authoptsp != NULL)
475 char *cp, *key_options = NULL, *fp = NULL; 692 *authoptsp = NULL;
476 const char *reason = NULL;
477 693
694 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
478 /* Always consume entire file */ 695 /* Always consume entire file */
479 if (found_key) 696 if (found_key)
480 continue; 697 continue;
481 if (found != NULL)
482 sshkey_free(found);
483 found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type);
484 if (found == NULL)
485 goto done;
486 auth_clear_options();
487 698
488 /* Skip leading whitespace, empty and comment lines. */ 699 /* Skip leading whitespace, empty and comment lines. */
489 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 700 cp = line;
490 ; 701 skip_space(&cp);
491 if (!*cp || *cp == '\n' || *cp == '#') 702 if (!*cp || *cp == '\n' || *cp == '#')
492 continue; 703 continue;
493 704 snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
494 if (sshkey_read(found, &cp) != 0) { 705 if (check_authkey_line(ssh, pw, key, cp, loc, authoptsp) == 0)
495 /* no key? check if there are options for this key */
496 int quoted = 0;
497 debug2("user_key_allowed: check options: '%s'", cp);
498 key_options = cp;
499 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
500 if (*cp == '\\' && cp[1] == '"')
501 cp++; /* Skip both */
502 else if (*cp == '"')
503 quoted = !quoted;
504 }
505 /* Skip remaining whitespace. */
506 for (; *cp == ' ' || *cp == '\t'; cp++)
507 ;
508 if (sshkey_read(found, &cp) != 0) {
509 debug2("user_key_allowed: advance: '%s'", cp);
510 /* still no key? advance to next line*/
511 continue;
512 }
513 }
514 if (sshkey_is_cert(key)) {
515 if (!sshkey_equal(found, key->cert->signature_key))
516 continue;
517 if (auth_parse_options(pw, key_options, file,
518 linenum) != 1)
519 continue;
520 if (!key_is_cert_authority)
521 continue;
522 if ((fp = sshkey_fingerprint(found,
523 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
524 continue;
525 debug("matching CA found: file %s, line %lu, %s %s",
526 file, linenum, sshkey_type(found), fp);
527 /*
528 * If the user has specified a list of principals as
529 * a key option, then prefer that list to matching
530 * their username in the certificate principals list.
531 */
532 if (authorized_principals != NULL &&
533 !match_principals_option(authorized_principals,
534 key->cert)) {
535 reason = "Certificate does not contain an "
536 "authorized principal";
537 fail_reason:
538 free(fp);
539 error("%s", reason);
540 auth_debug_add("%s", reason);
541 continue;
542 }
543 if (sshkey_cert_check_authority(key, 0, 0,
544 authorized_principals == NULL ? pw->pw_name : NULL,
545 &reason) != 0)
546 goto fail_reason;
547 if (auth_cert_options(key, pw, &reason) != 0)
548 goto fail_reason;
549 verbose("Accepted certificate ID \"%s\" (serial %llu) "
550 "signed by %s CA %s via %s", key->cert->key_id,
551 (unsigned long long)key->cert->serial,
552 sshkey_type(found), fp, file);
553 free(fp);
554 found_key = 1;
555 break;
556 } else if (sshkey_equal(found, key)) {
557 if (auth_parse_options(pw, key_options, file,
558 linenum) != 1)
559 continue;
560 if (key_is_cert_authority)
561 continue;
562 if ((fp = sshkey_fingerprint(found,
563 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
564 continue;
565 debug("matching key found: file %s, line %lu %s %s",
566 file, linenum, sshkey_type(found), fp);
567 free(fp);
568 found_key = 1; 706 found_key = 1;
569 continue;
570 }
571 } 707 }
572 done:
573 if (found != NULL)
574 sshkey_free(found);
575 if (!found_key)
576 debug2("key not found");
577 return found_key; 708 return found_key;
578} 709}
579 710
580/* Authenticate a certificate key against TrustedUserCAKeys */ 711/* Authenticate a certificate key against TrustedUserCAKeys */
581static int 712static int
582user_cert_trusted_ca(struct passwd *pw, struct sshkey *key) 713user_cert_trusted_ca(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
714 struct sshauthopt **authoptsp)
583{ 715{
584 char *ca_fp, *principals_file = NULL; 716 char *ca_fp, *principals_file = NULL;
585 const char *reason; 717 const char *reason;
718 struct sshauthopt *principals_opts = NULL, *cert_opts = NULL;
719 struct sshauthopt *final_opts = NULL;
586 int r, ret = 0, found_principal = 0, use_authorized_principals; 720 int r, ret = 0, found_principal = 0, use_authorized_principals;
587 721
722 if (authoptsp != NULL)
723 *authoptsp = NULL;
724
588 if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL) 725 if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
589 return 0; 726 return 0;
590 727
@@ -605,36 +742,69 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
605 * against the username. 742 * against the username.
606 */ 743 */
607 if ((principals_file = authorized_principals_file(pw)) != NULL) { 744 if ((principals_file = authorized_principals_file(pw)) != NULL) {
608 if (match_principals_file(principals_file, pw, key->cert)) 745 if (match_principals_file(ssh, pw, principals_file,
746 key->cert, &principals_opts))
609 found_principal = 1; 747 found_principal = 1;
610 } 748 }
611 /* Try querying command if specified */ 749 /* Try querying command if specified */
612 if (!found_principal && match_principals_command(pw, key)) 750 if (!found_principal && match_principals_command(ssh, pw, key,
751 &principals_opts))
613 found_principal = 1; 752 found_principal = 1;
614 /* If principals file or command is specified, then require a match */ 753 /* If principals file or command is specified, then require a match */
615 use_authorized_principals = principals_file != NULL || 754 use_authorized_principals = principals_file != NULL ||
616 options.authorized_principals_command != NULL; 755 options.authorized_principals_command != NULL;
617 if (!found_principal && use_authorized_principals) { 756 if (!found_principal && use_authorized_principals) {
618 reason = "Certificate does not contain an authorized principal"; 757 reason = "Certificate does not contain an authorized principal";
619 fail_reason: 758 goto fail_reason;
620 error("%s", reason);
621 auth_debug_add("%s", reason);
622 goto out;
623 } 759 }
760 if (use_authorized_principals && principals_opts == NULL)
761 fatal("%s: internal error: missing principals_opts", __func__);
624 if (sshkey_cert_check_authority(key, 0, 1, 762 if (sshkey_cert_check_authority(key, 0, 1,
625 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) 763 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
626 goto fail_reason; 764 goto fail_reason;
627 if (auth_cert_options(key, pw, &reason) != 0) 765
766 /* Check authority from options in key and from principals file/cmd */
767 if ((cert_opts = sshauthopt_from_cert(key)) == NULL) {
768 reason = "Invalid certificate options";
769 goto fail_reason;
770 }
771 if (auth_authorise_keyopts(ssh, pw, cert_opts, 0, "cert") != 0) {
772 reason = "Refused by certificate options";
628 goto fail_reason; 773 goto fail_reason;
774 }
775 if (principals_opts == NULL) {
776 final_opts = cert_opts;
777 cert_opts = NULL;
778 } else {
779 if (auth_authorise_keyopts(ssh, pw, principals_opts, 0,
780 "principals") != 0) {
781 reason = "Refused by certificate principals options";
782 goto fail_reason;
783 }
784 if ((final_opts = sshauthopt_merge(principals_opts,
785 cert_opts, &reason)) == NULL) {
786 fail_reason:
787 error("%s", reason);
788 auth_debug_add("%s", reason);
789 goto out;
790 }
791 }
629 792
793 /* Success */
630 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " 794 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
631 "%s CA %s via %s", key->cert->key_id, 795 "%s CA %s via %s", key->cert->key_id,
632 (unsigned long long)key->cert->serial, 796 (unsigned long long)key->cert->serial,
633 sshkey_type(key->cert->signature_key), ca_fp, 797 sshkey_type(key->cert->signature_key), ca_fp,
634 options.trusted_user_ca_keys); 798 options.trusted_user_ca_keys);
799 if (authoptsp != NULL) {
800 *authoptsp = final_opts;
801 final_opts = NULL;
802 }
635 ret = 1; 803 ret = 1;
636
637 out: 804 out:
805 sshauthopt_free(principals_opts);
806 sshauthopt_free(cert_opts);
807 sshauthopt_free(final_opts);
638 free(principals_file); 808 free(principals_file);
639 free(ca_fp); 809 free(ca_fp);
640 return ret; 810 return ret;
@@ -645,17 +815,22 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
645 * returns 1 if the key is allowed or 0 otherwise. 815 * returns 1 if the key is allowed or 0 otherwise.
646 */ 816 */
647static int 817static int
648user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file) 818user_key_allowed2(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
819 char *file, struct sshauthopt **authoptsp)
649{ 820{
650 FILE *f; 821 FILE *f;
651 int found_key = 0; 822 int found_key = 0;
652 823
824 if (authoptsp != NULL)
825 *authoptsp = NULL;
826
653 /* Temporarily use the user's uid. */ 827 /* Temporarily use the user's uid. */
654 temporarily_use_uid(pw); 828 temporarily_use_uid(pw);
655 829
656 debug("trying public key file %s", file); 830 debug("trying public key file %s", file);
657 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { 831 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
658 found_key = check_authkeys_file(f, file, key, pw); 832 found_key = check_authkeys_file(ssh, pw, f, file,
833 key, authoptsp);
659 fclose(f); 834 fclose(f);
660 } 835 }
661 836
@@ -668,17 +843,20 @@ user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
668 * returns 1 if the key is allowed or 0 otherwise. 843 * returns 1 if the key is allowed or 0 otherwise.
669 */ 844 */
670static int 845static int
671user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key) 846user_key_command_allowed2(struct ssh *ssh, struct passwd *user_pw,
847 struct sshkey *key, struct sshauthopt **authoptsp)
672{ 848{
849 struct passwd *runas_pw = NULL;
673 FILE *f = NULL; 850 FILE *f = NULL;
674 int r, ok, found_key = 0; 851 int r, ok, found_key = 0;
675 struct passwd *pw;
676 int i, uid_swapped = 0, ac = 0; 852 int i, uid_swapped = 0, ac = 0;
677 pid_t pid; 853 pid_t pid;
678 char *username = NULL, *key_fp = NULL, *keytext = NULL; 854 char *username = NULL, *key_fp = NULL, *keytext = NULL;
679 char *tmp, *command = NULL, **av = NULL; 855 char *tmp, *command = NULL, **av = NULL;
680 void (*osigchld)(int); 856 void (*osigchld)(int);
681 857
858 if (authoptsp != NULL)
859 *authoptsp = NULL;
682 if (options.authorized_keys_command == NULL) 860 if (options.authorized_keys_command == NULL)
683 return 0; 861 return 0;
684 if (options.authorized_keys_command_user == NULL) { 862 if (options.authorized_keys_command_user == NULL) {
@@ -695,8 +873,8 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
695 /* Prepare and verify the user for the command */ 873 /* Prepare and verify the user for the command */
696 username = percent_expand(options.authorized_keys_command_user, 874 username = percent_expand(options.authorized_keys_command_user,
697 "u", user_pw->pw_name, (char *)NULL); 875 "u", user_pw->pw_name, (char *)NULL);
698 pw = getpwnam(username); 876 runas_pw = getpwnam(username);
699 if (pw == NULL) { 877 if (runas_pw == NULL) {
700 error("AuthorizedKeysCommandUser \"%s\" not found: %s", 878 error("AuthorizedKeysCommandUser \"%s\" not found: %s",
701 username, strerror(errno)); 879 username, strerror(errno));
702 goto out; 880 goto out;
@@ -754,15 +932,16 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
754 xasprintf(&command, "%s %s", av[0], av[1]); 932 xasprintf(&command, "%s %s", av[0], av[1]);
755 } 933 }
756 934
757 if ((pid = subprocess("AuthorizedKeysCommand", pw, command, 935 if ((pid = subprocess("AuthorizedKeysCommand", runas_pw, command,
758 ac, av, &f, 936 ac, av, &f,
759 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) 937 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
760 goto out; 938 goto out;
761 939
762 uid_swapped = 1; 940 uid_swapped = 1;
763 temporarily_use_uid(pw); 941 temporarily_use_uid(runas_pw);
764 942
765 ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); 943 ok = check_authkeys_file(ssh, user_pw, f,
944 options.authorized_keys_command, key, authoptsp);
766 945
767 fclose(f); 946 fclose(f);
768 f = NULL; 947 f = NULL;
@@ -792,10 +971,14 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
792 * Check whether key authenticates and authorises the user. 971 * Check whether key authenticates and authorises the user.
793 */ 972 */
794int 973int
795user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt) 974user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
975 int auth_attempt, struct sshauthopt **authoptsp)
796{ 976{
797 u_int success, i; 977 u_int success, i;
798 char *file; 978 char *file;
979 struct sshauthopt *opts = NULL;
980 if (authoptsp != NULL)
981 *authoptsp = NULL;
799 982
800 if (auth_key_is_revoked(key)) 983 if (auth_key_is_revoked(key))
801 return 0; 984 return 0;
@@ -803,25 +986,31 @@ user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
803 auth_key_is_revoked(key->cert->signature_key)) 986 auth_key_is_revoked(key->cert->signature_key))
804 return 0; 987 return 0;
805 988
806 success = user_cert_trusted_ca(pw, key); 989 if ((success = user_cert_trusted_ca(ssh, pw, key, &opts)) != 0)
807 if (success) 990 goto out;
808 return success; 991 sshauthopt_free(opts);
992 opts = NULL;
809 993
810 success = user_key_command_allowed2(pw, key); 994 if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0)
811 if (success > 0) 995 goto out;
812 return success; 996 sshauthopt_free(opts);
997 opts = NULL;
813 998
814 for (i = 0; !success && i < options.num_authkeys_files; i++) { 999 for (i = 0; !success && i < options.num_authkeys_files; i++) {
815
816 if (strcasecmp(options.authorized_keys_files[i], "none") == 0) 1000 if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
817 continue; 1001 continue;
818 file = expand_authorized_keys( 1002 file = expand_authorized_keys(
819 options.authorized_keys_files[i], pw); 1003 options.authorized_keys_files[i], pw);
820 1004 success = user_key_allowed2(ssh, pw, key, file, &opts);
821 success = user_key_allowed2(pw, key, file);
822 free(file); 1005 free(file);
823 } 1006 }
824 1007
1008 out:
1009 if (success && authoptsp != NULL) {
1010 *authoptsp = opts;
1011 opts = NULL;
1012 }
1013 sshauthopt_free(opts);
825 return success; 1014 return success;
826} 1015}
827 1016