コード例 #1
0
ファイル: cli-authinteract.c プロジェクト: jchu/dropbear-ccn
void cli_auth_interactive() {

	TRACE(("enter cli_auth_interactive"))
	CHECKCLEARTOWRITE();

	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);

	/* username */
	buf_putstring(ses.writepayload, cli_opts.username,
			strlen(cli_opts.username));

	/* service name */
	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, 
			SSH_SERVICE_CONNECTION_LEN);

	/* method */
	buf_putstring(ses.writepayload, AUTH_METHOD_INTERACT,
			AUTH_METHOD_INTERACT_LEN);

	/* empty language tag */
	buf_putstring(ses.writepayload, "", 0);

	/* empty submethods */
	buf_putstring(ses.writepayload, "", 0);

	encrypt_packet();
	cli_ses.interact_request_received = 0;

	TRACE(("leave cli_auth_interactive"))

}
コード例 #2
0
ファイル: tcp-accept.c プロジェクト: Einheri/wl500g
static void tcp_acceptor(struct Listener *listener, int sock) {

	int fd;
	struct sockaddr_storage addr;
	socklen_t len;
	char ipstring[NI_MAXHOST], portstring[NI_MAXSERV];
	struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);

	len = sizeof(addr);

	fd = accept(sock, (struct sockaddr*)&addr, &len);
	if (fd < 0) {
		return;
	}

	if (getnameinfo((struct sockaddr*)&addr, len, ipstring, sizeof(ipstring),
				portstring, sizeof(portstring), 
				NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
		m_close(fd);
		return;
	}

	if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) {
		char* addr = NULL;
		unsigned int port = 0;

		if (tcpinfo->tcp_type == direct) {
			/* "direct-tcpip" */
			/* host to connect, port to connect */
			addr = tcpinfo->sendaddr;
			port = tcpinfo->sendport;
		} else {
			dropbear_assert(tcpinfo->tcp_type == forwarded);
			/* "forwarded-tcpip" */
			/* address that was connected, port that was connected */
			addr = tcpinfo->request_listenaddr;
			port = tcpinfo->listenport;
		}

		if (addr == NULL) {
			addr = "localhost";
		}
		buf_putstring(ses.writepayload, addr, strlen(addr));
		buf_putint(ses.writepayload, port);

		/* originator ip */
		buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
		/* originator port */
		buf_putint(ses.writepayload, atol(portstring));

		encrypt_packet();

	} else {
		/* XXX debug? */
		close(fd);
	}
}
コード例 #3
0
ファイル: kex.c プロジェクト: TheTypoMaster/AH4222
/* Send our list of algorithms we can use */
void send_msg_kexinit() {

	CHECKCLEARTOWRITE();
	buf_putbyte(ses.writepayload, SSH_MSG_KEXINIT);

	/* cookie */
	genrandom(buf_getwriteptr(ses.writepayload, 16), 16);
	buf_incrwritepos(ses.writepayload, 16);

	/* kex algos */
	buf_put_algolist(ses.writepayload, sshkex);

	/* server_host_key_algorithms */
	buf_put_algolist(ses.writepayload, sshhostkey);

	/* encryption_algorithms_client_to_server */
	buf_put_algolist(ses.writepayload, sshciphers);

	/* encryption_algorithms_server_to_client */
	buf_put_algolist(ses.writepayload, sshciphers);

	/* mac_algorithms_client_to_server */
	buf_put_algolist(ses.writepayload, sshhashes);

	/* mac_algorithms_server_to_client */
	buf_put_algolist(ses.writepayload, sshhashes);

	/* compression_algorithms_client_to_server */
	buf_put_algolist(ses.writepayload, sshcompress);

	/* compression_algorithms_server_to_client */
	buf_put_algolist(ses.writepayload, sshcompress);

	/* languages_client_to_server */
	buf_putstring(ses.writepayload, "", 0);

	/* languages_server_to_client */
	buf_putstring(ses.writepayload, "", 0);

	/* first_kex_packet_follows - unimplemented for now */
	buf_putbyte(ses.writepayload, 0x00);

	/* reserved unit32 */
	buf_putint(ses.writepayload, 0);

	/* set up transmitted kex packet buffer for hashing. 
	 * This is freed after the end of the kex */
	ses.transkexinit = buf_newcopy(ses.writepayload);

	encrypt_packet();
	ses.dataallowed = 0; /* don't send other packets during kex */

	ses.kexstate.sentkexinit = 1;
}
コード例 #4
0
ファイル: cli-tcpfwd.c プロジェクト: bengardner/dropbear
static void send_msg_global_request_remotetcp(const char *addr, int port) {

	TRACE(("enter send_msg_global_request_remotetcp"))

	CHECKCLEARTOWRITE();
	buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
	buf_putstring(ses.writepayload, "tcpip-forward", 13);
	buf_putbyte(ses.writepayload, 1); /* want_reply */
	buf_putstring(ses.writepayload, addr, strlen(addr));
	buf_putint(ses.writepayload, port);

	encrypt_packet();

	TRACE(("leave send_msg_global_request_remotetcp"))
}
コード例 #5
0
ファイル: channel.c プロジェクト: TheTypoMaster/AH4222
/* Send a channel open failure message, with a corresponding reason
 * code (usually resource shortage or unknown chan type) */
