diff --git a/Makefile.in b/Makefile.in old mode 100644 new mode 100755 index bc55b7de5..952f2fc53 --- a/Makefile.in +++ b/Makefile.in @@ -37,7 +37,8 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \ atomicio.o compat.o fake-rfc2553.o \ ltc_prng.o ecc.o ecdsa.o crypto_desc.o \ dbmalloc.o \ - gensignkey.o gendss.o genrsa.o + gensignkey.o gendss.o genrsa.o \ + dbconfigure.o SVROBJS=svr-kex.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \ @@ -75,8 +76,8 @@ ifeq (@DROPBEAR_FUZZ@, 1) else dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) - dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS) - dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS) + dropbearkeyobjs=$(COMMONOBJS) $(CLISVROBJS) $(KEYOBJS) + dropbearconvertobjs=$(COMMONOBJS) $(CLISVROBJS) $(CONVERTOBJS) scpobjs=$(SCPOBJS) endif diff --git a/crypto_desc.c b/crypto_desc.c old mode 100644 new mode 100755 index 0f946fcd3..412508e00 --- a/crypto_desc.c +++ b/crypto_desc.c @@ -3,12 +3,15 @@ #include "crypto_desc.h" #include "ltc_prng.h" #include "ecc.h" +#include "dbconfigure.h" +#include "algo.h" + +static void configure_algo(char *line, char *key, algo_type* algos); #if DROPBEAR_LTC_PRNG int dropbear_ltc_prng = -1; #endif - /* Register the compiled in ciphers. * This should be run before using any of the ciphers/hashes */ void crypto_init() { @@ -73,3 +76,92 @@ void crypto_init() { #endif } +static void configure_algo(char *line, char *key, algo_type* algos) +{ + char value[32][24] = {'\0'}; + unsigned int count = 0, length; + unsigned int n, m, found = 0; + + n = strlen(key); + while (line[n] == ' ' || line[n] == '\t') + n++; + if (line[n] == '\0') { + fprintf(stderr, "%s value is empty, skip setting.\n", key); + return; + } + + length = strlen(line) + 1; /* we need to reach '\0' */ + while (n < length && line[n] == ',') + n++; /* eat ',' in front of value */ + m = n; + for (; n < length; n++) { + if (line[n] == ',') { + strncpy(value[count], &line[m], n - m); + value[count][sizeof(value[0])/sizeof(char) - 1] = '\0'; + while (n + 1 < length && line[n + 1] == ',') + n++; + m = n + 1; /* skip ',' */ + if (++count >= sizeof(value)/sizeof(value[0])) { + fprintf(stderr, "Too many %s value, do truncate.\n", key); + break; + } + } else if (line[n] == '\0' && m != n) { + strncpy(value[count++], &line[m], n - m); + break; + } + } + if (count > 0) { + for (n = 0; algos[n].name != NULL; n++) { + algos[n].usable = 0; + for (m = 0; m < count; m++) { + if (!strcmp(algos[n].name, value[m])) { + found = 1; + algos[n].usable = 1; + } + } + } + } + + /* no match algorithm, restore all to usable? */ + if (!found) { + fprintf(stderr, "No match of %s in configuration file, skip setting.\n", key); + for (n = 0; algos[n].name != NULL; n++) + algos[n].usable = 1; + } +} + + +/* Read from /etc/dropbear/crypto_config in order to use specified algorithm. + * Format: + * Ciphers algo1,algo2,algo3 + * MACs algo1,algo2,algo3 + * ... + */ +void crypto_configure(const char *config_file) +{ + int i; + int ciphers_line = -1, macs_line = -1; + config_file_content *cfc = NULL; + + cfc = read_config_file(config_file); + if (!cfc) + return; + + for (i = 0; i < cfc->lines_count; i++) { + if (!strncmp("Ciphers", cfc->lines[i], strlen("Ciphers")) && + strlen(cfc->lines[i]) > strlen("Ciphers") + 2) { + ciphers_line = i; + } else if (!strncmp("MACs", cfc->lines[i], strlen("MACs")) && + strlen(cfc->lines[i]) > strlen("MACs") + 2) { + macs_line = i; + } + } + + if (ciphers_line != -1) + configure_algo(cfc->lines[ciphers_line], "Ciphers", sshciphers); + if (macs_line != -1) + configure_algo(cfc->lines[macs_line], "MACs", sshhashes); + + cfc->free(cfc); +} + diff --git a/crypto_desc.h b/crypto_desc.h old mode 100644 new mode 100755 index 08a75d98d..0684572ec --- a/crypto_desc.h +++ b/crypto_desc.h @@ -2,6 +2,7 @@ #define DROPBEAR_CRYPTO_DESC_H void crypto_init(void); +void crypto_configure(const char *config_file); extern int dropbear_ltc_prng; diff --git a/dbconfigure.c b/dbconfigure.c new file mode 100755 index 000000000..07919c308 --- /dev/null +++ b/dbconfigure.c @@ -0,0 +1,134 @@ +#include "dbconfigure.h" + +static int check_line_limit(const char *config_file, int line_length, int line_count); +static void free_config_file(config_file_content *self); +static config_file_content *init_config_file_content(void); + +static int check_line_limit(const char *config_file, int line_length, int line_count) +{ + if (line_length > CONFIG_FILE_LINE_MAX_LENGTH) { + fprintf(stderr, "[%s] line length too long\n", config_file); + return -1; + } + if (line_count > CONFIG_FILE_MAX_LINE) { + fprintf(stderr, "[%s] too many lines_count\n", config_file); + return -1; + } + return 0; +} + +static void free_config_file(config_file_content *self) +{ + int i; + + if (self) { + if (self->lines) { + for (i = 0; i < self->lines_count; i++) + if (self->lines[i]) + free(self->lines[i]); + free(self->lines); + } + free(self); + } +} + +static config_file_content *init_config_file_content(void) +{ + config_file_content *content; + + content = (config_file_content*) m_malloc(sizeof(config_file_content)); + content->free = free_config_file; + + return content; +} + +config_file_content *read_config_file(const char *config_file) +{ + char content[CONFIG_FILE_CONTENT_SIZE] = {'\0'}; + char buf[512]; + config_file_content *cfc = NULL; + int fd, ret, len; + unsigned int i, j, count = 0; + + if ((fd = open(config_file, O_RDONLY)) == -1) + return NULL; + + while ((ret = read(fd, buf, sizeof(buf))) > 0) { + if (count + ret >= sizeof(content)) { + fprintf(stderr, "config file %s too large\n", config_file); + close(fd); + return NULL; + } + memcpy(&content[count], buf, ret); + count += ret; + } + + cfc = init_config_file_content(); + cfc->lines = (char**) m_malloc(CONFIG_FILE_MAX_LINE * sizeof(char*)); + cfc->lines_count = 0; + for (i = 0, j = 0; i < count; i++) { + if (content[i] == '\n') { + if (i == 0) { /* some '\n' before text, eat them. */ + while (i < count - 1 && content[i + 1] == '\n') + i++; + j = i + 1; /* let j point to a character after '\n' */ + continue; + } + if (check_line_limit(config_file, i - j + 1, cfc->lines_count + 1) != 0) + goto error_free; + cfc->lines[cfc->lines_count++] = (char*) m_malloc((i - j + 1) * sizeof(char)); + memcpy(cfc->lines[cfc->lines_count - 1], &content[j], i - j); + cfc->lines[cfc->lines_count - 1][i - j] = '\0'; + while (i < count - 1 && content[i + 1] == '\n') + i++; /* eat '\n' after a line */ + j = i + 1; + } else if (content[i] == '#') { + unsigned int pre_i = i; + while (i < count - 1) { + if (content[i + 1] != '\n' && content[i + 1] != '#' && content[i] == '\n') + break; + else + i++; /* eat comment */ + } + if (pre_i != j) { /* comment after text in one line, ie: abcd #comment */ + if (check_line_limit(config_file, pre_i - j + 1, cfc->lines_count + 1) != 0) + goto error_free; + cfc->lines[cfc->lines_count++] = (char*) m_malloc((pre_i - j + 1) * sizeof(char)); + memcpy(cfc->lines[cfc->lines_count - 1], &content[j], pre_i - j); + cfc->lines[cfc->lines_count - 1][pre_i - j] = '\0'; + } + if (i == count - 1) /* reach end */ + break; + else + j = i + 1; + } else if (i == count - 1) { + if (check_line_limit(config_file, i - j + 2, cfc->lines_count + 1) != 0) + goto error_free; + cfc->lines[cfc->lines_count++] = (char*) m_malloc((i - j + 2) * sizeof(char)); + memcpy(cfc->lines[cfc->lines_count - 1], &content[j], i - j + 1); + cfc->lines[cfc->lines_count - 1][i + 1] = '\0'; + break; + } + + if (lines_cnt > 1) { + len = strlen(lines[lines_cnt - 1]); + + if (len >= 1 && lines[lines_cnt - 1][len - 1] == '\r') { + lines[lines_cnt - 1][len - 1] = '\0'; + } + } + } + + if (cfc->lines_count == 0) { + goto error_free; + } else { + close(fd); + return cfc; + } + +error_free: + cfc->free(cfc); + close(fd); + return NULL; +} + diff --git a/dbconfigure.h b/dbconfigure.h new file mode 100755 index 000000000..ea1de013a --- /dev/null +++ b/dbconfigure.h @@ -0,0 +1,24 @@ +#ifndef CONFIGURE_H_ +#define CONFIGURE_H_ + +#include +#include +#include +#include +#include +#include "dbmalloc.h" + + +#define CONFIG_FILE_MAX_LINE 256 +#define CONFIG_FILE_LINE_MAX_LENGTH 512 +#define CONFIG_FILE_CONTENT_SIZE (CONFIG_FILE_MAX_LINE * CONFIG_FILE_LINE_MAX_LENGTH) + +typedef struct Config_file_content { + char **lines; + int lines_count; /* exclude empty line and comment line */ + void (*free) (struct Config_file_content *self); +} config_file_content; + +config_file_content *read_config_file(const char *config_file); + +#endif diff --git a/svr-main.c b/svr-main.c old mode 100644 new mode 100755 index 0a39b7080..c605dad21 --- a/svr-main.c +++ b/svr-main.c @@ -401,6 +401,8 @@ static void commonsetup() { crypto_init(); + crypto_configure("/etc/dropbear/crypto_config"); + /* Now we can setup the hostkeys - needs to be after logging is on, * otherwise we might end up blatting error messages to the socket */ load_all_hostkeys();