1323136Sdes/* $OpenBSD: ssh-agent.c,v 1.218 2017/03/15 03:52:30 deraadt Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * The authentication agent program.
765674Skris *
865674Skris * As far as I am concerned, the code I have written for this software
965674Skris * can be used freely for any purpose.  Any derived versions of this
1065674Skris * software must be clearly marked as such, and if the derived work is
1165674Skris * incompatible with the protocol description in the RFC file, it must be
1265674Skris * called by a name other than "ssh" or "Secure Shell".
1365674Skris *
1492559Sdes * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
1565674Skris *
1665674Skris * Redistribution and use in source and binary forms, with or without
1765674Skris * modification, are permitted provided that the following conditions
1865674Skris * are met:
1965674Skris * 1. Redistributions of source code must retain the above copyright
2065674Skris *    notice, this list of conditions and the following disclaimer.
2165674Skris * 2. Redistributions in binary form must reproduce the above copyright
2265674Skris *    notice, this list of conditions and the following disclaimer in the
2365674Skris *    documentation and/or other materials provided with the distribution.
2465674Skris *
2565674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2665674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2765674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2865674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2965674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3065674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3165674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3265674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3365674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3465674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3557429Smarkm */
3657429Smarkm
3757429Smarkm#include "includes.h"
38162856Sdes__RCSID("$FreeBSD: stable/11/crypto/openssh/ssh-agent.c 323136 2017-09-02 23:39:51Z des $");
39162856Sdes
40162856Sdes#include <sys/types.h>
41162856Sdes#include <sys/param.h>
42162856Sdes#include <sys/resource.h>
43162856Sdes#include <sys/stat.h>
44162856Sdes#include <sys/socket.h>
45162856Sdes#ifdef HAVE_SYS_TIME_H
46162856Sdes# include <sys/time.h>
47162856Sdes#endif
48162856Sdes#ifdef HAVE_SYS_UN_H
49162856Sdes# include <sys/un.h>
50162856Sdes#endif
51106130Sdes#include "openbsd-compat/sys-queue.h"
5257429Smarkm
53294328Sdes#ifdef WITH_OPENSSL
5476262Sgreen#include <openssl/evp.h>
55181111Sdes#include "openbsd-compat/openssl-compat.h"
56294328Sdes#endif
5776262Sgreen
58162856Sdes#include <errno.h>
59162856Sdes#include <fcntl.h>
60294332Sdes#include <limits.h>
61162856Sdes#ifdef HAVE_PATHS_H
62162856Sdes# include <paths.h>
63162856Sdes#endif
64162856Sdes#include <signal.h>
65162856Sdes#include <stdarg.h>
66162856Sdes#include <stdio.h>
67162856Sdes#include <stdlib.h>
68162856Sdes#include <time.h>
69162856Sdes#include <string.h>
70162856Sdes#include <unistd.h>
71294336Sdes#ifdef HAVE_UTIL_H
72294336Sdes# include <util.h>
73294336Sdes#endif
74162856Sdes
75162856Sdes#include "xmalloc.h"
7657429Smarkm#include "ssh.h"
7757429Smarkm#include "rsa.h"
78294332Sdes#include "sshbuf.h"
79294332Sdes#include "sshkey.h"
8065674Skris#include "authfd.h"
8169591Sgreen#include "compat.h"
8276262Sgreen#include "log.h"
83113911Sdes#include "misc.h"
84263712Sdes#include "digest.h"
85294332Sdes#include "ssherr.h"
86323134Sdes#include "match.h"
8757429Smarkm
88204917Sdes#ifdef ENABLE_PKCS11
89204917Sdes#include "ssh-pkcs11.h"
9092559Sdes#endif
9192559Sdes
92323134Sdes#ifndef DEFAULT_PKCS11_WHITELIST
93323136Sdes# define DEFAULT_PKCS11_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
94323134Sdes#endif
95323134Sdes
9692559Sdestypedef enum {
9792559Sdes	AUTH_UNUSED,
9892559Sdes	AUTH_SOCKET,
9992559Sdes	AUTH_CONNECTION
10092559Sdes} sock_type;
10192559Sdes
10257429Smarkmtypedef struct {
10357429Smarkm	int fd;
10492559Sdes	sock_type type;
105294332Sdes	struct sshbuf *input;
106294332Sdes	struct sshbuf *output;
107294332Sdes	struct sshbuf *request;
10857429Smarkm} SocketEntry;
10957429Smarkm
11076262Sgreenu_int sockets_alloc = 0;
11157429SmarkmSocketEntry *sockets = NULL;
11257429Smarkm
11392559Sdestypedef struct identity {
11492559Sdes	TAILQ_ENTRY(identity) next;
115294332Sdes	struct sshkey *key;
11657429Smarkm	char *comment;
117204917Sdes	char *provider;
118255767Sdes	time_t death;
119113911Sdes	u_int confirm;
12057429Smarkm} Identity;
12157429Smarkm
12265674Skristypedef struct {
12365674Skris	int nentries;
12492559Sdes	TAILQ_HEAD(idqueue, identity) idlist;
12565674Skris} Idtab;
12657429Smarkm
12765674Skris/* private key table, one per protocol version */
12865674SkrisIdtab idtable[3];
12965674Skris
13057429Smarkmint max_fd = 0;
13157429Smarkm
13257429Smarkm/* pid of shell == parent of agent */
13360576Skrispid_t parent_pid = -1;
134255767Sdestime_t parent_alive_interval = 0;
13557429Smarkm
136294328Sdes/* pid of process for which cleanup_socket is applicable */
137294328Sdespid_t cleanup_pid = 0;
138294328Sdes
13957429Smarkm/* pathname and directory for AUTH_SOCKET */
140294332Sdeschar socket_name[PATH_MAX];
141294332Sdeschar socket_dir[PATH_MAX];
14257429Smarkm
143323134Sdes/* PKCS#11 path whitelist */
144323134Sdesstatic char *pkcs11_whitelist;
145323134Sdes
14698684Sdes/* locking */
147294336Sdes#define LOCK_SIZE	32
148294336Sdes#define LOCK_SALT_SIZE	16
149294336Sdes#define LOCK_ROUNDS	1
15098684Sdesint locked = 0;
151323129Sdesu_char lock_pwhash[LOCK_SIZE];
152323129Sdesu_char lock_salt[LOCK_SALT_SIZE];
15398684Sdes
15457429Smarkmextern char *__progname;
15557429Smarkm
156255767Sdes/* Default lifetime in seconds (0 == forever) */
157255767Sdesstatic long lifetime = 0;
158113911Sdes
159294332Sdesstatic int fingerprint_hash = SSH_FP_HASH_DEFAULT;
160294332Sdes
161226103Sdes/*
162226103Sdes * Client connection count; incremented in new_socket() and decremented in
163226103Sdes * close_socket().  When it reaches 0, ssh-agent will exit.  Since it is
164226103Sdes * normally initialized to 1, it will never reach 0.  However, if the -x
165226103Sdes * option is specified, it is initialized to 0 in main(); in that case,
166226103Sdes * ssh-agent will exit as soon as it has had at least one client but no
167226103Sdes * longer has any.
168226103Sdes */
169226103Sdesstatic int xcount = 1;
170226103Sdes
17192559Sdesstatic void
172106130Sdesclose_socket(SocketEntry *e)
173106130Sdes{
174226103Sdes	int last = 0;
175226103Sdes
176226103Sdes	if (e->type == AUTH_CONNECTION) {
177226103Sdes		debug("xcount %d -> %d", xcount, xcount - 1);
178226103Sdes		if (--xcount == 0)
179226103Sdes			last = 1;
180226103Sdes	}
181106130Sdes	close(e->fd);
182106130Sdes	e->fd = -1;
183106130Sdes	e->type = AUTH_UNUSED;
184294332Sdes	sshbuf_free(e->input);
185294332Sdes	sshbuf_free(e->output);
186294332Sdes	sshbuf_free(e->request);
187226103Sdes	if (last)
188226103Sdes		cleanup_exit(0);
189106130Sdes}
190106130Sdes
191106130Sdesstatic void
19265674Skrisidtab_init(void)
19357429Smarkm{
19465674Skris	int i;
19599063Sdes
19692559Sdes	for (i = 0; i <=2; i++) {
19792559Sdes		TAILQ_INIT(&idtable[i].idlist);
19865674Skris		idtable[i].nentries = 0;
19965674Skris	}
20065674Skris}
20165674Skris
20265674Skris/* return private key table for requested protocol version */
20392559Sdesstatic Idtab *
20465674Skrisidtab_lookup(int version)
20565674Skris{
20665674Skris	if (version < 1 || version > 2)
20765674Skris		fatal("internal error, bad protocol version %d", version);
20865674Skris	return &idtable[version];
20965674Skris}
21065674Skris
21198684Sdesstatic void
21298684Sdesfree_identity(Identity *id)
21398684Sdes{
214294332Sdes	sshkey_free(id->key);
215255767Sdes	free(id->provider);
216255767Sdes	free(id->comment);
217255767Sdes	free(id);
21898684Sdes}
21998684Sdes
22065674Skris/* return matching private key for given public key */
22192559Sdesstatic Identity *
222294332Sdeslookup_identity(struct sshkey *key, int version)
22365674Skris{
22492559Sdes	Identity *id;
22592559Sdes
22665674Skris	Idtab *tab = idtab_lookup(version);
22792559Sdes	TAILQ_FOREACH(id, &tab->idlist, next) {
228294332Sdes		if (sshkey_equal(key, id->key))
22992559Sdes			return (id);
23065674Skris	}
23192559Sdes	return (NULL);
23265674Skris}
23365674Skris
234113911Sdes/* Check confirmation of keysign request */
235113911Sdesstatic int
236113911Sdesconfirm_key(Identity *id)
237113911Sdes{
238147005Sdes	char *p;
239113911Sdes	int ret = -1;
240113911Sdes
241294332Sdes	p = sshkey_fingerprint(id->key, fingerprint_hash, SSH_FP_DEFAULT);
242294332Sdes	if (p != NULL &&
243294332Sdes	    ask_permission("Allow use of key %s?\nKey fingerprint %s.",
244147005Sdes	    id->comment, p))
245147005Sdes		ret = 0;
246255767Sdes	free(p);
247147005Sdes
248113911Sdes	return (ret);
249113911Sdes}
250113911Sdes
251294332Sdesstatic void
252294332Sdessend_status(SocketEntry *e, int success)
253294332Sdes{
254294332Sdes	int r;
255294332Sdes
256294332Sdes	if ((r = sshbuf_put_u32(e->output, 1)) != 0 ||
257294332Sdes	    (r = sshbuf_put_u8(e->output, success ?
258294332Sdes	    SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0)
259294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
260294332Sdes}
261294332Sdes
26265674Skris/* send list of supported public keys to 'client' */
26392559Sdesstatic void
26465674Skrisprocess_request_identities(SocketEntry *e, int version)
26565674Skris{
26665674Skris	Idtab *tab = idtab_lookup(version);
26799063Sdes	Identity *id;
268294332Sdes	struct sshbuf *msg;
269294332Sdes	int r;
27057429Smarkm
271294332Sdes	if ((msg = sshbuf_new()) == NULL)
272294332Sdes		fatal("%s: sshbuf_new failed", __func__);
273294332Sdes	if ((r = sshbuf_put_u8(msg, (version == 1) ?
274294332Sdes	    SSH_AGENT_RSA_IDENTITIES_ANSWER :
275294332Sdes	    SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
276294332Sdes	    (r = sshbuf_put_u32(msg, tab->nentries)) != 0)
277294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
27892559Sdes	TAILQ_FOREACH(id, &tab->idlist, next) {
27976262Sgreen		if (id->key->type == KEY_RSA1) {
280294328Sdes#ifdef WITH_SSH1
281294332Sdes			if ((r = sshbuf_put_u32(msg,
282294332Sdes			    BN_num_bits(id->key->rsa->n))) != 0 ||
283294332Sdes			    (r = sshbuf_put_bignum1(msg,
284294332Sdes			    id->key->rsa->e)) != 0 ||
285294332Sdes			    (r = sshbuf_put_bignum1(msg,
286294332Sdes			    id->key->rsa->n)) != 0)
287294332Sdes				fatal("%s: buffer error: %s",
288294332Sdes				    __func__, ssh_err(r));
289294328Sdes#endif
29065674Skris		} else {
29176262Sgreen			u_char *blob;
292294332Sdes			size_t blen;
293294332Sdes
294294332Sdes			if ((r = sshkey_to_blob(id->key, &blob, &blen)) != 0) {
295294332Sdes				error("%s: sshkey_to_blob: %s", __func__,
296294332Sdes				    ssh_err(r));
297294332Sdes				continue;
298294332Sdes			}
299294332Sdes			if ((r = sshbuf_put_string(msg, blob, blen)) != 0)
300294332Sdes				fatal("%s: buffer error: %s",
301294332Sdes				    __func__, ssh_err(r));
302255767Sdes			free(blob);
30365674Skris		}
304294332Sdes		if ((r = sshbuf_put_cstring(msg, id->comment)) != 0)
305294332Sdes			fatal("%s: buffer error: %s", __func__, ssh_err(r));
30657429Smarkm	}
307294332Sdes	if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
308294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
309294332Sdes	sshbuf_free(msg);
31057429Smarkm}
31157429Smarkm
312294328Sdes#ifdef WITH_SSH1
31365674Skris/* ssh1 only */
31492559Sdesstatic void
31565674Skrisprocess_authentication_challenge1(SocketEntry *e)
31657429Smarkm{
31799063Sdes	u_char buf[32], mdbuf[16], session_id[16];
31899063Sdes	u_int response_type;
31999063Sdes	BIGNUM *challenge;
32092559Sdes	Identity *id;
321294332Sdes	int r, len;
322294332Sdes	struct sshbuf *msg;
323263712Sdes	struct ssh_digest_ctx *md;
324294332Sdes	struct sshkey *key;
32557429Smarkm
326294332Sdes	if ((msg = sshbuf_new()) == NULL)
327294332Sdes		fatal("%s: sshbuf_new failed", __func__);
328294332Sdes	if ((key = sshkey_new(KEY_RSA1)) == NULL)
329294332Sdes		fatal("%s: sshkey_new failed", __func__);
33092559Sdes	if ((challenge = BN_new()) == NULL)
331294332Sdes		fatal("%s: BN_new failed", __func__);
33265674Skris
333294332Sdes	if ((r = sshbuf_get_u32(e->request, NULL)) != 0 || /* ignored */
334294332Sdes	    (r = sshbuf_get_bignum1(e->request, key->rsa->e)) != 0 ||
335294332Sdes	    (r = sshbuf_get_bignum1(e->request, key->rsa->n)) != 0 ||
336294332Sdes	    (r = sshbuf_get_bignum1(e->request, challenge)))
337294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
33857429Smarkm
33965674Skris	/* Only protocol 1.1 is supported */
340294332Sdes	if (sshbuf_len(e->request) == 0)
34165674Skris		goto failure;
342294332Sdes	if ((r = sshbuf_get(e->request, session_id, sizeof(session_id))) != 0 ||
343294332Sdes	    (r = sshbuf_get_u32(e->request, &response_type)) != 0)
344294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
34565674Skris	if (response_type != 1)
34665674Skris		goto failure;
34757429Smarkm
34892559Sdes	id = lookup_identity(key, 1);
349113911Sdes	if (id != NULL && (!id->confirm || confirm_key(id) == 0)) {
350294332Sdes		struct sshkey *private = id->key;
35165674Skris		/* Decrypt the challenge using the private key. */
352294332Sdes		if ((r = rsa_private_decrypt(challenge, challenge,
353294332Sdes		    private->rsa) != 0)) {
354294332Sdes			fatal("%s: rsa_public_encrypt: %s", __func__,
355294332Sdes			    ssh_err(r));
356294332Sdes			goto failure;	/* XXX ? */
357294332Sdes		}
35857429Smarkm
359294332Sdes		/* The response is MD5 of decrypted challenge plus session id */
36065674Skris		len = BN_num_bytes(challenge);
36165674Skris		if (len <= 0 || len > 32) {
362294332Sdes			logit("%s: bad challenge length %d", __func__, len);
36365674Skris			goto failure;
36465674Skris		}
36565674Skris		memset(buf, 0, 32);
36665674Skris		BN_bn2bin(challenge, buf + 32 - len);
367263712Sdes		if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
368263712Sdes		    ssh_digest_update(md, buf, 32) < 0 ||
369263712Sdes		    ssh_digest_update(md, session_id, 16) < 0 ||
370263712Sdes		    ssh_digest_final(md, mdbuf, sizeof(mdbuf)) < 0)
371263712Sdes			fatal("%s: md5 failed", __func__);
372263712Sdes		ssh_digest_free(md);
37357429Smarkm
37465674Skris		/* Send the response. */
375294332Sdes		if ((r = sshbuf_put_u8(msg, SSH_AGENT_RSA_RESPONSE)) != 0 ||
376294332Sdes		    (r = sshbuf_put(msg, mdbuf, sizeof(mdbuf))) != 0)
377294332Sdes			fatal("%s: buffer error: %s", __func__, ssh_err(r));
37865674Skris		goto send;
37965674Skris	}
38057429Smarkm
381294332Sdes failure:
38265674Skris	/* Unknown identity or protocol error.  Send failure. */
383294332Sdes	if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
384294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
385294332Sdes send:
386294332Sdes	if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
387294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
388294332Sdes	sshkey_free(key);
38965674Skris	BN_clear_free(challenge);
390294332Sdes	sshbuf_free(msg);
39165674Skris}
392294328Sdes#endif
39365674Skris
394296633Sdesstatic char *
395296633Sdesagent_decode_alg(struct sshkey *key, u_int flags)
396296633Sdes{
397296633Sdes	if (key->type == KEY_RSA) {
398296633Sdes		if (flags & SSH_AGENT_RSA_SHA2_256)
399296633Sdes			return "rsa-sha2-256";
400296633Sdes		else if (flags & SSH_AGENT_RSA_SHA2_512)
401296633Sdes			return "rsa-sha2-512";
402296633Sdes	}
403296633Sdes	return NULL;
404296633Sdes}
405296633Sdes
40665674Skris/* ssh2 only */
40792559Sdesstatic void
40865674Skrisprocess_sign_request2(SocketEntry *e)
40965674Skris{
41076262Sgreen	u_char *blob, *data, *signature = NULL;
411294332Sdes	size_t blen, dlen, slen = 0;
412294332Sdes	u_int compat = 0, flags;
413294332Sdes	int r, ok = -1;
414294332Sdes	struct sshbuf *msg;
415294332Sdes	struct sshkey *key;
416294332Sdes	struct identity *id;
41765674Skris
418294332Sdes	if ((msg = sshbuf_new()) == NULL)
419294332Sdes		fatal("%s: sshbuf_new failed", __func__);
420294332Sdes	if ((r = sshbuf_get_string(e->request, &blob, &blen)) != 0 ||
421294332Sdes	    (r = sshbuf_get_string(e->request, &data, &dlen)) != 0 ||
422294332Sdes	    (r = sshbuf_get_u32(e->request, &flags)) != 0)
423294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
42469591Sgreen	if (flags & SSH_AGENT_OLD_SIGNATURE)
425294332Sdes		compat = SSH_BUG_SIGBLOB;
426294332Sdes	if ((r = sshkey_from_blob(blob, blen, &key)) != 0) {
427296633Sdes		error("%s: cannot parse key blob: %s", __func__, ssh_err(r));
428294332Sdes		goto send;
42965674Skris	}
430294332Sdes	if ((id = lookup_identity(key, 2)) == NULL) {
431294332Sdes		verbose("%s: %s key not found", __func__, sshkey_type(key));
432294332Sdes		goto send;
433294332Sdes	}
434294332Sdes	if (id->confirm && confirm_key(id) != 0) {
435294332Sdes		verbose("%s: user refused key", __func__);
436294332Sdes		goto send;
437294332Sdes	}
438294332Sdes	if ((r = sshkey_sign(id->key, &signature, &slen,
439296633Sdes	    data, dlen, agent_decode_alg(key, flags), compat)) != 0) {
440296633Sdes		error("%s: sshkey_sign: %s", __func__, ssh_err(r));
441294332Sdes		goto send;
442294332Sdes	}
443294332Sdes	/* Success */
444294332Sdes	ok = 0;
445294332Sdes send:
446294332Sdes	sshkey_free(key);
44765674Skris	if (ok == 0) {
448294332Sdes		if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 ||
449294332Sdes		    (r = sshbuf_put_string(msg, signature, slen)) != 0)
450294332Sdes			fatal("%s: buffer error: %s", __func__, ssh_err(r));
451294332Sdes	} else if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
452294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
453294332Sdes
454294332Sdes	if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
455294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
456294332Sdes
457294332Sdes	sshbuf_free(msg);
458255767Sdes	free(data);
459255767Sdes	free(blob);
460255767Sdes	free(signature);
46157429Smarkm}
46257429Smarkm
46365674Skris/* shared */
46492559Sdesstatic void
46565674Skrisprocess_remove_identity(SocketEntry *e, int version)
46657429Smarkm{
467294332Sdes	size_t blen;
468294332Sdes	int r, success = 0;
469294332Sdes	struct sshkey *key = NULL;
47076262Sgreen	u_char *blob;
471294328Sdes#ifdef WITH_SSH1
472294328Sdes	u_int bits;
473294328Sdes#endif /* WITH_SSH1 */
47457429Smarkm
47592559Sdes	switch (version) {
476294328Sdes#ifdef WITH_SSH1
47765674Skris	case 1:
478294332Sdes		if ((key = sshkey_new(KEY_RSA1)) == NULL) {
479294332Sdes			error("%s: sshkey_new failed", __func__);
480294332Sdes			return;
481294332Sdes		}
482294332Sdes		if ((r = sshbuf_get_u32(e->request, &bits)) != 0 ||
483294332Sdes		    (r = sshbuf_get_bignum1(e->request, key->rsa->e)) != 0 ||
484294332Sdes		    (r = sshbuf_get_bignum1(e->request, key->rsa->n)) != 0)
485294332Sdes			fatal("%s: buffer error: %s", __func__, ssh_err(r));
48657429Smarkm
487294332Sdes		if (bits != sshkey_size(key))
488294332Sdes			logit("Warning: identity keysize mismatch: "
489294332Sdes			    "actual %u, announced %u",
490294332Sdes			    sshkey_size(key), bits);
49165674Skris		break;
492294328Sdes#endif /* WITH_SSH1 */
49365674Skris	case 2:
494294332Sdes		if ((r = sshbuf_get_string(e->request, &blob, &blen)) != 0)
495294332Sdes			fatal("%s: buffer error: %s", __func__, ssh_err(r));
496294332Sdes		if ((r = sshkey_from_blob(blob, blen, &key)) != 0)
497294332Sdes			error("%s: sshkey_from_blob failed: %s",
498294332Sdes			    __func__, ssh_err(r));
499255767Sdes		free(blob);
50065674Skris		break;
50165674Skris	}
50265674Skris	if (key != NULL) {
50392559Sdes		Identity *id = lookup_identity(key, version);
50492559Sdes		if (id != NULL) {
50557429Smarkm			/*
50657429Smarkm			 * We have this key.  Free the old key.  Since we
507157019Sdes			 * don't want to leave empty slots in the middle of
50876262Sgreen			 * the array, we actually free the key there and move
50976262Sgreen			 * all the entries between the empty slot and the end
51076262Sgreen			 * of the array.
51157429Smarkm			 */
51265674Skris			Idtab *tab = idtab_lookup(version);
51376262Sgreen			if (tab->nentries < 1)
51476262Sgreen				fatal("process_remove_identity: "
51576262Sgreen				    "internal error: tab->nentries %d",
51676262Sgreen				    tab->nentries);
51792559Sdes			TAILQ_REMOVE(&tab->idlist, id, next);
51892559Sdes			free_identity(id);
51965674Skris			tab->nentries--;
52065674Skris			success = 1;
52157429Smarkm		}
522294332Sdes		sshkey_free(key);
52365674Skris	}
524294332Sdes	send_status(e, success);
52557429Smarkm}
52657429Smarkm
52792559Sdesstatic void
52865674Skrisprocess_remove_all_identities(SocketEntry *e, int version)
52957429Smarkm{
53065674Skris	Idtab *tab = idtab_lookup(version);
53192559Sdes	Identity *id;
53257429Smarkm
53357429Smarkm	/* Loop over all identities and clear the keys. */
53492559Sdes	for (id = TAILQ_FIRST(&tab->idlist); id;
53592559Sdes	    id = TAILQ_FIRST(&tab->idlist)) {
53692559Sdes		TAILQ_REMOVE(&tab->idlist, id, next);
53792559Sdes		free_identity(id);
53857429Smarkm	}
53957429Smarkm
54057429Smarkm	/* Mark that there are no identities. */
54165674Skris	tab->nentries = 0;
54257429Smarkm
54357429Smarkm	/* Send success. */
544294332Sdes	send_status(e, 1);
54557429Smarkm}
54657429Smarkm
547181111Sdes/* removes expired keys and returns number of seconds until the next expiry */
548255767Sdesstatic time_t
54998684Sdesreaper(void)
55098684Sdes{
551255767Sdes	time_t deadline = 0, now = monotime();
55298684Sdes	Identity *id, *nxt;
55398684Sdes	int version;
55499063Sdes	Idtab *tab;
55598684Sdes
55698684Sdes	for (version = 1; version < 3; version++) {
55798684Sdes		tab = idtab_lookup(version);
55898684Sdes		for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
55998684Sdes			nxt = TAILQ_NEXT(id, next);
560181111Sdes			if (id->death == 0)
561181111Sdes				continue;
562181111Sdes			if (now >= id->death) {
563181111Sdes				debug("expiring key '%s'", id->comment);
56498684Sdes				TAILQ_REMOVE(&tab->idlist, id, next);
56598684Sdes				free_identity(id);
56698684Sdes				tab->nentries--;
567181111Sdes			} else
568181111Sdes				deadline = (deadline == 0) ? id->death :
569323134Sdes				    MINIMUM(deadline, id->death);
57098684Sdes		}
57198684Sdes	}
572181111Sdes	if (deadline == 0 || deadline <= now)
573181111Sdes		return 0;
574181111Sdes	else
575181111Sdes		return (deadline - now);
57698684Sdes}
57798684Sdes
578294332Sdes/*
579294332Sdes * XXX this and the corresponding serialisation function probably belongs
580294332Sdes * in key.c
581294332Sdes */
582294332Sdes#ifdef WITH_SSH1
583294332Sdesstatic int
584294332Sdesagent_decode_rsa1(struct sshbuf *m, struct sshkey **kp)
585294332Sdes{
586294332Sdes	struct sshkey *k = NULL;
587294332Sdes	int r = SSH_ERR_INTERNAL_ERROR;
588294332Sdes
589294332Sdes	*kp = NULL;
590294332Sdes	if ((k = sshkey_new_private(KEY_RSA1)) == NULL)
591294332Sdes		return SSH_ERR_ALLOC_FAIL;
592294332Sdes
593294332Sdes	if ((r = sshbuf_get_u32(m, NULL)) != 0 ||		/* ignored */
594294332Sdes	    (r = sshbuf_get_bignum1(m, k->rsa->n)) != 0 ||
595294332Sdes	    (r = sshbuf_get_bignum1(m, k->rsa->e)) != 0 ||
596294332Sdes	    (r = sshbuf_get_bignum1(m, k->rsa->d)) != 0 ||
597294332Sdes	    (r = sshbuf_get_bignum1(m, k->rsa->iqmp)) != 0 ||
598294332Sdes	    /* SSH1 and SSL have p and q swapped */
599294332Sdes	    (r = sshbuf_get_bignum1(m, k->rsa->q)) != 0 ||	/* p */
600294332Sdes	    (r = sshbuf_get_bignum1(m, k->rsa->p)) != 0) 	/* q */
601294332Sdes		goto out;
602294332Sdes
603294332Sdes	/* Generate additional parameters */
604294332Sdes	if ((r = rsa_generate_additional_parameters(k->rsa)) != 0)
605294332Sdes		goto out;
606294332Sdes	/* enable blinding */
607294332Sdes	if (RSA_blinding_on(k->rsa, NULL) != 1) {
608294332Sdes		r = SSH_ERR_LIBCRYPTO_ERROR;
609294332Sdes		goto out;
610294332Sdes	}
611294332Sdes
612294332Sdes	r = 0; /* success */
613294332Sdes out:
614294332Sdes	if (r == 0)
615294332Sdes		*kp = k;
616294332Sdes	else
617294332Sdes		sshkey_free(k);
618294332Sdes	return r;
619294332Sdes}
620294332Sdes#endif /* WITH_SSH1 */
621294332Sdes
62298684Sdesstatic void
62365674Skrisprocess_add_identity(SocketEntry *e, int version)
62457429Smarkm{
62599063Sdes	Idtab *tab = idtab_lookup(version);
626181111Sdes	Identity *id;
627294332Sdes	int success = 0, confirm = 0;
628294332Sdes	u_int seconds;
629294332Sdes	char *comment = NULL;
630255767Sdes	time_t death = 0;
631294332Sdes	struct sshkey *k = NULL;
632294332Sdes	u_char ctype;
633294332Sdes	int r = SSH_ERR_INTERNAL_ERROR;
63457429Smarkm
63565674Skris	switch (version) {
636294328Sdes#ifdef WITH_SSH1
63765674Skris	case 1:
638294332Sdes		r = agent_decode_rsa1(e->request, &k);
639113911Sdes		break;
640294328Sdes#endif /* WITH_SSH1 */
641261320Sdes	case 2:
642294332Sdes		r = sshkey_private_deserialize(e->request, &k);
643261320Sdes		break;
644113911Sdes	}
645294332Sdes	if (r != 0 || k == NULL ||
646294332Sdes	    (r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) {
647294332Sdes		error("%s: decode private key: %s", __func__, ssh_err(r));
648294332Sdes		goto err;
649294332Sdes	}
650294328Sdes
651294332Sdes	while (sshbuf_len(e->request)) {
652294332Sdes		if ((r = sshbuf_get_u8(e->request, &ctype)) != 0) {
653294332Sdes			error("%s: buffer error: %s", __func__, ssh_err(r));
654294332Sdes			goto err;
655294332Sdes		}
656294332Sdes		switch (ctype) {
65798684Sdes		case SSH_AGENT_CONSTRAIN_LIFETIME:
658294332Sdes			if ((r = sshbuf_get_u32(e->request, &seconds)) != 0) {
659294332Sdes				error("%s: bad lifetime constraint: %s",
660294332Sdes				    __func__, ssh_err(r));
661294332Sdes				goto err;
662294332Sdes			}
663294332Sdes			death = monotime() + seconds;
66498684Sdes			break;
665113911Sdes		case SSH_AGENT_CONSTRAIN_CONFIRM:
666113911Sdes			confirm = 1;
667113911Sdes			break;
66898684Sdes		default:
669294332Sdes			error("%s: Unknown constraint %d", __func__, ctype);
670294332Sdes err:
671294332Sdes			sshbuf_reset(e->request);
672255767Sdes			free(comment);
673294332Sdes			sshkey_free(k);
674181111Sdes			goto send;
67598684Sdes		}
67698684Sdes	}
677294332Sdes
678181111Sdes	success = 1;
679113911Sdes	if (lifetime && !death)
680255767Sdes		death = monotime() + lifetime;
681181111Sdes	if ((id = lookup_identity(k, version)) == NULL) {
682204917Sdes		id = xcalloc(1, sizeof(Identity));
68392559Sdes		id->key = k;
68492559Sdes		TAILQ_INSERT_TAIL(&tab->idlist, id, next);
68565674Skris		/* Increment the number of identities. */
68665674Skris		tab->nentries++;
68765674Skris	} else {
688294332Sdes		sshkey_free(k);
689255767Sdes		free(id->comment);
69065674Skris	}
691181111Sdes	id->comment = comment;
692181111Sdes	id->death = death;
693181111Sdes	id->confirm = confirm;
69465674Skrissend:
695294332Sdes	send_status(e, success);
69657429Smarkm}
69757429Smarkm
69898684Sdes/* XXX todo: encrypt sensitive data with passphrase */
69998684Sdesstatic void
70098684Sdesprocess_lock_agent(SocketEntry *e, int lock)
70198684Sdes{
702294336Sdes	int r, success = 0, delay;
703323129Sdes	char *passwd;
704323129Sdes	u_char passwdhash[LOCK_SIZE];
705294336Sdes	static u_int fail_count = 0;
706294336Sdes	size_t pwlen;
70792559Sdes
708294336Sdes	if ((r = sshbuf_get_cstring(e->request, &passwd, &pwlen)) != 0)
709294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
710294336Sdes	if (pwlen == 0) {
711294336Sdes		debug("empty password not supported");
712294336Sdes	} else if (locked && !lock) {
713294336Sdes		if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
714294336Sdes		    passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0)
715294336Sdes			fatal("bcrypt_pbkdf");
716323129Sdes		if (timingsafe_bcmp(passwdhash, lock_pwhash, LOCK_SIZE) == 0) {
717294336Sdes			debug("agent unlocked");
718294336Sdes			locked = 0;
719294336Sdes			fail_count = 0;
720323129Sdes			explicit_bzero(lock_pwhash, sizeof(lock_pwhash));
721294336Sdes			success = 1;
722294336Sdes		} else {
723294336Sdes			/* delay in 0.1s increments up to 10s */
724294336Sdes			if (fail_count < 100)
725294336Sdes				fail_count++;
726294336Sdes			delay = 100000 * fail_count;
727294336Sdes			debug("unlock failed, delaying %0.1lf seconds",
728294336Sdes			    (double)delay/1000000);
729294336Sdes			usleep(delay);
730294336Sdes		}
731294336Sdes		explicit_bzero(passwdhash, sizeof(passwdhash));
73298684Sdes	} else if (!locked && lock) {
733294336Sdes		debug("agent locked");
73498684Sdes		locked = 1;
735294336Sdes		arc4random_buf(lock_salt, sizeof(lock_salt));
736294336Sdes		if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
737323129Sdes		    lock_pwhash, sizeof(lock_pwhash), LOCK_ROUNDS) < 0)
738294336Sdes			fatal("bcrypt_pbkdf");
73998684Sdes		success = 1;
74098684Sdes	}
741294336Sdes	explicit_bzero(passwd, pwlen);
742255767Sdes	free(passwd);
743294332Sdes	send_status(e, success);
74498684Sdes}
74598684Sdes
74698684Sdesstatic void
74798684Sdesno_identities(SocketEntry *e, u_int type)
74898684Sdes{
749294332Sdes	struct sshbuf *msg;
750294332Sdes	int r;
75198684Sdes
752294332Sdes	if ((msg = sshbuf_new()) == NULL)
753294332Sdes		fatal("%s: sshbuf_new failed", __func__);
754294332Sdes	if ((r = sshbuf_put_u8(msg,
75598684Sdes	    (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ?
756294332Sdes	    SSH_AGENT_RSA_IDENTITIES_ANSWER :
757294332Sdes	    SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
758294332Sdes	    (r = sshbuf_put_u32(msg, 0)) != 0 ||
759294332Sdes	    (r = sshbuf_put_stringb(e->output, msg)) != 0)
760294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
761294332Sdes	sshbuf_free(msg);
76298684Sdes}
76398684Sdes
764204917Sdes#ifdef ENABLE_PKCS11
76592559Sdesstatic void
766181111Sdesprocess_add_smartcard_key(SocketEntry *e)
76792559Sdes{
768323134Sdes	char *provider = NULL, *pin, canonical_provider[PATH_MAX];
769294332Sdes	int r, i, version, count = 0, success = 0, confirm = 0;
770294332Sdes	u_int seconds;
771255767Sdes	time_t death = 0;
772294332Sdes	u_char type;
773294332Sdes	struct sshkey **keys = NULL, *k;
77498684Sdes	Identity *id;
77592559Sdes	Idtab *tab;
77692559Sdes
777294332Sdes	if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
778294332Sdes	    (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
779294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
780124211Sdes
781294332Sdes	while (sshbuf_len(e->request)) {
782294332Sdes		if ((r = sshbuf_get_u8(e->request, &type)) != 0)
783294332Sdes			fatal("%s: buffer error: %s", __func__, ssh_err(r));
784294332Sdes		switch (type) {
785124211Sdes		case SSH_AGENT_CONSTRAIN_LIFETIME:
786294332Sdes			if ((r = sshbuf_get_u32(e->request, &seconds)) != 0)
787294332Sdes				fatal("%s: buffer error: %s",
788294332Sdes				    __func__, ssh_err(r));
789294332Sdes			death = monotime() + seconds;
790124211Sdes			break;
791124211Sdes		case SSH_AGENT_CONSTRAIN_CONFIRM:
792124211Sdes			confirm = 1;
793124211Sdes			break;
794124211Sdes		default:
795181111Sdes			error("process_add_smartcard_key: "
796181111Sdes			    "Unknown constraint type %d", type);
797181111Sdes			goto send;
798124211Sdes		}
799124211Sdes	}
800323134Sdes	if (realpath(provider, canonical_provider) == NULL) {
801323134Sdes		verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
802323134Sdes		    provider, strerror(errno));
803323134Sdes		goto send;
804323134Sdes	}
805323134Sdes	if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) {
806323134Sdes		verbose("refusing PKCS#11 add of \"%.100s\": "
807323134Sdes		    "provider not whitelisted", canonical_provider);
808323134Sdes		goto send;
809323134Sdes	}
810323134Sdes	debug("%s: add %.100s", __func__, canonical_provider);
811124211Sdes	if (lifetime && !death)
812255767Sdes		death = monotime() + lifetime;
813124211Sdes
814323134Sdes	count = pkcs11_add_provider(canonical_provider, pin, &keys);
815204917Sdes	for (i = 0; i < count; i++) {
81698684Sdes		k = keys[i];
81798684Sdes		version = k->type == KEY_RSA1 ? 1 : 2;
81898684Sdes		tab = idtab_lookup(version);
81998684Sdes		if (lookup_identity(k, version) == NULL) {
820204917Sdes			id = xcalloc(1, sizeof(Identity));
82198684Sdes			id->key = k;
822323134Sdes			id->provider = xstrdup(canonical_provider);
823323134Sdes			id->comment = xstrdup(canonical_provider); /* XXX */
824124211Sdes			id->death = death;
825124211Sdes			id->confirm = confirm;
82698684Sdes			TAILQ_INSERT_TAIL(&tab->idlist, id, next);
82798684Sdes			tab->nentries++;
82898684Sdes			success = 1;
82998684Sdes		} else {
830294332Sdes			sshkey_free(k);
83198684Sdes		}
83298684Sdes		keys[i] = NULL;
83392559Sdes	}
83492559Sdessend:
835255767Sdes	free(pin);
836255767Sdes	free(provider);
837255767Sdes	free(keys);
838294332Sdes	send_status(e, success);
83992559Sdes}
84092559Sdes
84192559Sdesstatic void
84292559Sdesprocess_remove_smartcard_key(SocketEntry *e)
84392559Sdes{
844323136Sdes	char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
845294332Sdes	int r, version, success = 0;
846204917Sdes	Identity *id, *nxt;
84798684Sdes	Idtab *tab;
84892559Sdes
849294332Sdes	if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
850294332Sdes	    (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
851294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
852255767Sdes	free(pin);
85392559Sdes
854323136Sdes	if (realpath(provider, canonical_provider) == NULL) {
855323136Sdes		verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
856323136Sdes		    provider, strerror(errno));
857323136Sdes		goto send;
858323136Sdes	}
859323136Sdes
860323136Sdes	debug("%s: remove %.100s", __func__, canonical_provider);
861204917Sdes	for (version = 1; version < 3; version++) {
862204917Sdes		tab = idtab_lookup(version);
863204917Sdes		for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
864204917Sdes			nxt = TAILQ_NEXT(id, next);
865261320Sdes			/* Skip file--based keys */
866261320Sdes			if (id->provider == NULL)
867261320Sdes				continue;
868323136Sdes			if (!strcmp(canonical_provider, id->provider)) {
869204917Sdes				TAILQ_REMOVE(&tab->idlist, id, next);
870204917Sdes				free_identity(id);
871204917Sdes				tab->nentries--;
872204917Sdes			}
87392559Sdes		}
87492559Sdes	}
875323136Sdes	if (pkcs11_del_provider(canonical_provider) == 0)
876204917Sdes		success = 1;
877204917Sdes	else
878204917Sdes		error("process_remove_smartcard_key:"
879204917Sdes		    " pkcs11_del_provider failed");
880323136Sdessend:
881255767Sdes	free(provider);
882294332Sdes	send_status(e, success);
88392559Sdes}
884204917Sdes#endif /* ENABLE_PKCS11 */
88592559Sdes
88665674Skris/* dispatch incoming messages */
88765674Skris
88892559Sdesstatic void
88957429Smarkmprocess_message(SocketEntry *e)
89057429Smarkm{
891294332Sdes	u_int msg_len;
892294332Sdes	u_char type;
893294332Sdes	const u_char *cp;
894294332Sdes	int r;
89598684Sdes
896294332Sdes	if (sshbuf_len(e->input) < 5)
89757429Smarkm		return;		/* Incomplete message. */
898294332Sdes	cp = sshbuf_ptr(e->input);
899294332Sdes	msg_len = PEEK_U32(cp);
90057429Smarkm	if (msg_len > 256 * 1024) {
901106130Sdes		close_socket(e);
90257429Smarkm		return;
90357429Smarkm	}
904294332Sdes	if (sshbuf_len(e->input) < msg_len + 4)
90557429Smarkm		return;
90698684Sdes
90798684Sdes	/* move the current input to e->request */
908294332Sdes	sshbuf_reset(e->request);
909294332Sdes	if ((r = sshbuf_get_stringb(e->input, e->request)) != 0 ||
910294332Sdes	    (r = sshbuf_get_u8(e->request, &type)) != 0)
911294332Sdes		fatal("%s: buffer error: %s", __func__, ssh_err(r));
91257429Smarkm
91398684Sdes	/* check wheter agent is locked */
91498684Sdes	if (locked && type != SSH_AGENTC_UNLOCK) {
915294332Sdes		sshbuf_reset(e->request);
91698684Sdes		switch (type) {
91798684Sdes		case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
91898684Sdes		case SSH2_AGENTC_REQUEST_IDENTITIES:
91998684Sdes			/* send empty lists */
92098684Sdes			no_identities(e, type);
92198684Sdes			break;
92298684Sdes		default:
92398684Sdes			/* send a fail message for all other request types */
924294332Sdes			send_status(e, 0);
92598684Sdes		}
92698684Sdes		return;
92798684Sdes	}
92898684Sdes
92992559Sdes	debug("type %d", type);
93057429Smarkm	switch (type) {
93198684Sdes	case SSH_AGENTC_LOCK:
93298684Sdes	case SSH_AGENTC_UNLOCK:
93398684Sdes		process_lock_agent(e, type == SSH_AGENTC_LOCK);
93498684Sdes		break;
935294328Sdes#ifdef WITH_SSH1
93665674Skris	/* ssh1 */
93765674Skris	case SSH_AGENTC_RSA_CHALLENGE:
93865674Skris		process_authentication_challenge1(e);
93965674Skris		break;
94057429Smarkm	case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
94165674Skris		process_request_identities(e, 1);
94257429Smarkm		break;
94357429Smarkm	case SSH_AGENTC_ADD_RSA_IDENTITY:
94498684Sdes	case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED:
94565674Skris		process_add_identity(e, 1);
94657429Smarkm		break;
94757429Smarkm	case SSH_AGENTC_REMOVE_RSA_IDENTITY:
94865674Skris		process_remove_identity(e, 1);
94957429Smarkm		break;
950294332Sdes#endif
95157429Smarkm	case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
952294332Sdes		process_remove_all_identities(e, 1); /* safe for !WITH_SSH1 */
95357429Smarkm		break;
95465674Skris	/* ssh2 */
95565674Skris	case SSH2_AGENTC_SIGN_REQUEST:
95665674Skris		process_sign_request2(e);
95765674Skris		break;
95865674Skris	case SSH2_AGENTC_REQUEST_IDENTITIES:
95965674Skris		process_request_identities(e, 2);
96065674Skris		break;
96165674Skris	case SSH2_AGENTC_ADD_IDENTITY:
96298684Sdes	case SSH2_AGENTC_ADD_ID_CONSTRAINED:
96365674Skris		process_add_identity(e, 2);
96465674Skris		break;
96565674Skris	case SSH2_AGENTC_REMOVE_IDENTITY:
96665674Skris		process_remove_identity(e, 2);
96765674Skris		break;
96865674Skris	case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
96965674Skris		process_remove_all_identities(e, 2);
97065674Skris		break;
971204917Sdes#ifdef ENABLE_PKCS11
97292559Sdes	case SSH_AGENTC_ADD_SMARTCARD_KEY:
973124211Sdes	case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
97492559Sdes		process_add_smartcard_key(e);
97592559Sdes		break;
97692559Sdes	case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
97792559Sdes		process_remove_smartcard_key(e);
97892559Sdes		break;
979204917Sdes#endif /* ENABLE_PKCS11 */
98057429Smarkm	default:
98157429Smarkm		/* Unknown message.  Respond with failure. */
98257429Smarkm		error("Unknown message %d", type);
983294332Sdes		sshbuf_reset(e->request);
984294332Sdes		send_status(e, 0);
98557429Smarkm		break;
98657429Smarkm	}
98757429Smarkm}
98857429Smarkm
98992559Sdesstatic void
99092559Sdesnew_socket(sock_type type, int fd)
99157429Smarkm{
992120161Snectar	u_int i, old_alloc, new_alloc;
99399063Sdes
994226103Sdes	if (type == AUTH_CONNECTION) {
995226103Sdes		debug("xcount %d -> %d", xcount, xcount + 1);
996226103Sdes		++xcount;
997226103Sdes	}
998137019Sdes	set_nonblock(fd);
99957429Smarkm
100057429Smarkm	if (fd > max_fd)
100157429Smarkm		max_fd = fd;
100257429Smarkm
100357429Smarkm	for (i = 0; i < sockets_alloc; i++)
100457429Smarkm		if (sockets[i].type == AUTH_UNUSED) {
100557429Smarkm			sockets[i].fd = fd;
1006294332Sdes			if ((sockets[i].input = sshbuf_new()) == NULL)
1007294332Sdes				fatal("%s: sshbuf_new failed", __func__);
1008294332Sdes			if ((sockets[i].output = sshbuf_new()) == NULL)
1009294332Sdes				fatal("%s: sshbuf_new failed", __func__);
1010294332Sdes			if ((sockets[i].request = sshbuf_new()) == NULL)
1011294332Sdes				fatal("%s: sshbuf_new failed", __func__);
1012120161Snectar			sockets[i].type = type;
101357429Smarkm			return;
101457429Smarkm		}
101557429Smarkm	old_alloc = sockets_alloc;
1016120161Snectar	new_alloc = sockets_alloc + 10;
1017294336Sdes	sockets = xreallocarray(sockets, new_alloc, sizeof(sockets[0]));
1018120161Snectar	for (i = old_alloc; i < new_alloc; i++)
101957429Smarkm		sockets[i].type = AUTH_UNUSED;
1020120161Snectar	sockets_alloc = new_alloc;
102157429Smarkm	sockets[old_alloc].fd = fd;
1022294332Sdes	if ((sockets[old_alloc].input = sshbuf_new()) == NULL)
1023294332Sdes		fatal("%s: sshbuf_new failed", __func__);
1024294332Sdes	if ((sockets[old_alloc].output = sshbuf_new()) == NULL)
1025294332Sdes		fatal("%s: sshbuf_new failed", __func__);
1026294332Sdes	if ((sockets[old_alloc].request = sshbuf_new()) == NULL)
1027294332Sdes		fatal("%s: sshbuf_new failed", __func__);
1028120161Snectar	sockets[old_alloc].type = type;
102957429Smarkm}
103057429Smarkm
103192559Sdesstatic int
1032181111Sdesprepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
1033181111Sdes    struct timeval **tvpp)
103457429Smarkm{
1035255767Sdes	u_int i, sz;
103676262Sgreen	int n = 0;
1037181111Sdes	static struct timeval tv;
1038255767Sdes	time_t deadline;
103976262Sgreen
104076262Sgreen	for (i = 0; i < sockets_alloc; i++) {
104157429Smarkm		switch (sockets[i].type) {
104257429Smarkm		case AUTH_SOCKET:
104357429Smarkm		case AUTH_CONNECTION:
1044323134Sdes			n = MAXIMUM(n, sockets[i].fd);
104557429Smarkm			break;
104657429Smarkm		case AUTH_UNUSED:
104757429Smarkm			break;
104857429Smarkm		default:
104957429Smarkm			fatal("Unknown socket type %d", sockets[i].type);
105057429Smarkm			break;
105157429Smarkm		}
105276262Sgreen	}
105376262Sgreen
105476262Sgreen	sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
105592559Sdes	if (*fdrp == NULL || sz > *nallocp) {
1056255767Sdes		free(*fdrp);
1057255767Sdes		free(*fdwp);
105876262Sgreen		*fdrp = xmalloc(sz);
105976262Sgreen		*fdwp = xmalloc(sz);
106092559Sdes		*nallocp = sz;
106176262Sgreen	}
106292559Sdes	if (n < *fdl)
106392559Sdes		debug("XXX shrink: %d < %d", n, *fdl);
106492559Sdes	*fdl = n;
106576262Sgreen	memset(*fdrp, 0, sz);
106676262Sgreen	memset(*fdwp, 0, sz);
106776262Sgreen
106876262Sgreen	for (i = 0; i < sockets_alloc; i++) {
106976262Sgreen		switch (sockets[i].type) {
107076262Sgreen		case AUTH_SOCKET:
107176262Sgreen		case AUTH_CONNECTION:
107276262Sgreen			FD_SET(sockets[i].fd, *fdrp);
1073294332Sdes			if (sshbuf_len(sockets[i].output) > 0)
107476262Sgreen				FD_SET(sockets[i].fd, *fdwp);
107576262Sgreen			break;
107676262Sgreen		default:
107776262Sgreen			break;
107876262Sgreen		}
107976262Sgreen	}
1080181111Sdes	deadline = reaper();
1081181111Sdes	if (parent_alive_interval != 0)
1082181111Sdes		deadline = (deadline == 0) ? parent_alive_interval :
1083323134Sdes		    MINIMUM(deadline, parent_alive_interval);
1084181111Sdes	if (deadline == 0) {
1085181111Sdes		*tvpp = NULL;
1086181111Sdes	} else {
1087181111Sdes		tv.tv_sec = deadline;
1088181111Sdes		tv.tv_usec = 0;
1089181111Sdes		*tvpp = &tv;
1090181111Sdes	}
109176262Sgreen	return (1);
109257429Smarkm}
109357429Smarkm
109492559Sdesstatic void
109557429Smarkmafter_select(fd_set *readset, fd_set *writeset)
109657429Smarkm{
109799063Sdes	struct sockaddr_un sunaddr;
109858585Skris	socklen_t slen;
109957429Smarkm	char buf[1024];
1100294332Sdes	int len, sock, r;
1101204917Sdes	u_int i, orig_alloc;
1102106130Sdes	uid_t euid;
1103106130Sdes	gid_t egid;
110457429Smarkm
1105204917Sdes	for (i = 0, orig_alloc = sockets_alloc; i < orig_alloc; i++)
110657429Smarkm		switch (sockets[i].type) {
110757429Smarkm		case AUTH_UNUSED:
110857429Smarkm			break;
110957429Smarkm		case AUTH_SOCKET:
111057429Smarkm			if (FD_ISSET(sockets[i].fd, readset)) {
111158585Skris				slen = sizeof(sunaddr);
111276262Sgreen				sock = accept(sockets[i].fd,
1113162856Sdes				    (struct sockaddr *)&sunaddr, &slen);
111457429Smarkm				if (sock < 0) {
111592559Sdes					error("accept from AUTH_SOCKET: %s",
111692559Sdes					    strerror(errno));
111757429Smarkm					break;
111857429Smarkm				}
1119106130Sdes				if (getpeereid(sock, &euid, &egid) < 0) {
1120106130Sdes					error("getpeereid %d failed: %s",
1121106130Sdes					    sock, strerror(errno));
1122106130Sdes					close(sock);
1123106130Sdes					break;
1124106130Sdes				}
1125106130Sdes				if ((euid != 0) && (getuid() != euid)) {
1126106130Sdes					error("uid mismatch: "
1127106130Sdes					    "peer euid %u != uid %u",
1128106130Sdes					    (u_int) euid, (u_int) getuid());
1129106130Sdes					close(sock);
1130106130Sdes					break;
1131106130Sdes				}
113257429Smarkm				new_socket(AUTH_CONNECTION, sock);
113357429Smarkm			}
113457429Smarkm			break;
113557429Smarkm		case AUTH_CONNECTION:
1136294332Sdes			if (sshbuf_len(sockets[i].output) > 0 &&
113757429Smarkm			    FD_ISSET(sockets[i].fd, writeset)) {
1138204917Sdes				len = write(sockets[i].fd,
1139294332Sdes				    sshbuf_ptr(sockets[i].output),
1140294332Sdes				    sshbuf_len(sockets[i].output));
1141204917Sdes				if (len == -1 && (errno == EAGAIN ||
1142204917Sdes				    errno == EWOULDBLOCK ||
1143204917Sdes				    errno == EINTR))
1144204917Sdes					continue;
114557429Smarkm				if (len <= 0) {
1146106130Sdes					close_socket(&sockets[i]);
114757429Smarkm					break;
114857429Smarkm				}
1149294332Sdes				if ((r = sshbuf_consume(sockets[i].output,
1150294332Sdes				    len)) != 0)
1151294332Sdes					fatal("%s: buffer error: %s",
1152294332Sdes					    __func__, ssh_err(r));
115357429Smarkm			}
115457429Smarkm			if (FD_ISSET(sockets[i].fd, readset)) {
1155204917Sdes				len = read(sockets[i].fd, buf, sizeof(buf));
1156204917Sdes				if (len == -1 && (errno == EAGAIN ||
1157204917Sdes				    errno == EWOULDBLOCK ||
1158204917Sdes				    errno == EINTR))
1159204917Sdes					continue;
116057429Smarkm				if (len <= 0) {
1161106130Sdes					close_socket(&sockets[i]);
116257429Smarkm					break;
116357429Smarkm				}
1164294332Sdes				if ((r = sshbuf_put(sockets[i].input,
1165294332Sdes				    buf, len)) != 0)
1166294332Sdes					fatal("%s: buffer error: %s",
1167294332Sdes					    __func__, ssh_err(r));
1168294328Sdes				explicit_bzero(buf, sizeof(buf));
116957429Smarkm				process_message(&sockets[i]);
117057429Smarkm			}
117157429Smarkm			break;
117257429Smarkm		default:
117357429Smarkm			fatal("Unknown type %d", sockets[i].type);
117457429Smarkm		}
117557429Smarkm}
117657429Smarkm
117792559Sdesstatic void
1178126277Sdescleanup_socket(void)
117957429Smarkm{
1180294328Sdes	if (cleanup_pid != 0 && getpid() != cleanup_pid)
1181294328Sdes		return;
1182294328Sdes	debug("%s: cleanup", __func__);
118376262Sgreen	if (socket_name[0])
118476262Sgreen		unlink(socket_name);
118576262Sgreen	if (socket_dir[0])
118676262Sgreen		rmdir(socket_dir);
118757429Smarkm}
118857429Smarkm
1189126277Sdesvoid
119057429Smarkmcleanup_exit(int i)
119157429Smarkm{
1192126277Sdes	cleanup_socket();
1193126277Sdes	_exit(i);
119457429Smarkm}
119557429Smarkm
1196162856Sdes/*ARGSUSED*/
119792559Sdesstatic void
119876262Sgreencleanup_handler(int sig)
119957429Smarkm{
1200126277Sdes	cleanup_socket();
1201204917Sdes#ifdef ENABLE_PKCS11
1202204917Sdes	pkcs11_terminate();
1203204917Sdes#endif
120476262Sgreen	_exit(2);
120576262Sgreen}
120676262Sgreen
120792559Sdesstatic void
1208181111Sdescheck_parent_exists(void)
120992559Sdes{
1210226046Sdes	/*
1211226046Sdes	 * If our parent has exited then getppid() will return (pid_t)1,
1212226046Sdes	 * so testing for that should be safe.
1213226046Sdes	 */
1214226046Sdes	if (parent_pid != -1 && getppid() != parent_pid) {
121592559Sdes		/* printf("Parent has died - Authentication agent exiting.\n"); */
1216181111Sdes		cleanup_socket();
1217181111Sdes		_exit(2);
121892559Sdes	}
121992559Sdes}
122092559Sdes
122192559Sdesstatic void
122276262Sgreenusage(void)
122376262Sgreen{
1224294328Sdes	fprintf(stderr,
1225323136Sdes	    "usage: ssh-agent [-c | -s] [-Ddx] [-a bind_address] [-E fingerprint_hash]\n"
1226323134Sdes	    "                 [-P pkcs11_whitelist] [-t life] [command [arg ...]]\n"
1227294328Sdes	    "       ssh-agent [-c | -s] -k\n");
122857429Smarkm	exit(1);
122957429Smarkm}
123057429Smarkm
123157429Smarkmint
123257429Smarkmmain(int ac, char **av)
123357429Smarkm{
1234294336Sdes	int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0;
1235181111Sdes	int sock, fd, ch, result, saved_errno;
1236137019Sdes	u_int nalloc;
123799063Sdes	char *shell, *format, *pidstr, *agentsocket = NULL;
123899063Sdes	fd_set *readsetp = NULL, *writesetp = NULL;
123998941Sdes#ifdef HAVE_SETRLIMIT
124076262Sgreen	struct rlimit rlim;
124198941Sdes#endif
124299063Sdes	extern int optind;
124399063Sdes	extern char *optarg;
124457429Smarkm	pid_t pid;
124599063Sdes	char pidstrbuf[1 + 3 * sizeof pid];
1246181111Sdes	struct timeval *tvp = NULL;
1247197679Sdes	size_t len;
1248294328Sdes	mode_t prev_mask;
124957429Smarkm
1250296633Sdes	ssh_malloc_init();	/* must be called before any mallocs */
1251157019Sdes	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1252157019Sdes	sanitise_stdfd();
1253157019Sdes
1254106130Sdes	/* drop */
1255106130Sdes	setegid(getgid());
1256106130Sdes	setgid(getgid());
1257110506Sdes	setuid(geteuid());
1258106130Sdes
1259323129Sdes	platform_disable_tracing(0);	/* strict=no */
1260128460Sdes
1261294328Sdes#ifdef WITH_OPENSSL
1262221420Sdes	OpenSSL_add_all_algorithms();
1263294328Sdes#endif
126476262Sgreen
1265124211Sdes	__progname = ssh_get_progname(av[0]);
126698941Sdes	seed_rng();
126798941Sdes
1268323134Sdes	while ((ch = getopt(ac, av, "cDdksE:a:P:t:x")) != -1) {
126957429Smarkm		switch (ch) {
1270294332Sdes		case 'E':
1271294332Sdes			fingerprint_hash = ssh_digest_alg_by_name(optarg);
1272294332Sdes			if (fingerprint_hash == -1)
1273294332Sdes				fatal("Invalid hash algorithm \"%s\"", optarg);
1274294332Sdes			break;
127557429Smarkm		case 'c':
127657429Smarkm			if (s_flag)
127757429Smarkm				usage();
127857429Smarkm			c_flag++;
127957429Smarkm			break;
128057429Smarkm		case 'k':
128157429Smarkm			k_flag++;
128257429Smarkm			break;
1283323134Sdes		case 'P':
1284323134Sdes			if (pkcs11_whitelist != NULL)
1285323134Sdes				fatal("-P option already specified");
1286323134Sdes			pkcs11_whitelist = xstrdup(optarg);
1287323134Sdes			break;
128857429Smarkm		case 's':
128957429Smarkm			if (c_flag)
129057429Smarkm				usage();
129157429Smarkm			s_flag++;
129257429Smarkm			break;
129392559Sdes		case 'd':
1294294336Sdes			if (d_flag || D_flag)
129592559Sdes				usage();
129692559Sdes			d_flag++;
129792559Sdes			break;
1298294336Sdes		case 'D':
1299294336Sdes			if (d_flag || D_flag)
1300294336Sdes				usage();
1301294336Sdes			D_flag++;
1302294336Sdes			break;
130398684Sdes		case 'a':
130498684Sdes			agentsocket = optarg;
130598684Sdes			break;
1306113911Sdes		case 't':
1307113911Sdes			if ((lifetime = convtime(optarg)) == -1) {
1308113911Sdes				fprintf(stderr, "Invalid lifetime\n");
1309113911Sdes				usage();
1310113911Sdes			}
1311113911Sdes			break;
1312226103Sdes		case 'x':
1313226103Sdes			xcount = 0;
1314226103Sdes			break;
131557429Smarkm		default:
131657429Smarkm			usage();
131757429Smarkm		}
131857429Smarkm	}
131957429Smarkm	ac -= optind;
132057429Smarkm	av += optind;
132157429Smarkm
1322294336Sdes	if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag))
132357429Smarkm		usage();
132457429Smarkm
1325323134Sdes	if (pkcs11_whitelist == NULL)
1326323134Sdes		pkcs11_whitelist = xstrdup(DEFAULT_PKCS11_WHITELIST);
1327323134Sdes
132898684Sdes	if (ac == 0 && !c_flag && !s_flag) {
132957429Smarkm		shell = getenv("SHELL");
1330197679Sdes		if (shell != NULL && (len = strlen(shell)) > 2 &&
1331197679Sdes		    strncmp(shell + len - 3, "csh", 3) == 0)
133257429Smarkm			c_flag = 1;
133357429Smarkm	}
133457429Smarkm	if (k_flag) {
1335162856Sdes		const char *errstr = NULL;
1336162856Sdes
133757429Smarkm		pidstr = getenv(SSH_AGENTPID_ENV_NAME);
133857429Smarkm		if (pidstr == NULL) {
133957429Smarkm			fprintf(stderr, "%s not set, cannot kill agent\n",
134076262Sgreen			    SSH_AGENTPID_ENV_NAME);
134157429Smarkm			exit(1);
134257429Smarkm		}
1343162856Sdes		pid = (int)strtonum(pidstr, 2, INT_MAX, &errstr);
1344162856Sdes		if (errstr) {
1345162856Sdes			fprintf(stderr,
1346162856Sdes			    "%s=\"%s\", which is not a good PID: %s\n",
1347162856Sdes			    SSH_AGENTPID_ENV_NAME, pidstr, errstr);
134857429Smarkm			exit(1);
134957429Smarkm		}
135057429Smarkm		if (kill(pid, SIGTERM) == -1) {
135157429Smarkm			perror("kill");
135257429Smarkm			exit(1);
135357429Smarkm		}
135457429Smarkm		format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
135557429Smarkm		printf(format, SSH_AUTHSOCKET_ENV_NAME);
135657429Smarkm		printf(format, SSH_AGENTPID_ENV_NAME);
135798684Sdes		printf("echo Agent pid %ld killed;\n", (long)pid);
135857429Smarkm		exit(0);
135957429Smarkm	}
136057429Smarkm	parent_pid = getpid();
136157429Smarkm
136298684Sdes	if (agentsocket == NULL) {
136398684Sdes		/* Create private directory for agent socket */
1364221420Sdes		mktemp_proto(socket_dir, sizeof(socket_dir));
136598684Sdes		if (mkdtemp(socket_dir) == NULL) {
136698684Sdes			perror("mkdtemp: private socket dir");
136798684Sdes			exit(1);
136898684Sdes		}
136998684Sdes		snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
137098684Sdes		    (long)parent_pid);
137198684Sdes	} else {
137298684Sdes		/* Try to use specified agent socket */
137398684Sdes		socket_dir[0] = '\0';
137498684Sdes		strlcpy(socket_name, agentsocket, sizeof socket_name);
137557429Smarkm	}
137657429Smarkm
137757429Smarkm	/*
137857429Smarkm	 * Create socket early so it will exist before command gets run from
137957429Smarkm	 * the parent.
138057429Smarkm	 */
1381294328Sdes	prev_mask = umask(0177);
1382294328Sdes	sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0);
138357429Smarkm	if (sock < 0) {
1384294328Sdes		/* XXX - unix_listener() calls error() not perror() */
1385147005Sdes		*socket_name = '\0'; /* Don't unlink any existing file */
138657429Smarkm		cleanup_exit(1);
138757429Smarkm	}
138898941Sdes	umask(prev_mask);
138976262Sgreen
139057429Smarkm	/*
139157429Smarkm	 * Fork, and have the parent execute the command, if any, or present
139257429Smarkm	 * the socket data.  The child continues as the authentication agent.
139357429Smarkm	 */
1394294336Sdes	if (D_flag || d_flag) {
1395294336Sdes		log_init(__progname,
1396294336Sdes		    d_flag ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
1397294336Sdes		    SYSLOG_FACILITY_AUTH, 1);
139892559Sdes		format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
139992559Sdes		printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
140092559Sdes		    SSH_AUTHSOCKET_ENV_NAME);
140198684Sdes		printf("echo Agent pid %ld;\n", (long)parent_pid);
1402296633Sdes		fflush(stdout);
140392559Sdes		goto skip;
140492559Sdes	}
140557429Smarkm	pid = fork();
140657429Smarkm	if (pid == -1) {
140757429Smarkm		perror("fork");
140892559Sdes		cleanup_exit(1);
140957429Smarkm	}
141057429Smarkm	if (pid != 0) {		/* Parent - execute the given command. */
141157429Smarkm		close(sock);
141298684Sdes		snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
141357429Smarkm		if (ac == 0) {
141457429Smarkm			format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
141557429Smarkm			printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
141676262Sgreen			    SSH_AUTHSOCKET_ENV_NAME);
141757429Smarkm			printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
141876262Sgreen			    SSH_AGENTPID_ENV_NAME);
141998684Sdes			printf("echo Agent pid %ld;\n", (long)pid);
142057429Smarkm			exit(0);
142157429Smarkm		}
142269591Sgreen		if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
142369591Sgreen		    setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
142469591Sgreen			perror("setenv");
142569591Sgreen			exit(1);
142669591Sgreen		}
142757429Smarkm		execvp(av[0], av);
142857429Smarkm		perror(av[0]);
142957429Smarkm		exit(1);
143057429Smarkm	}
143192559Sdes	/* child */
143292559Sdes	log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
143392559Sdes
143492559Sdes	if (setsid() == -1) {
143592559Sdes		error("setsid: %s", strerror(errno));
143692559Sdes		cleanup_exit(1);
143792559Sdes	}
143892559Sdes
143992559Sdes	(void)chdir("/");
1440113911Sdes	if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1441113911Sdes		/* XXX might close listen socket */
1442113911Sdes		(void)dup2(fd, STDIN_FILENO);
1443113911Sdes		(void)dup2(fd, STDOUT_FILENO);
1444113911Sdes		(void)dup2(fd, STDERR_FILENO);
1445113911Sdes		if (fd > 2)
1446113911Sdes			close(fd);
1447113911Sdes	}
144857429Smarkm
144998941Sdes#ifdef HAVE_SETRLIMIT
145076262Sgreen	/* deny core dumps, since memory contains unencrypted private keys */
145176262Sgreen	rlim.rlim_cur = rlim.rlim_max = 0;
145276262Sgreen	if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
145392559Sdes		error("setrlimit RLIMIT_CORE: %s", strerror(errno));
145476262Sgreen		cleanup_exit(1);
145576262Sgreen	}
145698941Sdes#endif
145792559Sdes
145892559Sdesskip:
1459204917Sdes
1460294328Sdes	cleanup_pid = getpid();
1461294328Sdes
1462204917Sdes#ifdef ENABLE_PKCS11
1463204917Sdes	pkcs11_init(0);
1464204917Sdes#endif
146557429Smarkm	new_socket(AUTH_SOCKET, sock);
1466181111Sdes	if (ac > 0)
1467181111Sdes		parent_alive_interval = 10;
146865674Skris	idtab_init();
1469255767Sdes	signal(SIGPIPE, SIG_IGN);
1470294336Sdes	signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN);
147176262Sgreen	signal(SIGHUP, cleanup_handler);
147276262Sgreen	signal(SIGTERM, cleanup_handler);
147392559Sdes	nalloc = 0;
147492559Sdes
1475323134Sdes	if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1)
1476296633Sdes		fatal("%s: pledge: %s", __progname, strerror(errno));
1477296633Sdes	platform_pledge_agent();
1478296633Sdes
147957429Smarkm	while (1) {
1480181111Sdes		prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
1481181111Sdes		result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
1482181111Sdes		saved_errno = errno;
1483181111Sdes		if (parent_alive_interval != 0)
1484181111Sdes			check_parent_exists();
1485181111Sdes		(void) reaper();	/* remove expired keys */
1486181111Sdes		if (result < 0) {
1487181111Sdes			if (saved_errno == EINTR)
148857429Smarkm				continue;
1489181111Sdes			fatal("select: %s", strerror(saved_errno));
1490181111Sdes		} else if (result > 0)
1491181111Sdes			after_select(readsetp, writesetp);
149257429Smarkm	}
149357429Smarkm	/* NOTREACHED */
149457429Smarkm}
1495