1 /*
2  * Copyright (C) 2013-2018 Nikos Mavrogiannopoulos
3  * Copyright (C) 2015-2016 Red Hat, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <config.h>
20 
21 #include <sys/resource.h>
22 
23 #include <system.h>
24 #include "setproctitle.h"
25 #ifdef HAVE_LIBWRAP
26 #include <tcpd.h>
27 #endif
28 
29 #ifdef HAVE_LIBSYSTEMD
30 #include <systemd/sd-daemon.h>
31 #endif
32 #include <main.h>
33 #include <worker.h>
34 #include <base64-helper.h>
35 #include <snapshot.h>
36 #include <isolate.h>
37 
38 #ifdef HAVE_GSSAPI
39 #include <libtasn1.h>
40 
41 extern const ASN1_ARRAY_TYPE kkdcp_asn1_tab[];
42 ASN1_TYPE _kkdcp_pkix1_asn = ASN1_TYPE_EMPTY;
43 #endif
44 
45 extern struct snapshot_t *config_snapshot;
46 
47 int syslog_open = 0;
48 sigset_t sig_default_set;
49 static unsigned allow_broken_clients = 0;
50 
51 static int set_ws_from_env(worker_st * ws);
52 
53 extern char secmod_socket_file_name_socket_file[_POSIX_PATH_MAX];
54 
main(int argc,char ** argv)55 int main(int argc, char **argv)
56 {
57 	int ret, flags;
58 	void *worker_pool;
59 	void *main_pool, *config_pool;
60 	main_server_st *s;
61 	worker_st *ws;
62 	char *str;
63 
64 #ifdef DEBUG_LEAKS
65 	talloc_enable_leak_report_full();
66 #endif
67 
68 	if (!getenv(OCSERV_ENV_WORKER_STARTUP_MSG)) {
69 		fprintf(stderr,
70 			"This application is part of ocserv and should not be run in isolation\n");
71 		exit(1);
72 	}
73 
74 	/* main pool */
75 	main_pool = talloc_init("main");
76 	if (main_pool == NULL) {
77 		fprintf(stderr, "talloc init error\n");
78 		exit(1);
79 	}
80 
81 	config_pool = talloc_init("config");
82 	if (config_pool == NULL) {
83 		fprintf(stderr, "talloc init error\n");
84 		exit(1);
85 	}
86 
87 	if (snapshot_init(config_pool, &config_snapshot, "/tmp/ocserv_") < 0) {
88 		fprintf(stderr, "failed to init snapshot");
89 		exit(-1);
90 	}
91 
92 	s = talloc_zero(main_pool, main_server_st);
93 	if (s == NULL) {
94 		fprintf(stderr, "memory error\n");
95 		exit(1);
96 	}
97 	s->main_pool = main_pool;
98 	s->config_pool = config_pool;
99 	s->stats.start_time = s->stats.last_reset = time(0);
100 	s->top_fd = -1;
101 	s->ctl_fd = -1;
102 
103 	worker_pool = talloc_init("worker");
104 	if (worker_pool == NULL) {
105 		fprintf(stderr, "talloc init error\n");
106 		exit(1);
107 	}
108 
109 	s->ws = talloc_zero(worker_pool, worker_st);
110 	ws = s->ws;
111 
112 	if (ws == NULL) {
113 		fprintf(stderr, "talloc init error\n");
114 		exit(1);
115 	}
116 
117 	if (!set_ws_from_env(ws)) {
118 		return 1;
119 	}
120 
121 	restore_secmod_socket_file_name(ws->secmod_addr.sun_path);
122 
123 	str = getenv("OCSERV_ALLOW_BROKEN_CLIENTS");
124 	if (str && str[0] == '1' && str[1] == 0)
125 		allow_broken_clients = 1;
126 
127 	sigemptyset(&sig_default_set);
128 
129 	ocsignal(SIGPIPE, SIG_IGN);
130 
131 	/* Initialize GnuTLS */
132 	tls_global_init();
133 
134 	/* load configuration */
135 	s->vconfig = talloc_zero(config_pool, struct list_head);
136 	if (s->vconfig == NULL) {
137 		fprintf(stderr, "memory error\n");
138 		exit(1);
139 	}
140 	list_head_init(s->vconfig);
141 
142 	ret = cmd_parser(config_pool, argc, argv, s->vconfig, true);
143 	if (ret < 0) {
144 		fprintf(stderr, "Error in arguments\n");
145 		exit(1);
146 	}
147 
148 	snapshot_terminate(config_snapshot);
149 	config_snapshot = NULL;
150 
151 	flags = LOG_PID | LOG_NDELAY;
152 #ifdef LOG_PERROR
153 	if (GETPCONFIG(s)->debug != 0)
154 		flags |= LOG_PERROR;
155 #endif
156 	openlog("ocserv", flags, LOG_DAEMON);
157 	syslog_open = 1;
158 #ifdef HAVE_LIBWRAP
159 	allow_severity = LOG_DAEMON | LOG_INFO;
160 	deny_severity = LOG_DAEMON | LOG_WARNING;
161 #endif
162 
163 #ifdef HAVE_GSSAPI
164 	/* Initialize kkdcp structures */
165 	ret = asn1_array2tree(kkdcp_asn1_tab, &_kkdcp_pkix1_asn, NULL);
166 	if (ret != ASN1_SUCCESS) {
167 		mslog(s, NULL, LOG_ERR, "KKDCP ASN.1 initialization error");
168 		exit(1);
169 	}
170 #endif
171 
172 	init_fd_limits_default(s);
173 
174 	sigprocmask(SIG_SETMASK, &sig_default_set, NULL);
175 
176 	setproctitle(PACKAGE_NAME "-worker");
177 	kill_on_parent_kill(SIGTERM);
178 
179 	ws->main_pool = s->main_pool;
180 	ws->vconfig = s->vconfig;
181 
182 	ws->tun_fd = -1;
183 	DTLS_ACTIVE(ws)->dtls_tptr.fd = -1;
184 	DTLS_INACTIVE(ws)->dtls_tptr.fd = -1;
185 
186 	/* Drop privileges after this point */
187 	drop_privileges(s);
188 
189 	vpn_server(ws);
190 
191 	return 0;
192 }
193 
194 extern char **pam_auth_group_list;
195 extern char **gssapi_auth_group_list;
196 extern char **plain_auth_group_list;
197 extern unsigned pam_auth_group_list_size;
198 extern unsigned gssapi_auth_group_list_size;
199 extern unsigned plain_auth_group_list_size;
200 
clone_array(void * pool,char ** input_array,size_t input_array_size,char *** output_array)201 static int clone_array(void *pool, char **input_array, size_t input_array_size,
202 		       char ***output_array)
203 {
204 	int ret = 0;
205 	int index;
206 	char **array = talloc_zero_array(pool, char *, input_array_size);
207 	if (array == NULL) {
208 		goto cleanup;
209 	}
210 
211 	for (index = 0; index < input_array_size; index++) {
212 		array[index] = talloc_strdup(pool, input_array[index]);
213 		if (array[index] == NULL) {
214 			goto cleanup;
215 		}
216 	}
217 
218 	*output_array = array;
219 	array = NULL;
220 	ret = 1;
221  cleanup:
222 	if (array != NULL) {
223 		for (index = 0; index < input_array_size; index++) {
224 			if (array[index] != NULL) {
225 				talloc_free(array[index]);
226 			}
227 		}
228 		talloc_free(array);
229 	}
230 	return ret;
231 }
232 
set_ws_from_env(worker_st * ws)233 static int set_ws_from_env(worker_st * ws)
234 {
235 	PROTOBUF_ALLOCATOR(pa, ws);
236 	WorkerStartupMsg *msg = NULL;
237 	const char *string_buffer = getenv(OCSERV_ENV_WORKER_STARTUP_MSG);
238 	size_t string_size;
239 	size_t msg_size;
240 	uint8_t *msg_buffer = NULL;
241 	int ret = 0;
242 	size_t index;
243 
244 	if (string_buffer == NULL) {
245 		fprintf(stderr, "This application must be called from ocserv (no env variable set)\n");
246 		goto cleanup;
247 	}
248 
249 	string_size = strlen(string_buffer);
250 
251 	if (!oc_base64_decode_alloc
252 	    (ws, string_buffer, string_size, (char **)&msg_buffer, &msg_size)) {
253 		fprintf(stderr, "oc_base64_decode_alloc failed\n");
254 		goto cleanup;
255 	}
256 
257 	msg = worker_startup_msg__unpack(&pa, msg_size, msg_buffer);
258 	if (!msg) {
259 		fprintf(stderr, "worker_startup_msg__unpack failed\n");
260 		goto cleanup;
261 	}
262 
263 	if (msg->secmod_addr.len > sizeof(ws->secmod_addr)) {
264 		fprintf(stderr, "msg->secmod_addr.len too large\n");
265 		goto cleanup;
266 	}
267 	if (msg->remote_addr.len > sizeof(ws->remote_addr)) {
268 		fprintf(stderr, "msg->remote_addr.len too large\n");
269 		goto cleanup;
270 	}
271 	if (msg->our_addr.len > sizeof(ws->our_addr)) {
272 		fprintf(stderr, "msg->our_addr.len too large\n");
273 		goto cleanup;
274 	}
275 	if (msg->sec_auth_init_hmac.len > sizeof(ws->sec_auth_init_hmac)) {
276 		fprintf(stderr, "msg->sec_auth_init_hmac.len too large\n");
277 		goto cleanup;
278 	}
279 
280 	ws->secmod_addr_len = msg->secmod_addr.len;
281 	memcpy(&ws->secmod_addr, msg->secmod_addr.data, msg->secmod_addr.len);
282 
283 	ws->cmd_fd = msg->cmd_fd;
284 	ws->conn_fd = msg->conn_fd;
285 	ws->conn_type = (sock_type_t) msg->conn_type;
286 	ws->session_start_time = msg->session_start_time;
287 	ws->remote_addr_len = msg->remote_addr.len;
288 	memcpy(&ws->remote_addr, msg->remote_addr.data, msg->remote_addr.len);
289 	if (msg->our_addr.data != NULL)
290 		memcpy(&ws->our_addr, msg->our_addr.data, msg->our_addr.len);
291 
292 	memcpy((void *)ws->sec_auth_init_hmac, msg->sec_auth_init_hmac.data,
293 	       msg->sec_auth_init_hmac.len);
294 
295 	strlcpy(ws->remote_ip_str, msg->remote_ip_str,
296 		sizeof(ws->remote_ip_str));
297 	strlcpy(ws->our_ip_str, msg->our_ip_str, sizeof(ws->our_ip_str));
298 
299 	for (index = 0; index < msg->n_snapshot_entries; index++) {
300 		int fd = msg->snapshot_entries[index]->file_descriptor;
301 		const char *file_name = msg->snapshot_entries[index]->file_name;
302 		if (snapshot_restore_entry(config_snapshot, fd, file_name) != 0)
303 			goto cleanup;
304 	}
305 
306 	if (!clone_array
307 	    (ws, msg->pam_auth_group_list, msg->n_pam_auth_group_list,
308 	     &pam_auth_group_list))
309 		goto cleanup;
310 	pam_auth_group_list_size = (unsigned)msg->n_pam_auth_group_list;
311 
312 	if (!clone_array
313 	    (ws, msg->plain_auth_group_list, msg->n_plain_auth_group_list,
314 	     &plain_auth_group_list))
315 		goto cleanup;
316 	plain_auth_group_list_size = (unsigned)msg->n_plain_auth_group_list;
317 
318 	if (!clone_array
319 	    (ws, msg->gssapi_auth_group_list, msg->n_gssapi_auth_group_list,
320 	     &gssapi_auth_group_list))
321 		goto cleanup;
322 	gssapi_auth_group_list_size = (unsigned)msg->n_gssapi_auth_group_list;
323 
324 	ret = 1;
325 
326  cleanup:
327 	if (msg_buffer)
328 		talloc_free(msg_buffer);
329 
330 	if (msg)
331 		worker_startup_msg__free_unpacked(msg, &pa);
332 
333 	return ret;
334 }
335