Beispiel #1
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;
}
Beispiel #2
0
/* Send a signal to a session's process as requested by the client*/
static int sessionsignal(struct ChanSess *chansess) {

	int sig = 0;
	unsigned char* signame;
	int i;

	if (chansess->pid == 0) {
		/* haven't got a process pid yet */
		return DROPBEAR_FAILURE;
	}

	signame = buf_getstring(ses.payload, NULL);

	i = 0;
	while (signames[i].name != 0) {
		if (strcmp(signames[i].name, signame) == 0) {
			sig = signames[i].signal;
			break;
		}
		i++;
	}

	m_free(signame);

	if (sig == 0) {
		/* failed */
		return DROPBEAR_FAILURE;
	}
			
	if (kill(chansess->pid, sig) < 0) {
		return DROPBEAR_FAILURE;
	} 

	return DROPBEAR_SUCCESS;
}
Beispiel #3
0
/* Handle a command request from the client. This is used for both shell
 * and command-execution requests, and passes the command to
 * noptycommand or ptycommand as appropriate.
 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
		char iscmd) {

	unsigned int cmdlen;

	TRACE(("enter sessioncommand"));

	if (chansess->cmd != NULL) {
		/* TODO - send error - multiple commands? */
		return DROPBEAR_FAILURE;
	}

	if (iscmd) {
		/* "exec" */
		chansess->cmd = buf_getstring(ses.payload, &cmdlen);

		if (cmdlen > MAX_CMD_LEN) {
			/* TODO - send error - too long ? */
			return DROPBEAR_FAILURE;
		}
	}

	if (chansess->term == NULL) {
		/* no pty */
		return noptycommand(channel, chansess);
	} else {
		/* want pty */
		 return ptycommand(channel, chansess);
	}
}
Beispiel #4
0
/* Handle requests for a channel. These can be execution requests,
 * or x11/authagent forwarding. These are passed to appropriate handlers */
void chansessionrequest(struct Channel *channel) {

	unsigned char * type;
	unsigned int typelen;
	unsigned char wantreply;
	int ret = 1;
	struct ChanSess *chansess;

	TRACE(("enter chansessionrequest"));

	assert(channel->type == CHANNEL_ID_SESSION);

	type = buf_getstring(ses.payload, &typelen);
	wantreply = buf_getbyte(ses.payload);

	if (typelen > MAX_NAME_LEN) {
		send_msg_channel_failure(channel);
		m_free(type);
		TRACE(("leave chansessionrequest: type too long")); /* XXX send error?*/
		return;
	}

	chansess = (struct ChanSess*)channel->typedata;
	assert(chansess != NULL);
	TRACE(("type is %s\n", type));

	if (strcmp(type, "window-change") == 0) {
		ret = sessionwinchange(chansess);
	} else if (strcmp(type, "shell") == 0) {
		ret = sessioncommand(channel, chansess, 0);
	} else if (strcmp(type, "pty-req") == 0) {
		ret = sessionpty(chansess);
	} else if (strcmp(type, "exec") == 0) {
		ret = sessioncommand(channel, chansess, 1);
#ifndef DISABLE_X11FWD
	} else if (strcmp(type, "x11-req") == 0) {
		ret = x11req(chansess);
#endif
#ifndef DISABLE_AGENTFWD
	} else if (strcmp(type, "*****@*****.**") == 0) {
		ret = agentreq(chansess);
#endif
	} else if (strcmp(type, "signal") == 0) {
		ret = sessionsignal(chansess);
	} else {
		/* etc, todo "env", "subsystem" */
	}

	if (wantreply) {
		if (ret == 0) {
			send_msg_channel_success(channel);
		} else {
			send_msg_channel_failure(channel);
		}
	}

	m_free(type);
	TRACE(("leave chansessionrequest"));
}
Beispiel #5
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;
}
Beispiel #6
0
/* Process a password auth request, sending success or failure messages as
 * appropriate */
