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