Esempio n. 1
0
/* Handle channel specific requests, passing off to corresponding handlers
 * such as chansession or x11fwd */
void recv_msg_channel_request() {

	unsigned int chan;
	struct Channel *channel;

	TRACE(("enter recv_msg_channel_request"));
	
	chan = buf_getint(ses.payload);
	channel = getchannel(chan);

	if (channel == NULL) {
		/* disconnect ? */
		dropbear_exit("Unknown channel");
	}


	TRACE(("chan type is %d", channel->type));

	/* handle according to channel type */
	switch (channel->type) {

		case CHANNEL_ID_SESSION:
			TRACE(("continue recv_msg_channel_request: session request"));
			chansessionrequest(channel);
			break;

		default:
			send_msg_channel_failure(channel);
	}

	TRACE(("leave recv_msg_channel_request"));

}
Esempio n. 2
0
/* Retrieve an mp_int from the buffer.
 * Will fail for -ve since they shouldn't be required here.
 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_getmpint(buffer* buf, mp_int* mp) {

	unsigned int len;
	len = buf_getint(buf);
	
	if (len == 0) {
		mp_zero(mp);
		return DROPBEAR_SUCCESS;
	}

	if (len > BUF_MAX_MPINT) {
		return DROPBEAR_FAILURE;
	}

	/* check for negative */
	if (*buf_getptr(buf, 1) & (1 << (CHAR_BIT-1))) {
		return DROPBEAR_FAILURE;
	}

	if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
		return DROPBEAR_FAILURE;
	}

	buf_incrpos(buf, len);
	return DROPBEAR_SUCCESS;
}
Esempio n. 3
0
/* handle the channel EOF event, by closing the channel filedescriptor. The
 * channel isn't closed yet, it is left until the incoming (from the program
 * etc) FD is also EOF */
void recv_msg_channel_eof() {

	unsigned int chan;
	struct Channel * channel;

	TRACE(("enter recv_msg_channel_eof"));

	chan = buf_getint(ses.payload);
	channel = getchannel(chan);

	if (channel == NULL) {
		dropbear_exit("EOF for unknown channel");
	}

	channel->recveof = 1;

	/* we should close the channel */
	if (channel->type == CHANNEL_ID_X11 || channel->type == CHANNEL_ID_AGENT
			|| channel->type == CHANNEL_ID_TCPDIRECT) {
		shutdown(channel->infd, 0);
	} else {
		close(channel->infd);
	}
	channel->infd = -1;

	if (channel->transeof && (channel->erreof || channel->errfd == -1)
			&& !channel->sentclosed) {
		send_msg_channel_close(channel);
	}

	TRACE(("leave recv_msg_channel_eof"));
}
Esempio n. 4
0
/* when we receive channel data, put it in a buffer for writing to the program/
 * shell etc */