void svr_auth_password() {
	
	char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
	char * testcrypt = NULL; /* crypt generated from the user's password sent */
	unsigned char * password;
	unsigned int passwordlen;

	unsigned int changepw;

	passwdcrypt = ses.authstate.pw_passwd;

#ifdef DEBUG_HACKCRYPT
	/* debugging crypt for non-root testing with shadows */
	passwdcrypt = DEBUG_HACKCRYPT;
#endif

	/* check if client wants to change password */
	changepw = buf_getbool(ses.payload);
	if (changepw) {
		/* not implemented by this server */
		send_msg_userauth_failure(0, 1);
		return;
	}

	password = buf_getstring(ses.payload, &passwordlen);

	/* the first bytes of passwdcrypt are the salt */
	testcrypt = crypt((char*)password, passwdcrypt);
	m_burn(password, passwordlen);
	m_free(password);

	/* check for empty password */
	if (passwdcrypt[0] == '\0') {
		dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
				ses.authstate.pw_name);
		send_msg_userauth_failure(0, 1);
		return;
	}

	if (strcmp(testcrypt, passwdcrypt) == 0) {
		/* successful authentication */
		dropbear_log(LOG_NOTICE, 
				"Password auth succeeded for '%s' from %s",
				ses.authstate.pw_name,
				svr_ses.addrstring);
		send_msg_userauth_success();
	} else {
		dropbear_log(LOG_WARNING,
				"Bad password attempt for '%s' from %s",
				ses.authstate.pw_name,
				svr_ses.addrstring);
		send_msg_userauth_failure(0, 1);
	}
}
Beispiel #7
0
/* match the first algorithm in the comma-seperated list in buf which is
 * also in localalgos[], or return NULL on failure. */
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[]) {

	unsigned char * algolist = NULL;
	unsigned char * remotealgos[MAX_PROPOSED_ALGO];
	unsigned int len;
	unsigned int count, i, j;
	algo_type * ret = NULL;

	/* get the comma-seperated list from the buffer ie "algo1,algo2,algo3" */
	algolist = buf_getstring(buf, &len);
	if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
		goto out; /* just a sanity check, no other use */
	}

	/* remotealgos will contain a list of the strings parsed out */
	/* We will have at least one string (even if it's just "") */
	remotealgos[0] = algolist;
	count = 1;
	/* Iterate through, replacing ','s with NULs, to split it into
	 * words. */
	for (i = 0; i < len; i++) {
		if (algolist[i] == '\0') {
			/* someone is trying something strange */
			goto out;
		}
		if (algolist[i] == ',' && i != len) {
			algolist[i] = '\0';
			remotealgos[count] = &algolist[i+1];
			count++;
		}
		if (count == MAX_PROPOSED_ALGO) {
			break;
		}
	}

	/* iterate and find the first match */
	for (i = 0; i < count; i++) {
		len = strlen(remotealgos[i]);
		for (j = 0; localalgos[j].name != NULL; j++) {
			if (!localalgos[j].usable) {
				continue;
			}
			if (len == strlen(localalgos[j].name) 
					&& strcmp(localalgos[j].name, remotealgos[i]) == 0) {
				ret = &localalgos[j];
				goto out;
			}
		}
	}

out:
	m_free(algolist);
	return ret;
}
Beispiel #8
0
/* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) {
	buffer *ret;
	unsigned char* str;
	unsigned int len;
	str = buf_getstring(buf, &len);
	ret = m_malloc(sizeof(*ret));
	ret->data = str;
	ret->len = len;
	ret->size = len;
	ret->pos = 0;
	return ret;
}
Beispiel #9
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;
}
Beispiel #10
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) {
/* processes a SSH_MSG_SERVICE_REQUEST, returning 0 if finished,
 * 1 if not */
