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