]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/priv.c
Change the way interface information are collected.
[thirdparty/lldpd.git] / src / priv.c
CommitLineData
b5562b23
VB
1/*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* This file contains code for privilege separation. When an error arises in
18 * monitor (which is running as root), it just stops instead of trying to
19 * recover. This module also contains proxies to privileged operations. In this
20 * case, error can be non fatal. */
21
22#include "lldpd.h"
23
24#include <stdio.h>
25#include <unistd.h>
26#include <errno.h>
27#include <sys/types.h>
28#include <sys/wait.h>
29#include <sys/stat.h>
29e043b5 30#include <sys/types.h>
d72a05d4
VB
31#include <sys/socket.h>
32#include <sys/un.h>
29e043b5 33#include <regex.h>
b5562b23
VB
34#include <fcntl.h>
35#include <pwd.h>
36#include <grp.h>
37#include <sys/utsname.h>
4afe659e 38#include <sys/ioctl.h>
b5562b23 39#include <netdb.h>
4afe659e 40#include <linux/sockios.h>
021a304e 41#include <linux/if_packet.h>
c933faf6
VB
42#include <netinet/in.h>
43#include <arpa/nameser.h>
44#include <resolv.h>
4afe659e
VB
45
46enum {
d72a05d4 47 PRIV_PING,
4afe659e
VB
48 PRIV_CREATE_CTL_SOCKET,
49 PRIV_DELETE_CTL_SOCKET,
50 PRIV_GET_HOSTNAME,
51 PRIV_OPEN,
52 PRIV_ETHTOOL,
a7502371
VB
53 PRIV_IFACE_INIT,
54 PRIV_IFACE_MULTICAST,
d72a05d4 55 PRIV_SNMP_SOCKET,
b5562b23
VB
56};
57
4afe659e
VB
58static int may_read(int, void *, size_t);
59static void must_read(int, void *, size_t);
ef76f920 60static void must_write(int, const void *, size_t);
b5562b23 61
8888d191
VB
62static int remote; /* Other side */
63static int monitored = -1; /* Child */
64static int sock = -1;
b5562b23 65
33aced7a 66/* UID/GID of unprivileged user */
8888d191
VB
67static gid_t gid = 0;
68static uid_t uid = 0;
33aced7a 69
b5562b23
VB
70/* Proxies */
71
8888d191 72static void
d72a05d4
VB
73priv_ping()
74{
75 int cmd, rc;
76 cmd = PRIV_PING;
77 must_write(remote, &cmd, sizeof(int));
78 must_read(remote, &rc, sizeof(int));
79 LLOG_DEBUG("monitor ready");
80}
81
b5562b23
VB
82/* Proxy for ctl_create, no argument since this is the monitor that decides the
83 * location of the socket */
84int
85priv_ctl_create()
86{
4afe659e
VB
87 int cmd, rc;
88 cmd = PRIV_CREATE_CTL_SOCKET;
89 must_write(remote, &cmd, sizeof(int));
90 must_read(remote, &rc, sizeof(int));
91 if (rc == -1)
b5562b23 92 return -1;
4afe659e 93 return receive_fd(remote);
b5562b23
VB
94}
95
96/* Proxy for ctl_cleanup */
97void
98priv_ctl_cleanup()
99{
4afe659e
VB
100 int cmd, rc;
101 cmd = PRIV_DELETE_CTL_SOCKET;
102 must_write(remote, &cmd, sizeof(int));
103 must_read(remote, &rc, sizeof(int));
b5562b23
VB
104}
105
106/* Proxy for gethostbyname */
107char *
108priv_gethostbyname()
109{
4afe659e
VB
110 int cmd, rc;
111 static char *buf = NULL;
112 cmd = PRIV_GET_HOSTNAME;
113 must_write(remote, &cmd, sizeof(int));
114 must_read(remote, &rc, sizeof(int));
115 if ((buf = (char*)realloc(buf, rc+1)) == NULL)
116 fatal(NULL);
117 must_read(remote, buf, rc+1);
118 return buf;
b5562b23
VB
119}
120
121/* Proxy for open */
122int
123priv_open(char *file)
124{
4afe659e
VB
125 int cmd, len, rc;
126 cmd = PRIV_OPEN;
127 must_write(remote, &cmd, sizeof(int));
128 len = strlen(file);
129 must_write(remote, &len, sizeof(int));
130 must_write(remote, file, len + 1);
131 must_read(remote, &rc, sizeof(int));
132 if (rc == -1)
133 return rc;
134 return receive_fd(remote);
135}
136
137/* Proxy for ethtool ioctl */
138int
139priv_ethtool(char *ifname, struct ethtool_cmd *ethc)
140{
141 int cmd, rc, len;
142 cmd = PRIV_ETHTOOL;
143 must_write(remote, &cmd, sizeof(int));
144 len = strlen(ifname);
145 must_write(remote, &len, sizeof(int));
146 must_write(remote, ifname, len + 1);
147 must_read(remote, &rc, sizeof(int));
148 if (rc != 0)
149 return rc;
150 must_read(remote, ethc, sizeof(struct ethtool_cmd));
151 return rc;
b5562b23
VB
152}
153
a7502371 154int
6e75df87 155priv_iface_eth_init(struct lldpd_hardware *hardware)
a7502371
VB
156{
157 int cmd, rc;
158 cmd = PRIV_IFACE_INIT;
159 must_write(remote, &cmd, sizeof(int));
a7502371
VB
160 must_write(remote, hardware->h_ifname, IFNAMSIZ);
161 must_read(remote, &rc, sizeof(int));
162 if (rc != 0)
163 return rc; /* It's errno */
6e75df87 164 hardware->h_sendfd = receive_fd(remote);
a7502371
VB
165 return 0;
166}
167
168int
ef76f920 169priv_iface_multicast(const char *name, u_int8_t *mac, int add)
a7502371
VB
170{
171 int cmd, rc;
172 cmd = PRIV_IFACE_MULTICAST;
d72a05d4 173 must_write(remote, &cmd, sizeof(int));
a7502371
VB
174 must_write(remote, name, IFNAMSIZ);
175 must_write(remote, mac, ETH_ALEN);
176 must_write(remote, &add, sizeof(int));
177 must_read(remote, &rc, sizeof(int));
178 return rc;
179}
180
d72a05d4
VB
181int
182priv_snmp_socket(struct sockaddr_un *addr)
183{
184 int cmd, rc;
185 cmd = PRIV_SNMP_SOCKET;
186 must_write(remote, &cmd, sizeof(int));
187 must_write(remote, addr, sizeof(struct sockaddr_un));
188 must_read(remote, &rc, sizeof(int));
189 if (rc < 0)
190 return rc;
191 return receive_fd(remote);
192}
193
8888d191 194static void
d72a05d4
VB
195asroot_ping()
196{
197 int rc = 1;
198 must_write(remote, &rc, sizeof(int));
199}
200
8888d191 201static void
4afe659e 202asroot_ctl_create()
b5562b23 203{
4afe659e
VB
204 int rc;
205 if ((rc = ctl_create(LLDPD_CTL_SOCKET)) == -1) {
206 LLOG_WARN("[priv]: unable to create control socket");
207 must_write(remote, &rc, sizeof(int));
208 return;
b5562b23 209 }
33aced7a
VB
210 if (chown(LLDPD_CTL_SOCKET, uid, gid) == -1)
211 LLOG_WARN("[priv]: unable to chown control socket");
212 if (chmod(LLDPD_CTL_SOCKET,
213 S_IRUSR | S_IWUSR | S_IXUSR |
214 S_IRGRP | S_IWGRP | S_IXGRP) == -1)
215 LLOG_WARN("[priv]: unable to chmod control socket");
4afe659e
VB
216 must_write(remote, &rc, sizeof(int));
217 send_fd(remote, rc);
218 close(rc);
b5562b23
VB
219}
220
8888d191 221static void
4afe659e 222asroot_ctl_cleanup()
b5562b23 223{
4afe659e 224 int rc = 0;
b5562b23 225 ctl_cleanup(LLDPD_CTL_SOCKET);
4afe659e
VB
226
227 /* Ack */
228 must_write(remote, &rc, sizeof(int));
b5562b23
VB
229}
230
8888d191 231static void
4afe659e 232asroot_gethostbyname()
b5562b23
VB
233{
234 struct utsname un;
235 struct hostent *hp;
4afe659e 236 int len;
b5562b23 237 if (uname(&un) != 0)
4afe659e 238 fatal("[priv]: failed to get system information");
b5a6c479 239 if ((hp = gethostbyname(un.nodename)) == NULL) {
c933faf6
VB
240 LLOG_INFO("[priv]: unable to get system name");
241 res_init();
b5a6c479
VB
242 len = strlen(un.nodename);
243 must_write(remote, &len, sizeof(int));
244 must_write(remote, un.nodename, len + 1);
245 } else {
246 len = strlen(hp->h_name);
247 must_write(remote, &len, sizeof(int));
248 must_write(remote, hp->h_name, len + 1);
249 }
b5562b23
VB
250}
251
8888d191 252static void
4afe659e 253asroot_open()
b5562b23 254{
4afe659e 255 const char* authorized[] = {
b5562b23 256 "/proc/sys/net/ipv4/ip_forward",
1d291522
VB
257 "/proc/net/bonding/[^.][^/]*",
258 "/proc/self/net/bonding/[^.][^/]*",
89840df0
VB
259 SYSFS_CLASS_NET "[^.][^/]*/brforward",
260 SYSFS_CLASS_NET "[^.][^/]*/brport",
bac91719 261 SYSFS_CLASS_NET "[^.][^/]*/brif/[^.][^/]*/port_no",
89840df0
VB
262 SYSFS_CLASS_DMI "product_version",
263 SYSFS_CLASS_DMI "product_serial",
264 SYSFS_CLASS_DMI "product_name",
265 SYSFS_CLASS_DMI "bios_version",
266 SYSFS_CLASS_DMI "sys_vendor",
267 SYSFS_CLASS_DMI "chassis_asset_tag",
b5562b23
VB
268 NULL
269 };
ef76f920 270 const char **f;
4afe659e
VB
271 char *file;
272 int fd, len, rc;
29e043b5 273 regex_t preg;
4afe659e
VB
274
275 must_read(remote, &len, sizeof(len));
276 if ((file = (char *)malloc(len + 1)) == NULL)
277 fatal(NULL);
29e043b5
VB
278 must_read(remote, file, len);
279 file[len] = '\0';
b5562b23
VB
280
281 for (f=authorized; *f != NULL; f++) {
29e043b5
VB
282 if (regcomp(&preg, *f, REG_NOSUB) != 0)
283 /* Should not happen */
284 fatal("unable to compile a regex");
285 if (regexec(&preg, file, 0, NULL, 0) == 0) {
286 regfree(&preg);
4afe659e 287 break;
29e043b5
VB
288 }
289 regfree(&preg);
b5562b23 290 }
4afe659e
VB
291 if (*f == NULL) {
292 LLOG_WARNX("[priv]: not authorized to open %s", file);
293 rc = -1;
294 must_write(remote, &rc, sizeof(int));
295 free(file);
b5562b23
VB
296 return;
297 }
0aa5f676 298 if ((fd = open(file, O_RDONLY)) == -1) {
4afe659e
VB
299 rc = -1;
300 must_write(remote, &rc, sizeof(int));
301 free(file);
b5562b23
VB
302 return;
303 }
4afe659e
VB
304 free(file);
305 must_write(remote, &fd, sizeof(int));
306 send_fd(remote, fd);
b5562b23
VB
307 close(fd);
308}
309
8888d191 310static void
4afe659e
VB
311asroot_ethtool()
312{
313 struct ifreq ifr;
314 struct ethtool_cmd ethc;
a7502371 315 int len, rc;
4afe659e
VB
316 char *ifname;
317
318 memset(&ifr, 0, sizeof(ifr));
319 memset(&ethc, 0, sizeof(ethc));
320 must_read(remote, &len, sizeof(int));
321 if ((ifname = (char*)malloc(len + 1)) == NULL)
322 fatal(NULL);
29e043b5
VB
323 must_read(remote, ifname, len);
324 ifname[len] = '\0';
4afe659e 325 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
aabbb9ac 326 free(ifname);
4afe659e
VB
327 ifr.ifr_data = (caddr_t)&ethc;
328 ethc.cmd = ETHTOOL_GSET;
4afe659e 329 if ((rc = ioctl(sock, SIOCETHTOOL, &ifr)) != 0) {
4afe659e 330 must_write(remote, &rc, sizeof(int));
4afe659e
VB
331 return;
332 }
4afe659e
VB
333 must_write(remote, &rc, sizeof(int));
334 must_write(remote, &ethc, sizeof(struct ethtool_cmd));
335}
336
8888d191 337static void
6e75df87 338asroot_iface_eth_init()
a7502371
VB
339{
340 struct sockaddr_ll sa;
6e75df87 341 int s;
a7502371
VB
342 char ifname[IFNAMSIZ];
343
a7502371 344 must_read(remote, ifname, IFNAMSIZ);
29e043b5 345 ifname[IFNAMSIZ-1] = '\0';
a7502371
VB
346
347 /* Open listening socket to receive/send frames */
348 if ((s = socket(PF_PACKET, SOCK_RAW,
349 htons(ETH_P_ALL))) < 0) {
350 must_write(remote, &errno, sizeof(errno));
351 return;
352 }
353 memset(&sa, 0, sizeof(sa));
354 sa.sll_family = AF_PACKET;
355 sa.sll_protocol = 0;
6e75df87 356 sa.sll_ifindex = if_nametoindex(ifname);
a7502371
VB
357 if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
358 must_write(remote, &errno, sizeof(errno));
359 close(s);
360 return;
361 }
a7502371
VB
362 errno = 0;
363 must_write(remote, &errno, sizeof(errno));
364 send_fd(remote, s);
365 close(s);
366}
367
8888d191 368static void
a7502371
VB
369asroot_iface_multicast()
370{
371 int add, rc = 0;
372 struct ifreq ifr;
373 memset(&ifr, 0, sizeof(ifr));
374 must_read(remote, ifr.ifr_name, IFNAMSIZ);
29e043b5 375 ifr.ifr_name[IFNAMSIZ-1] = '\0';
a7502371
VB
376 must_read(remote, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
377 must_read(remote, &add, sizeof(int));
378
379 if (ioctl(sock, (add)?SIOCADDMULTI:SIOCDELMULTI,
380 &ifr) < 0) {
381 must_write(remote, &errno, sizeof(errno));
382 return;
509861fe
VB
383 }
384
a7502371
VB
385 must_write(remote, &rc, sizeof(rc));
386}
387
d72a05d4
VB
388static void
389asroot_snmp_socket()
390{
391 int sock, rc;
392 static struct sockaddr_un *addr = NULL;
393 struct sockaddr_un bogus;
394
395 if (!addr) {
396 addr = (struct sockaddr_un *)malloc(sizeof(struct sockaddr_un));
397 must_read(remote, addr, sizeof(struct sockaddr_un));
398 } else
399 /* We have already been asked to connect to a socket. We will
400 * connect to the same socket. */
401 must_read(remote, &bogus, sizeof(struct sockaddr_un));
402 if (addr->sun_family != AF_UNIX)
403 fatal("someone is trying to trick me");
404 addr->sun_path[sizeof(addr->sun_path)-1] = '\0';
405
406 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
33aced7a 407 LLOG_WARN("[priv]: cannot open socket");
d72a05d4
VB
408 must_write(remote, &sock, sizeof(int));
409 return;
410 }
411 if ((rc = connect(sock, (struct sockaddr *) addr,
412 sizeof(struct sockaddr_un))) != 0) {
5ac76eba
VB
413 LLOG_INFO("[priv]: cannot connect to %s: %s",
414 addr->sun_path, strerror(errno));
d72a05d4
VB
415 close(sock);
416 rc = -1;
417 must_write(remote, &rc, sizeof(int));
418 return;
419 }
420 must_write(remote, &rc, sizeof(int));
421 send_fd(remote, sock);
e7c8287d 422 close(sock);
d72a05d4
VB
423}
424
b5562b23
VB
425struct dispatch_actions {
426 int msg;
4afe659e 427 void(*function)(void);
b5562b23
VB
428};
429
8888d191 430static struct dispatch_actions actions[] = {
d72a05d4 431 {PRIV_PING, asroot_ping},
4afe659e
VB
432 {PRIV_CREATE_CTL_SOCKET, asroot_ctl_create},
433 {PRIV_DELETE_CTL_SOCKET, asroot_ctl_cleanup},
434 {PRIV_GET_HOSTNAME, asroot_gethostbyname},
435 {PRIV_OPEN, asroot_open},
436 {PRIV_ETHTOOL, asroot_ethtool},
6e75df87 437 {PRIV_IFACE_INIT, asroot_iface_eth_init},
a7502371 438 {PRIV_IFACE_MULTICAST, asroot_iface_multicast},
d72a05d4 439 {PRIV_SNMP_SOCKET, asroot_snmp_socket},
4afe659e 440 {-1, NULL}
b5562b23
VB
441};
442
443/* Main loop, run as root */
8888d191 444static void
b5562b23
VB
445priv_loop()
446{
4afe659e 447 int cmd;
b5562b23
VB
448 struct dispatch_actions *a;
449
4afe659e 450 while (!may_read(remote, &cmd, sizeof(int))) {
b5562b23 451 for (a = actions; a->function != NULL; a++) {
4afe659e
VB
452 if (cmd == a->msg) {
453 a->function();
b5562b23
VB
454 break;
455 }
456 }
457 if (a->function == NULL)
4afe659e 458 fatal("[priv]: bogus message received");
b5562b23
VB
459 }
460 /* Should never be there */
461}
462
8888d191 463static void
b5562b23
VB
464priv_exit()
465{
466 int status;
467 int rc;
468 if ((rc = waitpid(monitored, &status, WNOHANG)) == 0) {
4afe659e 469 LLOG_DEBUG("[priv]: killing child");
b5562b23
VB
470 kill(monitored, SIGTERM);
471 }
472 if ((rc = waitpid(monitored, &status, WNOHANG)) == -1)
473 _exit(0);
4afe659e 474 LLOG_DEBUG("[priv]: waiting for child %d to terminate", monitored);
b5562b23
VB
475}
476
4afe659e
VB
477/* If priv parent gets a TERM or HUP, pass it through to child instead */
478static void
479sig_pass_to_chld(int sig)
b5562b23 480{
4afe659e
VB
481 int oerrno = errno;
482 if (monitored != -1)
483 kill(monitored, sig);
484 errno = oerrno;
485}
486
487/* if parent gets a SIGCHLD, it will exit */
488static void
489sig_chld(int sig)
490{
491 LLOG_DEBUG("[priv]: received signal %d, exiting", sig);
b5562b23
VB
492 priv_exit();
493}
494
495/* Initialization */
496void
a2993d83 497priv_init(char *chrootdir)
b5562b23
VB
498{
499 int pair[2];
500 struct passwd *user;
b5562b23 501 struct group *group;
4afe659e 502 gid_t gidset[1];
90149ee3 503 int status;
b5562b23
VB
504
505 /* Create socket pair */
4afe659e
VB
506 if (socketpair(AF_LOCAL, SOCK_DGRAM, PF_UNSPEC, pair) < 0)
507 fatal("[priv]: unable to create socket pair for privilege separation");
b5562b23
VB
508
509 /* Get users */
510 if ((user = getpwnam(PRIVSEP_USER)) == NULL)
4afe659e 511 fatal("[priv]: no " PRIVSEP_USER " user for privilege separation");
b5562b23
VB
512 uid = user->pw_uid;
513 if ((group = getgrnam(PRIVSEP_GROUP)) == NULL)
4afe659e 514 fatal("[priv]: no " PRIVSEP_GROUP " group for privilege separation");
b5562b23
VB
515 gid = group->gr_gid;
516
517 /* Spawn off monitor */
518 if ((monitored = fork()) < 0)
4afe659e 519 fatal("[priv]: unable to fork monitor");
b5562b23
VB
520 switch (monitored) {
521 case 0:
522 /* We are in the children, drop privileges */
a2993d83 523 if (chroot(chrootdir) == -1)
4afe659e
VB
524 fatal("[priv]: unable to chroot");
525 if (chdir("/") != 0)
526 fatal("[priv]: unable to chdir");
527 gidset[0] = gid;
528 if (setresgid(gid, gid, gid) == -1)
529 fatal("[priv]: setresgid() failed");
530 if (setgroups(1, gidset) == -1)
531 fatal("[priv]: setgroups() failed");
532 if (setresuid(uid, uid, uid) == -1)
533 fatal("[priv]: setresuid() failed");
b5562b23
VB
534 remote = pair[0];
535 close(pair[1]);
d72a05d4 536 priv_ping();
b5562b23
VB
537 break;
538 default:
539 /* We are in the monitor */
540 remote = pair[1];
541 close(pair[0]);
542 if (atexit(priv_exit) != 0)
4afe659e 543 fatal("[priv]: unable to set exit function");
a7502371
VB
544 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
545 fatal("[priv]: unable to get a socket");
546 }
4afe659e
VB
547
548 signal(SIGALRM, sig_pass_to_chld);
549 signal(SIGTERM, sig_pass_to_chld);
550 signal(SIGHUP, sig_pass_to_chld);
551 signal(SIGINT, sig_pass_to_chld);
552 signal(SIGQUIT, sig_pass_to_chld);
553 signal(SIGCHLD, sig_chld);
90149ee3
VB
554 if (waitpid(monitored, &status, WNOHANG) != 0)
555 /* Child is already dead */
556 _exit(1);
b5562b23
VB
557 priv_loop();
558 exit(0);
559 }
b5562b23 560}
4afe659e
VB
561
562/* Stolen from sbin/pflogd/privsep.c from OpenBSD */
563/*
564 * Copyright (c) 2003 Can Erkin Acar
565 * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
566 *
567 * Permission to use, copy, modify, and distribute this software for any
568 * purpose with or without fee is hereby granted, provided that the above
569 * copyright notice and this permission notice appear in all copies.
570 *
571 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
572 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
573 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
574 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
575 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
576 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
577 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
578 */
579
580/* Read all data or return 1 for error. */
581static int
582may_read(int fd, void *buf, size_t n)
583{
584 char *s = buf;
585 ssize_t res, pos = 0;
586
587 while (n > pos) {
588 res = read(fd, s + pos, n - pos);
589 switch (res) {
590 case -1:
591 if (errno == EINTR || errno == EAGAIN)
592 continue;
593 case 0:
594 return (1);
595 default:
596 pos += res;
597 }
598 }
599 return (0);
600}
601
602/* Read data with the assertion that it all must come through, or
603 * else abort the process. Based on atomicio() from openssh. */
604static void
605must_read(int fd, void *buf, size_t n)
606{
607 char *s = buf;
608 ssize_t res, pos = 0;
609
610 while (n > pos) {
611 res = read(fd, s + pos, n - pos);
612 switch (res) {
613 case -1:
614 if (errno == EINTR || errno == EAGAIN)
615 continue;
616 case 0:
617 _exit(0);
618 default:
619 pos += res;
620 }
621 }
622}
623
624/* Write data with the assertion that it all has to be written, or
625 * else abort the process. Based on atomicio() from openssh. */
626static void
ef76f920 627must_write(int fd, const void *buf, size_t n)
4afe659e 628{
ef76f920 629 const char *s = buf;
4afe659e
VB
630 ssize_t res, pos = 0;
631
632 while (n > pos) {
633 res = write(fd, s + pos, n - pos);
634 switch (res) {
635 case -1:
636 if (errno == EINTR || errno == EAGAIN)
637 continue;
638 case 0:
639 _exit(0);
640 default:
641 pos += res;
642 }
643 }
644}