blob: 07f19c53ad0df1bc2f49aa5a450850c32ff57d26 [file] [log] [blame]
djm@openbsd.org9a14c642019-10-31 21:23:19 +00001/* $OpenBSD: ssh-agent.c,v 1.239 2019/10/31 21:23:19 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>
djm@openbsd.org07da39f2019-10-31 21:22:01 +000044#include <sys/wait.h>
Damien Miller9aec9192006-08-05 10:57:45 +100045#ifdef HAVE_SYS_TIME_H
46# include <sys/time.h>
47#endif
Damien Miller574c41f2006-03-15 11:40:10 +110048#ifdef HAVE_SYS_UN_H
49# include <sys/un.h>
50#endif
Damien Miller9b481512002-09-12 10:43:29 +100051#include "openbsd-compat/sys-queue.h"
Damien Millere3b60b52006-07-10 21:08:03 +100052
Damien Miller1f0311c2014-05-15 14:24:09 +100053#ifdef WITH_OPENSSL
Damien Millere3476ed2006-07-24 14:13:33 +100054#include <openssl/evp.h>
Darren Tuckerbfaaf962008-02-28 19:13:52 +110055#include "openbsd-compat/openssl-compat.h"
Damien Miller1f0311c2014-05-15 14:24:09 +100056#endif
Damien Millere3476ed2006-07-24 14:13:33 +100057
Darren Tucker39972492006-07-12 22:22:46 +100058#include <errno.h>
Damien Miller57cf6382006-07-10 21:13:46 +100059#include <fcntl.h>
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +000060#include <limits.h>
Damien Miller03e20032006-03-15 11:16:59 +110061#ifdef HAVE_PATHS_H
Damien Millera9263d02006-03-15 11:18:26 +110062# include <paths.h>
Damien Miller03e20032006-03-15 11:16:59 +110063#endif
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +000064#ifdef HAVE_POLL_H
65# include <poll.h>
66#endif
Damien Miller6ff3cad2006-03-15 11:52:09 +110067#include <signal.h>
Damien Millerded319c2006-09-01 15:38:36 +100068#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100069#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100070#include <stdlib.h>
Damien Miller5598b4f2006-07-24 14:09:40 +100071#include <time.h>
Damien Millere3476ed2006-07-24 14:13:33 +100072#include <string.h>
Damien Millere6b3b612006-07-24 14:01:23 +100073#include <unistd.h>
Damien Millere97201f2015-05-21 17:55:15 +100074#ifdef HAVE_UTIL_H
75# include <util.h>
76#endif
Damien Miller6ff3cad2006-03-15 11:52:09 +110077
Damien Millerd7834352006-08-05 12:39:39 +100078#include "xmalloc.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100079#include "ssh.h"
markus@openbsd.org139ca812015-01-14 13:09:09 +000080#include "sshbuf.h"
81#include "sshkey.h"
Damien Miller994cf142000-07-21 10:19:44 +100082#include "authfd.h"
Damien Miller62cee002000-09-23 17:15:56 +110083#include "compat.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000084#include "log.h"
Damien Miller6c711792003-01-24 11:36:23 +110085#include "misc.h"
Damien Miller4a1c7aa2014-02-04 11:03:36 +110086#include "digest.h"
markus@openbsd.org139ca812015-01-14 13:09:09 +000087#include "ssherr.h"
djm@openbsd.org786d5992016-11-30 03:07:37 +000088#include "match.h"
djm@openbsd.org07da39f2019-10-31 21:22:01 +000089#include "msg.h"
90#include "pathnames.h"
Damien Miller7ea845e2010-02-12 09:21:02 +110091#include "ssh-pkcs11.h"
djm@openbsd.org07da39f2019-10-31 21:22:01 +000092#include "ssh-sk.h"
Ben Lindstrom3f471632001-07-04 03:53:15 +000093
djm@openbsd.org07da39f2019-10-31 21:22:01 +000094#ifndef DEFAULT_PROVIDER_WHITELIST
95# define DEFAULT_PROVIDER_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
djm@openbsd.org786d5992016-11-30 03:07:37 +000096#endif
97
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +000098/* Maximum accepted message length */
99#define AGENT_MAX_LEN (256*1024)
djm@openbsd.orgd6915882019-01-22 22:58:50 +0000100/* Maximum bytes to read from client socket */
101#define AGENT_RBUF_LEN (4096)
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000102
Ben Lindstrom65366a82001-12-06 16:32:47 +0000103typedef enum {
104 AUTH_UNUSED,
105 AUTH_SOCKET,
106 AUTH_CONNECTION
107} sock_type;
108
Damien Miller95def091999-11-25 00:26:21 +1100109typedef struct {
110 int fd;
Ben Lindstrom65366a82001-12-06 16:32:47 +0000111 sock_type type;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000112 struct sshbuf *input;
113 struct sshbuf *output;
114 struct sshbuf *request;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000115} SocketEntry;
116
Ben Lindstrom46c16222000-12-22 01:43:59 +0000117u_int sockets_alloc = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000118SocketEntry *sockets = NULL;
119
Damien Miller1a534ae2002-01-22 23:26:13 +1100120typedef struct identity {
121 TAILQ_ENTRY(identity) next;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000122 struct sshkey *key;
Damien Miller95def091999-11-25 00:26:21 +1100123 char *comment;
Damien Miller7ea845e2010-02-12 09:21:02 +1100124 char *provider;
Darren Tucker55119252013-06-02 07:43:59 +1000125 time_t death;
Damien Miller6c711792003-01-24 11:36:23 +1100126 u_int confirm;
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000127 char *sk_provider;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000128} Identity;
129
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000130struct idtable {
Damien Millerad833b32000-08-23 10:46:23 +1000131 int nentries;
Damien Miller1a534ae2002-01-22 23:26:13 +1100132 TAILQ_HEAD(idqueue, identity) idlist;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000133};
Damien Millerad833b32000-08-23 10:46:23 +1000134
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000135/* private key table */
136struct idtable *idtab;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000137
138int max_fd = 0;
139
140/* pid of shell == parent of agent */
Damien Miller166fca82000-04-20 07:42:21 +1000141pid_t parent_pid = -1;
Darren Tucker073f7952013-06-02 23:47:11 +1000142time_t parent_alive_interval = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000143
Damien Millerb1e967c2014-07-03 21:22:40 +1000144/* pid of process for which cleanup_socket is applicable */
145pid_t cleanup_pid = 0;
146
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000147/* pathname and directory for AUTH_SOCKET */
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +0000148char socket_name[PATH_MAX];
149char socket_dir[PATH_MAX];
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000150
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000151/* PKCS#11/Security key path whitelist */
152static char *provider_whitelist;
djm@openbsd.org786d5992016-11-30 03:07:37 +0000153
Ben Lindstrom2f717042002-06-06 21:52:03 +0000154/* locking */
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000155#define LOCK_SIZE 32
156#define LOCK_SALT_SIZE 16
157#define LOCK_ROUNDS 1
Ben Lindstrom2f717042002-06-06 21:52:03 +0000158int locked = 0;
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000159u_char lock_pwhash[LOCK_SIZE];
160u_char lock_salt[LOCK_SALT_SIZE];
Ben Lindstrom2f717042002-06-06 21:52:03 +0000161
Damien Miller95def091999-11-25 00:26:21 +1100162extern char *__progname;
Damien Miller95def091999-11-25 00:26:21 +1100163
Darren Tucker55119252013-06-02 07:43:59 +1000164/* Default lifetime in seconds (0 == forever) */
165static long lifetime = 0;
Damien Miller53d81482003-01-22 11:47:19 +1100166
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000167static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
168
Ben Lindstrombba81212001-06-25 05:01:22 +0000169static void
Damien Miller58f34862002-09-04 16:31:21 +1000170close_socket(SocketEntry *e)
171{
Damien Miller58f34862002-09-04 16:31:21 +1000172 close(e->fd);
173 e->fd = -1;
174 e->type = AUTH_UNUSED;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000175 sshbuf_free(e->input);
176 sshbuf_free(e->output);
177 sshbuf_free(e->request);
Damien Miller58f34862002-09-04 16:31:21 +1000178}
179
180static void
Damien Millerad833b32000-08-23 10:46:23 +1000181idtab_init(void)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000182{
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000183 idtab = xcalloc(1, sizeof(*idtab));
184 TAILQ_INIT(&idtab->idlist);
185 idtab->nentries = 0;
Damien Millerad833b32000-08-23 10:46:23 +1000186}
187
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000188static void
189free_identity(Identity *id)
190{
markus@openbsd.org139ca812015-01-14 13:09:09 +0000191 sshkey_free(id->key);
Darren Tuckera627d422013-06-02 07:31:17 +1000192 free(id->provider);
193 free(id->comment);
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000194 free(id->sk_provider);
Darren Tuckera627d422013-06-02 07:31:17 +1000195 free(id);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000196}
197
Damien Millerad833b32000-08-23 10:46:23 +1000198/* return matching private key for given public key */
Damien Miller1a534ae2002-01-22 23:26:13 +1100199static Identity *
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000200lookup_identity(struct sshkey *key)
Damien Millerad833b32000-08-23 10:46:23 +1000201{
Damien Miller1a534ae2002-01-22 23:26:13 +1100202 Identity *id;
203
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000204 TAILQ_FOREACH(id, &idtab->idlist, next) {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000205 if (sshkey_equal(key, id->key))
Damien Miller1a534ae2002-01-22 23:26:13 +1100206 return (id);
Damien Millerad833b32000-08-23 10:46:23 +1000207 }
Damien Miller1a534ae2002-01-22 23:26:13 +1100208 return (NULL);
209}
210
Damien Miller6c711792003-01-24 11:36:23 +1100211/* Check confirmation of keysign request */
212static int
213confirm_key(Identity *id)
214{
Darren Tuckerce327b62004-11-05 20:38:03 +1100215 char *p;
Damien Miller6c711792003-01-24 11:36:23 +1100216 int ret = -1;
217
markus@openbsd.org139ca812015-01-14 13:09:09 +0000218 p = sshkey_fingerprint(id->key, fingerprint_hash, SSH_FP_DEFAULT);
djm@openbsd.org9ce86c92015-01-28 22:36:00 +0000219 if (p != NULL &&
220 ask_permission("Allow use of key %s?\nKey fingerprint %s.",
Darren Tuckerce327b62004-11-05 20:38:03 +1100221 id->comment, p))
222 ret = 0;
Darren Tuckera627d422013-06-02 07:31:17 +1000223 free(p);
Darren Tuckerce327b62004-11-05 20:38:03 +1100224
Damien Miller6c711792003-01-24 11:36:23 +1100225 return (ret);
226}
227
markus@openbsd.org139ca812015-01-14 13:09:09 +0000228static void
229send_status(SocketEntry *e, int success)
230{
231 int r;
232
233 if ((r = sshbuf_put_u32(e->output, 1)) != 0 ||
234 (r = sshbuf_put_u8(e->output, success ?
235 SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0)
236 fatal("%s: buffer error: %s", __func__, ssh_err(r));
237}
238
Damien Millerad833b32000-08-23 10:46:23 +1000239/* send list of supported public keys to 'client' */
Ben Lindstrombba81212001-06-25 05:01:22 +0000240static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000241process_request_identities(SocketEntry *e)
Damien Millerad833b32000-08-23 10:46:23 +1000242{
Damien Miller1a534ae2002-01-22 23:26:13 +1100243 Identity *id;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000244 struct sshbuf *msg;
245 int r;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000246
markus@openbsd.org139ca812015-01-14 13:09:09 +0000247 if ((msg = sshbuf_new()) == NULL)
248 fatal("%s: sshbuf_new failed", __func__);
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000249 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
250 (r = sshbuf_put_u32(msg, idtab->nentries)) != 0)
markus@openbsd.org139ca812015-01-14 13:09:09 +0000251 fatal("%s: buffer error: %s", __func__, ssh_err(r));
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000252 TAILQ_FOREACH(id, &idtab->idlist, next) {
markus@openbsd.org1b11ea72018-02-23 15:58:37 +0000253 if ((r = sshkey_puts_opts(id->key, msg, SSHKEY_SERIALIZE_INFO))
254 != 0 ||
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000255 (r = sshbuf_put_cstring(msg, id->comment)) != 0) {
256 error("%s: put key/comment: %s", __func__,
djm@openbsd.org873d3e72017-04-30 23:18:44 +0000257 ssh_err(r));
258 continue;
Damien Millerad833b32000-08-23 10:46:23 +1000259 }
Damien Miller95def091999-11-25 00:26:21 +1100260 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000261 if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
262 fatal("%s: buffer error: %s", __func__, ssh_err(r));
263 sshbuf_free(msg);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000264}
265
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000266
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000267static char *
268agent_decode_alg(struct sshkey *key, u_int flags)
269{
270 if (key->type == KEY_RSA) {
271 if (flags & SSH_AGENT_RSA_SHA2_256)
272 return "rsa-sha2-256";
273 else if (flags & SSH_AGENT_RSA_SHA2_512)
274 return "rsa-sha2-512";
djm@openbsd.org2317ce42019-06-14 03:51:47 +0000275 } else if (key->type == KEY_RSA_CERT) {
276 if (flags & SSH_AGENT_RSA_SHA2_256)
277 return "rsa-sha2-256-cert-v01@openssh.com";
278 else if (flags & SSH_AGENT_RSA_SHA2_512)
279 return "rsa-sha2-512-cert-v01@openssh.com";
markus@openbsd.org76c9fbb2015-12-04 16:41:28 +0000280 }
281 return NULL;
282}
283
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000284static int
285provider_sign(const char *provider, struct sshkey *key,
286 u_char **sigp, size_t *lenp,
287 const u_char *data, size_t datalen,
288 const char *alg, u_int compat)
289{
290 int status, pair[2], r = SSH_ERR_INTERNAL_ERROR;
291 pid_t pid;
292 char *helper, *verbosity = NULL;
293 struct sshbuf *kbuf, *req, *resp;
294 u_char version;
295
296 debug3("%s: start for provider %s", __func__, provider);
297
298 *sigp = NULL;
299 *lenp = 0;
300
301 helper = getenv("SSH_SK_HELPER");
302 if (helper == NULL || strlen(helper) == 0)
303 helper = _PATH_SSH_SK_HELPER;
304 if (log_level_get() >= SYSLOG_LEVEL_DEBUG1)
305 verbosity = "-vvv";
306
307 /* Start helper */
308 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
309 error("socketpair: %s", strerror(errno));
310 return SSH_ERR_SYSTEM_ERROR;
311 }
312 if ((pid = fork()) == -1) {
313 error("fork: %s", strerror(errno));
314 close(pair[0]);
315 close(pair[1]);
316 return SSH_ERR_SYSTEM_ERROR;
317 }
318 if (pid == 0) {
319 if ((dup2(pair[1], STDIN_FILENO) == -1) ||
320 (dup2(pair[1], STDOUT_FILENO) == -1))
321 fatal("%s: dup2: %s", __func__, ssh_err(r));
322 close(pair[0]);
323 close(pair[1]);
324 closefrom(STDERR_FILENO + 1);
325 debug("%s: starting %s %s", __func__, helper,
326 verbosity == NULL ? "" : verbosity);
327 execlp(helper, helper, verbosity, (char *)NULL);
328 fatal("%s: execlp: %s", __func__, strerror(errno));
329 }
330 close(pair[1]);
331
332 if ((kbuf = sshbuf_new()) == NULL ||
333 (req = sshbuf_new()) == NULL ||
334 (resp = sshbuf_new()) == NULL)
335 fatal("%s: sshbuf_new failed", __func__);
336
337 if ((r = sshkey_private_serialize(key, kbuf)) != 0 ||
338 (r = sshbuf_put_stringb(req, kbuf)) != 0 ||
339 (r = sshbuf_put_cstring(req, provider)) != 0 ||
340 (r = sshbuf_put_string(req, data, datalen)) != 0 ||
341 (r = sshbuf_put_u32(req, compat)) != 0)
342 fatal("%s: compose: %s", __func__, ssh_err(r));
343 if ((r = ssh_msg_send(pair[0], SSH_SK_HELPER_VERSION, req)) != 0) {
344 error("%s: send: %s", __func__, ssh_err(r));
345 goto out;
346 }
347 if ((r = ssh_msg_recv(pair[0], resp)) != 0) {
348 error("%s: receive: %s", __func__, ssh_err(r));
349 goto out;
350 }
351 if ((r = sshbuf_get_u8(resp, &version)) != 0) {
352 error("%s: parse version: %s", __func__, ssh_err(r));
353 goto out;
354 }
355 if (version != SSH_SK_HELPER_VERSION) {
356 error("%s: unsupported version: got %u, expected %u",
357 __func__, version, SSH_SK_HELPER_VERSION);
358 r = SSH_ERR_INVALID_FORMAT;
359 goto out;
360 }
361 if ((r = sshbuf_get_string(resp, sigp, lenp)) != 0) {
362 error("%s: parse signature: %s", __func__, ssh_err(r));
363 r = SSH_ERR_INVALID_FORMAT;
364 goto out;
365 }
366 if (sshbuf_len(resp) != 0) {
367 error("%s: trailing data in response", __func__);
368 r = SSH_ERR_INVALID_FORMAT;
369 goto out;
370 }
371 /* success */
372 r = 0;
373 out:
374 while (waitpid(pid, &status, 0) == -1) {
375 if (errno != EINTR)
376 fatal("%s: waitpid: %s", __func__, ssh_err(r));
377 }
378 if (!WIFEXITED(status)) {
379 error("%s: helper %s exited abnormally", __func__, helper);
380 if (r == 0)
381 r = SSH_ERR_SYSTEM_ERROR;
382 } else if (WEXITSTATUS(status) != 0) {
383 error("%s: helper %s exited with non-zero exit status",
384 __func__, helper);
385 if (r == 0)
386 r = SSH_ERR_SYSTEM_ERROR;
387 }
388 if (r != 0) {
389 freezero(*sigp, *lenp);
390 *sigp = NULL;
391 *lenp = 0;
392 }
393 sshbuf_free(kbuf);
394 sshbuf_free(req);
395 sshbuf_free(resp);
396 return r;
397}
398
Damien Millerad833b32000-08-23 10:46:23 +1000399/* ssh2 only */
Ben Lindstrombba81212001-06-25 05:01:22 +0000400static void
Damien Millerad833b32000-08-23 10:46:23 +1000401process_sign_request2(SocketEntry *e)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000402{
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000403 const u_char *data;
404 u_char *signature = NULL;
405 size_t dlen, slen = 0;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000406 u_int compat = 0, flags;
407 int r, ok = -1;
408 struct sshbuf *msg;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000409 struct sshkey *key = NULL;
djm@openbsd.org0088c572015-01-14 19:33:41 +0000410 struct identity *id;
Damien Millerad833b32000-08-23 10:46:23 +1000411
djm@openbsd.org0088c572015-01-14 19:33:41 +0000412 if ((msg = sshbuf_new()) == NULL)
413 fatal("%s: sshbuf_new failed", __func__);
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000414 if ((r = sshkey_froms(e->request, &key)) != 0 ||
415 (r = sshbuf_get_string_direct(e->request, &data, &dlen)) != 0 ||
djm@openbsd.org@openbsd.org93c68a82017-11-15 00:13:40 +0000416 (r = sshbuf_get_u32(e->request, &flags)) != 0) {
417 error("%s: couldn't parse request: %s", __func__, ssh_err(r));
418 goto send;
419 }
420
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000421 if ((id = lookup_identity(key)) == NULL) {
djm@openbsd.org0088c572015-01-14 19:33:41 +0000422 verbose("%s: %s key not found", __func__, sshkey_type(key));
423 goto send;
424 }
425 if (id->confirm && confirm_key(id) != 0) {
426 verbose("%s: user refused key", __func__);
427 goto send;
428 }
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000429 if (id->sk_provider != NULL) {
430 if ((r = provider_sign(id->sk_provider, id->key, &signature,
431 &slen, data, dlen, agent_decode_alg(key, flags),
432 compat)) != 0) {
djm@openbsd.org9a14c642019-10-31 21:23:19 +0000433 error("%s: sign: %s", __func__, ssh_err(r));
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000434 goto send;
435 }
436 } else {
437 if ((r = sshkey_sign(id->key, &signature, &slen,
djm@openbsd.org9a14c642019-10-31 21:23:19 +0000438 data, dlen, agent_decode_alg(key, flags),
439 NULL, compat)) != 0) {
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000440 error("%s: sshkey_sign: %s", __func__, ssh_err(r));
441 goto send;
442 }
djm@openbsd.org0088c572015-01-14 19:33:41 +0000443 }
444 /* Success */
445 ok = 0;
446 send:
447 sshkey_free(key);
Damien Millerad833b32000-08-23 10:46:23 +1000448 if (ok == 0) {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000449 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 ||
450 (r = sshbuf_put_string(msg, signature, slen)) != 0)
451 fatal("%s: buffer error: %s", __func__, ssh_err(r));
452 } else if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
453 fatal("%s: buffer error: %s", __func__, ssh_err(r));
454
455 if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
456 fatal("%s: buffer error: %s", __func__, ssh_err(r));
457
458 sshbuf_free(msg);
Darren Tuckera627d422013-06-02 07:31:17 +1000459 free(signature);
Damien Millerad833b32000-08-23 10:46:23 +1000460}
461
462/* shared */
Ben Lindstrombba81212001-06-25 05:01:22 +0000463static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000464process_remove_identity(SocketEntry *e)
Damien Millerad833b32000-08-23 10:46:23 +1000465{
markus@openbsd.org139ca812015-01-14 13:09:09 +0000466 int r, success = 0;
467 struct sshkey *key = NULL;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000468 Identity *id;
Damien Miller7e8e8201999-11-16 13:37:16 +1100469
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000470 if ((r = sshkey_froms(e->request, &key)) != 0) {
471 error("%s: get key: %s", __func__, ssh_err(r));
472 goto done;
Damien Millerad833b32000-08-23 10:46:23 +1000473 }
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000474 if ((id = lookup_identity(key)) == NULL) {
475 debug("%s: key not found", __func__);
476 goto done;
Damien Millerad833b32000-08-23 10:46:23 +1000477 }
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000478 /* We have this key, free it. */
479 if (idtab->nentries < 1)
480 fatal("%s: internal error: nentries %d",
481 __func__, idtab->nentries);
482 TAILQ_REMOVE(&idtab->idlist, id, next);
483 free_identity(id);
484 idtab->nentries--;
485 sshkey_free(key);
486 success = 1;
487 done:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000488 send_status(e, success);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000489}
490
Ben Lindstrombba81212001-06-25 05:01:22 +0000491static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000492process_remove_all_identities(SocketEntry *e)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000493{
Damien Miller1a534ae2002-01-22 23:26:13 +1100494 Identity *id;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000495
Damien Miller95def091999-11-25 00:26:21 +1100496 /* Loop over all identities and clear the keys. */
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000497 for (id = TAILQ_FIRST(&idtab->idlist); id;
498 id = TAILQ_FIRST(&idtab->idlist)) {
499 TAILQ_REMOVE(&idtab->idlist, id, next);
Damien Miller1a534ae2002-01-22 23:26:13 +1100500 free_identity(id);
Damien Miller95def091999-11-25 00:26:21 +1100501 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000502
Damien Miller95def091999-11-25 00:26:21 +1100503 /* Mark that there are no identities. */
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000504 idtab->nentries = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000505
506 /* Send success. */
markus@openbsd.org139ca812015-01-14 13:09:09 +0000507 send_status(e, 1);
Damien Miller95def091999-11-25 00:26:21 +1100508}
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000509
Darren Tucker2812dc92007-03-21 20:45:06 +1100510/* removes expired keys and returns number of seconds until the next expiry */
Darren Tucker55119252013-06-02 07:43:59 +1000511static time_t
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000512reaper(void)
513{
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000514 time_t deadline = 0, now = monotime();
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000515 Identity *id, *nxt;
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000516
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000517 for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
518 nxt = TAILQ_NEXT(id, next);
519 if (id->death == 0)
520 continue;
521 if (now >= id->death) {
522 debug("expiring key '%s'", id->comment);
523 TAILQ_REMOVE(&idtab->idlist, id, next);
524 free_identity(id);
525 idtab->nentries--;
526 } else
527 deadline = (deadline == 0) ? id->death :
528 MINIMUM(deadline, id->death);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000529 }
Darren Tucker2812dc92007-03-21 20:45:06 +1100530 if (deadline == 0 || deadline <= now)
531 return 0;
532 else
533 return (deadline - now);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000534}
535
536static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000537process_add_identity(SocketEntry *e)
Damien Miller95def091999-11-25 00:26:21 +1100538{
Damien Miller4c7728c2007-10-26 14:25:31 +1000539 Identity *id;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000540 int success = 0, confirm = 0;
markus@openbsd.org1b11ea72018-02-23 15:58:37 +0000541 u_int seconds, maxsign;
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000542 char *fp, *comment = NULL, *ext_name = NULL, *sk_provider = NULL;
Darren Tucker55119252013-06-02 07:43:59 +1000543 time_t death = 0;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000544 struct sshkey *k = NULL;
545 u_char ctype;
546 int r = SSH_ERR_INTERNAL_ERROR;
Damien Miller95def091999-11-25 00:26:21 +1100547
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000548 if ((r = sshkey_private_deserialize(e->request, &k)) != 0 ||
549 k == NULL ||
markus@openbsd.org139ca812015-01-14 13:09:09 +0000550 (r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) {
551 error("%s: decode private key: %s", __func__, ssh_err(r));
552 goto err;
553 }
djm@openbsd.org4f7a56d2019-06-21 04:21:04 +0000554 if ((r = sshkey_shield_private(k)) != 0) {
555 error("%s: shield private key: %s", __func__, ssh_err(r));
556 goto err;
557 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000558 while (sshbuf_len(e->request)) {
559 if ((r = sshbuf_get_u8(e->request, &ctype)) != 0) {
560 error("%s: buffer error: %s", __func__, ssh_err(r));
561 goto err;
562 }
563 switch (ctype) {
Ben Lindstromc90f8a92002-06-21 00:06:54 +0000564 case SSH_AGENT_CONSTRAIN_LIFETIME:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000565 if ((r = sshbuf_get_u32(e->request, &seconds)) != 0) {
566 error("%s: bad lifetime constraint: %s",
567 __func__, ssh_err(r));
568 goto err;
569 }
570 death = monotime() + seconds;
Ben Lindstrom4eb4c4e2002-06-21 00:04:48 +0000571 break;
Damien Miller6c711792003-01-24 11:36:23 +1100572 case SSH_AGENT_CONSTRAIN_CONFIRM:
573 confirm = 1;
574 break;
markus@openbsd.org1b11ea72018-02-23 15:58:37 +0000575 case SSH_AGENT_CONSTRAIN_MAXSIGN:
576 if ((r = sshbuf_get_u32(e->request, &maxsign)) != 0) {
577 error("%s: bad maxsign constraint: %s",
578 __func__, ssh_err(r));
579 goto err;
580 }
581 if ((r = sshkey_enable_maxsign(k, maxsign)) != 0) {
582 error("%s: cannot enable maxsign: %s",
583 __func__, ssh_err(r));
584 goto err;
585 }
586 break;
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000587 case SSH_AGENT_CONSTRAIN_EXTENSION:
588 if ((r = sshbuf_get_cstring(e->request,
589 &ext_name, NULL)) != 0) {
590 error("%s: cannot parse extension: %s",
591 __func__, ssh_err(r));
592 goto err;
593 }
594 debug("%s: constraint ext %s", __func__, ext_name);
595 if (strcmp(ext_name, "sk-provider@openssh.com") == 0) {
596 if (sk_provider != NULL) {
597 error("%s already set", ext_name);
598 goto err;
599 }
600 if ((r = sshbuf_get_cstring(e->request,
601 &sk_provider, NULL)) != 0) {
602 error("%s: cannot parse %s: %s",
603 __func__, ext_name, ssh_err(r));
604 goto err;
605 }
606 } else {
607 error("%s: unsupported constraint \"%s\"",
608 __func__, ext_name);
609 goto err;
610 }
611 free(ext_name);
612 break;
Ben Lindstrom4eb4c4e2002-06-21 00:04:48 +0000613 default:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000614 error("%s: Unknown constraint %d", __func__, ctype);
615 err:
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000616 free(sk_provider);
617 free(ext_name);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000618 sshbuf_reset(e->request);
Darren Tuckera627d422013-06-02 07:31:17 +1000619 free(comment);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000620 sshkey_free(k);
Damien Miller1cfadab2008-06-30 00:05:21 +1000621 goto send;
Ben Lindstrom4eb4c4e2002-06-21 00:04:48 +0000622 }
623 }
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000624 if (sk_provider != NULL) {
625 if (sshkey_type_plain(k->type) != KEY_ECDSA_SK) {
626 error("Cannot add provider: %s is not a security key",
627 sshkey_type(k));
628 free(sk_provider);
629 goto send;
630 }
631 if (match_pattern_list(sk_provider,
632 provider_whitelist, 0) != 1) {
633 error("Refusing add key: provider %s not whitelisted",
634 sk_provider);
635 free(sk_provider);
636 goto send;
637 }
638 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000639
Damien Miller1cfadab2008-06-30 00:05:21 +1000640 success = 1;
Damien Miller53d81482003-01-22 11:47:19 +1100641 if (lifetime && !death)
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000642 death = monotime() + lifetime;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000643 if ((id = lookup_identity(k)) == NULL) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100644 id = xcalloc(1, sizeof(Identity));
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000645 TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000646 /* Increment the number of identities. */
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000647 idtab->nentries++;
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000648 } else {
markus@openbsd.org1b11ea72018-02-23 15:58:37 +0000649 /* key state might have been updated */
650 sshkey_free(id->key);
Darren Tuckera627d422013-06-02 07:31:17 +1000651 free(id->comment);
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000652 free(id->sk_provider);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000653 }
markus@openbsd.org1b11ea72018-02-23 15:58:37 +0000654 id->key = k;
Damien Miller4c7728c2007-10-26 14:25:31 +1000655 id->comment = comment;
656 id->death = death;
657 id->confirm = confirm;
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000658 id->sk_provider = sk_provider;
659
660 if ((fp = sshkey_fingerprint(k, SSH_FP_HASH_DEFAULT,
661 SSH_FP_DEFAULT)) == NULL)
662 fatal("%s: sshkey_fingerprint failed", __func__);
663 debug("%s: add %s %s \"%.100s\" (life: %u) (confirm: %u) "
664 "(provider: %s)", __func__, sshkey_ssh_name(k), fp, comment,
665 seconds, confirm, sk_provider == NULL ? "none" : sk_provider);
666 free(fp);
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000667send:
markus@openbsd.org139ca812015-01-14 13:09:09 +0000668 send_status(e, success);
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000669}
670
Ben Lindstrom2f717042002-06-06 21:52:03 +0000671/* XXX todo: encrypt sensitive data with passphrase */
672static void
673process_lock_agent(SocketEntry *e, int lock)
674{
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000675 int r, success = 0, delay;
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000676 char *passwd;
677 u_char passwdhash[LOCK_SIZE];
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000678 static u_int fail_count = 0;
679 size_t pwlen;
Ben Lindstrom2f717042002-06-06 21:52:03 +0000680
djm@openbsd.org@openbsd.org83a1e5d2017-11-15 02:10:16 +0000681 /*
682 * This is deliberately fatal: the user has requested that we lock,
683 * but we can't parse their request properly. The only safe thing to
684 * do is abort.
685 */
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000686 if ((r = sshbuf_get_cstring(e->request, &passwd, &pwlen)) != 0)
markus@openbsd.org139ca812015-01-14 13:09:09 +0000687 fatal("%s: buffer error: %s", __func__, ssh_err(r));
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000688 if (pwlen == 0) {
689 debug("empty password not supported");
690 } else if (locked && !lock) {
691 if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
692 passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0)
693 fatal("bcrypt_pbkdf");
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000694 if (timingsafe_bcmp(passwdhash, lock_pwhash, LOCK_SIZE) == 0) {
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000695 debug("agent unlocked");
696 locked = 0;
697 fail_count = 0;
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000698 explicit_bzero(lock_pwhash, sizeof(lock_pwhash));
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000699 success = 1;
700 } else {
701 /* delay in 0.1s increments up to 10s */
702 if (fail_count < 100)
703 fail_count++;
704 delay = 100000 * fail_count;
705 debug("unlock failed, delaying %0.1lf seconds",
706 (double)delay/1000000);
707 usleep(delay);
708 }
709 explicit_bzero(passwdhash, sizeof(passwdhash));
Ben Lindstrom2f717042002-06-06 21:52:03 +0000710 } else if (!locked && lock) {
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000711 debug("agent locked");
Ben Lindstrom2f717042002-06-06 21:52:03 +0000712 locked = 1;
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000713 arc4random_buf(lock_salt, sizeof(lock_salt));
714 if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
djm@openbsd.org1a31d022016-05-02 08:49:03 +0000715 lock_pwhash, sizeof(lock_pwhash), LOCK_ROUNDS) < 0)
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000716 fatal("bcrypt_pbkdf");
Ben Lindstrom2f717042002-06-06 21:52:03 +0000717 success = 1;
718 }
dtucker@openbsd.org9173d0f2015-05-15 05:44:21 +0000719 explicit_bzero(passwd, pwlen);
Darren Tuckera627d422013-06-02 07:31:17 +1000720 free(passwd);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000721 send_status(e, success);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000722}
723
724static void
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000725no_identities(SocketEntry *e)
Ben Lindstrom2f717042002-06-06 21:52:03 +0000726{
markus@openbsd.org139ca812015-01-14 13:09:09 +0000727 struct sshbuf *msg;
728 int r;
Ben Lindstrom2f717042002-06-06 21:52:03 +0000729
markus@openbsd.org139ca812015-01-14 13:09:09 +0000730 if ((msg = sshbuf_new()) == NULL)
731 fatal("%s: sshbuf_new failed", __func__);
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000732 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
markus@openbsd.org139ca812015-01-14 13:09:09 +0000733 (r = sshbuf_put_u32(msg, 0)) != 0 ||
734 (r = sshbuf_put_stringb(e->output, msg)) != 0)
735 fatal("%s: buffer error: %s", __func__, ssh_err(r));
736 sshbuf_free(msg);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000737}
Ben Lindstrom3f471632001-07-04 03:53:15 +0000738
Damien Miller7ea845e2010-02-12 09:21:02 +1100739#ifdef ENABLE_PKCS11
Ben Lindstrom3f471632001-07-04 03:53:15 +0000740static void
Damien Miller1cfadab2008-06-30 00:05:21 +1000741process_add_smartcard_key(SocketEntry *e)
Ben Lindstrom3f471632001-07-04 03:53:15 +0000742{
djm@openbsd.org@openbsd.org83a1e5d2017-11-15 02:10:16 +0000743 char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000744 int r, i, count = 0, success = 0, confirm = 0;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000745 u_int seconds;
Darren Tucker55119252013-06-02 07:43:59 +1000746 time_t death = 0;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000747 u_char type;
748 struct sshkey **keys = NULL, *k;
Ben Lindstrom822b6342002-06-23 21:38:49 +0000749 Identity *id;
Damien Miller9f0f5c62001-12-21 14:45:46 +1100750
markus@openbsd.org139ca812015-01-14 13:09:09 +0000751 if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
djm@openbsd.org@openbsd.org83a1e5d2017-11-15 02:10:16 +0000752 (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0) {
753 error("%s: buffer error: %s", __func__, ssh_err(r));
754 goto send;
755 }
Damien Millerd94f20d2003-06-11 22:06:33 +1000756
markus@openbsd.org139ca812015-01-14 13:09:09 +0000757 while (sshbuf_len(e->request)) {
djm@openbsd.org@openbsd.org83a1e5d2017-11-15 02:10:16 +0000758 if ((r = sshbuf_get_u8(e->request, &type)) != 0) {
759 error("%s: buffer error: %s", __func__, ssh_err(r));
760 goto send;
761 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000762 switch (type) {
Damien Millerd94f20d2003-06-11 22:06:33 +1000763 case SSH_AGENT_CONSTRAIN_LIFETIME:
djm@openbsd.org@openbsd.org83a1e5d2017-11-15 02:10:16 +0000764 if ((r = sshbuf_get_u32(e->request, &seconds)) != 0) {
765 error("%s: buffer error: %s",
markus@openbsd.org139ca812015-01-14 13:09:09 +0000766 __func__, ssh_err(r));
djm@openbsd.org@openbsd.org83a1e5d2017-11-15 02:10:16 +0000767 goto send;
768 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000769 death = monotime() + seconds;
Damien Millerd94f20d2003-06-11 22:06:33 +1000770 break;
771 case SSH_AGENT_CONSTRAIN_CONFIRM:
772 confirm = 1;
773 break;
774 default:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000775 error("%s: Unknown constraint type %d", __func__, type);
Damien Miller1cfadab2008-06-30 00:05:21 +1000776 goto send;
Damien Millerd94f20d2003-06-11 22:06:33 +1000777 }
778 }
djm@openbsd.org786d5992016-11-30 03:07:37 +0000779 if (realpath(provider, canonical_provider) == NULL) {
780 verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
781 provider, strerror(errno));
782 goto send;
783 }
djm@openbsd.org07da39f2019-10-31 21:22:01 +0000784 if (match_pattern_list(canonical_provider, provider_whitelist, 0) != 1) {
djm@openbsd.org786d5992016-11-30 03:07:37 +0000785 verbose("refusing PKCS#11 add of \"%.100s\": "
786 "provider not whitelisted", canonical_provider);
787 goto send;
788 }
789 debug("%s: add %.100s", __func__, canonical_provider);
Damien Millerd94f20d2003-06-11 22:06:33 +1000790 if (lifetime && !death)
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000791 death = monotime() + lifetime;
Damien Millerd94f20d2003-06-11 22:06:33 +1000792
djm@openbsd.org786d5992016-11-30 03:07:37 +0000793 count = pkcs11_add_provider(canonical_provider, pin, &keys);
Damien Miller7ea845e2010-02-12 09:21:02 +1100794 for (i = 0; i < count; i++) {
Ben Lindstrom0936a5b2002-03-26 03:17:42 +0000795 k = keys[i];
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000796 if (lookup_identity(k) == NULL) {
Damien Miller7ea845e2010-02-12 09:21:02 +1100797 id = xcalloc(1, sizeof(Identity));
Ben Lindstrom0936a5b2002-03-26 03:17:42 +0000798 id->key = k;
djm@openbsd.org786d5992016-11-30 03:07:37 +0000799 id->provider = xstrdup(canonical_provider);
800 id->comment = xstrdup(canonical_provider); /* XXX */
Damien Millerd94f20d2003-06-11 22:06:33 +1000801 id->death = death;
802 id->confirm = confirm;
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000803 TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
804 idtab->nentries++;
Ben Lindstrom0936a5b2002-03-26 03:17:42 +0000805 success = 1;
806 } else {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000807 sshkey_free(k);
Ben Lindstrom0936a5b2002-03-26 03:17:42 +0000808 }
809 keys[i] = NULL;
Ben Lindstrom3f471632001-07-04 03:53:15 +0000810 }
Ben Lindstrom3f471632001-07-04 03:53:15 +0000811send:
Darren Tuckera627d422013-06-02 07:31:17 +1000812 free(pin);
813 free(provider);
814 free(keys);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000815 send_status(e, success);
Ben Lindstrom3f471632001-07-04 03:53:15 +0000816}
817
818static void
819process_remove_smartcard_key(SocketEntry *e)
820{
djm@openbsd.org25f83762017-03-15 02:25:09 +0000821 char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000822 int r, success = 0;
Damien Miller7ea845e2010-02-12 09:21:02 +1100823 Identity *id, *nxt;
Ben Lindstrom3f471632001-07-04 03:53:15 +0000824
markus@openbsd.org139ca812015-01-14 13:09:09 +0000825 if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
djm@openbsd.org@openbsd.org83a1e5d2017-11-15 02:10:16 +0000826 (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0) {
827 error("%s: buffer error: %s", __func__, ssh_err(r));
828 goto send;
829 }
Darren Tuckera627d422013-06-02 07:31:17 +1000830 free(pin);
Ben Lindstrom3f471632001-07-04 03:53:15 +0000831
djm@openbsd.org25f83762017-03-15 02:25:09 +0000832 if (realpath(provider, canonical_provider) == NULL) {
833 verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
834 provider, strerror(errno));
835 goto send;
836 }
837
838 debug("%s: remove %.100s", __func__, canonical_provider);
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000839 for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
840 nxt = TAILQ_NEXT(id, next);
841 /* Skip file--based keys */
842 if (id->provider == NULL)
843 continue;
844 if (!strcmp(canonical_provider, id->provider)) {
845 TAILQ_REMOVE(&idtab->idlist, id, next);
846 free_identity(id);
847 idtab->nentries--;
Ben Lindstrom3f471632001-07-04 03:53:15 +0000848 }
Ben Lindstrom3f471632001-07-04 03:53:15 +0000849 }
djm@openbsd.org25f83762017-03-15 02:25:09 +0000850 if (pkcs11_del_provider(canonical_provider) == 0)
Damien Miller7ea845e2010-02-12 09:21:02 +1100851 success = 1;
852 else
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000853 error("%s: pkcs11_del_provider failed", __func__);
deraadt@openbsd.org1a321bf2017-03-15 03:52:30 +0000854send:
Darren Tuckera627d422013-06-02 07:31:17 +1000855 free(provider);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000856 send_status(e, success);
Ben Lindstrom3f471632001-07-04 03:53:15 +0000857}
Damien Miller7ea845e2010-02-12 09:21:02 +1100858#endif /* ENABLE_PKCS11 */
Ben Lindstrom3f471632001-07-04 03:53:15 +0000859
Damien Millerad833b32000-08-23 10:46:23 +1000860/* dispatch incoming messages */
861
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000862static int
863process_message(u_int socknum)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000864{
markus@openbsd.org139ca812015-01-14 13:09:09 +0000865 u_int msg_len;
866 u_char type;
867 const u_char *cp;
868 int r;
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000869 SocketEntry *e;
870
871 if (socknum >= sockets_alloc) {
872 fatal("%s: socket number %u >= allocated %u",
873 __func__, socknum, sockets_alloc);
874 }
875 e = &sockets[socknum];
Ben Lindstrom61d328a2002-06-06 21:54:57 +0000876
markus@openbsd.org139ca812015-01-14 13:09:09 +0000877 if (sshbuf_len(e->input) < 5)
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000878 return 0; /* Incomplete message header. */
markus@openbsd.org139ca812015-01-14 13:09:09 +0000879 cp = sshbuf_ptr(e->input);
880 msg_len = PEEK_U32(cp);
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000881 if (msg_len > AGENT_MAX_LEN) {
882 debug("%s: socket %u (fd=%d) message too long %u > %u",
883 __func__, socknum, e->fd, msg_len, AGENT_MAX_LEN);
884 return -1;
Damien Miller95def091999-11-25 00:26:21 +1100885 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000886 if (sshbuf_len(e->input) < msg_len + 4)
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000887 return 0; /* Incomplete message body. */
Ben Lindstrom21d1ed82002-06-06 21:48:57 +0000888
889 /* move the current input to e->request */
markus@openbsd.org139ca812015-01-14 13:09:09 +0000890 sshbuf_reset(e->request);
891 if ((r = sshbuf_get_stringb(e->input, e->request)) != 0 ||
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000892 (r = sshbuf_get_u8(e->request, &type)) != 0) {
893 if (r == SSH_ERR_MESSAGE_INCOMPLETE ||
894 r == SSH_ERR_STRING_TOO_LARGE) {
895 debug("%s: buffer error: %s", __func__, ssh_err(r));
896 return -1;
897 }
markus@openbsd.org139ca812015-01-14 13:09:09 +0000898 fatal("%s: buffer error: %s", __func__, ssh_err(r));
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000899 }
900
901 debug("%s: socket %u (fd=%d) type %d", __func__, socknum, e->fd, type);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000902
djm@openbsd.org001aa552018-04-10 00:10:49 +0000903 /* check whether agent is locked */
Ben Lindstrom2f717042002-06-06 21:52:03 +0000904 if (locked && type != SSH_AGENTC_UNLOCK) {
markus@openbsd.org139ca812015-01-14 13:09:09 +0000905 sshbuf_reset(e->request);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000906 switch (type) {
Ben Lindstrom2f717042002-06-06 21:52:03 +0000907 case SSH2_AGENTC_REQUEST_IDENTITIES:
908 /* send empty lists */
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000909 no_identities(e);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000910 break;
911 default:
912 /* send a fail message for all other request types */
markus@openbsd.org139ca812015-01-14 13:09:09 +0000913 send_status(e, 0);
Ben Lindstrom2f717042002-06-06 21:52:03 +0000914 }
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000915 return 0;
Ben Lindstrom2f717042002-06-06 21:52:03 +0000916 }
917
Damien Miller95def091999-11-25 00:26:21 +1100918 switch (type) {
Ben Lindstrom2f717042002-06-06 21:52:03 +0000919 case SSH_AGENTC_LOCK:
920 case SSH_AGENTC_UNLOCK:
921 process_lock_agent(e, type == SSH_AGENTC_LOCK);
922 break;
djm@openbsd.org2f04af92015-03-04 21:12:59 +0000923 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000924 process_remove_all_identities(e); /* safe for !WITH_SSH1 */
djm@openbsd.org2f04af92015-03-04 21:12:59 +0000925 break;
Damien Millerad833b32000-08-23 10:46:23 +1000926 /* ssh2 */
927 case SSH2_AGENTC_SIGN_REQUEST:
928 process_sign_request2(e);
929 break;
930 case SSH2_AGENTC_REQUEST_IDENTITIES:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000931 process_request_identities(e);
Damien Millerad833b32000-08-23 10:46:23 +1000932 break;
933 case SSH2_AGENTC_ADD_IDENTITY:
Ben Lindstrom2b266b72002-06-21 00:08:39 +0000934 case SSH2_AGENTC_ADD_ID_CONSTRAINED:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000935 process_add_identity(e);
Damien Millerad833b32000-08-23 10:46:23 +1000936 break;
937 case SSH2_AGENTC_REMOVE_IDENTITY:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000938 process_remove_identity(e);
Damien Millerad833b32000-08-23 10:46:23 +1000939 break;
940 case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
djm@openbsd.orgf4a6a882017-04-30 23:29:10 +0000941 process_remove_all_identities(e);
Damien Miller95def091999-11-25 00:26:21 +1100942 break;
Damien Miller7ea845e2010-02-12 09:21:02 +1100943#ifdef ENABLE_PKCS11
Ben Lindstrom3f471632001-07-04 03:53:15 +0000944 case SSH_AGENTC_ADD_SMARTCARD_KEY:
Damien Millerd94f20d2003-06-11 22:06:33 +1000945 case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
Ben Lindstrom3f471632001-07-04 03:53:15 +0000946 process_add_smartcard_key(e);
Damien Miller9f0f5c62001-12-21 14:45:46 +1100947 break;
Ben Lindstrom3f471632001-07-04 03:53:15 +0000948 case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
949 process_remove_smartcard_key(e);
Damien Miller9f0f5c62001-12-21 14:45:46 +1100950 break;
Damien Miller7ea845e2010-02-12 09:21:02 +1100951#endif /* ENABLE_PKCS11 */
Damien Miller95def091999-11-25 00:26:21 +1100952 default:
953 /* Unknown message. Respond with failure. */
954 error("Unknown message %d", type);
markus@openbsd.org139ca812015-01-14 13:09:09 +0000955 sshbuf_reset(e->request);
956 send_status(e, 0);
Damien Miller95def091999-11-25 00:26:21 +1100957 break;
958 }
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +0000959 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000960}
961
Ben Lindstrombba81212001-06-25 05:01:22 +0000962static void
Ben Lindstrom65366a82001-12-06 16:32:47 +0000963new_socket(sock_type type, int fd)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000964{
Darren Tuckerfb16b242003-09-22 21:04:23 +1000965 u_int i, old_alloc, new_alloc;
Ben Lindstrom822b6342002-06-23 21:38:49 +0000966
Damien Miller232711f2004-06-15 10:35:30 +1000967 set_nonblock(fd);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000968
Damien Miller95def091999-11-25 00:26:21 +1100969 if (fd > max_fd)
970 max_fd = fd;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000971
Damien Miller95def091999-11-25 00:26:21 +1100972 for (i = 0; i < sockets_alloc; i++)
973 if (sockets[i].type == AUTH_UNUSED) {
974 sockets[i].fd = fd;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000975 if ((sockets[i].input = sshbuf_new()) == NULL)
976 fatal("%s: sshbuf_new failed", __func__);
977 if ((sockets[i].output = sshbuf_new()) == NULL)
978 fatal("%s: sshbuf_new failed", __func__);
979 if ((sockets[i].request = sshbuf_new()) == NULL)
980 fatal("%s: sshbuf_new failed", __func__);
Darren Tuckerfb16b242003-09-22 21:04:23 +1000981 sockets[i].type = type;
Damien Miller95def091999-11-25 00:26:21 +1100982 return;
983 }
984 old_alloc = sockets_alloc;
Darren Tuckerfb16b242003-09-22 21:04:23 +1000985 new_alloc = sockets_alloc + 10;
deraadt@openbsd.org657a5fb2015-04-24 01:36:00 +0000986 sockets = xreallocarray(sockets, new_alloc, sizeof(sockets[0]));
Darren Tuckerfb16b242003-09-22 21:04:23 +1000987 for (i = old_alloc; i < new_alloc; i++)
Damien Miller95def091999-11-25 00:26:21 +1100988 sockets[i].type = AUTH_UNUSED;
Darren Tuckerfb16b242003-09-22 21:04:23 +1000989 sockets_alloc = new_alloc;
Damien Miller95def091999-11-25 00:26:21 +1100990 sockets[old_alloc].fd = fd;
markus@openbsd.org139ca812015-01-14 13:09:09 +0000991 if ((sockets[old_alloc].input = sshbuf_new()) == NULL)
992 fatal("%s: sshbuf_new failed", __func__);
993 if ((sockets[old_alloc].output = sshbuf_new()) == NULL)
994 fatal("%s: sshbuf_new failed", __func__);
995 if ((sockets[old_alloc].request = sshbuf_new()) == NULL)
996 fatal("%s: sshbuf_new failed", __func__);
Darren Tuckerfb16b242003-09-22 21:04:23 +1000997 sockets[old_alloc].type = type;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000998}
999
Ben Lindstrombba81212001-06-25 05:01:22 +00001000static int
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001001handle_socket_read(u_int socknum)
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001002{
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001003 struct sockaddr_un sunaddr;
1004 socklen_t slen;
1005 uid_t euid;
1006 gid_t egid;
1007 int fd;
1008
1009 slen = sizeof(sunaddr);
1010 fd = accept(sockets[socknum].fd, (struct sockaddr *)&sunaddr, &slen);
deraadt@openbsd.org4d28fa72019-06-28 13:35:04 +00001011 if (fd == -1) {
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001012 error("accept from AUTH_SOCKET: %s", strerror(errno));
1013 return -1;
1014 }
deraadt@openbsd.org4d28fa72019-06-28 13:35:04 +00001015 if (getpeereid(fd, &euid, &egid) == -1) {
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001016 error("getpeereid %d failed: %s", fd, strerror(errno));
1017 close(fd);
1018 return -1;
1019 }
1020 if ((euid != 0) && (getuid() != euid)) {
1021 error("uid mismatch: peer euid %u != uid %u",
1022 (u_int) euid, (u_int) getuid());
1023 close(fd);
1024 return -1;
1025 }
1026 new_socket(AUTH_CONNECTION, fd);
1027 return 0;
1028}
1029
1030static int
1031handle_conn_read(u_int socknum)
1032{
djm@openbsd.orgd6915882019-01-22 22:58:50 +00001033 char buf[AGENT_RBUF_LEN];
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001034 ssize_t len;
1035 int r;
1036
1037 if ((len = read(sockets[socknum].fd, buf, sizeof(buf))) <= 0) {
1038 if (len == -1) {
1039 if (errno == EAGAIN || errno == EINTR)
1040 return 0;
1041 error("%s: read error on socket %u (fd %d): %s",
1042 __func__, socknum, sockets[socknum].fd,
1043 strerror(errno));
1044 }
1045 return -1;
1046 }
1047 if ((r = sshbuf_put(sockets[socknum].input, buf, len)) != 0)
1048 fatal("%s: buffer error: %s", __func__, ssh_err(r));
1049 explicit_bzero(buf, sizeof(buf));
1050 process_message(socknum);
1051 return 0;
1052}
1053
1054static int
1055handle_conn_write(u_int socknum)
1056{
1057 ssize_t len;
1058 int r;
1059
1060 if (sshbuf_len(sockets[socknum].output) == 0)
1061 return 0; /* shouldn't happen */
1062 if ((len = write(sockets[socknum].fd,
1063 sshbuf_ptr(sockets[socknum].output),
1064 sshbuf_len(sockets[socknum].output))) <= 0) {
1065 if (len == -1) {
1066 if (errno == EAGAIN || errno == EINTR)
1067 return 0;
1068 error("%s: read error on socket %u (fd %d): %s",
1069 __func__, socknum, sockets[socknum].fd,
1070 strerror(errno));
1071 }
1072 return -1;
1073 }
1074 if ((r = sshbuf_consume(sockets[socknum].output, len)) != 0)
1075 fatal("%s: buffer error: %s", __func__, ssh_err(r));
1076 return 0;
1077}
1078
1079static void
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001080after_poll(struct pollfd *pfd, size_t npfd, u_int maxfds)
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001081{
1082 size_t i;
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001083 u_int socknum, activefds = npfd;
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001084
1085 for (i = 0; i < npfd; i++) {
1086 if (pfd[i].revents == 0)
1087 continue;
1088 /* Find sockets entry */
1089 for (socknum = 0; socknum < sockets_alloc; socknum++) {
1090 if (sockets[socknum].type != AUTH_SOCKET &&
1091 sockets[socknum].type != AUTH_CONNECTION)
1092 continue;
1093 if (pfd[i].fd == sockets[socknum].fd)
1094 break;
1095 }
1096 if (socknum >= sockets_alloc) {
1097 error("%s: no socket for fd %d", __func__, pfd[i].fd);
1098 continue;
1099 }
1100 /* Process events */
1101 switch (sockets[socknum].type) {
1102 case AUTH_SOCKET:
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001103 if ((pfd[i].revents & (POLLIN|POLLERR)) == 0)
1104 break;
1105 if (npfd > maxfds) {
1106 debug3("out of fds (active %u >= limit %u); "
1107 "skipping accept", activefds, maxfds);
1108 break;
1109 }
1110 if (handle_socket_read(socknum) == 0)
1111 activefds++;
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001112 break;
1113 case AUTH_CONNECTION:
1114 if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
1115 handle_conn_read(socknum) != 0) {
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001116 goto close_sock;
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001117 }
1118 if ((pfd[i].revents & (POLLOUT|POLLHUP)) != 0 &&
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001119 handle_conn_write(socknum) != 0) {
1120 close_sock:
1121 if (activefds == 0)
1122 fatal("activefds == 0 at close_sock");
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001123 close_socket(&sockets[socknum]);
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001124 activefds--;
1125 break;
1126 }
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001127 break;
1128 default:
1129 break;
1130 }
1131 }
1132}
1133
1134static int
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001135prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001136{
1137 struct pollfd *pfd = *pfdp;
1138 size_t i, j, npfd = 0;
Darren Tucker55119252013-06-02 07:43:59 +10001139 time_t deadline;
djm@openbsd.orgd6915882019-01-22 22:58:50 +00001140 int r;
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001141
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001142 /* Count active sockets */
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001143 for (i = 0; i < sockets_alloc; i++) {
Damien Miller95def091999-11-25 00:26:21 +11001144 switch (sockets[i].type) {
1145 case AUTH_SOCKET:
1146 case AUTH_CONNECTION:
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001147 npfd++;
Damien Miller95def091999-11-25 00:26:21 +11001148 break;
1149 case AUTH_UNUSED:
1150 break;
1151 default:
1152 fatal("Unknown socket type %d", sockets[i].type);
1153 break;
1154 }
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001155 }
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001156 if (npfd != *npfdp &&
1157 (pfd = recallocarray(pfd, *npfdp, npfd, sizeof(*pfd))) == NULL)
1158 fatal("%s: recallocarray failed", __func__);
1159 *pfdp = pfd;
1160 *npfdp = npfd;
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001161
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001162 for (i = j = 0; i < sockets_alloc; i++) {
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001163 switch (sockets[i].type) {
1164 case AUTH_SOCKET:
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001165 if (npfd > maxfds) {
1166 debug3("out of fds (active %zu >= limit %u); "
1167 "skipping arming listener", npfd, maxfds);
1168 break;
1169 }
1170 pfd[j].fd = sockets[i].fd;
1171 pfd[j].revents = 0;
1172 pfd[j].events = POLLIN;
1173 j++;
1174 break;
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001175 case AUTH_CONNECTION:
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001176 pfd[j].fd = sockets[i].fd;
1177 pfd[j].revents = 0;
djm@openbsd.orgd6915882019-01-22 22:58:50 +00001178 /*
1179 * Only prepare to read if we can handle a full-size
1180 * input read buffer and enqueue a max size reply..
1181 */
1182 if ((r = sshbuf_check_reserve(sockets[i].input,
1183 AGENT_RBUF_LEN)) == 0 &&
1184 (r = sshbuf_check_reserve(sockets[i].output,
1185 AGENT_MAX_LEN)) == 0)
1186 pfd[j].events = POLLIN;
1187 else if (r != SSH_ERR_NO_BUFFER_SPACE) {
1188 fatal("%s: buffer error: %s",
1189 __func__, ssh_err(r));
1190 }
markus@openbsd.org139ca812015-01-14 13:09:09 +00001191 if (sshbuf_len(sockets[i].output) > 0)
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001192 pfd[j].events |= POLLOUT;
1193 j++;
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001194 break;
1195 default:
1196 break;
1197 }
1198 }
Darren Tucker2812dc92007-03-21 20:45:06 +11001199 deadline = reaper();
1200 if (parent_alive_interval != 0)
1201 deadline = (deadline == 0) ? parent_alive_interval :
deraadt@openbsd.org9136ec12016-09-12 01:22:38 +00001202 MINIMUM(deadline, parent_alive_interval);
Darren Tucker2812dc92007-03-21 20:45:06 +11001203 if (deadline == 0) {
djm@openbsd.org9f0e44e2017-07-24 04:34:28 +00001204 *timeoutp = -1; /* INFTIM */
Darren Tucker2812dc92007-03-21 20:45:06 +11001205 } else {
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001206 if (deadline > INT_MAX / 1000)
1207 *timeoutp = INT_MAX / 1000;
1208 else
1209 *timeoutp = deadline * 1000;
Darren Tucker2812dc92007-03-21 20:45:06 +11001210 }
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001211 return (1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001212}
1213
Ben Lindstrombba81212001-06-25 05:01:22 +00001214static void
Darren Tucker6fa8abd2003-09-22 21:10:21 +10001215cleanup_socket(void)
Damien Miller792c5111999-10-29 09:47:09 +10001216{
Damien Millerb1e967c2014-07-03 21:22:40 +10001217 if (cleanup_pid != 0 && getpid() != cleanup_pid)
1218 return;
1219 debug("%s: cleanup", __func__);
Ben Lindstrom77808ab2001-01-26 05:10:34 +00001220 if (socket_name[0])
1221 unlink(socket_name);
1222 if (socket_dir[0])
1223 rmdir(socket_dir);
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001224}
1225
Darren Tucker3e33cec2003-10-02 16:12:36 +10001226void
Damien Miller792c5111999-10-29 09:47:09 +10001227cleanup_exit(int i)
1228{
Darren Tucker6fa8abd2003-09-22 21:10:21 +10001229 cleanup_socket();
1230 _exit(i);
Damien Miller792c5111999-10-29 09:47:09 +10001231}
1232
Damien Miller1c13bd82006-03-26 14:28:14 +11001233/*ARGSUSED*/
Ben Lindstrombba81212001-06-25 05:01:22 +00001234static void
Ben Lindstrom77808ab2001-01-26 05:10:34 +00001235cleanup_handler(int sig)
1236{
Darren Tucker6fa8abd2003-09-22 21:10:21 +10001237 cleanup_socket();
Damien Miller7ea845e2010-02-12 09:21:02 +11001238#ifdef ENABLE_PKCS11
1239 pkcs11_terminate();
1240#endif
Ben Lindstrom77808ab2001-01-26 05:10:34 +00001241 _exit(2);
1242}
1243
Ben Lindstrombba81212001-06-25 05:01:22 +00001244static void
Darren Tucker2812dc92007-03-21 20:45:06 +11001245check_parent_exists(void)
Ben Lindstrom0250da02001-07-22 20:44:00 +00001246{
Darren Tucker3e78a512011-06-03 14:14:16 +10001247 /*
1248 * If our parent has exited then getppid() will return (pid_t)1,
1249 * so testing for that should be safe.
1250 */
1251 if (parent_pid != -1 && getppid() != parent_pid) {
Ben Lindstrom0250da02001-07-22 20:44:00 +00001252 /* printf("Parent has died - Authentication agent exiting.\n"); */
Darren Tucker2812dc92007-03-21 20:45:06 +11001253 cleanup_socket();
1254 _exit(2);
Ben Lindstrom0250da02001-07-22 20:44:00 +00001255 }
Ben Lindstrom0250da02001-07-22 20:44:00 +00001256}
1257
1258static void
Ben Lindstrom28072eb2001-02-10 23:13:41 +00001259usage(void)
Damien Miller792c5111999-10-29 09:47:09 +10001260{
Damien Millerf0858de2014-04-20 13:01:30 +10001261 fprintf(stderr,
jmc@openbsd.orgb7ca2762015-04-24 06:26:49 +00001262 "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n"
djm@openbsd.org07da39f2019-10-31 21:22:01 +00001263 " [-P provider_whitelist] [-t life] [command [arg ...]]\n"
Damien Millerf0858de2014-04-20 13:01:30 +10001264 " ssh-agent [-c | -s] -k\n");
Damien Miller95def091999-11-25 00:26:21 +11001265 exit(1);
Damien Miller792c5111999-10-29 09:47:09 +10001266}
1267
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001268int
1269main(int ac, char **av)
1270{
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001271 int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0;
Darren Tuckercf0d2db2007-02-28 21:19:58 +11001272 int sock, fd, ch, result, saved_errno;
Ben Lindstrom822b6342002-06-23 21:38:49 +00001273 char *shell, *format, *pidstr, *agentsocket = NULL;
Ben Lindstrom2c467a22000-12-27 04:57:41 +00001274#ifdef HAVE_SETRLIMIT
Ben Lindstromc72745a2000-12-02 19:03:54 +00001275 struct rlimit rlim;
Ben Lindstrom2c467a22000-12-27 04:57:41 +00001276#endif
Damien Miller615f9392000-05-17 22:53:33 +10001277 extern int optind;
Ben Lindstrom883844d2002-06-23 00:20:50 +00001278 extern char *optarg;
Ben Lindstrom822b6342002-06-23 21:38:49 +00001279 pid_t pid;
1280 char pidstrbuf[1 + 3 * sizeof pid];
Darren Tucker90133232009-06-21 17:50:15 +10001281 size_t len;
Damien Millerab2ec582014-07-18 15:04:47 +10001282 mode_t prev_mask;
djm@openbsd.org9f0e44e2017-07-24 04:34:28 +00001283 int timeout = -1; /* INFTIM */
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001284 struct pollfd *pfd = NULL;
1285 size_t npfd = 0;
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001286 u_int maxfds;
Kevin Stevesde41bc62000-12-14 00:04:08 +00001287
Darren Tuckerce321d82005-10-03 18:11:24 +10001288 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1289 sanitise_stdfd();
1290
Damien Miller6cffb9a2002-09-04 16:20:26 +10001291 /* drop */
1292 setegid(getgid());
1293 setgid(getgid());
1294
Darren Tucker0fb7f592016-06-09 16:23:07 +10001295 platform_disable_tracing(0); /* strict=no */
Damien Miller6c4914a2004-03-03 11:08:59 +11001296
Darren Tucker7694e9d2019-10-28 17:05:36 +11001297#ifdef RLIMIT_NOFILE
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001298 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
1299 fatal("%s: getrlimit: %s", __progname, strerror(errno));
Darren Tucker7694e9d2019-10-28 17:05:36 +11001300#endif
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001301
Damien Miller59d3d5b2003-08-22 09:34:41 +10001302 __progname = ssh_get_progname(av[0]);
Damien Miller60bc5172001-03-19 09:38:15 +11001303 seed_rng();
Kevin Stevesef4eea92001-02-05 12:42:17 +00001304
djm@openbsd.org786d5992016-11-30 03:07:37 +00001305 while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) {
Damien Miller95def091999-11-25 00:26:21 +11001306 switch (ch) {
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001307 case 'E':
1308 fingerprint_hash = ssh_digest_alg_by_name(optarg);
1309 if (fingerprint_hash == -1)
1310 fatal("Invalid hash algorithm \"%s\"", optarg);
1311 break;
Damien Miller95def091999-11-25 00:26:21 +11001312 case 'c':
1313 if (s_flag)
1314 usage();
1315 c_flag++;
1316 break;
1317 case 'k':
1318 k_flag++;
1319 break;
djm@openbsd.org786d5992016-11-30 03:07:37 +00001320 case 'P':
djm@openbsd.org07da39f2019-10-31 21:22:01 +00001321 if (provider_whitelist != NULL)
djm@openbsd.org786d5992016-11-30 03:07:37 +00001322 fatal("-P option already specified");
djm@openbsd.org07da39f2019-10-31 21:22:01 +00001323 provider_whitelist = xstrdup(optarg);
djm@openbsd.org786d5992016-11-30 03:07:37 +00001324 break;
Damien Miller95def091999-11-25 00:26:21 +11001325 case 's':
1326 if (c_flag)
1327 usage();
1328 s_flag++;
1329 break;
Ben Lindstromd94580c2001-07-04 03:48:02 +00001330 case 'd':
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001331 if (d_flag || D_flag)
Ben Lindstromd94580c2001-07-04 03:48:02 +00001332 usage();
1333 d_flag++;
1334 break;
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001335 case 'D':
1336 if (d_flag || D_flag)
1337 usage();
1338 D_flag++;
1339 break;
Ben Lindstromb7788f32002-06-06 21:46:08 +00001340 case 'a':
1341 agentsocket = optarg;
1342 break;
Damien Miller53d81482003-01-22 11:47:19 +11001343 case 't':
1344 if ((lifetime = convtime(optarg)) == -1) {
1345 fprintf(stderr, "Invalid lifetime\n");
1346 usage();
1347 }
1348 break;
Damien Miller95def091999-11-25 00:26:21 +11001349 default:
1350 usage();
1351 }
Damien Miller792c5111999-10-29 09:47:09 +10001352 }
Damien Miller95def091999-11-25 00:26:21 +11001353 ac -= optind;
1354 av += optind;
Damien Miller792c5111999-10-29 09:47:09 +10001355
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001356 if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag))
Damien Miller95def091999-11-25 00:26:21 +11001357 usage();
Damien Miller792c5111999-10-29 09:47:09 +10001358
djm@openbsd.org07da39f2019-10-31 21:22:01 +00001359 if (provider_whitelist == NULL)
1360 provider_whitelist = xstrdup(DEFAULT_PROVIDER_WHITELIST);
djm@openbsd.org786d5992016-11-30 03:07:37 +00001361
Ben Lindstromeecdf232002-04-02 21:03:51 +00001362 if (ac == 0 && !c_flag && !s_flag) {
Damien Miller95def091999-11-25 00:26:21 +11001363 shell = getenv("SHELL");
Darren Tucker90133232009-06-21 17:50:15 +10001364 if (shell != NULL && (len = strlen(shell)) > 2 &&
1365 strncmp(shell + len - 3, "csh", 3) == 0)
Damien Miller95def091999-11-25 00:26:21 +11001366 c_flag = 1;
Damien Miller792c5111999-10-29 09:47:09 +10001367 }
Damien Miller95def091999-11-25 00:26:21 +11001368 if (k_flag) {
Damien Miller89c3fe42006-03-31 23:11:28 +11001369 const char *errstr = NULL;
1370
Damien Miller95def091999-11-25 00:26:21 +11001371 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
1372 if (pidstr == NULL) {
1373 fprintf(stderr, "%s not set, cannot kill agent\n",
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001374 SSH_AGENTPID_ENV_NAME);
Damien Miller95def091999-11-25 00:26:21 +11001375 exit(1);
1376 }
Damien Miller89c3fe42006-03-31 23:11:28 +11001377 pid = (int)strtonum(pidstr, 2, INT_MAX, &errstr);
1378 if (errstr) {
1379 fprintf(stderr,
1380 "%s=\"%s\", which is not a good PID: %s\n",
1381 SSH_AGENTPID_ENV_NAME, pidstr, errstr);
Damien Miller95def091999-11-25 00:26:21 +11001382 exit(1);
1383 }
1384 if (kill(pid, SIGTERM) == -1) {
1385 perror("kill");
1386 exit(1);
1387 }
1388 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
1389 printf(format, SSH_AUTHSOCKET_ENV_NAME);
1390 printf(format, SSH_AGENTPID_ENV_NAME);
Ben Lindstromce0f6342002-06-11 16:42:49 +00001391 printf("echo Agent pid %ld killed;\n", (long)pid);
Damien Miller95def091999-11-25 00:26:21 +11001392 exit(0);
Damien Miller792c5111999-10-29 09:47:09 +10001393 }
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001394
1395 /*
1396 * Minimum file descriptors:
1397 * stdio (3) + listener (1) + syslog (1 maybe) + connection (1) +
1398 * a few spare for libc / stack protectors / sanitisers, etc.
1399 */
1400#define SSH_AGENT_MIN_FDS (3+1+1+1+4)
1401 if (rlim.rlim_cur < SSH_AGENT_MIN_FDS)
djm@openbsd.org960e7c62018-11-09 02:57:58 +00001402 fatal("%s: file descriptor rlimit %lld too low (minimum %u)",
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001403 __progname, (long long)rlim.rlim_cur, SSH_AGENT_MIN_FDS);
1404 maxfds = rlim.rlim_cur - SSH_AGENT_MIN_FDS;
1405
Damien Miller95def091999-11-25 00:26:21 +11001406 parent_pid = getpid();
1407
Ben Lindstromb7788f32002-06-06 21:46:08 +00001408 if (agentsocket == NULL) {
1409 /* Create private directory for agent socket */
Damien Miller2cd62932010-12-01 11:50:35 +11001410 mktemp_proto(socket_dir, sizeof(socket_dir));
Ben Lindstromb7788f32002-06-06 21:46:08 +00001411 if (mkdtemp(socket_dir) == NULL) {
1412 perror("mkdtemp: private socket dir");
1413 exit(1);
1414 }
Ben Lindstromce0f6342002-06-11 16:42:49 +00001415 snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
1416 (long)parent_pid);
Ben Lindstromb7788f32002-06-06 21:46:08 +00001417 } else {
1418 /* Try to use specified agent socket */
1419 socket_dir[0] = '\0';
1420 strlcpy(socket_name, agentsocket, sizeof socket_name);
Damien Miller792c5111999-10-29 09:47:09 +10001421 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001422
Damien Miller5428f641999-11-25 11:54:57 +11001423 /*
1424 * Create socket early so it will exist before command gets run from
1425 * the parent.
1426 */
Damien Millerab2ec582014-07-18 15:04:47 +10001427 prev_mask = umask(0177);
Damien Miller7acefbb2014-07-18 14:11:24 +10001428 sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0);
Damien Miller95def091999-11-25 00:26:21 +11001429 if (sock < 0) {
Damien Miller7acefbb2014-07-18 14:11:24 +10001430 /* XXX - unix_listener() calls error() not perror() */
Darren Tucker1dee8682004-11-05 20:26:49 +11001431 *socket_name = '\0'; /* Don't unlink any existing file */
Damien Miller95def091999-11-25 00:26:21 +11001432 cleanup_exit(1);
Damien Miller792c5111999-10-29 09:47:09 +10001433 }
Damien Millerab2ec582014-07-18 15:04:47 +10001434 umask(prev_mask);
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001435
Damien Miller5428f641999-11-25 11:54:57 +11001436 /*
1437 * Fork, and have the parent execute the command, if any, or present
1438 * the socket data. The child continues as the authentication agent.
1439 */
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001440 if (D_flag || d_flag) {
1441 log_init(__progname,
1442 d_flag ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
1443 SYSLOG_FACILITY_AUTH, 1);
Ben Lindstromd94580c2001-07-04 03:48:02 +00001444 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1445 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
1446 SSH_AUTHSOCKET_ENV_NAME);
Ben Lindstromce0f6342002-06-11 16:42:49 +00001447 printf("echo Agent pid %ld;\n", (long)parent_pid);
dtucker@openbsd.org79394ed2015-12-11 02:29:03 +00001448 fflush(stdout);
Ben Lindstromd94580c2001-07-04 03:48:02 +00001449 goto skip;
1450 }
Damien Miller95def091999-11-25 00:26:21 +11001451 pid = fork();
1452 if (pid == -1) {
1453 perror("fork");
Damien Millerc653b892002-02-08 22:05:41 +11001454 cleanup_exit(1);
Damien Miller95def091999-11-25 00:26:21 +11001455 }
1456 if (pid != 0) { /* Parent - execute the given command. */
1457 close(sock);
Ben Lindstromce0f6342002-06-11 16:42:49 +00001458 snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
Damien Miller95def091999-11-25 00:26:21 +11001459 if (ac == 0) {
1460 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1461 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001462 SSH_AUTHSOCKET_ENV_NAME);
Damien Miller95def091999-11-25 00:26:21 +11001463 printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
Ben Lindstrom226cfa02001-01-22 05:34:40 +00001464 SSH_AGENTPID_ENV_NAME);
Ben Lindstromce0f6342002-06-11 16:42:49 +00001465 printf("echo Agent pid %ld;\n", (long)pid);
Damien Miller95def091999-11-25 00:26:21 +11001466 exit(0);
1467 }
Damien Millere4340be2000-09-16 13:29:08 +11001468 if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
1469 setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
1470 perror("setenv");
1471 exit(1);
1472 }
Damien Miller95def091999-11-25 00:26:21 +11001473 execvp(av[0], av);
1474 perror(av[0]);
1475 exit(1);
1476 }
Damien Millerc653b892002-02-08 22:05:41 +11001477 /* child */
1478 log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
Ben Lindstrom3fdf8762001-07-22 20:40:24 +00001479
1480 if (setsid() == -1) {
Damien Millerc653b892002-02-08 22:05:41 +11001481 error("setsid: %s", strerror(errno));
Ben Lindstrom3fdf8762001-07-22 20:40:24 +00001482 cleanup_exit(1);
1483 }
1484
1485 (void)chdir("/");
Damien Miller6c711792003-01-24 11:36:23 +11001486 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1487 /* XXX might close listen socket */
1488 (void)dup2(fd, STDIN_FILENO);
1489 (void)dup2(fd, STDOUT_FILENO);
1490 (void)dup2(fd, STDERR_FILENO);
1491 if (fd > 2)
1492 close(fd);
1493 }
Damien Miller95def091999-11-25 00:26:21 +11001494
Ben Lindstrom2c467a22000-12-27 04:57:41 +00001495#ifdef HAVE_SETRLIMIT
Ben Lindstromc72745a2000-12-02 19:03:54 +00001496 /* deny core dumps, since memory contains unencrypted private keys */
1497 rlim.rlim_cur = rlim.rlim_max = 0;
deraadt@openbsd.org4d28fa72019-06-28 13:35:04 +00001498 if (setrlimit(RLIMIT_CORE, &rlim) == -1) {
Damien Millerc653b892002-02-08 22:05:41 +11001499 error("setrlimit RLIMIT_CORE: %s", strerror(errno));
Ben Lindstromc72745a2000-12-02 19:03:54 +00001500 cleanup_exit(1);
1501 }
Ben Lindstrom2c467a22000-12-27 04:57:41 +00001502#endif
Ben Lindstromd94580c2001-07-04 03:48:02 +00001503
1504skip:
Damien Miller7ea845e2010-02-12 09:21:02 +11001505
Damien Millerb1e967c2014-07-03 21:22:40 +10001506 cleanup_pid = getpid();
1507
Damien Miller7ea845e2010-02-12 09:21:02 +11001508#ifdef ENABLE_PKCS11
1509 pkcs11_init(0);
1510#endif
Damien Miller95def091999-11-25 00:26:21 +11001511 new_socket(AUTH_SOCKET, sock);
Darren Tucker2812dc92007-03-21 20:45:06 +11001512 if (ac > 0)
1513 parent_alive_interval = 10;
Damien Millerad833b32000-08-23 10:46:23 +10001514 idtab_init();
Damien Miller48bfa9c2001-07-14 12:12:55 +10001515 signal(SIGPIPE, SIG_IGN);
djm@openbsd.org2ea97462015-04-24 05:26:44 +00001516 signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN);
Ben Lindstrom77808ab2001-01-26 05:10:34 +00001517 signal(SIGHUP, cleanup_handler);
1518 signal(SIGTERM, cleanup_handler);
Ben Lindstroma3d5a4c2001-07-18 15:58:08 +00001519
djm@openbsd.org786d5992016-11-30 03:07:37 +00001520 if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1)
djm@openbsd.orgd9521622015-12-01 23:29:24 +00001521 fatal("%s: pledge: %s", __progname, strerror(errno));
Damien Miller4626cba2016-01-08 14:24:56 +11001522 platform_pledge_agent();
djm@openbsd.orgd9521622015-12-01 23:29:24 +00001523
Damien Miller95def091999-11-25 00:26:21 +11001524 while (1) {
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001525 prepare_poll(&pfd, &npfd, &timeout, maxfds);
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001526 result = poll(pfd, npfd, timeout);
Darren Tuckercf0d2db2007-02-28 21:19:58 +11001527 saved_errno = errno;
Darren Tucker2812dc92007-03-21 20:45:06 +11001528 if (parent_alive_interval != 0)
1529 check_parent_exists();
1530 (void) reaper(); /* remove expired keys */
deraadt@openbsd.org4d28fa72019-06-28 13:35:04 +00001531 if (result == -1) {
Darren Tuckercf0d2db2007-02-28 21:19:58 +11001532 if (saved_errno == EINTR)
Damien Miller95def091999-11-25 00:26:21 +11001533 continue;
djm@openbsd.orgfd0e8fa2017-07-19 01:15:02 +00001534 fatal("poll: %s", strerror(saved_errno));
Darren Tuckercf0d2db2007-02-28 21:19:58 +11001535 } else if (result > 0)
djm@openbsd.orgb2140a72018-05-11 03:38:51 +00001536 after_poll(pfd, npfd, maxfds);
Damien Miller95def091999-11-25 00:26:21 +11001537 }
1538 /* NOTREACHED */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001539}