View | Details | Raw Unified | Return to bug 2081 | Differences between
and this patch

Collapse All | Expand All

(-)a/auth2-pubkey.c (-21 / +171 lines)
Lines 62-67 Link Here
62
#include "monitor_wrap.h"
62
#include "monitor_wrap.h"
63
#include "authfile.h"
63
#include "authfile.h"
64
#include "match.h"
64
#include "match.h"
65
#include "ssherr.h"
66
#include "channels.h" /* XXX for session.h */
67
#include "session.h" /* XXX for child_set_env(); refactor? */
65
68
66
/* import */
69
/* import */
67
extern ServerOptions options;
70
extern ServerOptions options;
Lines 517-522 user_key_allowed2(struct passwd *pw, Key *key, char *file) Link Here
517
}
520
}
518
521
519
/*
522
/*
523
 * Splits 's' into an argument vector. Handles quoted string, basic escape
524
 * characters (\\, \", \'), but not nested quotes. Caller must free the
525
 * argument vector and its members.
526
 */
527
static int
528
split_argv(const char *s, int *argcp, char ***argvp)
529
{
530
	int r = SSH_ERR_INTERNAL_ERROR;
531
	int argc = 0, quote, i, j;
532
	char *arg, **argv = xcalloc(1, sizeof(*argv));
533
534
	*argvp = NULL;
535
	*argcp = 0;
536
537
	for (i = 0; s[i] != '\0'; i++) {
538
		/* Skip leading whitespace */
539
		if (s[i] == ' ' || s[i] == '\t')
540
			continue;
541
542
		/* Start of a token */
543
		quote = 0;
544
		if (s[i] == '\\' &&
545
		    (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
546
			i++;
547
		else if (s[i] == '\'' || s[i] == '"')
548
			quote = s[i++];
549
550
		argv = xrealloc(argv, (argc + 2), sizeof(*argv));
551
		arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
552
		argv[argc] = NULL;
553
554
		/* Copy the token in, removing escapes */
555
		for (j = 0; s[i] != '\0'; i++) {
556
			if (s[i] == '\\') {
557
				if (s[i + 1] == '\'' ||
558
				    s[i + 1] == '\"' ||
559
				    s[i + 1] == '\\') {
560
					i++; /* Skip '\' */
561
					arg[j++] = s[i];
562
				} else {
563
					/* Unrecognised escape */
564
					arg[j++] = s[i];
565
				}
566
			} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
567
				break; /* done */
568
			else if (quote != 0 && s[i] == quote)
569
				break; /* done */
570
			else
571
				arg[j++] = s[i];
572
		}
573
		if (s[i] == '\0') {
574
			if (quote != 0) {
575
				/* Ran out of string looking for close quote */
576
				r = SSH_ERR_INVALID_FORMAT;
577
				goto out;
578
			}
579
			break;
580
		}
581
	}
582
	/* Success */
583
	*argcp = argc;
584
	*argvp = argv;
585
	argc = 0;
586
	argv = NULL;
587
	r = 0;
588
 out:
589
	if (argc != 0 && argv != NULL) {
590
		for (i = 0; i < argc; i++)
591
			free(argv[i]);
592
		free(argv);
593
	}
594
	return r;
595
}
596
/*
520
 * Checks whether key is allowed in output of command.
597
 * Checks whether key is allowed in output of command.
521
 * returns 1 if the key is allowed or 0 otherwise.
598
 * returns 1 if the key is allowed or 0 otherwise.
522
 */
599
 */
Lines 524-576 static int Link Here
524
user_key_command_allowed2(struct passwd *user_pw, Key *key)
601
user_key_command_allowed2(struct passwd *user_pw, Key *key)
525
{
602
{
526
	FILE *f;
603
	FILE *f;
527
	int ok, found_key = 0;
604
	int r, ok, found_key = 0;
528
	struct passwd *pw;
605
	struct passwd *pw;
529
	struct stat st;
606
	struct stat st;
530
	int status, devnull, p[2], i;
607
	int status, devnull, p[3], i, ac = 0;
531
	pid_t pid;
608
	pid_t pid;
532
	char *username, errmsg[512];
609
	char *username = NULL, *key_fp = NULL, *keytext = NULL;
610
	char *command = NULL, **av = NULL, *cp, errmsg[512];
611
	u_int envsize;
612
	char **child_env;
613
	void (*osigchld)(int);
533
614
534
	if (options.authorized_keys_command == NULL ||
615
	if (options.authorized_keys_command == NULL)
535
	    options.authorized_keys_command[0] != '/')
536
		return 0;
616
		return 0;
537
538
	if (options.authorized_keys_command_user == NULL) {
617
	if (options.authorized_keys_command_user == NULL) {
539
		error("No user for AuthorizedKeysCommand specified, skipping");
618
		error("No user for AuthorizedKeysCommand specified, skipping");
540
		return 0;
619
		return 0;
541
	}
620
	}
542
621
622
	/*
623
	 * NB. all returns later this function should go via "out" to
624
	 * ensure the original SIGCHLD handler is restored properly.
625
	 */
626
	osigchld = signal(SIGCHLD, SIG_DFL);
627
628
	/* Prepare and verify the user for the command */
543
	username = percent_expand(options.authorized_keys_command_user,
629
	username = percent_expand(options.authorized_keys_command_user,
544
	    "u", user_pw->pw_name, (char *)NULL);
630
	    "u", user_pw->pw_name, (char *)NULL);
545
	pw = getpwnam(username);
631
	pw = getpwnam(username);
546
	if (pw == NULL) {
632
	if (pw == NULL) {
547
		error("AuthorizedKeysCommandUser \"%s\" not found: %s",
633
		error("AuthorizedKeysCommandUser \"%s\" not found: %s",
548
		    username, strerror(errno));
634
		    username, strerror(errno));
549
		free(username);
635
		goto out;
550
		return 0;
551
	}
636
	}
552
	free(username);
553
637
638
	/* Prepare AuthorizedKeysCommand */
639
	if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash,
640
	    SSH_FP_DEFAULT)) == NULL) {
641
		error("%s: sshkey_fingerprint failed", __func__);
642
		goto out;
643
	}
644
	if ((r = sshkey_to_base64(key, &keytext)) != 0) {
645
		error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
646
		goto out;
647
	}
648
	command = percent_expand(options.authorized_keys_command,
649
	    "u", user_pw->pw_name, "h", user_pw->pw_dir,
650
	    "t", sshkey_ssh_name(key), "f", key_fp, "k", keytext, (char *)NULL);
651
652
	/* Turn the command into an argument vector */
653
	if (split_argv(command, &ac, &av) != 0) {
654
		error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
655
		    command);
656
		goto out;
657
	}