void recv_msg_channel_data() {

	unsigned int chan;
	struct Channel * channel;
	unsigned int datalen;
	unsigned int pos;
	unsigned int maxdata;

	TRACE(("enter recv_msg_channel_data"));
	
	chan = buf_getint(ses.payload);
	channel = getchannel(chan);
	if (channel == NULL) {
		/* disconnect ? */
		dropbear_exit("Unknown channel");
	}

	assert(channel->infd != -1);

	datalen = buf_getint(ses.payload);

	/* if the client is going to send us more data than we've allocated, then 
	 * it has ignored the windowsize, so we "MAY ignore all extra data" */
	maxdata = channel->writebuf->size - channel->writebuf->pos;
	if (datalen > maxdata) {
		TRACE(("Warning: recv_msg_channel_data: extra data past window"));
		datalen = maxdata;
	}

	/* write to the buffer - we always append to the end of the buffer */
	pos = channel->writebuf->pos;
	buf_setpos(channel->writebuf, channel->writebuf->len);
	memcpy(buf_getwriteptr(channel->writebuf, datalen), 
			buf_getptr(ses.payload, datalen), datalen);
	buf_incrwritepos(channel->writebuf, datalen);
	buf_setpos(channel->writebuf, pos); /* revert pos */

	channel->recvwindow -= datalen;
/*	if (channel->recvwindow < RECV_MINWINDOW) {
		send_msg_channel_window_adjust(channel, 
				RECV_MAXWINDOW - channel->recvwindow);
		channel->recvwindow = RECV_MAXWINDOW;
	}*/

	TRACE(("leave recv_msg_channel_data"));
}
Esempio n. 5
0
/* Let the process know that the window size has changed, as notified from the
 * client. Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int sessionwinchange(struct ChanSess *chansess) {

	if (chansess->master < 0) {
		/* haven't got a pty yet */
		return DROPBEAR_FAILURE;
	}
			
	chansess->termc = buf_getint(ses.payload);
	chansess->termr = buf_getint(ses.payload);
	chansess->termw = buf_getint(ses.payload);
	chansess->termh = buf_getint(ses.payload);
	
	pty_change_window_size(chansess->master, chansess->termr, chansess->termc,
		chansess->termw, chansess->termh);

	return DROPBEAR_FAILURE;
}
Esempio n. 6
0
static int newtcpforwarded(struct Channel * channel) {

    char *origaddr = NULL;
	unsigned int origport;
	m_list_elem * iter = NULL;
	struct TCPFwdEntry *fwd;
	char portstring[NI_MAXSERV];
	int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;

	origaddr = buf_getstring(ses.payload, NULL);
	origport = buf_getint(ses.payload);

	/* Find which port corresponds. First try and match address as well as port,
	in case they want to forward different ports separately ... */
	for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
		fwd = (struct TCPFwdEntry*)iter->item;
		if (origport == fwd->listenport
				&& strcmp(origaddr, fwd->listenaddr) == 0) {
			break;
		}
	}

	if (!iter)
	{
		/* ... otherwise try to generically match the only forwarded port 
		without address (also handles ::1 vs 127.0.0.1 vs localhost case).
		rfc4254 is vague about the definition of "address that was connected" */
		for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
			fwd = (struct TCPFwdEntry*)iter->item;
			if (origport == fwd->listenport) {
				break;
			}
		}
	}


	if (iter == NULL) {
		/* We didn't request forwarding on that port */
        	cleantext(origaddr);
		dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"", 
                origaddr, origport);
		goto out;
	}
	
	snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
	channel->conn_pending = connect_remote(AF_UNSPEC, fwd->connectaddr,
					portstring, channel_connect_done, channel);

	channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
	
	err = SSH_OPEN_IN_PROGRESS;

out:
	m_free(origaddr);
	TRACE(("leave newtcpdirect: err %d", err))
	return err;
}
Esempio n. 7
0
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int x11req(struct ChanSess * chansess) {

	int fd;

	if (!svr_pubkey_allows_x11fwd()) {
		return DROPBEAR_FAILURE;
	}

	/* we already have an x11 connection */
	if (chansess->x11listener != NULL) {
		return DROPBEAR_FAILURE;
	}

	chansess->x11singleconn = buf_getbool(ses.payload);
	chansess->x11authprot = buf_getstring(ses.payload, NULL);
	chansess->x11authcookie = buf_getstring(ses.payload, NULL);
	chansess->x11screennum = buf_getint(ses.payload);

	/* create listening socket */
	fd = socket(PF_INET, SOCK_STREAM, 0);
	if (fd < 0) {
		goto fail;
	}

	/* allocate port and bind */
	chansess->x11port = bindport(fd);
	if (chansess->x11port < 0) {
		goto fail;
	}

	/* listen */
	if (listen(fd, 20) < 0) {
		goto fail;
	}

	/* set non-blocking */
	setnonblocking(fd);

	/* listener code will handle the socket now.
	 * No cleanup handler needed, since listener_remove only happens
	 * from our cleanup anyway */
	chansess->x11listener = new_listener( &fd, 1, 0, chansess, x11accept, NULL);
	if (chansess->x11listener == NULL) {
		goto fail;
	}

	return DROPBEAR_SUCCESS;

fail:
	/* cleanup */
	m_free(chansess->x11authprot);
	m_free(chansess->x11authcookie);
	close(fd);

	return DROPBEAR_FAILURE;
}
Esempio n. 8
0
/* Confirmation that our channel open request (for forwardings) was 
 * successful*/