static void send_msg_channel_open_failure(unsigned int remotechan, 
		int reason, const unsigned char *text, const unsigned char *lang) {

	TRACE(("enter send_msg_channel_open_failure"));
	CHECKCLEARTOWRITE();
	
	buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
	buf_putint(ses.writepayload, remotechan);
	buf_putint(ses.writepayload, reason);
	buf_putstring(ses.writepayload, text, strlen((char*)text));
	buf_putstring(ses.writepayload, lang, strlen((char*)lang));

	encrypt_packet();
	TRACE(("leave send_msg_channel_open_failure"));
}
コード例 #6
0
ファイル: channel.c プロジェクト: TheTypoMaster/AH4222
/* Create a new channel, and start the open request. This is intended
 * for X11, agent, tcp forwarding, and should be filled with channel-specific
 * options, with the calling function calling encrypt_packet() after
 * completion. It is mandatory for the caller to encrypt_packet() if
 * DROPBEAR_SUCCESS is returned */
int send_msg_channel_open_init(int fd, const char * typestring) {

	struct Channel* chan;

	chan = newchannel(0, CHANNEL_ID_AGENT, 0, 0);
	if (!chan) {
		return DROPBEAR_FAILURE;
	}

	/* set fd non-blocking */
	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
		return DROPBEAR_FAILURE;
	}

	chan->infd = chan->outfd = fd;
	ses.maxfd = MAX(ses.maxfd, fd);

	/* now open the channel connection */
	CHECKCLEARTOWRITE();

	buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN);
	buf_putstring(ses.writepayload, typestring, strlen(typestring));
	buf_putint(ses.writepayload, chan->index);
	buf_putint(ses.writepayload, RECV_MAXWINDOW);
	buf_putint(ses.writepayload, RECV_MAXPACKET);

	return DROPBEAR_SUCCESS;
}
コード例 #7
0
ファイル: cli-session.c プロジェクト: iquaba/dropbear
static void send_msg_service_request(char* servicename) {

	TRACE(("enter send_msg_service_request: servicename='%s'", servicename))

	CHECKCLEARTOWRITE();

	buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
	buf_putstring(ses.writepayload, servicename, strlen(servicename));

	encrypt_packet();
	TRACE(("leave send_msg_service_request"))
}
コード例 #8
0
ファイル: kex.c プロジェクト: TheTypoMaster/AH4222
/* Executed upon receiving a kexinit message from the client to initiate
 * key exchange. If we haven't already done so, we send the list of our
 * preferred algorithms. The client's requested algorithms are processed,
 * and we calculate the first portion of the key-exchange-hash for used
 * later in the key exchange. No response is sent, as the client should
 * initiate the diffie-hellman key exchange */