658
	if (ac == 0) {
659
		error("AuthorizedKeysCommand \"%s\" yielded no arguments",
660
		    command);
661
		goto out;
662
	}
663
664
	/*
665
	 * If AuthorizedKeysCommand was run without arguments
666
	 * then fall back to the old behaviour of passing the
667
	 * target username as a single argument.
668
	 */
669
	if (ac == 1) {
670
		av = xrealloc(av, ac + 2, sizeof(*av));
671
		av[1] = xstrdup(user_pw->pw_name);
672
		av[2] = NULL;
673
		/* Fix up command too, since it is used in log messages */
674
		free(command);
675
		xasprintf(&command, "%s %s",
676
		    options.authorized_keys_command, user_pw->pw_name);
677
	}
678
679
	/* Verify the path exists and is safe-ish to execute */
680
	if (*av[0] != '/') {
681
		error("AuthorizedKeysCommand path is not absolute");
682
		goto out;
683
	}
554
	temporarily_use_uid(pw);
684
	temporarily_use_uid(pw);
555
685
	if (stat(av[0], &st) < 0) {
556
	if (stat(options.authorized_keys_command, &st) < 0) {
557
		error("Could not stat AuthorizedKeysCommand \"%s\": %s",
686
		error("Could not stat AuthorizedKeysCommand \"%s\": %s",
558
		    options.authorized_keys_command, strerror(errno));
687
		    av[0], strerror(errno));
559
		goto out;
688
		goto out;
560
	}
689
	}