void recv_msg_channel_open_confirmation() {

	unsigned int chan;
	struct Channel * channel;

	TRACE(("enter recv_msg_channel_open_confirmation"));
	chan = buf_getint(ses.payload);

	channel = getchannel(chan);
	if (channel == NULL) {
		dropbear_exit("Unknown channel");
	}

	channel->remotechan =  buf_getint(ses.payload);
	channel->transwindow = buf_getint(ses.payload);
	channel->transmaxpacket = buf_getint(ses.payload);

	TRACE(("leave recv_msg_channel_open_confirmation"));
}
/* Handle a diffie-hellman key exchange reply. */
void recv_msg_kexdh_reply() {

	DEF_MP_INT(dh_f);
	sign_key *hostkey = NULL;
	unsigned int type, keybloblen;
	unsigned char* keyblob = NULL;


	TRACE(("enter recv_msg_kexdh_reply"))

	if (cli_ses.kex_state != KEXDH_INIT_SENT) {
		dropbear_exit("Received out-of-order kexdhreply");
	}
	m_mp_init(&dh_f);
	type = ses.newkeys->algo_hostkey;
	TRACE(("type is %d", type))

	hostkey = new_sign_key();
	keybloblen = buf_getint(ses.payload);

	keyblob = buf_getptr(ses.payload, keybloblen);
	if (!ses.kexstate.donefirstkex) {
		/* Only makes sense the first time */
		checkhostkey(keyblob, keybloblen);
	}

	if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
		TRACE(("failed getting pubkey"))
		dropbear_exit("Bad KEX packet");
	}

	if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
		TRACE(("failed getting mpint"))
		dropbear_exit("Bad KEX packet");
	}

	kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
	mp_clear(&dh_f);
	mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
	m_free(cli_ses.dh_e);
	m_free(cli_ses.dh_x);

	if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) 
			!= DROPBEAR_SUCCESS) {
		dropbear_exit("Bad hostkey signature");
	}

	sign_key_free(hostkey);
	hostkey = NULL;

	send_msg_newkeys();
	ses.requirenext = SSH_MSG_NEWKEYS;
	TRACE(("leave recv_msg_kexdh_init"))
}
Esempio n. 10
0
/* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) {
	buffer *ret = NULL;
	unsigned int len = buf_getint(buf);
	if (len > MAX_STRING_LEN) {
		dropbear_exit("String too long");
	}
	ret = buf_new(len);
	memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
	buf_incrpos(buf, len);
	buf_incrlen(ret, len);
	return ret;
}
Esempio n. 11
0
/* Increment the outgoing data window for a channel - the remote end limits
 * the amount of data which may be transmitted, this window is decremented
 * as data is sent, and incremented upon receiving window-adjust messages */
void recv_msg_channel_window_adjust() {

	unsigned int chan;
	struct Channel * channel;
	unsigned int incr;
	
	chan = buf_getint(ses.payload);
	channel = getchannel(chan);

	if (channel == NULL) {
		dropbear_exit("Unknown channel"); /* TODO - disconnect */
	}
	
	incr = buf_getint(ses.payload);
	TRACE(("received window increment %d", incr));
	incr = MIN(incr, MAX_TRANS_WIN_INCR);
	
	channel->transwindow += incr;
	channel->transwindow = MIN(channel->transwindow, MAX_TRANS_WINDOW);

}
Esempio n. 12
0
static int newtcpforwarded(struct Channel * channel) {

    char *origaddr = NULL;
	unsigned int origport;
	m_list_elem * iter = NULL;
	struct TCPFwdEntry *fwd;
	char portstring[NI_MAXSERV];
	int sock;
	int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;

	origaddr = buf_getstring(ses.payload, NULL);
	origport = buf_getint(ses.payload);

	/* Find which port corresponds */
	for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
		fwd = (struct TCPFwdEntry*)iter->item;
		if (origport == fwd->listenport
				&& (strcmp(origaddr, fwd->listenaddr) == 0)) {
			break;
		}
	}

	if (iter == NULL) {
		/* We didn't request forwarding on that port */
        cleantext(origaddr);
		dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"", 
                origaddr, origport);
		goto out;
	}
	
	snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
	sock = connect_remote(AF_UNSPEC, fwd->connectaddr, portstring, 1, NULL);
	if (sock < 0) {
		TRACE(("leave newtcpdirect: sock failed"))
		err = SSH_OPEN_CONNECT_FAILED;
		goto out;
	}

	ses.maxfd = MAX(ses.maxfd, sock);

	/* We don't set readfd, that will get set after the connection's
	 * progress succeeds */
	channel->writefd = sock;
	channel->initconn = 1;
	
	err = SSH_OPEN_IN_PROGRESS;

