1d059297112922cabb0c674840589be8db821fd9aAdam Langley/* $OpenBSD: ssh-agent.c,v 1.199 2015/03/04 21:12:59 djm Exp $ */
2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Author: Tatu Ylonen <ylo@cs.hut.fi>
4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *                    All rights reserved
6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * The authentication agent program.
7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * As far as I am concerned, the code I have written for this software
9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * can be used freely for any purpose.  Any derived versions of this
10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * software must be clearly marked as such, and if the derived work is
11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * incompatible with the protocol description in the RFC file, it must be
12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * called by a name other than "ssh" or "Secure Shell".
13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Redistribution and use in source and binary forms, with or without
17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * modification, are permitted provided that the following conditions
18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * are met:
19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 1. Redistributions of source code must retain the above copyright
20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    notice, this list of conditions and the following disclaimer.
21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 2. Redistributions in binary form must reproduce the above copyright
22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    notice, this list of conditions and the following disclaimer in the
23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    documentation and/or other materials provided with the distribution.
24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
36bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
37bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h"
38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
39d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <sys/param.h>	/* MIN MAX */
40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h>
41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/param.h>
42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/resource.h>
43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/stat.h>
44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/socket.h>
45bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_SYS_TIME_H
46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <sys/time.h>
47bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
48bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_SYS_UN_H
49bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <sys/un.h>
50bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
51bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "openbsd-compat/sys-queue.h"
52bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
53d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
54bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <openssl/evp.h>
55bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "openbsd-compat/openssl-compat.h"
56d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
57bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
58bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <errno.h>
59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <fcntl.h>
60d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <limits.h>
61bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_PATHS_H
62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <paths.h>
63bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
64bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <signal.h>
65bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdarg.h>
66bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdio.h>
67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdlib.h>
68bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <time.h>
69bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h>
70bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <unistd.h>
71bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
72d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "key.h"	/* XXX for typedef */
73d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "buffer.h"	/* XXX for typedef */
74d059297112922cabb0c674840589be8db821fd9aAdam Langley
75bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "xmalloc.h"
76bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh.h"
77bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "rsa.h"
78d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshbuf.h"
79d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshkey.h"
80bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "authfd.h"
81bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "compat.h"
82bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h"
83bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "misc.h"
84d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "digest.h"
85d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h"
86bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
87bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef ENABLE_PKCS11
88bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh-pkcs11.h"
89bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
90bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
91bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#if defined(HAVE_SYS_PRCTL_H)
92bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/prctl.h>	/* For prctl() and PR_SET_DUMPABLE */
93bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
94bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
95bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmantypedef enum {
96bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	AUTH_UNUSED,
97bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	AUTH_SOCKET,
98bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	AUTH_CONNECTION
99bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} sock_type;
100bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmantypedef struct {
102bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int fd;
103bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	sock_type type;
104d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *input;
105d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *output;
106d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *request;
107bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} SocketEntry;
108bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
109bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanu_int sockets_alloc = 0;
110bd77cf78387b72b7b3ea870459077672bf75c3b5Greg HartmanSocketEntry *sockets = NULL;
111bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
112bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmantypedef struct identity {
113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	TAILQ_ENTRY(identity) next;
114d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *key;
115bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *comment;
116bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *provider;
117d059297112922cabb0c674840589be8db821fd9aAdam Langley	time_t death;
118bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int confirm;
119bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} Identity;
120bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
121bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmantypedef struct {
122bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int nentries;
123bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	TAILQ_HEAD(idqueue, identity) idlist;
124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} Idtab;
125bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
126bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* private key table, one per protocol version */
127bd77cf78387b72b7b3ea870459077672bf75c3b5Greg HartmanIdtab idtable[3];
128bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
129bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint max_fd = 0;
130bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
131bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* pid of shell == parent of agent */
132bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanpid_t parent_pid = -1;
133d059297112922cabb0c674840589be8db821fd9aAdam Langleytime_t parent_alive_interval = 0;
134d059297112922cabb0c674840589be8db821fd9aAdam Langley
135d059297112922cabb0c674840589be8db821fd9aAdam Langley/* pid of process for which cleanup_socket is applicable */
136d059297112922cabb0c674840589be8db821fd9aAdam Langleypid_t cleanup_pid = 0;
137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
138bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* pathname and directory for AUTH_SOCKET */
139d059297112922cabb0c674840589be8db821fd9aAdam Langleychar socket_name[PATH_MAX];
140d059297112922cabb0c674840589be8db821fd9aAdam Langleychar socket_dir[PATH_MAX];
141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
142bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* locking */
143bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint locked = 0;
144bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanchar *lock_passwd = NULL;
145bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
146bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern char *__progname;
147bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
148d059297112922cabb0c674840589be8db821fd9aAdam Langley/* Default lifetime in seconds (0 == forever) */
149d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic long lifetime = 0;
150d059297112922cabb0c674840589be8db821fd9aAdam Langley
151d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int fingerprint_hash = SSH_FP_HASH_DEFAULT;
152bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
154bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanclose_socket(SocketEntry *e)
155bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	close(e->fd);
157bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	e->fd = -1;
158bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	e->type = AUTH_UNUSED;
159d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(e->input);
160d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(e->output);
161d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(e->request);
162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
163bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
165bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanidtab_init(void)
166bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int i;
168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (i = 0; i <=2; i++) {
170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		TAILQ_INIT(&idtable[i].idlist);
171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		idtable[i].nentries = 0;
172bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
173bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
174bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
175bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* return private key table for requested protocol version */
176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic Idtab *
177bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanidtab_lookup(int version)
178bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
179bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (version < 1 || version > 2)
180bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		fatal("internal error, bad protocol version %d", version);
181bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return &idtable[version];
182bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
184bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanfree_identity(Identity *id)
186bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
187d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshkey_free(id->key);
188d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(id->provider);
189d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(id->comment);
190d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(id);
191bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
193bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* return matching private key for given public key */
194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic Identity *
195d059297112922cabb0c674840589be8db821fd9aAdam Langleylookup_identity(struct sshkey *key, int version)
196bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
197bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Identity *id;
198bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
199bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Idtab *tab = idtab_lookup(version);
200bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	TAILQ_FOREACH(id, &tab->idlist, next) {
201d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (sshkey_equal(key, id->key))
202bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return (id);
203bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
204bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (NULL);
205bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
207bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Check confirmation of keysign request */
208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int
209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanconfirm_key(Identity *id)
210bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *p;
212bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int ret = -1;
213bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
214d059297112922cabb0c674840589be8db821fd9aAdam Langley	p = sshkey_fingerprint(id->key, fingerprint_hash, SSH_FP_DEFAULT);
215d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (p != NULL &&
216d059297112922cabb0c674840589be8db821fd9aAdam Langley	    ask_permission("Allow use of key %s?\nKey fingerprint %s.",
217bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    id->comment, p))
218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		ret = 0;
219d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(p);
220bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
221bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (ret);
222bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
223bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
224d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic void
225d059297112922cabb0c674840589be8db821fd9aAdam Langleysend_status(SocketEntry *e, int success)
226d059297112922cabb0c674840589be8db821fd9aAdam Langley{
227d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
228d059297112922cabb0c674840589be8db821fd9aAdam Langley
229d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_put_u32(e->output, 1)) != 0 ||
230d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_put_u8(e->output, success ?
231d059297112922cabb0c674840589be8db821fd9aAdam Langley	    SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0)
232d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
233d059297112922cabb0c674840589be8db821fd9aAdam Langley}
234d059297112922cabb0c674840589be8db821fd9aAdam Langley
235bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* send list of supported public keys to 'client' */
236bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
237bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_request_identities(SocketEntry *e, int version)
238bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
239bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Idtab *tab = idtab_lookup(version);
240bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Identity *id;
241d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *msg;
242d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
243d059297112922cabb0c674840589be8db821fd9aAdam Langley
244d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((msg = sshbuf_new()) == NULL)
245d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: sshbuf_new failed", __func__);
246d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_put_u8(msg, (version == 1) ?
247d059297112922cabb0c674840589be8db821fd9aAdam Langley	    SSH_AGENT_RSA_IDENTITIES_ANSWER :
248d059297112922cabb0c674840589be8db821fd9aAdam Langley	    SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
249d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_put_u32(msg, tab->nentries)) != 0)
250d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
251bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	TAILQ_FOREACH(id, &tab->idlist, next) {
252bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (id->key->type == KEY_RSA1) {
253d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
254d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((r = sshbuf_put_u32(msg,
255d059297112922cabb0c674840589be8db821fd9aAdam Langley			    BN_num_bits(id->key->rsa->n))) != 0 ||
256d059297112922cabb0c674840589be8db821fd9aAdam Langley			    (r = sshbuf_put_bignum1(msg,
257d059297112922cabb0c674840589be8db821fd9aAdam Langley			    id->key->rsa->e)) != 0 ||
258d059297112922cabb0c674840589be8db821fd9aAdam Langley			    (r = sshbuf_put_bignum1(msg,
259d059297112922cabb0c674840589be8db821fd9aAdam Langley			    id->key->rsa->n)) != 0)
260d059297112922cabb0c674840589be8db821fd9aAdam Langley				fatal("%s: buffer error: %s",
261d059297112922cabb0c674840589be8db821fd9aAdam Langley				    __func__, ssh_err(r));
262d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
263bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		} else {
264bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			u_char *blob;
265d059297112922cabb0c674840589be8db821fd9aAdam Langley			size_t blen;
266d059297112922cabb0c674840589be8db821fd9aAdam Langley
267d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((r = sshkey_to_blob(id->key, &blob, &blen)) != 0) {
268d059297112922cabb0c674840589be8db821fd9aAdam Langley				error("%s: sshkey_to_blob: %s", __func__,
269d059297112922cabb0c674840589be8db821fd9aAdam Langley				    ssh_err(r));
270d059297112922cabb0c674840589be8db821fd9aAdam Langley				continue;
271d059297112922cabb0c674840589be8db821fd9aAdam Langley			}
272d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((r = sshbuf_put_string(msg, blob, blen)) != 0)
273d059297112922cabb0c674840589be8db821fd9aAdam Langley				fatal("%s: buffer error: %s",
274d059297112922cabb0c674840589be8db821fd9aAdam Langley				    __func__, ssh_err(r));
275d059297112922cabb0c674840589be8db821fd9aAdam Langley			free(blob);
276bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
277d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshbuf_put_cstring(msg, id->comment)) != 0)
278d059297112922cabb0c674840589be8db821fd9aAdam Langley			fatal("%s: buffer error: %s", __func__, ssh_err(r));
279bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
280d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
281d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
282d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(msg);
283bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
284bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
285d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
286bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* ssh1 only */
287bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
288bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_authentication_challenge1(SocketEntry *e)
289bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
290bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_char buf[32], mdbuf[16], session_id[16];
291bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int response_type;
292bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	BIGNUM *challenge;
293bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Identity *id;
294d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, len;
295d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *msg;
296d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct ssh_digest_ctx *md;
297d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *key;
298d059297112922cabb0c674840589be8db821fd9aAdam Langley
299d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((msg = sshbuf_new()) == NULL)
300d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: sshbuf_new failed", __func__);
301d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((key = sshkey_new(KEY_RSA1)) == NULL)
302d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: sshkey_new failed", __func__);
303bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((challenge = BN_new()) == NULL)
304d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: BN_new failed", __func__);
305bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
306d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get_u32(e->request, NULL)) != 0 || /* ignored */
307d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(e->request, key->rsa->e)) != 0 ||
308d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(e->request, key->rsa->n)) != 0 ||
309d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(e->request, challenge)))
310d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
311bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
312bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Only protocol 1.1 is supported */
313d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshbuf_len(e->request) == 0)
314bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		goto failure;
315d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get(e->request, session_id, sizeof(session_id))) != 0 ||
316d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_u32(e->request, &response_type)) != 0)
317d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
318bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (response_type != 1)
319bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		goto failure;
320bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
321bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	id = lookup_identity(key, 1);
322bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (id != NULL && (!id->confirm || confirm_key(id) == 0)) {
323d059297112922cabb0c674840589be8db821fd9aAdam Langley		struct sshkey *private = id->key;
324bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Decrypt the challenge using the private key. */
325d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = rsa_private_decrypt(challenge, challenge,
326d059297112922cabb0c674840589be8db821fd9aAdam Langley		    private->rsa) != 0)) {
327d059297112922cabb0c674840589be8db821fd9aAdam Langley			fatal("%s: rsa_public_encrypt: %s", __func__,
328d059297112922cabb0c674840589be8db821fd9aAdam Langley			    ssh_err(r));
329d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto failure;	/* XXX ? */
330d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
331bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
332d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* The response is MD5 of decrypted challenge plus session id */
333bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		len = BN_num_bytes(challenge);
334bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (len <= 0 || len > 32) {
335d059297112922cabb0c674840589be8db821fd9aAdam Langley			logit("%s: bad challenge length %d", __func__, len);
336bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			goto failure;
337bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
338bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		memset(buf, 0, 32);
339bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		BN_bn2bin(challenge, buf + 32 - len);
340d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
341d059297112922cabb0c674840589be8db821fd9aAdam Langley		    ssh_digest_update(md, buf, 32) < 0 ||
342d059297112922cabb0c674840589be8db821fd9aAdam Langley		    ssh_digest_update(md, session_id, 16) < 0 ||
343d059297112922cabb0c674840589be8db821fd9aAdam Langley		    ssh_digest_final(md, mdbuf, sizeof(mdbuf)) < 0)
344d059297112922cabb0c674840589be8db821fd9aAdam Langley			fatal("%s: md5 failed", __func__);
345d059297112922cabb0c674840589be8db821fd9aAdam Langley		ssh_digest_free(md);
346bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
347bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Send the response. */
348d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshbuf_put_u8(msg, SSH_AGENT_RSA_RESPONSE)) != 0 ||
349d059297112922cabb0c674840589be8db821fd9aAdam Langley		    (r = sshbuf_put(msg, mdbuf, sizeof(mdbuf))) != 0)
350d059297112922cabb0c674840589be8db821fd9aAdam Langley			fatal("%s: buffer error: %s", __func__, ssh_err(r));
351bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		goto send;
352bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
353bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
354d059297112922cabb0c674840589be8db821fd9aAdam Langley failure:
355bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Unknown identity or protocol error.  Send failure. */
356d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
357d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
358d059297112922cabb0c674840589be8db821fd9aAdam Langley send:
359d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
360d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
361d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshkey_free(key);
362bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	BN_clear_free(challenge);
363d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(msg);
364bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
365d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
366bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
367bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* ssh2 only */
368bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
369bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_sign_request2(SocketEntry *e)
370bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
371bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_char *blob, *data, *signature = NULL;
372d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t blen, dlen, slen = 0;
373d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int compat = 0, flags;
374d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, ok = -1;
375d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *msg;
376d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *key;
377d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct identity *id;
378d059297112922cabb0c674840589be8db821fd9aAdam Langley
379d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((msg = sshbuf_new()) == NULL)
380d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: sshbuf_new failed", __func__);
381d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get_string(e->request, &blob, &blen)) != 0 ||
382d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_string(e->request, &data, &dlen)) != 0 ||
383d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_u32(e->request, &flags)) != 0)
384d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
385bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (flags & SSH_AGENT_OLD_SIGNATURE)
386d059297112922cabb0c674840589be8db821fd9aAdam Langley		compat = SSH_BUG_SIGBLOB;
387d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_from_blob(blob, blen, &key)) != 0) {
388d059297112922cabb0c674840589be8db821fd9aAdam Langley		error("%s: cannot parse key blob: %s", __func__, ssh_err(ok));
389d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto send;
390bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
391d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((id = lookup_identity(key, 2)) == NULL) {
392d059297112922cabb0c674840589be8db821fd9aAdam Langley		verbose("%s: %s key not found", __func__, sshkey_type(key));
393d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto send;
394d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
395d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (id->confirm && confirm_key(id) != 0) {
396d059297112922cabb0c674840589be8db821fd9aAdam Langley		verbose("%s: user refused key", __func__);
397d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto send;
398d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
399d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_sign(id->key, &signature, &slen,
400d059297112922cabb0c674840589be8db821fd9aAdam Langley	    data, dlen, compat)) != 0) {
401d059297112922cabb0c674840589be8db821fd9aAdam Langley		error("%s: sshkey_sign: %s", __func__, ssh_err(ok));
402d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto send;
403bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
404d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* Success */
405d059297112922cabb0c674840589be8db821fd9aAdam Langley	ok = 0;
406d059297112922cabb0c674840589be8db821fd9aAdam Langley send:
407d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshkey_free(key);
408d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (ok == 0) {
409d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 ||
410d059297112922cabb0c674840589be8db821fd9aAdam Langley		    (r = sshbuf_put_string(msg, signature, slen)) != 0)
411d059297112922cabb0c674840589be8db821fd9aAdam Langley			fatal("%s: buffer error: %s", __func__, ssh_err(r));
412d059297112922cabb0c674840589be8db821fd9aAdam Langley	} else if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
413d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
414d059297112922cabb0c674840589be8db821fd9aAdam Langley
415d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
416d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
417d059297112922cabb0c674840589be8db821fd9aAdam Langley
418d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(msg);
419d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(data);
420d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(blob);
421d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(signature);
422bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
423bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
424bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* shared */
425bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
426bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_remove_identity(SocketEntry *e, int version)
427bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
428d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t blen;
429d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, success = 0;
430d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *key = NULL;
431bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_char *blob;
432d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
433d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int bits;
434d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_SSH1 */
435bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
436bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	switch (version) {
437d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
438bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case 1:
439d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((key = sshkey_new(KEY_RSA1)) == NULL) {
440d059297112922cabb0c674840589be8db821fd9aAdam Langley			error("%s: sshkey_new failed", __func__);
441d059297112922cabb0c674840589be8db821fd9aAdam Langley			return;
442d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
443d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshbuf_get_u32(e->request, &bits)) != 0 ||
444d059297112922cabb0c674840589be8db821fd9aAdam Langley		    (r = sshbuf_get_bignum1(e->request, key->rsa->e)) != 0 ||
445d059297112922cabb0c674840589be8db821fd9aAdam Langley		    (r = sshbuf_get_bignum1(e->request, key->rsa->n)) != 0)
446d059297112922cabb0c674840589be8db821fd9aAdam Langley			fatal("%s: buffer error: %s", __func__, ssh_err(r));
447d059297112922cabb0c674840589be8db821fd9aAdam Langley
448d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (bits != sshkey_size(key))
449d059297112922cabb0c674840589be8db821fd9aAdam Langley			logit("Warning: identity keysize mismatch: "
450d059297112922cabb0c674840589be8db821fd9aAdam Langley			    "actual %u, announced %u",
451d059297112922cabb0c674840589be8db821fd9aAdam Langley			    sshkey_size(key), bits);
452bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
453d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_SSH1 */
454bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case 2:
455d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshbuf_get_string(e->request, &blob, &blen)) != 0)
456d059297112922cabb0c674840589be8db821fd9aAdam Langley			fatal("%s: buffer error: %s", __func__, ssh_err(r));
457d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshkey_from_blob(blob, blen, &key)) != 0)
458d059297112922cabb0c674840589be8db821fd9aAdam Langley			error("%s: sshkey_from_blob failed: %s",
459d059297112922cabb0c674840589be8db821fd9aAdam Langley			    __func__, ssh_err(r));
460d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(blob);
461bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
462bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
463bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (key != NULL) {
464bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		Identity *id = lookup_identity(key, version);
465bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (id != NULL) {
466bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			/*
467bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			 * We have this key.  Free the old key.  Since we
468bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			 * don't want to leave empty slots in the middle of
469bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			 * the array, we actually free the key there and move
470bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			 * all the entries between the empty slot and the end
471bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			 * of the array.
472bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			 */
473bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			Idtab *tab = idtab_lookup(version);
474bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (tab->nentries < 1)
475bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				fatal("process_remove_identity: "
476bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    "internal error: tab->nentries %d",
477bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    tab->nentries);
478bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			TAILQ_REMOVE(&tab->idlist, id, next);
479bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			free_identity(id);
480bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			tab->nentries--;
481bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			success = 1;
482bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
483d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshkey_free(key);
484bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
485d059297112922cabb0c674840589be8db821fd9aAdam Langley	send_status(e, success);
486bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
487bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
488bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
489bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_remove_all_identities(SocketEntry *e, int version)
490bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
491bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Idtab *tab = idtab_lookup(version);
492bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Identity *id;
493bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
494bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Loop over all identities and clear the keys. */
495bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (id = TAILQ_FIRST(&tab->idlist); id;
496bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    id = TAILQ_FIRST(&tab->idlist)) {
497bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		TAILQ_REMOVE(&tab->idlist, id, next);
498bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		free_identity(id);
499bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
500bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
501bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Mark that there are no identities. */
502bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	tab->nentries = 0;
503bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
504bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Send success. */
505d059297112922cabb0c674840589be8db821fd9aAdam Langley	send_status(e, 1);
506bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
507bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
508bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* removes expired keys and returns number of seconds until the next expiry */
509d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic time_t
510bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanreaper(void)
511bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
512d059297112922cabb0c674840589be8db821fd9aAdam Langley	time_t deadline = 0, now = monotime();
513bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Identity *id, *nxt;
514bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int version;
515bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Idtab *tab;
516bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
517bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (version = 1; version < 3; version++) {
518bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		tab = idtab_lookup(version);
519bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
520bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			nxt = TAILQ_NEXT(id, next);
521bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (id->death == 0)
522bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				continue;
523bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (now >= id->death) {
524bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				debug("expiring key '%s'", id->comment);
525bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				TAILQ_REMOVE(&tab->idlist, id, next);
526bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				free_identity(id);
527bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				tab->nentries--;
528bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			} else
529bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				deadline = (deadline == 0) ? id->death :
530bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    MIN(deadline, id->death);
531bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
532bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
533bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (deadline == 0 || deadline <= now)
534bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
535bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	else
536bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return (deadline - now);
537bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
538bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
539d059297112922cabb0c674840589be8db821fd9aAdam Langley/*
540d059297112922cabb0c674840589be8db821fd9aAdam Langley * XXX this and the corresponding serialisation function probably belongs
541d059297112922cabb0c674840589be8db821fd9aAdam Langley * in key.c
542d059297112922cabb0c674840589be8db821fd9aAdam Langley */
543d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
544d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int
545d059297112922cabb0c674840589be8db821fd9aAdam Langleyagent_decode_rsa1(struct sshbuf *m, struct sshkey **kp)
546d059297112922cabb0c674840589be8db821fd9aAdam Langley{
547d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *k = NULL;
548d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r = SSH_ERR_INTERNAL_ERROR;
549d059297112922cabb0c674840589be8db821fd9aAdam Langley
550d059297112922cabb0c674840589be8db821fd9aAdam Langley	*kp = NULL;
551d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((k = sshkey_new_private(KEY_RSA1)) == NULL)
552d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_ALLOC_FAIL;
553d059297112922cabb0c674840589be8db821fd9aAdam Langley
554d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get_u32(m, NULL)) != 0 ||		/* ignored */
555d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(m, k->rsa->n)) != 0 ||
556d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(m, k->rsa->e)) != 0 ||
557d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(m, k->rsa->d)) != 0 ||
558d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(m, k->rsa->iqmp)) != 0 ||
559d059297112922cabb0c674840589be8db821fd9aAdam Langley	    /* SSH1 and SSL have p and q swapped */
560d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(m, k->rsa->q)) != 0 ||	/* p */
561d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_bignum1(m, k->rsa->p)) != 0) 	/* q */
562d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
563d059297112922cabb0c674840589be8db821fd9aAdam Langley
564d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* Generate additional parameters */
565d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = rsa_generate_additional_parameters(k->rsa)) != 0)
566d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
567d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* enable blinding */
568d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (RSA_blinding_on(k->rsa, NULL) != 1) {
569d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_LIBCRYPTO_ERROR;
570d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
571d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
572d059297112922cabb0c674840589be8db821fd9aAdam Langley
573d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0; /* success */
574d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
575d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (r == 0)
576d059297112922cabb0c674840589be8db821fd9aAdam Langley		*kp = k;
577d059297112922cabb0c674840589be8db821fd9aAdam Langley	else
578d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshkey_free(k);
579d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
580d059297112922cabb0c674840589be8db821fd9aAdam Langley}
581d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_SSH1 */
582d059297112922cabb0c674840589be8db821fd9aAdam Langley
583bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
584bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_add_identity(SocketEntry *e, int version)
585bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
586bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Idtab *tab = idtab_lookup(version);
587bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Identity *id;
588d059297112922cabb0c674840589be8db821fd9aAdam Langley	int success = 0, confirm = 0;
589d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int seconds;
590d059297112922cabb0c674840589be8db821fd9aAdam Langley	char *comment = NULL;
591d059297112922cabb0c674840589be8db821fd9aAdam Langley	time_t death = 0;
592d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *k = NULL;
593d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char ctype;
594d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r = SSH_ERR_INTERNAL_ERROR;
595bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
596bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	switch (version) {
597d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
598bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case 1:
599d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = agent_decode_rsa1(e->request, &k);
600bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
601d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_SSH1 */
602bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case 2:
603d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = sshkey_private_deserialize(e->request, &k);
604bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
605bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
606d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (r != 0 || k == NULL ||
607d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) {
608d059297112922cabb0c674840589be8db821fd9aAdam Langley		error("%s: decode private key: %s", __func__, ssh_err(r));
609d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto err;
610bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
611d059297112922cabb0c674840589be8db821fd9aAdam Langley
612d059297112922cabb0c674840589be8db821fd9aAdam Langley	while (sshbuf_len(e->request)) {
613d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshbuf_get_u8(e->request, &ctype)) != 0) {
614d059297112922cabb0c674840589be8db821fd9aAdam Langley			error("%s: buffer error: %s", __func__, ssh_err(r));
615d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto err;
616d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
617d059297112922cabb0c674840589be8db821fd9aAdam Langley		switch (ctype) {
618bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case SSH_AGENT_CONSTRAIN_LIFETIME:
619d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((r = sshbuf_get_u32(e->request, &seconds)) != 0) {
620d059297112922cabb0c674840589be8db821fd9aAdam Langley				error("%s: bad lifetime constraint: %s",
621d059297112922cabb0c674840589be8db821fd9aAdam Langley				    __func__, ssh_err(r));
622d059297112922cabb0c674840589be8db821fd9aAdam Langley				goto err;
623d059297112922cabb0c674840589be8db821fd9aAdam Langley			}
624d059297112922cabb0c674840589be8db821fd9aAdam Langley			death = monotime() + seconds;
625bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
626bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case SSH_AGENT_CONSTRAIN_CONFIRM:
627bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			confirm = 1;
628bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
629bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		default:
630d059297112922cabb0c674840589be8db821fd9aAdam Langley			error("%s: Unknown constraint %d", __func__, ctype);
631d059297112922cabb0c674840589be8db821fd9aAdam Langley err:
632d059297112922cabb0c674840589be8db821fd9aAdam Langley			sshbuf_reset(e->request);
633d059297112922cabb0c674840589be8db821fd9aAdam Langley			free(comment);
634d059297112922cabb0c674840589be8db821fd9aAdam Langley			sshkey_free(k);
635bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			goto send;
636bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
637bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
638d059297112922cabb0c674840589be8db821fd9aAdam Langley
639bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	success = 1;
640bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (lifetime && !death)
641d059297112922cabb0c674840589be8db821fd9aAdam Langley		death = monotime() + lifetime;
642bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((id = lookup_identity(k, version)) == NULL) {
643bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		id = xcalloc(1, sizeof(Identity));
644bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		id->key = k;
645bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		TAILQ_INSERT_TAIL(&tab->idlist, id, next);
646bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Increment the number of identities. */
647bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		tab->nentries++;
648bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	} else {
649d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshkey_free(k);
650d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(id->comment);
651bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
652bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	id->comment = comment;
653bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	id->death = death;
654bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	id->confirm = confirm;
655bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmansend:
656d059297112922cabb0c674840589be8db821fd9aAdam Langley	send_status(e, success);
657bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
658bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
659bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* XXX todo: encrypt sensitive data with passphrase */
660bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
661bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_lock_agent(SocketEntry *e, int lock)
662bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
663d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, success = 0;
664bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *passwd;
665bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
666d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get_cstring(e->request, &passwd, NULL)) != 0)
667d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
668bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (locked && !lock && strcmp(passwd, lock_passwd) == 0) {
669bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		locked = 0;
670d059297112922cabb0c674840589be8db821fd9aAdam Langley		explicit_bzero(lock_passwd, strlen(lock_passwd));
671d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(lock_passwd);
672bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		lock_passwd = NULL;
673bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		success = 1;
674bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	} else if (!locked && lock) {
675bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		locked = 1;
676bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		lock_passwd = xstrdup(passwd);
677bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		success = 1;
678bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
679d059297112922cabb0c674840589be8db821fd9aAdam Langley	explicit_bzero(passwd, strlen(passwd));
680d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(passwd);
681d059297112922cabb0c674840589be8db821fd9aAdam Langley	send_status(e, success);
682bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
683bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
684bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
685bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanno_identities(SocketEntry *e, u_int type)
686bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
687d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *msg;
688d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
689bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
690d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((msg = sshbuf_new()) == NULL)
691d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: sshbuf_new failed", __func__);
692d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_put_u8(msg,
693bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ?
694d059297112922cabb0c674840589be8db821fd9aAdam Langley	    SSH_AGENT_RSA_IDENTITIES_ANSWER :
695d059297112922cabb0c674840589be8db821fd9aAdam Langley	    SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
696d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_put_u32(msg, 0)) != 0 ||
697d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_put_stringb(e->output, msg)) != 0)
698d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
699d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(msg);
700bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
701bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
702bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef ENABLE_PKCS11
703bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
704bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_add_smartcard_key(SocketEntry *e)
705bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
706bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *provider = NULL, *pin;
707d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, i, version, count = 0, success = 0, confirm = 0;
708d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int seconds;
709d059297112922cabb0c674840589be8db821fd9aAdam Langley	time_t death = 0;
710d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char type;
711d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey **keys = NULL, *k;
712bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Identity *id;
713bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Idtab *tab;
714bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
715d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
716d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
717d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
718bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
719d059297112922cabb0c674840589be8db821fd9aAdam Langley	while (sshbuf_len(e->request)) {
720d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshbuf_get_u8(e->request, &type)) != 0)
721d059297112922cabb0c674840589be8db821fd9aAdam Langley			fatal("%s: buffer error: %s", __func__, ssh_err(r));
722d059297112922cabb0c674840589be8db821fd9aAdam Langley		switch (type) {
723bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case SSH_AGENT_CONSTRAIN_LIFETIME:
724d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((r = sshbuf_get_u32(e->request, &seconds)) != 0)
725d059297112922cabb0c674840589be8db821fd9aAdam Langley				fatal("%s: buffer error: %s",
726d059297112922cabb0c674840589be8db821fd9aAdam Langley				    __func__, ssh_err(r));
727d059297112922cabb0c674840589be8db821fd9aAdam Langley			death = monotime() + seconds;
728bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
729bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case SSH_AGENT_CONSTRAIN_CONFIRM:
730bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			confirm = 1;
731bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
732bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		default:
733bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			error("process_add_smartcard_key: "
734bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    "Unknown constraint type %d", type);
735bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			goto send;
736bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
737bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
738bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (lifetime && !death)
739d059297112922cabb0c674840589be8db821fd9aAdam Langley		death = monotime() + lifetime;
740bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
741bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	count = pkcs11_add_provider(provider, pin, &keys);
742bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (i = 0; i < count; i++) {
743bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		k = keys[i];
744bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		version = k->type == KEY_RSA1 ? 1 : 2;
745bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		tab = idtab_lookup(version);
746bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (lookup_identity(k, version) == NULL) {
747bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			id = xcalloc(1, sizeof(Identity));
748bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			id->key = k;
749bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			id->provider = xstrdup(provider);
750bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			id->comment = xstrdup(provider); /* XXX */
751bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			id->death = death;
752bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			id->confirm = confirm;
753bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			TAILQ_INSERT_TAIL(&tab->idlist, id, next);
754bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			tab->nentries++;
755bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			success = 1;
756bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		} else {
757d059297112922cabb0c674840589be8db821fd9aAdam Langley			sshkey_free(k);
758bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
759bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		keys[i] = NULL;
760bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
761bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmansend:
762d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(pin);
763d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(provider);
764d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(keys);
765d059297112922cabb0c674840589be8db821fd9aAdam Langley	send_status(e, success);
766bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
767bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
768bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
769bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_remove_smartcard_key(SocketEntry *e)
770bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
771bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *provider = NULL, *pin = NULL;
772d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, version, success = 0;
773bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Identity *id, *nxt;
774bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	Idtab *tab;
775bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
776d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
777d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
778d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
779d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(pin);
780bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
781bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (version = 1; version < 3; version++) {
782bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		tab = idtab_lookup(version);
783bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
784bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			nxt = TAILQ_NEXT(id, next);
785d059297112922cabb0c674840589be8db821fd9aAdam Langley			/* Skip file--based keys */
786d059297112922cabb0c674840589be8db821fd9aAdam Langley			if (id->provider == NULL)
787d059297112922cabb0c674840589be8db821fd9aAdam Langley				continue;
788bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (!strcmp(provider, id->provider)) {
789bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				TAILQ_REMOVE(&tab->idlist, id, next);
790bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				free_identity(id);
791bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				tab->nentries--;
792bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			}
793bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
794bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
795bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (pkcs11_del_provider(provider) == 0)
796bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		success = 1;
797bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	else
798bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("process_remove_smartcard_key:"
799bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    " pkcs11_del_provider failed");
800d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(provider);
801d059297112922cabb0c674840589be8db821fd9aAdam Langley	send_status(e, success);
802bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
803bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif /* ENABLE_PKCS11 */
804bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
805bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* dispatch incoming messages */
806bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
807bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
808bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprocess_message(SocketEntry *e)
809bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
810d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int msg_len;
811d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char type;
812d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *cp;
813d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
814bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
815d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshbuf_len(e->input) < 5)
816bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return;		/* Incomplete message. */
817d059297112922cabb0c674840589be8db821fd9aAdam Langley	cp = sshbuf_ptr(e->input);
818d059297112922cabb0c674840589be8db821fd9aAdam Langley	msg_len = PEEK_U32(cp);
819bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (msg_len > 256 * 1024) {
820bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close_socket(e);
821bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return;
822bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
823d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshbuf_len(e->input) < msg_len + 4)
824bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return;
825bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
826bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* move the current input to e->request */
827d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_reset(e->request);
828d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get_stringb(e->input, e->request)) != 0 ||
829d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_u8(e->request, &type)) != 0)
830d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: buffer error: %s", __func__, ssh_err(r));
831bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
832bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* check wheter agent is locked */
833bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (locked && type != SSH_AGENTC_UNLOCK) {
834d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshbuf_reset(e->request);
835bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		switch (type) {
836bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
837bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case SSH2_AGENTC_REQUEST_IDENTITIES:
838bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			/* send empty lists */
839bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			no_identities(e, type);
840bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
841bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		default:
842bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			/* send a fail message for all other request types */
843d059297112922cabb0c674840589be8db821fd9aAdam Langley			send_status(e, 0);
844bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
845bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return;
846bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
847bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
848bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	debug("type %d", type);
849bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	switch (type) {
850bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_LOCK:
851bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_UNLOCK:
852bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_lock_agent(e, type == SSH_AGENTC_LOCK);
853bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
854d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
855bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* ssh1 */
856bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_RSA_CHALLENGE:
857bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_authentication_challenge1(e);
858bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
859bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
860bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_request_identities(e, 1);
861bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
862bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_ADD_RSA_IDENTITY:
863bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED:
864bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_add_identity(e, 1);
865bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
866bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_REMOVE_RSA_IDENTITY:
867bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_remove_identity(e, 1);
868bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
869d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
870bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
871d059297112922cabb0c674840589be8db821fd9aAdam Langley		process_remove_all_identities(e, 1); /* safe for !WITH_SSH1 */
872bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
873bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* ssh2 */
874bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH2_AGENTC_SIGN_REQUEST:
875bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_sign_request2(e);
876bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
877bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH2_AGENTC_REQUEST_IDENTITIES:
878bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_request_identities(e, 2);
879bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
880bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH2_AGENTC_ADD_IDENTITY:
881bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH2_AGENTC_ADD_ID_CONSTRAINED:
882bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_add_identity(e, 2);
883bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
884bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH2_AGENTC_REMOVE_IDENTITY:
885bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_remove_identity(e, 2);
886bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
887bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
888bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_remove_all_identities(e, 2);
889bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
890bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef ENABLE_PKCS11
891bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_ADD_SMARTCARD_KEY:
892bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
893bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_add_smartcard_key(e);
894bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
895bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
896bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		process_remove_smartcard_key(e);
897bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
898bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif /* ENABLE_PKCS11 */
899bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	default:
900bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Unknown message.  Respond with failure. */
901bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("Unknown message %d", type);
902d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshbuf_reset(e->request);
903d059297112922cabb0c674840589be8db821fd9aAdam Langley		send_status(e, 0);
904bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
905bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
906bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
907bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
908bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
909bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmannew_socket(sock_type type, int fd)
910bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
911bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int i, old_alloc, new_alloc;
912bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
913bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	set_nonblock(fd);
914bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
915bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fd > max_fd)
916bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		max_fd = fd;
917bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
918bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (i = 0; i < sockets_alloc; i++)
919bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (sockets[i].type == AUTH_UNUSED) {
920bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			sockets[i].fd = fd;
921d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((sockets[i].input = sshbuf_new()) == NULL)
922d059297112922cabb0c674840589be8db821fd9aAdam Langley				fatal("%s: sshbuf_new failed", __func__);
923d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((sockets[i].output = sshbuf_new()) == NULL)
924d059297112922cabb0c674840589be8db821fd9aAdam Langley				fatal("%s: sshbuf_new failed", __func__);
925d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((sockets[i].request = sshbuf_new()) == NULL)
926d059297112922cabb0c674840589be8db821fd9aAdam Langley				fatal("%s: sshbuf_new failed", __func__);
927bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			sockets[i].type = type;
928bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return;
929bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
930bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	old_alloc = sockets_alloc;
931bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	new_alloc = sockets_alloc + 10;
932bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	sockets = xrealloc(sockets, new_alloc, sizeof(sockets[0]));
933bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (i = old_alloc; i < new_alloc; i++)
934bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		sockets[i].type = AUTH_UNUSED;
935bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	sockets_alloc = new_alloc;
936bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	sockets[old_alloc].fd = fd;
937d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((sockets[old_alloc].input = sshbuf_new()) == NULL)
938d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: sshbuf_new failed", __func__);
939d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((sockets[old_alloc].output = sshbuf_new()) == NULL)
940d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: sshbuf_new failed", __func__);
941d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((sockets[old_alloc].request = sshbuf_new()) == NULL)
942d059297112922cabb0c674840589be8db821fd9aAdam Langley		fatal("%s: sshbuf_new failed", __func__);
943bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	sockets[old_alloc].type = type;
944bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
945bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
946bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int
947bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanprepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
948bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman    struct timeval **tvpp)
949bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
950d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int i, sz;
951bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int n = 0;
952bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	static struct timeval tv;
953d059297112922cabb0c674840589be8db821fd9aAdam Langley	time_t deadline;
954bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
955bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (i = 0; i < sockets_alloc; i++) {
956bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		switch (sockets[i].type) {
957bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case AUTH_SOCKET:
958bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case AUTH_CONNECTION:
959bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			n = MAX(n, sockets[i].fd);
960bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
961bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case AUTH_UNUSED:
962bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
963bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		default:
964bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			fatal("Unknown socket type %d", sockets[i].type);
965bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
966bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
967bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
968bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
969bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
970bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (*fdrp == NULL || sz > *nallocp) {
971d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(*fdrp);
972d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(*fdwp);
973bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		*fdrp = xmalloc(sz);
974bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		*fdwp = xmalloc(sz);
975bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		*nallocp = sz;
976bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
977bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (n < *fdl)
978bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		debug("XXX shrink: %d < %d", n, *fdl);
979bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	*fdl = n;
980bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	memset(*fdrp, 0, sz);
981bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	memset(*fdwp, 0, sz);
982bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
983bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (i = 0; i < sockets_alloc; i++) {
984bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		switch (sockets[i].type) {
985bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case AUTH_SOCKET:
986bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case AUTH_CONNECTION:
987bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			FD_SET(sockets[i].fd, *fdrp);
988d059297112922cabb0c674840589be8db821fd9aAdam Langley			if (sshbuf_len(sockets[i].output) > 0)
989bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				FD_SET(sockets[i].fd, *fdwp);
990bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
991bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		default:
992bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
993bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
994bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
995bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	deadline = reaper();
996bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (parent_alive_interval != 0)
997bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		deadline = (deadline == 0) ? parent_alive_interval :
998bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    MIN(deadline, parent_alive_interval);
999bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (deadline == 0) {
1000bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		*tvpp = NULL;
1001bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	} else {
1002bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		tv.tv_sec = deadline;
1003bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		tv.tv_usec = 0;
1004bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		*tvpp = &tv;
1005bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1006bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (1);
1007bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
1008bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1009bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
1010bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanafter_select(fd_set *readset, fd_set *writeset)
1011bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
1012bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct sockaddr_un sunaddr;
1013bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	socklen_t slen;
1014bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char buf[1024];
1015d059297112922cabb0c674840589be8db821fd9aAdam Langley	int len, sock, r;
1016bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int i, orig_alloc;
1017bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	uid_t euid;
1018bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	gid_t egid;
1019bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1020bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (i = 0, orig_alloc = sockets_alloc; i < orig_alloc; i++)
1021bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		switch (sockets[i].type) {
1022bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case AUTH_UNUSED:
1023bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1024bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case AUTH_SOCKET:
1025bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (FD_ISSET(sockets[i].fd, readset)) {
1026bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				slen = sizeof(sunaddr);
1027bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				sock = accept(sockets[i].fd,
1028bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    (struct sockaddr *)&sunaddr, &slen);
1029bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				if (sock < 0) {
1030bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					error("accept from AUTH_SOCKET: %s",
1031bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					    strerror(errno));
1032bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					break;
1033bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				}
1034bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				if (getpeereid(sock, &euid, &egid) < 0) {
1035bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					error("getpeereid %d failed: %s",
1036bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					    sock, strerror(errno));
1037bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					close(sock);
1038bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					break;
1039bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				}
1040bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				if ((euid != 0) && (getuid() != euid)) {
1041bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					error("uid mismatch: "
1042bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					    "peer euid %u != uid %u",
1043bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					    (u_int) euid, (u_int) getuid());
1044bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					close(sock);
1045bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					break;
1046bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				}
1047bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				new_socket(AUTH_CONNECTION, sock);
1048bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			}
1049bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1050bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case AUTH_CONNECTION:
1051d059297112922cabb0c674840589be8db821fd9aAdam Langley			if (sshbuf_len(sockets[i].output) > 0 &&
1052bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    FD_ISSET(sockets[i].fd, writeset)) {
1053bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				len = write(sockets[i].fd,
1054d059297112922cabb0c674840589be8db821fd9aAdam Langley				    sshbuf_ptr(sockets[i].output),
1055d059297112922cabb0c674840589be8db821fd9aAdam Langley				    sshbuf_len(sockets[i].output));
1056bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				if (len == -1 && (errno == EAGAIN ||
1057bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    errno == EWOULDBLOCK ||
1058bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    errno == EINTR))
1059bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					continue;
1060bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				if (len <= 0) {
1061bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					close_socket(&sockets[i]);
1062bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					break;
1063bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				}
1064d059297112922cabb0c674840589be8db821fd9aAdam Langley				if ((r = sshbuf_consume(sockets[i].output,
1065d059297112922cabb0c674840589be8db821fd9aAdam Langley				    len)) != 0)
1066d059297112922cabb0c674840589be8db821fd9aAdam Langley					fatal("%s: buffer error: %s",
1067d059297112922cabb0c674840589be8db821fd9aAdam Langley					    __func__, ssh_err(r));
1068bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			}
1069bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (FD_ISSET(sockets[i].fd, readset)) {
1070bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				len = read(sockets[i].fd, buf, sizeof(buf));
1071bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				if (len == -1 && (errno == EAGAIN ||
1072bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    errno == EWOULDBLOCK ||
1073bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    errno == EINTR))
1074bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					continue;
1075bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				if (len <= 0) {
1076bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					close_socket(&sockets[i]);
1077bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman					break;
1078bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				}
1079d059297112922cabb0c674840589be8db821fd9aAdam Langley				if ((r = sshbuf_put(sockets[i].input,
1080d059297112922cabb0c674840589be8db821fd9aAdam Langley				    buf, len)) != 0)
1081d059297112922cabb0c674840589be8db821fd9aAdam Langley					fatal("%s: buffer error: %s",
1082d059297112922cabb0c674840589be8db821fd9aAdam Langley					    __func__, ssh_err(r));
1083d059297112922cabb0c674840589be8db821fd9aAdam Langley				explicit_bzero(buf, sizeof(buf));
1084bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				process_message(&sockets[i]);
1085bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			}
1086bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1087bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		default:
1088bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			fatal("Unknown type %d", sockets[i].type);
1089bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
1090bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
1091bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1092bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
1093bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancleanup_socket(void)
1094bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
1095d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (cleanup_pid != 0 && getpid() != cleanup_pid)
1096d059297112922cabb0c674840589be8db821fd9aAdam Langley		return;
1097d059297112922cabb0c674840589be8db821fd9aAdam Langley	debug("%s: cleanup", __func__);
1098bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (socket_name[0])
1099bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		unlink(socket_name);
1100bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (socket_dir[0])
1101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		rmdir(socket_dir);
1102bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
1103bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1104bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid
1105bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancleanup_exit(int i)
1106bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
1107bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	cleanup_socket();
1108bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	_exit(i);
1109bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
1110bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1111bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*ARGSUSED*/
1112bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
1113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancleanup_handler(int sig)
1114bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
1115bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	cleanup_socket();
1116bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef ENABLE_PKCS11
1117bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	pkcs11_terminate();
1118bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
1119bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	_exit(2);
1120bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
1121bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1122bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
1123bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancheck_parent_exists(void)
1124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
1125bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/*
1126bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * If our parent has exited then getppid() will return (pid_t)1,
1127bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * so testing for that should be safe.
1128bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 */
1129bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (parent_pid != -1 && getppid() != parent_pid) {
1130bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* printf("Parent has died - Authentication agent exiting.\n"); */
1131bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		cleanup_socket();
1132bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		_exit(2);
1133bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1134bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
1135bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1136bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void
1137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanusage(void)
1138bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
1139d059297112922cabb0c674840589be8db821fd9aAdam Langley	fprintf(stderr,
1140d059297112922cabb0c674840589be8db821fd9aAdam Langley	    "usage: ssh-agent [-c | -s] [-d] [-a bind_address] [-E fingerprint_hash]\n"
1141d059297112922cabb0c674840589be8db821fd9aAdam Langley	    "                 [-t life] [command [arg ...]]\n"
1142d059297112922cabb0c674840589be8db821fd9aAdam Langley	    "       ssh-agent [-c | -s] -k\n");
1143bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	exit(1);
1144bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
1145bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1146bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
1147bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanmain(int ac, char **av)
1148bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
1149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0;
1150bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int sock, fd, ch, result, saved_errno;
1151bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int nalloc;
1152bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *shell, *format, *pidstr, *agentsocket = NULL;
1153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fd_set *readsetp = NULL, *writesetp = NULL;
1154bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_SETRLIMIT
1155bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct rlimit rlim;
1156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
1157bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	extern int optind;
1158bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	extern char *optarg;
1159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	pid_t pid;
1160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char pidstrbuf[1 + 3 * sizeof pid];
1161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct timeval *tvp = NULL;
1162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	size_t len;
1163d059297112922cabb0c674840589be8db821fd9aAdam Langley	mode_t prev_mask;
1164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1165bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1166bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	sanitise_stdfd();
1167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* drop */
1169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	setegid(getgid());
1170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	setgid(getgid());
1171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1172bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
1173bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Disable ptrace on Linux without sgid bit */
1174bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	prctl(PR_SET_DUMPABLE, 0);
1175bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
1176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1177d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
1178bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	OpenSSL_add_all_algorithms();
1179d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
1180bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1181bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	__progname = ssh_get_progname(av[0]);
1182bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	seed_rng();
1183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1184d059297112922cabb0c674840589be8db821fd9aAdam Langley	while ((ch = getopt(ac, av, "cdksE:a:t:")) != -1) {
1185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		switch (ch) {
1186d059297112922cabb0c674840589be8db821fd9aAdam Langley		case 'E':
1187d059297112922cabb0c674840589be8db821fd9aAdam Langley			fingerprint_hash = ssh_digest_alg_by_name(optarg);
1188d059297112922cabb0c674840589be8db821fd9aAdam Langley			if (fingerprint_hash == -1)
1189d059297112922cabb0c674840589be8db821fd9aAdam Langley				fatal("Invalid hash algorithm \"%s\"", optarg);
1190d059297112922cabb0c674840589be8db821fd9aAdam Langley			break;
1191bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 'c':
1192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (s_flag)
1193bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				usage();
1194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			c_flag++;
1195bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1196bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 'k':
1197bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			k_flag++;
1198bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1199bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 's':
1200bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (c_flag)
1201bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				usage();
1202bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			s_flag++;
1203bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1204bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 'd':
1205bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (d_flag)
1206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				usage();
1207bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			d_flag++;
1208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 'a':
1210bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			agentsocket = optarg;
1211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1212bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 't':
1213bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if ((lifetime = convtime(optarg)) == -1) {
1214bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				fprintf(stderr, "Invalid lifetime\n");
1215bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				usage();
1216bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			}
1217bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
1218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		default:
1219bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			usage();
1220bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
1221bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1222bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	ac -= optind;
1223bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	av += optind;
1224bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1225bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
1226bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		usage();
1227bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1228bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (ac == 0 && !c_flag && !s_flag) {
1229bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		shell = getenv("SHELL");
1230bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (shell != NULL && (len = strlen(shell)) > 2 &&
1231bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    strncmp(shell + len - 3, "csh", 3) == 0)
1232bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			c_flag = 1;
1233bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1234bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (k_flag) {
1235bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		const char *errstr = NULL;
1236bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1237bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		pidstr = getenv(SSH_AGENTPID_ENV_NAME);
1238bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (pidstr == NULL) {
1239bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			fprintf(stderr, "%s not set, cannot kill agent\n",
1240bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    SSH_AGENTPID_ENV_NAME);
1241bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			exit(1);
1242bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
1243bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		pid = (int)strtonum(pidstr, 2, INT_MAX, &errstr);
1244bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (errstr) {
1245bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			fprintf(stderr,
1246bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    "%s=\"%s\", which is not a good PID: %s\n",
1247bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    SSH_AGENTPID_ENV_NAME, pidstr, errstr);
1248bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			exit(1);
1249bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
1250bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (kill(pid, SIGTERM) == -1) {
1251bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			perror("kill");
1252bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			exit(1);
1253bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
1254bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
1255bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		printf(format, SSH_AUTHSOCKET_ENV_NAME);
1256bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		printf(format, SSH_AGENTPID_ENV_NAME);
1257bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		printf("echo Agent pid %ld killed;\n", (long)pid);
1258bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		exit(0);
1259bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1260bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	parent_pid = getpid();
1261bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1262bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (agentsocket == NULL) {
1263bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Create private directory for agent socket */
1264bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		mktemp_proto(socket_dir, sizeof(socket_dir));
1265bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (mkdtemp(socket_dir) == NULL) {
1266bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			perror("mkdtemp: private socket dir");
1267bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			exit(1);
1268bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
1269bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
1270bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    (long)parent_pid);
1271bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	} else {
1272bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Try to use specified agent socket */
1273bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		socket_dir[0] = '\0';
1274bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		strlcpy(socket_name, agentsocket, sizeof socket_name);
1275bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1276bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1277bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/*
1278bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * Create socket early so it will exist before command gets run from
1279bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * the parent.
1280bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 */
1281bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	prev_mask = umask(0177);
1282d059297112922cabb0c674840589be8db821fd9aAdam Langley	sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0);
1283d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sock < 0) {
1284d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* XXX - unix_listener() calls error() not perror() */
1285bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		*socket_name = '\0'; /* Don't unlink any existing file */
1286bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		cleanup_exit(1);
1287bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1288bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	umask(prev_mask);
1289bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1290bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/*
1291bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * Fork, and have the parent execute the command, if any, or present
1292bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * the socket data.  The child continues as the authentication agent.
1293bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 */
1294bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (d_flag) {
1295bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
1296bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1297bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
1298bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    SSH_AUTHSOCKET_ENV_NAME);
1299bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		printf("echo Agent pid %ld;\n", (long)parent_pid);
1300bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		goto skip;
1301bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1302bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	pid = fork();
1303bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (pid == -1) {
1304bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		perror("fork");
1305bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		cleanup_exit(1);
1306bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1307bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (pid != 0) {		/* Parent - execute the given command. */
1308bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(sock);
1309bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
1310bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (ac == 0) {
1311bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1312bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
1313bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    SSH_AUTHSOCKET_ENV_NAME);
1314bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
1315bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    SSH_AGENTPID_ENV_NAME);
1316bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			printf("echo Agent pid %ld;\n", (long)pid);
1317bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			exit(0);
1318bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
1319bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
1320bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
1321bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			perror("setenv");
1322bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			exit(1);
1323bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
1324bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		execvp(av[0], av);
1325bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		perror(av[0]);
1326bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		exit(1);
1327bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1328bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* child */
1329bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
1330bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1331bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (setsid() == -1) {
1332bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("setsid: %s", strerror(errno));
1333bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		cleanup_exit(1);
1334bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1335bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1336bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	(void)chdir("/");
1337bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1338bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* XXX might close listen socket */
1339bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		(void)dup2(fd, STDIN_FILENO);
1340bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		(void)dup2(fd, STDOUT_FILENO);
1341bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		(void)dup2(fd, STDERR_FILENO);
1342bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (fd > 2)
1343bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			close(fd);
1344bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1345bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1346bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_SETRLIMIT
1347bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* deny core dumps, since memory contains unencrypted private keys */
1348bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	rlim.rlim_cur = rlim.rlim_max = 0;
1349bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
1350bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("setrlimit RLIMIT_CORE: %s", strerror(errno));
1351bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		cleanup_exit(1);
1352bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1353bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
1354bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1355bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanskip:
1356bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1357d059297112922cabb0c674840589be8db821fd9aAdam Langley	cleanup_pid = getpid();
1358d059297112922cabb0c674840589be8db821fd9aAdam Langley
1359bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef ENABLE_PKCS11
1360bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	pkcs11_init(0);
1361bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
1362bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	new_socket(AUTH_SOCKET, sock);
1363bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (ac > 0)
1364bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		parent_alive_interval = 10;
1365bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	idtab_init();
1366bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	signal(SIGPIPE, SIG_IGN);
1367d059297112922cabb0c674840589be8db821fd9aAdam Langley	signal(SIGINT, d_flag ? cleanup_handler : SIG_IGN);
1368bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	signal(SIGHUP, cleanup_handler);
1369bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	signal(SIGTERM, cleanup_handler);
1370bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	nalloc = 0;
1371bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
1372bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	while (1) {
1373bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
1374bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
1375bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		saved_errno = errno;
1376bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (parent_alive_interval != 0)
1377bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			check_parent_exists();
1378bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		(void) reaper();	/* remove expired keys */
1379bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (result < 0) {
1380bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (saved_errno == EINTR)
1381bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				continue;
1382bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			fatal("select: %s", strerror(saved_errno));
1383bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		} else if (result > 0)
1384bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			after_select(readsetp, writesetp);
1385bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
1386bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* NOTREACHED */
1387bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
1388