561
	if (auth_secure_path(options.authorized_keys_command, &st, NULL, 0,
690
	if (auth_secure_path(av[0], &st, NULL, 0,
562
	    errmsg, sizeof(errmsg)) != 0) {
691
	    errmsg, sizeof(errmsg)) != 0) {
563
		error("Unsafe AuthorizedKeysCommand: %s", errmsg);
692
		error("Unsafe AuthorizedKeysCommand \"%s\": %s", av[0], errmsg);
564
		goto out;
693
		goto out;
565
	}
694
	}
566
695
696
	/*
697
	 * Run the command; stderr is left in place, stdout is the
698
	 * authorized_keys output.
699
	 */
567
	if (pipe(p) != 0) {
700
	if (pipe(p) != 0) {
568
		error("%s: pipe: %s", __func__, strerror(errno));
701
		error("%s: pipe: %s", __func__, strerror(errno));
569
		goto out;
702
		goto out;
570
	}
703
	}
571
704
572
	debug3("Running AuthorizedKeysCommand: \"%s %s\" as \"%s\"",
705
	debug3("Running AuthorizedKeysCommand: \"%s\" as \"%s\"",
573
	    options.authorized_keys_command, user_pw->pw_name, pw->pw_name);
706
	    command, pw->pw_name);
574
707
575
	/*
708
	/*
576
	 * Don't want to call this in the child, where it can fatal() and
709
	 * Don't want to call this in the child, where it can fatal() and
Lines 585-590 user_key_command_allowed2(struct passwd *user_pw, Key *key) Link Here
585
		close(p[1]);
718
		close(p[1]);
586
		return 0;
719
		return 0;
587
	case 0: /* child */
720
	case 0: /* child */
721
		/* Prepare a minimal environment for the child. */
722
		envsize = 5;
723
		child_env = xcalloc(sizeof(*child_env), envsize);
724
		child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
725
		child_set_env(&child_env, &envsize, "USER", pw->pw_name);
726
		child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
727
		child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
728
		if ((cp = getenv("LANG")) != NULL)
729
			child_set_env(&child_env, &envsize, "LANG", cp);
730
588
		for (i = 0; i < NSIG; i++)
731
		for (i = 0; i < NSIG; i++)
589
			signal(i, SIG_DFL);
732
			signal(i, SIG_DFL);
590
733
Lines 618-628 user_key_command_allowed2(struct passwd *user_pw, Key *key) Link Here
618
			_exit(1);
761
			_exit(1);
619
		}
762
		}
620
763
621
		execl(options.authorized_keys_command,
764
		execve(av[0], av, child_env);
622
		    options.authorized_keys_command, user_pw->pw_name, NULL);
765
		error("AuthorizedKeysCommand exec \"%s\" failed: %s",
623
766
		    command, strerror(errno));
624
		error("AuthorizedKeysCommand %s exec failed: %s",
625
		    options.authorized_keys_command, strerror(errno));
626
		_exit(127);
767
		_exit(127);
627
	default: /* parent */
768
	default: /* parent */
628
		break;
769
		break;
Lines 658-666 user_key_command_allowed2(struct passwd *user_pw, Key *key) Link Here
658
		    options.authorized_keys_command, WEXITSTATUS(status));
799
		    options.authorized_keys_command, WEXITSTATUS(status));
659
		goto out;
800
		goto out;
660
	}
801
	}
802
	/* Read completed successfully */
661
	found_key = ok;
803
	found_key = ok;
662
 out:
804
 out:
805
	signal(SIGCHLD, osigchld);
806
	for (i = 0; i < ac; i++)
807
		free(av[i]);
808
	free(av);
663
	restore_uid();
809
	restore_uid();
810
	free(command);
811
	free(username);
812
	free(key_fp);
813
	free(keytext);
664
	return found_key;
