1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1999-2001 Brian Somers <brian@Awfulhak.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/socket.h> 31 #include <sys/un.h> 32 #include <netinet/in.h> 33 #include <arpa/inet.h> 34 #include <netdb.h> 35 #include <netgraph.h> 36 #include <net/ethernet.h> 37 #include <netinet/in_systm.h> 38 #include <netinet/ip.h> 39 #include <netgraph/ng_ether.h> 40 #include <netgraph/ng_message.h> 41 #include <netgraph/ng_pppoe.h> 42 #include <netgraph/ng_socket.h> 43 44 #include <errno.h> 45 #include <paths.h> 46 #include <signal.h> 47 #include <stdio.h> 48 #include <stdarg.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <sysexits.h> 52 #include <sys/fcntl.h> 53 #ifndef NOKLDLOAD 54 #include <sys/linker.h> 55 #include <sys/module.h> 56 #endif 57 #include <sys/uio.h> 58 #include <sys/wait.h> 59 #include <syslog.h> 60 #include <termios.h> 61 #include <unistd.h> 62 63 64 #define DEFAULT_EXEC_PREFIX "exec /usr/sbin/ppp -direct " 65 #define HISMACADDR "HISMACADDR" 66 #define SESSION_ID "SESSION_ID" 67 68 static void nglogx(const char *, ...) __printflike(1, 2); 69 70 static int ReceivedSignal; 71 72 static int 73 usage(const char *prog) 74 { 75 fprintf(stderr, "usage: %s [-Fd] [-P pidfile] [-a name] [-e exec | -l label]" 76 " [-n ngdebug] [-p provider] interface\n", prog); 77 return EX_USAGE; 78 } 79 80 static void 81 Farewell(int sig) 82 { 83 ReceivedSignal = sig; 84 } 85 86 static int 87 ConfigureNode(const char *prog, const char *iface, const char *provider, 88 int cs, int ds, int debug, struct ngm_connect *ngc) 89 { 90 /* 91 * We're going to do this with the passed `ds' & `cs' descriptors: 92 * 93 * .---------. 94 * | ether | 95 * | <iface> | 96 * `---------' 97 * (orphan) ds cs 98 * | | | 99 * | | | 100 * (ethernet) | | 101 * .---------. .-----------. 102 * | pppoe | | socket | 103 * | <iface> |(pppoe-<pid>)<---->(pppoe-<pid>)| <unnamed> | 104 * `--------- `-----------' 105 * (exec-<pid>) 106 * ^ .-----------. .-------------. 107 * | | socket | | ppp -direct | 108 * `--->(exec-<pid>)| <unnamed> |--fd--| provider | 109 * `-----------' `-------------' 110 * 111 * where there are potentially many ppp processes running off of the 112 * same PPPoE node. 113 * The exec-<pid> hook isn't made 'till we Spawn(). 114 */ 115 116 char *epath, *spath; 117 struct ngpppoe_init_data *data; 118 const struct hooklist *hlist; 119 const struct nodeinfo *ninfo; 120 const struct linkinfo *nlink; 121 struct ngm_mkpeer mkp; 122 struct ng_mesg *resp; 123 u_char rbuf[2048]; 124 int f, plen; 125 126 /* 127 * Ask for a list of hooks attached to the "ether" node. This node should 128 * magically exist as a way of hooking stuff onto an ethernet device 129 */ 130 epath = (char *)alloca(strlen(iface) + 2); 131 sprintf(epath, "%s:", iface); 132 133 if (debug) 134 fprintf(stderr, "Sending NGM_LISTHOOKS to %s\n", epath); 135 136 if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { 137 if (errno == ENOENT) 138 fprintf(stderr, "%s Cannot send a netgraph message: Invalid interface\n", 139 epath); 140 else 141 fprintf(stderr, "%s Cannot send a netgraph message: %s\n", 142 epath, strerror(errno)); 143 return EX_UNAVAILABLE; 144 } 145 146 /* Get our list back */ 147 resp = (struct ng_mesg *)rbuf; 148 if (NgRecvMsg(cs, resp, sizeof rbuf, NULL) <= 0) { 149 perror("Cannot get netgraph response"); 150 return EX_UNAVAILABLE; 151 } 152 153 hlist = (const struct hooklist *)resp->data; 154 ninfo = &hlist->nodeinfo; 155 156 if (debug) 157 fprintf(stderr, "Got reply from id [%x]: Type %s with %d hooks\n", 158 ninfo->id, ninfo->type, ninfo->hooks); 159 160 /* Make sure we've got the right type of node */ 161 if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, sizeof NG_ETHER_NODE_TYPE - 1)) { 162 fprintf(stderr, "%s Unexpected node type ``%s'' (wanted ``" 163 NG_ETHER_NODE_TYPE "'')\n", epath, ninfo->type); 164 return EX_DATAERR; 165 } 166 167 /* look for a hook already attached. */ 168 for (f = 0; f < ninfo->hooks; f++) { 169 nlink = &hlist->link[f]; 170 171 if (debug) 172 fprintf(stderr, " Got [%x]:%s -> [%x]:%s\n", ninfo->id, 173 nlink->ourhook, nlink->nodeinfo.id, nlink->peerhook); 174 175 if (!strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) || 176 !strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT)) { 177 /* 178 * Something is using the data coming out of this `ether' node. 179 * If it's a PPPoE node, we use that node, otherwise we complain that 180 * someone else is using the node. 181 */ 182 if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) { 183 fprintf(stderr, "%s Node type %s is currently active\n", 184 epath, nlink->nodeinfo.type); 185 return EX_UNAVAILABLE; 186 } 187 break; 188 } 189 } 190 191 if (f == ninfo->hooks) { 192 /* 193 * Create a new PPPoE node connected to the `ether' node using 194 * the magic `orphan' and `ethernet' hooks 195 */ 196 snprintf(mkp.type, sizeof mkp.type, "%s", NG_PPPOE_NODE_TYPE); 197 snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", NG_ETHER_HOOK_ORPHAN); 198 snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", NG_PPPOE_HOOK_ETHERNET); 199 200 if (debug) 201 fprintf(stderr, "Send MKPEER: %s%s -> [type %s]:%s\n", epath, 202 mkp.ourhook, mkp.type, mkp.peerhook); 203 204 if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, 205 NGM_MKPEER, &mkp, sizeof mkp) < 0) { 206 fprintf(stderr, "%s Cannot create a peer PPPoE node: %s\n", 207 epath, strerror(errno)); 208 return EX_OSERR; 209 } 210 } 211 212 /* Connect the PPPoE node to our socket node. */ 213 snprintf(ngc->path, sizeof ngc->path, "%s%s", epath, NG_ETHER_HOOK_ORPHAN); 214 snprintf(ngc->ourhook, sizeof ngc->ourhook, "pppoe-%ld", (long)getpid()); 215 memcpy(ngc->peerhook, ngc->ourhook, sizeof ngc->peerhook); 216 217 if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, 218 NGM_CONNECT, ngc, sizeof *ngc) < 0) { 219 perror("Cannot CONNECT PPPoE and socket nodes"); 220 return EX_OSERR; 221 } 222 223 plen = strlen(provider); 224 225 data = (struct ngpppoe_init_data *)alloca(sizeof *data + plen); 226 snprintf(data->hook, sizeof data->hook, "%s", ngc->peerhook); 227 memcpy(data->data, provider, plen); 228 data->data_len = plen; 229 230 spath = (char *)alloca(strlen(ngc->peerhook) + 3); 231 strcpy(spath, ".:"); 232 strcpy(spath + 2, ngc->ourhook); 233 234 if (debug) { 235 if (provider) 236 fprintf(stderr, "Sending PPPOE_LISTEN to %s, provider %s\n", 237 spath, provider); 238 else 239 fprintf(stderr, "Sending PPPOE_LISTEN to %s\n", spath); 240 } 241 242 if (NgSendMsg(cs, spath, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN, 243 data, sizeof *data + plen) == -1) { 244 fprintf(stderr, "%s: Cannot LISTEN on netgraph node: %s\n", 245 spath, strerror(errno)); 246 return EX_OSERR; 247 } 248 249 return 0; 250 } 251 252 static void 253 Spawn(const char *prog, const char *acname, const char *provider, 254 const char *exec, struct ngm_connect ngc, int cs, int ds, void *request, 255 int sz, int debug) 256 { 257 char msgbuf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)]; 258 struct ng_mesg *rep = (struct ng_mesg *)msgbuf; 259 struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep); 260 struct ngpppoe_init_data *data; 261 char env[18], unknown[14], sessionid[5], *path; 262 unsigned char *macaddr; 263 const char *msg; 264 int ret, slen; 265 266 switch ((ret = fork())) { 267 case -1: 268 syslog(LOG_ERR, "fork: %m"); 269 break; 270 271 case 0: 272 switch (fork()) { 273 case 0: 274 break; 275 case -1: 276 _exit(errno); 277 default: 278 _exit(0); 279 } 280 close(cs); 281 close(ds); 282 283 /* Create a new socket node */ 284 if (debug) 285 syslog(LOG_INFO, "Creating a new socket node"); 286 287 if (NgMkSockNode(NULL, &cs, &ds) == -1) { 288 syslog(LOG_ERR, "Cannot create netgraph socket node: %m"); 289 _exit(EX_CANTCREAT); 290 } 291 292 /* Connect the PPPoE node to our new socket node. */ 293 snprintf(ngc.ourhook, sizeof ngc.ourhook, "exec-%ld", (long)getpid()); 294 memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook); 295 296 if (debug) 297 syslog(LOG_INFO, "Sending CONNECT from .:%s -> %s.%s", 298 ngc.ourhook, ngc.path, ngc.peerhook); 299 if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, 300 NGM_CONNECT, &ngc, sizeof ngc) < 0) { 301 syslog(LOG_ERR, "Cannot CONNECT PPPoE and socket nodes: %m"); 302 _exit(EX_OSERR); 303 } 304 305 /* 306 * If we tell the socket node not to LINGER, it will go away when 307 * the last hook is removed. 308 */ 309 if (debug) 310 syslog(LOG_INFO, "Sending NGM_SOCK_CMD_NOLINGER to socket"); 311 if (NgSendMsg(cs, ".:", NGM_SOCKET_COOKIE, 312 NGM_SOCK_CMD_NOLINGER, NULL, 0) < 0) { 313 syslog(LOG_ERR, "Cannot send NGM_SOCK_CMD_NOLINGER: %m"); 314 _exit(EX_OSERR); 315 } 316 317 /* Put the PPPoE node into OFFER mode */ 318 slen = strlen(acname); 319 data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen); 320 snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook); 321 memcpy(data->data, acname, slen); 322 data->data_len = slen; 323 324 path = (char *)alloca(strlen(ngc.ourhook) + 3); 325 strcpy(path, ".:"); 326 strcpy(path + 2, ngc.ourhook); 327 328 syslog(LOG_INFO, "Offering to %s as access concentrator %s", 329 path, acname); 330 if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER, 331 data, sizeof *data + slen) == -1) { 332 syslog(LOG_INFO, "%s: Cannot OFFER on netgraph node: %m", path); 333 _exit(EX_OSERR); 334 } 335 /* If we have a provider code, set it */ 336 if (provider) { 337 slen = strlen(provider); 338 data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen); 339 snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook); 340 memcpy(data->data, provider, slen); 341 data->data_len = slen; 342 343 syslog(LOG_INFO, "adding to %s as offered service %s", 344 path, acname); 345 if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_SERVICE, 346 data, sizeof *data + slen) == -1) { 347 syslog(LOG_INFO, "%s: Cannot add service on netgraph node: %m", path); 348 _exit(EX_OSERR); 349 } 350 } 351 352 /* Put the peer's MAC address in the environment */ 353 if (sz >= sizeof(struct ether_header)) { 354 macaddr = ((struct ether_header *)request)->ether_shost; 355 snprintf(env, sizeof(env), "%x:%x:%x:%x:%x:%x", 356 macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], 357 macaddr[5]); 358 if (setenv(HISMACADDR, env, 1) != 0) 359 syslog(LOG_INFO, "setenv: cannot set %s: %m", HISMACADDR); 360 } 361 362 /* And send our request data to the waiting node */ 363 if (debug) 364 syslog(LOG_INFO, "Sending original request to %s (%d bytes)", path, sz); 365 if (NgSendData(ds, ngc.ourhook, request, sz) == -1) { 366 syslog(LOG_ERR, "Cannot send original request to %s: %m", path); 367 _exit(EX_OSERR); 368 } 369 370 /* Then wait for a success indication */ 371 372 if (debug) 373 syslog(LOG_INFO, "Waiting for a SUCCESS reply %s", path); 374 375 do { 376 if ((ret = NgRecvMsg(cs, rep, sizeof msgbuf, NULL)) < 0) { 377 syslog(LOG_ERR, "%s: Cannot receive a message: %m", path); 378 _exit(EX_OSERR); 379 } 380 381 if (ret == 0) { 382 /* The socket has been closed */ 383 syslog(LOG_INFO, "%s: Client timed out", path); 384 _exit(EX_TEMPFAIL); 385 } 386 387 if (rep->header.version != NG_VERSION) { 388 syslog(LOG_ERR, "%ld: Unexpected netgraph version, expected %ld", 389 (long)rep->header.version, (long)NG_VERSION); 390 _exit(EX_PROTOCOL); 391 } 392 393 if (rep->header.typecookie != NGM_PPPOE_COOKIE) { 394 syslog(LOG_INFO, "%ld: Unexpected netgraph cookie, expected %ld", 395 (long)rep->header.typecookie, (long)NGM_PPPOE_COOKIE); 396 continue; 397 } 398 399 switch (rep->header.cmd) { 400 case NGM_PPPOE_SET_FLAG: msg = "SET_FLAG"; break; 401 case NGM_PPPOE_CONNECT: msg = "CONNECT"; break; 402 case NGM_PPPOE_LISTEN: msg = "LISTEN"; break; 403 case NGM_PPPOE_OFFER: msg = "OFFER"; break; 404 case NGM_PPPOE_SUCCESS: msg = "SUCCESS"; break; 405 case NGM_PPPOE_FAIL: msg = "FAIL"; break; 406 case NGM_PPPOE_CLOSE: msg = "CLOSE"; break; 407 case NGM_PPPOE_GET_STATUS: msg = "GET_STATUS"; break; 408 case NGM_PPPOE_ACNAME: 409 msg = "ACNAME"; 410 if (setenv("ACNAME", sts->hook, 1) != 0) 411 syslog(LOG_WARNING, "setenv: cannot set ACNAME=%s: %m", 412 sts->hook); 413 break; 414 case NGM_PPPOE_SESSIONID: 415 msg = "SESSIONID"; 416 snprintf(sessionid, sizeof sessionid, "%04x", *(u_int16_t *)sts); 417 if (setenv("SESSIONID", sessionid, 1) != 0) 418 syslog(LOG_WARNING, "setenv: cannot set SESSIONID=%s: %m", 419 sessionid); 420 break; 421 default: 422 snprintf(unknown, sizeof unknown, "<%d>", (int)rep->header.cmd); 423 msg = unknown; 424 break; 425 } 426 427 switch (rep->header.cmd) { 428 case NGM_PPPOE_FAIL: 429 case NGM_PPPOE_CLOSE: 430 syslog(LOG_ERR, "Received NGM_PPPOE_%s (hook \"%s\")", 431 msg, sts->hook); 432 _exit(0); 433 } 434 435 syslog(LOG_INFO, "Received NGM_PPPOE_%s (hook \"%s\")", msg, sts->hook); 436 } while (rep->header.cmd != NGM_PPPOE_SUCCESS); 437 438 dup2(ds, STDIN_FILENO); 439 dup2(ds, STDOUT_FILENO); 440 close(ds); 441 close(cs); 442 443 setsid(); 444 syslog(LOG_INFO, "Executing: %s", exec); 445 execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", exec, (char *)NULL); 446 syslog(LOG_ERR, "execlp failed: %m"); 447 _exit(EX_OSFILE); 448 449 default: 450 wait(&ret); 451 errno = ret; 452 if (errno) 453 syslog(LOG_ERR, "Second fork failed: %m"); 454 break; 455 } 456 } 457 458 #ifndef NOKLDLOAD 459 static int 460 LoadModules(void) 461 { 462 const char *module[] = { "netgraph", "ng_socket", "ng_ether", "ng_pppoe" }; 463 int f; 464 465 for (f = 0; f < sizeof module / sizeof *module; f++) 466 if (modfind(module[f]) == -1 && kldload(module[f]) == -1) { 467 fprintf(stderr, "kldload: %s: %s\n", module[f], strerror(errno)); 468 return 0; 469 } 470 471 return 1; 472 } 473 #endif 474 475 static void 476 nglog(const char *fmt, ...) 477 { 478 char nfmt[256]; 479 va_list ap; 480 481 snprintf(nfmt, sizeof nfmt, "%s: %s", fmt, strerror(errno)); 482 va_start(ap, fmt); 483 vsyslog(LOG_INFO, nfmt, ap); 484 va_end(ap); 485 } 486 487 static void 488 nglogx(const char *fmt, ...) 489 { 490 va_list ap; 491 492 va_start(ap, fmt); 493 vsyslog(LOG_INFO, fmt, ap); 494 va_end(ap); 495 } 496 497 int 498 main(int argc, char *argv[]) 499 { 500 char hostname[MAXHOSTNAMELEN], *exec, rhook[NG_HOOKSIZ]; 501 unsigned char response[1024]; 502 const char *label, *prog, *provider, *acname; 503 struct ngm_connect ngc; 504 struct sigaction act; 505 int ch, cs, ds, ret, optF, optd, optn, sz, f; 506 const char *pidfile; 507 508 prog = strrchr(argv[0], '/'); 509 prog = prog ? prog + 1 : argv[0]; 510 pidfile = NULL; 511 exec = NULL; 512 label = NULL; 513 acname = NULL; 514 provider = ""; 515 optF = optd = optn = 0; 516 517 while ((ch = getopt(argc, argv, "FP:a:de:l:n:p:")) != -1) { 518 switch (ch) { 519 case 'F': 520 optF = 1; 521 break; 522 523 case 'P': 524 pidfile = optarg; 525 break; 526 527 case 'a': 528 acname = optarg; 529 break; 530 531 case 'd': 532 optd = 1; 533 break; 534 535 case 'e': 536 exec = optarg; 537 break; 538 539 case 'l': 540 label = optarg; 541 break; 542 543 case 'n': 544 optn = 1; 545 NgSetDebug(atoi(optarg)); 546 break; 547 548 case 'p': 549 provider = optarg; 550 break; 551 552 default: 553 return usage(prog); 554 } 555 } 556 557 if (optind >= argc || optind + 2 < argc) 558 return usage(prog); 559 560 if (exec != NULL && label != NULL) 561 return usage(prog); 562 563 if (exec == NULL) { 564 if (label == NULL) 565 label = provider; 566 if (label == NULL) { 567 fprintf(stderr, "%s: Either a provider, a label or an exec command" 568 " must be given\n", prog); 569 return usage(prog); 570 } 571 exec = (char *)alloca(sizeof DEFAULT_EXEC_PREFIX + strlen(label)); 572 if (exec == NULL) { 573 fprintf(stderr, "%s: Cannot allocate %zu bytes\n", prog, 574 sizeof DEFAULT_EXEC_PREFIX + strlen(label)); 575 return EX_OSERR; 576 } 577 strcpy(exec, DEFAULT_EXEC_PREFIX); 578 strcpy(exec + sizeof DEFAULT_EXEC_PREFIX - 1, label); 579 } 580 581 if (acname == NULL) { 582 char *dot; 583 584 if (gethostname(hostname, sizeof hostname)) 585 strcpy(hostname, "localhost"); 586 else if ((dot = strchr(hostname, '.'))) 587 *dot = '\0'; 588 589 acname = hostname; 590 } 591 592 #ifndef NOKLDLOAD 593 if (!LoadModules()) 594 return EX_UNAVAILABLE; 595 #endif 596 597 /* Create a socket node */ 598 if (NgMkSockNode(NULL, &cs, &ds) == -1) { 599 perror("Cannot create netgraph socket node"); 600 return EX_CANTCREAT; 601 } 602 603 /* Connect it up (and fill in `ngc') */ 604 if ((ret = ConfigureNode(prog, argv[optind], provider, cs, ds, 605 optd, &ngc)) != 0) { 606 close(cs); 607 close(ds); 608 return ret; 609 } 610 611 if (!optF && daemon(1, 0) == -1) { 612 perror("daemon()"); 613 close(cs); 614 close(ds); 615 return EX_OSERR; 616 } 617 618 619 if (pidfile != NULL) { 620 FILE *fp; 621 622 if ((fp = fopen(pidfile, "w")) == NULL) { 623 perror(pidfile); 624 close(cs); 625 close(ds); 626 return EX_CANTCREAT; 627 } else { 628 fprintf(fp, "%d\n", (int)getpid()); 629 fclose(fp); 630 } 631 } 632 633 openlog(prog, LOG_PID | (optF ? LOG_PERROR : 0), LOG_DAEMON); 634 if (!optF && optn) 635 NgSetErrLog(nglog, nglogx); 636 637 memset(&act, '\0', sizeof act); 638 act.sa_handler = Farewell; 639 act.sa_flags = 0; 640 sigemptyset(&act.sa_mask); 641 sigaction(SIGHUP, &act, NULL); 642 sigaction(SIGINT, &act, NULL); 643 sigaction(SIGQUIT, &act, NULL); 644 sigaction(SIGTERM, &act, NULL); 645 646 while (!ReceivedSignal) { 647 if (*provider) 648 syslog(LOG_INFO, "Listening as provider %s", provider); 649 else 650 syslog(LOG_INFO, "Listening"); 651 652 switch (sz = NgRecvData(ds, response, sizeof response, rhook)) { 653 case -1: 654 syslog(LOG_INFO, "NgRecvData: %m"); 655 break; 656 case 0: 657 syslog(LOG_INFO, "NgRecvData: socket closed"); 658 break; 659 default: 660 if (optd) { 661 char *dbuf, *ptr; 662 663 ptr = dbuf = alloca(sz * 2 + 1); 664 for (f = 0; f < sz; f++, ptr += 2) 665 sprintf(ptr, "%02x", (u_char)response[f]); 666 *ptr = '\0'; 667 syslog(LOG_INFO, "Got %d bytes of data: %s", sz, dbuf); 668 } 669 } 670 if (sz <= 0) { 671 ret = EX_UNAVAILABLE; 672 break; 673 } 674 Spawn(prog, acname, provider, exec, ngc, cs, ds, response, sz, optd); 675 } 676 677 if (pidfile) 678 remove(pidfile); 679 680 if (ReceivedSignal) { 681 syslog(LOG_INFO, "Received signal %d, exiting", ReceivedSignal); 682 683 signal(ReceivedSignal, SIG_DFL); 684 raise(ReceivedSignal); 685 686 /* NOTREACHED */ 687 688 ret = -ReceivedSignal; 689 } 690 691 return ret; 692 } 693