Home | History | Annotate | Download | only in dropbear
      1 /*
      2  * Dropbear - a SSH2 server
      3  *
      4  * Copyright (c) 2002,2003 Matt Johnston
      5  * All rights reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE. */
     24 
     25 #include "includes.h"
     26 #include "runopts.h"
     27 #include "signkey.h"
     28 #include "buffer.h"
     29 #include "dbutil.h"
     30 #include "algo.h"
     31 
     32 svr_runopts svr_opts; /* GLOBAL */
     33 
     34 static void printhelp(const char * progname);
     35 static void addportandaddress(char* spec);
     36 
     37 static void printhelp(const char * progname) {
     38 
     39 	fprintf(stderr, "Dropbear sshd v%s\n"
     40 					"Usage: %s [options]\n"
     41 					"Options are:\n"
     42 					"-b bannerfile	Display the contents of bannerfile"
     43 					" before user login\n"
     44 					"		(default: none)\n"
     45 #ifdef DROPBEAR_DSS
     46 					"-d dsskeyfile	Use dsskeyfile for the dss host key\n"
     47 					"		(default: %s)\n"
     48 #endif
     49 #ifdef DROPBEAR_RSA
     50 					"-r rsakeyfile	Use rsakeyfile for the rsa host key\n"
     51 					"		(default: %s)\n"
     52 #endif
     53 					"-F		Don't fork into background\n"
     54 #ifdef DISABLE_SYSLOG
     55 					"(Syslog support not compiled in, using stderr)\n"
     56 #else
     57 					"-E		Log to stderr rather than syslog\n"
     58 #endif
     59 #ifdef DO_MOTD
     60 					"-m		Don't display the motd on login\n"
     61 #endif
     62 					"-w		Disallow root logins\n"
     63 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
     64 					"-s		Disable password logins\n"
     65 					"-g		Disable password logins for root\n"
     66 #endif
     67 #ifdef ENABLE_SVR_LOCALTCPFWD
     68 					"-j		Disable local port forwarding\n"
     69 #endif
     70 #ifdef ENABLE_SVR_REMOTETCPFWD
     71 					"-k		Disable remote port forwarding\n"
     72 					"-a		Allow connections to forwarded ports from any host\n"
     73 #endif
     74 					"-p [address:]port\n"
     75 					"		Listen on specified tcp port (and optionally address),\n"
     76 					"		up to %d can be specified\n"
     77 					"		(default port is %s if none specified)\n"
     78 					"-P PidFile	Create pid file PidFile\n"
     79 					"		(default %s)\n"
     80 #ifdef INETD_MODE
     81 					"-i		Start for inetd\n"
     82 #endif
     83 #ifdef DEBUG_TRACE
     84 					"-v		verbose\n"
     85 #endif
     86 					,DROPBEAR_VERSION, progname,
     87 #ifdef DROPBEAR_DSS
     88 					DSS_PRIV_FILENAME,
     89 #endif
     90 #ifdef DROPBEAR_RSA
     91 					RSA_PRIV_FILENAME,
     92 #endif
     93 					DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE);
     94 }
     95 
     96 void svr_getopts(int argc, char ** argv) {
     97 
     98 	unsigned int i;
     99 	char ** next = 0;
    100 	int nextisport = 0;
    101 
    102 	/* see printhelp() for options */
    103 	svr_opts.rsakeyfile = NULL;
    104 	svr_opts.dsskeyfile = NULL;
    105 	svr_opts.bannerfile = NULL;
    106 	svr_opts.banner = NULL;
    107 	svr_opts.forkbg = 1;
    108 	svr_opts.norootlogin = 0;
    109 	svr_opts.noauthpass = 0;
    110 	svr_opts.norootpass = 0;
    111 	svr_opts.inetdmode = 0;
    112 	svr_opts.portcount = 0;
    113 	svr_opts.hostkey = NULL;
    114 	svr_opts.pidfile = DROPBEAR_PIDFILE;
    115 #ifdef ENABLE_SVR_LOCALTCPFWD
    116 	svr_opts.nolocaltcp = 0;
    117 #endif
    118 #ifdef ENABLE_SVR_REMOTETCPFWD
    119 	svr_opts.noremotetcp = 0;
    120 #endif
    121 	/* not yet
    122 	opts.ipv4 = 1;
    123 	opts.ipv6 = 1;
    124 	*/
    125 #ifdef DO_MOTD
    126 	svr_opts.domotd = 1;
    127 #endif
    128 #ifndef DISABLE_SYSLOG
    129 	svr_opts.usingsyslog = 1;
    130 #endif
    131 #ifdef ENABLE_SVR_REMOTETCPFWD
    132 	opts.listen_fwd_all = 0;
    133 #endif
    134 
    135 	for (i = 1; i < (unsigned int)argc; i++) {
    136 		if (nextisport) {
    137 			addportandaddress(argv[i]);
    138 			nextisport = 0;
    139 			continue;
    140 		}
    141 
    142 		if (next) {
    143 			*next = argv[i];
    144 			if (*next == NULL) {
    145 				dropbear_exit("Invalid null argument");
    146 			}
    147 			next = 0x00;
    148 			continue;
    149 		}
    150 
    151 		if (argv[i][0] == '-') {
    152 			switch (argv[i][1]) {
    153 				case 'b':
    154 					next = &svr_opts.bannerfile;
    155 					break;
    156 #ifdef DROPBEAR_DSS
    157 				case 'd':
    158 					next = &svr_opts.dsskeyfile;
    159 					break;
    160 #endif
    161 #ifdef DROPBEAR_RSA
    162 				case 'r':
    163 					next = &svr_opts.rsakeyfile;
    164 					break;
    165 #endif
    166 				case 'F':
    167 					svr_opts.forkbg = 0;
    168 					break;
    169 #ifndef DISABLE_SYSLOG
    170 				case 'E':
    171 					svr_opts.usingsyslog = 0;
    172 					break;
    173 #endif
    174 #ifdef ENABLE_SVR_LOCALTCPFWD
    175 				case 'j':
    176 					svr_opts.nolocaltcp = 1;
    177 					break;
    178 #endif
    179 #ifdef ENABLE_SVR_REMOTETCPFWD
    180 				case 'k':
    181 					svr_opts.noremotetcp = 1;
    182 					break;
    183 				case 'a':
    184 					opts.listen_fwd_all = 1;
    185 					break;
    186 #endif
    187 #ifdef INETD_MODE
    188 				case 'i':
    189 					svr_opts.inetdmode = 1;
    190 					break;
    191 #endif
    192 				case 'p':
    193 				  nextisport = 1;
    194 				  break;
    195 				case 'P':
    196 					next = &svr_opts.pidfile;
    197 					break;
    198 #ifdef DO_MOTD
    199 				/* motd is displayed by default, -m turns it off */
    200 				case 'm':
    201 					svr_opts.domotd = 0;
    202 					break;
    203 #endif
    204 				case 'w':
    205 					svr_opts.norootlogin = 1;
    206 					break;
    207 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
    208 				case 's':
    209 					svr_opts.noauthpass = 1;
    210 					break;
    211 				case 'g':
    212 					svr_opts.norootpass = 1;
    213 					break;
    214 #endif
    215 				case 'h':
    216 					printhelp(argv[0]);
    217 					exit(EXIT_FAILURE);
    218 					break;
    219 #ifdef DEBUG_TRACE
    220 				case 'v':
    221 					debug_trace = 1;
    222 					break;
    223 #endif
    224 				default:
    225 					fprintf(stderr, "Unknown argument %s\n", argv[i]);
    226 					printhelp(argv[0]);
    227 					exit(EXIT_FAILURE);
    228 					break;
    229 			}
    230 		}
    231 	}
    232 
    233 	/* Set up listening ports */
    234 	if (svr_opts.portcount == 0) {
    235 		svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
    236 		svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
    237 		svr_opts.portcount = 1;
    238 	}
    239 
    240 	if (svr_opts.dsskeyfile == NULL) {
    241 		svr_opts.dsskeyfile = DSS_PRIV_FILENAME;
    242 	}
    243 	if (svr_opts.rsakeyfile == NULL) {
    244 		svr_opts.rsakeyfile = RSA_PRIV_FILENAME;
    245 	}
    246 
    247 	if (svr_opts.bannerfile) {
    248 		struct stat buf;
    249 		if (stat(svr_opts.bannerfile, &buf) != 0) {
    250 			dropbear_exit("Error opening banner file '%s'",
    251 					svr_opts.bannerfile);
    252 		}
    253 
    254 		if (buf.st_size > MAX_BANNER_SIZE) {
    255 			dropbear_exit("Banner file too large, max is %d bytes",
    256 					MAX_BANNER_SIZE);
    257 		}
    258 
    259 		svr_opts.banner = buf_new(buf.st_size);
    260 		if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
    261 			dropbear_exit("Error reading banner file '%s'",
    262 					svr_opts.bannerfile);
    263 		}
    264 		buf_setpos(svr_opts.banner, 0);
    265 	}
    266 
    267 }
    268 
    269 static void addportandaddress(char* spec) {
    270 
    271 	char *myspec = NULL;
    272 
    273 	if (svr_opts.portcount < DROPBEAR_MAX_PORTS) {
    274 
    275 		/* We don't free it, it becomes part of the runopt state */
    276 		myspec = m_strdup(spec);
    277 
    278 		/* search for ':', that separates address and port */
    279 		svr_opts.ports[svr_opts.portcount] = strchr(myspec, ':');
    280 
    281 		if (svr_opts.ports[svr_opts.portcount] == NULL) {
    282 			/* no ':' -> the whole string specifies just a port */
    283 			svr_opts.ports[svr_opts.portcount] = myspec;
    284 		} else {
    285 			/* Split the address/port */
    286 			svr_opts.ports[svr_opts.portcount][0] = '\0';
    287 			svr_opts.ports[svr_opts.portcount]++;
    288 			svr_opts.addresses[svr_opts.portcount] = myspec;
    289 		}
    290 
    291 		if (svr_opts.addresses[svr_opts.portcount] == NULL) {
    292 			/* no address given -> fill in the default address */
    293 			svr_opts.addresses[svr_opts.portcount] = m_strdup(DROPBEAR_DEFADDRESS);
    294 		}
    295 
    296 		if (svr_opts.ports[svr_opts.portcount][0] == '\0') {
    297 			/* empty port -> exit */
    298 			dropbear_exit("Bad port");
    299 		}
    300 
    301 		svr_opts.portcount++;
    302 	}
    303 }
    304 
    305 static void disablekey(int type, const char* filename) {
    306 
    307 	int i;
    308 
    309 	for (i = 0; sshhostkey[i].name != NULL; i++) {
    310 		if (sshhostkey[i].val == type) {
    311 			sshhostkey[i].usable = 0;
    312 			break;
    313 		}
    314 	}
    315 	dropbear_log(LOG_WARNING, "Failed reading '%s', disabling %s", filename,
    316 			type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
    317 }
    318 
    319 /* Must be called after syslog/etc is working */
    320 void loadhostkeys() {
    321 
    322 	int ret;
    323 	int type;
    324 
    325 	TRACE(("enter loadhostkeys"))
    326 
    327 	svr_opts.hostkey = new_sign_key();
    328 
    329 #ifdef DROPBEAR_RSA
    330 	type = DROPBEAR_SIGNKEY_RSA;
    331 	ret = readhostkey(svr_opts.rsakeyfile, svr_opts.hostkey, &type);
    332 	if (ret == DROPBEAR_FAILURE) {
    333 		disablekey(DROPBEAR_SIGNKEY_RSA, svr_opts.rsakeyfile);
    334 	}
    335 #endif
    336 #ifdef DROPBEAR_DSS
    337 	type = DROPBEAR_SIGNKEY_DSS;
    338 	ret = readhostkey(svr_opts.dsskeyfile, svr_opts.hostkey, &type);
    339 	if (ret == DROPBEAR_FAILURE) {
    340 		disablekey(DROPBEAR_SIGNKEY_DSS, svr_opts.dsskeyfile);
    341 	}
    342 #endif
    343 
    344 	if ( 1
    345 #ifdef DROPBEAR_DSS
    346 		&& svr_opts.hostkey->dsskey == NULL
    347 #endif
    348 #ifdef DROPBEAR_RSA
    349 		&& svr_opts.hostkey->rsakey == NULL
    350 #endif
    351 		) {
    352 		dropbear_exit("No hostkeys available");
    353 	}
    354 
    355 	TRACE(("leave loadhostkeys"))
    356 }
    357