814
	return found_key;
665
}
815
}
666
816
(-)a/sshd_config.5 (-3 / +15 lines)
Lines 230-238 The default is not to require multiple authentication; successful completion Link Here
230
of a single authentication method is sufficient.
230
of a single authentication method is sufficient.
231
.It Cm AuthorizedKeysCommand
231
.It Cm AuthorizedKeysCommand
232
Specifies a program to be used to look up the user's public keys.
232
Specifies a program to be used to look up the user's public keys.
233
The program must be owned by root and not writable by group or others.
233
The program must be owned by root, not writable by group or others and
234
It will be invoked with a single argument of the username
234
specified by an absolute path.
235
being authenticated, and should produce on standard output zero or
235
.Pp
236
Arguments to
237
.Cm AuthorizedKeysCommand
238
may be provided using the following tokens, which will be expanded
239
at runtime: %% is replaced by a literal '%', %u is replaced by the
240
username being authenticated, %h is replaced by the home directory
241
of the user being authenticated, %t is replaced with the key type
242
offered for authentication, %f is replaced with the fingerprint of
243
the key, and %k is replaced with the key being offered for authentication.
244
If no arguments are specified then the username of the target user
245
will be supplied.
246
.Pp
247
The program should produce on standard output zero or
236
more lines of authorized_keys output (see AUTHORIZED_KEYS in
248
more lines of authorized_keys output (see AUTHORIZED_KEYS in
237
.Xr sshd 8 ) .
249
.Xr sshd 8 ) .
238
If a key supplied by AuthorizedKeysCommand does not successfully authenticate
250
If a key supplied by AuthorizedKeysCommand does not successfully authenticate
(-)a/sshkey.c (-75 / +99 lines)
Lines 737-742 to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain) Link Here
737
	if (key == NULL)
737
	if (key == NULL)
738
		return SSH_ERR_INVALID_ARGUMENT;
738
		return SSH_ERR_INVALID_ARGUMENT;
739
739
740
	if (sshkey_is_cert(key)) {
741
		if (key->cert == NULL)
742
			return SSH_ERR_EXPECTED_CERT;
743
		if (sshbuf_len(key->cert->certblob) == 0)
744
			return SSH_ERR_KEY_LACKS_CERTBLOB;
745
	}
740
	type = force_plain ? sshkey_type_plain(key->type) : key->type;
746
	type = force_plain ? sshkey_type_plain(key->type) : key->type;
741
	typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
747
	typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
