ssh-agent.c revision 98684
1/*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 *                    All rights reserved
5 * The authentication agent program.
6 *
7 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose.  Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
12 *
13 * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include "includes.h"
37#include <sys/queue.h>
38RCSID("$OpenBSD: ssh-agent.c,v 1.95 2002/06/19 00:27:55 deraadt Exp $");
39RCSID("$FreeBSD: head/crypto/openssh/ssh-agent.c 98684 2002-06-23 16:09:08Z des $");
40
41#include <openssl/evp.h>
42#include <openssl/md5.h>
43
44#include "ssh.h"
45#include "rsa.h"
46#include "buffer.h"
47#include "bufaux.h"
48#include "xmalloc.h"
49#include "getput.h"
50#include "key.h"
51#include "authfd.h"
52#include "compat.h"
53#include "log.h"
54
55#ifdef SMARTCARD
56#include "scard.h"
57#endif
58
59typedef enum {
60	AUTH_UNUSED,
61	AUTH_SOCKET,
62	AUTH_CONNECTION
63} sock_type;
64
65typedef struct {
66	int fd;
67	sock_type type;
68	Buffer input;
69	Buffer output;
70	Buffer request;
71} SocketEntry;
72
73u_int sockets_alloc = 0;
74SocketEntry *sockets = NULL;
75
76typedef struct identity {
77	TAILQ_ENTRY(identity) next;
78	Key *key;
79	char *comment;
80	u_int death;
81} Identity;
82
83typedef struct {
84	int nentries;
85	TAILQ_HEAD(idqueue, identity) idlist;
86} Idtab;
87
88/* private key table, one per protocol version */
89Idtab idtable[3];
90
91int max_fd = 0;
92
93/* pid of shell == parent of agent */
94pid_t parent_pid = -1;
95
96/* pathname and directory for AUTH_SOCKET */
97char socket_name[1024];
98char socket_dir[1024];
99
100/* locking */
101int locked = 0;
102char *lock_passwd = NULL;
103
104extern char *__progname;
105
106static void
107idtab_init(void)
108{
109	int i;
110	for (i = 0; i <=2; i++) {
111		TAILQ_INIT(&idtable[i].idlist);
112		idtable[i].nentries = 0;
113	}
114}
115
116/* return private key table for requested protocol version */
117static Idtab *
118idtab_lookup(int version)
119{
120	if (version < 1 || version > 2)
121		fatal("internal error, bad protocol version %d", version);
122	return &idtable[version];
123}
124
125static void
126free_identity(Identity *id)
127{
128	key_free(id->key);
129	xfree(id->comment);
130	xfree(id);
131}
132
133/* return matching private key for given public key */
134static Identity *
135lookup_identity(Key *key, int version)
136{
137	Identity *id;
138
139	Idtab *tab = idtab_lookup(version);
140	TAILQ_FOREACH(id, &tab->idlist, next) {
141		if (key_equal(key, id->key))
142			return (id);
143	}
144	return (NULL);
145}
146
147/* send list of supported public keys to 'client' */
148static void
149process_request_identities(SocketEntry *e, int version)
150{
151	Idtab *tab = idtab_lookup(version);
152	Buffer msg;
153	Identity *id;
154
155	buffer_init(&msg);
156	buffer_put_char(&msg, (version == 1) ?
157	    SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
158	buffer_put_int(&msg, tab->nentries);
159	TAILQ_FOREACH(id, &tab->idlist, next) {
160		if (id->key->type == KEY_RSA1) {
161			buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
162			buffer_put_bignum(&msg, id->key->rsa->e);
163			buffer_put_bignum(&msg, id->key->rsa->n);
164		} else {
165			u_char *blob;
166			u_int blen;
167			key_to_blob(id->key, &blob, &blen);
168			buffer_put_string(&msg, blob, blen);
169			xfree(blob);
170		}
171		buffer_put_cstring(&msg, id->comment);
172	}
173	buffer_put_int(&e->output, buffer_len(&msg));
174	buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
175	buffer_free(&msg);
176}
177
178/* ssh1 only */
179static void
180process_authentication_challenge1(SocketEntry *e)
181{
182	Identity *id;
183	Key *key;
184	BIGNUM *challenge;
185	int i, len;
186	Buffer msg;
187	MD5_CTX md;
188	u_char buf[32], mdbuf[16], session_id[16];
189	u_int response_type;
190
191	buffer_init(&msg);
192	key = key_new(KEY_RSA1);
193	if ((challenge = BN_new()) == NULL)
194		fatal("process_authentication_challenge1: BN_new failed");
195
196	buffer_get_int(&e->request);				/* ignored */
197	buffer_get_bignum(&e->request, key->rsa->e);
198	buffer_get_bignum(&e->request, key->rsa->n);
199	buffer_get_bignum(&e->request, challenge);
200
201	/* Only protocol 1.1 is supported */
202	if (buffer_len(&e->request) == 0)
203		goto failure;
204	buffer_get(&e->request, session_id, 16);
205	response_type = buffer_get_int(&e->request);
206	if (response_type != 1)
207		goto failure;
208
209	id = lookup_identity(key, 1);
210	if (id != NULL) {
211		Key *private = id->key;
212		/* Decrypt the challenge using the private key. */
213		if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)
214			goto failure;
215
216		/* The response is MD5 of decrypted challenge plus session id. */
217		len = BN_num_bytes(challenge);
218		if (len <= 0 || len > 32) {
219			log("process_authentication_challenge: bad challenge length %d", len);
220			goto failure;
221		}
222		memset(buf, 0, 32);
223		BN_bn2bin(challenge, buf + 32 - len);
224		MD5_Init(&md);
225		MD5_Update(&md, buf, 32);
226		MD5_Update(&md, session_id, 16);
227		MD5_Final(mdbuf, &md);
228
229		/* Send the response. */
230		buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
231		for (i = 0; i < 16; i++)
232			buffer_put_char(&msg, mdbuf[i]);
233		goto send;
234	}
235
236failure:
237	/* Unknown identity or protocol error.  Send failure. */
238	buffer_put_char(&msg, SSH_AGENT_FAILURE);
239send:
240	buffer_put_int(&e->output, buffer_len(&msg));
241	buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
242	key_free(key);
243	BN_clear_free(challenge);
244	buffer_free(&msg);
245}
246
247/* ssh2 only */
248static void
249process_sign_request2(SocketEntry *e)
250{
251	extern int datafellows;
252	Key *key;
253	u_char *blob, *data, *signature = NULL;
254	u_int blen, dlen, slen = 0;
255	int flags;
256	Buffer msg;
257	int ok = -1;
258
259	datafellows = 0;
260
261	blob = buffer_get_string(&e->request, &blen);
262	data = buffer_get_string(&e->request, &dlen);
263
264	flags = buffer_get_int(&e->request);
265	if (flags & SSH_AGENT_OLD_SIGNATURE)
266		datafellows = SSH_BUG_SIGBLOB;
267
268	key = key_from_blob(blob, blen);
269	if (key != NULL) {
270		Identity *id = lookup_identity(key, 2);
271		if (id != NULL)
272			ok = key_sign(id->key, &signature, &slen, data, dlen);
273	}
274	key_free(key);
275	buffer_init(&msg);
276	if (ok == 0) {
277		buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
278		buffer_put_string(&msg, signature, slen);
279	} else {
280		buffer_put_char(&msg, SSH_AGENT_FAILURE);
281	}
282	buffer_put_int(&e->output, buffer_len(&msg));
283	buffer_append(&e->output, buffer_ptr(&msg),
284	    buffer_len(&msg));
285	buffer_free(&msg);
286	xfree(data);
287	xfree(blob);
288	if (signature != NULL)
289		xfree(signature);
290}
291
292/* shared */
293static void
294process_remove_identity(SocketEntry *e, int version)
295{
296	Key *key = NULL;
297	u_char *blob;
298	u_int blen;
299	u_int bits;
300	int success = 0;
301
302	switch (version) {
303	case 1:
304		key = key_new(KEY_RSA1);
305		bits = buffer_get_int(&e->request);
306		buffer_get_bignum(&e->request, key->rsa->e);
307		buffer_get_bignum(&e->request, key->rsa->n);
308
309		if (bits != key_size(key))
310			log("Warning: identity keysize mismatch: actual %d, announced %d",
311			    key_size(key), bits);
312		break;
313	case 2:
314		blob = buffer_get_string(&e->request, &blen);
315		key = key_from_blob(blob, blen);
316		xfree(blob);
317		break;
318	}
319	if (key != NULL) {
320		Identity *id = lookup_identity(key, version);
321		if (id != NULL) {
322			/*
323			 * We have this key.  Free the old key.  Since we
324			 * don\'t want to leave empty slots in the middle of
325			 * the array, we actually free the key there and move
326			 * all the entries between the empty slot and the end
327			 * of the array.
328			 */
329			Idtab *tab = idtab_lookup(version);
330			if (tab->nentries < 1)
331				fatal("process_remove_identity: "
332				    "internal error: tab->nentries %d",
333				    tab->nentries);
334			TAILQ_REMOVE(&tab->idlist, id, next);
335			free_identity(id);
336			tab->nentries--;
337			success = 1;
338		}
339		key_free(key);
340	}
341	buffer_put_int(&e->output, 1);
342	buffer_put_char(&e->output,
343	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
344}
345
346static void
347process_remove_all_identities(SocketEntry *e, int version)
348{
349	Idtab *tab = idtab_lookup(version);
350	Identity *id;
351
352	/* Loop over all identities and clear the keys. */
353	for (id = TAILQ_FIRST(&tab->idlist); id;
354	    id = TAILQ_FIRST(&tab->idlist)) {
355		TAILQ_REMOVE(&tab->idlist, id, next);
356		free_identity(id);
357	}
358
359	/* Mark that there are no identities. */
360	tab->nentries = 0;
361
362	/* Send success. */
363	buffer_put_int(&e->output, 1);
364	buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
365}
366
367static void
368reaper(void)
369{
370	Idtab *tab;
371	Identity *id, *nxt;
372	int version;
373	u_int now = time(NULL);
374
375	for (version = 1; version < 3; version++) {
376		tab = idtab_lookup(version);
377		for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
378			nxt = TAILQ_NEXT(id, next);
379			if (id->death != 0 && now >= id->death) {
380				TAILQ_REMOVE(&tab->idlist, id, next);
381				free_identity(id);
382				tab->nentries--;
383			}
384		}
385	}
386}
387
388static void
389process_add_identity(SocketEntry *e, int version)
390{
391	Key *k = NULL;
392	char *type_name;
393	char *comment;
394	int type, success = 0, death = 0;
395	Idtab *tab = idtab_lookup(version);
396
397	switch (version) {
398	case 1:
399		k = key_new_private(KEY_RSA1);
400		buffer_get_int(&e->request);			/* ignored */
401		buffer_get_bignum(&e->request, k->rsa->n);
402		buffer_get_bignum(&e->request, k->rsa->e);
403		buffer_get_bignum(&e->request, k->rsa->d);
404		buffer_get_bignum(&e->request, k->rsa->iqmp);
405
406		/* SSH and SSL have p and q swapped */
407		buffer_get_bignum(&e->request, k->rsa->q);	/* p */
408		buffer_get_bignum(&e->request, k->rsa->p);	/* q */
409
410		/* Generate additional parameters */
411		rsa_generate_additional_parameters(k->rsa);
412		break;
413	case 2:
414		type_name = buffer_get_string(&e->request, NULL);
415		type = key_type_from_name(type_name);
416		xfree(type_name);
417		switch (type) {
418		case KEY_DSA:
419			k = key_new_private(type);
420			buffer_get_bignum2(&e->request, k->dsa->p);
421			buffer_get_bignum2(&e->request, k->dsa->q);
422			buffer_get_bignum2(&e->request, k->dsa->g);
423			buffer_get_bignum2(&e->request, k->dsa->pub_key);
424			buffer_get_bignum2(&e->request, k->dsa->priv_key);
425			break;
426		case KEY_RSA:
427			k = key_new_private(type);
428			buffer_get_bignum2(&e->request, k->rsa->n);
429			buffer_get_bignum2(&e->request, k->rsa->e);
430			buffer_get_bignum2(&e->request, k->rsa->d);
431			buffer_get_bignum2(&e->request, k->rsa->iqmp);
432			buffer_get_bignum2(&e->request, k->rsa->p);
433			buffer_get_bignum2(&e->request, k->rsa->q);
434
435			/* Generate additional parameters */
436			rsa_generate_additional_parameters(k->rsa);
437			break;
438		default:
439			buffer_clear(&e->request);
440			goto send;
441		}
442		break;
443	}
444	comment = buffer_get_string(&e->request, NULL);
445	if (k == NULL) {
446		xfree(comment);
447		goto send;
448	}
449	success = 1;
450	while (buffer_len(&e->request)) {
451		switch (buffer_get_char(&e->request)) {
452		case SSH_AGENT_CONSTRAIN_LIFETIME:
453			death = time(NULL) + buffer_get_int(&e->request);
454			break;
455		default:
456			break;
457		}
458	}
459	if (lookup_identity(k, version) == NULL) {
460		Identity *id = xmalloc(sizeof(Identity));
461		id->key = k;
462		id->comment = comment;
463		id->death = death;
464		TAILQ_INSERT_TAIL(&tab->idlist, id, next);
465		/* Increment the number of identities. */
466		tab->nentries++;
467	} else {
468		key_free(k);
469		xfree(comment);
470	}
471send:
472	buffer_put_int(&e->output, 1);
473	buffer_put_char(&e->output,
474	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
475}
476
477/* XXX todo: encrypt sensitive data with passphrase */
478static void
479process_lock_agent(SocketEntry *e, int lock)
480{
481	char *passwd;
482	int success = 0;
483
484	passwd = buffer_get_string(&e->request, NULL);
485	if (locked && !lock && strcmp(passwd, lock_passwd) == 0) {
486		locked = 0;
487		memset(lock_passwd, 0, strlen(lock_passwd));
488		xfree(lock_passwd);
489		lock_passwd = NULL;
490		success = 1;
491	} else if (!locked && lock) {
492		locked = 1;
493		lock_passwd = xstrdup(passwd);
494		success = 1;
495	}
496	memset(passwd, 0, strlen(passwd));
497	xfree(passwd);
498
499	buffer_put_int(&e->output, 1);
500	buffer_put_char(&e->output,
501	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
502}
503
504static void
505no_identities(SocketEntry *e, u_int type)
506{
507	Buffer msg;
508
509	buffer_init(&msg);
510	buffer_put_char(&msg,
511	    (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ?
512	    SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
513	buffer_put_int(&msg, 0);
514	buffer_put_int(&e->output, buffer_len(&msg));
515	buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
516	buffer_free(&msg);
517}
518
519#ifdef SMARTCARD
520static void
521process_add_smartcard_key (SocketEntry *e)
522{
523	Identity *id;
524	Idtab *tab;
525	Key **keys, *k;
526	char *sc_reader_id = NULL, *pin;
527	int i, version, success = 0;
528
529	sc_reader_id = buffer_get_string(&e->request, NULL);
530	pin = buffer_get_string(&e->request, NULL);
531	keys = sc_get_keys(sc_reader_id, pin);
532	xfree(sc_reader_id);
533	xfree(pin);
534
535	if (keys == NULL || keys[0] == NULL) {
536		error("sc_get_keys failed");
537		goto send;
538	}
539	for (i = 0; keys[i] != NULL; i++) {
540		k = keys[i];
541		version = k->type == KEY_RSA1 ? 1 : 2;
542		tab = idtab_lookup(version);
543		if (lookup_identity(k, version) == NULL) {
544			id = xmalloc(sizeof(Identity));
545			id->key = k;
546			id->comment = xstrdup("smartcard key");
547			id->death = 0;
548			TAILQ_INSERT_TAIL(&tab->idlist, id, next);
549			tab->nentries++;
550			success = 1;
551		} else {
552			key_free(k);
553		}
554		keys[i] = NULL;
555	}
556	xfree(keys);
557send:
558	buffer_put_int(&e->output, 1);
559	buffer_put_char(&e->output,
560	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
561}
562
563static void
564process_remove_smartcard_key(SocketEntry *e)
565{
566	Identity *id;
567	Idtab *tab;
568	Key **keys, *k = NULL;
569	char *sc_reader_id = NULL, *pin;
570	int i, version, success = 0;
571
572	sc_reader_id = buffer_get_string(&e->request, NULL);
573	pin = buffer_get_string(&e->request, NULL);
574	keys = sc_get_keys(sc_reader_id, pin);
575	xfree(sc_reader_id);
576	xfree(pin);
577
578	if (keys == NULL || keys[0] == NULL) {
579		error("sc_get_keys failed");
580		goto send;
581	}
582	for (i = 0; keys[i] != NULL; i++) {
583		k = keys[i];
584		version = k->type == KEY_RSA1 ? 1 : 2;
585		if ((id = lookup_identity(k, version)) != NULL) {
586			tab = idtab_lookup(version);
587			TAILQ_REMOVE(&tab->idlist, id, next);
588			tab->nentries--;
589			free_identity(id);
590			success = 1;
591		}
592		key_free(k);
593		keys[i] = NULL;
594	}
595	xfree(keys);
596send:
597	buffer_put_int(&e->output, 1);
598	buffer_put_char(&e->output,
599	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
600}
601#endif /* SMARTCARD */
602
603/* dispatch incoming messages */
604
605static void
606process_message(SocketEntry *e)
607{
608	u_int msg_len;
609	u_int type;
610	u_char *cp;
611
612	/* kill dead keys */
613	reaper();
614
615	if (buffer_len(&e->input) < 5)
616		return;		/* Incomplete message. */
617	cp = buffer_ptr(&e->input);
618	msg_len = GET_32BIT(cp);
619	if (msg_len > 256 * 1024) {
620		shutdown(e->fd, SHUT_RDWR);
621		close(e->fd);
622		e->type = AUTH_UNUSED;
623		buffer_free(&e->input);
624		buffer_free(&e->output);
625		buffer_free(&e->request);
626		return;
627	}
628	if (buffer_len(&e->input) < msg_len + 4)
629		return;
630
631	/* move the current input to e->request */
632	buffer_consume(&e->input, 4);
633	buffer_clear(&e->request);
634	buffer_append(&e->request, buffer_ptr(&e->input), msg_len);
635	buffer_consume(&e->input, msg_len);
636	type = buffer_get_char(&e->request);
637
638	/* check wheter agent is locked */
639	if (locked && type != SSH_AGENTC_UNLOCK) {
640		buffer_clear(&e->request);
641		switch (type) {
642		case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
643		case SSH2_AGENTC_REQUEST_IDENTITIES:
644			/* send empty lists */
645			no_identities(e, type);
646			break;
647		default:
648			/* send a fail message for all other request types */
649			buffer_put_int(&e->output, 1);
650			buffer_put_char(&e->output, SSH_AGENT_FAILURE);
651		}
652		return;
653	}
654
655	debug("type %d", type);
656	switch (type) {
657	case SSH_AGENTC_LOCK:
658	case SSH_AGENTC_UNLOCK:
659		process_lock_agent(e, type == SSH_AGENTC_LOCK);
660		break;
661	/* ssh1 */
662	case SSH_AGENTC_RSA_CHALLENGE:
663		process_authentication_challenge1(e);
664		break;
665	case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
666		process_request_identities(e, 1);
667		break;
668	case SSH_AGENTC_ADD_RSA_IDENTITY:
669	case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED:
670		process_add_identity(e, 1);
671		break;
672	case SSH_AGENTC_REMOVE_RSA_IDENTITY:
673		process_remove_identity(e, 1);
674		break;
675	case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
676		process_remove_all_identities(e, 1);
677		break;
678	/* ssh2 */
679	case SSH2_AGENTC_SIGN_REQUEST:
680		process_sign_request2(e);
681		break;
682	case SSH2_AGENTC_REQUEST_IDENTITIES:
683		process_request_identities(e, 2);
684		break;
685	case SSH2_AGENTC_ADD_IDENTITY:
686	case SSH2_AGENTC_ADD_ID_CONSTRAINED:
687		process_add_identity(e, 2);
688		break;
689	case SSH2_AGENTC_REMOVE_IDENTITY:
690		process_remove_identity(e, 2);
691		break;
692	case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
693		process_remove_all_identities(e, 2);
694		break;
695#ifdef SMARTCARD
696	case SSH_AGENTC_ADD_SMARTCARD_KEY:
697		process_add_smartcard_key(e);
698		break;
699	case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
700		process_remove_smartcard_key(e);
701		break;
702#endif /* SMARTCARD */
703	default:
704		/* Unknown message.  Respond with failure. */
705		error("Unknown message %d", type);
706		buffer_clear(&e->request);
707		buffer_put_int(&e->output, 1);
708		buffer_put_char(&e->output, SSH_AGENT_FAILURE);
709		break;
710	}
711}
712
713static void
714new_socket(sock_type type, int fd)
715{
716	u_int i, old_alloc;
717	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
718		error("fcntl O_NONBLOCK: %s", strerror(errno));
719
720	if (fd > max_fd)
721		max_fd = fd;
722
723	for (i = 0; i < sockets_alloc; i++)
724		if (sockets[i].type == AUTH_UNUSED) {
725			sockets[i].fd = fd;
726			sockets[i].type = type;
727			buffer_init(&sockets[i].input);
728			buffer_init(&sockets[i].output);
729			buffer_init(&sockets[i].request);
730			return;
731		}
732	old_alloc = sockets_alloc;
733	sockets_alloc += 10;
734	if (sockets)
735		sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
736	else
737		sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
738	for (i = old_alloc; i < sockets_alloc; i++)
739		sockets[i].type = AUTH_UNUSED;
740	sockets[old_alloc].type = type;
741	sockets[old_alloc].fd = fd;
742	buffer_init(&sockets[old_alloc].input);
743	buffer_init(&sockets[old_alloc].output);
744	buffer_init(&sockets[old_alloc].request);
745}
746
747static int
748prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp)
749{
750	u_int i, sz;
751	int n = 0;
752
753	for (i = 0; i < sockets_alloc; i++) {
754		switch (sockets[i].type) {
755		case AUTH_SOCKET:
756		case AUTH_CONNECTION:
757			n = MAX(n, sockets[i].fd);
758			break;
759		case AUTH_UNUSED:
760			break;
761		default:
762			fatal("Unknown socket type %d", sockets[i].type);
763			break;
764		}
765	}
766
767	sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
768	if (*fdrp == NULL || sz > *nallocp) {
769		if (*fdrp)
770			xfree(*fdrp);
771		if (*fdwp)
772			xfree(*fdwp);
773		*fdrp = xmalloc(sz);
774		*fdwp = xmalloc(sz);
775		*nallocp = sz;
776	}
777	if (n < *fdl)
778		debug("XXX shrink: %d < %d", n, *fdl);
779	*fdl = n;
780	memset(*fdrp, 0, sz);
781	memset(*fdwp, 0, sz);
782
783	for (i = 0; i < sockets_alloc; i++) {
784		switch (sockets[i].type) {
785		case AUTH_SOCKET:
786		case AUTH_CONNECTION:
787			FD_SET(sockets[i].fd, *fdrp);
788			if (buffer_len(&sockets[i].output) > 0)
789				FD_SET(sockets[i].fd, *fdwp);
790			break;
791		default:
792			break;
793		}
794	}
795	return (1);
796}
797
798static void
799after_select(fd_set *readset, fd_set *writeset)
800{
801	u_int i;
802	int len, sock;
803	socklen_t slen;
804	char buf[1024];
805	struct sockaddr_un sunaddr;
806
807	for (i = 0; i < sockets_alloc; i++)
808		switch (sockets[i].type) {
809		case AUTH_UNUSED:
810			break;
811		case AUTH_SOCKET:
812			if (FD_ISSET(sockets[i].fd, readset)) {
813				slen = sizeof(sunaddr);
814				sock = accept(sockets[i].fd,
815				    (struct sockaddr *) &sunaddr, &slen);
816				if (sock < 0) {
817					error("accept from AUTH_SOCKET: %s",
818					    strerror(errno));
819					break;
820				}
821				new_socket(AUTH_CONNECTION, sock);
822			}
823			break;
824		case AUTH_CONNECTION:
825			if (buffer_len(&sockets[i].output) > 0 &&
826			    FD_ISSET(sockets[i].fd, writeset)) {
827				do {
828					len = write(sockets[i].fd,
829					    buffer_ptr(&sockets[i].output),
830					    buffer_len(&sockets[i].output));
831					if (len == -1 && (errno == EAGAIN ||
832					    errno == EINTR))
833						continue;
834					break;
835				} while (1);
836				if (len <= 0) {
837					shutdown(sockets[i].fd, SHUT_RDWR);
838					close(sockets[i].fd);
839					sockets[i].type = AUTH_UNUSED;
840					buffer_free(&sockets[i].input);
841					buffer_free(&sockets[i].output);
842					buffer_free(&sockets[i].request);
843					break;
844				}
845				buffer_consume(&sockets[i].output, len);
846			}
847			if (FD_ISSET(sockets[i].fd, readset)) {
848				do {
849					len = read(sockets[i].fd, buf, sizeof(buf));
850					if (len == -1 && (errno == EAGAIN ||
851					    errno == EINTR))
852						continue;
853					break;
854				} while (1);
855				if (len <= 0) {
856					shutdown(sockets[i].fd, SHUT_RDWR);
857					close(sockets[i].fd);
858					sockets[i].type = AUTH_UNUSED;
859					buffer_free(&sockets[i].input);
860					buffer_free(&sockets[i].output);
861					buffer_free(&sockets[i].request);
862					break;
863				}
864				buffer_append(&sockets[i].input, buf, len);
865				process_message(&sockets[i]);
866			}
867			break;
868		default:
869			fatal("Unknown type %d", sockets[i].type);
870		}
871}
872
873static void
874cleanup_socket(void *p)
875{
876	if (socket_name[0])
877		unlink(socket_name);
878	if (socket_dir[0])
879		rmdir(socket_dir);
880}
881
882static void
883cleanup_exit(int i)
884{
885	cleanup_socket(NULL);
886	exit(i);
887}
888
889static void
890cleanup_handler(int sig)
891{
892	cleanup_socket(NULL);
893	_exit(2);
894}
895
896static void
897check_parent_exists(int sig)
898{
899	int save_errno = errno;
900
901	if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
902		/* printf("Parent has died - Authentication agent exiting.\n"); */
903		cleanup_handler(sig); /* safe */
904	}
905	signal(SIGALRM, check_parent_exists);
906	alarm(10);
907	errno = save_errno;
908}
909
910static void
911usage(void)
912{
913	fprintf(stderr, "Usage: %s [options] [command [args ...]]\n",
914	    __progname);
915	fprintf(stderr, "Options:\n");
916	fprintf(stderr, "  -c          Generate C-shell commands on stdout.\n");
917	fprintf(stderr, "  -s          Generate Bourne shell commands on stdout.\n");
918	fprintf(stderr, "  -k          Kill the current agent.\n");
919	fprintf(stderr, "  -d          Debug mode.\n");
920	fprintf(stderr, "  -a socket   Bind agent socket to given name.\n");
921	exit(1);
922}
923
924int
925main(int ac, char **av)
926{
927	int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
928	struct sockaddr_un sunaddr;
929	struct rlimit rlim;
930	pid_t pid;
931	char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
932	char *agentsocket = NULL;
933	extern int optind;
934	fd_set *readsetp = NULL, *writesetp = NULL;
935
936	SSLeay_add_all_algorithms();
937
938	while ((ch = getopt(ac, av, "cdksa:")) != -1) {
939		switch (ch) {
940		case 'c':
941			if (s_flag)
942				usage();
943			c_flag++;
944			break;
945		case 'k':
946			k_flag++;
947			break;
948		case 's':
949			if (c_flag)
950				usage();
951			s_flag++;
952			break;
953		case 'd':
954			if (d_flag)
955				usage();
956			d_flag++;
957			break;
958		case 'a':
959			agentsocket = optarg;
960			break;
961		default:
962			usage();
963		}
964	}
965	ac -= optind;
966	av += optind;
967
968	if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
969		usage();
970
971	if (ac == 0 && !c_flag && !s_flag) {
972		shell = getenv("SHELL");
973		if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
974			c_flag = 1;
975	}
976	if (k_flag) {
977		pidstr = getenv(SSH_AGENTPID_ENV_NAME);
978		if (pidstr == NULL) {
979			fprintf(stderr, "%s not set, cannot kill agent\n",
980			    SSH_AGENTPID_ENV_NAME);
981			exit(1);
982		}
983		pid = atoi(pidstr);
984		if (pid < 1) {
985			fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
986			    SSH_AGENTPID_ENV_NAME, pidstr);
987			exit(1);
988		}
989		if (kill(pid, SIGTERM) == -1) {
990			perror("kill");
991			exit(1);
992		}
993		format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
994		printf(format, SSH_AUTHSOCKET_ENV_NAME);
995		printf(format, SSH_AGENTPID_ENV_NAME);
996		printf("echo Agent pid %ld killed;\n", (long)pid);
997		exit(0);
998	}
999	parent_pid = getpid();
1000
1001	if (agentsocket == NULL) {
1002		/* Create private directory for agent socket */
1003		strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
1004		if (mkdtemp(socket_dir) == NULL) {
1005			perror("mkdtemp: private socket dir");
1006			exit(1);
1007		}
1008		snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
1009		    (long)parent_pid);
1010	} else {
1011		/* Try to use specified agent socket */
1012		socket_dir[0] = '\0';
1013		strlcpy(socket_name, agentsocket, sizeof socket_name);
1014	}
1015
1016	/*
1017	 * Create socket early so it will exist before command gets run from
1018	 * the parent.
1019	 */
1020	sock = socket(AF_UNIX, SOCK_STREAM, 0);
1021	if (sock < 0) {
1022		perror("socket");
1023		cleanup_exit(1);
1024	}
1025	memset(&sunaddr, 0, sizeof(sunaddr));
1026	sunaddr.sun_family = AF_UNIX;
1027	strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
1028	sunaddr.sun_len = SUN_LEN(&sunaddr) + 1;
1029	if (bind(sock, (struct sockaddr *)&sunaddr, sunaddr.sun_len) < 0) {
1030		perror("bind");
1031		cleanup_exit(1);
1032	}
1033	if (listen(sock, 5) < 0) {
1034		perror("listen");
1035		cleanup_exit(1);
1036	}
1037
1038	/*
1039	 * Fork, and have the parent execute the command, if any, or present
1040	 * the socket data.  The child continues as the authentication agent.
1041	 */
1042	if (d_flag) {
1043		log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
1044		format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1045		printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
1046		    SSH_AUTHSOCKET_ENV_NAME);
1047		printf("echo Agent pid %ld;\n", (long)parent_pid);
1048		goto skip;
1049	}
1050	pid = fork();
1051	if (pid == -1) {
1052		perror("fork");
1053		cleanup_exit(1);
1054	}
1055	if (pid != 0) {		/* Parent - execute the given command. */
1056		close(sock);
1057		snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
1058		if (ac == 0) {
1059			format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1060			printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
1061			    SSH_AUTHSOCKET_ENV_NAME);
1062			printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
1063			    SSH_AGENTPID_ENV_NAME);
1064			printf("echo Agent pid %ld;\n", (long)pid);
1065			exit(0);
1066		}
1067		if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
1068		    setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
1069			perror("setenv");
1070			exit(1);
1071		}
1072		execvp(av[0], av);
1073		perror(av[0]);
1074		exit(1);
1075	}
1076	/* child */
1077	log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
1078
1079	if (setsid() == -1) {
1080		error("setsid: %s", strerror(errno));
1081		cleanup_exit(1);
1082	}
1083
1084	(void)chdir("/");
1085	close(0);
1086	close(1);
1087	close(2);
1088
1089	/* deny core dumps, since memory contains unencrypted private keys */
1090	rlim.rlim_cur = rlim.rlim_max = 0;
1091	if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
1092		error("setrlimit RLIMIT_CORE: %s", strerror(errno));
1093		cleanup_exit(1);
1094	}
1095
1096skip:
1097	fatal_add_cleanup(cleanup_socket, NULL);
1098	new_socket(AUTH_SOCKET, sock);
1099	if (ac > 0) {
1100		signal(SIGALRM, check_parent_exists);
1101		alarm(10);
1102	}
1103	idtab_init();
1104	if (!d_flag)
1105		signal(SIGINT, SIG_IGN);
1106	signal(SIGPIPE, SIG_IGN);
1107	signal(SIGHUP, cleanup_handler);
1108	signal(SIGTERM, cleanup_handler);
1109	nalloc = 0;
1110
1111	while (1) {
1112		prepare_select(&readsetp, &writesetp, &max_fd, &nalloc);
1113		if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
1114			if (errno == EINTR)
1115				continue;
1116			fatal("select: %s", strerror(errno));
1117		}
1118		after_select(readsetp, writesetp);
1119	}
1120	/* NOTREACHED */
1121}
1122