Hello,

please find attached a new patch allowing to use the 'command' option
with public keys in authorized_keys file. 

This patch include the one from my previous email :
On Sun, 25 May 2008 11:50:29 +0200
Frédéric Moulins <[EMAIL PROTECTED]> wrote:

> Hello,
> 
> the following patch allow to skip options of public keys in
> authorized_keys file.
> 
> authorized_keys file still must respect :
> * no whitespace at the begining of a line.
> * only one space or tab character between options and algorithm type.
> 
> Code has been copied and adapted from OpenSSH function
> user_key_allowed2 in auth2-pubkey.c.
> 

A PubKeyOptions structure is declared in auth.h. It contains the
same parameters used in OpenSSH that I commented out except
'forced_command' that is used. This structure is used under
ses.authstate.

A new function 'addpubkeyoptions' in svr-authpubkey.c parse,  validate
and set options in the session structure. Code has been copied and
adapted from the parsing function in OpenSSH. It only parses the
'command' option for the moment. Any other option will be taken as bad
option and invalidate the key. In order to add support for other
options, you can copy and slightly adapt (mallocS, freeS and gotoS)
chunks of parsing code from OpenSSH function auth_parse_options in
auth-options.c.

What do you think of it ? 
Any feedback or suggestions is welcome (malloc/free, structures, corner
cases,...).


fred

PS : patch is still against dropbear-0.50. Tell me if you prefer a
patch against the latest development version.
diff -urN dropbear-0.50.orig/auth.h dropbear-0.50/auth.h
--- dropbear-0.50.orig/auth.h	2007-08-08 17:39:36.000000000 +0200
+++ dropbear-0.50/auth.h	2008-05-25 23:13:18.000000000 +0200
@@ -94,6 +94,9 @@
 	char *printableuser; /* stripped of control chars, used for logs etc */
 	struct passwd * pw;
 
+#ifdef ENABLE_SVR_PUBKEY_AUTH
+	struct PubKeyOptions* pubkey_options;
+#endif
 };
 
 struct SignKeyList;
@@ -108,4 +111,27 @@
 
 };
 
+#ifdef ENABLE_SVR_PUBKEY_AUTH
+struct PubKeyOptions;
+struct PubKeyOptions {
+/* Flags set authorized_keys flags */
+/* Not yet supported
+	int no_port_forwarding_flag;
+	int no_agent_forwarding_flag;
+	int no_x11_forwarding_flag;
+	int no_pty_flag;
+	int no_user_rc;
+*/
+	/* "command=" option. */
+	char * forced_command;
+
+	/* "environment=" options. */
+//	char ** custom_environment;
+
+	/* "tunnel=" option. */
+//	int forced_tun_device;
+
+};
+#endif
+
 #endif /* _AUTH_H_ */
diff -urN dropbear-0.50.orig/svr-authpubkey.c dropbear-0.50/svr-authpubkey.c
--- dropbear-0.50.orig/svr-authpubkey.c	2007-08-08 17:39:37.000000000 +0200
+++ dropbear-0.50/svr-authpubkey.c	2008-05-26 01:12:00.000000000 +0200
@@ -45,6 +45,7 @@
 static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
 		unsigned char* keyblob, unsigned int keybloblen);
 static int checkfileperm(char * filename);
+static int addpubkeyoptions(const char* opts);
 
 /* process a pubkey auth request, sending success or failure message as
  * appropriate */
@@ -158,8 +159,9 @@
 	char * filename = NULL;
 	int ret = DROPBEAR_FAILURE;
 	buffer * line = NULL;
-	unsigned int len, pos;
-	
+	unsigned int len, pos, quoted;
+	const char *options = NULL;
+
 	TRACE(("enter checkpubkey"))
 
 	/* check that we can use the algo */
@@ -196,6 +198,8 @@
 
 	/* iterate through the lines */
 	do {
+		/* new line : potentially new options */
+		options = NULL;
 
 		if (buf_getline(line, authfile) == DROPBEAR_FAILURE) {
 			/* EOF reached */
@@ -208,10 +212,39 @@
 			continue; /* line is too short for it to be a valid key */
 		}
 
-		/* check the key type - this also stops us from using keys
-		 * which have options with them */
+		/* check the key type - will fail if there are options */
 		if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) {
-			continue;
+			/* there may be options or a commented line */
+			if ('#' == line->data[line->pos]) continue;
+			/* no comment, skip to next space character */
+			len = 0;
+			pos = line->pos;
+			options = buf_getptr(line, 1);
+			quoted = 0;
+			while (line->data[pos] 
+				&& (quoted || (line->data[pos] != ' '
+						&& line->data[pos] != '\t'
+						&& line->data[pos] != '\n'
+						&& line->data[pos] != '\r'))) { 
+				pos++;
+				if (line->data[pos] == '\\' 
+					&& line->data[pos+1] == '"') { 
+					pos++;	/* skip both */ 
+				} else if (line->data[pos] == '"') 
+					quoted = !quoted; 
+			} /* line->data[pos] == ['\0'|' '|'\t'] */
+
+			/* skip line if there is nothing left */
+			if (pos >= line->len) continue;
+			/* skip line if it begins with a space or tab character */
+			if (pos == line->pos) continue;
+			/* set the position of the line after what we have read */
+			buf_setpos(line, pos+1);
+			/* give a second chance to the algo */
+			if (line->pos + algolen > line->len) continue;
+			if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) { 
+				continue;
+			 }
 		}
 		buf_incrpos(line, algolen);
 		