742
748
Lines 1381-1478 sshkey_read(struct sshkey *ret, char **cpp) Link Here
1381
}
1387
}
1382
1388
1383
int
1389
int
1384
sshkey_write(const struct sshkey *key, FILE *f)
1390
sshkey_to_base64(const struct sshkey *key, char **b64p)
1385
{
1391
{
1386
	int ret = SSH_ERR_INTERNAL_ERROR;
1392
	int r = SSH_ERR_INTERNAL_ERROR;
1387
	struct sshbuf *b = NULL, *bb = NULL;
1393
	struct sshbuf *b = NULL;
1388
	char *uu = NULL;
1394
	char *uu = NULL;
1395
1396
	if (b64p != NULL)
1397
		*b64p = NULL;
1398
	if ((b = sshbuf_new()) == NULL)
1399
		return SSH_ERR_ALLOC_FAIL;
1400
	if ((r = sshkey_putb(key, b)) != 0)
1401
		goto out;
1402
	if ((uu = sshbuf_dtob64(b)) == NULL) {
1403
		r = SSH_ERR_ALLOC_FAIL;
1404
		goto out;
1405
	}
1406
	/* Success */
1407
	if (b64p != NULL) {
1408
		*b64p = uu;
1409
		uu = NULL;
1410
	}
1411
	r = 0;
1412
 out:
1413
	sshbuf_free(b);
1414
	free(uu);
1415
	return r;
1416
}
1417
1418
static int
1419
sshkey_format_rsa1(const struct sshkey *key, struct sshbuf *b)
1420
{
1421
	int r = SSH_ERR_INTERNAL_ERROR;
1389
#ifdef WITH_SSH1
1422
#ifdef WITH_SSH1
1390
	u_int bits = 0;
1423
	u_int bits = 0;
1391
	char *dec_e = NULL, *dec_n = NULL;
1424
	char *dec_e = NULL, *dec_n = NULL;
1392
#endif /* WITH_SSH1 */
1393
1425
1394
	if (sshkey_is_cert(key)) {
1426
	if (key->rsa == NULL || key->rsa->e == NULL ||
1395
		if (key->cert == NULL)
1427
	    key->rsa->n == NULL) {
1396
			return SSH_ERR_EXPECTED_CERT;
1428
		r = SSH_ERR_INVALID_ARGUMENT;
1397
		if (sshbuf_len(key->cert->certblob) == 0)
1429
		goto out;
1398
			return SSH_ERR_KEY_LACKS_CERTBLOB;
1399
	}
1430
	}
1400
	if ((b = sshbuf_new()) == NULL)
1431
	if ((dec_e = BN_bn2dec(key->rsa->e)) == NULL ||
1401
		return SSH_ERR_ALLOC_FAIL;
1432
	    (dec_n = BN_bn2dec(key->rsa->n)) == NULL) {
1402
	switch (key->type) {
1433
		r = SSH_ERR_ALLOC_FAIL;
1403
#ifdef WITH_SSH1
1404
	case KEY_RSA1:
1405
		if (key->rsa == NULL || key->rsa->e == NULL ||
1406
		    key->rsa->n == NULL) {
1407
			ret = SSH_ERR_INVALID_ARGUMENT;
1408
			goto out;
1409
		}
1410
		if ((dec_e = BN_bn2dec(key->rsa->e)) == NULL ||
1411
		    (dec_n = BN_bn2dec(key->rsa->n)) == NULL) {
1412
			ret = SSH_ERR_ALLOC_FAIL;
1413
			goto out;
1414
		}
1415
		/* size of modulus 'n' */
1416
		if ((bits = BN_num_bits(key->rsa->n)) <= 0) {
1417
			ret = SSH_ERR_INVALID_ARGUMENT;
1418
			goto out;
1419
		}
1420
		if ((ret = sshbuf_putf(b, "%u %s %s", bits, dec_e, dec_n)) != 0)
1421
			goto out;
1422
#endif /* WITH_SSH1 */
1423
		break;
1424
#ifdef WITH_OPENSSL
1425
	case KEY_DSA:
1426
	case KEY_DSA_CERT_V00:
1427
	case KEY_DSA_CERT:
1428
	case KEY_ECDSA:
1429
	case KEY_ECDSA_CERT:
1430
	case KEY_RSA:
1431
	case KEY_RSA_CERT_V00:
1432
	case KEY_RSA_CERT:
1433
#endif /* WITH_OPENSSL */
1434
	case KEY_ED25519:
1435
	case KEY_ED25519_CERT:
1436
		if ((bb = sshbuf_new()) == NULL) {
1437
			ret = SSH_ERR_ALLOC_FAIL;
1438
			goto out;
1439
		}
1440
		if ((ret = sshkey_putb(key, bb)) != 0)
1441
			goto out;
1442
		if ((uu = sshbuf_dtob64(bb)) == NULL) {
1443
			ret = SSH_ERR_ALLOC_FAIL;
1444
			goto out;
1445
		}
1446
		if ((ret = sshbuf_putf(b, "%s ", sshkey_ssh_name(key))) != 0)
1447
			goto out;
1448
		if ((ret = sshbuf_put(b, uu, strlen(uu))) != 0)
1449
			goto out;
1450
		break;
1451
	default:
1452
		ret = SSH_ERR_KEY_TYPE_UNKNOWN;
1453
		goto out;
1434
		goto out;
1454
	}
1435
	}
1455
	if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
1436
	/* size of modulus 'n' */
1456
		if (feof(f))
1437
	if ((bits = BN_num_bits(key->rsa->n)) <= 0) {
1457
			errno = EPIPE;
1438
		r = SSH_ERR_INVALID_ARGUMENT;
1458
		ret = SSH_ERR_SYSTEM_ERROR;
1459
		goto out;
1439
		goto out;
1460
	}
1440
	}
1461
	ret = 0;
1441
	if ((r = sshbuf_putf(b, "%u %s %s", bits, dec_e, dec_n)) != 0)
1442
		goto out;
1443
1444
	/* Success */
1445
	r = 0;
1462
 out:
1446
 out:
1463
	if (b != NULL)
1464
		sshbuf_free(b);
1465
	if (bb != NULL)
1466
		sshbuf_free(bb);
1467
	if (uu != NULL)
1468
		free(uu);
1469
#ifdef WITH_SSH1
1470
	if (dec_e != NULL)
1447
	if (dec_e != NULL)
1471
		OPENSSL_free(dec_e);
1448
		OPENSSL_free(dec_e);
1472
	if (dec_n != NULL)
1449
	if (dec_n != NULL)
1473
		OPENSSL_free(dec_n);
1450
		OPENSSL_free(dec_n);
1474
#endif /* WITH_SSH1 */
1451
#endif /* WITH_SSH1 */
1475
	return ret;
1452
1453
	return r;
1454
}
1455
1456
static int
1457
sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
1458
{
1459
	int r = SSH_ERR_INTERNAL_ERROR;
1460
	char *uu = NULL;
1461
1462
	if (key->type == KEY_RSA1) {
1463
		if ((r = sshkey_format_rsa1(key, b)) != 0)
1464
			goto out;
1465
	} else {
1466
		/* Unsupported key types handled in sshkey_to_base64() */
1467
		if ((r = sshkey_to_base64(key, &uu)) != 0)
1468
			goto out;
1469
		if ((r = sshbuf_putf(b, "%s %s",
1470
		    sshkey_ssh_name(key), uu)) != 0)
1471
			goto out;
1472
	}
1473
	r = 0;
1474
 out:
1475
	free(uu);
1476
	return r;
1477
}
1478
1479
int
1480
sshkey_write(const struct sshkey *key, FILE *f)
1481
{
1482
	struct sshbuf *b = NULL;
1483
	int r = SSH_ERR_INTERNAL_ERROR;
1484
1485
	if ((b = sshbuf_new()) == NULL)
1486
		return SSH_ERR_ALLOC_FAIL;
1487
	if ((r = sshkey_format_text(key, b)) != 0)
1488
		goto out;
1489
	if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
1490
		if (feof(f))
1491
			errno = EPIPE;
1492
		r = SSH_ERR_SYSTEM_ERROR;
1493
		goto out;
1494
	}
