- (djm) Pick up LOGIN_PROGRAM from environment or PATH if not set by headers
 - (djm) OpenBSD CVS updates:
   - deraadt@cvs.openbsd.org 2000/08/18 20:07:23
     [ssh.c]
     accept remsh as a valid name as well; roman@buildpoint.com
   - deraadt@cvs.openbsd.org 2000/08/18 20:17:13
     [deattack.c crc32.c packet.c]
     rename crc32() to ssh_crc32() to avoid zlib name clash.  do not move to
     libz crc32 function yet, because it has ugly "long"'s in it;
     oneill@cs.sfu.ca
   - deraadt@cvs.openbsd.org 2000/08/18 20:26:08
     [scp.1 scp.c]
     -S prog support; tv@debian.org
   - deraadt@cvs.openbsd.org 2000/08/18 20:50:07
     [scp.c]
     knf
   - deraadt@cvs.openbsd.org 2000/08/18 20:57:33
     [log-client.c]
     shorten
   - markus@cvs.openbsd.org  2000/08/19 12:48:11
     [channels.c channels.h clientloop.c ssh.c ssh.h]
     support for ~. in ssh2
   - deraadt@cvs.openbsd.org 2000/08/19 15:29:40
     [crc32.h]
     proper prototype
   - markus@cvs.openbsd.org  2000/08/19 15:34:44
     [authfd.c authfd.h key.c key.h ssh-add.1 ssh-add.c ssh-agent.1]
     [ssh-agent.c ssh-keygen.c sshconnect1.c sshconnect2.c Makefile]
     [fingerprint.c fingerprint.h]
     add SSH2/DSA support to the agent and some other DSA related cleanups.
     (note that we cannot talk to ssh.com's ssh2 agents)
   - markus@cvs.openbsd.org  2000/08/19 15:55:52
     [channels.c channels.h clientloop.c]
     more ~ support for ssh2
   - markus@cvs.openbsd.org  2000/08/19 16:21:19
     [clientloop.c]
     oops
   - millert@cvs.openbsd.org 2000/08/20 12:25:53
     [session.c]
     We have to stash the result of get_remote_name_or_ip() before we
     close our socket or getpeername() will get EBADF and the process
     will exit.  Only a problem for "UseLogin yes".
   - millert@cvs.openbsd.org 2000/08/20 12:30:59
     [session.c]
     Only check /etc/nologin if "UseLogin no" since login(1) may have its
     own policy on determining who is allowed to login when /etc/nologin
     is present.  Also use the _PATH_NOLOGIN define.
   - millert@cvs.openbsd.org 2000/08/20 12:42:43
     [auth1.c auth2.c session.c ssh.c]
     Add calls to setusercontext() and login_get*().  We basically call
     setusercontext() in most places where previously we did a setlogin().
     Add default login.conf file and put root in the "daemon" login class.
   - millert@cvs.openbsd.org 2000/08/21 10:23:31
     [session.c]
     Fix incorrect PATH setting; noted by Markus.
diff --git a/ssh-agent.c b/ssh-agent.c
index e8383b5..56b81a7 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ssh-agent.c,v 1.32 2000/07/16 08:27:21 markus Exp $	*/
+/*	$OpenBSD: ssh-agent.c,v 1.33 2000/08/19 21:34:43 markus Exp $	*/
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -6,10 +6,13 @@
  *                    All rights reserved
  * Created: Wed Mar 29 03:46:59 1995 ylo
  * The authentication agent program.
+ *
+ * SSH2 implementation,
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh-agent.c,v 1.32 2000/07/16 08:27:21 markus Exp $");
+RCSID("$OpenBSD: ssh-agent.c,v 1.33 2000/08/19 21:34:43 markus Exp $");
 
 #include "ssh.h"
 #include "rsa.h"
@@ -20,11 +23,14 @@
 #include "getput.h"
 #include "mpaux.h"
 
+#include <openssl/evp.h>
 #include <openssl/md5.h>
 #include <openssl/dsa.h>
 #include <openssl/rsa.h>
 #include "key.h"
 #include "authfd.h"
+#include "dsa.h"
+#include "kex.h"
 
 typedef struct {
 	int fd;
@@ -39,12 +45,17 @@
 SocketEntry *sockets = NULL;
 
 typedef struct {
-	RSA *key;
+	Key *key;
 	char *comment;
 } Identity;
 
-unsigned int num_identities = 0;
-Identity *identities = NULL;
+typedef struct {
+	int nentries;
+	Identity *identities;
+} Idtab;
+
+/* private key table, one per protocol version */
+Idtab idtable[3];
 
 int max_fd = 0;
 
@@ -62,175 +73,243 @@
 #endif /* HAVE___PROGNAME */
 
 void
-process_request_identity(SocketEntry *e)
+idtab_init(void)
 {
+	int i;
+	for (i = 0; i <=2; i++){
+		idtable[i].identities = NULL;
+		idtable[i].nentries = 0;
+	}
+}
+
+/* return private key table for requested protocol version */
+Idtab *
+idtab_lookup(int version)
+{
+	if (version < 1 || version > 2)
+		fatal("internal error, bad protocol version %d", version);
+	return &idtable[version];
+}
+
+/* return matching private key for given public key */
+Key *
+lookup_private_key(Key *key, int *idx, int version)
+{
+	int i;
+	Idtab *tab = idtab_lookup(version);
+	for (i = 0; i < tab->nentries; i++) {
+		if (key_equal(key, tab->identities[i].key)) {
+			if (idx != NULL)
+				*idx = i;
+			return tab->identities[i].key;
+		}
+	}
+	return NULL;
+}
+
+/* send list of supported public keys to 'client' */
+void
+process_request_identities(SocketEntry *e, int version)
+{
+	Idtab *tab = idtab_lookup(version);
 	Buffer msg;
 	int i;
 
 	buffer_init(&msg);
-	buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
-	buffer_put_int(&msg, num_identities);
-	for (i = 0; i < num_identities; i++) {
-		buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
-		buffer_put_bignum(&msg, identities[i].key->e);
-		buffer_put_bignum(&msg, identities[i].key->n);
-		buffer_put_string(&msg, identities[i].comment,
-				  strlen(identities[i].comment));
+	buffer_put_char(&msg, (version == 1) ?
+	    SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
+	buffer_put_int(&msg, tab->nentries);
+	for (i = 0; i < tab->nentries; i++) {
+		Identity *id = &tab->identities[i];
+		if (id->key->type == KEY_RSA) {
+			buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
+			buffer_put_bignum(&msg, id->key->rsa->e);
+			buffer_put_bignum(&msg, id->key->rsa->n);
+		} else {
+			unsigned char *blob;
+			unsigned int blen;
+			dsa_make_key_blob(id->key, &blob, &blen);
+			buffer_put_string(&msg, blob, blen);
+			xfree(blob);
+		}
+		buffer_put_cstring(&msg, id->comment);
 	}
 	buffer_put_int(&e->output, buffer_len(&msg));
 	buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
 	buffer_free(&msg);
 }
 
+/* ssh1 only */
 void
-process_authentication_challenge(SocketEntry *e)
+process_authentication_challenge1(SocketEntry *e)
 {
-	int i, pub_bits, len;
-	BIGNUM *pub_e, *pub_n, *challenge;
+	Key *key, *private;
+	BIGNUM *challenge;
+	int i, len;
 	Buffer msg;
 	MD5_CTX md;
 	unsigned char buf[32], mdbuf[16], session_id[16];
 	unsigned int response_type;
 
 	buffer_init(&msg);
-	pub_e = BN_new();
-	pub_n = BN_new();
+	key = key_new(KEY_RSA);
 	challenge = BN_new();
-	pub_bits = buffer_get_int(&e->input);
-	buffer_get_bignum(&e->input, pub_e);
-	buffer_get_bignum(&e->input, pub_n);
+
+	buffer_get_int(&e->input);				/* ignored */
+	buffer_get_bignum(&e->input, key->rsa->e);
+	buffer_get_bignum(&e->input, key->rsa->n);
 	buffer_get_bignum(&e->input, challenge);
-	if (buffer_len(&e->input) == 0) {
-		/* Compatibility code for old servers. */
-		memset(session_id, 0, 16);
-		response_type = 0;
-	} else {
-		/* New code. */
-		buffer_get(&e->input, (char *) session_id, 16);
-		response_type = buffer_get_int(&e->input);
-	}
-	for (i = 0; i < num_identities; i++)
-		if (pub_bits == BN_num_bits(identities[i].key->n) &&
-		    BN_cmp(pub_e, identities[i].key->e) == 0 &&
-		    BN_cmp(pub_n, identities[i].key->n) == 0) {
-			/* Decrypt the challenge using the private key. */
-			rsa_private_decrypt(challenge, challenge, identities[i].key);
 
-			/* Compute the desired response. */
-			switch (response_type) {
-			case 0:/* As of protocol 1.0 */
-				/* This response type is no longer supported. */
-				log("Compatibility with ssh protocol 1.0 no longer supported.");
-				buffer_put_char(&msg, SSH_AGENT_FAILURE);
-				goto send;
+	/* Only protocol 1.1 is supported */
+	if (buffer_len(&e->input) == 0)
+		goto failure;
+	buffer_get(&e->input, (char *) session_id, 16);
+	response_type = buffer_get_int(&e->input);
+	if (response_type != 1)
+		goto failure;
 
-			case 1:/* As of protocol 1.1 */
-				/* The response is MD5 of decrypted challenge plus session id. */
-				len = BN_num_bytes(challenge);
+	private = lookup_private_key(key, NULL, 1);
+	if (private != NULL) {
+		/* Decrypt the challenge using the private key. */
+		rsa_private_decrypt(challenge, challenge, private->rsa);
 
-				if (len <= 0 || len > 32) {
-					fatal("process_authentication_challenge: "
-					 "bad challenge length %d", len);
-				}
-				memset(buf, 0, 32);
-				BN_bn2bin(challenge, buf + 32 - len);
-				MD5_Init(&md);
-				MD5_Update(&md, buf, 32);
-				MD5_Update(&md, session_id, 16);
-				MD5_Final(mdbuf, &md);
-				break;
-
-			default:
-				fatal("process_authentication_challenge: bad response_type %d",
-				      response_type);
-				break;
-			}
-
-			/* Send the response. */
-			buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
-			for (i = 0; i < 16; i++)
-				buffer_put_char(&msg, mdbuf[i]);
-
-			goto send;
+		/* The response is MD5 of decrypted challenge plus session id. */
+		len = BN_num_bytes(challenge);
+		if (len <= 0 || len > 32) {
+			log("process_authentication_challenge: bad challenge length %d", len);
+			goto failure;
 		}
-	/* Unknown identity.  Send failure. */
+		memset(buf, 0, 32);
+		BN_bn2bin(challenge, buf + 32 - len);
+		MD5_Init(&md);
+		MD5_Update(&md, buf, 32);
+		MD5_Update(&md, session_id, 16);
+		MD5_Final(mdbuf, &md);
+
+		/* Send the response. */
+		buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
+		for (i = 0; i < 16; i++)
+			buffer_put_char(&msg, mdbuf[i]);
+		goto send;
+	}
+
+failure:
+	/* Unknown identity or protocol error.  Send failure. */
 	buffer_put_char(&msg, SSH_AGENT_FAILURE);
 send:
 	buffer_put_int(&e->output, buffer_len(&msg));
-	buffer_append(&e->output, buffer_ptr(&msg),
-		      buffer_len(&msg));
-	buffer_free(&msg);
-	BN_clear_free(pub_e);
-	BN_clear_free(pub_n);
+	buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
+	key_free(key);
 	BN_clear_free(challenge);
+	buffer_free(&msg);
 }
 
+/* ssh2 only */
 void
-process_remove_identity(SocketEntry *e)
+process_sign_request2(SocketEntry *e)
 {
+	extern int datafellows;
+	Key *key, *private;
+	unsigned char *blob, *data, *signature = NULL;
+	unsigned int blen, dlen, slen = 0;
+	Buffer msg;
+	int ok = -1;
+
+	datafellows = 0;
+	
+	blob = buffer_get_string(&e->input, &blen);
+	data = buffer_get_string(&e->input, &dlen);
+
+	key = dsa_key_from_blob(blob, blen);
+	if (key != NULL) {
+		private = lookup_private_key(key, NULL, 2);
+		if (private != NULL)
+			ok = dsa_sign(private, &signature, &slen, data, dlen);
+	}
+	key_free(key);
+	buffer_init(&msg);
+	if (ok == 0) {
+		buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
+		buffer_put_string(&msg, signature, slen);
+	} else {
+		buffer_put_char(&msg, SSH_AGENT_FAILURE);
+	}
+	buffer_put_int(&e->output, buffer_len(&msg));
+	buffer_append(&e->output, buffer_ptr(&msg),
+	    buffer_len(&msg));
+	buffer_free(&msg);
+	xfree(data);
+	xfree(blob);
+	if (signature != NULL)
+		xfree(signature);
+}
+
+/* shared */
+void
+process_remove_identity(SocketEntry *e, int version)
+{
+	Key *key = NULL, *private;
+	unsigned char *blob;
+	unsigned int blen;
 	unsigned int bits;
-	unsigned int i;
-	BIGNUM *dummy, *n;
+	int success = 0;
 
-	dummy = BN_new();
-	n = BN_new();
+	switch(version){
+	case 1:
+		key = key_new(KEY_RSA);
+		bits = buffer_get_int(&e->input);
+		buffer_get_bignum(&e->input, key->rsa->e);
+		buffer_get_bignum(&e->input, key->rsa->n);
 
-	/* Get the key from the packet. */
-	bits = buffer_get_int(&e->input);
-	buffer_get_bignum(&e->input, dummy);
-	buffer_get_bignum(&e->input, n);
-
-	if (bits != BN_num_bits(n))
-		log("Warning: identity keysize mismatch: actual %d, announced %d",
-		      BN_num_bits(n), bits);
-
-	/* Check if we have the key. */
-	for (i = 0; i < num_identities; i++)
-		if (BN_cmp(identities[i].key->n, n) == 0) {
+		if (bits != key_size(key))
+			log("Warning: identity keysize mismatch: actual %d, announced %d",
+			      key_size(key), bits);
+		break;
+	case 2:
+		blob = buffer_get_string(&e->input, &blen);
+		key = dsa_key_from_blob(blob, blen);
+		xfree(blob);
+		break;
+	}
+	if (key != NULL) {
+		int idx;
+		private = lookup_private_key(key, &idx, version);
+		if (private != NULL) {
 			/*
 			 * We have this key.  Free the old key.  Since we
 			 * don\'t want to leave empty slots in the middle of
 			 * the array, we actually free the key there and copy
 			 * data from the last entry.
 			 */
-			RSA_free(identities[i].key);
-			xfree(identities[i].comment);
-			if (i < num_identities - 1)
-				identities[i] = identities[num_identities - 1];
-			num_identities--;
-			BN_clear_free(dummy);
-			BN_clear_free(n);
-
-			/* Send success. */
-			buffer_put_int(&e->output, 1);
-			buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
-			return;
+			Idtab *tab = idtab_lookup(version);
+			key_free(tab->identities[idx].key);
+			xfree(tab->identities[idx].comment);
+			if (idx != tab->nentries)
+				tab->identities[idx] = tab->identities[tab->nentries];
+			tab->nentries--;
+			success = 1;
 		}
-	/* We did not have the key. */
-	BN_clear(dummy);
-	BN_clear(n);
-
-	/* Send failure. */
+		key_free(key);
+	}
 	buffer_put_int(&e->output, 1);
-	buffer_put_char(&e->output, SSH_AGENT_FAILURE);
+	buffer_put_char(&e->output,
+	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
 }
 
-/*
- * Removes all identities from the agent.
- */
 void
-process_remove_all_identities(SocketEntry *e)
+process_remove_all_identities(SocketEntry *e, int version)
 {
 	unsigned int i;
+	Idtab *tab = idtab_lookup(version);
 
 	/* Loop over all identities and clear the keys. */
-	for (i = 0; i < num_identities; i++) {
-		RSA_free(identities[i].key);
-		xfree(identities[i].comment);
+	for (i = 0; i < tab->nentries; i++) {
+		key_free(tab->identities[i].key);
+		xfree(tab->identities[i].comment);
 	}
 
 	/* Mark that there are no identities. */
-	num_identities = 0;
+	tab->nentries = 0;
 
 	/* Send success. */
 	buffer_put_int(&e->output, 1);
@@ -238,79 +317,108 @@
 	return;
 }
 
-/*
- * Adds an identity to the agent.
- */
 void
-process_add_identity(SocketEntry *e)
+process_add_identity(SocketEntry *e, int version)
 {
-	RSA *k;
-	int i;
+	Key *k = NULL;
+	RSA *rsa;
 	BIGNUM *aux;
 	BN_CTX *ctx;
+	char *type;
+	char *comment;
+	int success = 0;
+	Idtab *tab = idtab_lookup(version);
 
-	if (num_identities == 0)
-		identities = xmalloc(sizeof(Identity));
-	else
-		identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
+	switch (version) {
+	case 1:
+		k = key_new(KEY_RSA);
+		rsa = k->rsa;
 
-	identities[num_identities].key = RSA_new();
-	k = identities[num_identities].key;
-	buffer_get_int(&e->input);	/* bits */
-	k->n = BN_new();
-	buffer_get_bignum(&e->input, k->n);
-	k->e = BN_new();
-	buffer_get_bignum(&e->input, k->e);
-	k->d = BN_new();
-	buffer_get_bignum(&e->input, k->d);
-	k->iqmp = BN_new();
-	buffer_get_bignum(&e->input, k->iqmp);
-	/* SSH and SSL have p and q swapped */
-	k->q = BN_new();
-	buffer_get_bignum(&e->input, k->q);	/* p */
-	k->p = BN_new();
-	buffer_get_bignum(&e->input, k->p);	/* q */
+		/* allocate mem for private key */
+		/* XXX rsa->n and rsa->e are already allocated */
+		rsa->d = BN_new();
+		rsa->iqmp = BN_new();
+		rsa->q = BN_new();
+		rsa->p = BN_new();
+		rsa->dmq1 = BN_new();
+		rsa->dmp1 = BN_new();
 
-	/* Generate additional parameters */
-	aux = BN_new();
-	ctx = BN_CTX_new();
+		buffer_get_int(&e->input);		 /* ignored */
 
-	BN_sub(aux, k->q, BN_value_one());
-	k->dmq1 = BN_new();
-	BN_mod(k->dmq1, k->d, aux, ctx);
+		buffer_get_bignum(&e->input, rsa->n);
+		buffer_get_bignum(&e->input, rsa->e);
+		buffer_get_bignum(&e->input, rsa->d);
+		buffer_get_bignum(&e->input, rsa->iqmp);
 
-	BN_sub(aux, k->p, BN_value_one());
-	k->dmp1 = BN_new();
-	BN_mod(k->dmp1, k->d, aux, ctx);
+		/* SSH and SSL have p and q swapped */
+		buffer_get_bignum(&e->input, rsa->q);	/* p */
+		buffer_get_bignum(&e->input, rsa->p);	/* q */
 
-	BN_clear_free(aux);
-	BN_CTX_free(ctx);
+		/* Generate additional parameters */
+		aux = BN_new();
+		ctx = BN_CTX_new();
 
-	identities[num_identities].comment = buffer_get_string(&e->input, NULL);
+		BN_sub(aux, rsa->q, BN_value_one());
+		BN_mod(rsa->dmq1, rsa->d, aux, ctx);
 
-	/* Check if we already have the key. */
-	for (i = 0; i < num_identities; i++)
-		if (BN_cmp(identities[i].key->n, k->n) == 0) {
-			/*
-			 * We already have this key.  Clear and free the new
-			 * data and return success.
-			 */
-			RSA_free(k);
-			xfree(identities[num_identities].comment);
+		BN_sub(aux, rsa->p, BN_value_one());
+		BN_mod(rsa->dmp1, rsa->d, aux, ctx);
 
-			/* Send success. */
-			buffer_put_int(&e->output, 1);
-			buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
-			return;
+		BN_clear_free(aux);
+		BN_CTX_free(ctx);
+
+		break;
+	case 2:
+		type = buffer_get_string(&e->input, NULL);
+		if (strcmp(type, KEX_DSS)) {
+			buffer_clear(&e->input);
+			xfree(type);
+			goto send;
 		}
-	/* Increment the number of identities. */
-	num_identities++;
+		xfree(type);
 
-	/* Send a success message. */
+		k = key_new(KEY_DSA);
+
+		/* allocate mem for private key */
+		k->dsa->priv_key = BN_new();
+
+		buffer_get_bignum2(&e->input, k->dsa->p);
+		buffer_get_bignum2(&e->input, k->dsa->q);
+		buffer_get_bignum2(&e->input, k->dsa->g);
+		buffer_get_bignum2(&e->input, k->dsa->pub_key);
+		buffer_get_bignum2(&e->input, k->dsa->priv_key);
+
+		break;
+	}
+
+	comment = buffer_get_string(&e->input, NULL);
+	if (k == NULL) {
+		xfree(comment);
+		goto send;
+	}
+	success = 1;
+	if (lookup_private_key(k, NULL, version) == NULL) {
+		if (tab->nentries == 0)
+			tab->identities = xmalloc(sizeof(Identity));
+		else
+			tab->identities = xrealloc(tab->identities,
+			    (tab->nentries + 1) * sizeof(Identity));
+		tab->identities[tab->nentries].key = k;
+		tab->identities[tab->nentries].comment = comment;
+		/* Increment the number of identities. */
+		tab->nentries++;
+	} else {
+		key_free(k);
+		xfree(comment);
+	}
+send:
 	buffer_put_int(&e->output, 1);
-	buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
+	buffer_put_char(&e->output,
+	    success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
 }
 
+/* dispatch incoming messages */
+
 void
 process_message(SocketEntry *e)
 {
@@ -333,20 +441,37 @@
 	type = buffer_get_char(&e->input);
 
 	switch (type) {
-	case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
-		process_request_identity(e);
-		break;
+	/* ssh1 */
 	case SSH_AGENTC_RSA_CHALLENGE:
-		process_authentication_challenge(e);
+		process_authentication_challenge1(e);
+		break;
+	case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
+		process_request_identities(e, 1);
 		break;
 	case SSH_AGENTC_ADD_RSA_IDENTITY:
-		process_add_identity(e);
+		process_add_identity(e, 1);
 		break;
 	case SSH_AGENTC_REMOVE_RSA_IDENTITY:
-		process_remove_identity(e);
+		process_remove_identity(e, 1);
 		break;
 	case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
-		process_remove_all_identities(e);
+		process_remove_all_identities(e, 1);
+		break;
+	/* ssh2 */
+	case SSH2_AGENTC_SIGN_REQUEST:
+		process_sign_request2(e);
+		break;
+	case SSH2_AGENTC_REQUEST_IDENTITIES:
+		process_request_identities(e, 2);
+		break;
+	case SSH2_AGENTC_ADD_IDENTITY:
+		process_add_identity(e, 2);
+		break;
+	case SSH2_AGENTC_REMOVE_IDENTITY:
+		process_remove_identity(e, 2);
+		break;
+	case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
+		process_remove_all_identities(e, 2);
 		break;
 	default:
 		/* Unknown message.  Respond with failure. */
@@ -511,9 +636,9 @@
 	pid_t pid;
 	char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
 	extern int optind;
-
+	
 	init_rng();
-
+	
 	/* check if RSA support exists */
 	if (rsa_alive() == 0) {
 		fprintf(stderr,
@@ -654,6 +779,7 @@
 		signal(SIGALRM, check_parent_exists);
 		alarm(10);
 	}
+	idtab_init();
 	signal(SIGINT, SIG_IGN);
 	signal(SIGPIPE, SIG_IGN);
 	signal(SIGHUP, cleanup_exit);