out:
	m_free(origaddr);
	TRACE(("leave newtcpdirect: err %d", err))
	return err;
}
Esempio n. 13
0
static void cli_chansessreq(struct Channel *channel) {

	unsigned char* type = NULL;
	int wantreply;

	TRACE(("enter cli_chansessreq"))

	type = buf_getstring(ses.payload, NULL);
	wantreply = buf_getbool(ses.payload);

	if (strcmp(type, "exit-status") == 0) {
		cli_ses.retval = buf_getint(ses.payload);
		TRACE(("got exit-status of '%d'", cli_ses.retval))
	} else if (strcmp(type, "exit-signal") == 0) {
Esempio n. 14
0
/* Return a null-terminated string, it is malloced, so must be free()ed
 * Note that the string isn't checked for null bytes, hence the retlen
 * may be longer than what is returned by strlen */
char* buf_getstring(buffer* buf, unsigned int *retlen) {

	unsigned int len;
	char* ret;
	len = buf_getint(buf);
	if (len > MAX_STRING_LEN) {
		dropbear_exit("String too long");
	}

	if (retlen != NULL) {
		*retlen = len;
	}
	ret = m_malloc(len+1);
	memcpy(ret, buf_getptr(buf, len), len);
	buf_incrpos(buf, len);
	ret[len] = '\0';

	return ret;
}
Esempio n. 15
0
/* The only global success/failure messages are for remotetcp.
 * Since there isn't any identifier in these messages, we have to rely on them
 * being in the same order as we sent the requests. This is the ordering
 * of the cli_opts.remotefwds list.
 * If the requested remote port is 0 the listen port will be
 * dynamically allocated by the server and the port number will be returned
 * to client and the port number reported to the user. */
void cli_recv_msg_request_success() {
	/* We just mark off that we have received the reply,
	 * so that we can report failure for later ones. */
	m_list_elem * iter = NULL;
	for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
		struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
		if (!fwd->have_reply) {
			fwd->have_reply = 1;
			if (fwd->listenport == 0) {
				/* The server should let us know which port was allocated if we requestd port 0 */
				int allocport = buf_getint(ses.payload);
				if (allocport > 0) {
					dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d", 
							allocport, fwd->connectaddr, fwd->connectport);
				}
			}
			return;
		}
	}
}
Esempio n. 16
0
/* Handle channel closure(), respond in kind and close the channels */
void recv_msg_channel_close() {

	unsigned int chan;
	struct Channel * channel;

	TRACE(("enter recv_msg_channel_close"));

	chan = buf_getint(ses.payload);
	TRACE(("close channel = %d", chan));
	channel = getchannel(chan);

	if (channel == NULL) {
		/* disconnect ? */
		dropbear_exit("Close for unknown channel");
	}

	if (!channel->sentclosed) {
		send_msg_channel_close(channel);
	}

	closechannel(channel);
	
	TRACE(("leave recv_msg_channel_close"));
}
Esempio n. 17
0
/* Function used to read the initial portion of a packet, and determine the
 * length. Only called during the first BLOCKSIZE of a packet. */
