1 /*
2  * Copyright (C) 2013-2016 Nikos Mavrogiannopoulos
3  * Copyright (C) 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 #include <stdio.h>
21 #include <stdint.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/uio.h>
28 /* for recvmsg */
29 #include <netinet/in.h>
30 #include <netinet/ip.h>
31 #include <poll.h>
32 #include <limits.h>
33 #include <assert.h>
34 #include <nettle/sha1.h>
35 #include "common.h"
36 #include "defs.h"
37 #include "common/base64-helper.h"
38 
39 int saved_argc = 0;
40 char **saved_argv = NULL;
41 
_vhost_prefix(const char * name)42 const char *_vhost_prefix(const char *name)
43 {
44 	static char tmp[128];
45 
46 	snprintf(tmp, sizeof(tmp), "vhost:%s: ", name);
47 	return tmp;
48 }
49 
50 /* A hash of the input, to a 20-byte output. The goal is one-wayness.
51  */
safe_hash(const uint8_t * data,unsigned data_size,uint8_t output[20])52 static void safe_hash(const uint8_t *data, unsigned data_size, uint8_t output[20])
53 {
54 	struct sha1_ctx ctx;
55 
56 	sha1_init(&ctx);
57 
58 	sha1_update(&ctx, data_size, data);
59 	sha1_digest(&ctx, 20, output);
60 }
61 
62 
calc_safe_id(const uint8_t * data,unsigned size,char * output,unsigned output_size)63 char *calc_safe_id(const uint8_t *data, unsigned size, char *output, unsigned output_size)
64 {
65 	uint8_t safe_id[20];
66 
67 	safe_hash(data, size, safe_id);
68 	oc_base64_encode((char*)safe_id, 20, output, output_size);
69 
70 	return output;
71 }
72 
73 /* Note that meaning slightly changes depending on whether we are
74  * referring to the cookie or the session itself.
75  */
ps_status_to_str(int status,unsigned cookie)76 const char *ps_status_to_str(int status, unsigned cookie)
77 {
78 	switch (status) {
79 		case PS_AUTH_COMPLETED:
80 			if (cookie)
81 				return "authenticated";
82 			else
83 				return "connected";
84 		case PS_AUTH_INIT:
85 		case PS_AUTH_CONT:
86 			return "authenticating";
87 		case PS_AUTH_INACTIVE:
88 			return "pre-auth";
89 		case PS_AUTH_FAILED:
90 			return "auth failed";
91 		default:
92 			return "unknown";
93 	}
94 }
95 
cmd_request_to_str(unsigned _cmd)96 const char *cmd_request_to_str(unsigned _cmd)
97 {
98 	cmd_request_t cmd = _cmd;
99 	static char tmp[32];
100 
101 	switch (cmd) {
102 	case AUTH_COOKIE_REP:
103 		return "auth cookie reply";
104 	case AUTH_COOKIE_REQ:
105 		return "auth cookie request";
106 	case RESUME_STORE_REQ:
107 		return "resume data store request";
108 	case RESUME_DELETE_REQ:
109 		return "resume data delete request";
110 	case RESUME_FETCH_REQ:
111 		return "resume data fetch request";
112 	case RESUME_FETCH_REP:
113 		return "resume data fetch reply";
114 	case CMD_UDP_FD:
115 		return "udp fd";
116 	case CMD_TUN_MTU:
117 		return "tun mtu change";
118 	case CMD_TERMINATE:
119 		return "terminate";
120 	case CMD_SESSION_INFO:
121 		return "session info";
122 	case CMD_BAN_IP:
123 		return "ban IP";
124 	case CMD_BAN_IP_REPLY:
125 		return "ban IP reply";
126 	case CMD_LATENCY_STATS_DELTA:
127 		return "latency stats delta";
128 	case CMD_SEC_CLI_STATS:
129 		return "sm: worker cli stats";
130 	case CMD_SEC_AUTH_INIT:
131 		return "sm: auth init";
132 	case CMD_SEC_AUTH_CONT:
133 		return "sm: auth cont";
134 	case CMD_SEC_AUTH_REPLY:
135 		return "sm: auth rep";
136 	case CMD_SEC_DECRYPT:
137 		return "sm: decrypt";
138 	case CMD_SEC_SIGN:
139 		return "sm: sign";
140 	case CMD_SEC_SIGN_DATA:
141 		return "sm: sign data";
142 	case CMD_SEC_SIGN_HASH:
143 		return "sm: sign hash";
144 	case CMD_SEC_GET_PK:
145 		return "sm: get pk";
146 	case CMD_SECM_SESSION_CLOSE:
147 		return "sm: session close";
148 	case CMD_SECM_SESSION_OPEN:
149 		return "sm: session open";
150 	case CMD_SECM_SESSION_REPLY:
151 		return "sm: session reply";
152 	case CMD_SECM_BAN_IP:
153 		return "sm: ban IP";
154 	case CMD_SECM_BAN_IP_REPLY:
155 		return "sm: ban IP reply";
156 	case CMD_SECM_CLI_STATS:
157 		return "sm: main cli stats";
158 	case CMD_SECM_LIST_COOKIES:
159 		return "sm: list cookies";
160 	case CMD_SECM_LIST_COOKIES_REPLY:
161 		return "sm: list cookies reply";
162 	case CMD_SECM_STATS:
163 		return "sm: stats";
164 	case CMD_SECM_RELOAD:
165 		return "sm: reload";
166 	case CMD_SECM_RELOAD_REPLY:
167 		return "sm: reload reply";
168 	default:
169 		snprintf(tmp, sizeof(tmp), "unknown (%u)", _cmd);
170 		return tmp;
171 	}
172 }
173 
discon_reason_to_str(unsigned reason)174 const char *discon_reason_to_str(unsigned reason)
175 {
176 	static char tmp[32];
177 
178 	switch (reason) {
179 	case 0:
180 	case REASON_ANY:
181 		return "unspecified";
182 	case REASON_USER_DISCONNECT:
183 		return "user disconnected";
184 	case REASON_TEMP_DISCONNECT:
185 		return "anyconnect client disconnected";
186 	case REASON_SERVER_DISCONNECT:
187 		return "server disconnected";
188 	case REASON_IDLE_TIMEOUT:
189 		return "idle timeout";
190 	case REASON_DPD_TIMEOUT:
191 		return "DPD timeout";
192 	case REASON_ERROR:
193 		return "unspecified error";
194 	case REASON_SESSION_TIMEOUT:
195 		return "session timeout";
196 	case REASON_HEALTH_PROBE:
197 		return "TCP health probe";
198 	default:
199 		snprintf(tmp, sizeof(tmp), "unknown (%u)", reason);
200 		return tmp;
201 	}
202 }
203 
discon_reason_to_log_level(unsigned int reason)204 unsigned int discon_reason_to_log_level(unsigned int reason)
205 {
206 	switch (reason) {
207 	case 0:
208 	case REASON_ANY:
209 	case REASON_HEALTH_PROBE:
210 		return LOG_DEBUG;
211 	case REASON_USER_DISCONNECT:
212 	case REASON_TEMP_DISCONNECT:
213 	case REASON_SERVER_DISCONNECT:
214 	case REASON_IDLE_TIMEOUT:
215 	case REASON_DPD_TIMEOUT:
216 	case REASON_ERROR:
217 	case REASON_SESSION_TIMEOUT:
218 	default:
219 		return LOG_INFO;
220 	}
221 }
222 
force_write(int sockfd,const void * buf,size_t len)223 ssize_t force_write(int sockfd, const void *buf, size_t len)
224 {
225 	int left = len;
226 	int ret;
227 	const uint8_t *p = buf;
228 
229 	while (left > 0) {
230 		ret = write(sockfd, p, left);
231 		if (ret == -1) {
232 			if (errno != EAGAIN && errno != EINTR)
233 				return ret;
234 			else
235 				ms_sleep(50);
236 		}
237 
238 		if (ret > 0) {
239 			left -= ret;
240 			p += ret;
241 		}
242 	}
243 
244 	return len;
245 }
246 
force_read(int sockfd,void * buf,size_t len)247 ssize_t force_read(int sockfd, void *buf, size_t len)
248 {
249 	int left = len;
250 	int ret;
251 	uint8_t *p = buf;
252 
253 	while (left > 0) {
254 		ret = read(sockfd, p, left);
255 		if (ret == -1) {
256 			if (errno != EAGAIN && errno != EINTR)
257 				return ret;
258 		} else if (ret == 0) {
259 			assert(left != 0); /* ensured by the while */
260 			errno = ENOENT;
261 			return -1;
262 		}
263 
264 		if (ret > 0) {
265 			left -= ret;
266 			p += ret;
267 		}
268 	}
269 
270 	return len;
271 }
272 
force_read_timeout(int sockfd,void * buf,size_t len,unsigned sec)273 ssize_t force_read_timeout(int sockfd, void *buf, size_t len, unsigned sec)
274 {
275 	int left = len;
276 	int ret;
277 	uint8_t *p = buf;
278 	struct pollfd pfd;
279 
280 	while (left > 0) {
281 		if (sec > 0) {
282 			pfd.fd = sockfd;
283 			pfd.events = POLLIN;
284 			pfd.revents = 0;
285 
286 			do {
287 				ret = poll(&pfd, 1, sec * 1000);
288 			} while (ret == -1 && errno == EINTR);
289 
290 			if (ret == -1 || ret == 0) {
291 				errno = ETIMEDOUT;
292 				return -1;
293 			}
294 		}
295 
296 		ret = read(sockfd, p, left);
297 		if (ret == -1) {
298 			if (errno != EAGAIN && errno != EINTR)
299 				return ret;
300 		} else if (ret == 0) {
301 			assert(left != 0);
302 			errno = ENOENT;
303 			return -1;
304 		}
305 
306 		if (ret > 0) {
307 			left -= ret;
308 			p += ret;
309 		}
310 	}
311 
312 	return len;
313 }
314 
set_non_block(int fd)315 void set_non_block(int fd)
316 {
317 	int val, ret;
318 
319 	val = fcntl(fd, F_GETFL, 0);
320 	ret = fcntl(fd, F_SETFL, val | O_NONBLOCK);
321 	if (ret == -1) {
322 		/* We log but we do not fail; this seems to be failing when we test
323 		 * on 32-bit mode container over a 64-bit kernel. I believe this is related to that:
324 		 * https://patchwork.kernel.org/project/qemu-devel/patch/20200331133536.3328-1-linus.walleij@linaro.org/
325 		 */
326 		int e = errno;
327 		syslog(LOG_ERR, "set_non_block: %s", strerror(e));
328 	}
329 }
330 
set_block(int fd)331 void set_block(int fd)
332 {
333 	int val, ret;
334 
335 	val = fcntl(fd, F_GETFL, 0);
336 	ret = fcntl(fd, F_SETFL, val & (~O_NONBLOCK));
337 	if (ret == -1) {
338 		int e = errno;
339 		syslog(LOG_ERR, "set_non_block: %s", strerror(e));
340 	}
341 }
342 
recv_timeout(int sockfd,void * buf,size_t len,unsigned sec)343 ssize_t recv_timeout(int sockfd, void *buf, size_t len, unsigned sec)
344 {
345 	int ret;
346 	struct pollfd pfd;
347 
348 	pfd.fd = sockfd;
349 	pfd.events = POLLIN;
350 	pfd.revents = 0;
351 
352 	do {
353 		ret = poll(&pfd, 1, sec * 1000);
354 	} while (ret == -1 && errno == EINTR);
355 
356 	if (ret == -1 || ret == 0) {
357 		errno = ETIMEDOUT;
358 		return -1;
359 	}
360 
361 	return recv(sockfd, buf, len, 0);
362 }
363 
recvmsg_timeout(int sockfd,struct msghdr * msg,int flags,unsigned sec)364 ssize_t recvmsg_timeout(int sockfd, struct msghdr * msg, int flags,
365 			unsigned sec)
366 {
367 	int ret;
368 
369 	if (sec) {
370 		struct pollfd pfd;
371 
372 		pfd.fd = sockfd;
373 		pfd.events = POLLIN;
374 		pfd.revents = 0;
375 
376 		do {
377 			ret = poll(&pfd, 1, sec * 1000);
378 		} while (ret == -1 && errno == EINTR);
379 
380 		if (ret == -1 || ret == 0) {
381 			errno = ETIMEDOUT;
382 			return -1;
383 		}
384 	}
385 
386 	do {
387 		ret = recvmsg(sockfd, msg, flags);
388 	} while (ret == -1 && errno == EINTR);
389 
390 	return ret;
391 }
392 
forward_msg(void * pool,int ifd,uint8_t icmd,int ofd,uint8_t ocmd,unsigned timeout)393 int forward_msg(void *pool, int ifd, uint8_t icmd, int ofd, uint8_t ocmd, unsigned timeout)
394 {
395 	struct iovec iov[3];
396 	char data[5];
397 	uint32_t length;
398 	ssize_t left;
399 	uint8_t rcmd;
400 	struct msghdr hdr;
401 	int ret;
402 
403 	iov[0].iov_base = &rcmd;
404 	iov[0].iov_len = 1;
405 
406 	iov[1].iov_base = &length;
407 	iov[1].iov_len = 4;
408 
409 	memset(&hdr, 0, sizeof(hdr));
410 	hdr.msg_iov = iov;
411 	hdr.msg_iovlen = 2;
412 
413 	ret = recvmsg_timeout(ifd, &hdr, 0, timeout);
414 	if (ret == -1) {
415 		int e = errno;
416 		syslog(LOG_ERR, "%s:%u: recvmsg: %s", __FILE__, __LINE__,
417 		       strerror(e));
418 		return ERR_BAD_COMMAND;
419 	}
420 
421 	if (ret == 0) {
422 		return ERR_PEER_TERMINATED;
423 	}
424 
425 	if (rcmd != icmd) {
426 		syslog(LOG_ERR, "%s:%u: expected %d, received %d", __FILE__,
427 		       __LINE__, (int)rcmd, (int)icmd);
428 		return ERR_BAD_COMMAND;
429 	}
430 
431 	data[0] = ocmd;
432 	memcpy(&data[1], &length, 4);
433 
434 	/* send headers */
435 	ret = force_write(ofd, data, 5);
436 	if (ret != 5) {
437 		syslog(LOG_ERR, "%s:%u: cannot send headers: %s", __FILE__,
438 		       __LINE__, strerror(errno));
439 		return ERR_BAD_COMMAND;
440 	}
441 
442 	left = length;
443 
444 	while (left > 0) {
445 		char buf[1024];
446 
447 		ret = recv(ifd, buf, sizeof(buf), 0);
448 		if (ret == -1 || ret == 0) {
449 			if (errno == EAGAIN || errno == EINTR)
450 				continue;
451 			syslog(LOG_ERR, "%s:%u: cannot send between descriptors: %s", __FILE__,
452 			       __LINE__, strerror(errno));
453 			return ERR_BAD_COMMAND;
454 		}
455 
456 		ret = force_write(ofd, buf, ret);
457 		if (ret == -1 || ret == 0) {
458 			syslog(LOG_ERR, "%s:%u: cannot send between descriptors: %s", __FILE__,
459 			       __LINE__, strerror(errno));
460 			return ERR_BAD_COMMAND;
461 		}
462 
463 		left -= ret;
464 	}
465 
466 	return 0;
467 }
468 
469 /* Sends message + socketfd */
send_socket_msg(void * pool,int fd,uint8_t cmd,int socketfd,const void * msg,pack_size_func get_size,pack_func pack)470 int send_socket_msg(void *pool, int fd, uint8_t cmd,
471 		    int socketfd, const void *msg,
472 		    pack_size_func get_size, pack_func pack)
473 {
474 	struct iovec iov[3];
475 	struct msghdr hdr;
476 	union {
477 		struct cmsghdr cm;
478 		char control[CMSG_SPACE(sizeof(int))];
479 	} control_un;
480 	struct cmsghdr *cmptr;
481 	void *packed = NULL;
482 	uint32_t length32;
483 	size_t length = 0;
484 	int ret;
485 
486 	memset(&hdr, 0, sizeof(hdr));
487 
488 	iov[0].iov_base = &cmd;
489 	iov[0].iov_len = 1;
490 
491 	if (msg)
492 		length = get_size(msg);
493 
494 	if (length >= UINT32_MAX)
495 		return -1;
496 
497 	length32 = length;
498 	iov[1].iov_base = &length32;
499 	iov[1].iov_len = 4;
500 
501 	hdr.msg_iov = iov;
502 	hdr.msg_iovlen = 2;
503 
504 	if (length > 0) {
505 		packed = talloc_size(pool, length);
506 		if (packed == NULL) {
507 			syslog(LOG_ERR, "%s:%u: memory error", __FILE__,
508 			       __LINE__);
509 			return -1;
510 		}
511 
512 		iov[2].iov_base = packed;
513 		iov[2].iov_len = length;
514 
515 		ret = pack(msg, packed);
516 		if (ret == 0) {
517 			syslog(LOG_ERR, "%s:%u: packing error", __FILE__,
518 			       __LINE__);
519 			ret = -1;
520 			goto cleanup;
521 		}
522 
523 		hdr.msg_iovlen++;
524 	}
525 
526 	if (socketfd != -1) {
527 		hdr.msg_control = control_un.control;
528 		hdr.msg_controllen = sizeof(control_un.control);
529 
530 		cmptr = CMSG_FIRSTHDR(&hdr);
531 		cmptr->cmsg_len = CMSG_LEN(sizeof(int));
532 		cmptr->cmsg_level = SOL_SOCKET;
533 		cmptr->cmsg_type = SCM_RIGHTS;
534 		memcpy(CMSG_DATA(cmptr), &socketfd, sizeof(int));
535 	}
536 
537 	do {
538 		ret = sendmsg(fd, &hdr, 0);
539 	} while (ret == -1 && errno == EINTR);
540 	if (ret < 0) {
541 		int e = errno;
542 		syslog(LOG_ERR, "%s:%u: %s", __FILE__, __LINE__, strerror(e));
543 	}
544 
545  cleanup:
546 	if (length > 0)
547 		safe_memset(packed, 0, length);
548 	talloc_free(packed);
549 	return ret;
550 }
551 
recv_msg_headers(int fd,uint8_t * cmd,unsigned timeout)552 int recv_msg_headers(int fd, uint8_t *cmd, unsigned timeout)
553 {
554 	struct iovec iov[3];
555 	char buffer[5];
556 	uint32_t l32;
557 	struct msghdr hdr;
558 	int ret;
559 
560 	iov[0].iov_base = buffer;
561 	iov[0].iov_len = 5;
562 
563 	memset(&hdr, 0, sizeof(hdr));
564 	hdr.msg_iov = iov;
565 	hdr.msg_iovlen = 1;
566 
567 	ret = recvmsg_timeout(fd, &hdr, 0, timeout);
568 	if (ret == -1) {
569 		int e = errno;
570 		syslog(LOG_WARNING, "%s:%u: recvmsg: %s", __FILE__, __LINE__,
571 		       strerror(e));
572 		return ERR_BAD_COMMAND;
573 	}
574 
575 	if (ret == 0) {
576 		return ERR_PEER_TERMINATED;
577 	}
578 
579 	*cmd = buffer[0];
580 	memcpy(&l32, &buffer[1], 4);
581 
582 	return l32;
583 }
584 
recv_msg_data(int fd,uint8_t * cmd,uint8_t * data,size_t data_size,int * received_fd)585 int recv_msg_data(int fd, uint8_t *cmd, uint8_t *data, size_t data_size,
586 		  int *received_fd)
587 {
588 	struct iovec iov[3];
589 	uint32_t l32;
590 	struct msghdr hdr;
591 	union {
592 		struct cmsghdr cm;
593 		char control[CMSG_SPACE(sizeof(int))];
594 	} control_un;
595 	struct cmsghdr *cmptr;
596 	int ret;
597 
598 	iov[0].iov_base = cmd;
599 	iov[0].iov_len = 1;
600 
601 	iov[1].iov_base = &l32;
602 	iov[1].iov_len = 4;
603 
604 	memset(&hdr, 0, sizeof(hdr));
605 	hdr.msg_iov = iov;
606 	hdr.msg_iovlen = 2;
607 
608 	hdr.msg_control = control_un.control;
609 	hdr.msg_controllen = sizeof(control_un.control);
610 
611 	ret = recvmsg_timeout(fd, &hdr, 0, MAIN_SEC_MOD_TIMEOUT);
612 	if (ret == -1) {
613 		int e = errno;
614 		syslog(LOG_ERR, "%s:%u: recvmsg: %s", __FILE__, __LINE__,
615 		       strerror(e));
616 		return ERR_BAD_COMMAND;
617 	}
618 
619 	if (ret == 0) {
620 		return ERR_PEER_TERMINATED;
621 	}
622 
623 	/* try to receive socket (if any) */
624 	if (received_fd != NULL) {
625 		*received_fd = -1;
626 
627 		if ((cmptr = CMSG_FIRSTHDR(&hdr)) != NULL
628 		    && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
629 			if (cmptr->cmsg_level != SOL_SOCKET
630 			    || cmptr->cmsg_type != SCM_RIGHTS) {
631 				syslog(LOG_ERR,
632 				       "%s:%u: recvmsg returned invalid msg type",
633 				       __FILE__, __LINE__);
634 				return ERR_BAD_COMMAND;
635 			}
636 
637 			if (CMSG_DATA(cmptr))
638 				memcpy(received_fd, CMSG_DATA(cmptr), sizeof(int));
639 		}
640 	}
641 
642 	if (l32 > data_size) {
643 		syslog(LOG_ERR, "%s:%u: recv_msg_data: received more data than expected", __FILE__,
644 		       __LINE__);
645 		ret = ERR_BAD_COMMAND;
646 		goto cleanup;
647 	}
648 
649 	ret = force_read_timeout(fd, data, l32, MAIN_SEC_MOD_TIMEOUT);
650 	if (ret < l32) {
651 		int e = errno;
652 		syslog(LOG_ERR, "%s:%u: recvmsg: %s", __FILE__,
653 		       __LINE__, strerror(e));
654 		ret = ERR_BAD_COMMAND;
655 		goto cleanup;
656 	}
657 
658 	ret = l32;
659 
660  cleanup:
661 	if (ret < 0 && received_fd != NULL && *received_fd != -1) {
662 		close(*received_fd);
663 		*received_fd = -1;
664 	}
665 	return ret;
666 }
667 
recv_socket_msg(void * pool,int fd,uint8_t cmd,int * socketfd,void ** msg,unpack_func unpack,unsigned timeout)668 int recv_socket_msg(void *pool, int fd, uint8_t cmd,
669 		    int *socketfd, void **msg, unpack_func unpack,
670 		    unsigned timeout)
671 {
672 	struct iovec iov[3];
673 	uint32_t length;
674 	uint8_t rcmd;
675 	struct msghdr hdr;
676 	uint8_t *data = NULL;
677 	union {
678 		struct cmsghdr cm;
679 		char control[CMSG_SPACE(sizeof(int))];
680 	} control_un;
681 	struct cmsghdr *cmptr;
682 	int ret;
683 	PROTOBUF_ALLOCATOR(pa, pool);
684 
685 	iov[0].iov_base = &rcmd;
686 	iov[0].iov_len = 1;
687 
688 	iov[1].iov_base = &length;
689 	iov[1].iov_len = 4;
690 
691 	memset(&hdr, 0, sizeof(hdr));
692 	hdr.msg_iov = iov;
693 	hdr.msg_iovlen = 2;
694 
695 	hdr.msg_control = control_un.control;
696 	hdr.msg_controllen = sizeof(control_un.control);
697 
698 	ret = recvmsg_timeout(fd, &hdr, 0, timeout);
699 	if (ret == -1) {
700 		int e = errno;
701 		syslog(LOG_ERR, "%s:%u: recvmsg: %s", __FILE__, __LINE__,
702 		       strerror(e));
703 		return ERR_BAD_COMMAND;
704 	}
705 
706 	if (ret == 0) {
707 		return ERR_PEER_TERMINATED;
708 	}
709 
710 	if (rcmd != cmd) {
711 		syslog(LOG_ERR, "%s:%u: expected %d, received %d", __FILE__,
712 		       __LINE__, (int)rcmd, (int)cmd);
713 		return ERR_BAD_COMMAND;
714 	}
715 
716 	/* try to receive socket (if any) */
717 	if (socketfd != NULL) {
718 		if ((cmptr = CMSG_FIRSTHDR(&hdr)) != NULL
719 		    && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
720 			if (cmptr->cmsg_level != SOL_SOCKET
721 			    || cmptr->cmsg_type != SCM_RIGHTS) {
722 				syslog(LOG_ERR,
723 				       "%s:%u: recvmsg returned invalid msg type",
724 				       __FILE__, __LINE__);
725 				return ERR_BAD_COMMAND;
726 			}
727 
728 			if (CMSG_DATA(cmptr))
729 				memcpy(socketfd, CMSG_DATA(cmptr), sizeof(int));
730 			else
731 				*socketfd = -1;
732 		} else {
733 			*socketfd = -1;
734 		}
735 	}
736 
737 	if (length > 0 && msg) {
738 		data = talloc_size(pool, length);
739 		if (data == NULL) {
740 			ret = ERR_MEM;
741 			goto cleanup;
742 		}
743 
744 		ret = force_read_timeout(fd, data, length, timeout);
745 		if (ret < length) {
746 			int e = errno;
747 			syslog(LOG_ERR, "%s:%u: recvmsg: %s", __FILE__,
748 			       __LINE__, strerror(e));
749 			ret = ERR_BAD_COMMAND;
750 			goto cleanup;
751 		}
752 
753 		*msg = unpack(&pa, length, data);
754 		if (*msg == NULL) {
755 			syslog(LOG_ERR, "%s:%u: unpacking error", __FILE__,
756 			       __LINE__);
757 			ret = ERR_MEM;
758 			goto cleanup;
759 		}
760 	}
761 
762 	ret = 0;
763 
764  cleanup:
765 	talloc_free(data);
766 	if (ret < 0 && socketfd != NULL && *socketfd != -1) {
767 		close(*socketfd);
768 		*socketfd = -1;
769 	}
770 	return ret;
771 }
772 
773 
_talloc_free2(void * ctx,void * ptr)774 void _talloc_free2(void *ctx, void *ptr)
775 {
776 	talloc_free(ptr);
777 }
778 
_talloc_size2(void * ctx,size_t size)779 void *_talloc_size2(void *ctx, size_t size)
780 {
781 	return talloc_size(ctx, size);
782 }
783 
784 /* like recvfrom but also returns the address of our interface.
785  *
786  * @def_port: is provided to fill in the missing port number
787  *   in our_addr.
788  */
oc_recvfrom_at(int sockfd,void * buf,size_t len,int flags,struct sockaddr * src_addr,socklen_t * addrlen,struct sockaddr * our_addr,socklen_t * our_addrlen,int def_port)789 ssize_t oc_recvfrom_at(int sockfd, void *buf, size_t len, int flags,
790 		       struct sockaddr * src_addr, socklen_t * addrlen,
791 		       struct sockaddr * our_addr, socklen_t * our_addrlen,
792 		       int def_port)
793 {
794 	int ret;
795 	char cmbuf[256];
796 	struct iovec iov = { buf, len };
797 	struct cmsghdr *cmsg;
798 	struct msghdr mh = {
799 		.msg_name = src_addr,
800 		.msg_namelen = *addrlen,
801 		.msg_iov = &iov,
802 		.msg_iovlen = 1,
803 		.msg_control = cmbuf,
804 		.msg_controllen = sizeof(cmbuf),
805 	};
806 
807 	do {
808 		ret = recvmsg(sockfd, &mh, 0);
809 	} while (ret == -1 && errno == EINTR);
810 	if (ret < 0) {
811 		return -1;
812 	}
813 
814 	/* find our address */
815 	for (cmsg = CMSG_FIRSTHDR(&mh); cmsg != NULL;
816 	     cmsg = CMSG_NXTHDR(&mh, cmsg)) {
817 #if defined(IP_PKTINFO)
818 		if (cmsg->cmsg_level == IPPROTO_IP
819 		    && cmsg->cmsg_type == IP_PKTINFO) {
820 			struct in_pktinfo *pi = (void *)CMSG_DATA(cmsg);
821 			struct sockaddr_in *a = (struct sockaddr_in *)our_addr;
822 
823 			if (*our_addrlen < sizeof(struct sockaddr_in)
824 			    || pi == NULL)
825 				return -1;
826 
827 			a->sin_family = AF_INET;
828 			memcpy(&a->sin_addr, &pi->ipi_addr,
829 			       sizeof(struct in_addr));
830 			a->sin_port = htons(def_port);
831 			*our_addrlen = sizeof(struct sockaddr_in);
832 			break;
833 		}
834 #elif defined(IP_RECVDSTADDR)
835 		if (cmsg->cmsg_level == IPPROTO_IP
836 		    && cmsg->cmsg_type == IP_RECVDSTADDR) {
837 			struct in_addr *pi = (void *)CMSG_DATA(cmsg);
838 			struct sockaddr_in *a = (struct sockaddr_in *)our_addr;
839 
840 			if (*our_addrlen < sizeof(struct sockaddr_in)
841 			    || pi == NULL)
842 				return -1;
843 
844 			a->sin_family = AF_INET;
845 			memcpy(&a->sin_addr, &pi->s_addr,
846 			       sizeof(struct in_addr));
847 			a->sin_port = htons(def_port);
848 			*our_addrlen = sizeof(struct sockaddr_in);
849 			break;
850 		}
851 #endif
852 #ifdef IPV6_RECVPKTINFO
853 		if (cmsg->cmsg_level == IPPROTO_IPV6
854 		    && cmsg->cmsg_type == IPV6_PKTINFO) {
855 			struct in6_pktinfo *pi = (void *)CMSG_DATA(cmsg);
856 			struct sockaddr_in6 *a =
857 			    (struct sockaddr_in6 *)our_addr;
858 
859 			if (*our_addrlen < sizeof(struct sockaddr_in6)
860 			    || pi == NULL)
861 				return -1;
862 
863 			a->sin6_family = AF_INET6;
864 			memcpy(&a->sin6_addr, &pi->ipi6_addr,
865 			       sizeof(struct in6_addr));
866 			a->sin6_port = htons(def_port);
867 			*our_addrlen = sizeof(struct sockaddr_in6);
868 			break;
869 		}
870 #endif
871 	}
872 	*addrlen = mh.msg_namelen;
873 
874 	return ret;
875 }
876 
877 #ifndef HAVE_STRLCPY
878 
879 /*
880  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
881  *
882  * Permission to use, copy, modify, and distribute this software for any
883  * purpose with or without fee is hereby granted, provided that the above
884  * copyright notice and this permission notice appear in all copies.
885  *
886  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
887  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
888  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
889  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
890  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
891  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
892  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
893  *
894  * Copyright 2006  The FreeRADIUS server project
895  */
896 
897 /*
898  * Copy src to string dst of size siz.  At most siz-1 characters
899  * will be copied.  Always NUL terminates (unless siz == 0).
900  * Returns strlen(src); if retval >= siz, truncation occurred.
901  */
oc_strlcpy(char * dst,char const * src,size_t siz)902 size_t oc_strlcpy(char *dst, char const *src, size_t siz)
903 {
904 	char *d = dst;
905 	char const *s = src;
906 	size_t n = siz;
907 
908 	/* Copy as many bytes as will fit */
909 	if (n != 0 && --n != 0) {
910 		do {
911 			if ((*d++ = *s++) == 0)
912 				break;
913 		} while (--n != 0);
914 	}
915 
916 	/* Not enough room in dst, add NUL and traverse rest of src */
917 	if (n == 0) {
918 		if (siz != 0)
919 			*d = '\0';	/* NUL-terminate dst */
920 		while (*s++) ;
921 	}
922 
923 	return (s - src - 1);	/* count does not include NUL */
924 }
925 
926 #endif
927 
928