void recv_msg_service_request() {

	unsigned char * name;
	unsigned int len;

	TRACE(("enter recv_msg_service_request"))

	name = buf_getstring(ses.payload, &len);

	/* ssh-userauth */
	if (len == SSH_SERVICE_USERAUTH_LEN && 
			strncmp(SSH_SERVICE_USERAUTH, name, len) == 0) {

		send_msg_service_accept(name, len);
		m_free(name);
		TRACE(("leave recv_msg_service_request: done ssh-userauth"))
		return;
	}
/* This just sets up the state variables right for the main client session loop
 * to deal with */
void recv_msg_service_accept() {

	unsigned char* servicename;
	unsigned int len;

	TRACE(("enter recv_msg_service_accept"))

	servicename = buf_getstring(ses.payload, &len);

	/* ssh-userauth */
	if (cli_ses.state == SERVICE_AUTH_REQ_SENT
			&& len == SSH_SERVICE_USERAUTH_LEN
			&& strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {

		cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
		m_free(servicename);
		TRACE(("leave recv_msg_service_accept: done ssh-userauth"))
		return;
	}
Beispiel #13
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"))
}
/* Process a password auth request, sending success or failure messages as
 * appropriate */
void svr_auth_password() {
	
#ifdef HAVE_SHADOW_H
	struct spwd *spasswd = NULL;
#endif
	char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
	char * testcrypt = NULL; /* crypt generated from the user's password sent */
	unsigned char * password;
	unsigned int passwordlen;
	int passwd_cmp;
	unsigned int changepw;

	passwdcrypt = ses.authstate.pw_passwd;
#ifdef HAVE_SHADOW_H
	/* get the shadow password if possible */
	spasswd = getspnam(ses.authstate.pw_name);
	if (spasswd != NULL && spasswd->sp_pwdp != NULL) {
		passwdcrypt = spasswd->sp_pwdp;
	}
#endif

#ifdef DEBUG_HACKCRYPT
	/* debugging crypt for non-root testing with shadows */
	passwdcrypt = DEBUG_HACKCRYPT;
#endif

	/* check for empty password - need to do this again here
	 * since the shadow password may differ to that tested
	 * in auth.c */
	if (passwdcrypt[0] == '\0' && !svr_opts.noauthpass &&
		!(svr_opts.norootpass && ses.authstate.pw_uid == 0) )
	{
		dropbear_log(LOG_WARNING, "%s: User '%s' has blank password, rejected",
				__FUNCTION__,
				ses.authstate.pw_name);
		send_msg_userauth_failure(0, 1);
		return;
	}

	/* check if client wants to change password */
	changepw = buf_getbool(ses.payload);
	if (changepw) {
		/* not implemented by this server */
		send_msg_userauth_failure(0, 1);
		return;
	}

	password = buf_getstring(ses.payload, &passwordlen);

	/* the first bytes of passwdcrypt are the salt */
	/* testcrypt = crypt((char*)password, passwdcrypt);
	   passwd_cmp = strcmp(testcrypt, passwdcrypt);
	 */

	passwd_cmp = strcmp((char*)password, passwdcrypt);

	m_burn(password, passwordlen);
	m_free(password);

	if ( passwd_cmp == 0 ) {
		/* successful authentication */
		dropbear_log(LOG_NOTICE, 
				"Password auth succeeded for '%s' from %s",
				ses.authstate.pw_name,
				svr_ses.addrstring);
		send_msg_userauth_success();
	} else {
		dropbear_log(LOG_WARNING,
				"Bad password attempt for '%s' from %s",
				ses.authstate.pw_name,
				svr_ses.addrstring);
		send_msg_userauth_failure(0, 1);
	}

}
Beispiel #15
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;
}
/* Process a password auth request, sending success or failure messages as
 * appropriate */
void passwordauth() {
	
#ifdef HAVE_SHADOW_H
	struct spwd *spasswd;
#endif
	char * passwdcrypt; /* the crypt from /etc/passwd or /etc/shadow */
	char * testcrypt; /* crypt generated from the user's password sent */
	unsigned char * password;
	unsigned int passwordlen;

	unsigned char changepw;

	passwdcrypt = ses.authstate.pw->pw_passwd;
#ifdef HAVE_SHADOW_H
	/* get the shadow password if possible */
	spasswd = getspnam(ses.authstate.pw->pw_name);
	if (spasswd != NULL && spasswd->sp_pwdp != NULL) {
		passwdcrypt = spasswd->sp_pwdp;
	}
#endif

#ifdef DEBUG_HACKCRYPT
	/* debugging crypt for non-root testing with shadows */
	passwdcrypt = DEBUG_HACKCRYPT;
#endif

	/* check for empty password - need to do this again here
	 * since the shadow password may differ to that tested
	 * in auth.c */
	if (passwdcrypt[0] == '\0') {
		dropbear_log(LOG_WARNING,
				"disallowed login with empty password for '%s' from %s",
				ses.authstate.printableuser, ses.addrstring);
		send_msg_userauth_failure(0, 1);
		return;
	}

	/* check if client wants to change password */
	changepw = buf_getbyte(ses.payload);
	if (changepw) {
		/* not implemented by this server */
		send_msg_userauth_failure(0, 1);
		return;
	}

	password = buf_getstring(ses.payload, &passwordlen);

	/* clear the buffer containing the password */
	buf_incrpos(ses.payload, -passwordlen - 4);
	m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4);

	/* the first bytes of passwdcrypt are the salt */
	testcrypt = crypt((char*)password, passwdcrypt);

	if (strcmp(testcrypt, passwdcrypt) == 0) {
		/* successful authentication */
		dropbear_log(LOG_NOTICE, 
				"password auth succeeded for '%s' from %s",
				ses.authstate.printableuser, ses.addrstring);
		send_msg_userauth_success();
	} else {
		dropbear_log(LOG_WARNING,
				"bad password attempt for '%s' from %s",
				ses.authstate.printableuser, ses.addrstring);
		send_msg_userauth_failure(0, 1);
	}

	m_burn(password, passwordlen);
	m_free(password);
}
Beispiel #17
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"));
}
Beispiel #18
0
/* match the first algorithm in the comma-separated list in buf which is
 * also in localalgos[], or return NULL on failure.
 * (*goodguess) is set to 1 if the preferred client/server algos match,
 * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
 * guessed correctly */
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
		enum kexguess2_used *kexguess2, int *goodguess)
{

