mirror of
				https://github.com/clearml/dropbear
				synced 2025-06-26 18:17:32 +00:00 
			
		
		
		
	Add ~. and ~^Z handling to exit/suspend dbclient
This commit is contained in:
		
							parent
							
								
									c172fb3b32
								
							
						
					
					
						commit
						5996c3824c
					
				| @ -83,8 +83,10 @@ struct Channel { | ||||
| 
 | ||||
| 	int flushing; | ||||
| 
 | ||||
| 	const struct ChanType* type; | ||||
| 	/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */ | ||||
| 	void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len); | ||||
| 
 | ||||
| 	const struct ChanType* type; | ||||
| }; | ||||
| 
 | ||||
| struct ChanType { | ||||
|  | ||||
| @ -38,9 +38,10 @@ | ||||
| static void cli_closechansess(struct Channel *channel); | ||||
| static int cli_initchansess(struct Channel *channel); | ||||
| static void cli_chansessreq(struct Channel *channel); | ||||
| 
 | ||||
| static void send_chansess_pty_req(struct Channel *channel); | ||||
| static void send_chansess_shell_req(struct Channel *channel); | ||||
| static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len); | ||||
| 
 | ||||
| 
 | ||||
| static void cli_tty_setup(); | ||||
| 
 | ||||
| @ -374,7 +375,9 @@ static int cli_initchansess(struct Channel *channel) { | ||||
| 
 | ||||
| 	if (cli_opts.wantpty) { | ||||
| 		cli_tty_setup(); | ||||
| 	} | ||||
| 		channel->read_mangler = cli_escape_handler; | ||||
| 		cli_ses.last_char = '\r'; | ||||
| 	}	 | ||||
| 
 | ||||
| 	return 0; /* Success */ | ||||
| } | ||||
| @ -429,3 +432,59 @@ void cli_send_chansess_request() { | ||||
| 	TRACE(("leave cli_send_chansess_request")) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // returns 1 if the character should be consumed, 0 to pass through
 | ||||
| static int | ||||
| do_escape(unsigned char c) { | ||||
| 	switch (c) { | ||||
| 		case '.': | ||||
| 			dropbear_exit("Terminated"); | ||||
| 			return 1; | ||||
| 			break; | ||||
| 		case 0x1a: | ||||
| 			// ctrl-z
 | ||||
| 			cli_tty_cleanup(); | ||||
| 			kill(getpid(), SIGTSTP); | ||||
| 			// after continuation
 | ||||
| 			cli_tty_setup(); | ||||
| 			cli_ses.winchange = 1; | ||||
| 			return 1; | ||||
| 			break; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static | ||||
| void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len) { | ||||
| 	char c; | ||||
| 	int skip_char = 0; | ||||
| 
 | ||||
| 	// only handle escape characters if they are read one at a time. simplifies
 | ||||
| 	// the code and avoids nasty people putting ~. at the start of a line to paste 
 | ||||
| 	if (*len != 1) { | ||||
| 		cli_ses.last_char = 0x0; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	c = buf[0]; | ||||
| 
 | ||||
| 	if (cli_ses.last_char == DROPBEAR_ESCAPE_CHAR) { | ||||
| 		skip_char = do_escape(c); | ||||
| 		cli_ses.last_char = 0x0; | ||||
| 	} else { | ||||
| 		if (c == DROPBEAR_ESCAPE_CHAR) { | ||||
| 			if (cli_ses.last_char == '\r') { | ||||
| 				cli_ses.last_char = DROPBEAR_ESCAPE_CHAR; | ||||
| 				skip_char = 1; | ||||
| 			} else { | ||||
| 				cli_ses.last_char = 0x0; | ||||
| 			} | ||||
| 		} else { | ||||
| 			cli_ses.last_char = c; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (skip_char) { | ||||
| 		*len = 0; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -643,6 +643,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) { | ||||
| 
 | ||||
| 	/* read the data */ | ||||
| 	len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen); | ||||
| 
 | ||||
| 	if (len <= 0) { | ||||
| 		if (len == 0 || errno != EINTR) { | ||||
| 			/* This will also get hit in the case of EAGAIN. The only
 | ||||
| @ -650,12 +651,22 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) { | ||||
| 			in which case it can be treated the same as EOF */ | ||||
| 			close_chan_fd(channel, fd, SHUT_RD); | ||||
| 		} | ||||
| 		ses.writepayload->len = ses.writepayload->pos = 0; | ||||
| 		buf_setpos(ses.writepayload, 0); | ||||
| 		buf_setlen(ses.writepayload, 0); | ||||
| 		TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d",  | ||||
| 					len, errno, fd)) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (channel->read_mangler) { | ||||
| 		channel->read_mangler(channel, buf_getwriteptr(ses.writepayload, len), &len); | ||||
| 		if (len == 0) { | ||||
| 			buf_setpos(ses.writepayload, 0); | ||||
| 			buf_setlen(ses.writepayload, 0); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	TRACE(("send_msg_channel_data: len %d fd %d", len, fd)) | ||||
| 	buf_incrwritepos(ses.writepayload, len); | ||||
| 	/* ... real size here */ | ||||
|  | ||||
| @ -259,6 +259,9 @@ struct clientsession { | ||||
| 	int stderrcopy; | ||||
| 	int stderrflags; | ||||
| 
 | ||||
| 	/* for escape char handling */ | ||||
| 	int last_char; | ||||
| 
 | ||||
| 	int winchange; /* Set to 1 when a windowchange signal happens */ | ||||
| 
 | ||||
| 	int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
 | ||||
|  | ||||
| @ -54,6 +54,8 @@ | ||||
| 
 | ||||
| #define _PATH_CP "/bin/cp" | ||||
| 
 | ||||
| #define DROPBEAR_ESCAPE_CHAR '~' | ||||
| 
 | ||||
| /* success/failure defines */ | ||||
| #define DROPBEAR_SUCCESS 0 | ||||
| #define DROPBEAR_FAILURE -1 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user