jcs's openbsd hax
openbsd
1/* $OpenBSD: auth2-pubkey.c,v 1.113 2022/02/27 01:33:59 naddy Exp $ */
2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26
27#include <sys/types.h>
28#include <sys/stat.h>
29
30#include <stdlib.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <paths.h>
34#include <pwd.h>
35#include <signal.h>
36#include <stdio.h>
37#include <stdarg.h>
38#include <string.h>
39#include <time.h>
40#include <unistd.h>
41#include <limits.h>
42
43#include "xmalloc.h"
44#include "ssh.h"
45#include "ssh2.h"
46#include "packet.h"
47#include "kex.h"
48#include "sshbuf.h"
49#include "log.h"
50#include "misc.h"
51#include "servconf.h"
52#include "compat.h"
53#include "sshkey.h"
54#include "hostfile.h"
55#include "auth.h"
56#include "pathnames.h"
57#include "uidswap.h"
58#include "auth-options.h"
59#include "canohost.h"
60#ifdef GSSAPI
61#include "ssh-gss.h"
62#endif
63#include "monitor_wrap.h"
64#include "authfile.h"
65#include "match.h"
66#include "ssherr.h"
67#include "kex.h"
68#include "channels.h" /* XXX for session.h */
69#include "session.h" /* XXX for child_set_env(); refactor? */
70#include "sk-api.h"
71
72/* import */
73extern ServerOptions options;
74
75static char *
76format_key(const struct sshkey *key)
77{
78 char *ret, *fp = sshkey_fingerprint(key,
79 options.fingerprint_hash, SSH_FP_DEFAULT);
80
81 xasprintf(&ret, "%s %s", sshkey_type(key), fp);
82 free(fp);
83 return ret;
84}
85
86static int
87userauth_pubkey(struct ssh *ssh, const char *method)
88{
89 Authctxt *authctxt = ssh->authctxt;
90 struct passwd *pw = authctxt->pw;
91 struct sshbuf *b = NULL;
92 struct sshkey *key = NULL, *hostkey = NULL;
93 char *pkalg = NULL, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
94 u_char *pkblob = NULL, *sig = NULL, have_sig;
95 size_t blen, slen;
96 int hostbound, r, pktype;
97 int req_presence = 0, req_verify = 0, authenticated = 0;
98 struct sshauthopt *authopts = NULL;
99 struct sshkey_sig_details *sig_details = NULL;
100
101 hostbound = strcmp(method, "publickey-hostbound-v00@openssh.com") == 0;
102
103 if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
104 (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
105 (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
106 fatal_fr(r, "parse %s packet", method);
107
108 /* hostbound auth includes the hostkey offered at initial KEX */
109 if (hostbound) {
110 if ((r = sshpkt_getb_froms(ssh, &b)) != 0 ||
111 (r = sshkey_fromb(b, &hostkey)) != 0)
112 fatal_fr(r, "parse %s hostkey", method);
113 if (ssh->kex->initial_hostkey == NULL)
114 fatal_f("internal error: initial hostkey not recorded");
115 if (!sshkey_equal(hostkey, ssh->kex->initial_hostkey))
116 fatal_f("%s packet contained wrong host key", method);
117 sshbuf_free(b);
118 b = NULL;
119 }
120
121 if (log_level_get() >= SYSLOG_LEVEL_DEBUG2) {
122 char *keystring;
123 struct sshbuf *pkbuf;
124
125 if ((pkbuf = sshbuf_from(pkblob, blen)) == NULL)
126 fatal_f("sshbuf_from failed");
127 if ((keystring = sshbuf_dtob64_string(pkbuf, 0)) == NULL)
128 fatal_f("sshbuf_dtob64 failed");
129 debug2_f("%s user %s %s public key %s %s",
130 authctxt->valid ? "valid" : "invalid", authctxt->user,
131 have_sig ? "attempting" : "querying", pkalg, keystring);
132 sshbuf_free(pkbuf);
133 free(keystring);
134 }
135
136 pktype = sshkey_type_from_name(pkalg);
137 if (pktype == KEY_UNSPEC) {
138 /* this is perfectly legal */
139 verbose_f("unsupported public key algorithm: %s", pkalg);
140 goto done;
141 }
142 if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
143 error_fr(r, "parse key");
144 goto done;
145 }
146 if (key == NULL) {
147 error_f("cannot decode key: %s", pkalg);
148 goto done;
149 }
150 if (key->type != pktype) {
151 error_f("type mismatch for decoded key "
152 "(received %d, expected %d)", key->type, pktype);
153 goto done;
154 }
155 if (sshkey_type_plain(key->type) == KEY_RSA &&
156 (ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
157 logit("Refusing RSA key because client uses unsafe "
158 "signature scheme");
159 goto done;
160 }
161 if (auth2_key_already_used(authctxt, key)) {
162 logit("refusing previously-used %s key", sshkey_type(key));
163 goto done;
164 }
165 if (match_pattern_list(pkalg, options.pubkey_accepted_algos, 0) != 1) {
166 logit_f("signature algorithm %s not in "
167 "PubkeyAcceptedAlgorithms", pkalg);
168 goto done;
169 }
170 if ((r = sshkey_check_cert_sigtype(key,
171 options.ca_sign_algorithms)) != 0) {
172 logit_fr(r, "certificate signature algorithm %s",
173 (key->cert == NULL || key->cert->signature_type == NULL) ?
174 "(null)" : key->cert->signature_type);
175 goto done;
176 }
177 key_s = format_key(key);
178 if (sshkey_is_cert(key))
179 ca_s = format_key(key->cert->signature_key);
180
181 if (have_sig) {
182 debug3_f("%s have %s signature for %s%s%s",
183 method, pkalg, key_s,
184 ca_s == NULL ? "" : " CA ", ca_s == NULL ? "" : ca_s);
185 if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
186 (r = sshpkt_get_end(ssh)) != 0)
187 fatal_fr(r, "parse signature packet");
188 if ((b = sshbuf_new()) == NULL)
189 fatal_f("sshbuf_new failed");
190 if (ssh->compat & SSH_OLD_SESSIONID) {
191 if ((r = sshbuf_putb(b, ssh->kex->session_id)) != 0)
192 fatal_fr(r, "put old session id");
193 } else {
194 if ((r = sshbuf_put_stringb(b,
195 ssh->kex->session_id)) != 0)
196 fatal_fr(r, "put session id");
197 }
198 if (!authctxt->valid || authctxt->user == NULL) {
199 debug2_f("disabled because of invalid user");
200 goto done;
201 }
202 /* reconstruct packet */
203 xasprintf(&userstyle, "%s%s%s", authctxt->user,
204 authctxt->style ? ":" : "",
205 authctxt->style ? authctxt->style : "");
206 if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
207 (r = sshbuf_put_cstring(b, userstyle)) != 0 ||
208 (r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
209 (r = sshbuf_put_cstring(b, method)) != 0 ||
210 (r = sshbuf_put_u8(b, have_sig)) != 0 ||
211 (r = sshbuf_put_cstring(b, pkalg)) != 0 ||
212 (r = sshbuf_put_string(b, pkblob, blen)) != 0)
213 fatal_fr(r, "reconstruct %s packet", method);
214 if (hostbound &&
215 (r = sshkey_puts(ssh->kex->initial_hostkey, b)) != 0)
216 fatal_fr(r, "reconstruct %s packet", method);
217#ifdef DEBUG_PK
218 sshbuf_dump(b, stderr);
219#endif
220 /* test for correct signature */
221 authenticated = 0;
222 if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
223 PRIVSEP(sshkey_verify(key, sig, slen,
224 sshbuf_ptr(b), sshbuf_len(b),
225 (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL,
226 ssh->compat, &sig_details)) == 0) {
227 authenticated = 1;
228 }
229 if (authenticated == 1 && sig_details != NULL) {
230 auth2_record_info(authctxt, "signature count = %u",
231 sig_details->sk_counter);
232 debug_f("sk_counter = %u, sk_flags = 0x%02x",
233 sig_details->sk_counter, sig_details->sk_flags);
234 req_presence = (options.pubkey_auth_options &
235 PUBKEYAUTH_TOUCH_REQUIRED) ||
236 !authopts->no_require_user_presence;
237 if (req_presence && (sig_details->sk_flags &
238 SSH_SK_USER_PRESENCE_REQD) == 0) {
239 error("public key %s signature for %s%s from "
240 "%.128s port %d rejected: user presence "
241 "(authenticator touch) requirement "
242 "not met ", key_s,
243 authctxt->valid ? "" : "invalid user ",
244 authctxt->user, ssh_remote_ipaddr(ssh),
245 ssh_remote_port(ssh));
246 authenticated = 0;
247 goto done;
248 }
249 req_verify = (options.pubkey_auth_options &
250 PUBKEYAUTH_VERIFY_REQUIRED) ||
251 authopts->require_verify;
252 if (req_verify && (sig_details->sk_flags &
253 SSH_SK_USER_VERIFICATION_REQD) == 0) {
254 error("public key %s signature for %s%s from "
255 "%.128s port %d rejected: user "
256 "verification requirement not met ", key_s,
257 authctxt->valid ? "" : "invalid user ",
258 authctxt->user, ssh_remote_ipaddr(ssh),
259 ssh_remote_port(ssh));
260 authenticated = 0;
261 goto done;
262 }
263 }
264 auth2_record_key(authctxt, authenticated, key);
265 } else {
266 debug_f("%s test pkalg %s pkblob %s%s%s", method, pkalg, key_s,
267 ca_s == NULL ? "" : " CA ", ca_s == NULL ? "" : ca_s);
268
269 if ((r = sshpkt_get_end(ssh)) != 0)
270 fatal_fr(r, "parse packet");
271
272 if (!authctxt->valid || authctxt->user == NULL) {
273 debug2_f("disabled because of invalid user");
274 goto done;
275 }
276 /* XXX fake reply and always send PK_OK ? */
277 /*
278 * XXX this allows testing whether a user is allowed
279 * to login: if you happen to have a valid pubkey this
280 * message is sent. the message is NEVER sent at all
281 * if a user is not allowed to login. is this an
282 * issue? -markus
283 */
284 if (PRIVSEP(user_key_allowed(ssh, pw, key, 0, NULL))) {
285 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
286 != 0 ||
287 (r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
288 (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 ||
289 (r = sshpkt_send(ssh)) != 0 ||
290 (r = ssh_packet_write_wait(ssh)) != 0)
291 fatal_fr(r, "send packet");
292 authctxt->postponed = 1;
293 }
294 }
295done:
296 if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) {
297 debug_f("key options inconsistent with existing");
298 authenticated = 0;
299 }
300 debug2_f("authenticated %d pkalg %s", authenticated, pkalg);
301
302 sshbuf_free(b);
303 sshauthopt_free(authopts);
304 sshkey_free(key);
305 sshkey_free(hostkey);
306 free(userstyle);
307 free(pkalg);
308 free(pkblob);
309 free(key_s);
310 free(ca_s);
311 free(sig);
312 sshkey_sig_details_free(sig_details);
313 return authenticated;
314}
315
316static int
317match_principals_option(const char *principal_list, struct sshkey_cert *cert)
318{
319 char *result;
320 u_int i;
321
322 /* XXX percent_expand() sequences for authorized_principals? */
323
324 for (i = 0; i < cert->nprincipals; i++) {
325 if ((result = match_list(cert->principals[i],
326 principal_list, NULL)) != NULL) {
327 debug3("matched principal from key options \"%.100s\"",
328 result);
329 free(result);
330 return 1;
331 }
332 }
333 return 0;
334}
335
336/*
337 * Process a single authorized_principals format line. Returns 0 and sets
338 * authoptsp is principal is authorised, -1 otherwise. "loc" is used as a
339 * log preamble for file/line information.
340 */
341static int
342check_principals_line(struct ssh *ssh, char *cp, const struct sshkey_cert *cert,
343 const char *loc, struct sshauthopt **authoptsp)
344{
345 u_int i, found = 0;
346 char *ep, *line_opts;
347 const char *reason = NULL;
348 struct sshauthopt *opts = NULL;
349
350 if (authoptsp != NULL)
351 *authoptsp = NULL;
352
353 /* Trim trailing whitespace. */
354 ep = cp + strlen(cp) - 1;
355 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
356 *ep-- = '\0';
357
358 /*
359 * If the line has internal whitespace then assume it has
360 * key options.
361 */
362 line_opts = NULL;
363 if ((ep = strrchr(cp, ' ')) != NULL ||
364 (ep = strrchr(cp, '\t')) != NULL) {
365 for (; *ep == ' ' || *ep == '\t'; ep++)
366 ;
367 line_opts = cp;
368 cp = ep;
369 }
370 if ((opts = sshauthopt_parse(line_opts, &reason)) == NULL) {
371 debug("%s: bad principals options: %s", loc, reason);
372 auth_debug_add("%s: bad principals options: %s", loc, reason);
373 return -1;
374 }
375 /* Check principals in cert against those on line */
376 for (i = 0; i < cert->nprincipals; i++) {
377 if (strcmp(cp, cert->principals[i]) != 0)
378 continue;
379 debug3("%s: matched principal \"%.100s\"",
380 loc, cert->principals[i]);
381 found = 1;
382 }
383 if (found && authoptsp != NULL) {
384 *authoptsp = opts;
385 opts = NULL;
386 }
387 sshauthopt_free(opts);
388 return found ? 0 : -1;
389}
390
391static int
392process_principals(struct ssh *ssh, FILE *f, const char *file,
393 const struct sshkey_cert *cert, struct sshauthopt **authoptsp)
394{
395 char loc[256], *line = NULL, *cp, *ep;
396 size_t linesize = 0;
397 u_long linenum = 0, nonblank = 0;
398 u_int found_principal = 0;
399
400 if (authoptsp != NULL)
401 *authoptsp = NULL;
402
403 while (getline(&line, &linesize, f) != -1) {
404 linenum++;
405 /* Always consume entire input */
406 if (found_principal)
407 continue;
408
409 /* Skip leading whitespace. */
410 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
411 ;
412 /* Skip blank and comment lines. */
413 if ((ep = strchr(cp, '#')) != NULL)
414 *ep = '\0';
415 if (!*cp || *cp == '\n')
416 continue;
417
418 nonblank++;
419 snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
420 if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0)
421 found_principal = 1;
422 }
423 debug2_f("%s: processed %lu/%lu lines", file, nonblank, linenum);
424 free(line);
425 return found_principal;
426}
427
428/* XXX remove pw args here and elsewhere once ssh->authctxt is guaranteed */
429
430static int
431match_principals_file(struct ssh *ssh, struct passwd *pw, char *file,
432 struct sshkey_cert *cert, struct sshauthopt **authoptsp)
433{
434 FILE *f;
435 int success;
436
437 if (authoptsp != NULL)
438 *authoptsp = NULL;
439
440 temporarily_use_uid(pw);
441 debug("trying authorized principals file %s", file);
442 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
443 restore_uid();
444 return 0;
445 }
446 success = process_principals(ssh, f, file, cert, authoptsp);
447 fclose(f);
448 restore_uid();
449 return success;
450}
451
452/*
453 * Checks whether principal is allowed in output of command.
454 * returns 1 if the principal is allowed or 0 otherwise.
455 */
456static int
457match_principals_command(struct ssh *ssh, struct passwd *user_pw,
458 const struct sshkey *key, struct sshauthopt **authoptsp)
459{
460 struct passwd *runas_pw = NULL;
461 const struct sshkey_cert *cert = key->cert;
462 FILE *f = NULL;
463 int r, ok, found_principal = 0;
464 int i, ac = 0, uid_swapped = 0;
465 pid_t pid;
466 char *tmp, *username = NULL, *command = NULL, **av = NULL;
467 char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL;
468 char serial_s[32], uidstr[32];
469 void (*osigchld)(int);
470
471 if (authoptsp != NULL)
472 *authoptsp = NULL;
473 if (options.authorized_principals_command == NULL)
474 return 0;
475 if (options.authorized_principals_command_user == NULL) {
476 error("No user for AuthorizedPrincipalsCommand specified, "
477 "skipping");
478 return 0;
479 }
480
481 /*
482 * NB. all returns later this function should go via "out" to
483 * ensure the original SIGCHLD handler is restored properly.
484 */
485 osigchld = ssh_signal(SIGCHLD, SIG_DFL);
486
487 /* Prepare and verify the user for the command */
488 username = percent_expand(options.authorized_principals_command_user,
489 "u", user_pw->pw_name, (char *)NULL);
490 runas_pw = getpwnam(username);
491 if (runas_pw == NULL) {
492 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
493 username, strerror(errno));
494 goto out;
495 }
496
497 /* Turn the command into an argument vector */
498 if (argv_split(options.authorized_principals_command,
499 &ac, &av, 0) != 0) {
500 error("AuthorizedPrincipalsCommand \"%s\" contains "
501 "invalid quotes", options.authorized_principals_command);
502 goto out;
503 }
504 if (ac == 0) {
505 error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments",
506 options.authorized_principals_command);
507 goto out;
508 }
509 if ((ca_fp = sshkey_fingerprint(cert->signature_key,
510 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
511 error_f("sshkey_fingerprint failed");
512 goto out;
513 }
514 if ((key_fp = sshkey_fingerprint(key,
515 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
516 error_f("sshkey_fingerprint failed");
517 goto out;
518 }
519 if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) {
520 error_fr(r, "sshkey_to_base64 failed");
521 goto out;
522 }
523 if ((r = sshkey_to_base64(key, &keytext)) != 0) {
524 error_fr(r, "sshkey_to_base64 failed");
525 goto out;
526 }
527 snprintf(serial_s, sizeof(serial_s), "%llu",
528 (unsigned long long)cert->serial);
529 snprintf(uidstr, sizeof(uidstr), "%llu",
530 (unsigned long long)user_pw->pw_uid);
531 for (i = 1; i < ac; i++) {
532 tmp = percent_expand(av[i],
533 "U", uidstr,
534 "u", user_pw->pw_name,
535 "h", user_pw->pw_dir,
536 "t", sshkey_ssh_name(key),
537 "T", sshkey_ssh_name(cert->signature_key),
538 "f", key_fp,
539 "F", ca_fp,
540 "k", keytext,
541 "K", catext,
542 "i", cert->key_id,
543 "s", serial_s,
544 (char *)NULL);
545 if (tmp == NULL)
546 fatal_f("percent_expand failed");
547 free(av[i]);
548 av[i] = tmp;
549 }
550 /* Prepare a printable command for logs, etc. */
551 command = argv_assemble(ac, av);
552
553 if ((pid = subprocess("AuthorizedPrincipalsCommand", command,
554 ac, av, &f,
555 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD,
556 runas_pw, temporarily_use_uid, restore_uid)) == 0)
557 goto out;
558
559 uid_swapped = 1;
560 temporarily_use_uid(runas_pw);
561
562 ok = process_principals(ssh, f, "(command)", cert, authoptsp);
563
564 fclose(f);
565 f = NULL;
566
567 if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
568 goto out;
569
570 /* Read completed successfully */
571 found_principal = ok;
572 out:
573 if (f != NULL)
574 fclose(f);
575 ssh_signal(SIGCHLD, osigchld);
576 for (i = 0; i < ac; i++)
577 free(av[i]);
578 free(av);
579 if (uid_swapped)
580 restore_uid();
581 free(command);
582 free(username);
583 free(ca_fp);
584 free(key_fp);
585 free(catext);
586 free(keytext);
587 return found_principal;
588}
589
590/*
591 * Check a single line of an authorized_keys-format file. Returns 0 if key
592 * matches, -1 otherwise. Will return key/cert options via *authoptsp
593 * on success. "loc" is used as file/line location in log messages.
594 */
595static int
596check_authkey_line(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
597 char *cp, const char *loc, struct sshauthopt **authoptsp)
598{
599 int want_keytype = sshkey_is_cert(key) ? KEY_UNSPEC : key->type;
600 struct sshkey *found = NULL;
601 struct sshauthopt *keyopts = NULL, *certopts = NULL, *finalopts = NULL;
602 char *key_options = NULL, *fp = NULL;
603 const char *reason = NULL;
604 int ret = -1;
605
606 if (authoptsp != NULL)
607 *authoptsp = NULL;
608
609 if ((found = sshkey_new(want_keytype)) == NULL) {
610 debug3_f("keytype %d failed", want_keytype);
611 goto out;
612 }
613
614 /* XXX djm: peek at key type in line and skip if unwanted */
615
616 if (sshkey_read(found, &cp) != 0) {
617 /* no key? check for options */
618 debug2("%s: check options: '%s'", loc, cp);
619 key_options = cp;
620 if (sshkey_advance_past_options(&cp) != 0) {
621 reason = "invalid key option string";
622 goto fail_reason;
623 }
624 skip_space(&cp);
625 if (sshkey_read(found, &cp) != 0) {
626 /* still no key? advance to next line*/
627 debug2("%s: advance: '%s'", loc, cp);
628 goto out;
629 }
630 }
631 /* Parse key options now; we need to know if this is a CA key */
632 if ((keyopts = sshauthopt_parse(key_options, &reason)) == NULL) {
633 debug("%s: bad key options: %s", loc, reason);
634 auth_debug_add("%s: bad key options: %s", loc, reason);
635 goto out;
636 }
637 /* Ignore keys that don't match or incorrectly marked as CAs */
638 if (sshkey_is_cert(key)) {
639 /* Certificate; check signature key against CA */
640 if (!sshkey_equal(found, key->cert->signature_key) ||
641 !keyopts->cert_authority)
642 goto out;
643 } else {
644 /* Plain key: check it against key found in file */
645 if (!sshkey_equal(found, key) || keyopts->cert_authority)
646 goto out;
647 }
648
649 /* We have a candidate key, perform authorisation checks */
650 if ((fp = sshkey_fingerprint(found,
651 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
652 fatal_f("fingerprint failed");
653
654 debug("%s: matching %s found: %s %s", loc,
655 sshkey_is_cert(key) ? "CA" : "key", sshkey_type(found), fp);
656
657 if (auth_authorise_keyopts(ssh, pw, keyopts,
658 sshkey_is_cert(key), loc) != 0) {
659 reason = "Refused by key options";
660 goto fail_reason;
661 }
662 /* That's all we need for plain keys. */
663 if (!sshkey_is_cert(key)) {
664 verbose("Accepted key %s %s found at %s",
665 sshkey_type(found), fp, loc);
666 finalopts = keyopts;
667 keyopts = NULL;
668 goto success;
669 }
670
671 /*
672 * Additional authorisation for certificates.
673 */
674
675 /* Parse and check options present in certificate */
676 if ((certopts = sshauthopt_from_cert(key)) == NULL) {
677 reason = "Invalid certificate options";
678 goto fail_reason;
679 }
680 if (auth_authorise_keyopts(ssh, pw, certopts, 0, loc) != 0) {
681 reason = "Refused by certificate options";
682 goto fail_reason;
683 }
684 if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL)
685 goto fail_reason;
686
687 /*
688 * If the user has specified a list of principals as
689 * a key option, then prefer that list to matching
690 * their username in the certificate principals list.
691 */
692 if (keyopts->cert_principals != NULL &&
693 !match_principals_option(keyopts->cert_principals, key->cert)) {
694 reason = "Certificate does not contain an authorized principal";
695 goto fail_reason;
696 }
697 if (sshkey_cert_check_authority_now(key, 0, 0, 0,
698 keyopts->cert_principals == NULL ? pw->pw_name : NULL,
699 &reason) != 0)
700 goto fail_reason;
701
702 verbose("Accepted certificate ID \"%s\" (serial %llu) "
703 "signed by CA %s %s found at %s",
704 key->cert->key_id,
705 (unsigned long long)key->cert->serial,
706 sshkey_type(found), fp, loc);
707
708 success:
709 if (finalopts == NULL)
710 fatal_f("internal error: missing options");
711 if (authoptsp != NULL) {
712 *authoptsp = finalopts;
713 finalopts = NULL;
714 }
715 /* success */
716 ret = 0;
717 goto out;
718
719 fail_reason:
720 error("%s", reason);
721 auth_debug_add("%s", reason);
722 out:
723 free(fp);
724 sshauthopt_free(keyopts);
725 sshauthopt_free(certopts);
726 sshauthopt_free(finalopts);
727 sshkey_free(found);
728 return ret;
729}
730
731/*
732 * Checks whether key is allowed in authorized_keys-format file,
733 * returns 1 if the key is allowed or 0 otherwise.
734 */
735static int
736check_authkeys_file(struct ssh *ssh, struct passwd *pw, FILE *f,
737 char *file, struct sshkey *key, struct sshauthopt **authoptsp)
738{
739 char *cp, *line = NULL, loc[256];
740 size_t linesize = 0;
741 int found_key = 0;
742 u_long linenum = 0, nonblank = 0;
743
744 if (authoptsp != NULL)
745 *authoptsp = NULL;
746
747 while (getline(&line, &linesize, f) != -1) {
748 linenum++;
749 /* Always consume entire file */
750 if (found_key)
751 continue;
752
753 /* Skip leading whitespace, empty and comment lines. */
754 cp = line;
755 skip_space(&cp);
756 if (!*cp || *cp == '\n' || *cp == '#')
757 continue;
758
759 nonblank++;
760 snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
761 if (check_authkey_line(ssh, pw, key, cp, loc, authoptsp) == 0)
762 found_key = 1;
763 }
764 free(line);
765 debug2_f("%s: processed %lu/%lu lines", file, nonblank, linenum);
766 return found_key;
767}
768
769/* Authenticate a certificate key against TrustedUserCAKeys */
770static int
771user_cert_trusted_ca(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
772 struct sshauthopt **authoptsp)
773{
774 char *ca_fp, *principals_file = NULL;
775 const char *reason;
776 struct sshauthopt *principals_opts = NULL, *cert_opts = NULL;
777 struct sshauthopt *final_opts = NULL;
778 int r, ret = 0, found_principal = 0, use_authorized_principals;
779
780 if (authoptsp != NULL)
781 *authoptsp = NULL;
782
783 if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
784 return 0;
785
786 if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
787 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
788 return 0;
789
790 if ((r = sshkey_in_file(key->cert->signature_key,
791 options.trusted_user_ca_keys, 1, 0)) != 0) {
792 debug2_fr(r, "CA %s %s is not listed in %s",
793 sshkey_type(key->cert->signature_key), ca_fp,
794 options.trusted_user_ca_keys);
795 goto out;
796 }
797 /*
798 * If AuthorizedPrincipals is in use, then compare the certificate
799 * principals against the names in that file rather than matching
800 * against the username.
801 */
802 if ((principals_file = authorized_principals_file(pw)) != NULL) {
803 if (match_principals_file(ssh, pw, principals_file,
804 key->cert, &principals_opts))
805 found_principal = 1;
806 }
807 /* Try querying command if specified */
808 if (!found_principal && match_principals_command(ssh, pw, key,
809 &principals_opts))
810 found_principal = 1;
811 /* If principals file or command is specified, then require a match */
812 use_authorized_principals = principals_file != NULL ||
813 options.authorized_principals_command != NULL;
814 if (!found_principal && use_authorized_principals) {
815 reason = "Certificate does not contain an authorized principal";
816 goto fail_reason;
817 }
818 if (use_authorized_principals && principals_opts == NULL)
819 fatal_f("internal error: missing principals_opts");
820 if (sshkey_cert_check_authority_now(key, 0, 1, 0,
821 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
822 goto fail_reason;
823
824 /* Check authority from options in key and from principals file/cmd */
825 if ((cert_opts = sshauthopt_from_cert(key)) == NULL) {
826 reason = "Invalid certificate options";
827 goto fail_reason;
828 }
829 if (auth_authorise_keyopts(ssh, pw, cert_opts, 0, "cert") != 0) {
830 reason = "Refused by certificate options";
831 goto fail_reason;
832 }
833 if (principals_opts == NULL) {
834 final_opts = cert_opts;
835 cert_opts = NULL;
836 } else {
837 if (auth_authorise_keyopts(ssh, pw, principals_opts, 0,
838 "principals") != 0) {
839 reason = "Refused by certificate principals options";
840 goto fail_reason;
841 }
842 if ((final_opts = sshauthopt_merge(principals_opts,
843 cert_opts, &reason)) == NULL) {
844 fail_reason:
845 error("%s", reason);
846 auth_debug_add("%s", reason);
847 goto out;
848 }
849 }
850
851 /* Success */
852 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
853 "%s CA %s via %s", key->cert->key_id,
854 (unsigned long long)key->cert->serial,
855 sshkey_type(key->cert->signature_key), ca_fp,
856 options.trusted_user_ca_keys);
857 if (authoptsp != NULL) {
858 *authoptsp = final_opts;
859 final_opts = NULL;
860 }
861 ret = 1;
862 out:
863 sshauthopt_free(principals_opts);
864 sshauthopt_free(cert_opts);
865 sshauthopt_free(final_opts);
866 free(principals_file);
867 free(ca_fp);
868 return ret;
869}
870
871/*
872 * Checks whether key is allowed in file.
873 * returns 1 if the key is allowed or 0 otherwise.
874 */
875static int
876user_key_allowed2(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
877 char *file, struct sshauthopt **authoptsp)
878{
879 FILE *f;
880 int found_key = 0;
881
882 if (authoptsp != NULL)
883 *authoptsp = NULL;
884
885 /* Temporarily use the user's uid. */
886 temporarily_use_uid(pw);
887
888 debug("trying public key file %s", file);
889 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
890 found_key = check_authkeys_file(ssh, pw, f, file,
891 key, authoptsp);
892 fclose(f);
893 }
894
895 restore_uid();
896 return found_key;
897}
898
899/*
900 * Checks whether key is allowed in output of command.
901 * returns 1 if the key is allowed or 0 otherwise.
902 */
903static int
904user_key_command_allowed2(struct ssh *ssh, struct passwd *user_pw,
905 struct sshkey *key, struct sshauthopt **authoptsp)
906{
907 struct passwd *runas_pw = NULL;
908 FILE *f = NULL;
909 int r, ok, found_key = 0;
910 int i, uid_swapped = 0, ac = 0;
911 pid_t pid;
912 char *username = NULL, *key_fp = NULL, *keytext = NULL;
913 char uidstr[32], *tmp, *command = NULL, **av = NULL;
914 void (*osigchld)(int);
915
916 if (authoptsp != NULL)
917 *authoptsp = NULL;
918 if (options.authorized_keys_command == NULL)
919 return 0;
920 if (options.authorized_keys_command_user == NULL) {
921 error("No user for AuthorizedKeysCommand specified, skipping");
922 return 0;
923 }
924
925 /*
926 * NB. all returns later this function should go via "out" to
927 * ensure the original SIGCHLD handler is restored properly.
928 */
929 osigchld = ssh_signal(SIGCHLD, SIG_DFL);
930
931 /* Prepare and verify the user for the command */
932 username = percent_expand(options.authorized_keys_command_user,
933 "u", user_pw->pw_name, (char *)NULL);
934 runas_pw = getpwnam(username);
935 if (runas_pw == NULL) {
936 error("AuthorizedKeysCommandUser \"%s\" not found: %s",
937 username, strerror(errno));
938 goto out;
939 }
940
941 /* Prepare AuthorizedKeysCommand */
942 if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash,
943 SSH_FP_DEFAULT)) == NULL) {
944 error_f("sshkey_fingerprint failed");
945 goto out;
946 }
947 if ((r = sshkey_to_base64(key, &keytext)) != 0) {
948 error_fr(r, "sshkey_to_base64 failed");
949 goto out;
950 }
951
952 /* Turn the command into an argument vector */
953 if (argv_split(options.authorized_keys_command, &ac, &av, 0) != 0) {
954 error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
955 options.authorized_keys_command);
956 goto out;
957 }
958 if (ac == 0) {
959 error("AuthorizedKeysCommand \"%s\" yielded no arguments",
960 options.authorized_keys_command);
961 goto out;
962 }
963 snprintf(uidstr, sizeof(uidstr), "%llu",
964 (unsigned long long)user_pw->pw_uid);
965 for (i = 1; i < ac; i++) {
966 tmp = percent_expand(av[i],
967 "U", uidstr,
968 "u", user_pw->pw_name,
969 "h", user_pw->pw_dir,
970 "t", sshkey_ssh_name(key),
971 "f", key_fp,
972 "k", keytext,
973 (char *)NULL);
974 if (tmp == NULL)
975 fatal_f("percent_expand failed");
976 free(av[i]);
977 av[i] = tmp;
978 }
979 /* Prepare a printable command for logs, etc. */
980 command = argv_assemble(ac, av);
981
982 /*
983 * If AuthorizedKeysCommand was run without arguments
984 * then fall back to the old behaviour of passing the
985 * target username as a single argument.
986 */
987 if (ac == 1) {
988 av = xreallocarray(av, ac + 2, sizeof(*av));
989 av[1] = xstrdup(user_pw->pw_name);
990 av[2] = NULL;
991 /* Fix up command too, since it is used in log messages */
992 free(command);
993 xasprintf(&command, "%s %s", av[0], av[1]);
994 }
995
996 if ((pid = subprocess("AuthorizedKeysCommand", command,
997 ac, av, &f,
998 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD,
999 runas_pw, temporarily_use_uid, restore_uid)) == 0)
1000 goto out;
1001
1002 uid_swapped = 1;
1003 temporarily_use_uid(runas_pw);
1004
1005 ok = check_authkeys_file(ssh, user_pw, f,
1006 options.authorized_keys_command, key, authoptsp);
1007
1008 fclose(f);
1009 f = NULL;
1010
1011 if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
1012 goto out;
1013
1014 /* Read completed successfully */
1015 found_key = ok;
1016 out:
1017 if (f != NULL)
1018 fclose(f);
1019 ssh_signal(SIGCHLD, osigchld);
1020 for (i = 0; i < ac; i++)
1021 free(av[i]);
1022 free(av);
1023 if (uid_swapped)
1024 restore_uid();
1025 free(command);
1026 free(username);
1027 free(key_fp);
1028 free(keytext);
1029 return found_key;
1030}
1031
1032/*
1033 * Check whether key authenticates and authorises the user.
1034 */
1035int
1036user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
1037 int auth_attempt, struct sshauthopt **authoptsp)
1038{
1039 u_int success = 0, i;
1040 char *file;
1041 struct sshauthopt *opts = NULL;
1042
1043 if (authoptsp != NULL)
1044 *authoptsp = NULL;
1045
1046 if (auth_key_is_revoked(key))
1047 return 0;
1048 if (sshkey_is_cert(key) &&
1049 auth_key_is_revoked(key->cert->signature_key))
1050 return 0;
1051
1052 for (i = 0; !success && i < options.num_authkeys_files; i++) {
1053 if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
1054 continue;
1055 file = expand_authorized_keys(
1056 options.authorized_keys_files[i], pw);
1057 success = user_key_allowed2(ssh, pw, key, file, &opts);
1058 free(file);
1059 if (!success) {
1060 sshauthopt_free(opts);
1061 opts = NULL;
1062 }
1063 }
1064 if (success)
1065 goto out;
1066
1067 if ((success = user_cert_trusted_ca(ssh, pw, key, &opts)) != 0)
1068 goto out;
1069 sshauthopt_free(opts);
1070 opts = NULL;
1071
1072 if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0)
1073 goto out;
1074 sshauthopt_free(opts);
1075 opts = NULL;
1076
1077 out:
1078 if (success && authoptsp != NULL) {
1079 *authoptsp = opts;
1080 opts = NULL;
1081 }
1082 sshauthopt_free(opts);
1083 return success;
1084}
1085
1086Authmethod method_pubkey = {
1087 "publickey",
1088 "publickey-hostbound-v00@openssh.com",
1089 userauth_pubkey,
1090 &options.pubkey_authentication
1091};