Branch data Line data Source code
1 : : /* $OpenBSD: auth2-pubkey.c,v 1.39 2013/12/30 23:52:27 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 : : #include <sys/wait.h>
31 : :
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 : :
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 "servconf.h"
52 : : #include "compat.h"
53 : : #include "key.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 "misc.h"
65 : : #include "authfile.h"
66 : : #include "match.h"
67 : :
68 : : /* import */
69 : : extern ServerOptions options;
70 : : extern u_char *session_id2;
71 : : extern u_int session_id2_len;
72 : :
73 : : static int
74 : 1610 : userauth_pubkey(Authctxt *authctxt)
75 : : {
76 : : Buffer b;
77 : 1610 : Key *key = NULL;
78 : : char *pkalg, *userstyle;
79 : : u_char *pkblob, *sig;
80 : : u_int alen, blen, slen;
81 : : int have_sig, pktype;
82 : 1610 : int authenticated = 0;
83 : :
84 [ - + ]: 1610 : if (!authctxt->valid) {
85 : 0 : debug2("userauth_pubkey: disabled because of invalid user");
86 : 0 : return 0;
87 : : }
88 : 1610 : have_sig = packet_get_char();
89 [ - + ]: 1610 : if (datafellows & SSH_BUG_PKAUTH) {
90 : 0 : debug2("userauth_pubkey: SSH_BUG_PKAUTH");
91 : : /* no explicit pkalg given */
92 : 0 : pkblob = packet_get_string(&blen);
93 : 0 : buffer_init(&b);
94 : 0 : buffer_append(&b, pkblob, blen);
95 : : /* so we have to extract the pkalg from the pkblob */
96 : 0 : pkalg = buffer_get_string(&b, &alen);
97 : 0 : buffer_free(&b);
98 : : } else {
99 : 1610 : pkalg = packet_get_string(&alen);
100 : 1610 : pkblob = packet_get_string(&blen);
101 : : }
102 : 1610 : pktype = key_type_from_name(pkalg);
103 [ - + ]: 1610 : if (pktype == KEY_UNSPEC) {
104 : : /* this is perfectly legal */
105 : 0 : logit("userauth_pubkey: unsupported public key algorithm: %s",
106 : : pkalg);
107 : 0 : goto done;
108 : : }
109 : 1610 : key = key_from_blob(pkblob, blen);
110 [ - + ]: 1610 : if (key == NULL) {
111 : 0 : error("userauth_pubkey: cannot decode key: %s", pkalg);
112 : 0 : goto done;
113 : : }
114 [ - + ]: 1610 : if (key->type != pktype) {
115 : 0 : error("userauth_pubkey: type mismatch for decoded key "
116 : : "(received %d, expected %d)", key->type, pktype);
117 : 0 : goto done;
118 : : }
119 [ + + ][ - + ]: 1610 : if (key_type_plain(key->type) == KEY_RSA &&
120 : 1284 : (datafellows & SSH_BUG_RSASIGMD5) != 0) {
121 : 0 : logit("Refusing RSA key because client uses unsafe "
122 : : "signature scheme");
123 : 0 : goto done;
124 : : }
125 [ + + ]: 1610 : if (have_sig) {
126 : 732 : sig = packet_get_string(&slen);
127 [ - + ]: 732 : packet_check_eom();
128 : 732 : buffer_init(&b);
129 [ - + ]: 732 : if (datafellows & SSH_OLD_SESSIONID) {
130 : 0 : buffer_append(&b, session_id2, session_id2_len);
131 : : } else {
132 : 732 : buffer_put_string(&b, session_id2, session_id2_len);
133 : : }
134 : : /* reconstruct packet */
135 : 732 : buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
136 [ + + ][ + + ]: 732 : xasprintf(&userstyle, "%s%s%s", authctxt->user,
137 : : authctxt->style ? ":" : "",
138 : 732 : authctxt->style ? authctxt->style : "");
139 : 732 : buffer_put_cstring(&b, userstyle);
140 : 732 : free(userstyle);
141 [ + - ]: 732 : buffer_put_cstring(&b,
142 : 732 : datafellows & SSH_BUG_PKSERVICE ?
143 : : "ssh-userauth" :
144 : : authctxt->service);
145 [ - + ]: 732 : if (datafellows & SSH_BUG_PKAUTH) {
146 : 0 : buffer_put_char(&b, have_sig);
147 : : } else {
148 : 732 : buffer_put_cstring(&b, "publickey");
149 : 732 : buffer_put_char(&b, have_sig);
150 : 732 : buffer_put_cstring(&b, pkalg);
151 : : }
152 : 732 : buffer_put_string(&b, pkblob, blen);
153 : : #ifdef DEBUG_PK
154 : : buffer_dump(&b);
155 : : #endif
156 : 732 : pubkey_auth_info(authctxt, key, NULL);
157 : :
158 : : /* test for correct signature */
159 : 732 : authenticated = 0;
160 [ + + ][ + - ]: 1464 : if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
[ + - ]
161 : 732 : PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
162 [ + + ]: 1464 : buffer_len(&b))) == 1)
163 : 732 : authenticated = 1;
164 : 732 : buffer_free(&b);
165 : 732 : free(sig);
166 : : } else {
167 : 878 : debug("test whether pkalg/pkblob are acceptable");
168 [ - + ]: 878 : packet_check_eom();
169 : :
170 : : /* XXX fake reply and always send PK_OK ? */
171 : : /*
172 : : * XXX this allows testing whether a user is allowed
173 : : * to login: if you happen to have a valid pubkey this
174 : : * message is sent. the message is NEVER sent at all
175 : : * if a user is not allowed to login. is this an
176 : : * issue? -markus
177 : : */
178 [ + + ][ + + ]: 878 : if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
179 : 732 : packet_start(SSH2_MSG_USERAUTH_PK_OK);
180 : 732 : packet_put_string(pkalg, alen);
181 : 732 : packet_put_string(pkblob, blen);
182 : 732 : packet_send();
183 : 732 : packet_write_wait();
184 : 732 : authctxt->postponed = 1;
185 : : }
186 : : }
187 [ + + ]: 1610 : if (authenticated != 1)
188 : 878 : auth_clear_options();
189 : : done:
190 : 1610 : debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
191 [ + - ]: 1610 : if (key != NULL)
192 : 1610 : key_free(key);
193 : 1610 : free(pkalg);
194 : 1610 : free(pkblob);
195 : 1610 : return authenticated;
196 : : }
197 : :
198 : : void
199 : 2234 : pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
200 : : {
201 : : char *fp, *extra;
202 : : va_list ap;
203 : : int i;
204 : :
205 : 2234 : extra = NULL;
206 [ - + ]: 2234 : if (fmt != NULL) {
207 : 0 : va_start(ap, fmt);
208 : 0 : i = vasprintf(&extra, fmt, ap);
209 : 0 : va_end(ap);
210 [ # # ][ # # ]: 0 : if (i < 0 || extra == NULL)
211 : 0 : fatal("%s: vasprintf failed", __func__);
212 : : }
213 : :
214 [ + + ]: 2234 : if (key_is_cert(key)) {
215 : 310 : fp = key_fingerprint(key->cert->signature_key,
216 : : SSH_FP_MD5, SSH_FP_HEX);
217 [ - + ][ - + ]: 310 : auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s",
218 : : key_type(key), key->cert->key_id,
219 : 310 : (unsigned long long)key->cert->serial,
220 : 310 : key_type(key->cert->signature_key), fp,
221 : 310 : extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
222 : 310 : free(fp);
223 : : } else {
224 : 1924 : fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
225 [ - + ][ - + ]: 1924 : auth_info(authctxt, "%s %s%s%s", key_type(key), fp,
226 : 1924 : extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
227 : 1924 : free(fp);
228 : : }
229 : 2234 : free(extra);
230 : 2234 : }
231 : :
232 : : static int
233 : 72 : match_principals_option(const char *principal_list, struct KeyCert *cert)
234 : : {
235 : : char *result;
236 : : u_int i;
237 : :
238 : : /* XXX percent_expand() sequences for authorized_principals? */
239 : :
240 [ + - ]: 68 : for (i = 0; i < cert->nprincipals; i++) {
241 [ + + ]: 68 : if ((result = match_list(cert->principals[i],
242 : : principal_list, NULL)) != NULL) {
243 : 36 : debug3("matched principal from key options \"%.100s\"",
244 : : result);
245 : 36 : free(result);
246 : : return 1;
247 : : }
248 : : }
249 : : return 0;
250 : : }
251 : :
252 : : static int
253 : 100 : match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert)
254 : : {
255 : : FILE *f;
256 : : char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
257 : 100 : u_long linenum = 0;
258 : : u_int i;
259 : :
260 : 100 : temporarily_use_uid(pw);
261 : 100 : debug("trying authorized principals file %s", file);
262 [ + - ]: 100 : if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
263 : 0 : restore_uid();
264 : : return 0;
265 : : }
266 [ + - ]: 100 : while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
267 : : /* Skip leading whitespace. */
268 [ - + ]: 100 : for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
269 : : ;
270 : : /* Skip blank and comment lines. */
271 [ - + ]: 100 : if ((ep = strchr(cp, '#')) != NULL)
272 : 0 : *ep = '\0';
273 [ - + ]: 100 : if (!*cp || *cp == '\n')
274 : 0 : continue;
275 : : /* Trim trailing whitespace. */
276 : 100 : ep = cp + strlen(cp) - 1;
277 [ + - ][ + + ]: 200 : while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
[ - + ]
278 : 100 : *ep-- = '\0';
279 : : /*
280 : : * If the line has internal whitespace then assume it has
281 : : * key options.
282 : : */
283 : 100 : line_opts = NULL;
284 [ + + ][ - + ]: 100 : if ((ep = strrchr(cp, ' ')) != NULL ||
285 : : (ep = strrchr(cp, '\t')) != NULL) {
286 [ + + ]: 128 : for (; *ep == ' ' || *ep == '\t'; ep++)
287 : : ;
288 : : line_opts = cp;
289 : : cp = ep;
290 : : }
291 [ + - ]: 196 : for (i = 0; i < cert->nprincipals; i++) {
292 [ + + ]: 196 : if (strcmp(cp, cert->principals[i]) == 0) {
293 : 100 : debug3("matched principal \"%.100s\" "
294 : : "from file \"%s\" on line %lu",
295 : : cert->principals[i], file, linenum);
296 [ - + ]: 100 : if (auth_parse_options(pw, line_opts,
297 : : file, linenum) != 1)
298 : 0 : continue;
299 : 100 : fclose(f);
300 : 100 : restore_uid();
301 : : return 1;
302 : : }
303 : : }
304 : : }
305 : 0 : fclose(f);
306 : 0 : restore_uid();
307 : : return 0;
308 : : }
309 : :
310 : : /*
311 : : * Checks whether key is allowed in authorized_keys-format file,
312 : : * returns 1 if the key is allowed or 0 otherwise.
313 : : */
314 : : static int
315 : 1386 : check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
316 : : {
317 : : char line[SSH_MAX_PUBKEY_BYTES];
318 : : const char *reason;
319 : 1386 : int found_key = 0;
320 : 1386 : u_long linenum = 0;
321 : : Key *found;
322 : : char *fp;
323 : :
324 : 1386 : found_key = 0;
325 : :
326 : 1386 : found = NULL;
327 [ + + ]: 1486 : while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
328 : 1388 : char *cp, *key_options = NULL;
329 [ + + ]: 1388 : if (found != NULL)
330 : 2 : key_free(found);
331 [ + + ]: 1388 : found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
332 : 1388 : auth_clear_options();
333 : :
334 : : /* Skip leading whitespace, empty and comment lines. */
335 [ - + ]: 1388 : for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
336 : : ;
337 [ + + ][ - + ]: 1388 : if (!*cp || *cp == '\n' || *cp == '#')
338 : 78 : continue;
339 : :
340 [ + + ]: 1348 : if (key_read(found, &cp) != 1) {
341 : : /* no key? check if there are options for this key */
342 : 262 : int quoted = 0;
343 : 262 : debug2("user_key_allowed: check options: '%s'", cp);
344 : 262 : key_options = cp;
345 [ - + ][ + + ]: 7140 : for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
[ + + ]
346 [ - + ][ # # ]: 6878 : if (*cp == '\\' && cp[1] == '"')
347 : 0 : cp++; /* Skip both */
348 [ + + ]: 6878 : else if (*cp == '"')
349 : 340 : quoted = !quoted;
350 : : }
351 : : /* Skip remaining whitespace. */
352 [ + + ]: 524 : for (; *cp == ' ' || *cp == '\t'; cp++)
353 : : ;
354 [ + + ]: 262 : if (key_read(found, &cp) != 1) {
355 : 38 : debug2("user_key_allowed: advance: '%s'", cp);
356 : : /* still no key? advance to next line*/
357 : 38 : continue;
358 : : }
359 : : }
360 [ + + ]: 1310 : if (key_is_cert(key)) {
361 [ - + ]: 116 : if (!key_equal(found, key->cert->signature_key))
362 : 0 : continue;
363 [ - + ]: 116 : if (auth_parse_options(pw, key_options, file,
364 : : linenum) != 1)
365 : 0 : continue;
366 [ - + ]: 116 : if (!key_is_cert_authority)
367 : 0 : continue;
368 : 116 : fp = key_fingerprint(found, SSH_FP_MD5,
369 : : SSH_FP_HEX);
370 : 116 : debug("matching CA found: file %s, line %lu, %s %s",
371 : : file, linenum, key_type(found), fp);
372 : : /*
373 : : * If the user has specified a list of principals as
374 : : * a key option, then prefer that list to matching
375 : : * their username in the certificate principals list.
376 : : */
377 [ + + - + ]: 152 : if (authorized_principals != NULL &&
378 : 36 : !match_principals_option(authorized_principals,
379 : : key->cert)) {
380 : 0 : reason = "Certificate does not contain an "
381 : : "authorized principal";
382 : : fail_reason:
383 : 0 : free(fp);
384 : 0 : error("%s", reason);
385 : 0 : auth_debug_add("%s", reason);
386 : 0 : continue;
387 : : }
388 [ + + ][ - + ]: 116 : if (key_cert_check_authority(key, 0, 0,
389 : 116 : authorized_principals == NULL ? pw->pw_name : NULL,
390 : : &reason) != 0)
391 : : goto fail_reason;
392 [ - + ]: 116 : if (auth_cert_options(key, pw) != 0) {
393 : 0 : free(fp);
394 : 0 : continue;
395 : : }
396 : 116 : verbose("Accepted certificate ID \"%s\" "
397 : 116 : "signed by %s CA %s via %s", key->cert->key_id,
398 : : key_type(found), fp, file);
399 : 116 : free(fp);
400 : 116 : found_key = 1;
401 : 1388 : break;
402 [ + + ]: 1194 : } else if (key_equal(found, key)) {
403 [ - + ]: 1172 : if (auth_parse_options(pw, key_options, file,
404 : : linenum) != 1)
405 : 0 : continue;
406 [ - + ]: 1172 : if (key_is_cert_authority)
407 : 0 : continue;
408 : 1172 : found_key = 1;
409 : 1172 : fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
410 : 1172 : debug("matching key found: file %s, line %lu %s %s",
411 : : file, linenum, key_type(found), fp);
412 : 1172 : free(fp);
413 : 1194 : break;
414 : : }
415 : : }
416 [ + - ]: 1386 : if (found != NULL)
417 : 1386 : key_free(found);
418 [ + + ]: 1386 : if (!found_key)
419 : 98 : debug2("key not found");
420 : 1386 : return found_key;
421 : : }
422 : :
423 : : /* Authenticate a certificate key against TrustedUserCAKeys */
424 : : static int
425 : 1610 : user_cert_trusted_ca(struct passwd *pw, Key *key)
426 : : {
427 : 1610 : char *ca_fp, *principals_file = NULL;
428 : : const char *reason;
429 : 1610 : int ret = 0;
430 : :
431 [ + + ][ + + ]: 1610 : if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
432 : : return 0;
433 : :
434 : 176 : ca_fp = key_fingerprint(key->cert->signature_key,
435 : : SSH_FP_MD5, SSH_FP_HEX);
436 : :
437 [ - + ]: 176 : if (key_in_file(key->cert->signature_key,
438 : 176 : options.trusted_user_ca_keys, 1) != 1) {
439 : 0 : debug2("%s: CA %s %s is not listed in %s", __func__,
440 : 0 : key_type(key->cert->signature_key), ca_fp,
441 : : options.trusted_user_ca_keys);
442 : 0 : goto out;
443 : : }
444 : : /*
445 : : * If AuthorizedPrincipals is in use, then compare the certificate
446 : : * principals against the names in that file rather than matching
447 : : * against the username.
448 : : */
449 [ + + ]: 176 : if ((principals_file = authorized_principals_file(pw)) != NULL) {
450 [ - + ]: 100 : if (!match_principals_file(principals_file, pw, key->cert)) {
451 : 0 : reason = "Certificate does not contain an "
452 : : "authorized principal";
453 : : fail_reason:
454 : 0 : error("%s", reason);
455 : 0 : auth_debug_add("%s", reason);
456 : 0 : goto out;
457 : : }
458 : : }
459 [ + + ][ - + ]: 176 : if (key_cert_check_authority(key, 0, 1,
460 : : principals_file == NULL ? pw->pw_name : NULL, &reason) != 0)
461 : : goto fail_reason;
462 [ + - ]: 176 : if (auth_cert_options(key, pw) != 0)
463 : : goto out;
464 : :
465 : 176 : verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s",
466 : 352 : key->cert->key_id, key_type(key->cert->signature_key), ca_fp,
467 : : options.trusted_user_ca_keys);
468 : 176 : ret = 1;
469 : :
470 : : out:
471 : 176 : free(principals_file);
472 : 176 : free(ca_fp);
473 : 176 : return ret;
474 : : }
475 : :
476 : : /*
477 : : * Checks whether key is allowed in file.
478 : : * returns 1 if the key is allowed or 0 otherwise.
479 : : */
480 : : static int
481 : 1438 : user_key_allowed2(struct passwd *pw, Key *key, char *file)
482 : : {
483 : : FILE *f;
484 : 1438 : int found_key = 0;
485 : :
486 : : /* Temporarily use the user's uid. */
487 : 1438 : temporarily_use_uid(pw);
488 : :
489 : 1438 : debug("trying public key file %s", file);
490 [ + + ]: 1438 : if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
491 : 1386 : found_key = check_authkeys_file(f, file, key, pw);
492 : 1386 : fclose(f);
493 : : }
494 : :
495 : 1438 : restore_uid();
496 : 1438 : return found_key;
497 : : }
498 : :
499 : : /*
500 : : * Checks whether key is allowed in output of command.
501 : : * returns 1 if the key is allowed or 0 otherwise.
502 : : */
503 : : static int
504 : 1434 : user_key_command_allowed2(struct passwd *user_pw, Key *key)
505 : : {
506 : : FILE *f;
507 : 1434 : int ok, found_key = 0;
508 : : struct passwd *pw;
509 : : struct stat st;
510 : : int status, devnull, p[2], i;
511 : : pid_t pid;
512 : : char *username, errmsg[512];
513 : :
514 [ - + ][ # # ]: 1434 : if (options.authorized_keys_command == NULL ||
515 : 0 : options.authorized_keys_command[0] != '/')
516 : : return 0;
517 : :
518 [ # # ]: 0 : if (options.authorized_keys_command_user == NULL) {
519 : 0 : error("No user for AuthorizedKeysCommand specified, skipping");
520 : : return 0;
521 : : }
522 : :
523 : 0 : username = percent_expand(options.authorized_keys_command_user,
524 : : "u", user_pw->pw_name, (char *)NULL);
525 : 0 : pw = getpwnam(username);
526 [ # # ]: 0 : if (pw == NULL) {
527 : 0 : error("AuthorizedKeysCommandUser \"%s\" not found: %s",
528 : 0 : username, strerror(errno));
529 : 0 : free(username);
530 : : return 0;
531 : : }
532 : 0 : free(username);
533 : :
534 : 0 : temporarily_use_uid(pw);
535 : :
536 [ # # ]: 0 : if (stat(options.authorized_keys_command, &st) < 0) {
537 : 0 : error("Could not stat AuthorizedKeysCommand \"%s\": %s",
538 : 0 : options.authorized_keys_command, strerror(errno));
539 : : goto out;
540 : : }
541 [ # # ]: 0 : if (auth_secure_path(options.authorized_keys_command, &st, NULL, 0,
542 : : errmsg, sizeof(errmsg)) != 0) {
543 : 0 : error("Unsafe AuthorizedKeysCommand: %s", errmsg);
544 : : goto out;
545 : : }
546 : :
547 [ # # ]: 0 : if (pipe(p) != 0) {
548 : 0 : error("%s: pipe: %s", __func__, strerror(errno));
549 : : goto out;
550 : : }
551 : :
552 : 0 : debug3("Running AuthorizedKeysCommand: \"%s %s\" as \"%s\"",
553 : : options.authorized_keys_command, user_pw->pw_name, pw->pw_name);
554 : :
555 : : /*
556 : : * Don't want to call this in the child, where it can fatal() and
557 : : * run cleanup_exit() code.
558 : : */
559 : 0 : restore_uid();
560 : :
561 [ # # # ]: 0 : switch ((pid = fork())) {
562 : : case -1: /* error */
563 : 0 : error("%s: fork: %s", __func__, strerror(errno));
564 : 0 : close(p[0]);
565 : 0 : close(p[1]);
566 : : return 0;
567 : : case 0: /* child */
568 [ # # ]: 0 : for (i = 0; i < NSIG; i++)
569 : 0 : signal(i, SIG_DFL);
570 : :
571 [ # # ]: 0 : if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
572 : 0 : error("%s: open %s: %s", __func__, _PATH_DEVNULL,
573 : 0 : strerror(errno));
574 : 0 : _exit(1);
575 : : }
576 : : /* Keep stderr around a while longer to catch errors */
577 [ # # # # ]: 0 : if (dup2(devnull, STDIN_FILENO) == -1 ||
578 : 0 : dup2(p[1], STDOUT_FILENO) == -1) {
579 : 0 : error("%s: dup2: %s", __func__, strerror(errno));
580 : 0 : _exit(1);
581 : : }
582 : 0 : closefrom(STDERR_FILENO + 1);
583 : :
584 : : /* Don't use permanently_set_uid() here to avoid fatal() */
585 [ # # ]: 0 : if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
586 : 0 : error("setresgid %u: %s", (u_int)pw->pw_gid,
587 : 0 : strerror(errno));
588 : 0 : _exit(1);
589 : : }
590 [ # # ]: 0 : if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
591 : 0 : error("setresuid %u: %s", (u_int)pw->pw_uid,
592 : 0 : strerror(errno));
593 : 0 : _exit(1);
594 : : }
595 : : /* stdin is pointed to /dev/null at this point */
596 [ # # ]: 0 : if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
597 : 0 : error("%s: dup2: %s", __func__, strerror(errno));
598 : 0 : _exit(1);
599 : : }
600 : :
601 : 0 : execl(options.authorized_keys_command,
602 : : options.authorized_keys_command, user_pw->pw_name, NULL);
603 : :
604 : 0 : error("AuthorizedKeysCommand %s exec failed: %s",
605 : 0 : options.authorized_keys_command, strerror(errno));
606 : 0 : _exit(127);
607 : : default: /* parent */
608 : : break;
609 : : }
610 : :
611 : 0 : temporarily_use_uid(pw);
612 : :
613 : 0 : close(p[1]);
614 [ # # ]: 0 : if ((f = fdopen(p[0], "r")) == NULL) {
615 : 0 : error("%s: fdopen: %s", __func__, strerror(errno));
616 : 0 : close(p[0]);
617 : : /* Don't leave zombie child */
618 : 0 : kill(pid, SIGTERM);
619 [ # # ][ # # ]: 0 : while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
620 : : ;
621 : : goto out;
622 : : }
623 : 0 : ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
624 : 0 : fclose(f);
625 : :
626 [ # # ]: 0 : while (waitpid(pid, &status, 0) == -1) {
627 [ # # ]: 0 : if (errno != EINTR) {
628 : 0 : error("%s: waitpid: %s", __func__, strerror(errno));
629 : : goto out;
630 : : }
631 : : }
632 [ # # ]: 0 : if (WIFSIGNALED(status)) {
633 : 0 : error("AuthorizedKeysCommand %s exited on signal %d",
634 : 0 : options.authorized_keys_command, WTERMSIG(status));
635 : : goto out;
636 [ # # ]: 0 : } else if (WEXITSTATUS(status) != 0) {
637 : 0 : error("AuthorizedKeysCommand %s returned status %d",
638 : 0 : options.authorized_keys_command, WEXITSTATUS(status));
639 : : goto out;
640 : : }
641 : : found_key = ok;
642 : : out:
643 : 0 : restore_uid();
644 : : return found_key;
645 : : }
646 : :
647 : : /*
648 : : * Check whether key authenticates and authorises the user.
649 : : */
650 : : int
651 : 1610 : user_key_allowed(struct passwd *pw, Key *key)
652 : : {
653 : : u_int success, i;
654 : : char *file;
655 : :
656 [ + - ]: 1610 : if (auth_key_is_revoked(key))
657 : : return 0;
658 [ + + ][ + - ]: 1610 : if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
659 : : return 0;
660 : :
661 : 1610 : success = user_cert_trusted_ca(pw, key);
662 [ + + ]: 1610 : if (success)
663 : : return success;
664 : :
665 : 1434 : success = user_key_command_allowed2(pw, key);
666 [ + - ]: 1434 : if (success > 0)
667 : : return success;
668 : :
669 [ + + ][ + + ]: 2872 : for (i = 0; !success && i < options.num_authkeys_files; i++) {
670 : :
671 [ - + ]: 1438 : if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
672 : 0 : continue;
673 : 1438 : file = expand_authorized_keys(
674 : : options.authorized_keys_files[i], pw);
675 : :
676 : 1438 : success = user_key_allowed2(pw, key, file);
677 : 1438 : free(file);
678 : : }
679 : :
680 : 1434 : return success;
681 : : }
682 : :
683 : : Authmethod method_pubkey = {
684 : : "publickey",
685 : : userauth_pubkey,
686 : : &options.pubkey_authentication
687 : : };
|