static void read_packet_init() {

	unsigned int maxlen;
	int len;
	unsigned char blocksize;
	unsigned char macsize;


	blocksize = ses.keys->recv_algo_crypt->blocksize;
	macsize = ses.keys->recv_algo_mac->hashsize;

	if (ses.readbuf == NULL) {
		/* start of a new packet */
		ses.readbuf = buf_new(INIT_READBUF);
		assert(ses.decryptreadbuf == NULL);
		ses.decryptreadbuf = buf_new(blocksize);
	}

	maxlen = blocksize - ses.readbuf->pos;
			
	/* read the rest of the packet if possible */
	len = read(ses.sock, buf_getwriteptr(ses.readbuf, maxlen),
			maxlen);
	if (len == 0) {
		dropbear_close("remote host closed connection");
	}
	if (len < 0) {
		if (errno == EINTR) {
			TRACE(("leave read_packet_init: EINTR"));
			return;
		}
		dropbear_exit("error reading");
	}

	buf_incrwritepos(ses.readbuf, len);

	if ((unsigned int)len != maxlen) {
		/* don't have enough bytes to determine length, get next time */
		return;
	}

	/* now we have the first block, need to get packet length, so we decrypt
	 * the first block (only need first 4 bytes) */
	buf_setpos(ses.readbuf, 0);
	if (ses.keys->recv_algo_crypt->cipherdesc == NULL) {
		/* copy it */
		memcpy(buf_getwriteptr(ses.decryptreadbuf, blocksize),
				buf_getptr(ses.readbuf, blocksize),
				blocksize);
	} else {
		/* decrypt it */
		if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize), 
					buf_getwriteptr(ses.decryptreadbuf,blocksize),
					&ses.keys->recv_symmetric_struct) != CRYPT_OK) {
			dropbear_exit("error decrypting");
		}
	}
	buf_setlen(ses.decryptreadbuf, blocksize);
	len = buf_getint(ses.decryptreadbuf) + 4 + macsize;

	buf_setpos(ses.readbuf, blocksize);

	/* check packet length */
	if ((len > MAX_PACKET_LEN) ||
		(len < MIN_PACKET_LEN + macsize) ||
		((len - macsize) % blocksize != 0)) {
		dropbear_exit("bad packet size");
	}

	buf_resize(ses.readbuf, len);
	buf_setlen(ses.readbuf, len);

}
Esempio n. 18
0
/* read the client's choice of algorithms */
static void read_kex() {

	algo_type * algo;
	unsigned char* str;
	char * erralgo = NULL;

	buf_incrpos(ses.payload, 16); /* start after the cookie */

	ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));

	/* kex_algorithms */
	algo = buf_match_algo(ses.payload, sshkex);
	if (algo == NULL) {
		erralgo = "kex";
		goto error;
	}
	ses.newkeys->algo_kex = algo->val;

	/* server_host_key_algorithms */
	algo = buf_match_algo(ses.payload, sshhostkey);
	if (algo == NULL) {
		erralgo = "hostkey";
		goto error;
	}
	ses.newkeys->algo_hostkey = algo->val;

	/* encryption_algorithms_client_to_server */
	algo = buf_match_algo(ses.payload, sshciphers);
	if (algo == NULL) {
		erralgo = "enc c->s";
		goto error;
	}
	ses.newkeys->recv_algo_crypt = (struct dropbear_cipher*)algo->data;

	/* encryption_algorithms_server_to_client */
	algo = buf_match_algo(ses.payload, sshciphers);
	if (algo == NULL) {
		erralgo = "enc s->c";
		goto error;
	}
	ses.newkeys->trans_algo_crypt = (struct dropbear_cipher*)algo->data;

	/* mac_algorithms_client_to_server */
	algo = buf_match_algo(ses.payload, sshhashes);
	if (algo == NULL) {
		erralgo = "mac c->s";
		goto error;
	}
	ses.newkeys->recv_algo_mac = (struct dropbear_hash*)algo->data;

	/* mac_algorithms_server_to_client */
	algo = buf_match_algo(ses.payload, sshhashes);
	if (algo == NULL) {
		erralgo = "mac s->c";
		goto error;
	}
	ses.newkeys->trans_algo_mac = (struct dropbear_hash*)algo->data;

	/* compression_algorithms_client_to_server */
	algo = buf_match_algo(ses.payload, sshcompress);
	if (algo == NULL) {
		erralgo = "comp c->s";
		goto error;
	}
	ses.newkeys->recv_algo_comp = algo->val;

	/* compression_algorithms_server_to_client */
	algo = buf_match_algo(ses.payload, sshcompress);
	if (algo == NULL) {
		erralgo = "comp s->c";
		goto error;
	}
	ses.newkeys->trans_algo_comp = algo->val;

	/* languages_client_to_server */
	str = buf_getstring(ses.payload, NULL);
	m_free(str);

	/* languages_server_to_client */
	str = buf_getstring(ses.payload, NULL);
	m_free(str);

	/* first_kex_packet_follows */
	if (buf_getbyte(ses.payload)) {
		ses.kexstate.firstfollows = 1;
		/* XXX currently not handled */
	}

	/* reserved for future extensions */
	buf_getint(ses.payload);

	return;

