169839b01ed7119552176836ff6e89ec80ad5010
[dragonfly.git] / crypto / openssh / auth2-pubkey.c
1 /* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 djm 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 #include "includes.h"
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #include <errno.h>
32 #include <fcntl.h>
33 #ifdef HAVE_PATHS_H
34 # include <paths.h>
35 #endif
36 #include <pwd.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <time.h>
42 #include <unistd.h>
43 #include <limits.h>
44
45 #include "xmalloc.h"
46 #include "ssh.h"
47 #include "ssh2.h"
48 #include "packet.h"
49 #include "buffer.h"
50 #include "log.h"
51 #include "misc.h"
52 #include "servconf.h"
53 #include "compat.h"
54 #include "sshkey.h"
55 #include "hostfile.h"
56 #include "auth.h"
57 #include "pathnames.h"
58 #include "uidswap.h"
59 #include "auth-options.h"
60 #include "canohost.h"
61 #ifdef GSSAPI
62 #include "ssh-gss.h"
63 #endif
64 #include "monitor_wrap.h"
65 #include "authfile.h"
66 #include "match.h"
67 #include "ssherr.h"
68 #include "channels.h" /* XXX for session.h */
69 #include "session.h" /* XXX for child_set_env(); refactor? */
70
71 /* import */
72 extern ServerOptions options;
73 extern u_char *session_id2;
74 extern u_int session_id2_len;
75
76 static int
77 userauth_pubkey(struct ssh *ssh)
78 {
79         Authctxt *authctxt = ssh->authctxt;
80         struct sshbuf *b;
81         struct sshkey *key = NULL;
82         char *pkalg, *userstyle = NULL, *fp = NULL;
83         u_char *pkblob, *sig, have_sig;
84         size_t blen, slen;
85         int r, pktype;
86         int authenticated = 0;
87
88         if (!authctxt->valid) {
89                 debug2("%s: disabled because of invalid user", __func__);
90                 return 0;
91         }
92         if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0)
93                 fatal("%s: sshpkt_get_u8 failed: %s", __func__, ssh_err(r));
94         if (ssh->compat & SSH_BUG_PKAUTH) {
95                 debug2("%s: SSH_BUG_PKAUTH", __func__);
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);
113         if (pktype == KEY_UNSPEC) {
114                 /* this is perfectly legal */
115                 logit("%s: unsupported public key algorithm: %s",
116                     __func__, pkalg);
117                 goto done;
118         }
119         if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
120                 error("%s: could not parse key: %s", __func__, ssh_err(r));
121                 goto done;
122         }
123         if (key == NULL) {
124                 error("%s: cannot decode key: %s", __func__, pkalg);
125                 goto done;
126         }
127         if (key->type != pktype) {
128                 error("%s: type mismatch for decoded key "
129                     "(received %d, expected %d)", __func__, key->type, pktype);
130                 goto done;
131         }
132         if (sshkey_type_plain(key->type) == KEY_RSA &&
133             (ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
134                 logit("Refusing RSA key because client uses unsafe "
135                     "signature scheme");
136                 goto done;
137         }
138         fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
139         if (auth2_key_already_used(authctxt, key)) {
140                 logit("refusing previously-used %s key", sshkey_type(key));
141                 goto done;
142         }
143         if (match_pattern_list(sshkey_ssh_name(key),
144             options.pubkey_key_types, 0) != 1) {
145                 logit("%s: key type %s not in PubkeyAcceptedKeyTypes",
146                     __func__, sshkey_ssh_name(key));
147                 goto done;
148         }
149
150         if (have_sig) {
151                 debug3("%s: have signature for %s %s",
152                     __func__, sshkey_type(key), fp);
153                 if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
154                     (r = sshpkt_get_end(ssh)) != 0)
155                         fatal("%s: %s", __func__, ssh_err(r));
156                 if ((b = sshbuf_new()) == NULL)
157                         fatal("%s: sshbuf_new failed", __func__);
158                 if (ssh->compat & SSH_OLD_SESSIONID) {
159                         if ((r = sshbuf_put(b, session_id2,
160                             session_id2_len)) != 0)
161                                 fatal("%s: sshbuf_put session id: %s",
162                                     __func__, ssh_err(r));
163                 } else {
164                         if ((r = sshbuf_put_string(b, session_id2,
165                             session_id2_len)) != 0)
166                                 fatal("%s: sshbuf_put_string session id: %s",
167                                     __func__, ssh_err(r));
168                 }
169                 /* reconstruct packet */
170                 xasprintf(&userstyle, "%s%s%s", authctxt->user,
171                     authctxt->style ? ":" : "",
172                     authctxt->style ? authctxt->style : "");
173                 if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
174                     (r = sshbuf_put_cstring(b, userstyle)) != 0 ||
175                     (r = sshbuf_put_cstring(b, ssh->compat & SSH_BUG_PKSERVICE ?
176                     "ssh-userauth" : authctxt->service)) != 0)
177                         fatal("%s: build packet failed: %s",
178                             __func__, ssh_err(r));
179                 if (ssh->compat & SSH_BUG_PKAUTH) {
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",
192                             __func__, ssh_err(r));
193 #ifdef DEBUG_PK
194                 sshbuf_dump(b, stderr);
195 #endif
196
197                 /* test for correct signature */
198                 authenticated = 0;
199                 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
200                     PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
201                     sshbuf_len(b), ssh->compat)) == 0) {
202                         authenticated = 1;
203                 }
204                 sshbuf_free(b);
205                 free(sig);
206                 auth2_record_key(authctxt, authenticated, key);
207         } else {
208                 debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
209                     __func__, sshkey_type(key), fp);
210                 if ((r = sshpkt_get_end(ssh)) != 0)
211                         fatal("%s: %s", __func__, ssh_err(r));
212
213                 /* XXX fake reply and always send PK_OK ? */
214                 /*
215                  * XXX this allows testing whether a user is allowed
216                  * to login: if you happen to have a valid pubkey this
217                  * message is sent. the message is NEVER sent at all
218                  * if a user is not allowed to login. is this an
219                  * issue? -markus
220                  */
221                 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) {
222                         if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
223                             != 0 ||
224                             (r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
225                             (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 ||
226                             (r = sshpkt_send(ssh)) != 0)
227                                 fatal("%s: %s", __func__, ssh_err(r));
228                         ssh_packet_write_wait(ssh);
229                         authctxt->postponed = 1;
230                 }
231         }
232         if (authenticated != 1)
233                 auth_clear_options();
234 done:
235         debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
236         sshkey_free(key);
237         free(userstyle);
238         free(pkalg);
239         free(pkblob);
240         free(fp);
241         return authenticated;
242 }
243
244 static int
245 match_principals_option(const char *principal_list, struct sshkey_cert *cert)
246 {
247         char *result;
248         u_int i;
249
250         /* XXX percent_expand() sequences for authorized_principals? */
251
252         for (i = 0; i < cert->nprincipals; i++) {
253                 if ((result = match_list(cert->principals[i],
254                     principal_list, NULL)) != NULL) {
255                         debug3("matched principal from key options \"%.100s\"",
256                             result);
257                         free(result);
258                         return 1;
259                 }
260         }
261         return 0;
262 }
263
264 static int
265 process_principals(FILE *f, const char *file, struct passwd *pw,
266     const struct sshkey_cert *cert)
267 {
268         char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
269         u_long linenum = 0;
270         u_int i, found_principal = 0;
271
272         while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
273                 /* Always consume entire input */
274                 if (found_principal)
275                         continue;
276                 /* Skip leading whitespace. */
277                 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
278                         ;
279                 /* Skip blank and comment lines. */
280                 if ((ep = strchr(cp, '#')) != NULL)
281                         *ep = '\0';
282                 if (!*cp || *cp == '\n')
283                         continue;
284                 /* Trim trailing whitespace. */
285                 ep = cp + strlen(cp) - 1;
286                 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
287                         *ep-- = '\0';
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         }
312         return found_principal;
313 }
314
315 static int
316 match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
317 {
318         FILE *f;
319         int success;
320
321         temporarily_use_uid(pw);
322         debug("trying authorized principals file %s", file);
323         if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
324                 restore_uid();
325                 return 0;
326         }
327         success = process_principals(f, file, pw, cert);
328         fclose(f);
329         restore_uid();
330         return success;
331 }
332
333 /*
334  * Checks whether principal is allowed in output of command.
335  * returns 1 if the principal is allowed or 0 otherwise.
336  */
337 static int
338 match_principals_command(struct passwd *user_pw, const struct sshkey *key)
339 {
340         const struct sshkey_cert *cert = key->cert;
341         FILE *f = NULL;
342         int r, ok, found_principal = 0;
343         struct passwd *pw;
344         int i, ac = 0, uid_swapped = 0;
345         pid_t pid;
346         char *tmp, *username = NULL, *command = NULL, **av = NULL;
347         char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL;
348         char serial_s[16];
349         void (*osigchld)(int);
350
351         if (options.authorized_principals_command == NULL)
352                 return 0;
353         if (options.authorized_principals_command_user == NULL) {
354                 error("No user for AuthorizedPrincipalsCommand specified, "
355                     "skipping");
356                 return 0;
357         }
358
359         /*
360          * NB. all returns later this function should go via "out" to
361          * ensure the original SIGCHLD handler is restored properly.
362          */
363         osigchld = signal(SIGCHLD, SIG_DFL);
364
365         /* Prepare and verify the user for the command */
366         username = percent_expand(options.authorized_principals_command_user,
367             "u", user_pw->pw_name, (char *)NULL);
368         pw = getpwnam(username);
369         if (pw == NULL) {
370                 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
371                     username, strerror(errno));
372                 goto out;
373         }
374
375         /* Turn the command into an argument vector */
376         if (argv_split(options.authorized_principals_command, &ac, &av) != 0) {
377                 error("AuthorizedPrincipalsCommand \"%s\" contains "
378                     "invalid quotes", command);
379                 goto out;
380         }
381         if (ac == 0) {
382                 error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments",
383                     command);
384                 goto out;
385         }
386         if ((ca_fp = sshkey_fingerprint(cert->signature_key,
387             options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
388                 error("%s: sshkey_fingerprint failed", __func__);
389                 goto out;
390         }
391         if ((key_fp = sshkey_fingerprint(key,
392             options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
393                 error("%s: sshkey_fingerprint failed", __func__);
394                 goto out;
395         }
396         if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) {
397                 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
398                 goto out;
399         }
400         if ((r = sshkey_to_base64(key, &keytext)) != 0) {
401                 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
402                 goto out;
403         }
404         snprintf(serial_s, sizeof(serial_s), "%llu",
405             (unsigned long long)cert->serial);
406         for (i = 1; i < ac; i++) {
407                 tmp = percent_expand(av[i],
408                     "u", user_pw->pw_name,
409                     "h", user_pw->pw_dir,
410                     "t", sshkey_ssh_name(key),
411                     "T", sshkey_ssh_name(cert->signature_key),
412                     "f", key_fp,
413                     "F", ca_fp,
414                     "k", keytext,
415                     "K", catext,
416                     "i", cert->key_id,
417                     "s", serial_s,
418                     (char *)NULL);
419                 if (tmp == NULL)
420                         fatal("%s: percent_expand failed", __func__);
421                 free(av[i]);
422                 av[i] = tmp;
423         }
424         /* Prepare a printable command for logs, etc. */
425         command = argv_assemble(ac, av);
426
427         if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
428             ac, av, &f,
429             SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
430                 goto out;
431
432         uid_swapped = 1;
433         temporarily_use_uid(pw);
434
435         ok = process_principals(f, "(command)", pw, cert);
436
437         fclose(f);
438         f = NULL;
439
440         if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
441                 goto out;
442
443         /* Read completed successfully */
444         found_principal = ok;
445  out:
446         if (f != NULL)
447                 fclose(f);
448         signal(SIGCHLD, osigchld);
449         for (i = 0; i < ac; i++)
450                 free(av[i]);
451         free(av);
452         if (uid_swapped)
453                 restore_uid();
454         free(command);
455         free(username);
456         free(ca_fp);
457         free(key_fp);
458         free(catext);
459         free(keytext);
460         return found_principal;
461 }
462 /*
463  * Checks whether key is allowed in authorized_keys-format file,
464  * returns 1 if the key is allowed or 0 otherwise.
465  */
466 static int
467 check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw)
468 {
469         char line[SSH_MAX_PUBKEY_BYTES];
470         int found_key = 0;
471         u_long linenum = 0;
472         struct sshkey *found = NULL;
473
474         while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
475                 char *cp, *key_options = NULL, *fp = NULL;
476                 const char *reason = NULL;
477
478                 /* Always consume entire file */
479                 if (found_key)
480                         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
488                 /* Skip leading whitespace, empty and comment lines. */
489                 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
490                         ;
491                 if (!*cp || *cp == '\n' || *cp == '#')
492                         continue;
493
494                 if (sshkey_read(found, &cp) != 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;
569                         continue;
570                 }
571         }
572  done:
573         if (found != NULL)
574                 sshkey_free(found);
575         if (!found_key)
576                 debug2("key not found");
577         return found_key;
578 }
579
580 /* Authenticate a certificate key against TrustedUserCAKeys */
581 static int
582 user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
583 {
584         char *ca_fp, *principals_file = NULL;
585         const char *reason;
586         int r, ret = 0, found_principal = 0, use_authorized_principals;
587
588         if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
589                 return 0;
590
591         if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
592             options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
593                 return 0;
594
595         if ((r = sshkey_in_file(key->cert->signature_key,
596             options.trusted_user_ca_keys, 1, 0)) != 0) {
597                 debug2("%s: CA %s %s is not listed in %s: %s", __func__,
598                     sshkey_type(key->cert->signature_key), ca_fp,
599                     options.trusted_user_ca_keys, ssh_err(r));
600                 goto out;
601         }
602         /*
603          * If AuthorizedPrincipals is in use, then compare the certificate
604          * principals against the names in that file rather than matching
605          * against the username.
606          */
607         if ((principals_file = authorized_principals_file(pw)) != NULL) {
608                 if (match_principals_file(principals_file, pw, key->cert))
609                         found_principal = 1;
610         }
611         /* Try querying command if specified */
612         if (!found_principal && match_principals_command(pw, key))
613                 found_principal = 1;
614         /* If principals file or command is specified, then require a match */
615         use_authorized_principals = principals_file != NULL ||
616             options.authorized_principals_command != NULL;
617         if (!found_principal && use_authorized_principals) {
618                 reason = "Certificate does not contain an authorized principal";
619  fail_reason:
620                 error("%s", reason);
621                 auth_debug_add("%s", reason);
622                 goto out;
623         }
624         if (sshkey_cert_check_authority(key, 0, 1,
625             use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
626                 goto fail_reason;
627         if (auth_cert_options(key, pw, &reason) != 0)
628                 goto fail_reason;
629
630         verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
631             "%s CA %s via %s", key->cert->key_id,
632             (unsigned long long)key->cert->serial,
633             sshkey_type(key->cert->signature_key), ca_fp,
634             options.trusted_user_ca_keys);
635         ret = 1;
636
637  out:
638         free(principals_file);
639         free(ca_fp);
640         return ret;
641 }
642
643 /*
644  * Checks whether key is allowed in file.
645  * returns 1 if the key is allowed or 0 otherwise.
646  */
647 static int
648 user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
649 {
650         FILE *f;
651         int found_key = 0;
652
653         /* Temporarily use the user's uid. */
654         temporarily_use_uid(pw);
655
656         debug("trying public key file %s", file);
657         if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
658                 found_key = check_authkeys_file(f, file, key, pw);
659                 fclose(f);
660         }
661
662         restore_uid();
663         return found_key;
664 }
665
666 /*
667  * Checks whether key is allowed in output of command.
668  * returns 1 if the key is allowed or 0 otherwise.
669  */
670 static int
671 user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
672 {
673         FILE *f = NULL;
674         int r, ok, found_key = 0;
675         struct passwd *pw;
676         int i, uid_swapped = 0, ac = 0;
677         pid_t pid;
678         char *username = NULL, *key_fp = NULL, *keytext = NULL;
679         char *tmp, *command = NULL, **av = NULL;
680         void (*osigchld)(int);
681
682         if (options.authorized_keys_command == NULL)
683                 return 0;
684         if (options.authorized_keys_command_user == NULL) {
685                 error("No user for AuthorizedKeysCommand specified, skipping");
686                 return 0;
687         }
688
689         /*
690          * NB. all returns later this function should go via "out" to
691          * ensure the original SIGCHLD handler is restored properly.
692          */
693         osigchld = signal(SIGCHLD, SIG_DFL);
694
695         /* Prepare and verify the user for the command */
696         username = percent_expand(options.authorized_keys_command_user,
697             "u", user_pw->pw_name, (char *)NULL);
698         pw = getpwnam(username);
699         if (pw == NULL) {
700                 error("AuthorizedKeysCommandUser \"%s\" not found: %s",
701                     username, strerror(errno));
702                 goto out;
703         }
704
705         /* Prepare AuthorizedKeysCommand */
706         if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash,
707             SSH_FP_DEFAULT)) == NULL) {
708                 error("%s: sshkey_fingerprint failed", __func__);
709                 goto out;
710         }
711         if ((r = sshkey_to_base64(key, &keytext)) != 0) {
712                 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
713                 goto out;
714         }
715
716         /* Turn the command into an argument vector */
717         if (argv_split(options.authorized_keys_command, &ac, &av) != 0) {
718                 error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
719                     command);
720                 goto out;
721         }
722         if (ac == 0) {
723                 error("AuthorizedKeysCommand \"%s\" yielded no arguments",
724                     command);
725                 goto out;
726         }
727         for (i = 1; i < ac; i++) {
728                 tmp = percent_expand(av[i],
729                     "u", user_pw->pw_name,
730                     "h", user_pw->pw_dir,
731                     "t", sshkey_ssh_name(key),
732                     "f", key_fp,
733                     "k", keytext,
734                     (char *)NULL);
735                 if (tmp == NULL)
736                         fatal("%s: percent_expand failed", __func__);
737                 free(av[i]);
738                 av[i] = tmp;
739         }
740         /* Prepare a printable command for logs, etc. */
741         command = argv_assemble(ac, av);
742
743         /*
744          * If AuthorizedKeysCommand was run without arguments
745          * then fall back to the old behaviour of passing the
746          * target username as a single argument.
747          */
748         if (ac == 1) {
749                 av = xreallocarray(av, ac + 2, sizeof(*av));
750                 av[1] = xstrdup(user_pw->pw_name);
751                 av[2] = NULL;
752                 /* Fix up command too, since it is used in log messages */
753                 free(command);
754                 xasprintf(&command, "%s %s", av[0], av[1]);
755         }
756
757         if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
758             ac, av, &f,
759             SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
760                 goto out;
761
762         uid_swapped = 1;
763         temporarily_use_uid(pw);
764
765         ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
766
767         fclose(f);
768         f = NULL;
769
770         if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
771                 goto out;
772
773         /* Read completed successfully */
774         found_key = ok;
775  out:
776         if (f != NULL)
777                 fclose(f);
778         signal(SIGCHLD, osigchld);
779         for (i = 0; i < ac; i++)
780                 free(av[i]);
781         free(av);
782         if (uid_swapped)
783                 restore_uid();
784         free(command);
785         free(username);
786         free(key_fp);
787         free(keytext);
788         return found_key;
789 }
790
791 /*
792  * Check whether key authenticates and authorises the user.
793  */
794 int
795 user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
796 {
797         u_int success, i;
798         char *file;
799
800         if (auth_key_is_revoked(key))
801                 return 0;
802         if (sshkey_is_cert(key) &&
803             auth_key_is_revoked(key->cert->signature_key))
804                 return 0;
805
806         success = user_cert_trusted_ca(pw, key);
807         if (success)
808                 return success;
809
810         success = user_key_command_allowed2(pw, key);
811         if (success > 0)
812                 return success;
813
814         for (i = 0; !success && i < options.num_authkeys_files; i++) {
815
816                 if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
817                         continue;
818                 file = expand_authorized_keys(
819                     options.authorized_keys_files[i], pw);
820
821                 success = user_key_allowed2(pw, key, file);
822                 free(file);
823         }
824
825         return success;
826 }
827
828 Authmethod method_pubkey = {
829         "publickey",
830         userauth_pubkey,
831         &options.pubkey_authentication
832 };