xref: /titanic_44/usr/src/cmd/ssh/libssh/common/authfd.c (revision b9aa66a73c9016cf5c71fe80efe90ce9f2ca5c73)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
37c478bd9Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
47c478bd9Sstevel@tonic-gate  *                    All rights reserved
57c478bd9Sstevel@tonic-gate  * Functions for connecting the local authentication agent.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
87c478bd9Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
97c478bd9Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
107c478bd9Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
117c478bd9Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * SSH2 implementation,
147c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
177c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
187c478bd9Sstevel@tonic-gate  * are met:
197c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
207c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
217c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
227c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
237c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
267c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
277c478bd9Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
287c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
297c478bd9Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
307c478bd9Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
317c478bd9Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
327c478bd9Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
337c478bd9Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
347c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include "includes.h"
387c478bd9Sstevel@tonic-gate RCSID("$OpenBSD: authfd.c,v 1.57 2002/09/11 18:27:26 stevesk Exp $");
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <openssl/evp.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include "ssh.h"
437c478bd9Sstevel@tonic-gate #include "rsa.h"
447c478bd9Sstevel@tonic-gate #include "buffer.h"
457c478bd9Sstevel@tonic-gate #include "bufaux.h"
467c478bd9Sstevel@tonic-gate #include "xmalloc.h"
477c478bd9Sstevel@tonic-gate #include "getput.h"
487c478bd9Sstevel@tonic-gate #include "key.h"
497c478bd9Sstevel@tonic-gate #include "authfd.h"
507c478bd9Sstevel@tonic-gate #include "cipher.h"
517c478bd9Sstevel@tonic-gate #include "kex.h"
527c478bd9Sstevel@tonic-gate #include "compat.h"
537c478bd9Sstevel@tonic-gate #include "log.h"
547c478bd9Sstevel@tonic-gate #include "atomicio.h"
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static int agent_present = 0;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* helper */
597c478bd9Sstevel@tonic-gate int	decode_reply(int type);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /* macro to check for "agent failure" message */
627c478bd9Sstevel@tonic-gate #define agent_failed(x) \
637c478bd9Sstevel@tonic-gate     ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \
647c478bd9Sstevel@tonic-gate     (x == SSH2_AGENT_FAILURE))
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate int
ssh_agent_present(void)677c478bd9Sstevel@tonic-gate ssh_agent_present(void)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	int authfd;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	if (agent_present)
727c478bd9Sstevel@tonic-gate 		return 1;
737c478bd9Sstevel@tonic-gate 	if ((authfd = ssh_get_authentication_socket()) == -1)
747c478bd9Sstevel@tonic-gate 		return 0;
757c478bd9Sstevel@tonic-gate 	else {
767c478bd9Sstevel@tonic-gate 		ssh_close_authentication_socket(authfd);
777c478bd9Sstevel@tonic-gate 		return 1;
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /* Returns the number of the authentication fd, or -1 if there is none. */
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate int
ssh_get_authentication_socket(void)847c478bd9Sstevel@tonic-gate ssh_get_authentication_socket(void)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	const char *authsocket;
877c478bd9Sstevel@tonic-gate 	int sock;
887c478bd9Sstevel@tonic-gate 	struct sockaddr_un sunaddr;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
917c478bd9Sstevel@tonic-gate 	if (!authsocket)
927c478bd9Sstevel@tonic-gate 		return -1;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	sunaddr.sun_family = AF_UNIX;
957c478bd9Sstevel@tonic-gate 	strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
987c478bd9Sstevel@tonic-gate 	if (sock < 0)
997c478bd9Sstevel@tonic-gate 		return -1;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	/* close on exec */
102*b9aa66a7SJan Pechanec 	if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) {
1037c478bd9Sstevel@tonic-gate 		close(sock);
1047c478bd9Sstevel@tonic-gate 		return -1;
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 	if (connect(sock, (struct sockaddr *) &sunaddr, sizeof sunaddr) < 0) {
1077c478bd9Sstevel@tonic-gate 		close(sock);
1087c478bd9Sstevel@tonic-gate 		return -1;
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate 	agent_present = 1;
1117c478bd9Sstevel@tonic-gate 	return sock;
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static int
ssh_request_reply(AuthenticationConnection * auth,Buffer * request,Buffer * reply)1157c478bd9Sstevel@tonic-gate ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	int l, len;
1187c478bd9Sstevel@tonic-gate 	char buf[1024];
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/* Get the length of the message, and format it in the buffer. */
1217c478bd9Sstevel@tonic-gate 	len = buffer_len(request);
1227c478bd9Sstevel@tonic-gate 	PUT_32BIT(buf, len);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	/* Send the length and then the packet to the agent. */
1257c478bd9Sstevel@tonic-gate 	if (atomicio(write, auth->fd, buf, 4) != 4 ||
1267c478bd9Sstevel@tonic-gate 	    atomicio(write, auth->fd, buffer_ptr(request),
1277c478bd9Sstevel@tonic-gate 	    buffer_len(request)) != buffer_len(request)) {
1287c478bd9Sstevel@tonic-gate 		error("Error writing to authentication socket.");
1297c478bd9Sstevel@tonic-gate 		return 0;
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 	/*
1327c478bd9Sstevel@tonic-gate 	 * Wait for response from the agent.  First read the length of the
1337c478bd9Sstevel@tonic-gate 	 * response packet.
1347c478bd9Sstevel@tonic-gate 	 */
1357c478bd9Sstevel@tonic-gate 	len = 4;
1367c478bd9Sstevel@tonic-gate 	while (len > 0) {
1377c478bd9Sstevel@tonic-gate 		l = read(auth->fd, buf + 4 - len, len);
1387c478bd9Sstevel@tonic-gate 		if (l == -1 && (errno == EAGAIN || errno == EINTR))
1397c478bd9Sstevel@tonic-gate 			continue;
1407c478bd9Sstevel@tonic-gate 		if (l <= 0) {
1417c478bd9Sstevel@tonic-gate 			error("Error reading response length from authentication socket.");
1427c478bd9Sstevel@tonic-gate 			return 0;
1437c478bd9Sstevel@tonic-gate 		}
1447c478bd9Sstevel@tonic-gate 		len -= l;
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	/* Extract the length, and check it for sanity. */
1487c478bd9Sstevel@tonic-gate 	len = GET_32BIT(buf);
1497c478bd9Sstevel@tonic-gate 	if (len > 256 * 1024)
1507c478bd9Sstevel@tonic-gate 		fatal("Authentication response too long: %d", len);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/* Read the rest of the response in to the buffer. */
1537c478bd9Sstevel@tonic-gate 	buffer_clear(reply);
1547c478bd9Sstevel@tonic-gate 	while (len > 0) {
1557c478bd9Sstevel@tonic-gate 		l = len;
1567c478bd9Sstevel@tonic-gate 		if (l > sizeof(buf))
1577c478bd9Sstevel@tonic-gate 			l = sizeof(buf);
1587c478bd9Sstevel@tonic-gate 		l = read(auth->fd, buf, l);
1597c478bd9Sstevel@tonic-gate 		if (l == -1 && (errno == EAGAIN || errno == EINTR))
1607c478bd9Sstevel@tonic-gate 			continue;
1617c478bd9Sstevel@tonic-gate 		if (l <= 0) {
1627c478bd9Sstevel@tonic-gate 			error("Error reading response from authentication socket.");
1637c478bd9Sstevel@tonic-gate 			return 0;
1647c478bd9Sstevel@tonic-gate 		}
1657c478bd9Sstevel@tonic-gate 		buffer_append(reply, buf, l);
1667c478bd9Sstevel@tonic-gate 		len -= l;
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 	return 1;
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate  * Closes the agent socket if it should be closed (depends on how it was
1737c478bd9Sstevel@tonic-gate  * obtained).  The argument must have been returned by
1747c478bd9Sstevel@tonic-gate  * ssh_get_authentication_socket().
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate void
ssh_close_authentication_socket(int sock)1787c478bd9Sstevel@tonic-gate ssh_close_authentication_socket(int sock)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	if (getenv(SSH_AUTHSOCKET_ENV_NAME))
1817c478bd9Sstevel@tonic-gate 		close(sock);
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate  * Opens and connects a private socket for communication with the
1867c478bd9Sstevel@tonic-gate  * authentication agent.  Returns the file descriptor (which must be
1877c478bd9Sstevel@tonic-gate  * shut down and closed by the caller when no longer needed).
1887c478bd9Sstevel@tonic-gate  * Returns NULL if an error occurred and the connection could not be
1897c478bd9Sstevel@tonic-gate  * opened.
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate AuthenticationConnection *
ssh_get_authentication_connection(void)1937c478bd9Sstevel@tonic-gate ssh_get_authentication_connection(void)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	AuthenticationConnection *auth;
1967c478bd9Sstevel@tonic-gate 	int sock;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	sock = ssh_get_authentication_socket();
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/*
2017c478bd9Sstevel@tonic-gate 	 * Fail if we couldn't obtain a connection.  This happens if we
2027c478bd9Sstevel@tonic-gate 	 * exited due to a timeout.
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	if (sock < 0)
2057c478bd9Sstevel@tonic-gate 		return NULL;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	auth = xmalloc(sizeof(*auth));
2087c478bd9Sstevel@tonic-gate 	auth->fd = sock;
2097c478bd9Sstevel@tonic-gate 	buffer_init(&auth->identities);
2107c478bd9Sstevel@tonic-gate 	auth->howmany = 0;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	return auth;
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate  * Closes the connection to the authentication agent and frees any associated
2177c478bd9Sstevel@tonic-gate  * memory.
2187c478bd9Sstevel@tonic-gate  */
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate void
ssh_close_authentication_connection(AuthenticationConnection * auth)2217c478bd9Sstevel@tonic-gate ssh_close_authentication_connection(AuthenticationConnection *auth)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	buffer_free(&auth->identities);
2247c478bd9Sstevel@tonic-gate 	close(auth->fd);
2257c478bd9Sstevel@tonic-gate 	xfree(auth);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate /* Lock/unlock agent */
2297c478bd9Sstevel@tonic-gate int
ssh_lock_agent(AuthenticationConnection * auth,int lock,const char * password)2307c478bd9Sstevel@tonic-gate ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	int type;
2337c478bd9Sstevel@tonic-gate 	Buffer msg;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	buffer_init(&msg);
2367c478bd9Sstevel@tonic-gate 	buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK);
2377c478bd9Sstevel@tonic-gate 	buffer_put_cstring(&msg, password);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if (ssh_request_reply(auth, &msg, &msg) == 0) {
2407c478bd9Sstevel@tonic-gate 		buffer_free(&msg);
2417c478bd9Sstevel@tonic-gate 		return 0;
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	type = buffer_get_char(&msg);
2447c478bd9Sstevel@tonic-gate 	buffer_free(&msg);
2457c478bd9Sstevel@tonic-gate 	return decode_reply(type);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * Returns the first authentication identity held by the agent.
2507c478bd9Sstevel@tonic-gate  */
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate int
ssh_get_num_identities(AuthenticationConnection * auth,int version)2537c478bd9Sstevel@tonic-gate ssh_get_num_identities(AuthenticationConnection *auth, int version)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 	int type, code1 = 0, code2 = 0;
2567c478bd9Sstevel@tonic-gate 	Buffer request;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	switch (version) {
2597c478bd9Sstevel@tonic-gate 	case 1:
2607c478bd9Sstevel@tonic-gate 		code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
2617c478bd9Sstevel@tonic-gate 		code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
2627c478bd9Sstevel@tonic-gate 		break;
2637c478bd9Sstevel@tonic-gate 	case 2:
2647c478bd9Sstevel@tonic-gate 		code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
2657c478bd9Sstevel@tonic-gate 		code2 = SSH2_AGENT_IDENTITIES_ANSWER;
2667c478bd9Sstevel@tonic-gate 		break;
2677c478bd9Sstevel@tonic-gate 	default:
2687c478bd9Sstevel@tonic-gate 		return 0;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	/*
2727c478bd9Sstevel@tonic-gate 	 * Send a message to the agent requesting for a list of the
2737c478bd9Sstevel@tonic-gate 	 * identities it can represent.
2747c478bd9Sstevel@tonic-gate 	 */
2757c478bd9Sstevel@tonic-gate 	buffer_init(&request);
2767c478bd9Sstevel@tonic-gate 	buffer_put_char(&request, code1);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	buffer_clear(&auth->identities);
2797c478bd9Sstevel@tonic-gate 	if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
2807c478bd9Sstevel@tonic-gate 		buffer_free(&request);
2817c478bd9Sstevel@tonic-gate 		return 0;
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 	buffer_free(&request);
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	/* Get message type, and verify that we got a proper answer. */
2867c478bd9Sstevel@tonic-gate 	type = buffer_get_char(&auth->identities);
2877c478bd9Sstevel@tonic-gate 	if (agent_failed(type)) {
2887c478bd9Sstevel@tonic-gate 		return 0;
2897c478bd9Sstevel@tonic-gate 	} else if (type != code2) {
2907c478bd9Sstevel@tonic-gate 		fatal("Bad authentication reply message type: %d", type);
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	/* Get the number of entries in the response and check it for sanity. */
2947c478bd9Sstevel@tonic-gate 	auth->howmany = buffer_get_int(&auth->identities);
2957c478bd9Sstevel@tonic-gate 	if (auth->howmany > 1024)
2967c478bd9Sstevel@tonic-gate 		fatal("Too many identities in authentication reply: %d",
2977c478bd9Sstevel@tonic-gate 		    auth->howmany);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	return auth->howmany;
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate Key *
ssh_get_first_identity(AuthenticationConnection * auth,char ** comment,int version)3037c478bd9Sstevel@tonic-gate ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	/* get number of identities and return the first entry (if any). */
3067c478bd9Sstevel@tonic-gate 	if (ssh_get_num_identities(auth, version) > 0)
3077c478bd9Sstevel@tonic-gate 		return ssh_get_next_identity(auth, comment, version);
3087c478bd9Sstevel@tonic-gate 	return NULL;
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate Key *
ssh_get_next_identity(AuthenticationConnection * auth,char ** comment,int version)3127c478bd9Sstevel@tonic-gate ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	u_int bits;
3157c478bd9Sstevel@tonic-gate 	u_char *blob;
3167c478bd9Sstevel@tonic-gate 	u_int blen;
3177c478bd9Sstevel@tonic-gate 	Key *key = NULL;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/* Return failure if no more entries. */
3207c478bd9Sstevel@tonic-gate 	if (auth->howmany <= 0)
3217c478bd9Sstevel@tonic-gate 		return NULL;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	/*
3247c478bd9Sstevel@tonic-gate 	 * Get the next entry from the packet.  These will abort with a fatal
3257c478bd9Sstevel@tonic-gate 	 * error if the packet is too short or contains corrupt data.
3267c478bd9Sstevel@tonic-gate 	 */
3277c478bd9Sstevel@tonic-gate 	switch (version) {
3287c478bd9Sstevel@tonic-gate 	case 1:
3297c478bd9Sstevel@tonic-gate 		key = key_new(KEY_RSA1);
3307c478bd9Sstevel@tonic-gate 		bits = buffer_get_int(&auth->identities);
3317c478bd9Sstevel@tonic-gate 		buffer_get_bignum(&auth->identities, key->rsa->e);
3327c478bd9Sstevel@tonic-gate 		buffer_get_bignum(&auth->identities, key->rsa->n);
3337c478bd9Sstevel@tonic-gate 		*comment = buffer_get_string(&auth->identities, NULL);
3347c478bd9Sstevel@tonic-gate 		if (bits != BN_num_bits(key->rsa->n))
3357c478bd9Sstevel@tonic-gate 			log("Warning: identity keysize mismatch: actual %d, announced %u",
3367c478bd9Sstevel@tonic-gate 			    BN_num_bits(key->rsa->n), bits);
3377c478bd9Sstevel@tonic-gate 		break;
3387c478bd9Sstevel@tonic-gate 	case 2:
3397c478bd9Sstevel@tonic-gate 		blob = buffer_get_string(&auth->identities, &blen);
3407c478bd9Sstevel@tonic-gate 		*comment = buffer_get_string(&auth->identities, NULL);
3417c478bd9Sstevel@tonic-gate 		key = key_from_blob(blob, blen);
3427c478bd9Sstevel@tonic-gate 		xfree(blob);
3437c478bd9Sstevel@tonic-gate 		break;
3447c478bd9Sstevel@tonic-gate 	default:
3457c478bd9Sstevel@tonic-gate 		return NULL;
3467c478bd9Sstevel@tonic-gate 		break;
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 	/* Decrement the number of remaining entries. */
3497c478bd9Sstevel@tonic-gate 	auth->howmany--;
3507c478bd9Sstevel@tonic-gate 	return key;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate  * Generates a random challenge, sends it to the agent, and waits for
3557c478bd9Sstevel@tonic-gate  * response from the agent.  Returns true (non-zero) if the agent gave the
3567c478bd9Sstevel@tonic-gate  * correct answer, zero otherwise.  Response type selects the style of
3577c478bd9Sstevel@tonic-gate  * response desired, with 0 corresponding to protocol version 1.0 (no longer
3587c478bd9Sstevel@tonic-gate  * supported) and 1 corresponding to protocol version 1.1.
3597c478bd9Sstevel@tonic-gate  */
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate int
ssh_decrypt_challenge(AuthenticationConnection * auth,Key * key,BIGNUM * challenge,u_char session_id[16],u_int response_type,u_char response[16])3627c478bd9Sstevel@tonic-gate ssh_decrypt_challenge(AuthenticationConnection *auth,
3637c478bd9Sstevel@tonic-gate     Key* key, BIGNUM *challenge,
3647c478bd9Sstevel@tonic-gate     u_char session_id[16],
3657c478bd9Sstevel@tonic-gate     u_int response_type,
3667c478bd9Sstevel@tonic-gate     u_char response[16])
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	Buffer buffer;
3697c478bd9Sstevel@tonic-gate 	int success = 0;
3707c478bd9Sstevel@tonic-gate 	int i;
3717c478bd9Sstevel@tonic-gate 	int type;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if (key->type != KEY_RSA1)
3747c478bd9Sstevel@tonic-gate 		return 0;
3757c478bd9Sstevel@tonic-gate 	if (response_type == 0) {
3767c478bd9Sstevel@tonic-gate 		log("Compatibility with ssh protocol version 1.0 no longer supported.");
3777c478bd9Sstevel@tonic-gate 		return 0;
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 	buffer_init(&buffer);
3807c478bd9Sstevel@tonic-gate 	buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
3817c478bd9Sstevel@tonic-gate 	buffer_put_int(&buffer, BN_num_bits(key->rsa->n));
3827c478bd9Sstevel@tonic-gate 	buffer_put_bignum(&buffer, key->rsa->e);
3837c478bd9Sstevel@tonic-gate 	buffer_put_bignum(&buffer, key->rsa->n);
3847c478bd9Sstevel@tonic-gate 	buffer_put_bignum(&buffer, challenge);
3857c478bd9Sstevel@tonic-gate 	buffer_append(&buffer, session_id, 16);
3867c478bd9Sstevel@tonic-gate 	buffer_put_int(&buffer, response_type);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
3897c478bd9Sstevel@tonic-gate 		buffer_free(&buffer);
3907c478bd9Sstevel@tonic-gate 		return 0;
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 	type = buffer_get_char(&buffer);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if (agent_failed(type)) {
3957c478bd9Sstevel@tonic-gate 		log("Agent admitted failure to authenticate using the key.");
3967c478bd9Sstevel@tonic-gate 	} else if (type != SSH_AGENT_RSA_RESPONSE) {
3977c478bd9Sstevel@tonic-gate 		fatal("Bad authentication response: %d", type);
3987c478bd9Sstevel@tonic-gate 	} else {
3997c478bd9Sstevel@tonic-gate 		success = 1;
4007c478bd9Sstevel@tonic-gate 		/*
4017c478bd9Sstevel@tonic-gate 		 * Get the response from the packet.  This will abort with a
4027c478bd9Sstevel@tonic-gate 		 * fatal error if the packet is corrupt.
4037c478bd9Sstevel@tonic-gate 		 */
4047c478bd9Sstevel@tonic-gate 		for (i = 0; i < 16; i++)
4057c478bd9Sstevel@tonic-gate 			response[i] = buffer_get_char(&buffer);
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 	buffer_free(&buffer);
4087c478bd9Sstevel@tonic-gate 	return success;
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate /* ask agent to sign data, returns -1 on error, 0 on success */
4127c478bd9Sstevel@tonic-gate int
ssh_agent_sign(AuthenticationConnection * auth,Key * key,u_char ** sigp,u_int * lenp,u_char * data,u_int datalen)4137c478bd9Sstevel@tonic-gate ssh_agent_sign(AuthenticationConnection *auth,
4147c478bd9Sstevel@tonic-gate     Key *key,
4157c478bd9Sstevel@tonic-gate     u_char **sigp, u_int *lenp,
4167c478bd9Sstevel@tonic-gate     u_char *data, u_int datalen)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	Buffer msg;
4197c478bd9Sstevel@tonic-gate 	u_char *blob;
4207c478bd9Sstevel@tonic-gate 	u_int blen;
4217c478bd9Sstevel@tonic-gate 	int type, flags = 0;
4227c478bd9Sstevel@tonic-gate 	int ret = -1;
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	if (key_to_blob(key, &blob, &blen) == 0)
4257c478bd9Sstevel@tonic-gate 		return -1;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (datafellows & SSH_BUG_SIGBLOB)
4287c478bd9Sstevel@tonic-gate 		flags = SSH_AGENT_OLD_SIGNATURE;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	buffer_init(&msg);
4317c478bd9Sstevel@tonic-gate 	buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
4327c478bd9Sstevel@tonic-gate 	buffer_put_string(&msg, blob, blen);
4337c478bd9Sstevel@tonic-gate 	buffer_put_string(&msg, data, datalen);
4347c478bd9Sstevel@tonic-gate 	buffer_put_int(&msg, flags);
4357c478bd9Sstevel@tonic-gate 	xfree(blob);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (ssh_request_reply(auth, &msg, &msg) == 0) {
4387c478bd9Sstevel@tonic-gate 		buffer_free(&msg);
4397c478bd9Sstevel@tonic-gate 		return -1;
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 	type = buffer_get_char(&msg);
4427c478bd9Sstevel@tonic-gate 	if (agent_failed(type)) {
4437c478bd9Sstevel@tonic-gate 		log("Agent admitted failure to sign using the key.");
4447c478bd9Sstevel@tonic-gate 	} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
4457c478bd9Sstevel@tonic-gate 		fatal("Bad authentication response: %d", type);
4467c478bd9Sstevel@tonic-gate 	} else {
4477c478bd9Sstevel@tonic-gate 		ret = 0;
4487c478bd9Sstevel@tonic-gate 		*sigp = buffer_get_string(&msg, lenp);
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 	buffer_free(&msg);
4517c478bd9Sstevel@tonic-gate 	return ret;
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /* Encode key for a message to the agent. */
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate static void
ssh_encode_identity_rsa1(Buffer * b,RSA * key,const char * comment)4577c478bd9Sstevel@tonic-gate ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
4587c478bd9Sstevel@tonic-gate {
4597c478bd9Sstevel@tonic-gate 	buffer_put_int(b, BN_num_bits(key->n));
4607c478bd9Sstevel@tonic-gate 	buffer_put_bignum(b, key->n);
4617c478bd9Sstevel@tonic-gate 	buffer_put_bignum(b, key->e);
4627c478bd9Sstevel@tonic-gate 	buffer_put_bignum(b, key->d);
4637c478bd9Sstevel@tonic-gate 	/* To keep within the protocol: p < q for ssh. in SSL p > q */
4647c478bd9Sstevel@tonic-gate 	buffer_put_bignum(b, key->iqmp);	/* ssh key->u */
4657c478bd9Sstevel@tonic-gate 	buffer_put_bignum(b, key->q);	/* ssh key->p, SSL key->q */
4667c478bd9Sstevel@tonic-gate 	buffer_put_bignum(b, key->p);	/* ssh key->q, SSL key->p */
4677c478bd9Sstevel@tonic-gate 	buffer_put_cstring(b, comment);
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate static void
ssh_encode_identity_ssh2(Buffer * b,Key * key,const char * comment)4717c478bd9Sstevel@tonic-gate ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	buffer_put_cstring(b, key_ssh_name(key));
4747c478bd9Sstevel@tonic-gate 	switch (key->type) {
4757c478bd9Sstevel@tonic-gate 	case KEY_RSA:
4767c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->rsa->n);
4777c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->rsa->e);
4787c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->rsa->d);
4797c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->rsa->iqmp);
4807c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->rsa->p);
4817c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->rsa->q);
4827c478bd9Sstevel@tonic-gate 		break;
4837c478bd9Sstevel@tonic-gate 	case KEY_DSA:
4847c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->dsa->p);
4857c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->dsa->q);
4867c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->dsa->g);
4877c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->dsa->pub_key);
4887c478bd9Sstevel@tonic-gate 		buffer_put_bignum2(b, key->dsa->priv_key);
4897c478bd9Sstevel@tonic-gate 		break;
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 	buffer_put_cstring(b, comment);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate  * Adds an identity to the authentication server.  This call is not meant to
4967c478bd9Sstevel@tonic-gate  * be used by normal applications.
4977c478bd9Sstevel@tonic-gate  */
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate int
ssh_add_identity_constrained(AuthenticationConnection * auth,Key * key,const char * comment,u_int life)5007c478bd9Sstevel@tonic-gate ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
5017c478bd9Sstevel@tonic-gate     const char *comment, u_int life)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	Buffer msg;
5047c478bd9Sstevel@tonic-gate 	int type, constrained = (life != 0);
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	buffer_init(&msg);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	switch (key->type) {
5097c478bd9Sstevel@tonic-gate 	case KEY_RSA1:
5107c478bd9Sstevel@tonic-gate 		type = constrained ?
5117c478bd9Sstevel@tonic-gate 		    SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
5127c478bd9Sstevel@tonic-gate 		    SSH_AGENTC_ADD_RSA_IDENTITY;
5137c478bd9Sstevel@tonic-gate 		buffer_put_char(&msg, type);
5147c478bd9Sstevel@tonic-gate 		ssh_encode_identity_rsa1(&msg, key->rsa, comment);
5157c478bd9Sstevel@tonic-gate 		break;
5167c478bd9Sstevel@tonic-gate 	case KEY_RSA:
5177c478bd9Sstevel@tonic-gate 	case KEY_DSA:
5187c478bd9Sstevel@tonic-gate 		type = constrained ?
5197c478bd9Sstevel@tonic-gate 		    SSH2_AGENTC_ADD_ID_CONSTRAINED :
5207c478bd9Sstevel@tonic-gate 		    SSH2_AGENTC_ADD_IDENTITY;
5217c478bd9Sstevel@tonic-gate 		buffer_put_char(&msg, type);
5227c478bd9Sstevel@tonic-gate 		ssh_encode_identity_ssh2(&msg, key, comment);
5237c478bd9Sstevel@tonic-gate 		break;
5247c478bd9Sstevel@tonic-gate 	default:
5257c478bd9Sstevel@tonic-gate 		buffer_free(&msg);
5267c478bd9Sstevel@tonic-gate 		return 0;
5277c478bd9Sstevel@tonic-gate 		break;
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 	if (constrained) {
5307c478bd9Sstevel@tonic-gate 		if (life != 0) {
5317c478bd9Sstevel@tonic-gate 			buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME);
5327c478bd9Sstevel@tonic-gate 			buffer_put_int(&msg, life);
5337c478bd9Sstevel@tonic-gate 		}
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 	if (ssh_request_reply(auth, &msg, &msg) == 0) {
5367c478bd9Sstevel@tonic-gate 		buffer_free(&msg);
5377c478bd9Sstevel@tonic-gate 		return 0;
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 	type = buffer_get_char(&msg);
5407c478bd9Sstevel@tonic-gate 	buffer_free(&msg);
5417c478bd9Sstevel@tonic-gate 	return decode_reply(type);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate int
ssh_add_identity(AuthenticationConnection * auth,Key * key,const char * comment)5457c478bd9Sstevel@tonic-gate ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	return ssh_add_identity_constrained(auth, key, comment, 0);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate  * Removes an identity from the authentication server.  This call is not
5527c478bd9Sstevel@tonic-gate  * meant to be used by normal applications.
5537c478bd9Sstevel@tonic-gate  */
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate int
ssh_remove_identity(AuthenticationConnection * auth,Key * key)5567c478bd9Sstevel@tonic-gate ssh_remove_identity(AuthenticationConnection *auth, Key *key)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate 	Buffer msg;
5597c478bd9Sstevel@tonic-gate 	int type;
5607c478bd9Sstevel@tonic-gate 	u_char *blob;
5617c478bd9Sstevel@tonic-gate 	u_int blen;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	buffer_init(&msg);
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	if (key->type == KEY_RSA1) {
5667c478bd9Sstevel@tonic-gate 		buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
5677c478bd9Sstevel@tonic-gate 		buffer_put_int(&msg, BN_num_bits(key->rsa->n));
5687c478bd9Sstevel@tonic-gate 		buffer_put_bignum(&msg, key->rsa->e);
5697c478bd9Sstevel@tonic-gate 		buffer_put_bignum(&msg, key->rsa->n);
5707c478bd9Sstevel@tonic-gate 	} else if (key->type == KEY_DSA || key->type == KEY_RSA) {
5717c478bd9Sstevel@tonic-gate 		key_to_blob(key, &blob, &blen);
5727c478bd9Sstevel@tonic-gate 		buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
5737c478bd9Sstevel@tonic-gate 		buffer_put_string(&msg, blob, blen);
5747c478bd9Sstevel@tonic-gate 		xfree(blob);
5757c478bd9Sstevel@tonic-gate 	} else {
5767c478bd9Sstevel@tonic-gate 		buffer_free(&msg);
5777c478bd9Sstevel@tonic-gate 		return 0;
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 	if (ssh_request_reply(auth, &msg, &msg) == 0) {
5807c478bd9Sstevel@tonic-gate 		buffer_free(&msg);
5817c478bd9Sstevel@tonic-gate 		return 0;
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 	type = buffer_get_char(&msg);
5847c478bd9Sstevel@tonic-gate 	buffer_free(&msg);
5857c478bd9Sstevel@tonic-gate 	return decode_reply(type);
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate  * Removes all identities from the agent.  This call is not meant to be used
5917c478bd9Sstevel@tonic-gate  * by normal applications.
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate int
ssh_remove_all_identities(AuthenticationConnection * auth,int version)5957c478bd9Sstevel@tonic-gate ssh_remove_all_identities(AuthenticationConnection *auth, int version)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	Buffer msg;
5987c478bd9Sstevel@tonic-gate 	int type;
5997c478bd9Sstevel@tonic-gate 	int code = (version==1) ?
6007c478bd9Sstevel@tonic-gate 		SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
6017c478bd9Sstevel@tonic-gate 		SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	buffer_init(&msg);
6047c478bd9Sstevel@tonic-gate 	buffer_put_char(&msg, code);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	if (ssh_request_reply(auth, &msg, &msg) == 0) {
6077c478bd9Sstevel@tonic-gate 		buffer_free(&msg);
6087c478bd9Sstevel@tonic-gate 		return 0;
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 	type = buffer_get_char(&msg);
6117c478bd9Sstevel@tonic-gate 	buffer_free(&msg);
6127c478bd9Sstevel@tonic-gate 	return decode_reply(type);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate int
decode_reply(int type)6167c478bd9Sstevel@tonic-gate decode_reply(int type)
6177c478bd9Sstevel@tonic-gate {
6187c478bd9Sstevel@tonic-gate 	switch (type) {
6197c478bd9Sstevel@tonic-gate 	case SSH_AGENT_FAILURE:
6207c478bd9Sstevel@tonic-gate 	case SSH_COM_AGENT2_FAILURE:
6217c478bd9Sstevel@tonic-gate 	case SSH2_AGENT_FAILURE:
6227c478bd9Sstevel@tonic-gate 		log("SSH_AGENT_FAILURE");
6237c478bd9Sstevel@tonic-gate 		return 0;
6247c478bd9Sstevel@tonic-gate 	case SSH_AGENT_SUCCESS:
6257c478bd9Sstevel@tonic-gate 		return 1;
6267c478bd9Sstevel@tonic-gate 	default:
6277c478bd9Sstevel@tonic-gate 		fatal("Bad response from authentication agent: %d", type);
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
6307c478bd9Sstevel@tonic-gate 	return 0;
6317c478bd9Sstevel@tonic-gate }
632