svr-runopts.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  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. #include "includes.h"
  25. #include "runopts.h"
  26. #include "signkey.h"
  27. #include "buffer.h"
  28. #include "dbutil.h"
  29. #include "algo.h"
  30. #include "ecdsa.h"
  31. svr_runopts svr_opts; /* GLOBAL */
  32. static void printhelp(const char * progname);
  33. static void addportandaddress(const char* spec);
  34. static void loadhostkey(const char *keyfile, int fatal_duplicate);
  35. static void addhostkey(const char *keyfile);
  36. static void printhelp(const char * progname) {
  37. fprintf(stderr, "Dropbear server v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
  38. "Usage: %s [options]\n"
  39. "-b bannerfile Display the contents of bannerfile"
  40. " before user login\n"
  41. " (default: none)\n"
  42. "-r keyfile Specify hostkeys (repeatable)\n"
  43. " defaults: \n"
  44. #ifdef DROPBEAR_DSS
  45. " dss %s\n"
  46. #endif
  47. #ifdef DROPBEAR_RSA
  48. " rsa %s\n"
  49. #endif
  50. #ifdef DROPBEAR_ECDSA
  51. " ecdsa %s\n"
  52. #endif
  53. #ifdef DROPBEAR_DELAY_HOSTKEY
  54. "-R Create hostkeys as required\n"
  55. #endif
  56. "-F Don't fork into background\n"
  57. #ifdef DISABLE_SYSLOG
  58. "(Syslog support not compiled in, using stderr)\n"
  59. #else
  60. "-E Log to stderr rather than syslog\n"
  61. #endif
  62. #ifdef DO_MOTD
  63. "-m Don't display the motd on login\n"
  64. #endif
  65. "-w Disallow root logins\n"
  66. #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
  67. "-s Disable password logins\n"
  68. "-g Disable password logins for root\n"
  69. "-B Allow blank password logins\n"
  70. #endif
  71. #ifdef ENABLE_SVR_LOCALTCPFWD
  72. "-j Disable local port forwarding\n"
  73. #endif
  74. #ifdef ENABLE_SVR_REMOTETCPFWD
  75. "-k Disable remote port forwarding\n"
  76. "-a Allow connections to forwarded ports from any host\n"
  77. #endif
  78. "-p [address:]port\n"
  79. " Listen on specified tcp port (and optionally address),\n"
  80. " up to %d can be specified\n"
  81. " (default port is %s if none specified)\n"
  82. "-P PidFile Create pid file PidFile\n"
  83. " (default %s)\n"
  84. #ifdef INETD_MODE
  85. "-i Start for inetd\n"
  86. #endif
  87. "-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
  88. "-K <keepalive> (0 is never, default %d, in seconds)\n"
  89. "-I <idle_timeout> (0 is never, default %d, in seconds)\n"
  90. "-V Version\n"
  91. #ifdef DEBUG_TRACE
  92. "-v verbose (compiled with DEBUG_TRACE)\n"
  93. #endif
  94. ,DROPBEAR_VERSION, progname,
  95. #ifdef DROPBEAR_DSS
  96. DSS_PRIV_FILENAME,
  97. #endif
  98. #ifdef DROPBEAR_RSA
  99. RSA_PRIV_FILENAME,
  100. #endif
  101. #ifdef DROPBEAR_ECDSA
  102. ECDSA_PRIV_FILENAME,
  103. #endif
  104. DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
  105. DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
  106. }
  107. void svr_getopts(int argc, char ** argv) {
  108. unsigned int i, j;
  109. char ** next = 0;
  110. int nextisport = 0;
  111. char* recv_window_arg = NULL;
  112. char* keepalive_arg = NULL;
  113. char* idle_timeout_arg = NULL;
  114. char* keyfile = NULL;
  115. char c;
  116. /* see printhelp() for options */
  117. svr_opts.bannerfile = NULL;
  118. svr_opts.banner = NULL;
  119. svr_opts.forkbg = 1;
  120. svr_opts.norootlogin = 0;
  121. svr_opts.noauthpass = 0;
  122. svr_opts.norootpass = 0;
  123. svr_opts.allowblankpass = 0;
  124. svr_opts.inetdmode = 0;
  125. svr_opts.portcount = 0;
  126. svr_opts.hostkey = NULL;
  127. svr_opts.delay_hostkey = 0;
  128. svr_opts.pidfile = DROPBEAR_PIDFILE;
  129. #ifdef ENABLE_SVR_LOCALTCPFWD
  130. svr_opts.nolocaltcp = 0;
  131. #endif
  132. #ifdef ENABLE_SVR_REMOTETCPFWD
  133. svr_opts.noremotetcp = 0;
  134. #endif
  135. #ifndef DISABLE_ZLIB
  136. #if DROPBEAR_SERVER_DELAY_ZLIB
  137. opts.compress_mode = DROPBEAR_COMPRESS_DELAYED;
  138. #else
  139. opts.compress_mode = DROPBEAR_COMPRESS_ON;
  140. #endif
  141. #endif
  142. /* not yet
  143. opts.ipv4 = 1;
  144. opts.ipv6 = 1;
  145. */
  146. #ifdef DO_MOTD
  147. svr_opts.domotd = 1;
  148. #endif
  149. #ifndef DISABLE_SYSLOG
  150. opts.usingsyslog = 1;
  151. #endif
  152. opts.recv_window = DEFAULT_RECV_WINDOW;
  153. opts.keepalive_secs = DEFAULT_KEEPALIVE;
  154. opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
  155. #ifdef ENABLE_SVR_REMOTETCPFWD
  156. opts.listen_fwd_all = 0;
  157. #endif
  158. for (i = 1; i < (unsigned int)argc; i++) {
  159. if (argv[i][0] != '-' || argv[i][1] == '\0')
  160. dropbear_exit("Invalid argument: %s", argv[i]);
  161. for (j = 1; (c = argv[i][j]) != '\0' && !next && !nextisport; j++) {
  162. switch (c) {
  163. case 'b':
  164. next = &svr_opts.bannerfile;
  165. break;
  166. case 'd':
  167. case 'r':
  168. next = &keyfile;
  169. break;
  170. case 'R':
  171. svr_opts.delay_hostkey = 1;
  172. break;
  173. case 'F':
  174. svr_opts.forkbg = 0;
  175. break;
  176. #ifndef DISABLE_SYSLOG
  177. case 'E':
  178. opts.usingsyslog = 0;
  179. break;
  180. #endif
  181. #ifdef ENABLE_SVR_LOCALTCPFWD
  182. case 'j':
  183. svr_opts.nolocaltcp = 1;
  184. break;
  185. #endif
  186. #ifdef ENABLE_SVR_REMOTETCPFWD
  187. case 'k':
  188. svr_opts.noremotetcp = 1;
  189. break;
  190. case 'a':
  191. opts.listen_fwd_all = 1;
  192. break;
  193. #endif
  194. #ifdef INETD_MODE
  195. case 'i':
  196. svr_opts.inetdmode = 1;
  197. break;
  198. #endif
  199. case 'p':
  200. nextisport = 1;
  201. break;
  202. case 'P':
  203. next = &svr_opts.pidfile;
  204. break;
  205. #ifdef DO_MOTD
  206. /* motd is displayed by default, -m turns it off */
  207. case 'm':
  208. svr_opts.domotd = 0;
  209. break;
  210. #endif
  211. case 'w':
  212. svr_opts.norootlogin = 1;
  213. break;
  214. case 'W':
  215. next = &recv_window_arg;
  216. break;
  217. case 'K':
  218. next = &keepalive_arg;
  219. break;
  220. case 'I':
  221. next = &idle_timeout_arg;
  222. break;
  223. #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
  224. case 's':
  225. svr_opts.noauthpass = 1;
  226. break;
  227. case 'g':
  228. svr_opts.norootpass = 1;
  229. break;
  230. case 'B':
  231. svr_opts.allowblankpass = 1;
  232. break;
  233. #endif
  234. case 'h':
  235. printhelp(argv[0]);
  236. exit(EXIT_SUCCESS);
  237. break;
  238. case 'u':
  239. /* backwards compatibility with old urandom option */
  240. break;
  241. #ifdef DEBUG_TRACE
  242. case 'v':
  243. debug_trace = 1;
  244. break;
  245. #endif
  246. case 'V':
  247. print_version();
  248. exit(EXIT_SUCCESS);
  249. break;
  250. default:
  251. fprintf(stderr, "Invalid option -%c\n", c);
  252. printhelp(argv[0]);
  253. exit(EXIT_FAILURE);
  254. break;
  255. }
  256. }
  257. if (!next && !nextisport)
  258. continue;
  259. if (c == '\0') {
  260. i++;
  261. j = 0;
  262. if (!argv[i]) {
  263. dropbear_exit("Missing argument");
  264. }
  265. }
  266. if (nextisport) {
  267. addportandaddress(&argv[i][j]);
  268. nextisport = 0;
  269. } else if (next) {
  270. *next = &argv[i][j];
  271. if (*next == NULL) {
  272. dropbear_exit("Invalid null argument");
  273. }
  274. next = 0x00;
  275. if (keyfile) {
  276. addhostkey(keyfile);
  277. keyfile = NULL;
  278. }
  279. }
  280. }
  281. /* Set up listening ports */
  282. if (svr_opts.portcount == 0) {
  283. svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
  284. svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS);
  285. svr_opts.portcount = 1;
  286. }
  287. if (svr_opts.bannerfile) {
  288. struct stat buf;
  289. if (stat(svr_opts.bannerfile, &buf) != 0) {
  290. dropbear_exit("Error opening banner file '%s'",
  291. svr_opts.bannerfile);
  292. }
  293. if (buf.st_size > MAX_BANNER_SIZE) {
  294. dropbear_exit("Banner file too large, max is %d bytes",
  295. MAX_BANNER_SIZE);
  296. }
  297. svr_opts.banner = buf_new(buf.st_size);
  298. if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
  299. dropbear_exit("Error reading banner file '%s'",
  300. svr_opts.bannerfile);
  301. }
  302. buf_setpos(svr_opts.banner, 0);
  303. }
  304. if (recv_window_arg) {
  305. opts.recv_window = atol(recv_window_arg);
  306. if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
  307. dropbear_exit("Bad recv window '%s'", recv_window_arg);
  308. }
  309. }
  310. if (keepalive_arg) {
  311. unsigned int val;
  312. if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
  313. dropbear_exit("Bad keepalive '%s'", keepalive_arg);
  314. }
  315. opts.keepalive_secs = val;
  316. }
  317. if (idle_timeout_arg) {
  318. unsigned int val;
  319. if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
  320. dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
  321. }
  322. opts.idle_timeout_secs = val;
  323. }
  324. }
  325. static void addportandaddress(const char* spec) {
  326. char *spec_copy = NULL, *myspec = NULL, *port = NULL, *address = NULL;
  327. if (svr_opts.portcount < DROPBEAR_MAX_PORTS) {
  328. /* We don't free it, it becomes part of the runopt state */
  329. spec_copy = m_strdup(spec);
  330. myspec = spec_copy;
  331. if (myspec[0] == '[') {
  332. myspec++;
  333. port = strchr(myspec, ']');
  334. if (!port) {
  335. /* Unmatched [ -> exit */
  336. dropbear_exit("Bad listen address");
  337. }
  338. port[0] = '\0';
  339. port++;
  340. if (port[0] != ':') {
  341. /* Missing port -> exit */
  342. dropbear_exit("Missing port");
  343. }
  344. } else {
  345. /* search for ':', that separates address and port */
  346. port = strrchr(myspec, ':');
  347. }
  348. if (!port) {
  349. /* no ':' -> the whole string specifies just a port */
  350. port = myspec;
  351. } else {
  352. /* Split the address/port */
  353. port[0] = '\0';
  354. port++;
  355. address = myspec;
  356. }
  357. if (!address) {
  358. /* no address given -> fill in the default address */
  359. address = DROPBEAR_DEFADDRESS;
  360. }
  361. if (port[0] == '\0') {
  362. /* empty port -> exit */
  363. dropbear_exit("Bad port");
  364. }
  365. svr_opts.ports[svr_opts.portcount] = m_strdup(port);
  366. svr_opts.addresses[svr_opts.portcount] = m_strdup(address);
  367. svr_opts.portcount++;
  368. m_free(spec_copy);
  369. }
  370. }
  371. static void disablekey(int type) {
  372. int i;
  373. TRACE(("Disabling key type %d", type))
  374. for (i = 0; sshhostkey[i].name != NULL; i++) {
  375. if (sshhostkey[i].val == type) {
  376. sshhostkey[i].usable = 0;
  377. break;
  378. }
  379. }
  380. }
  381. static void loadhostkey_helper(const char *name, void** src, void** dst, int fatal_duplicate) {
  382. if (*dst) {
  383. if (fatal_duplicate) {
  384. dropbear_exit("Only one %s key can be specified", name);
  385. }
  386. } else {
  387. *dst = *src;
  388. *src = NULL;
  389. }
  390. }
  391. /* Must be called after syslog/etc is working */
  392. static void loadhostkey(const char *keyfile, int fatal_duplicate) {
  393. sign_key * read_key = new_sign_key();
  394. enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
  395. if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
  396. if (!svr_opts.delay_hostkey) {
  397. dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
  398. }
  399. }
  400. #ifdef DROPBEAR_RSA
  401. if (type == DROPBEAR_SIGNKEY_RSA) {
  402. loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate);
  403. }
  404. #endif
  405. #ifdef DROPBEAR_DSS
  406. if (type == DROPBEAR_SIGNKEY_DSS) {
  407. loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate);
  408. }
  409. #endif
  410. #ifdef DROPBEAR_ECDSA
  411. #ifdef DROPBEAR_ECC_256
  412. if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
  413. loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate);
  414. }
  415. #endif
  416. #ifdef DROPBEAR_ECC_384
  417. if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
  418. loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate);
  419. }
  420. #endif
  421. #ifdef DROPBEAR_ECC_521
  422. if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
  423. loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate);
  424. }
  425. #endif
  426. #endif /* DROPBEAR_ECDSA */
  427. sign_key_free(read_key);
  428. TRACE(("leave loadhostkey"))
  429. }
  430. static void addhostkey(const char *keyfile) {
  431. if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
  432. dropbear_exit("Too many hostkeys");
  433. }
  434. svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
  435. svr_opts.num_hostkey_files++;
  436. }
  437. void load_all_hostkeys() {
  438. int i;
  439. int disable_unset_keys = 1;
  440. int any_keys = 0;
  441. svr_opts.hostkey = new_sign_key();
  442. for (i = 0; i < svr_opts.num_hostkey_files; i++) {
  443. char *hostkey_file = svr_opts.hostkey_files[i];
  444. loadhostkey(hostkey_file, 1);
  445. m_free(hostkey_file);
  446. }
  447. #ifdef DROPBEAR_RSA
  448. loadhostkey(RSA_PRIV_FILENAME, 0);
  449. #endif
  450. #ifdef DROPBEAR_DSS
  451. loadhostkey(DSS_PRIV_FILENAME, 0);
  452. #endif
  453. #ifdef DROPBEAR_ECDSA
  454. loadhostkey(ECDSA_PRIV_FILENAME, 0);
  455. #endif
  456. #ifdef DROPBEAR_DELAY_HOSTKEY
  457. if (svr_opts.delay_hostkey) {
  458. disable_unset_keys = 0;
  459. }
  460. #endif
  461. #ifdef DROPBEAR_RSA
  462. if (disable_unset_keys && !svr_opts.hostkey->rsakey) {
  463. disablekey(DROPBEAR_SIGNKEY_RSA);
  464. } else {
  465. any_keys = 1;
  466. }
  467. #endif
  468. #ifdef DROPBEAR_DSS
  469. if (disable_unset_keys && !svr_opts.hostkey->dsskey) {
  470. disablekey(DROPBEAR_SIGNKEY_DSS);
  471. } else {
  472. any_keys = 1;
  473. }
  474. #endif
  475. #ifdef DROPBEAR_ECDSA
  476. #ifdef DROPBEAR_ECC_256
  477. if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 256)
  478. && !svr_opts.hostkey->ecckey256) {
  479. disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
  480. } else {
  481. any_keys = 1;
  482. }
  483. #endif
  484. #ifdef DROPBEAR_ECC_384
  485. if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 384)
  486. && !svr_opts.hostkey->ecckey384) {
  487. disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
  488. } else {
  489. any_keys = 1;
  490. }
  491. #endif
  492. #ifdef DROPBEAR_ECC_521
  493. if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 521)
  494. && !svr_opts.hostkey->ecckey521) {
  495. disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
  496. } else {
  497. any_keys = 1;
  498. }
  499. #endif
  500. #endif /* DROPBEAR_ECDSA */
  501. if (!any_keys) {
  502. dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
  503. }
  504. }