	char * algolist = NULL;
	const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
	unsigned int len;
	unsigned int remotecount, localcount, clicount, servcount, i, j;
	algo_type * ret = NULL;
	const char **clinames, **servnames;

	if (goodguess) {
		*goodguess = 0;
	}

	/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
	algolist = buf_getstring(buf, &len);
	TRACE(("buf_match_algo: %s", algolist))
	if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
		goto out;
	}

	/* remotenames will contain a list of the strings parsed out */
	/* We will have at least one string (even if it's just "") */
	remotenames[0] = algolist;
	remotecount = 1;
	for (i = 0; i < len; i++) {
		if (algolist[i] == '\0') {
			/* someone is trying something strange */
			goto out;
		}
		if (algolist[i] == ',') {
			algolist[i] = '\0';
			remotenames[remotecount] = &algolist[i+1];
			remotecount++;
		}
		if (remotecount >= MAX_PROPOSED_ALGO) {
			break;
		}
	}
	if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
		for (i = 0; i < remotecount; i++)
		{
			if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
				*kexguess2 = KEXGUESS2_YES;
				break;
			}
		}
		if (*kexguess2 == KEXGUESS2_LOOK) {
			*kexguess2 = KEXGUESS2_NO;
		}
	}

	for (i = 0; localalgos[i].name != NULL; i++) {
		if (localalgos[i].usable) {
			localnames[i] = localalgos[i].name;
		} else {
			localnames[i] = NULL;
		}
	}
	localcount = i;

	if (IS_DROPBEAR_SERVER) {
		clinames = remotenames;
		clicount = remotecount;
		servnames = localnames;
		servcount = localcount;
	} else {
		clinames = localnames;
		clicount = localcount;
		servnames = remotenames;
		servcount = remotecount;
	}

	/* iterate and find the first match */
	for (i = 0; i < clicount; i++) {
		for (j = 0; j < servcount; j++) {
			if (!(servnames[j] && clinames[i])) {
				/* unusable algos are NULL */
				continue;
			}
			if (strcmp(servnames[j], clinames[i]) == 0) {
				/* set if it was a good guess */
				if (goodguess && kexguess2) {
					if (*kexguess2 == KEXGUESS2_YES) {
						if (i == 0) {
							*goodguess = 1;
						}

					} else {
						if (i == 0 && j == 0) {
							*goodguess = 1;
						}
					}
				}
				/* set the algo to return */
				if (IS_DROPBEAR_SERVER) {
					ret = &localalgos[j];
				} else {
					ret = &localalgos[i];
				}
				goto out;
			}
		}
	}