void recv_msg_kexinit() {
	
	TRACE(("enter recv_msg_kexinit"));
	
	if (!ses.kexstate.sentkexinit) {
		/* we need to send a kex packet */
		send_msg_kexinit();
		TRACE(("continue recv_msg_kexinit: sent kexinit"));
	}

	/* read the client's choice of algos */
	read_kex();

	/* start the kex hash */
	ses.kexhashbuf = buf_new(MAX_KEXHASHBUF);
	/* V_C, the client's version string (CR and NL excluded) */
	buf_putstring(ses.kexhashbuf, 
			ses.remoteident, strlen((char*)ses.remoteident));
	/* V_S, the server's version string (CR and NL excluded) */
	buf_putstring(ses.kexhashbuf,
			(unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));

	/* I_C, the payload of the client's SSH_MSG_KEXINIT */
	buf_setpos(ses.payload, 0);
	buf_putstring(ses.kexhashbuf,
			buf_getptr(ses.payload, ses.payload->len),
			ses.payload->len);
	/* I_S, the payload of the server's SSH_MSG_KEXINIT */
	buf_putstring(ses.kexhashbuf,
			buf_getptr(ses.transkexinit, ses.transkexinit->len),
			ses.transkexinit->len);
	buf_free(ses.transkexinit);
	ses.transkexinit = NULL;
	/* the rest of ses.kexhashbuf will be done after DH exchange */

	ses.kexstate.recvkexinit = 1;
	ses.expecting = SSH_MSG_KEXDH_INIT;

	TRACE(("leave recv_msg_kexinit"));
}
コード例 #9
0
ファイル: chansession.c プロジェクト: TheTypoMaster/AH4222
/* send the signal causing the exit to the client */
void send_msg_chansess_exitsignal(struct Channel * channel,
		struct ChanSess * chansess) {

	int i;
	char* signame = NULL;

	assert(chansess->exited);
	assert(chansess->exitsignal > 0);

	CHECKCLEARTOWRITE();

	/* we check that we can match a signal name, otherwise
	 * don't send anything */
	i = 0;
	while (signames[i].name != 0) {
		if (signames[i].signal == chansess->exitsignal) {
			signame = signames[i].name;
			break;
		}
		i++;
	}

	if (signame == NULL) {
		return;
	}

	buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
	buf_putint(ses.writepayload, channel->remotechan);
	buf_putstring(ses.writepayload, "exit-signal", 11);
	buf_putbyte(ses.writepayload, 0); /* boolean FALSE */
	buf_putstring(ses.writepayload, signame, strlen(signame));
	buf_putbyte(ses.writepayload, chansess->exitcore);
	buf_putstring(ses.writepayload, "", 0); /* error msg */
	buf_putstring(ses.writepayload, "", 0); /* lang */

	encrypt_packet();
}
コード例 #10
0
static void tcp_acceptor(struct Listener *listener, int sock) {

	int fd;
	struct sockaddr_storage addr;
	int len;
	char ipstring[NI_MAXHOST], portstring[NI_MAXSERV];
	struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);

	len = sizeof(addr);

	fd = accept(sock, (struct sockaddr*)&addr, &len);
	if (fd < 0) {
		return;
	}

	if (getnameinfo((struct sockaddr*)&addr, len, ipstring, sizeof(ipstring),
				portstring, sizeof(portstring), 
				NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
		return;
	}

	if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) {

		buf_putstring(ses.writepayload, tcpinfo->sendaddr, 
				strlen(tcpinfo->sendaddr));
		buf_putint(ses.writepayload, tcpinfo->sendport);
		buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
		buf_putint(ses.writepayload, atol(portstring));

		encrypt_packet();

	} else {
		/* XXX debug? */
		close(fd);
	}
}
コード例 #11
0
ファイル: algo.c プロジェクト: TheTypoMaster/AH4222
/* Output a comma seperated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {

	unsigned int pos = 0, i, len;
	char str[50]; /* enough for local algo storage */

	for (i = 0; localalgos[i].name != NULL; i++) {
		if (localalgos[i].usable) {
			len = strlen(localalgos[i].name);
			memcpy(&str[pos], localalgos[i].name, len);
			pos += len;
			str[pos] = ',';
			pos++;
		}
	}
	buf_putstring(buf, str, pos-1);
}
コード例 #12
0
ファイル: svr-x11fwd.c プロジェクト: WhitePatches/snake-os
static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr) {

	char* ipstring = NULL;

	if (send_msg_channel_open_init(fd, &chan_x11) == DROPBEAR_SUCCESS) {
		ipstring = inet_ntoa(addr->sin_addr);
		buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
		buf_putint(ses.writepayload, addr->sin_port);

		encrypt_packet();
		return DROPBEAR_SUCCESS;
	} else {
		return DROPBEAR_FAILURE;
	}

}
コード例 #13
0
ファイル: cli-kex.c プロジェクト: AllardJ/Tomato
void send_msg_kexdh_init() {
	TRACE(("send_msg_kexdh_init()"))	

	CHECKCLEARTOWRITE();
	buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
	switch (ses.newkeys->algo_kex->mode) {
		case DROPBEAR_KEX_NORMAL_DH:
			if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
				|| !cli_ses.dh_param) {
				if (cli_ses.dh_param) {
					free_kexdh_param(cli_ses.dh_param);
				}
				cli_ses.dh_param = gen_kexdh_param();
			}
			buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
			break;
		case DROPBEAR_KEX_ECDH:
#ifdef DROPBEAR_ECDH
			if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
				|| !cli_ses.ecdh_param) {
				if (cli_ses.ecdh_param) {
					free_kexecdh_param(cli_ses.ecdh_param);
				}
				cli_ses.ecdh_param = gen_kexecdh_param();
			}
			buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
