1 /* $OpenBSD: sasyncd.c,v 1.28 2018/04/10 15:58:21 cheloha Exp $ */ 2 3 /* 4 * Copyright (c) 2005 H�kan Olsson. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * This code was written under funding by Multicom Security AB. 30 */ 31 32 33 #include <sys/types.h> 34 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <pwd.h> 38 #include <signal.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <stdlib.h> 42 #include <time.h> 43 #include <unistd.h> 44 45 #include "sasyncd.h" 46 47 volatile sig_atomic_t daemon_shutdown = 0; 48 49 /* Called by signal handler for controlled daemon shutdown. */ 50 static void 51 sasyncd_stop(int s) 52 { 53 daemon_shutdown++; 54 } 55 56 static int 57 sasyncd_run(pid_t ppid) 58 { 59 struct timespec *timeout, ts; 60 fd_set *rfds, *wfds; 61 size_t fdsetsize; 62 int maxfd, n; 63 64 n = getdtablesize(); 65 fdsetsize = howmany(n, NFDBITS) * sizeof(fd_mask); 66 67 rfds = malloc(fdsetsize); 68 if (!rfds) { 69 log_err("malloc(%lu) failed", (unsigned long)fdsetsize); 70 return -1; 71 } 72 73 wfds = malloc(fdsetsize); 74 if (!wfds) { 75 log_err("malloc(%lu) failed", (unsigned long)fdsetsize); 76 free(rfds); 77 return -1; 78 } 79 80 control_setrun(); 81 82 signal(SIGINT, sasyncd_stop); 83 signal(SIGTERM, sasyncd_stop); 84 85 timer_add("carp_undemote", CARP_DEMOTE_MAXTIME, 86 monitor_carpundemote, NULL); 87 88 while (!daemon_shutdown) { 89 memset(rfds, 0, fdsetsize); 90 memset(wfds, 0, fdsetsize); 91 maxfd = net_set_rfds(rfds); 92 n = net_set_pending_wfds(wfds); 93 if (n > maxfd) 94 maxfd = n; 95 96 pfkey_set_rfd(rfds); 97 pfkey_set_pending_wfd(wfds); 98 if (cfgstate.pfkey_socket + 1 > maxfd) 99 maxfd = cfgstate.pfkey_socket + 1; 100 101 carp_set_rfd(rfds); 102 if (cfgstate.route_socket + 1 > maxfd) 103 maxfd = cfgstate.route_socket + 1; 104 105 timeout = &ts; 106 timer_next_event(&ts); 107 108 n = pselect(maxfd, rfds, wfds, NULL, timeout, NULL); 109 if (n == -1) { 110 if (errno != EINTR) { 111 log_err("select()"); 112 sleep(1); 113 } 114 } else if (n) { 115 net_handle_messages(rfds); 116 net_send_messages(wfds); 117 pfkey_read_message(rfds); 118 pfkey_send_message(wfds); 119 carp_read_message(rfds); 120 } 121 timer_run(); 122 123 /* Mostly for debugging. */ 124 if (getppid() != ppid) { 125 log_msg(0, "sasyncd: parent died"); 126 daemon_shutdown++; 127 } 128 } 129 free(rfds); 130 free(wfds); 131 return 0; 132 } 133 134 __dead static void 135 usage(void) 136 { 137 extern char *__progname; 138 139 fprintf(stderr, "usage: %s [-dnv] [-c config-file]\n", __progname); 140 exit(1); 141 } 142 143 int 144 main(int argc, char **argv) 145 { 146 extern char *__progname; 147 char *cfgfile = 0; 148 int ch, noaction = 0; 149 150 if (geteuid() != 0) { 151 /* No point in continuing. */ 152 fprintf(stderr, "%s: This daemon needs to be run as root.\n", 153 __progname); 154 return 1; 155 } 156 157 while ((ch = getopt(argc, argv, "c:dnv")) != -1) { 158 switch (ch) { 159 case 'c': 160 if (cfgfile) 161 usage(); 162 cfgfile = optarg; 163 break; 164 case 'd': 165 cfgstate.debug++; 166 break; 167 case 'n': 168 noaction = 1; 169 break; 170 case 'v': 171 cfgstate.verboselevel++; 172 break; 173 default: 174 usage(); 175 } 176 } 177 argc -= optind; 178 argv += optind; 179 180 if (argc > 0) 181 usage(); 182 183 log_init(__progname); 184 timer_init(); 185 186 cfgstate.runstate = INIT; 187 LIST_INIT(&cfgstate.peerlist); 188 189 cfgstate.listen_port = SASYNCD_DEFAULT_PORT; 190 cfgstate.flags |= CTL_DEFAULT; 191 192 if (!cfgfile) 193 cfgfile = SASYNCD_CFGFILE; 194 195 if (conf_parse_file(cfgfile) == 0 ) { 196 if (!cfgstate.sharedkey) { 197 fprintf(stderr, "config: " 198 "no shared key specified, cannot continue\n"); 199 exit(1); 200 } 201 if (!cfgstate.carp_ifname || !*cfgstate.carp_ifname) { 202 fprintf(stderr, "config: " 203 "no carp interface specified, cannot continue\n"); 204 exit(1); 205 } 206 } else { 207 exit(1); 208 } 209 210 if (noaction) { 211 fprintf(stderr, "configuration OK\n"); 212 exit(0); 213 } 214 215 carp_demote(CARP_INC, 0); 216 217 if (carp_init()) 218 return 1; 219 if (pfkey_init(0)) 220 return 1; 221 if (net_init()) 222 return 1; 223 224 if (!cfgstate.debug) 225 if (daemon(1, 0)) { 226 perror("daemon()"); 227 exit(1); 228 } 229 230 if (monitor_init()) { 231 /* Parent, with privileges. */ 232 monitor_loop(); 233 exit(0); 234 } 235 236 /* Child, no privileges left. Run main loop. */ 237 sasyncd_run(getppid()); 238 239 /* Shutdown. */ 240 log_msg(0, "shutting down..."); 241 242 net_shutdown(); 243 pfkey_shutdown(); 244 return 0; 245 } 246