1495
	/* Success */
1496
	r = 0;
1497
 out:
1498
	sshbuf_free(b);
1499
	return r;
1476
}
1500
}
1477
1501
1478
const char *
1502
const char *
(-)a/sshkey.h (+1 lines)
Lines 157-162 int sshkey_from_blob(const u_char *, size_t, struct sshkey **); Link Here
157
int	 sshkey_fromb(struct sshbuf *, struct sshkey **);
157
int	 sshkey_fromb(struct sshbuf *, struct sshkey **);
158
int	 sshkey_froms(struct sshbuf *, struct sshkey **);
158
int	 sshkey_froms(struct sshbuf *, struct sshkey **);
159
int	 sshkey_to_blob(const struct sshkey *, u_char **, size_t *);
159
int	 sshkey_to_blob(const struct sshkey *, u_char **, size_t *);
160
int	 sshkey_to_base64(const struct sshkey *, char **);
160
int	 sshkey_putb(const struct sshkey *, struct sshbuf *);
161
int	 sshkey_putb(const struct sshkey *, struct sshbuf *);
161
int	 sshkey_puts(const struct sshkey *, struct sshbuf *);
162
int	 sshkey_puts(const struct sshkey *, struct sshbuf *);
162
int	 sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
163
int	 sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);

Return to bug 2081