blob: 2ef8367b94d18943b655475208520925dcd3662a [file] [log] [blame]
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +00001/* $OpenBSD: ssh-agent.c,v 1.221 2017/04/30 23:29:10 djm Exp $ */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002/*
Damien Miller95def091999-11-25 00:26:21 +11003 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
Damien Miller95def091999-11-25 00:26:21 +11006 * The authentication agent program.
Damien Millerad833b32000-08-23 10:46:23 +10007 *
Damien Millere4340be2000-09-16 13:29:08 +11008 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose. Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
13 *
Ben Lindstrom44697232001-07-04 03:32:30 +000014 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
Damien Millere4340be2000-09-16 13:29:08 +110015 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Damien Miller95def091999-11-25 00:26:21 +110035 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100036
37#include "includes.h"
Damien Miller574c41f2006-03-15 11:40:10 +110038
39#include <sys/types.h>
Damien Miller8dbffe72006-08-05 11:02:17 +100040#include <sys/param.h>
41#include <sys/resource.h>
Damien Miller42fb0682006-03-15 14:03:06 +110042#include <sys/stat.h>
Damien Millere3b60b52006-07-10 21:08:03 +100043#include <sys/socket.h>
Damien Miller9aec9192006-08-05 10:57:45 +100044#ifdef HAVE_SYS_TIME_H
45# include <sys/time.h>
46#endif
Damien Miller574c41f2006-03-15 11:40:10 +110047#ifdef HAVE_SYS_UN_H
48# include <sys/un.h>
49#endif
Damien Miller9b481512002-09-12 10:43:29 +100050#include "openbsd-compat/sys-queue.h"
Damien Millere3b60b52006-07-10 21:08:03 +100051
Damien Miller1f0311c2014-05-15 14:24:09 +100052#ifdef WITH_OPENSSL
Damien Millere3476ed2006-07-24 14:13:33 +100053#include <openssl/evp.h>
Darren Tuckerbfaaf962008-02-28 19:13:52 +110054#include "openbsd-compat/openssl-compat.h"
Damien Miller1f0311c2014-05-15 14:24:09 +100055#endif
Damien Millere3476ed2006-07-24 14:13:33 +100056
Darren Tucker39972492006-07-12 22:22:46 +100057#include <errno.h>
Damien Miller57cf6382006-07-10 21:13:46 +100058#include <fcntl.h>
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +000059#include <limits.h>
Damien Miller03e20032006-03-15 11:16:59 +110060#ifdef HAVE_PATHS_H
Damien Millera9263d02006-03-15 11:18:26 +110061# include <paths.h>
Damien Miller03e20032006-03-15 11:16:59 +110062#endif
Damien Miller6ff3cad2006-03-15 11:52:09 +110063#include <signal.h>
Damien Millerded319c2006-09-01 15:38:36 +100064#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100065#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100066#include <stdlib.h>
Damien Miller5598b4f2006-07-24 14:09:40 +100067#include <time.h>
Damien Millere3476ed2006-07-24 14:13:33 +100068#include <string.h>
Damien Millere6b3b612006-07-24 14:01:23 +100069#include <unistd.h>
Damien Millere97201f2015-05-21 17:55:15 +100070#ifdef HAVE_UTIL_H
71# include <util.h>
72#endif
Damien Miller6ff3cad2006-03-15 11:52:09 +110073
Damien Millerd7834352006-08-05 12:39:39 +100074#include "xmalloc.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100075#include "ssh.h"
76#include "rsa.h"
markus@openbsd.org139ca812015-01-14 13:09:09 +000077#include "sshbuf.h"
78#include "sshkey.h"
Damien Miller994cf142000-07-21 10:19:44 +100079#include "authfd.h"
Damien Miller62cee002000-09-23 17:15:56 +110080#include "compat.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000081#include "log.h"
Damien Miller6c711792003-01-24 11:36:23 +110082#include "misc.h"
Damien Miller4a1c7aa2014-02-04 11:03:36 +110083#include "digest.h"
markus@openbsd.org139ca812015-01-14 13:09:09 +000084#include "ssherr.h"
djm@openbsd.org786d5992016-11-30 03:07:37 +000085#include "match.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100086
Damien Miller7ea845e2010-02-12 09:21:02 +110087#ifdef ENABLE_PKCS11
88#include "ssh-pkcs11.h"
Ben Lindstrombcc18082001-08-06 21:59:25 +000089#endif
Ben Lindstrom3f471632001-07-04 03:53:15 +000090
djm@openbsd.org786d5992016-11-30 03:07:37 +000091#ifndef DEFAULT_PKCS11_WHITELIST
djm@openbsd.orgb108ce92017-01-04 02:21:43 +000092# define DEFAULT_PKCS11_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
djm@openbsd.org786d5992016-11-30 03:07:37 +000093#endif
94
Ben Lindstrom65366a82001-12-06 16:32:47 +000095typedef enum {
96 AUTH_UNUSED,
97 AUTH_SOCKET,
98 AUTH_CONNECTION
99} sock_type;
100
Damien Miller95def091999-11-25 00:26:21 +1100101typedef struct {
102 int fd;
Ben Lindstrom65366a82001-12-06 16:32:47 +0000103 sock_type type;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000104 struct sshbuf *input;
105 struct sshbuf *output;
106 struct sshbuf *request;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000107} SocketEntry;
108
Ben Lindstrom46c16222000-12-22 01:43:59 +0000109u_int sockets_alloc = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000110SocketEntry *sockets = NULL;
111
Damien Miller1a534ae2002-01-22 23:26:13 +1100112typedef struct identity {
113 TAILQ_ENTRY(identity) next;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000114 struct sshkey *key;
Damien Miller95def091999-11-25 00:26:21 +1100115 char *comment;
Damien Miller7ea845e2010-02-12 09:21:02 +1100116 char *provider;
Darren Tucker55119252013-06-02 07:43:59 +1000117 time_t death;
Damien Miller6c711792003-01-24 11:36:23 +1100118 u_int confirm;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000119} Identity;
120
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000121struct idtable {
Damien Millerad833b32000-08-23 10:46:23 +1000122 int nentries;
Damien Miller1a534ae2002-01-22 23:26:13 +1100123 TAILQ_HEAD(idqueue, identity) idlist;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000124};
Damien Millerad833b32000-08-23 10:46:23 +1000125
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000126/* private key table */
127struct idtable *idtab;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000128
129int max_fd = 0;
130
131/* pid of shell == parent of agent */
Damien Miller166fca82000-04-20 07:42:21 +1000132pid_t parent_pid = -1;
Darren Tucker073f7952013-06-02 23:47:11 +1000133time_t parent_alive_interval = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000134
Damien Millerb1e967c2014-07-03 21:22:40 +1000135/* pid of process for which cleanup_socket is applicable */
136pid_t cleanup_pid = 0;
137
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000138/* pathname and directory for AUTH_SOCKET */
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +0000139char socket_name[PATH_MAX];
140char socket_dir[PATH_MAX];
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000141
djm@openbsd.org786d5992016-11-30 03:07:37 +0000142/* PKCS#11 path whitelist */
143static char *pkcs11_whitelist;
144
Ben Lindstrom2f717042002-06-06 21:52:03 +0000145/* locking */
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000146#define LOCK_SIZE 32
147#define LOCK_SALT_SIZE 16
148#define LOCK_ROUNDS 1
Ben Lindstrom2f717042002-06-06 21:52:03 +0000149int locked = 0;
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000150u_char lock_pwhash[LOCK_SIZE];
151u_char lock_salt[LOCK_SALT_SIZE];
Ben Lindstrom2f717042002-06-06 21:52:03 +0000152
Damien Miller95def091999-11-25 00:26:21 +1100153extern char *__progname;
Damien Miller95def091999-11-25 00:26:21 +1100154
Darren Tucker55119252013-06-02 07:43:59 +1000155/* Default lifetime in seconds (0 == forever) */
156static long lifetime = 0;
Damien Miller53d81482003-01-22 11:47:19 +1100157
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000158static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
159
Ben Lindstrombba81212001-06-25 05:01:22 +0000160static void
Damien Miller58f34862002-09-04 16:31:21 +1000161close_socket(SocketEntry *e)
162{
Damien Miller58f34862002-09-04 16:31:21 +1000163 close(e->fd);
164 e->fd = -1;
165 e->type = AUTH_UNUSED;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000166 sshbuf_free(e->input);
167 sshbuf_free(e->output);
168 sshbuf_free(e->request);
Damien Miller58f34862002-09-04 16:31:21 +1000169}
170
171static void
Damien Millerad833b32000-08-23 10:46:23 +1000172idtab_init(void)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000173{
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000174 idtab = xcalloc(1, sizeof(*idtab));
175 TAILQ_INIT(&idtab->idlist);
176 idtab->nentries = 0;
Damien Millerad833b32000-08-23 10:46:23 +1000177}
178
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000179static void
180free_identity(Identity *id)
181{
markus@openbsd.org139ca812015-01-14 13:09:09 +0000182 sshkey_free(id->key);
Darren Tuckera627d422013-06-02 07:31:17 +1000183 free(id->provider);
184 free(id->comment);
185 free(id);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000186}
187
Damien Millerad833b32000-08-23 10:46:23 +1000188/* return matching private key for given public key */
Damien Miller1a534ae2002-01-22 23:26:13 +1100189static Identity *
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000190lookup_identity(struct sshkey *key)
Damien Millerad833b32000-08-23 10:46:23 +1000191{
Damien Miller1a534ae2002-01-22 23:26:13 +1100192 Identity *id;
193
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000194 TAILQ_FOREACH(id, &idtab->idlist, next) {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000195 if (sshkey_equal(key, id->key))
Damien Miller1a534ae2002-01-22 23:26:13 +1100196 return (id);
Damien Millerad833b32000-08-23 10:46:23 +1000197 }
Damien Miller1a534ae2002-01-22 23:26:13 +1100198 return (NULL);
199}
200
Damien Miller6c711792003-01-24 11:36:23 +1100201/* Check confirmation of keysign request */
202static int
203confirm_key(Identity *id)
204{
Darren Tuckerce327b62004-11-05 20:38:03 +1100205 char *p;
Damien Miller6c711792003-01-24 11:36:23 +1100206 int ret = -1;
207
markus@openbsd.org139ca812015-01-14 13:09:09 +0000208 p = sshkey_fingerprint(id->key, fingerprint_hash, SSH_FP_DEFAULT);
djm@openbsd.org9ce86c92015-01-28 22:36:00 +0000209 if (p != NULL &&
210 ask_permission("Allow use of key %s?\nKey fingerprint %s.",
Darren Tuckerce327b62004-11-05 20:38:03 +1100211 id->comment, p))
212 ret = 0;
Darren Tuckera627d422013-06-02 07:31:17 +1000213 free(p);
Darren Tuckerce327b62004-11-05 20:38:03 +1100214
Damien Miller6c711792003-01-24 11:36:23 +1100215 return (ret);
216}
217
markus@openbsd.org139ca812015-01-14 13:09:09 +0000218static void
219send_status(SocketEntry *e, int success)
220{
221 int r;
222
223 if ((r = sshbuf_put_u32(e->output, 1)) != 0 ||
224 (r = sshbuf_put_u8(e->output, success ?
225 SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0)
226 fatal("%s: buffer error: %s", __func__, ssh_err(r));
227}
228
Damien Millerad833b32000-08-23 10:46:23 +1000229/* send list of supported public keys to 'client' */
Ben Lindstrombba81212001-06-25 05:01:22 +0000230static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000231process_request_identities(SocketEntry *e)
Damien Millerad833b32000-08-23 10:46:23 +1000232{
Damien Miller1a534ae2002-01-22 23:26:13 +1100233 Identity *id;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000234 struct sshbuf *msg;
235 int r;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000236
markus@openbsd.org139ca812015-01-14 13:09:09 +0000237 if ((msg = sshbuf_new()) == NULL)
238 fatal("%s: sshbuf_new failed", __func__);
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000239 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
240 (r = sshbuf_put_u32(msg, idtab->nentries)) != 0)
markus@openbsd.org139ca812015-01-14 13:09:09 +0000241 fatal("%s: buffer error: %s", __func__, ssh_err(r));
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000242 TAILQ_FOREACH(id, &idtab->idlist, next) {
243 if ((r = sshkey_puts(id->key, msg)) != 0 ||
244 (r = sshbuf_put_cstring(msg, id->comment)) != 0) {
245 error("%s: put key/comment: %s", __func__,
djm@openbsd.org873d3e72017-04-30 23:18:44 +0000246 ssh_err(r));
247 continue;
Damien Millerad833b32000-08-23 10:46:23 +1000248 }
Damien Miller95def091999-11-25 00:26:21 +1100249 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000250 if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
251 fatal("%s: buffer error: %s", __func__, ssh_err(r));
252 sshbuf_free(msg);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000253}
254
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000255
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000256static char *
257agent_decode_alg(struct sshkey *key, u_int flags)
258{
259 if (key->type == KEY_RSA) {
260 if (flags & SSH_AGENT_RSA_SHA2_256)
261 return "rsa-sha2-256";
262 else if (flags & SSH_AGENT_RSA_SHA2_512)
263 return "rsa-sha2-512";
264 }
265 return NULL;
266}
267
Damien Millerad833b32000-08-23 10:46:23 +1000268/* ssh2 only */
Ben Lindstrombba81212001-06-25 05:01:22 +0000269static void
Damien Millerad833b32000-08-23 10:46:23 +1000270process_sign_request2(SocketEntry *e)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000271{
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000272 const u_char *data;
273 u_char *signature = NULL;
274 size_t dlen, slen = 0;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000275 u_int compat = 0, flags;
276 int r, ok = -1;
277 struct sshbuf *msg;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000278 struct sshkey *key = NULL;
djm@openbsd.org0088c572015-01-14 19:33:41 +0000279 struct identity *id;
Damien Millerad833b32000-08-23 10:46:23 +1000280
djm@openbsd.org0088c572015-01-14 19:33:41 +0000281 if ((msg = sshbuf_new()) == NULL)
282 fatal("%s: sshbuf_new failed", __func__);
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000283 if ((r = sshkey_froms(e->request, &key)) != 0 ||
284 (r = sshbuf_get_string_direct(e->request, &data, &dlen)) != 0 ||
markus@openbsd.org139ca812015-01-14 13:09:09 +0000285 (r = sshbuf_get_u32(e->request, &flags)) != 0)
286 fatal("%s: buffer error: %s", __func__, ssh_err(r));
Damien Miller62cee002000-09-23 17:15:56 +1100287 if (flags & SSH_AGENT_OLD_SIGNATURE)
markus@openbsd.org139ca812015-01-14 13:09:09 +0000288 compat = SSH_BUG_SIGBLOB;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000289 if ((id = lookup_identity(key)) == NULL) {
djm@openbsd.org0088c572015-01-14 19:33:41 +0000290 verbose("%s: %s key not found", __func__, sshkey_type(key));
291 goto send;
292 }
293 if (id->confirm && confirm_key(id) != 0) {
294 verbose("%s: user refused key", __func__);
295 goto send;
296 }
297 if ((r = sshkey_sign(id->key, &signature, &slen,
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000298 data, dlen, agent_decode_alg(key, flags), compat)) != 0) {
djm@openbsd.org39736be2015-12-11 02:20:28 +0000299 error("%s: sshkey_sign: %s", __func__, ssh_err(r));
djm@openbsd.org0088c572015-01-14 19:33:41 +0000300 goto send;
301 }
302 /* Success */
303 ok = 0;
304 send:
305 sshkey_free(key);
Damien Millerad833b32000-08-23 10:46:23 +1000306 if (ok == 0) {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000307 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 ||
308 (r = sshbuf_put_string(msg, signature, slen)) != 0)
309 fatal("%s: buffer error: %s", __func__, ssh_err(r));
310 } else if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
311 fatal("%s: buffer error: %s", __func__, ssh_err(r));
312
313 if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
314 fatal("%s: buffer error: %s", __func__, ssh_err(r));
315
316 sshbuf_free(msg);
Darren Tuckera627d422013-06-02 07:31:17 +1000317 free(signature);
Damien Millerad833b32000-08-23 10:46:23 +1000318}
319
320/* shared */
Ben Lindstrombba81212001-06-25 05:01:22 +0000321static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000322process_remove_identity(SocketEntry *e)
Damien Millerad833b32000-08-23 10:46:23 +1000323{
markus@openbsd.org139ca812015-01-14 13:09:09 +0000324 int r, success = 0;
325 struct sshkey *key = NULL;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000326 Identity *id;
Damien Miller7e8e8201999-11-16 13:37:16 +1100327
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000328 if ((r = sshkey_froms(e->request, &key)) != 0) {
329 error("%s: get key: %s", __func__, ssh_err(r));
330 goto done;
Damien Millerad833b32000-08-23 10:46:23 +1000331 }
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000332 if ((id = lookup_identity(key)) == NULL) {
333 debug("%s: key not found", __func__);
334 goto done;
Damien Millerad833b32000-08-23 10:46:23 +1000335 }
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000336 /* We have this key, free it. */
337 if (idtab->nentries < 1)
338 fatal("%s: internal error: nentries %d",
339 __func__, idtab->nentries);
340 TAILQ_REMOVE(&idtab->idlist, id, next);
341 free_identity(id);
342 idtab->nentries--;
343 sshkey_free(key);
344 success = 1;
345 done:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000346 send_status(e, success);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000347}
348
Ben Lindstrombba81212001-06-25 05:01:22 +0000349static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000350process_remove_all_identities(SocketEntry *e)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000351{
Damien Miller1a534ae2002-01-22 23:26:13 +1100352 Identity *id;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000353
Damien Miller95def091999-11-25 00:26:21 +1100354 /* Loop over all identities and clear the keys. */
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000355 for (id = TAILQ_FIRST(&idtab->idlist); id;
356 id = TAILQ_FIRST(&idtab->idlist)) {
357 TAILQ_REMOVE(&idtab->idlist, id, next);
Damien Miller1a534ae2002-01-22 23:26:13 +1100358 free_identity(id);
Damien Miller95def091999-11-25 00:26:21 +1100359 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000360
Damien Miller95def091999-11-25 00:26:21 +1100361 /* Mark that there are no identities. */
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000362 idtab->nentries = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000363
364 /* Send success. */
markus@openbsd.org139ca812015-01-14 13:09:09 +0000365 send_status(e, 1);
Damien Miller95def091999-11-25 00:26:21 +1100366}
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000367
Darren Tucker2812dc92007-03-21 20:45:06 +1100368/* removes expired keys and returns number of seconds until the next expiry */
Darren Tucker55119252013-06-02 07:43:59 +1000369static time_t
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000370reaper(void)
371{
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000372 time_t deadline = 0, now = monotime();
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000373 Identity *id, *nxt;
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000374
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000375 for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
376 nxt = TAILQ_NEXT(id, next);
377 if (id->death == 0)
378 continue;
379 if (now >= id->death) {
380 debug("expiring key '%s'", id->comment);
381 TAILQ_REMOVE(&idtab->idlist, id, next);
382 free_identity(id);
383 idtab->nentries--;
384 } else
385 deadline = (deadline == 0) ? id->death :
386 MINIMUM(deadline, id->death);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000387 }
Darren Tucker2812dc92007-03-21 20:45:06 +1100388 if (deadline == 0 || deadline <= now)
389 return 0;
390 else
391 return (deadline - now);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000392}
393
394static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000395process_add_identity(SocketEntry *e)
Damien Miller95def091999-11-25 00:26:21 +1100396{
Damien Miller4c7728c2007-10-26 14:25:31 +1000397 Identity *id;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000398 int success = 0, confirm = 0;
399 u_int seconds;
400 char *comment = NULL;
Darren Tucker55119252013-06-02 07:43:59 +1000401 time_t death = 0;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000402 struct sshkey *k = NULL;
403 u_char ctype;
404 int r = SSH_ERR_INTERNAL_ERROR;
Damien Miller95def091999-11-25 00:26:21 +1100405
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000406 if ((r = sshkey_private_deserialize(e->request, &k)) != 0 ||
407 k == NULL ||
markus@openbsd.org139ca812015-01-14 13:09:09 +0000408 (r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) {
409 error("%s: decode private key: %s", __func__, ssh_err(r));
410 goto err;
411 }
Damien Miller86687062014-07-02 15:28:02 +1000412
markus@openbsd.org139ca812015-01-14 13:09:09 +0000413 while (sshbuf_len(e->request)) {
414 if ((r = sshbuf_get_u8(e->request, &ctype)) != 0) {
415 error("%s: buffer error: %s", __func__, ssh_err(r));
416 goto err;
417 }
418 switch (ctype) {
Ben Lindstromc90f8a92002-06-21 00:06:54 +0000419 case SSH_AGENT_CONSTRAIN_LIFETIME:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000420 if ((r = sshbuf_get_u32(e->request, &seconds)) != 0) {
421 error("%s: bad lifetime constraint: %s",
422 __func__, ssh_err(r));
423 goto err;
424 }
425 death = monotime() + seconds;
Ben Lindstrom4eb4c4e2002-06-21 00:04:48 +0000426 break;
Damien Miller6c711792003-01-24 11:36:23 +1100427 case SSH_AGENT_CONSTRAIN_CONFIRM:
428 confirm = 1;
429 break;
Ben Lindstrom4eb4c4e2002-06-21 00:04:48 +0000430 default:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000431 error("%s: Unknown constraint %d", __func__, ctype);
432 err:
433 sshbuf_reset(e->request);
Darren Tuckera627d422013-06-02 07:31:17 +1000434 free(comment);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000435 sshkey_free(k);
Damien Miller1cfadab2008-06-30 00:05:21 +1000436 goto send;
Ben Lindstrom4eb4c4e2002-06-21 00:04:48 +0000437 }
438 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000439
Damien Miller1cfadab2008-06-30 00:05:21 +1000440 success = 1;
Damien Miller53d81482003-01-22 11:47:19 +1100441 if (lifetime && !death)
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000442 death = monotime() + lifetime;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000443 if ((id = lookup_identity(k)) == NULL) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100444 id = xcalloc(1, sizeof(Identity));
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000445 id->key = k;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000446 TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000447 /* Increment the number of identities. */
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000448 idtab->nentries++;
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000449 } else {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000450 sshkey_free(k);
Darren Tuckera627d422013-06-02 07:31:17 +1000451 free(id->comment);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000452 }
Damien Miller4c7728c2007-10-26 14:25:31 +1000453 id->comment = comment;
454 id->death = death;
455 id->confirm = confirm;
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000456send:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000457 send_status(e, success);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000458}
459
Ben Lindstrom2f717042002-06-06 21:52:03 +0000460/* XXX todo: encrypt sensitive data with passphrase */
461static void
462process_lock_agent(SocketEntry *e, int lock)
463{
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000464 int r, success = 0, delay;
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000465 char *passwd;
466 u_char passwdhash[LOCK_SIZE];
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000467 static u_int fail_count = 0;
468 size_t pwlen;
Ben Lindstrom2f717042002-06-06 21:52:03 +0000469
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000470 if ((r = sshbuf_get_cstring(e->request, &passwd, &pwlen)) != 0)
markus@openbsd.org139ca812015-01-14 13:09:09 +0000471 fatal("%s: buffer error: %s", __func__, ssh_err(r));
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000472 if (pwlen == 0) {
473 debug("empty password not supported");
474 } else if (locked && !lock) {
475 if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
476 passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0)
477 fatal("bcrypt_pbkdf");
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000478 if (timingsafe_bcmp(passwdhash, lock_pwhash, LOCK_SIZE) == 0) {
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000479 debug("agent unlocked");
480 locked = 0;
481 fail_count = 0;
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000482 explicit_bzero(lock_pwhash, sizeof(lock_pwhash));
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000483 success = 1;
484 } else {
485 /* delay in 0.1s increments up to 10s */
486 if (fail_count < 100)
487 fail_count++;
488 delay = 100000 * fail_count;
489 debug("unlock failed, delaying %0.1lf seconds",
490 (double)delay/1000000);
491 usleep(delay);
492 }
493 explicit_bzero(passwdhash, sizeof(passwdhash));
Ben Lindstrom2f717042002-06-06 21:52:03 +0000494 } else if (!locked && lock) {
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000495 debug("agent locked");
Ben Lindstrom2f717042002-06-06 21:52:03 +0000496 locked = 1;
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000497 arc4random_buf(lock_salt, sizeof(lock_salt));
498 if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000499 lock_pwhash, sizeof(lock_pwhash), LOCK_ROUNDS) < 0)
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000500 fatal("bcrypt_pbkdf");
Ben Lindstrom2f717042002-06-06 21:52:03 +0000501 success = 1;
502 }
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000503 explicit_bzero(passwd, pwlen);
Darren Tuckera627d422013-06-02 07:31:17 +1000504 free(passwd);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000505 send_status(e, success);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000506}
507
508static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000509no_identities(SocketEntry *e)
Ben Lindstrom2f717042002-06-06 21:52:03 +0000510{
markus@openbsd.org139ca812015-01-14 13:09:09 +0000511 struct sshbuf *msg;
512 int r;
Ben Lindstrom2f717042002-06-06 21:52:03 +0000513
markus@openbsd.org139ca812015-01-14 13:09:09 +0000514 if ((msg = sshbuf_new()) == NULL)
515 fatal("%s: sshbuf_new failed", __func__);
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000516 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
markus@openbsd.org139ca812015-01-14 13:09:09 +0000517 (r = sshbuf_put_u32(msg, 0)) != 0 ||
518 (r = sshbuf_put_stringb(e->output, msg)) != 0)
519 fatal("%s: buffer error: %s", __func__, ssh_err(r));
520 sshbuf_free(msg);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000521}
Ben Lindstrom3f471632001-07-04 03:53:15 +0000522
Damien Miller7ea845e2010-02-12 09:21:02 +1100523#ifdef ENABLE_PKCS11
Ben Lindstrom3f471632001-07-04 03:53:15 +0000524static void
Damien Miller1cfadab2008-06-30 00:05:21 +1000525process_add_smartcard_key(SocketEntry *e)
Ben Lindstrom3f471632001-07-04 03:53:15 +0000526{
djm@openbsd.org786d5992016-11-30 03:07:37 +0000527 char *provider = NULL, *pin, canonical_provider[PATH_MAX];
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000528 int r, i, count = 0, success = 0, confirm = 0;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000529 u_int seconds;
Darren Tucker55119252013-06-02 07:43:59 +1000530 time_t death = 0;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000531 u_char type;
532 struct sshkey **keys = NULL, *k;
Ben Lindstrom822b6342002-06-23 21:38:49 +0000533 Identity *id;
Damien Miller9f0f5c62001-12-21 14:45:46 +1100534
markus@openbsd.org139ca812015-01-14 13:09:09 +0000535 if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
536 (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
537 fatal("%s: buffer error: %s", __func__, ssh_err(r));
Damien Millerd94f20d2003-06-11 22:06:33 +1000538
markus@openbsd.org139ca812015-01-14 13:09:09 +0000539 while (sshbuf_len(e->request)) {
540 if ((r = sshbuf_get_u8(e->request, &type)) != 0)
541 fatal("%s: buffer error: %s", __func__, ssh_err(r));
542 switch (type) {
Damien Millerd94f20d2003-06-11 22:06:33 +1000543 case SSH_AGENT_CONSTRAIN_LIFETIME:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000544 if ((r = sshbuf_get_u32(e->request, &seconds)) != 0)
545 fatal("%s: buffer error: %s",
546 __func__, ssh_err(r));
547 death = monotime() + seconds;
Damien Millerd94f20d2003-06-11 22:06:33 +1000548 break;
549 case SSH_AGENT_CONSTRAIN_CONFIRM:
550 confirm = 1;
551 break;
552 default:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000553 error("%s: Unknown constraint type %d", __func__, type);
Damien Miller1cfadab2008-06-30 00:05:21 +1000554 goto send;
Damien Millerd94f20d2003-06-11 22:06:33 +1000555 }
556 }
djm@openbsd.org786d5992016-11-30 03:07:37 +0000557 if (realpath(provider, canonical_provider) == NULL) {
558 verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
559 provider, strerror(errno));
560 goto send;
561 }
562 if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) {
563 verbose("refusing PKCS#11 add of \"%.100s\": "
564 "provider not whitelisted", canonical_provider);
565 goto send;
566 }
567 debug("%s: add %.100s", __func__, canonical_provider);
Damien Millerd94f20d2003-06-11 22:06:33 +1000568 if (lifetime && !death)
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000569 death = monotime() + lifetime;
Damien Millerd94f20d2003-06-11 22:06:33 +1000570
djm@openbsd.org786d5992016-11-30 03:07:37 +0000571 count = pkcs11_add_provider(canonical_provider, pin, &keys);
Damien Miller7ea845e2010-02-12 09:21:02 +1100572 for (i = 0; i < count; i++) {
Ben Lindstrom0936a5b2002-03-26 03:17:42 +0000573 k = keys[i];
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000574 if (lookup_identity(k) == NULL) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100575 id = xcalloc(1, sizeof(Identity));
Ben Lindstrom0936a5b2002-03-26 03:17:42 +0000576 id->key = k;
djm@openbsd.org786d5992016-11-30 03:07:37 +0000577 id->provider = xstrdup(canonical_provider);
578 id->comment = xstrdup(canonical_provider); /* XXX */
Damien Millerd94f20d2003-06-11 22:06:33 +1000579 id->death = death;
580 id->confirm = confirm;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000581 TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
582 idtab->nentries++;
Ben Lindstrom0936a5b2002-03-26 03:17:42 +0000583 success = 1;
584 } else {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000585 sshkey_free(k);
Ben Lindstrom0936a5b2002-03-26 03:17:42 +0000586 }
587 keys[i] = NULL;
Ben Lindstrom3f471632001-07-04 03:53:15 +0000588 }
Ben Lindstrom3f471632001-07-04 03:53:15 +0000589send:
Darren Tuckera627d422013-06-02 07:31:17 +1000590 free(pin);
591 free(provider);
592 free(keys);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000593 send_status(e, success);
Ben Lindstrom3f471632001-07-04 03:53:15 +0000594}
595
596static void
597process_remove_smartcard_key(SocketEntry *e)
598{
djm@openbsd.org25f83762017-03-15 02:25:09 +0000599 char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000600 int r, success = 0;
Damien Miller7ea845e2010-02-12 09:21:02 +1100601 Identity *id, *nxt;
Ben Lindstrom3f471632001-07-04 03:53:15 +0000602
markus@openbsd.org139ca812015-01-14 13:09:09 +0000603 if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
604 (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
605 fatal("%s: buffer error: %s", __func__, ssh_err(r));
Darren Tuckera627d422013-06-02 07:31:17 +1000606 free(pin);
Ben Lindstrom3f471632001-07-04 03:53:15 +0000607
djm@openbsd.org25f83762017-03-15 02:25:09 +0000608 if (realpath(provider, canonical_provider) == NULL) {
609 verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
610 provider, strerror(errno));
611 goto send;
612 }
613
614 debug("%s: remove %.100s", __func__, canonical_provider);
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000615 for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
616 nxt = TAILQ_NEXT(id, next);
617 /* Skip file--based keys */
618 if (id->provider == NULL)
619 continue;
620 if (!strcmp(canonical_provider, id->provider)) {
621 TAILQ_REMOVE(&idtab->idlist, id, next);
622 free_identity(id);
623 idtab->nentries--;
Ben Lindstrom3f471632001-07-04 03:53:15 +0000624 }
Ben Lindstrom3f471632001-07-04 03:53:15 +0000625 }
djm@openbsd.org25f83762017-03-15 02:25:09 +0000626 if (pkcs11_del_provider(canonical_provider) == 0)
Damien Miller7ea845e2010-02-12 09:21:02 +1100627 success = 1;
628 else
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000629 error("%s: pkcs11_del_provider failed", __func__);
deraadt@openbsd.org1a321bf2017-03-15 03:52:30 +0000630send:
Darren Tuckera627d422013-06-02 07:31:17 +1000631 free(provider);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000632 send_status(e, success);
Ben Lindstrom3f471632001-07-04 03:53:15 +0000633}
Damien Miller7ea845e2010-02-12 09:21:02 +1100634#endif /* ENABLE_PKCS11 */
Ben Lindstrom3f471632001-07-04 03:53:15 +0000635
Damien Millerad833b32000-08-23 10:46:23 +1000636/* dispatch incoming messages */
637
Ben Lindstrombba81212001-06-25 05:01:22 +0000638static void
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000639process_message(SocketEntry *e)
640{
markus@openbsd.org139ca812015-01-14 13:09:09 +0000641 u_int msg_len;
642 u_char type;
643 const u_char *cp;
644 int r;
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000645
markus@openbsd.org139ca812015-01-14 13:09:09 +0000646 if (sshbuf_len(e->input) < 5)
Damien Miller95def091999-11-25 00:26:21 +1100647 return; /* Incomplete message. */
markus@openbsd.org139ca812015-01-14 13:09:09 +0000648 cp = sshbuf_ptr(e->input);
649 msg_len = PEEK_U32(cp);
Damien Miller95def091999-11-25 00:26:21 +1100650 if (msg_len > 256 * 1024) {
Damien Miller58f34862002-09-04 16:31:21 +1000651 close_socket(e);
Damien Miller95def091999-11-25 00:26:21 +1100652 return;
653 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000654 if (sshbuf_len(e->input) < msg_len + 4)
Damien Miller95def091999-11-25 00:26:21 +1100655 return;
Ben Lindstrom21d1ed82002-06-06 21:48:57 +0000656
657 /* move the current input to e->request */
markus@openbsd.org139ca812015-01-14 13:09:09 +0000658 sshbuf_reset(e->request);
659 if ((r = sshbuf_get_stringb(e->input, e->request)) != 0 ||
660 (r = sshbuf_get_u8(e->request, &type)) != 0)
661 fatal("%s: buffer error: %s", __func__, ssh_err(r));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000662
Ben Lindstrom2f717042002-06-06 21:52:03 +0000663 /* check wheter agent is locked */
664 if (locked && type != SSH_AGENTC_UNLOCK) {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000665 sshbuf_reset(e->request);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000666 switch (type) {
Ben Lindstrom2f717042002-06-06 21:52:03 +0000667 case SSH2_AGENTC_REQUEST_IDENTITIES:
668 /* send empty lists */
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000669 no_identities(e);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000670 break;
671 default:
672 /* send a fail message for all other request types */
markus@openbsd.org139ca812015-01-14 13:09:09 +0000673 send_status(e, 0);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000674 }
675 return;
676 }
677
Ben Lindstrom3f471632001-07-04 03:53:15 +0000678 debug("type %d", type);
Damien Miller95def091999-11-25 00:26:21 +1100679 switch (type) {
Ben Lindstrom2f717042002-06-06 21:52:03 +0000680 case SSH_AGENTC_LOCK:
681 case SSH_AGENTC_UNLOCK:
682 process_lock_agent(e, type == SSH_AGENTC_LOCK);
683 break;
djm@openbsd.org2f04af92015-03-04 21:12:59 +0000684 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000685 process_remove_all_identities(e); /* safe for !WITH_SSH1 */
djm@openbsd.org2f04af92015-03-04 21:12:59 +0000686 break;
Damien Millerad833b32000-08-23 10:46:23 +1000687 /* ssh2 */
688 case SSH2_AGENTC_SIGN_REQUEST:
689 process_sign_request2(e);
690 break;
691 case SSH2_AGENTC_REQUEST_IDENTITIES:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000692 process_request_identities(e);
Damien Millerad833b32000-08-23 10:46:23 +1000693 break;
694 case SSH2_AGENTC_ADD_IDENTITY:
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000695 case SSH2_AGENTC_ADD_ID_CONSTRAINED:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000696 process_add_identity(e);
Damien Millerad833b32000-08-23 10:46:23 +1000697 break;
698 case SSH2_AGENTC_REMOVE_IDENTITY:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000699 process_remove_identity(e);
Damien Millerad833b32000-08-23 10:46:23 +1000700 break;
701 case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000702 process_remove_all_identities(e);
Damien Miller95def091999-11-25 00:26:21 +1100703 break;
Damien Miller7ea845e2010-02-12 09:21:02 +1100704#ifdef ENABLE_PKCS11
Ben Lindstrom3f471632001-07-04 03:53:15 +0000705 case SSH_AGENTC_ADD_SMARTCARD_KEY:
Damien Millerd94f20d2003-06-11 22:06:33 +1000706 case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
Ben Lindstrom3f471632001-07-04 03:53:15 +0000707 process_add_smartcard_key(e);
Damien Miller9f0f5c62001-12-21 14:45:46 +1100708 break;
Ben Lindstrom3f471632001-07-04 03:53:15 +0000709 case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
710 process_remove_smartcard_key(e);
Damien Miller9f0f5c62001-12-21 14:45:46 +1100711 break;
Damien Miller7ea845e2010-02-12 09:21:02 +1100712#endif /* ENABLE_PKCS11 */
Damien Miller95def091999-11-25 00:26:21 +1100713 default:
714 /* Unknown message. Respond with failure. */
715 error("Unknown message %d", type);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000716 sshbuf_reset(e->request);
717 send_status(e, 0);
Damien Miller95def091999-11-25 00:26:21 +1100718 break;
719 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000720}
721
Ben Lindstrombba81212001-06-25 05:01:22 +0000722static void
Ben Lindstrom65366a82001-12-06 16:32:47 +0000723new_socket(sock_type type, int fd)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000724{
Darren Tuckerfb16b242003-09-22 21:04:23 +1000725 u_int i, old_alloc, new_alloc;
Ben Lindstrom822b6342002-06-23 21:38:49 +0000726
Damien Miller232711f2004-06-15 10:35:30 +1000727 set_nonblock(fd);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000728
Damien Miller95def091999-11-25 00:26:21 +1100729 if (fd > max_fd)
730 max_fd = fd;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000731
Damien Miller95def091999-11-25 00:26:21 +1100732 for (i = 0; i < sockets_alloc; i++)
733 if (sockets[i].type == AUTH_UNUSED) {
734 sockets[i].fd = fd;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000735 if ((sockets[i].input = sshbuf_new()) == NULL)
736 fatal("%s: sshbuf_new failed", __func__);
737 if ((sockets[i].output = sshbuf_new()) == NULL)
738 fatal("%s: sshbuf_new failed", __func__);
739 if ((sockets[i].request = sshbuf_new()) == NULL)
740 fatal("%s: sshbuf_new failed", __func__);
Darren Tuckerfb16b242003-09-22 21:04:23 +1000741 sockets[i].type = type;
Damien Miller95def091999-11-25 00:26:21 +1100742 return;
743 }
744 old_alloc = sockets_alloc;
Darren Tuckerfb16b242003-09-22 21:04:23 +1000745 new_alloc = sockets_alloc + 10;
deraadt@openbsd.org657a5fb2015-04-24 01:36:00 +0000746 sockets = xreallocarray(sockets, new_alloc, sizeof(sockets[0]));
Darren Tuckerfb16b242003-09-22 21:04:23 +1000747 for (i = old_alloc; i < new_alloc; i++)
Damien Miller95def091999-11-25 00:26:21 +1100748 sockets[i].type = AUTH_UNUSED;
Darren Tuckerfb16b242003-09-22 21:04:23 +1000749 sockets_alloc = new_alloc;
Damien Miller95def091999-11-25 00:26:21 +1100750 sockets[old_alloc].fd = fd;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000751 if ((sockets[old_alloc].input = sshbuf_new()) == NULL)
752 fatal("%s: sshbuf_new failed", __func__);
753 if ((sockets[old_alloc].output = sshbuf_new()) == NULL)
754 fatal("%s: sshbuf_new failed", __func__);
755 if ((sockets[old_alloc].request = sshbuf_new()) == NULL)
756 fatal("%s: sshbuf_new failed", __func__);
Darren Tuckerfb16b242003-09-22 21:04:23 +1000757 sockets[old_alloc].type = type;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000758}
759
Ben Lindstrombba81212001-06-25 05:01:22 +0000760static int
Darren Tucker2812dc92007-03-21 20:45:06 +1100761prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
762 struct timeval **tvpp)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000763{
Darren Tucker55119252013-06-02 07:43:59 +1000764 u_int i, sz;
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000765 int n = 0;
Darren Tucker2812dc92007-03-21 20:45:06 +1100766 static struct timeval tv;
Darren Tucker55119252013-06-02 07:43:59 +1000767 time_t deadline;
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000768
769 for (i = 0; i < sockets_alloc; i++) {
Damien Miller95def091999-11-25 00:26:21 +1100770 switch (sockets[i].type) {
771 case AUTH_SOCKET:
772 case AUTH_CONNECTION:
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +0000773 n = MAXIMUM(n, sockets[i].fd);
Damien Miller95def091999-11-25 00:26:21 +1100774 break;
775 case AUTH_UNUSED:
776 break;
777 default:
778 fatal("Unknown socket type %d", sockets[i].type);
779 break;
780 }
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000781 }
782
783 sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
Ben Lindstroma3d5a4c2001-07-18 15:58:08 +0000784 if (*fdrp == NULL || sz > *nallocp) {
Darren Tuckera627d422013-06-02 07:31:17 +1000785 free(*fdrp);
786 free(*fdwp);
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000787 *fdrp = xmalloc(sz);
788 *fdwp = xmalloc(sz);
Ben Lindstroma3d5a4c2001-07-18 15:58:08 +0000789 *nallocp = sz;
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000790 }
Ben Lindstroma3d5a4c2001-07-18 15:58:08 +0000791 if (n < *fdl)
792 debug("XXX shrink: %d < %d", n, *fdl);
793 *fdl = n;
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000794 memset(*fdrp, 0, sz);
795 memset(*fdwp, 0, sz);
796
797 for (i = 0; i < sockets_alloc; i++) {
798 switch (sockets[i].type) {
799 case AUTH_SOCKET:
800 case AUTH_CONNECTION:
801 FD_SET(sockets[i].fd, *fdrp);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000802 if (sshbuf_len(sockets[i].output) > 0)
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000803 FD_SET(sockets[i].fd, *fdwp);
804 break;
805 default:
806 break;
807 }
808 }
Darren Tucker2812dc92007-03-21 20:45:06 +1100809 deadline = reaper();
810 if (parent_alive_interval != 0)
811 deadline = (deadline == 0) ? parent_alive_interval :
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +0000812 MINIMUM(deadline, parent_alive_interval);
Darren Tucker2812dc92007-03-21 20:45:06 +1100813 if (deadline == 0) {
814 *tvpp = NULL;
815 } else {
816 tv.tv_sec = deadline;
817 tv.tv_usec = 0;
818 *tvpp = &tv;
819 }
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000820 return (1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000821}
822
Ben Lindstrombba81212001-06-25 05:01:22 +0000823static void
Damien Miller95def091999-11-25 00:26:21 +1100824after_select(fd_set *readset, fd_set *writeset)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000825{
Ben Lindstrom822b6342002-06-23 21:38:49 +0000826 struct sockaddr_un sunaddr;
Damien Miller7684ee12000-03-17 23:40:15 +1100827 socklen_t slen;
Damien Miller95def091999-11-25 00:26:21 +1100828 char buf[1024];
markus@openbsd.org139ca812015-01-14 13:09:09 +0000829 int len, sock, r;
Darren Tucker72473c62009-10-07 09:01:03 +1100830 u_int i, orig_alloc;
Damien Miller538f1812002-09-12 09:51:10 +1000831 uid_t euid;
832 gid_t egid;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000833
Darren Tucker72473c62009-10-07 09:01:03 +1100834 for (i = 0, orig_alloc = sockets_alloc; i < orig_alloc; i++)
Damien Miller95def091999-11-25 00:26:21 +1100835 switch (sockets[i].type) {
836 case AUTH_UNUSED:
837 break;
838 case AUTH_SOCKET:
839 if (FD_ISSET(sockets[i].fd, readset)) {
Damien Miller7684ee12000-03-17 23:40:15 +1100840 slen = sizeof(sunaddr);
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000841 sock = accept(sockets[i].fd,
Damien Miller90967402006-03-26 14:07:26 +1100842 (struct sockaddr *)&sunaddr, &slen);
Damien Miller95def091999-11-25 00:26:21 +1100843 if (sock < 0) {
Damien Millerc653b892002-02-08 22:05:41 +1100844 error("accept from AUTH_SOCKET: %s",
845 strerror(errno));
Damien Miller95def091999-11-25 00:26:21 +1100846 break;
847 }
Damien Miller538f1812002-09-12 09:51:10 +1000848 if (getpeereid(sock, &euid, &egid) < 0) {
849 error("getpeereid %d failed: %s",
850 sock, strerror(errno));
851 close(sock);
852 break;
853 }
Damien Milleraf9de382002-10-03 11:54:35 +1000854 if ((euid != 0) && (getuid() != euid)) {
Damien Miller538f1812002-09-12 09:51:10 +1000855 error("uid mismatch: "
Damien Millerdb30b122002-09-19 11:46:58 +1000856 "peer euid %u != uid %u",
857 (u_int) euid, (u_int) getuid());
Damien Miller538f1812002-09-12 09:51:10 +1000858 close(sock);
859 break;
860 }
Damien Miller95def091999-11-25 00:26:21 +1100861 new_socket(AUTH_CONNECTION, sock);
862 }
863 break;
864 case AUTH_CONNECTION:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000865 if (sshbuf_len(sockets[i].output) > 0 &&
Damien Miller95def091999-11-25 00:26:21 +1100866 FD_ISSET(sockets[i].fd, writeset)) {
Darren Tucker72473c62009-10-07 09:01:03 +1100867 len = write(sockets[i].fd,
markus@openbsd.org139ca812015-01-14 13:09:09 +0000868 sshbuf_ptr(sockets[i].output),
869 sshbuf_len(sockets[i].output));
Darren Tucker72473c62009-10-07 09:01:03 +1100870 if (len == -1 && (errno == EAGAIN ||
871 errno == EWOULDBLOCK ||
872 errno == EINTR))
873 continue;
Damien Miller95def091999-11-25 00:26:21 +1100874 if (len <= 0) {
Damien Miller58f34862002-09-04 16:31:21 +1000875 close_socket(&sockets[i]);
Damien Miller95def091999-11-25 00:26:21 +1100876 break;
877 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000878 if ((r = sshbuf_consume(sockets[i].output,
879 len)) != 0)
880 fatal("%s: buffer error: %s",
881 __func__, ssh_err(r));
Damien Miller95def091999-11-25 00:26:21 +1100882 }
883 if (FD_ISSET(sockets[i].fd, readset)) {
Darren Tucker72473c62009-10-07 09:01:03 +1100884 len = read(sockets[i].fd, buf, sizeof(buf));
885 if (len == -1 && (errno == EAGAIN ||
886 errno == EWOULDBLOCK ||
887 errno == EINTR))
888 continue;
Damien Miller95def091999-11-25 00:26:21 +1100889 if (len <= 0) {
Damien Miller58f34862002-09-04 16:31:21 +1000890 close_socket(&sockets[i]);
Damien Miller95def091999-11-25 00:26:21 +1100891 break;
892 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000893 if ((r = sshbuf_put(sockets[i].input,
894 buf, len)) != 0)
895 fatal("%s: buffer error: %s",
896 __func__, ssh_err(r));
Damien Millerf4977942014-07-30 12:32:46 +1000897 explicit_bzero(buf, sizeof(buf));
Damien Miller95def091999-11-25 00:26:21 +1100898 process_message(&sockets[i]);
899 }
900 break;
901 default:
902 fatal("Unknown type %d", sockets[i].type);
903 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000904}
905
Ben Lindstrombba81212001-06-25 05:01:22 +0000906static void
Darren Tucker6fa8abd2003-09-22 21:10:21 +1000907cleanup_socket(void)
Damien Miller792c5111999-10-29 09:47:09 +1000908{
Damien Millerb1e967c2014-07-03 21:22:40 +1000909 if (cleanup_pid != 0 && getpid() != cleanup_pid)
910 return;
911 debug("%s: cleanup", __func__);
Ben Lindstrom77808ab2001-01-26 05:10:34 +0000912 if (socket_name[0])
913 unlink(socket_name);
914 if (socket_dir[0])
915 rmdir(socket_dir);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000916}
917
Darren Tucker3e33cec2003-10-02 16:12:36 +1000918void
Damien Miller792c5111999-10-29 09:47:09 +1000919cleanup_exit(int i)
920{
Darren Tucker6fa8abd2003-09-22 21:10:21 +1000921 cleanup_socket();
922 _exit(i);
Damien Miller792c5111999-10-29 09:47:09 +1000923}
924
Damien Miller1c13bd82006-03-26 14:28:14 +1100925/*ARGSUSED*/
Ben Lindstrombba81212001-06-25 05:01:22 +0000926static void
Ben Lindstrom77808ab2001-01-26 05:10:34 +0000927cleanup_handler(int sig)
928{
Darren Tucker6fa8abd2003-09-22 21:10:21 +1000929 cleanup_socket();
Damien Miller7ea845e2010-02-12 09:21:02 +1100930#ifdef ENABLE_PKCS11
931 pkcs11_terminate();
932#endif
Ben Lindstrom77808ab2001-01-26 05:10:34 +0000933 _exit(2);
934}
935
Ben Lindstrombba81212001-06-25 05:01:22 +0000936static void
Darren Tucker2812dc92007-03-21 20:45:06 +1100937check_parent_exists(void)
Ben Lindstrom0250da02001-07-22 20:44:00 +0000938{
Darren Tucker3e78a512011-06-03 14:14:16 +1000939 /*
940 * If our parent has exited then getppid() will return (pid_t)1,
941 * so testing for that should be safe.
942 */
943 if (parent_pid != -1 && getppid() != parent_pid) {
Ben Lindstrom0250da02001-07-22 20:44:00 +0000944 /* printf("Parent has died - Authentication agent exiting.\n"); */
Darren Tucker2812dc92007-03-21 20:45:06 +1100945 cleanup_socket();
946 _exit(2);
Ben Lindstrom0250da02001-07-22 20:44:00 +0000947 }
Ben Lindstrom0250da02001-07-22 20:44:00 +0000948}
949
950static void
Ben Lindstrom28072eb2001-02-10 23:13:41 +0000951usage(void)
Damien Miller792c5111999-10-29 09:47:09 +1000952{
Damien Millerf0858de2014-04-20 13:01:30 +1000953 fprintf(stderr,
jmc@openbsd.orgb7ca2762015-04-24 06:26:49 +0000954 "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n"
djm@openbsd.org786d5992016-11-30 03:07:37 +0000955 " [-P pkcs11_whitelist] [-t life] [command [arg ...]]\n"
Damien Millerf0858de2014-04-20 13:01:30 +1000956 " ssh-agent [-c | -s] -k\n");
Damien Miller95def091999-11-25 00:26:21 +1100957 exit(1);
Damien Miller792c5111999-10-29 09:47:09 +1000958}
959
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000960int
961main(int ac, char **av)
962{
djm@openbsd.org2ea97462015-04-24 05:26:44 +0000963 int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0;
Darren Tuckercf0d2db2007-02-28 21:19:58 +1100964 int sock, fd, ch, result, saved_errno;
Darren Tuckerc7a6fc42004-08-13 21:18:00 +1000965 u_int nalloc;
Ben Lindstrom822b6342002-06-23 21:38:49 +0000966 char *shell, *format, *pidstr, *agentsocket = NULL;
967 fd_set *readsetp = NULL, *writesetp = NULL;
Ben Lindstrom2c467a22000-12-27 04:57:41 +0000968#ifdef HAVE_SETRLIMIT
Ben Lindstromc72745a2000-12-02 19:03:54 +0000969 struct rlimit rlim;
Ben Lindstrom2c467a22000-12-27 04:57:41 +0000970#endif
Damien Miller615f9392000-05-17 22:53:33 +1000971 extern int optind;
Ben Lindstrom883844d2002-06-23 00:20:50 +0000972 extern char *optarg;
Ben Lindstrom822b6342002-06-23 21:38:49 +0000973 pid_t pid;
974 char pidstrbuf[1 + 3 * sizeof pid];
Darren Tucker2812dc92007-03-21 20:45:06 +1100975 struct timeval *tvp = NULL;
Darren Tucker90133232009-06-21 17:50:15 +1000976 size_t len;
Damien Millerab2ec582014-07-18 15:04:47 +1000977 mode_t prev_mask;
Kevin Stevesde41bc62000-12-14 00:04:08 +0000978
dtucker@openbsd.orgffb1e7e2016-02-15 09:47:49 +0000979 ssh_malloc_init(); /* must be called before any mallocs */
Darren Tuckerce321d82005-10-03 18:11:24 +1000980 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
981 sanitise_stdfd();
982
Damien Miller6cffb9a2002-09-04 16:20:26 +1000983 /* drop */
984 setegid(getgid());
985 setgid(getgid());
986
Darren Tucker0fb7f592016-06-09 16:23:07 +1000987 platform_disable_tracing(0); /* strict=no */
Damien Miller6c4914a2004-03-03 11:08:59 +1100988
Damien Miller1f0311c2014-05-15 14:24:09 +1000989#ifdef WITH_OPENSSL
Damien Miller4314c2b2010-09-10 11:12:09 +1000990 OpenSSL_add_all_algorithms();
Damien Miller1f0311c2014-05-15 14:24:09 +1000991#endif
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000992
Damien Miller59d3d5b2003-08-22 09:34:41 +1000993 __progname = ssh_get_progname(av[0]);
Damien Miller60bc5172001-03-19 09:38:15 +1100994 seed_rng();
Kevin Stevesef4eea92001-02-05 12:42:17 +0000995
djm@openbsd.org786d5992016-11-30 03:07:37 +0000996 while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) {
Damien Miller95def091999-11-25 00:26:21 +1100997 switch (ch) {
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000998 case 'E':
999 fingerprint_hash = ssh_digest_alg_by_name(optarg);
1000 if (fingerprint_hash == -1)
1001 fatal("Invalid hash algorithm \"%s\"", optarg);
1002 break;
Damien Miller95def091999-11-25 00:26:21 +11001003 case 'c':
1004 if (s_flag)
1005 usage();
1006 c_flag++;
1007 break;
1008 case 'k':
1009 k_flag++;
1010 break;
djm@openbsd.org786d5992016-11-30 03:07:37 +00001011 case 'P':
1012 if (pkcs11_whitelist != NULL)
1013 fatal("-P option already specified");
1014 pkcs11_whitelist = xstrdup(optarg);
1015 break;
Damien Miller95def091999-11-25 00:26:21 +11001016 case 's':
1017 if (c_flag)
1018 usage();
1019 s_flag++;
1020 break;
Ben Lindstromd94580c2001-07-04 03:48:02 +00001021 case 'd':
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001022 if (d_flag || D_flag)
Ben Lindstromd94580c2001-07-04 03:48:02 +00001023 usage();
1024 d_flag++;
1025 break;
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001026 case 'D':
1027 if (d_flag || D_flag)
1028 usage();
1029 D_flag++;
1030 break;
Ben Lindstromb7788f32002-06-06 21:46:08 +00001031 case 'a':
1032 agentsocket = optarg;
1033 break;
Damien Miller53d81482003-01-22 11:47:19 +11001034 case 't':
1035 if ((lifetime = convtime(optarg)) == -1) {
1036 fprintf(stderr, "Invalid lifetime\n");
1037 usage();
1038 }
1039 break;
Damien Miller95def091999-11-25 00:26:21 +11001040 default:
1041 usage();
1042 }
Damien Miller792c5111999-10-29 09:47:09 +10001043 }
Damien Miller95def091999-11-25 00:26:21 +11001044 ac -= optind;
1045 av += optind;
Damien Miller792c5111999-10-29 09:47:09 +10001046
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001047 if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag))
Damien Miller95def091999-11-25 00:26:21 +11001048 usage();
Damien Miller792c5111999-10-29 09:47:09 +10001049
djm@openbsd.org786d5992016-11-30 03:07:37 +00001050 if (pkcs11_whitelist == NULL)
1051 pkcs11_whitelist = xstrdup(DEFAULT_PKCS11_WHITELIST);
1052
Ben Lindstromeecdf232002-04-02 21:03:51 +00001053 if (ac == 0 && !c_flag && !s_flag) {
Damien Miller95def091999-11-25 00:26:21 +11001054 shell = getenv("SHELL");
Darren Tucker90133232009-06-21 17:50:15 +10001055 if (shell != NULL && (len = strlen(shell)) > 2 &&
1056 strncmp(shell + len - 3, "csh", 3) == 0)
Damien Miller95def091999-11-25 00:26:21 +11001057 c_flag = 1;
Damien Miller792c5111999-10-29 09:47:09 +10001058 }
Damien Miller95def091999-11-25 00:26:21 +11001059 if (k_flag) {
Damien Miller89c3fe42006-03-31 23:11:28 +11001060 const char *errstr = NULL;
1061
Damien Miller95def091999-11-25 00:26:21 +11001062 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
1063 if (pidstr == NULL) {
1064 fprintf(stderr, "%s not set, cannot kill agent\n",
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001065 SSH_AGENTPID_ENV_NAME);
Damien Miller95def091999-11-25 00:26:21 +11001066 exit(1);
1067 }
Damien Miller89c3fe42006-03-31 23:11:28 +11001068 pid = (int)strtonum(pidstr, 2, INT_MAX, &errstr);
1069 if (errstr) {
1070 fprintf(stderr,
1071 "%s=\"%s\", which is not a good PID: %s\n",
1072 SSH_AGENTPID_ENV_NAME, pidstr, errstr);
Damien Miller95def091999-11-25 00:26:21 +11001073 exit(1);
1074 }
1075 if (kill(pid, SIGTERM) == -1) {
1076 perror("kill");
1077 exit(1);
1078 }
1079 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
1080 printf(format, SSH_AUTHSOCKET_ENV_NAME);
1081 printf(format, SSH_AGENTPID_ENV_NAME);
Ben Lindstromce0f6342002-06-11 16:42:49 +00001082 printf("echo Agent pid %ld killed;\n", (long)pid);
Damien Miller95def091999-11-25 00:26:21 +11001083 exit(0);
Damien Miller792c5111999-10-29 09:47:09 +10001084 }
Damien Miller95def091999-11-25 00:26:21 +11001085 parent_pid = getpid();
1086
Ben Lindstromb7788f32002-06-06 21:46:08 +00001087 if (agentsocket == NULL) {
1088 /* Create private directory for agent socket */
Damien Miller2cd62932010-12-01 11:50:35 +11001089 mktemp_proto(socket_dir, sizeof(socket_dir));
Ben Lindstromb7788f32002-06-06 21:46:08 +00001090 if (mkdtemp(socket_dir) == NULL) {
1091 perror("mkdtemp: private socket dir");
1092 exit(1);
1093 }
Ben Lindstromce0f6342002-06-11 16:42:49 +00001094 snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
1095 (long)parent_pid);
Ben Lindstromb7788f32002-06-06 21:46:08 +00001096 } else {
1097 /* Try to use specified agent socket */
1098 socket_dir[0] = '\0';
1099 strlcpy(socket_name, agentsocket, sizeof socket_name);
Damien Miller792c5111999-10-29 09:47:09 +10001100 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001101
Damien Miller5428f641999-11-25 11:54:57 +11001102 /*
1103 * Create socket early so it will exist before command gets run from
1104 * the parent.
1105 */
Damien Millerab2ec582014-07-18 15:04:47 +10001106 prev_mask = umask(0177);
Damien Miller7acefbb2014-07-18 14:11:24 +10001107 sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0);
Damien Miller95def091999-11-25 00:26:21 +11001108 if (sock < 0) {
Damien Miller7acefbb2014-07-18 14:11:24 +10001109 /* XXX - unix_listener() calls error() not perror() */
Darren Tucker1dee8682004-11-05 20:26:49 +11001110 *socket_name = '\0'; /* Don't unlink any existing file */
Damien Miller95def091999-11-25 00:26:21 +11001111 cleanup_exit(1);
Damien Miller792c5111999-10-29 09:47:09 +10001112 }
Damien Millerab2ec582014-07-18 15:04:47 +10001113 umask(prev_mask);
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001114
Damien Miller5428f641999-11-25 11:54:57 +11001115 /*
1116 * Fork, and have the parent execute the command, if any, or present
1117 * the socket data. The child continues as the authentication agent.
1118 */
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001119 if (D_flag || d_flag) {
1120 log_init(__progname,
1121 d_flag ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
1122 SYSLOG_FACILITY_AUTH, 1);
Ben Lindstromd94580c2001-07-04 03:48:02 +00001123 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1124 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
1125 SSH_AUTHSOCKET_ENV_NAME);
Ben Lindstromce0f6342002-06-11 16:42:49 +00001126 printf("echo Agent pid %ld;\n", (long)parent_pid);
dtucker@openbsd.org79394ed2015-12-11 02:29:03 +00001127 fflush(stdout);
Ben Lindstromd94580c2001-07-04 03:48:02 +00001128 goto skip;
1129 }
Damien Miller95def091999-11-25 00:26:21 +11001130 pid = fork();
1131 if (pid == -1) {
1132 perror("fork");
Damien Millerc653b892002-02-08 22:05:41 +11001133 cleanup_exit(1);
Damien Miller95def091999-11-25 00:26:21 +11001134 }
1135 if (pid != 0) { /* Parent - execute the given command. */
1136 close(sock);
Ben Lindstromce0f6342002-06-11 16:42:49 +00001137 snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
Damien Miller95def091999-11-25 00:26:21 +11001138 if (ac == 0) {
1139 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1140 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001141 SSH_AUTHSOCKET_ENV_NAME);
Damien Miller95def091999-11-25 00:26:21 +11001142 printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001143 SSH_AGENTPID_ENV_NAME);
Ben Lindstromce0f6342002-06-11 16:42:49 +00001144 printf("echo Agent pid %ld;\n", (long)pid);
Damien Miller95def091999-11-25 00:26:21 +11001145 exit(0);
1146 }
Damien Millere4340be2000-09-16 13:29:08 +11001147 if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
1148 setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
1149 perror("setenv");
1150 exit(1);
1151 }
Damien Miller95def091999-11-25 00:26:21 +11001152 execvp(av[0], av);
1153 perror(av[0]);
1154 exit(1);
1155 }
Damien Millerc653b892002-02-08 22:05:41 +11001156 /* child */
1157 log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
Ben Lindstrom3fdf8762001-07-22 20:40:24 +00001158
1159 if (setsid() == -1) {
Damien Millerc653b892002-02-08 22:05:41 +11001160 error("setsid: %s", strerror(errno));
Ben Lindstrom3fdf8762001-07-22 20:40:24 +00001161 cleanup_exit(1);
1162 }
1163
1164 (void)chdir("/");
Damien Miller6c711792003-01-24 11:36:23 +11001165 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1166 /* XXX might close listen socket */
1167 (void)dup2(fd, STDIN_FILENO);
1168 (void)dup2(fd, STDOUT_FILENO);
1169 (void)dup2(fd, STDERR_FILENO);
1170 if (fd > 2)
1171 close(fd);
1172 }
Damien Miller95def091999-11-25 00:26:21 +11001173
Ben Lindstrom2c467a22000-12-27 04:57:41 +00001174#ifdef HAVE_SETRLIMIT
Ben Lindstromc72745a2000-12-02 19:03:54 +00001175 /* deny core dumps, since memory contains unencrypted private keys */
1176 rlim.rlim_cur = rlim.rlim_max = 0;
1177 if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
Damien Millerc653b892002-02-08 22:05:41 +11001178 error("setrlimit RLIMIT_CORE: %s", strerror(errno));
Ben Lindstromc72745a2000-12-02 19:03:54 +00001179 cleanup_exit(1);
1180 }
Ben Lindstrom2c467a22000-12-27 04:57:41 +00001181#endif
Ben Lindstromd94580c2001-07-04 03:48:02 +00001182
1183skip:
Damien Miller7ea845e2010-02-12 09:21:02 +11001184
Damien Millerb1e967c2014-07-03 21:22:40 +10001185 cleanup_pid = getpid();
1186
Damien Miller7ea845e2010-02-12 09:21:02 +11001187#ifdef ENABLE_PKCS11
1188 pkcs11_init(0);
1189#endif
Damien Miller95def091999-11-25 00:26:21 +11001190 new_socket(AUTH_SOCKET, sock);
Darren Tucker2812dc92007-03-21 20:45:06 +11001191 if (ac > 0)
1192 parent_alive_interval = 10;
Damien Millerad833b32000-08-23 10:46:23 +10001193 idtab_init();
Damien Miller48bfa9c2001-07-14 12:12:55 +10001194 signal(SIGPIPE, SIG_IGN);
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001195 signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN);
Ben Lindstrom77808ab2001-01-26 05:10:34 +00001196 signal(SIGHUP, cleanup_handler);
1197 signal(SIGTERM, cleanup_handler);
Ben Lindstroma3d5a4c2001-07-18 15:58:08 +00001198 nalloc = 0;
1199
djm@openbsd.org786d5992016-11-30 03:07:37 +00001200 if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1)
djm@openbsd.orgd9521622015-12-01 23:29:24 +00001201 fatal("%s: pledge: %s", __progname, strerror(errno));
Damien Miller4626cba2016-01-08 14:24:56 +11001202 platform_pledge_agent();
djm@openbsd.orgd9521622015-12-01 23:29:24 +00001203
Damien Miller95def091999-11-25 00:26:21 +11001204 while (1) {
Darren Tucker2812dc92007-03-21 20:45:06 +11001205 prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
1206 result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
Darren Tuckercf0d2db2007-02-28 21:19:58 +11001207 saved_errno = errno;
Darren Tucker2812dc92007-03-21 20:45:06 +11001208 if (parent_alive_interval != 0)
1209 check_parent_exists();
1210 (void) reaper(); /* remove expired keys */
Darren Tuckercf0d2db2007-02-28 21:19:58 +11001211 if (result < 0) {
1212 if (saved_errno == EINTR)
Damien Miller95def091999-11-25 00:26:21 +11001213 continue;
Darren Tuckercf0d2db2007-02-28 21:19:58 +11001214 fatal("select: %s", strerror(saved_errno));
1215 } else if (result > 0)
1216 after_select(readsetp, writesetp);
Damien Miller95def091999-11-25 00:26:21 +11001217 }
1218 /* NOTREACHED */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001219}