@@ -233,6 +266,10 @@
 
 		ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line, NULL);
 		if (ret == DROPBEAR_SUCCESS) {
+			ret = addpubkeyoptions(options);
+		}
+
+		if (ret == DROPBEAR_SUCCESS) {
 			break;
 		}
 
@@ -343,5 +380,83 @@
 	return DROPBEAR_SUCCESS;
 }
 
+/* parse pubkey options and set ses.authstate.pubkey_options accordingly */
+static int addpubkeyoptions(const char* opts) {
+	const char *cp;
+	int i;
+	int ret = DROPBEAR_FAILURE;
+
+	TRACE(("enter addpubkeyoptions"))
+	
+	if (!opts || *opts == ' ') {
+		/* no option, success */
+		ret = DROPBEAR_SUCCESS;
+		goto end;
+	}
+	
+	ses.authstate.pubkey_options = (struct PubKeyOptions*)m_malloc(sizeof( struct PubKeyOptions ));
+
+	while (*opts && *opts != ' ' && *opts != '\t') {
+		cp = "command=\"";
+		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+			opts += strlen(cp);
+			ses.authstate.pubkey_options->forced_command = (char*)m_malloc(strlen(opts) + 1);
+			i = 0;
+			while (*opts) {
+				if (*opts == '"')
+					break;
+				if (*opts == '\\' && opts[1] == '"') {
+					opts += 2;
+					ses.authstate.pubkey_options->forced_command[i++] = '"';
+					continue;
+				}
+				ses.authstate.pubkey_options->forced_command[i++] = *opts++;
+			}
+			if (!*opts) {
+				dropbear_log(LOG_WARNING, "Missing end quote in public key command option");
+				m_free(ses.authstate.pubkey_options->forced_command);
+				ses.authstate.pubkey_options->forced_command = NULL;
+				goto bad_option;
+			}
+			ses.authstate.pubkey_options->forced_command[i] = '\0';
+			if (strlen(ses.authstate.pubkey_options->forced_command) > MAX_CMD_LEN) {
+				m_free(ses.authstate.pubkey_options->forced_command);
+				ses.authstate.pubkey_options->forced_command = NULL;
+				goto bad_option;
+			}
+			TRACE(("addpubkeyoptions: forced command '%s'", 
+				ses.authstate.pubkey_options->forced_command))
+			opts++;
+			goto next_option;
+		}
+		next_option:
+		/*
+		 * Skip the comma, and move to the next option
+		 * (or break out if there are no more).
+		 */
+		if (!*opts)
+			TRACE(("Bugs in svr-chansession.c pubkey option processing."))
+		if (*opts == ' ' || *opts == '\t')
+			break;		/* End of options. */
+		if (*opts != ',')
+			goto bad_option;
+		opts++;
+		/* Process the next option. */
+	}
+	/* parsed all options with no problem */
+	ret = DROPBEAR_SUCCESS;
+	goto end;
+
+bad_option:
+	ret = DROPBEAR_FAILURE;
+	m_free(ses.authstate.pubkey_options);
+	ses.authstate.pubkey_options = NULL;
+	dropbear_log(LOG_WARNING, "Bad public key options : %.50s", opts);
+
+end:
+	TRACE(("leave addpubkeyoptions"))
+	return ret;
+
+}
 
 #endif 
Les fichiers binaires dropbear-0.50.orig/.svr-authpubkey.c.swp et dropbear-0.50/.svr-authpubkey.c.swp sont différents.
diff -urN dropbear-0.50.orig/svr-chansession.c dropbear-0.50/svr-chansession.c
--- dropbear-0.50.orig/svr-chansession.c	2007-08-08 17:39:37.000000000 +0200
+++ dropbear-0.50/svr-chansession.c	2008-05-25 19:44:30.000000000 +0200
@@ -578,14 +578,22 @@
 		return DROPBEAR_FAILURE;
 	}
 
+#ifdef ENABLE_SVR_PUBKEY_AUTH
+		/* take public key options into account */
+		if (ses.authstate.pubkey_options)
+			chansess->cmd = ses.authstate.pubkey_options->forced_command;
+#endif
+
 	if (iscmd) {
 		/* "exec" */
-		chansess->cmd = buf_getstring(ses.payload, &cmdlen);
+		if (chansess->cmd == NULL) {
+			chansess->cmd = buf_getstring(ses.payload, &cmdlen);
 
-		if (cmdlen > MAX_CMD_LEN) {
-			m_free(chansess->cmd);
-			/* TODO - send error - too long ? */
-			return DROPBEAR_FAILURE;
+			if (cmdlen > MAX_CMD_LEN) {
+				m_free(chansess->cmd);
+				/* TODO - send error - too long ? */
+				return DROPBEAR_FAILURE;
+			}
 		}
 		if (issubsys) {
 #ifdef SFTPSERVER_PATH
diff -urN dropbear-0.50.orig/svr-session.c dropbear-0.50/svr-session.c
--- dropbear-0.50.orig/svr-session.c	2007-08-08 17:39:37.000000000 +0200
+++ dropbear-0.50/svr-session.c	2008-05-26 00:57:04.000000000 +0200
@@ -144,6 +144,13 @@
 
 	_dropbear_log(LOG_INFO, fmtbuf, param);
 
+#ifdef ENABLE_SVR_PUBKEY_AUTH
+	/* free potential public key options */
+	if (ses.authstate.pubkey_options) {
+		m_free(ses.authstate.pubkey_options);
+		ses.authstate.pubkey_options = NULL;
+	}
+#endif
 	/* must be after we've done with username etc */
 	common_session_cleanup();
 

Reply via email to