klishd.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. #define _GNU_SOURCE
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <assert.h>
  7. #include <signal.h>
  8. #include <syslog.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #include <getopt.h>
  15. #include <sys/socket.h>
  16. #include <sys/un.h>
  17. #include <sys/fsuid.h>
  18. #include <sys/wait.h>
  19. #include <poll.h>
  20. #include <time.h>
  21. #include <faux/faux.h>
  22. #include <faux/str.h>
  23. #include <faux/ini.h>
  24. #include <faux/log.h>
  25. #include <faux/sched.h>
  26. #include <faux/sysdb.h>
  27. #include <faux/net.h>
  28. #include <faux/list.h>
  29. #include <faux/conv.h>
  30. #include <faux/file.h>
  31. #include <crsp.h>
  32. #include <crsp_cdp.h>
  33. #include <crsp_hl.h>
  34. #ifndef VERSION
  35. #define VERSION "1.0.0"
  36. #endif
  37. #define CRSD_LOG_NAME "crsd"
  38. #define CRSD_DEFAULT_PIDFILE "/var/run/crsd.pid"
  39. #define CRSD_DEFAULT_CFGFILE "/etc/crs/crsd.conf"
  40. #define CRSD_DEFAULT_FETCH_INTERVAL 120
  41. #define CRSD_DEFAULT_FETCH_MARGIN 50
  42. #define CRSD_DEFAULT_FETCH_TIMEOUT 60
  43. #define CRSD_DEFAULT_CRL_MAX_SIZE 50000000ul
  44. #define CRSD_DEFAULT_CRL_STORAGE_MAX_SIZE 5000000000ul
  45. #define CRSD_DEFAULT_ROOTCERT_DIR "/etc/config/ike/ipsec.d/rootcerts"
  46. #define CRSD_DEFAULT_CACERT_DIR "/etc/config/ike/ipsec.d/cacerts"
  47. #define CRSD_DEFAULT_CERT_DIR "/etc/config/ike/ipsec.d/certs"
  48. #define CRSD_DEFAULT_OCSPCERT_DIR "/etc/config/ike/ipsec.d/ocspcerts"
  49. #define CRSD_DEFAULT_CRL_DIR "/etc/config/ike/ipsec.d/crls"
  50. #define CRSD_DEFAULT_KEY_DIR "/etc/config/ike/ipsec.d/private"
  51. #define CRSD_DEFAULT_P10_DIR "/etc/config/ike/ipsec.d/reqs"
  52. #define CRSD_DEFAULT_SECRETS_FILE "/etc/config/ike/ipsec.secrets"
  53. // Signal handlers
  54. static volatile int sigterm = 0; // Exit if 1
  55. static void sighandler(int signo);
  56. static volatile int sighup = 0; // Re-read config file
  57. static void sighup_handler(int signo);
  58. static volatile int sigchld = 0; // Child execution is finished
  59. static void sigchld_handler(int signo);
  60. // Options and config file
  61. static void help(int status, const char *argv0);
  62. static struct options *opts_init(void);
  63. static void opts_free(struct options *opts);
  64. static int opts_parse(int argc, char *argv[], struct options *opts);
  65. static int opts_show(struct options *opts);
  66. static int config_parse(const char *cfgfile, struct options *opts);
  67. // Local syslog function
  68. bool_t verbose = BOOL_FALSE;
  69. bool_t silent = BOOL_FALSE;
  70. static void lsyslog(int priority, const char *format, ...)
  71. {
  72. va_list ap;
  73. if (silent)
  74. return;
  75. if (!verbose && (LOG_DEBUG == priority))
  76. return;
  77. // Calculate buffer size
  78. va_start(ap, format);
  79. vsyslog(priority, format, ap);
  80. va_end(ap);
  81. }
  82. /** @brief Command line and config file options
  83. */
  84. struct options {
  85. char *pidfile;
  86. char *cfgfile;
  87. char *unix_socket_path;
  88. bool_t cfgfile_userdefined;
  89. bool_t foreground; // Don't daemonize
  90. bool_t verbose;
  91. bool_t silent;
  92. bool_t check;
  93. int log_facility;
  94. char *uid_str;
  95. char *gid_str;
  96. uid_t uid;
  97. gid_t gid;
  98. long int fetch_interval;
  99. unsigned char fetch_margin;
  100. long int fetch_timeout;
  101. unsigned long int crl_max_size;
  102. unsigned long int crl_storage_max_size;
  103. char *rootcert_dir;
  104. char *cacert_dir;
  105. char *cert_dir;
  106. char *ocspcert_dir;
  107. char *crl_dir;
  108. char *key_dir;
  109. char *p10_dir;
  110. char *secrets_file;
  111. };
  112. // Network
  113. static int create_listen_sock(const char *path, uid_t uid, gid_t gid);
  114. /** @brief Main function
  115. */
  116. int main(int argc, char **argv)
  117. {
  118. int retval = -1;
  119. struct options *opts = NULL;
  120. int pidfd = -1;
  121. int logmask = 0;
  122. int logoptions = 0;
  123. // Event scheduler
  124. faux_sched_t *sched = NULL;
  125. // Network
  126. int listen_sock = -1;
  127. faux_pollfd_t *fds = NULL;
  128. // Signal vars
  129. struct sigaction sig_act = {};
  130. sigset_t sig_set = {};
  131. sigset_t orig_sig_set = {}; // Saved signal mask
  132. // Parse command line options
  133. opts = opts_init();
  134. if (opts_parse(argc, argv, opts))
  135. goto err;
  136. // Initialize syslog
  137. logoptions = LOG_CONS;
  138. if (opts->foreground)
  139. logoptions |= LOG_PERROR;
  140. openlog(CRSD_LOG_NAME, logoptions, opts->log_facility);
  141. if (!opts->verbose) {
  142. logmask = setlogmask(0);
  143. logmask = logmask & ~LOG_MASK(LOG_DEBUG);
  144. setlogmask(logmask);
  145. }
  146. // Parse config file
  147. lsyslog(LOG_DEBUG, "Parse config file: %s\n", opts->cfgfile);
  148. if (!access(opts->cfgfile, R_OK)) {
  149. if (config_parse(opts->cfgfile, opts))
  150. goto err;
  151. } else if (opts->cfgfile_userdefined) {
  152. // User defined config must be found
  153. fprintf(stderr, "Error: Can't find config file %s\n",
  154. opts->cfgfile);
  155. goto err;
  156. }
  157. if (opts->check) { // Check only. Return 0 if config file is ok.
  158. retval = 0;
  159. goto err;
  160. }
  161. // DEBUG: Show options
  162. opts_show(opts);
  163. // Set crsp lib global var for debug
  164. if (opts->verbose)
  165. crsp_debug = 1;
  166. lsyslog(LOG_INFO, "Start daemon.\n");
  167. // Fork the daemon
  168. if (!opts->foreground) {
  169. // Daemonize
  170. lsyslog(LOG_DEBUG, "Daemonize\n");
  171. if (daemon(0, 0) < 0) {
  172. lsyslog(LOG_ERR, "Can't daemonize\n");
  173. goto err;
  174. }
  175. // Write pidfile
  176. lsyslog(LOG_DEBUG, "Write PID file: %s\n", opts->pidfile);
  177. if ((pidfd = open(opts->pidfile,
  178. O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
  179. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
  180. lsyslog(LOG_WARNING, "Can't open pidfile %s: %s\n",
  181. opts->pidfile, strerror(errno));
  182. } else {
  183. char str[20];
  184. snprintf(str, sizeof(str), "%u\n", getpid());
  185. str[sizeof(str) - 1] = '\0';
  186. if (write(pidfd, str, strlen(str)) < 0)
  187. lsyslog(LOG_WARNING, "Can't write to %s: %s\n",
  188. opts->pidfile, strerror(errno));
  189. close(pidfd);
  190. }
  191. }
  192. // Network initialization
  193. lsyslog(LOG_DEBUG, "Create listen socket: %s\n", opts->unix_socket_path);
  194. listen_sock = create_listen_sock(opts->unix_socket_path,
  195. opts->uid, opts->gid);
  196. if (listen_sock < 0)
  197. goto err;
  198. // Change UID/GID
  199. if (opts->uid != getuid()) {
  200. lsyslog(LOG_DEBUG, "Change UID: %s\n", opts->uid_str ? opts->uid_str : "");
  201. setfsuid(opts->uid);
  202. if (setresuid(opts->uid, opts->uid, opts->uid) < 0) {
  203. lsyslog(LOG_ERR, "Can't change user: %s", strerror(errno));
  204. goto err;
  205. }
  206. }
  207. if (opts->gid != getgid()) {
  208. lsyslog(LOG_DEBUG, "Change GID: %s\n", opts->gid_str ? opts->gid_str : "");
  209. if (setresgid(opts->gid, opts->gid, opts->gid) < 0 ) {
  210. lsyslog(LOG_ERR, "Can't change group: %s", strerror(errno));
  211. goto err;
  212. }
  213. }
  214. // Set signal handler
  215. lsyslog(LOG_DEBUG, "Set signal handlers\n");
  216. sigemptyset(&sig_set);
  217. sigaddset(&sig_set, SIGTERM);
  218. sigaddset(&sig_set, SIGINT);
  219. sigaddset(&sig_set, SIGQUIT);
  220. sig_act.sa_flags = 0;
  221. sig_act.sa_mask = sig_set;
  222. sig_act.sa_handler = &sighandler;
  223. sigaction(SIGTERM, &sig_act, NULL);
  224. sigaction(SIGINT, &sig_act, NULL);
  225. sigaction(SIGQUIT, &sig_act, NULL);
  226. // SIGHUP handler
  227. sigemptyset(&sig_set);
  228. sigaddset(&sig_set, SIGHUP);
  229. sig_act.sa_flags = 0;
  230. sig_act.sa_mask = sig_set;
  231. sig_act.sa_handler = &sighup_handler;
  232. sigaction(SIGHUP, &sig_act, NULL);
  233. // SIGCHLD handler
  234. sigemptyset(&sig_set);
  235. sigaddset(&sig_set, SIGCHLD);
  236. sig_act.sa_flags = 0;
  237. sig_act.sa_mask = sig_set;
  238. sig_act.sa_handler = &sigchld_handler;
  239. sigaction(SIGCHLD, &sig_act, NULL);
  240. // The struct pollfd vector for ppoll()
  241. fds = faux_pollfd_new();
  242. if (!fds) {
  243. lsyslog(LOG_ERR, "Can't init pollfd vector");
  244. goto err;
  245. }
  246. // Add listen socket to pollfds vector
  247. faux_pollfd_add(fds, listen_sock, POLLIN);
  248. // Block signals to prevent race conditions while loop and ppoll()
  249. // Catch signals while ppoll() only
  250. sigemptyset(&sig_set);
  251. sigaddset(&sig_set, SIGTERM);
  252. sigaddset(&sig_set, SIGINT);
  253. sigaddset(&sig_set, SIGQUIT);
  254. sigaddset(&sig_set, SIGHUP);
  255. sigaddset(&sig_set, SIGCHLD);
  256. sigprocmask(SIG_BLOCK, &sig_set, &orig_sig_set);
  257. // Main loop
  258. while (!sigterm) {
  259. int sn = 0;
  260. struct timespec *timeout = NULL;
  261. struct timespec next_interval = {};
  262. faux_pollfd_iterator_t pollfd_iter;
  263. struct pollfd *pollfd = NULL;
  264. pid_t pid = -1;
  265. // Re-read config file on SIGHUP
  266. if (sighup) {
  267. if (access(opts->cfgfile, R_OK) == 0) {
  268. lsyslog(LOG_INFO, "Re-reading config file\n");
  269. if (config_parse(opts->cfgfile, opts) < 0)
  270. lsyslog(LOG_ERR, "Error while config file parsing.\n");
  271. reschedule_all(sched, cdp_db,
  272. opts->fetch_interval,
  273. opts->fetch_margin);
  274. } else if (opts->cfgfile_userdefined) {
  275. lsyslog(LOG_ERR, "Can't find config file.\n");
  276. }
  277. sighup = 0;
  278. }
  279. // Non-blocking wait for all children
  280. while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
  281. lsyslog(LOG_DEBUG, "Exit child process %d\n", pid);
  282. }
  283. sigchld = 0;
  284. // Find out timeout interval
  285. if (faux_sched_next_interval(sched, &next_interval) < 0) {
  286. timeout = NULL;
  287. } else {
  288. timeout = &next_interval;
  289. lsyslog(LOG_DEBUG, "Next interval: %ld\n", timeout->tv_sec);
  290. }
  291. // Wait for events
  292. sn = ppoll(faux_pollfd_vector(fds), faux_pollfd_len(fds), timeout, &orig_sig_set);
  293. if (sn < 0) {
  294. if ((EAGAIN == errno) || (EINTR == errno))
  295. continue;
  296. lsyslog(LOG_ERR, "Error while select(): %s\n", strerror(errno));
  297. break;
  298. }
  299. // Timeout (Scheduled event)
  300. if (0 == sn) {
  301. int id = 0; // Event idenftifier
  302. void *data = NULL; // Event data
  303. // Some scheduled events
  304. while(faux_sched_pop(sched, &id, &data) == 0) {
  305. cdp_t *cdp = (cdp_t *)data;
  306. download_args_t download_args = {};
  307. // Now we have only one type of event - it's
  308. // a scheduled CRL downloading
  309. lsyslog(LOG_DEBUG, "sched: Update event for %s\n", cdp_uri(cdp));
  310. download_args.cdp = cdp;
  311. download_args.opts = opts;
  312. fork_action(download_crl, (void *)&download_args);
  313. }
  314. continue;
  315. }
  316. // Get data via socket
  317. faux_pollfd_init_iterator(fds, &pollfd_iter);
  318. while ((pollfd = faux_pollfd_each_active(fds, &pollfd_iter))) {
  319. crsp_msg_t *req = NULL;
  320. crsp_msg_t *ack = NULL;
  321. faux_net_t *net = NULL;
  322. int fd = pollfd->fd;
  323. crsp_recv_e recv_status = CRSP_RECV_OK;
  324. // Listen socket
  325. if (fd == listen_sock) {
  326. int new_conn = -1;
  327. new_conn = accept(listen_sock, NULL, NULL);
  328. if (new_conn < 0)
  329. continue;
  330. faux_pollfd_add(fds, new_conn, POLLIN);
  331. lsyslog(LOG_DEBUG, "New connection %d\n", new_conn);
  332. continue;
  333. }
  334. // If it's not a listen socket then we have received
  335. // a message from client.
  336. net = faux_net_new();
  337. faux_net_set_fd(net, fd);
  338. // Get message
  339. req = crsp_msg_recv(net, &recv_status);
  340. // Prepare empty answer structure
  341. ack = crsp_msg_new();
  342. // Compose answer
  343. if (req) {
  344. msg_cb_f *handler =
  345. msg_handler[crsp_msg_get_cmd(req)];
  346. crsp_msg_t *answer = NULL;
  347. // Callback function fills the answer by
  348. // real data
  349. if (handler) {
  350. msg_cb_args_t args = {};
  351. args.cdp_db = cdp_db;
  352. args.sched = sched;
  353. args.opts = opts;
  354. args.credio = credio;
  355. args.net = net;
  356. answer = handler(req, ack, &args);
  357. if (!answer) { // Some local problem
  358. crsp_msg_set_cmd(ack, CRSP_CMD_ERROR);
  359. crsp_msg_set_status(ack, CRSP_STATUS_ERROR);
  360. }
  361. cdp_db_debug(cdp_db);
  362. // If there is no handler for this commnand just
  363. // return "unknown/unsupported command" message.
  364. } else {
  365. crsp_msg_set_cmd(ack, CRSP_CMD_ERROR);
  366. crsp_msg_set_status(ack, CRSP_STATUS_UNSUPPORTED);
  367. }
  368. // Some error while receiving
  369. } else {
  370. crsp_msg_set_cmd(ack, CRSP_CMD_ERROR);
  371. switch(recv_status) {
  372. case CRSP_RECV_OK: // Some system problem
  373. crsp_msg_set_status(ack, CRSP_STATUS_ERROR);
  374. break;
  375. default: // Classified problem
  376. // Now error codes of status is
  377. // equal to receive statuses. It can be
  378. // changed later.
  379. crsp_msg_set_status(ack, recv_status);
  380. break;
  381. }
  382. }
  383. // Send ACK
  384. crsp_msg_send(ack, net);
  385. crsp_msg_free(ack);
  386. crsp_msg_free(req);
  387. close(fd);
  388. faux_net_free(net);
  389. faux_pollfd_del_by_fd(fds, fd);
  390. lsyslog(LOG_DEBUG, "Close connection %d\n", fd);
  391. }
  392. } // Main loop end
  393. retval = 0;
  394. err:
  395. lsyslog(LOG_DEBUG, "Cleanup.\n");
  396. sigprocmask(SIG_BLOCK, &orig_sig_set, NULL);
  397. faux_pollfd_free(fds);
  398. faux_sched_free(sched);
  399. // Close listen socket
  400. if (listen_sock >= 0)
  401. close(listen_sock);
  402. // Clean CDP database
  403. cdp_db_free(cdp_db);
  404. // Remove pidfile
  405. if (pidfd >= 0) {
  406. if (unlink(opts->pidfile) < 0) {
  407. lsyslog(LOG_ERR, "Can't remove pid-file %s: %s\n",
  408. opts->pidfile, strerror(errno));
  409. }
  410. }
  411. // Crypto cleanup
  412. pgst_credio_free(&credio);
  413. pgst_cossl_free(&ossl);
  414. // Free command line options
  415. opts_free(opts);
  416. lsyslog(LOG_INFO, "Stop daemon.\n");
  417. return retval;
  418. }
  419. /** @brief Create listen socket
  420. */
  421. static int create_listen_sock(const char *path, uid_t uid, gid_t gid)
  422. {
  423. int sock = -1;
  424. int opt = 1;
  425. struct sockaddr_un laddr = {};
  426. // mode_t mode = 0660;
  427. if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  428. lsyslog(LOG_ERR, "Cannot create socket: %s\n", strerror(errno));
  429. goto error;
  430. }
  431. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
  432. lsyslog(LOG_ERR, "Can't set socket options: %s\n", strerror(errno));
  433. goto error;
  434. }
  435. laddr.sun_family = AF_UNIX;
  436. strncpy(laddr.sun_path, path, USOCK_PATH_MAX);
  437. laddr.sun_path[USOCK_PATH_MAX - 1] = '\0';
  438. unlink(path);
  439. if (bind(sock, (struct sockaddr *)&laddr, sizeof(laddr))) {
  440. lsyslog(LOG_ERR, "Can't bind socket: %s\n", strerror(errno));
  441. goto err2;
  442. }
  443. if (uid != getuid() || gid != getgid()) {
  444. if (chown(path, uid, gid)) {
  445. lsyslog(LOG_ERR, "Can't chown socket: %s\n", strerror(errno));
  446. goto err2;
  447. }
  448. }
  449. // if (chmod(path, mode)) {
  450. // lsyslog(LOG_ERR, "Can't chmod socket: %s\n", strerror(errno));
  451. // goto err2;
  452. // }
  453. if (listen(sock, 64)) {
  454. lsyslog(LOG_ERR, "Can't listen socket: %s\n", strerror(errno));
  455. goto err2;
  456. }
  457. return sock;
  458. err2:
  459. unlink(path);
  460. error:
  461. if (sock != -1)
  462. close(sock);
  463. return -1;
  464. }
  465. /** @brief Signal handler for temination signals (like SIGTERM, SIGINT, ...)
  466. */
  467. static void sighandler(int signo)
  468. {
  469. sigterm = 1;
  470. signo = signo; // Happy compiler
  471. }
  472. /** @brief Re-read config file on SIGHUP
  473. */
  474. static void sighup_handler(int signo)
  475. {
  476. sighup = 1;
  477. signo = signo; // Happy compiler
  478. }
  479. /** @brief Child was finished
  480. */
  481. static void sigchld_handler(int signo)
  482. {
  483. sigchld = 1;
  484. signo = signo; // Happy compiler
  485. }
  486. /** @brief Initialize option structure by defaults
  487. */
  488. static struct options *opts_init(void)
  489. {
  490. struct options *opts = NULL;
  491. opts = faux_zmalloc(sizeof(*opts));
  492. assert(opts);
  493. // Initialize
  494. opts->pidfile = faux_str_dup(CRSD_DEFAULT_PIDFILE);
  495. opts->cfgfile = faux_str_dup(CRSD_DEFAULT_CFGFILE);
  496. opts->unix_socket_path = faux_str_dup(CRSD_DEFAULT_UNIX_SOCKET_PATH);
  497. opts->cfgfile_userdefined = BOOL_FALSE;
  498. opts->foreground = BOOL_FALSE; // Daemonize by default
  499. opts->verbose = BOOL_FALSE;
  500. opts->silent = BOOL_FALSE;
  501. opts->check = BOOL_FALSE;
  502. opts->log_facility = LOG_DAEMON;
  503. opts->uid = getuid();
  504. opts->gid = getgid();
  505. opts->uid_str = faux_sysdb_name_by_uid(opts->uid);
  506. opts->gid_str = faux_sysdb_name_by_gid(opts->gid);
  507. opts->fetch_interval = CRSD_DEFAULT_FETCH_INTERVAL;
  508. opts->fetch_margin = CRSD_DEFAULT_FETCH_MARGIN;
  509. opts->fetch_timeout = CRSD_DEFAULT_FETCH_TIMEOUT;
  510. opts->crl_max_size = CRSD_DEFAULT_CRL_MAX_SIZE;
  511. opts->crl_storage_max_size = CRSD_DEFAULT_CRL_STORAGE_MAX_SIZE;
  512. opts->rootcert_dir = faux_str_dup(CRSD_DEFAULT_ROOTCERT_DIR);
  513. opts->cacert_dir = faux_str_dup(CRSD_DEFAULT_CACERT_DIR);
  514. opts->cert_dir = faux_str_dup(CRSD_DEFAULT_CERT_DIR);
  515. opts->ocspcert_dir = faux_str_dup(CRSD_DEFAULT_OCSPCERT_DIR);
  516. opts->crl_dir = faux_str_dup(CRSD_DEFAULT_CRL_DIR);
  517. opts->key_dir = faux_str_dup(CRSD_DEFAULT_KEY_DIR);
  518. opts->p10_dir = faux_str_dup(CRSD_DEFAULT_P10_DIR);
  519. opts->secrets_file = faux_str_dup(CRSD_DEFAULT_SECRETS_FILE);
  520. return opts;
  521. }
  522. /** @brief Free options structure
  523. */
  524. static void opts_free(struct options *opts)
  525. {
  526. faux_str_free(opts->pidfile);
  527. faux_str_free(opts->cfgfile);
  528. faux_str_free(opts->unix_socket_path);
  529. faux_str_free(opts->uid_str);
  530. faux_str_free(opts->gid_str);
  531. faux_str_free(opts->rootcert_dir);
  532. faux_str_free(opts->cacert_dir);
  533. faux_str_free(opts->cert_dir);
  534. faux_str_free(opts->ocspcert_dir);
  535. faux_str_free(opts->crl_dir);
  536. faux_str_free(opts->key_dir);
  537. faux_str_free(opts->p10_dir);
  538. faux_str_free(opts->secrets_file);
  539. faux_free(opts);
  540. }
  541. /** @brief Parse command line options
  542. */
  543. static int opts_parse(int argc, char *argv[], struct options *opts)
  544. {
  545. static const char *shortopts = "hp:c:fl:vsk";
  546. static const struct option longopts[] = {
  547. {"help", 0, NULL, 'h'},
  548. {"pid", 1, NULL, 'p'},
  549. {"conf", 1, NULL, 'c'},
  550. {"foreground", 0, NULL, 'f'},
  551. {"verbose", 0, NULL, 'v'},
  552. {"silent", 0, NULL, 's'},
  553. {"check", 0, NULL, 'k'},
  554. {"facility", 1, NULL, 'l'},
  555. {NULL, 0, NULL, 0}
  556. };
  557. optind = 1;
  558. while(1) {
  559. int opt = 0;
  560. opt = getopt_long(argc, argv, shortopts, longopts, NULL);
  561. if (-1 == opt)
  562. break;
  563. switch (opt) {
  564. case 'p':
  565. faux_str_free(opts->pidfile);
  566. opts->pidfile = faux_str_dup(optarg);
  567. break;
  568. case 'c':
  569. faux_str_free(opts->cfgfile);
  570. opts->cfgfile = faux_str_dup(optarg);
  571. opts->cfgfile_userdefined = BOOL_TRUE;
  572. break;
  573. case 'f':
  574. opts->foreground = BOOL_TRUE;
  575. break;
  576. case 'v':
  577. opts->verbose = BOOL_TRUE;
  578. break;
  579. case 's':
  580. opts->silent = BOOL_TRUE;
  581. break;
  582. case 'k':
  583. opts->check = BOOL_TRUE;
  584. break;
  585. case 'l':
  586. if (faux_log_facility_id(optarg, &(opts->log_facility))) {
  587. fprintf(stderr, "Error: Illegal syslog facility %s.\n", optarg);
  588. _exit(-1);
  589. }
  590. break;
  591. case 'h':
  592. help(0, argv[0]);
  593. _exit(0);
  594. break;
  595. default:
  596. help(-1, argv[0]);
  597. _exit(-1);
  598. break;
  599. }
  600. }
  601. return 0;
  602. }
  603. /** @brief Print help message
  604. */
  605. static void help(int status, const char *argv0)
  606. {
  607. const char *name = NULL;
  608. if (!argv0)
  609. return;
  610. // Find the basename
  611. name = strrchr(argv0, '/');
  612. if (name)
  613. name++;
  614. else
  615. name = argv0;
  616. if (status != 0) {
  617. fprintf(stderr, "Try `%s -h' for more information.\n",
  618. name);
  619. } else {
  620. printf("Version : %s\n", VERSION);
  621. printf("Usage : %s [options]\n", name);
  622. printf("Certificate Revocation Service Daemon\n");
  623. printf("Options :\n");
  624. printf("\t-h, --help Print this help.\n");
  625. printf("\t-f, --foreground Don't daemonize.\n");
  626. printf("\t-v, --verbose Be verbose.\n");
  627. printf("\t-s, --silent Be silent.\n");
  628. printf("\t-k, --check Check config only and exit.\n");
  629. printf("\t-p <path>, --pid=<path> File to save daemon's PID to ("
  630. CRSD_DEFAULT_PIDFILE ").\n");
  631. printf("\t-c <path>, --conf=<path> Config file ("
  632. CRSD_DEFAULT_CFGFILE ").\n");
  633. printf("\t-l, --facility Syslog facility (DAEMON).\n");
  634. }
  635. }
  636. /** @brief Parse config file
  637. */
  638. static int config_parse(const char *cfgfile, struct options *opts)
  639. {
  640. faux_ini_t *ini = NULL;
  641. const char *tmp = NULL;
  642. ini = faux_ini_new();
  643. assert(ini);
  644. if (!ini)
  645. return -1;
  646. if (faux_ini_parse_file(ini, cfgfile)) {
  647. lsyslog(LOG_ERR, "Can't parse config file: %s\n", cfgfile);
  648. faux_ini_free(ini);
  649. return -1;
  650. }
  651. if ((tmp = faux_ini_find(ini, "UnixSocketPath"))) {
  652. faux_str_free(opts->unix_socket_path);
  653. opts->unix_socket_path = faux_str_dup(tmp);
  654. }
  655. if ((tmp = faux_ini_find(ini, "UID"))) {
  656. faux_str_free(opts->uid_str);
  657. opts->uid_str = faux_str_dup(tmp);
  658. if (faux_sysdb_uid_by_name(opts->uid_str, &opts->uid) < 0) {
  659. lsyslog(LOG_ERR, "Unknown user: %s\n", opts->uid_str);
  660. faux_ini_free(ini);
  661. return -1; // Unknown user
  662. }
  663. }
  664. if ((tmp = faux_ini_find(ini, "GID"))) {
  665. faux_str_free(opts->gid_str);
  666. opts->gid_str = faux_str_dup(tmp);
  667. if (faux_sysdb_gid_by_name(opts->gid_str, &opts->gid)) {
  668. lsyslog(LOG_ERR, "Unknown group: %s\n", opts->gid_str);
  669. faux_ini_free(ini);
  670. return -1; // Unknown group
  671. }
  672. }
  673. if ((tmp = faux_ini_find(ini, "FetchInterval"))) {
  674. if (faux_conv_atol(tmp, &opts->fetch_interval, 10) < 0) {
  675. lsyslog(LOG_ERR, "Illegal FetchInterval: %s\n", tmp);
  676. faux_ini_free(ini);
  677. return -1;
  678. }
  679. if (opts->fetch_interval < 0) {
  680. lsyslog(LOG_ERR, "FetchInterval can't be less than zero: %s\n", tmp);
  681. faux_ini_free(ini);
  682. return -1;
  683. }
  684. }
  685. if ((tmp = faux_ini_find(ini, "FetchMargin"))) {
  686. if (faux_conv_atouc(tmp, &opts->fetch_margin, 10) < 0) {
  687. lsyslog(LOG_ERR, "Illegal FetchMargin: %s\n", tmp);
  688. faux_ini_free(ini);
  689. return -1;
  690. }
  691. if (opts->fetch_margin > 100) { // Value in percents
  692. lsyslog(LOG_ERR, "FetchMargin (in percents) can't be greater than 100: %s\n", tmp);
  693. faux_ini_free(ini);
  694. return -1;
  695. }
  696. }
  697. if ((tmp = faux_ini_find(ini, "FetchTimeout"))) {
  698. if (faux_conv_atol(tmp, &opts->fetch_timeout, 10) < 0) {
  699. lsyslog(LOG_ERR, "Illegal FetchTimeout: %s\n", tmp);
  700. faux_ini_free(ini);
  701. return -1;
  702. }
  703. if (opts->fetch_timeout < 0) {
  704. lsyslog(LOG_ERR, "FetchTimeout can't be less than zero: %s\n", tmp);
  705. faux_ini_free(ini);
  706. return -1;
  707. }
  708. if (opts->fetch_timeout > opts->fetch_interval) {
  709. lsyslog(LOG_ERR, "FetchTimeout can't be greater than FetchInterval: %s\n", tmp);
  710. faux_ini_free(ini);
  711. return -1;
  712. }
  713. }
  714. if ((tmp = faux_ini_find(ini, "CRLMaxSize"))) {
  715. if (faux_conv_atoul(tmp, &opts->crl_max_size, 10) < 0) {
  716. lsyslog(LOG_ERR, "Illegal CRLMaxSize: %s\n", tmp);
  717. faux_ini_free(ini);
  718. return -1;
  719. }
  720. if (opts->crl_max_size > CRSD_DEFAULT_CRL_MAX_SIZE) {
  721. lsyslog(LOG_ERR, "CRLMaxSize can't be greater than %lu: %s\n",
  722. CRSD_DEFAULT_CRL_MAX_SIZE, tmp);
  723. faux_ini_free(ini);
  724. return -1;
  725. }
  726. }
  727. if ((tmp = faux_ini_find(ini, "CRLStorageMaxSize"))) {
  728. if (faux_conv_atoul(tmp, &opts->crl_storage_max_size, 10) < 0) {
  729. lsyslog(LOG_ERR, "Illegal CRLStorageMaxSize: %s\n", tmp);
  730. faux_ini_free(ini);
  731. return -1;
  732. }
  733. }
  734. if ((tmp = faux_ini_find(ini, "RootCertDir"))) {
  735. faux_str_free(opts->rootcert_dir);
  736. opts->rootcert_dir = faux_str_dup(tmp);
  737. }
  738. if ((tmp = faux_ini_find(ini, "CACertDir"))) {
  739. faux_str_free(opts->cacert_dir);
  740. opts->cacert_dir = faux_str_dup(tmp);
  741. }
  742. if ((tmp = faux_ini_find(ini, "CertDir"))) {
  743. faux_str_free(opts->cert_dir);
  744. opts->cert_dir = faux_str_dup(tmp);
  745. }
  746. if ((tmp = faux_ini_find(ini, "OCSPCertDir"))) {
  747. faux_str_free(opts->ocspcert_dir);
  748. opts->ocspcert_dir = faux_str_dup(tmp);
  749. }
  750. if ((tmp = faux_ini_find(ini, "CRLDir"))) {
  751. faux_str_free(opts->crl_dir);
  752. opts->crl_dir = faux_str_dup(tmp);
  753. }
  754. if ((tmp = faux_ini_find(ini, "KeyDir"))) {
  755. faux_str_free(opts->key_dir);
  756. opts->key_dir = faux_str_dup(tmp);
  757. }
  758. if ((tmp = faux_ini_find(ini, "P10Dir"))) {
  759. faux_str_free(opts->p10_dir);
  760. opts->p10_dir = faux_str_dup(tmp);
  761. }
  762. if ((tmp = faux_ini_find(ini, "SecretsFile"))) {
  763. faux_str_free(opts->secrets_file);
  764. opts->secrets_file = faux_str_dup(tmp);
  765. }
  766. faux_ini_free(ini);
  767. return 0;
  768. }
  769. /** @brief Show options. For debug purposes.
  770. */
  771. static int opts_show(struct options *opts)
  772. {
  773. assert(opts);
  774. if (!opts)
  775. return -1;
  776. lsyslog(LOG_DEBUG, "opts: Foreground = %s\n", opts->foreground ? "true" : "false");
  777. lsyslog(LOG_DEBUG, "opts: Verbose = %s\n", opts->verbose ? "true" : "false");
  778. lsyslog(LOG_DEBUG, "opts: LogFacility = %s\n", faux_log_facility_str(opts->log_facility));
  779. lsyslog(LOG_DEBUG, "opts: PIDPath = %s\n", opts->pidfile);
  780. lsyslog(LOG_DEBUG, "opts: ConfigPath = %s\n", opts->cfgfile);
  781. lsyslog(LOG_DEBUG, "opts: UnixSocketPath = %s\n", opts->unix_socket_path);
  782. lsyslog(LOG_DEBUG, "opts: UID = %s\n", opts->uid_str ? opts->uid_str : "");
  783. lsyslog(LOG_DEBUG, "opts: GID = %s\n", opts->gid_str ? opts->gid_str : "");
  784. lsyslog(LOG_DEBUG, "opts: FetchInterval = %ld sec\n", opts->fetch_interval);
  785. lsyslog(LOG_DEBUG, "opts: FetchMargin = %u %% \n", opts->fetch_margin);
  786. lsyslog(LOG_DEBUG, "opts: FetchTimeout = %ld sec\n", opts->fetch_timeout);
  787. lsyslog(LOG_DEBUG, "opts: CRLMaxSize = %ld bytes\n", opts->crl_max_size);
  788. lsyslog(LOG_DEBUG, "opts: CRLStorageMaxSize = %ld bytes\n", opts->crl_storage_max_size);
  789. lsyslog(LOG_DEBUG, "opts: RootCertDir = %s\n", opts->rootcert_dir);
  790. lsyslog(LOG_DEBUG, "opts: CACertDir = %s\n", opts->cacert_dir);
  791. lsyslog(LOG_DEBUG, "opts: CertDir = %s\n", opts->cert_dir);
  792. lsyslog(LOG_DEBUG, "opts: OCSPCertDir = %s\n", opts->ocspcert_dir);
  793. lsyslog(LOG_DEBUG, "opts: CRLDir = %s\n", opts->crl_dir);
  794. lsyslog(LOG_DEBUG, "opts: KeyDir = %s\n", opts->key_dir);
  795. lsyslog(LOG_DEBUG, "opts: P10Dir = %s\n", opts->p10_dir);
  796. lsyslog(LOG_DEBUG, "opts: SecretsFile = %s\n", opts->secrets_file);
  797. return 0;
  798. }