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
sasyncd_stop(int s)51 sasyncd_stop(int s)
52 {
53 daemon_shutdown++;
54 }
55
56 static int
sasyncd_run(pid_t ppid)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
usage(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
main(int argc,char ** argv)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