error:
	dropbear_exit("no matching algo %s", erralgo);

}
Esempio n. 19
0
/* Handle a new channel request, performing any channel-type-specific setup */
void recv_msg_channel_open() {

	unsigned char* type;
	unsigned int typelen;
	unsigned int typeval;
	unsigned int remotechan, transwindow, transmaxpacket;
	struct Channel* channel;
	unsigned int errtype = SSH_OPEN_UNKNOWN_CHANNEL_TYPE;


	TRACE(("enter recv_msg_channel_open"));

	/* get the packet contents */
	type = buf_getstring(ses.payload, &typelen);

	remotechan = buf_getint(ses.payload);
	transwindow = buf_getint(ses.payload);
	transwindow = MIN(transwindow, MAX_TRANS_WINDOW);
	transmaxpacket = buf_getint(ses.payload);
	transmaxpacket = MIN(transmaxpacket, MAX_TRANS_PAYLOAD_LEN);

	/* figure what type of packet it is */
	if (typelen > MAX_NAME_LEN) {
		goto failure;
	}
	if (strcmp(type, "session") == 0) {
		typeval = CHANNEL_ID_SESSION;
#ifndef DISABLE_LOCALTCPFWD
	} else if (strcmp(type, "direct-tcpip") == 0) {
		typeval = CHANNEL_ID_TCPDIRECT;
#endif
	} else {
		goto failure;
	}

	/* create the channel */
	channel = newchannel(remotechan, typeval, transwindow, transmaxpacket);

	if (channel == NULL) {
		errtype = SSH_OPEN_RESOURCE_SHORTAGE;
		goto failure;
	}
	
	/* type specific initialisation */
	if (typeval == CHANNEL_ID_SESSION) {
		newchansess(channel);
#ifndef DISABLE_LOCALTCPFWD
	} else if (typeval == CHANNEL_ID_TCPDIRECT) {
		if (newtcpdirect(channel) == DROPBEAR_FAILURE) {
			deletechannel(channel);
			goto failure;
		}
#endif
	}

	/* success */
	send_msg_channel_open_confirmation(channel, channel->recvwindow,
			channel->recvmaxpacket);
	goto cleanup;

failure:
	send_msg_channel_open_failure(remotechan, errtype, "", "");

cleanup:
	m_free(type);

	TRACE(("leave recv_msg_channel_open"));
}
Esempio n. 20
0
/* Just increment the buffer position the same as if we'd used buf_getstring,
 * but don't bother copying/malloc()ing for it */
void buf_eatstring(buffer *buf) {

	buf_incrpos( buf, buf_getint(buf) );
}
Esempio n. 21
0
/* Handle a diffie-hellman key exchange reply. */
void recv_msg_kexdh_reply() {

	sign_key *hostkey = NULL;
	unsigned int type, keybloblen;
	unsigned char* keyblob = NULL;

	TRACE(("enter recv_msg_kexdh_reply"))

	if (cli_ses.kex_state != KEXDH_INIT_SENT) {
		dropbear_exit("Received out-of-order kexdhreply");
	}
	type = ses.newkeys->algo_hostkey;
	TRACE(("type is %d", type))

	hostkey = new_sign_key();
	keybloblen = buf_getint(ses.payload);

	keyblob = buf_getptr(ses.payload, keybloblen);
	if (!ses.kexstate.donefirstkex) {
		/* Only makes sense the first time */
		checkhostkey(keyblob, keybloblen);
	}

	if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
		TRACE(("failed getting pubkey"))
		dropbear_exit("Bad KEX packet");
	}

	switch (ses.newkeys->algo_kex->mode) {
		case DROPBEAR_KEX_NORMAL_DH:
			{
			DEF_MP_INT(dh_f);
			m_mp_init(&dh_f);
			if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
				TRACE(("failed getting mpint"))
				dropbear_exit("Bad KEX packet");
			}

			kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
			mp_clear(&dh_f);
			}
			break;
		case DROPBEAR_KEX_ECDH:
#ifdef DROPBEAR_ECDH
			{
			buffer *ecdh_qs = buf_getstringbuf(ses.payload);
			kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
			buf_free(ecdh_qs);
			}
#endif
			break;
#ifdef DROPBEAR_CURVE25519
		case DROPBEAR_KEX_CURVE25519:
			{
			buffer *ecdh_qs = buf_getstringbuf(ses.payload);
			kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey);
			buf_free(ecdh_qs);
			}