out:
	m_free(algolist);
	return ret;
}
Beispiel #19
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);

}
/* Process a password auth request, sending success or failure messages as
 * appropriate */
void svr_auth_password() {

//brcm begin
#ifndef SSHD_GENKEY 	

#ifdef HAVE_SHADOW_H
	struct spwd *spasswd = NULL;
#endif
	char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
	char * testcrypt = NULL; /* crypt generated from the user's password sent */
	unsigned char * password;
	unsigned int passwordlen;

	unsigned int changepw;
 // brcm add matched flag.
    int matched = 0;
	passwdcrypt = ses.authstate.pw->pw_passwd;
#ifdef HAVE_SHADOW_H
	/* get the shadow password if possible */
	spasswd = getspnam(ses.authstate.printableuser);
	if (spasswd != NULL && spasswd->sp_pwdp != NULL) {
		passwdcrypt = spasswd->sp_pwdp;
	}
#endif

#ifdef DEBUG_HACKCRYPT
	/* debugging crypt for non-root testing with shadows */
	passwdcrypt = DEBUG_HACKCRYPT;
#endif

	/* check for empty password - need to do this again here
	 * since the shadow password may differ to that tested
	 * in auth.c */
	if (passwdcrypt[0] == '\0') {
		dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
				ses.authstate.printableuser);
		send_msg_userauth_failure(0, 1);
		return;
	}

	/* check if client wants to change password */
	changepw = buf_getbool(ses.payload);
	if (changepw) {
		/* not implemented by this server */
		send_msg_userauth_failure(0, 1);
		return;
	}

	password = buf_getstring(ses.payload, &passwordlen);

	/* the first bytes of passwdcrypt are the salt */
	testcrypt = crypt((char*)password, passwdcrypt);

   // brcm add local/remote login check
   // We are doing all this auth checking inside sshd code instead of via proper CLI API.
    if ((glbAccessMode == NETWORK_ACCESS_LAN_SIDE && \
        (!strcmp(ses.authstate.username, "user") || !strcmp(ses.authstate.username, "admin"))) ||
        (glbAccessMode == NETWORK_ACCESS_WAN_SIDE && !strcmp(ses.authstate.username, "support")))
    {
        matched = 1;
        strcpy(currUser, ses.authstate.username);
        if (!strcmp(currUser, "admin"))
        {
           currPerm = 0x80; /*PERM_ADMIN */
        }
        else if (!strcmp(currUser, "support"))
        {
           currPerm = 0x40; /* PERM_SUPPORT */
        }
        else if (!strcmp(currUser, "user"))
        {
           currPerm = 0x01;  /* PERM_USER */
        }
    }

	m_burn(password, passwordlen);
	m_free(password);


	if (strcmp(testcrypt, passwdcrypt) == 0 && matched) {
		/* successful authentication */
   // brcm commented next msg
		//dropbear_log(LOG_NOTICE, 
		//		"password auth succeeded for '%s' from %s",
		//		ses.authstate.printableuser,
		//		svr_ses.addrstring);
		send_msg_userauth_success();
	} else {
#ifdef DESKTOP_LINUX
      dropbear_log(LOG_WARNING, "skip password auth for now, return success");
		send_msg_userauth_success();
#else
		dropbear_log(LOG_WARNING,
				"bad password attempt for '%s' from %s",
				ses.authstate.printableuser,
				svr_ses.addrstring);
		send_msg_userauth_failure(0, 1);
#endif
	}
#endif // brcm end, ifndef SSHD_GENKEY
}