diff options
Diffstat (limited to 'ssh-agent.c')
-rw-r--r-- | ssh-agent.c | 80 |
1 files changed, 58 insertions, 22 deletions
diff --git a/ssh-agent.c b/ssh-agent.c index aeda656ac..34b19b754 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-agent.c,v 1.199 2015/03/04 21:12:59 djm Exp $ */ | 1 | /* $OpenBSD: ssh-agent.c,v 1.203 2015/05/15 05:44:21 dtucker Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -68,6 +68,9 @@ | |||
68 | #include <time.h> | 68 | #include <time.h> |
69 | #include <string.h> | 69 | #include <string.h> |
70 | #include <unistd.h> | 70 | #include <unistd.h> |
71 | #ifdef HAVE_UTIL_H | ||
72 | # include <util.h> | ||
73 | #endif | ||
71 | 74 | ||
72 | #include "key.h" /* XXX for typedef */ | 75 | #include "key.h" /* XXX for typedef */ |
73 | #include "buffer.h" /* XXX for typedef */ | 76 | #include "buffer.h" /* XXX for typedef */ |
@@ -140,8 +143,12 @@ char socket_name[PATH_MAX]; | |||
140 | char socket_dir[PATH_MAX]; | 143 | char socket_dir[PATH_MAX]; |
141 | 144 | ||
142 | /* locking */ | 145 | /* locking */ |
146 | #define LOCK_SIZE 32 | ||
147 | #define LOCK_SALT_SIZE 16 | ||
148 | #define LOCK_ROUNDS 1 | ||
143 | int locked = 0; | 149 | int locked = 0; |
144 | char *lock_passwd = NULL; | 150 | char lock_passwd[LOCK_SIZE]; |
151 | char lock_salt[LOCK_SALT_SIZE]; | ||
145 | 152 | ||
146 | extern char *__progname; | 153 | extern char *__progname; |
147 | 154 | ||
@@ -660,23 +667,45 @@ send: | |||
660 | static void | 667 | static void |
661 | process_lock_agent(SocketEntry *e, int lock) | 668 | process_lock_agent(SocketEntry *e, int lock) |
662 | { | 669 | { |
663 | int r, success = 0; | 670 | int r, success = 0, delay; |
664 | char *passwd; | 671 | char *passwd, passwdhash[LOCK_SIZE]; |
672 | static u_int fail_count = 0; | ||
673 | size_t pwlen; | ||
665 | 674 | ||
666 | if ((r = sshbuf_get_cstring(e->request, &passwd, NULL)) != 0) | 675 | if ((r = sshbuf_get_cstring(e->request, &passwd, &pwlen)) != 0) |
667 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | 676 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
668 | if (locked && !lock && strcmp(passwd, lock_passwd) == 0) { | 677 | if (pwlen == 0) { |
669 | locked = 0; | 678 | debug("empty password not supported"); |
670 | explicit_bzero(lock_passwd, strlen(lock_passwd)); | 679 | } else if (locked && !lock) { |
671 | free(lock_passwd); | 680 | if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt), |
672 | lock_passwd = NULL; | 681 | passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0) |
673 | success = 1; | 682 | fatal("bcrypt_pbkdf"); |
683 | if (timingsafe_bcmp(passwdhash, lock_passwd, LOCK_SIZE) == 0) { | ||
684 | debug("agent unlocked"); | ||
685 | locked = 0; | ||
686 | fail_count = 0; | ||
687 | explicit_bzero(lock_passwd, sizeof(lock_passwd)); | ||
688 | success = 1; | ||
689 | } else { | ||
690 | /* delay in 0.1s increments up to 10s */ | ||
691 | if (fail_count < 100) | ||
692 | fail_count++; | ||
693 | delay = 100000 * fail_count; | ||
694 | debug("unlock failed, delaying %0.1lf seconds", | ||
695 | (double)delay/1000000); | ||
696 | usleep(delay); | ||
697 | } | ||
698 | explicit_bzero(passwdhash, sizeof(passwdhash)); | ||
674 | } else if (!locked && lock) { | 699 | } else if (!locked && lock) { |
700 | debug("agent locked"); | ||
675 | locked = 1; | 701 | locked = 1; |
676 | lock_passwd = xstrdup(passwd); | 702 | arc4random_buf(lock_salt, sizeof(lock_salt)); |
703 | if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt), | ||
704 | lock_passwd, sizeof(lock_passwd), LOCK_ROUNDS) < 0) | ||
705 | fatal("bcrypt_pbkdf"); | ||
677 | success = 1; | 706 | success = 1; |
678 | } | 707 | } |
679 | explicit_bzero(passwd, strlen(passwd)); | 708 | explicit_bzero(passwd, pwlen); |
680 | free(passwd); | 709 | free(passwd); |
681 | send_status(e, success); | 710 | send_status(e, success); |
682 | } | 711 | } |
@@ -929,7 +958,7 @@ new_socket(sock_type type, int fd) | |||
929 | } | 958 | } |
930 | old_alloc = sockets_alloc; | 959 | old_alloc = sockets_alloc; |
931 | new_alloc = sockets_alloc + 10; | 960 | new_alloc = sockets_alloc + 10; |
932 | sockets = xrealloc(sockets, new_alloc, sizeof(sockets[0])); | 961 | sockets = xreallocarray(sockets, new_alloc, sizeof(sockets[0])); |
933 | for (i = old_alloc; i < new_alloc; i++) | 962 | for (i = old_alloc; i < new_alloc; i++) |
934 | sockets[i].type = AUTH_UNUSED; | 963 | sockets[i].type = AUTH_UNUSED; |
935 | sockets_alloc = new_alloc; | 964 | sockets_alloc = new_alloc; |
@@ -1137,7 +1166,7 @@ static void | |||
1137 | usage(void) | 1166 | usage(void) |
1138 | { | 1167 | { |
1139 | fprintf(stderr, | 1168 | fprintf(stderr, |
1140 | "usage: ssh-agent [-c | -s] [-d] [-a bind_address] [-E fingerprint_hash]\n" | 1169 | "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n" |
1141 | " [-t life] [command [arg ...]]\n" | 1170 | " [-t life] [command [arg ...]]\n" |
1142 | " ssh-agent [-c | -s] -k\n"); | 1171 | " ssh-agent [-c | -s] -k\n"); |
1143 | exit(1); | 1172 | exit(1); |
@@ -1146,7 +1175,7 @@ usage(void) | |||
1146 | int | 1175 | int |
1147 | main(int ac, char **av) | 1176 | main(int ac, char **av) |
1148 | { | 1177 | { |
1149 | int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0; | 1178 | int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0; |
1150 | int sock, fd, ch, result, saved_errno; | 1179 | int sock, fd, ch, result, saved_errno; |
1151 | u_int nalloc; | 1180 | u_int nalloc; |
1152 | char *shell, *format, *pidstr, *agentsocket = NULL; | 1181 | char *shell, *format, *pidstr, *agentsocket = NULL; |
@@ -1181,7 +1210,7 @@ main(int ac, char **av) | |||
1181 | __progname = ssh_get_progname(av[0]); | 1210 | __progname = ssh_get_progname(av[0]); |
1182 | seed_rng(); | 1211 | seed_rng(); |
1183 | 1212 | ||
1184 | while ((ch = getopt(ac, av, "cdksE:a:t:")) != -1) { | 1213 | while ((ch = getopt(ac, av, "cDdksE:a:t:")) != -1) { |
1185 | switch (ch) { | 1214 | switch (ch) { |
1186 | case 'E': | 1215 | case 'E': |
1187 | fingerprint_hash = ssh_digest_alg_by_name(optarg); | 1216 | fingerprint_hash = ssh_digest_alg_by_name(optarg); |
@@ -1202,10 +1231,15 @@ main(int ac, char **av) | |||
1202 | s_flag++; | 1231 | s_flag++; |
1203 | break; | 1232 | break; |
1204 | case 'd': | 1233 | case 'd': |
1205 | if (d_flag) | 1234 | if (d_flag || D_flag) |
1206 | usage(); | 1235 | usage(); |
1207 | d_flag++; | 1236 | d_flag++; |
1208 | break; | 1237 | break; |
1238 | case 'D': | ||
1239 | if (d_flag || D_flag) | ||
1240 | usage(); | ||
1241 | D_flag++; | ||
1242 | break; | ||
1209 | case 'a': | 1243 | case 'a': |
1210 | agentsocket = optarg; | 1244 | agentsocket = optarg; |
1211 | break; | 1245 | break; |
@@ -1222,7 +1256,7 @@ main(int ac, char **av) | |||
1222 | ac -= optind; | 1256 | ac -= optind; |
1223 | av += optind; | 1257 | av += optind; |
1224 | 1258 | ||
1225 | if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) | 1259 | if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag)) |
1226 | usage(); | 1260 | usage(); |
1227 | 1261 | ||
1228 | if (ac == 0 && !c_flag && !s_flag) { | 1262 | if (ac == 0 && !c_flag && !s_flag) { |
@@ -1291,8 +1325,10 @@ main(int ac, char **av) | |||
1291 | * Fork, and have the parent execute the command, if any, or present | 1325 | * Fork, and have the parent execute the command, if any, or present |
1292 | * the socket data. The child continues as the authentication agent. | 1326 | * the socket data. The child continues as the authentication agent. |
1293 | */ | 1327 | */ |
1294 | if (d_flag) { | 1328 | if (D_flag || d_flag) { |
1295 | log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1); | 1329 | log_init(__progname, |
1330 | d_flag ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO, | ||
1331 | SYSLOG_FACILITY_AUTH, 1); | ||
1296 | format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; | 1332 | format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; |
1297 | printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, | 1333 | printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, |
1298 | SSH_AUTHSOCKET_ENV_NAME); | 1334 | SSH_AUTHSOCKET_ENV_NAME); |
@@ -1364,7 +1400,7 @@ skip: | |||
1364 | parent_alive_interval = 10; | 1400 | parent_alive_interval = 10; |
1365 | idtab_init(); | 1401 | idtab_init(); |
1366 | signal(SIGPIPE, SIG_IGN); | 1402 | signal(SIGPIPE, SIG_IGN); |
1367 | signal(SIGINT, d_flag ? cleanup_handler : SIG_IGN); | 1403 | signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN); |
1368 | signal(SIGHUP, cleanup_handler); | 1404 | signal(SIGHUP, cleanup_handler); |
1369 | signal(SIGTERM, cleanup_handler); | 1405 | signal(SIGTERM, cleanup_handler); |
1370 | nalloc = 0; | 1406 | nalloc = 0; |