#endif
			break;
	}

	if (cli_ses.dh_param) {
		free_kexdh_param(cli_ses.dh_param);
		cli_ses.dh_param = NULL;
	}
#ifdef DROPBEAR_ECDH
	if (cli_ses.ecdh_param) {
		free_kexecdh_param(cli_ses.ecdh_param);
		cli_ses.ecdh_param = NULL;
	}
#endif
#ifdef DROPBEAR_CURVE25519
	if (cli_ses.curve25519_param) {
		free_kexcurve25519_param(cli_ses.curve25519_param);
		cli_ses.curve25519_param = NULL;
	}
#endif

	cli_ses.param_kex_algo = NULL;
	if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
		dropbear_exit("Bad hostkey signature");
	}

	sign_key_free(hostkey);
	hostkey = NULL;

	send_msg_newkeys();
	ses.requirenext[0] = SSH_MSG_NEWKEYS;
	ses.requirenext[1] = 0;
	TRACE(("leave recv_msg_kexdh_init"))
}
Esempio n. 22
0
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"))
}
Esempio n. 23
0
/* Set up a session pty which will be used to execute the shell or program.
 * The pty is allocated now, and kept for when the shell/program executes.
 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int sessionpty(struct ChanSess * chansess) {

	unsigned int termlen;
	unsigned char namebuf[65];
	struct termios termio;

	TRACE(("enter sessionpty"));
	chansess->term = buf_getstring(ses.payload, &termlen);
	if (termlen > MAX_TERM_LEN) {
		/* TODO send disconnect ? */
		TRACE(("leave sessionpty: term len too long"));
		return DROPBEAR_FAILURE;
	}
	chansess->termc = buf_getint(ses.payload);
	chansess->termr = buf_getint(ses.payload);
	chansess->termw = buf_getint(ses.payload);
	chansess->termh = buf_getint(ses.payload);

	/* allocate the pty */
	assert(chansess->master == -1); /* haven't already got one */
	if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) {
		TRACE(("leave sessionpty: failed to allocate pty"));
		return DROPBEAR_FAILURE;
	}
	
	chansess->tty = (char*)strdup(namebuf);
	if (!chansess->tty) {
		dropbear_exit("out of memory"); /* TODO disconnect */
	}

	pty_setowner(ses.authstate.pw, chansess->tty);
	pty_change_window_size(chansess->master, chansess->termr, chansess->termc,
			chansess->termw, chansess->termh);

	/* Term modes */
	/* We'll ignore errors and continue if we can't set modes.
	 * We're ignoring baud rates since they seem evil */
	if (tcgetattr(chansess->master, &termio) == 0) {
		unsigned char opcode;
		unsigned int value;
		const struct TermCode * termcode;

		while (((opcode = buf_getbyte(ses.payload)) != 0x00) &&
				opcode <= 159) {
			/* handle types of code */
			if (opcode > MAX_TERMCODE) {
				continue;
			}
			termcode = &termcodes[(unsigned int)opcode];
			
			value = buf_getint(ses.payload);

			switch (termcode->type) {

				case TERMCODE_NONE:
					break;

				case TERMCODE_CONTROLCHAR:
					termio.c_cc[termcode->mapcode] = value;
					break;

				case TERMCODE_INPUT:
					if (value) {
						termio.c_iflag |= termcode->mapcode;
					} else {
						termio.c_iflag &= ~(termcode->mapcode);
					}
					break;

				case TERMCODE_OUTPUT:
					if (value) {
						termio.c_oflag |= termcode->mapcode;
					} else {
						termio.c_oflag &= ~(termcode->mapcode);
					}
					break;

				case TERMCODE_LOCAL:
					if (value) {
						termio.c_lflag |= termcode->mapcode;
					} else {
						termio.c_lflag &= ~(termcode->mapcode);
					}
					break;

				case TERMCODE_CONTROL:
					if (value) {
						termio.c_cflag |= termcode->mapcode;
					} else {
						termio.c_cflag &= ~(termcode->mapcode);
					}
					break;
					
			}
		}
		if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) {
			dropbear_log(LOG_INFO, "error setting terminal attributes");
		}
	}

	TRACE(("leave sessionpty"));
	return DROPBEAR_SUCCESS;
}