#endif
			break;
#ifdef DROPBEAR_CURVE25519
		case DROPBEAR_KEX_CURVE25519:
			if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
				|| !cli_ses.curve25519_param) {
				if (cli_ses.curve25519_param) {
					free_kexcurve25519_param(cli_ses.curve25519_param);
				}
				cli_ses.curve25519_param = gen_kexcurve25519_param();
			}
			buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
#endif
			break;
	}

	cli_ses.param_kex_algo = ses.newkeys->algo_kex;
	encrypt_packet();
	ses.requirenext[0] = SSH_MSG_KEXDH_REPLY;
	ses.requirenext[1] = SSH_MSG_KEXINIT;
}
コード例 #14
0
ファイル: chansession.c プロジェクト: TheTypoMaster/AH4222
/* send the exitstatus to the client */
void send_msg_chansess_exitstatus(struct Channel * channel,
		struct ChanSess * chansess) {

	assert(chansess->exited);
	assert(chansess->exitsignal == -1);

	CHECKCLEARTOWRITE();

	buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
	buf_putint(ses.writepayload, channel->remotechan);
	buf_putstring(ses.writepayload, "exit-status", 11);
	buf_putbyte(ses.writepayload, 0); /* boolean FALSE */
	buf_putint(ses.writepayload, chansess->exitstatus);

	encrypt_packet();

}
コード例 #15
0
ファイル: common-algo.c プロジェクト: CoffeMug/dropbear
/* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {

	unsigned int i, len;
	unsigned int donefirst = 0;
	buffer *algolist = NULL;

	algolist = buf_new(300);
	for (i = 0; localalgos[i].name != NULL; i++) {
		if (localalgos[i].usable) {
			if (donefirst)
				buf_putbyte(algolist, ',');
			donefirst = 1;
			len = strlen(localalgos[i].name);
			buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
		}
	}
	buf_putstring(buf, (const char*)algolist->data, algolist->len);
	buf_free(algolist);
}
コード例 #16
0
/* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {

	unsigned int pos = 0, i, len;
	char str[50]; /* enough for local algo storage */

	for (i = 0; localalgos[i].name != NULL; i++) {
		if (localalgos[i].usable) {
			/* Avoid generating a trailing comma */
			if (pos)
			    str[pos++] = ',';
			len = strlen(localalgos[i].name);
			memcpy(&str[pos], localalgos[i].name, len);
			pos += len;
		}
	}
	str[pos]=0;
	/* Debug this */
	TRACE(("buf_put_algolist: %s", str))
	buf_putstring(buf, str, pos);
}
コード例 #17
0
ファイル: channel.c プロジェクト: TheTypoMaster/AH4222
/* Reads data from the server's program/shell/etc, and puts it in a
 * channel_data packet to send.
 * chan is the remote channel, isextended is 0 if it is normal data, 1
 * if it is extended data. if it is extended, then the type is in
 * exttype */
