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