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