static void send_msg_channel_data(struct Channel *channel, int isextended,
		unsigned int exttype) {

	buffer *buf;
	int len;
	unsigned int maxlen;
	int fd;

	TRACE(("enter send_msg_channel_data"));
	TRACE(("extended = %d type = %d", isextended, exttype));

	CHECKCLEARTOWRITE();

	assert(!channel->sentclosed);

	if (isextended) {
		if (channel->erreof) {
			TRACE(("leave send_msg_channel_data: erreof already set"));
			return;
		}
		assert(exttype == SSH_EXTENDED_DATA_STDERR);
		fd = channel->errfd;
	} else {
		if (channel->transeof) {
			TRACE(("leave send_msg_channel_data: transeof already set"));
			return;
		}
		fd = channel->outfd;
	}
	assert(fd >= 0);

	maxlen = MIN(channel->transwindow, channel->transmaxpacket);
	/* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and 
	 * exttype if is extended */
	maxlen = MIN(maxlen, ses.writepayload->size 
			- 1 - 4 - 4 - (isextended ? 4 : 0));
	if (maxlen == 0) {
		TRACE(("leave send_msg_channel_data: no window"));
		return; /* the data will get written later */
	}

	/* read the data */
	buf = buf_new(maxlen);
	len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
	if (len <= 0) {
		/* on error etc, send eof */
		if (errno != EINTR) {
			
			if (isextended) {
				channel->erreof = 1;
			} else {
				channel->transeof = 1;
			}
			
			if ((channel->erreof || channel->errfd == -1)
					&& channel->transeof) {
				send_msg_channel_eof(channel);
			}
		}
		buf_free(buf);
		TRACE(("leave send_msg_channel_data: len <= 0, erreof %d transeof %d",
					channel->erreof, channel->transeof));
		return;
	}
	buf_incrlen(buf, len);

	buf_putbyte(ses.writepayload, 
			isextended ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA);
	buf_putint(ses.writepayload, channel->remotechan);

	if (isextended) {
		buf_putint(ses.writepayload, exttype);
	}

	buf_putstring(ses.writepayload, buf_getptr(buf, len), len);
	buf_free(buf);

	channel->transwindow -= len;

	encrypt_packet();
	TRACE(("leave send_msg_channel_data"));
}
コード例 #18
0
ファイル: buffer.c プロジェクト: CoffeMug/dropbear
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
	buf_putstring(buf, (const char*)buf_str->data, buf_str->len);
}
コード例 #19
0
ファイル: cli-authinteract.c プロジェクト: jchu/dropbear-ccn
void recv_msg_userauth_info_request() {

	unsigned char *name = NULL;
	unsigned char *instruction = NULL;
	unsigned int num_prompts = 0;
	unsigned int i;

	unsigned char *prompt = NULL;
	unsigned int echo = 0;
	unsigned char *response = NULL;

	TRACE(("enter recv_msg_recv_userauth_info_request"))

	/* Let the user know what password/host they are authing for */
	if (!cli_ses.interact_request_received) {
		fprintf(stderr, "Login for %s@%s\n", cli_opts.username,
				//cli_opts.remotehost);
                cli_opts.remote_name_str);
	}
	cli_ses.interact_request_received = 1;

	name = buf_getstring(ses.payload, NULL);
	instruction = buf_getstring(ses.payload, NULL);

	/* language tag */
	buf_eatstring(ses.payload);

	num_prompts = buf_getint(ses.payload);
	
	if (num_prompts >= DROPBEAR_MAX_CLI_INTERACT_PROMPTS) {
		dropbear_exit("Too many prompts received for keyboard-interactive");
	}

	/* we'll build the response as we go */
	CHECKCLEARTOWRITE();
	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_INFO_RESPONSE);
	buf_putint(ses.writepayload, num_prompts);

	if (strlen(name) > 0) {
		cleantext(name);
		fprintf(stderr, "%s", name);
	}
	m_free(name);

	if (strlen(instruction) > 0) {
		cleantext(instruction);
		fprintf(stderr, "%s", instruction);
	}
	m_free(instruction);

	for (i = 0; i < num_prompts; i++) {
		unsigned int response_len = 0;
		prompt = buf_getstring(ses.payload, NULL);
		cleantext(prompt);

		echo = buf_getbool(ses.payload);

		if (!echo) {
			unsigned char* p = getpass_or_cancel(prompt);
			response = m_strdup(p);
			m_burn(p, strlen(p));
		} else {
			response = get_response(prompt);
		}

		response_len = strlen(response);
		buf_putstring(ses.writepayload, response, response_len);
		m_burn(response, response_len);
		m_free(response);
	}

	encrypt_packet();


	TRACE(("leave recv_msg_recv_userauth_info_request"))
}
コード例 #20
0
ファイル: packet_auth.c プロジェクト: LlsDimple/tinyssh
int packet_auth(struct buf *b, struct buf *b2) {

    crypto_uint8 ch, flagsignature;
    long long pos, i, count, sign_bytes = 0;
    crypto_uint32 len;
    const char *pkname;
    int (*sign_open)(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *) = 0;
    int (*parsesignpk)(unsigned char *, const unsigned char *, long long) = 0;
    int (*parsesignature)(unsigned char *, const unsigned char *, long long) = 0;
    void (*putsignpk)(struct buf *, const unsigned char *) = 0;
    void (*putsignpkbase64)(struct buf *, const unsigned char *) = 0;
    unsigned char pk[sshcrypto_sign_PUBLICKEYMAX];
    unsigned char sig[sshcrypto_sign_MAX];
    unsigned long long smlen;

    buf_purge(b);

    /* parse "ssh-userauth" */
    pos = 0;
    if (!packet_getall(b, SSH_MSG_SERVICE_REQUEST)) bug();
    pos = packetparser_uint8(b->buf, b->len, pos, &ch);       /* SSH_MSG_SERVICE_REQUEST */
    if (ch != SSH_MSG_SERVICE_REQUEST) bug_proto();
    pos = packetparser_uint32(b->buf, b->len, pos, &len);     /* "ssh-userauth" */
    if (len != 12) bug_proto();
    pos = packetparser_skip(b->buf, b->len, pos, len);
    if (!byte_isequal(b->buf + pos - len, len, "ssh-userauth")) bug_proto();
    pos = packetparser_end(b->buf, b->len, pos);

    /* send service accept */
    b->buf[0] = SSH_MSG_SERVICE_ACCEPT;
    packet_put(b);
    if (!packet_sendall()) bug();


    for (count = 0; count < 32; ++count) {
        /* receive userauth request */
        pkname = "unknown";
        pos = 0;
        buf_purge(b);
        if (!packet_getall(b, SSH_MSG_USERAUTH_REQUEST)) bug();
        pos = packetparser_uint8(b->buf, b->len, pos, &ch);         /* SSH_MSG_USERAUTH_REQUEST */
        if (ch != SSH_MSG_USERAUTH_REQUEST) bug_proto();
        pos = packetparser_uint32(b->buf, b->len, pos, &len);       /* name */
        if (len >= PACKET_NAMESIZE) bug_proto();
        pos = packetparser_copy(b->buf, b->len, pos, (unsigned char *)packet.name, len);
        packet.name[len] = 0;
        pos = packetparser_uint32(b->buf, b->len, pos, &len);       /* "ssh-connection" */
        if (len != 14) bug_proto();
        pos = packetparser_skip(b->buf, b->len, pos, len);
        if (!byte_isequal(b->buf + pos - len, len, "ssh-connection")) bug_proto();

        pos = packetparser_uint32(b->buf, b->len, pos, &len);       /* publickey/password/hostbased/none */
        pos = packetparser_skip(b->buf, b->len, pos, len);

        if (str_equaln((char *)b->buf + pos - len, len, "none")) pkname = "none";
        if (str_equaln((char *)b->buf + pos - len, len, "password")) pkname = "password";
        if (str_equaln((char *)b->buf + pos - len, len, "hostbased")) pkname = "hostbased";
        if (str_equaln((char *)b->buf + pos - len, len, "publickey")) {
            pos = packetparser_uint8(b->buf, b->len, pos, &flagsignature);

            pos = packetparser_uint32(b->buf, b->len, pos, &len);   /* public key algorithm name */
            pos = packetparser_skip(b->buf, b->len, pos, len);
            if (b->buf[pos] != 0) bug_proto();
            pkname = (char *)b->buf + pos - len; /* XXX */

            sign_open = 0; parsesignpk = 0; putsignpk = 0; putsignpkbase64 = 0; parsesignature = 0; sign_bytes = 0;
            for (i = 0; sshcrypto_keys[i].name; ++i) {
                if (!sshcrypto_keys[i].sign_flagclient) continue;
                if (!str_equaln(pkname, len, sshcrypto_keys[i].name)) continue;
                pkname = sshcrypto_keys[i].name;
                sign_open = sshcrypto_keys[i].sign_open;
                parsesignature = sshcrypto_keys[i].parsesignature;
                parsesignpk = sshcrypto_keys[i].parsesignpk;
                putsignpk = sshcrypto_keys[i].buf_putsignpk;
                putsignpkbase64 = sshcrypto_keys[i].buf_putsignpkbase64;
                sign_bytes = sshcrypto_keys[i].sign_bytes;
                break;
            }
            if (sign_open && parsesignpk && putsignpk && putsignpkbase64 && parsesignature) {
                pos = packetparser_uint32(b->buf, b->len, pos, &len);   /* public key blob */
                pos = packetparser_skip(b->buf, b->len, pos, len);
                if (!parsesignpk(pk, b->buf + pos - len, len)) bug_proto();

                if (!flagsignature) {
                    /* 'publickey' ... without signature */
                    buf_purge(b);
                    buf_putnum8(b, SSH_MSG_USERAUTH_PK_OK);
                    buf_putstring(b, pkname);
                    putsignpk(b, pk);
                    packet_put(b);
                    if (!packet_sendall()) bug();
                    continue;
                }


                /* 'publickey' ... with signature */
                pos = packetparser_uint32(b->buf, b->len, pos, &len);   /* signature blob */
                pos = packetparser_skip(b->buf, b->len, pos, len);
                if (!parsesignature(sig, b->buf + pos - len, len)) bug_proto();
                pos = packetparser_end(b->buf, b->len, pos);
                purge(b->buf + b->len - len - 4, len + 4);
                b->len -= len + 4;


                /* authenticate user - verify signature */
                buf_purge(b2);
                buf_put(b2, sig, sign_bytes);
                buf_putstringlen(b2, packet.sessionid, sshcrypto_hash_bytes);
                buf_put(b2, b->buf, b->len);

                buf_purge(b);
                if (b->alloc <= b2->len) bug_nomem();
                if (sign_open(b->buf, &smlen, b2->buf, b2->len, pk) != 0) { errno = EAUTH; bug(); }
                b->len = smlen; buf_purge(b);

                /* authorize user -  using authorized_keys */
                buf_purge(b);
                putsignpkbase64(b, pk);
                buf_putnum8(b, 0);
                if (subprocess_auth(packet.name, pkname, (char *)b->buf) == 0) goto authorized;
            }
        }

        /* reject */
        log_i5("auth: ", packet.name, ": ", pkname, " rejected");
        buf_purge(b);
        buf_putnum8(b, SSH_MSG_USERAUTH_FAILURE);
        buf_putstring(b,"publickey");
        buf_putnum8(b, 0);
        packet_put(b);
        if (!packet_sendall()) bug();
    }
    log_w1("auth: too many authentication tries");
    return 0;


authorized:
    /* authenticated + authorized */
    log_i5("auth: ", packet.name, ": ", pkname, " accepted");
    buf_purge(b);
    buf_putnum8(b, SSH_MSG_USERAUTH_SUCCESS);
    buf_putstring(b,"ssh-connection");
    packet_put(b);
    if (!packet_sendall()) bug();

    purge(pk, sizeof pk);
    purge(sig, sizeof sig);
    return 1;
}