From 02ba553858208373f98eac864158104c98ee8d0c Mon Sep 17 00:00:00 2001 From: brian Date: Sun, 21 Nov 1999 23:39:14 +0000 Subject: pppoed(8) - a server to accept PPPoE connections --- libexec/pppoed/Makefile | 9 + libexec/pppoed/pppoed.8 | 169 +++++++++++++++ libexec/pppoed/pppoed.c | 557 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 735 insertions(+) create mode 100644 libexec/pppoed/Makefile create mode 100644 libexec/pppoed/pppoed.8 create mode 100644 libexec/pppoed/pppoed.c diff --git a/libexec/pppoed/Makefile b/libexec/pppoed/Makefile new file mode 100644 index 0000000..438dee6 --- /dev/null +++ b/libexec/pppoed/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= pppoed +SRCS= pppoed.c +DPADD= ${LIBNETGRAPH} +LDADD= -lnetgraph +MAN8= pppoed.8 + +.include diff --git a/libexec/pppoed/pppoed.8 b/libexec/pppoed/pppoed.8 new file mode 100644 index 0000000..da8038b --- /dev/null +++ b/libexec/pppoed/pppoed.8 @@ -0,0 +1,169 @@ +.\"- +.\" Copyright (c) 1999 Brian Somers +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd November 8, 1999 +.Dt PPPOED 8 +.Os FreeBSD +.Sh NAME +.Nm pppoed +.Nd handle incoming PPP over Ethernet connections +.Sh SYNOPSIS +.Nm pppoed +.Op Fl Fd +.Op Fl a Ar name +.Op Fl e Ar exec +.Op Fl p Ar provider +.Ar interface +.Sh DESCRIPTION +The +.Nm +program listens to the given +.Ar interface +for PPP over Ethernet (PPPoE) service request packets, and actions them +by negotiating a session then envoking a +.Em PPP +program. The negotiation is implemented by the +.Dq pppoe +netgraph node. See +.Xr ng_pppoe 8 +for details. +.Pp +.Nm +will only offer services to clients requesting services from the given +.Ar provider , +which is taken as an empty name if not provided. +If a provider name of +.Dq \&* +is given, any PPPoE requests will be offered service. +.Pp +The supplied +.Ar name +will be given as the access concentrator name when establishing the +connection. If no +.Ar name +is given, the current base hostname is used. +.Pp +After receiving a request (PADI) from the PPPoE netgraph node, +.Nm +.Xr fork 2 Ns No s +a child process and returns to service further requests. The child process +offers service +.Pq using Ar name +and waits for a +.Dv SUCCESS +indication from the PPPoE node. On receipt of the SUCCESS indication, +.Nm +will execute +.Pp +.D1 Ic exec /usr/sbin/ppp -direct Ar provider +.Pp +as a shell sub-process. It is possible to specify another command using the +.Ar exec +argument. This is mandatory if +.Ar provider +is not given. The child process will have standard input and standard output +attached to the same +.Xr netgraph 4 +data socket +.Pq see Xr ng_socket 8 +when started. +.Pp +Upon invocation, +.Nm +will attach a +.Dq pppoe +netgraph node to the relevant +.Dq ether +node using +.Dq Ar interface Ns No \&: +as the node name, and then connect that +.Dq pppoe +node to a local +.Dq socket +node. If the +.Fl F +flag has not been given, +.Nm +will then go into the background and disassociate itself from the controlling +terminal. When the +.Fl F +flag is given, +.Nm +stays in the foreground. +.Pp +If the +.Fl d +flag is given, additional diagnostics are provided (see the +.Sx DIAGNOSTICS +section below). +.Sh DIAGNOSTICS +After creating the necessary +.Xr netgraph 4 +nodes as described above, +.Nm +uses +.Xr syslogd 8 +to report all incoming connections. If the +.Fl d +flag is given, +.Nm +will report on the child processes creation of a new netgraph socket, it's +service offer and the invocation of the +.Em PPP +program. +.Pp +It is sometimes useful to add the following to +.Pa /etc/syslog.conf : +.Pp +.Dl !pppoed +.Dl *.* /var/log/pppoed.log +.Pp +and the following to +.Pa /etc/newsyslog.conf : +.Pp +.Dl /var/log/pppoed.log 640 3 100 * Z +.Pp +.Sh SEE ALSO +.Xr netgraph 4 , +.Xr syslog.conf 5 , +.Xr ng_pppoe 8 , +.Xr ng_socket 8 , +.Xr ppp 8 , +.Xr syslogd 8 +.Sh BUGS +If another netgraph node is using the given interface, +.Nm +will fail to start. This is because +.Xr netgraph 4 +does not currently allow node chaining. This may change in the future. +.Sh HISTORY +The +.Nm +program was written by +.An Brian Somers Aq brian@Awfulhak.org +and first appeared in +.Fx 3.4 . diff --git a/libexec/pppoed/pppoed.c b/libexec/pppoed/pppoed.c new file mode 100644 index 0000000..31abf16 --- /dev/null +++ b/libexec/pppoed/pppoed.c @@ -0,0 +1,557 @@ +/*- + * Copyright (c) 1999 Brian Somers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef NOKLDLOAD +#include +#include +#endif +#include +#include +#include +#include +#include + + +#define DEFAULT_EXEC_PREFIX "exec /usr/sbin/ppp -direct " + +static int +usage(const char *prog) +{ + fprintf(stderr, "Usage: %s [-Fd] [-a name] [-e exec] [-p provider]" + " interface\n", prog); + return EX_USAGE; +} + +static void +Fairwell(int sig) +{ + char buf[] = "Received signal XX, exiting"; + + /* No stdio in a signal handler */ + buf[16] = '0' + ((sig / 10) % 10); + buf[17] = '0' + (sig % 10); + + syslog(LOG_INFO, buf); + + signal(sig, SIG_DFL); + raise(sig); +} + +static int +ConfigureNode(const char *prog, const char *iface, const char *provider, + int cs, int ds, int debug, struct ngm_connect *ngc) +{ + /* + * We're going to do this with the passed `ds' & `cs' descriptors: + * + * .---------. + * | ether | + * | | + * `---------' + * (orphan) ds cs + * | | | + * | | | + * (ethernet) | | + * .---------. .-----------. + * | pppoe | | socket | + * | |(pppoe-)<---->(pppoe-)| | + * `--------- `-----------' + * (exec-) + * ^ .-----------. .-------------. + * | | socket | | ppp -direct | + * `--->(exec-)| |--fd--| provider | + * `-----------' `-------------' + * + * where there are potentially many ppp processes running off of the + * same PPPoE node. + * The exec- hook isn't made 'till we Spawn(). + */ + + char *epath, *spath; + struct ngpppoe_init_data *data; + const struct hooklist *hlist; + const struct nodeinfo *ninfo; + const struct linkinfo *nlink; + struct ngm_mkpeer mkp; + struct ng_mesg *resp; + u_char rbuf[2048]; + int f, plen; + + /* + * Ask for a list of hooks attached to the "ether" node. This node should + * magically exist as a way of hooking stuff onto an ethernet device + */ + epath = (char *)alloca(strlen(iface) + 2); + sprintf(epath, "%s:", iface); + + if (debug) + fprintf(stderr, "Sending NGM_LISTHOOKS to %s\n", epath); + + if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { + if (errno == ENOENT) + fprintf(stderr, "%s Cannot send a netgraph message: Invalid interface\n", + epath); + else + fprintf(stderr, "%s Cannot send a netgraph message: %s\n", + epath, strerror(errno)); + return EX_UNAVAILABLE; + } + + /* Get our list back */ + resp = (struct ng_mesg *)rbuf; + if (NgRecvMsg(cs, resp, sizeof rbuf, NULL) < 0) { + perror("Cannot get netgraph response"); + return EX_UNAVAILABLE; + } + + hlist = (const struct hooklist *)resp->data; + ninfo = &hlist->nodeinfo; + + if (debug) + fprintf(stderr, "Got reply from id [%x]: Type %s with %d hooks\n", + ninfo->id, ninfo->type, ninfo->hooks); + + /* Make sure we've got the right type of node */ + if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, sizeof NG_ETHER_NODE_TYPE - 1)) { + fprintf(stderr, "%s Unexpected node type ``%s'' (wanted ``" + NG_ETHER_NODE_TYPE "'')\n", epath, ninfo->type); + return EX_DATAERR; + } + + /* look for a hook already attached. */ + for (f = 0; f < ninfo->hooks; f++) { + nlink = &hlist->link[f]; + + if (debug) + fprintf(stderr, " Got [%x]:%s -> [%x]:%s\n", ninfo->id, + nlink->ourhook, nlink->nodeinfo.id, nlink->peerhook); + + if (!strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) || + !strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT)) { + /* + * Something is using the data coming out of this `ether' node. + * If it's a PPPoE node, we use that node, otherwise we complain that + * someone else is using the node. + */ + if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) { + fprintf(stderr, "%s Node type %s is currently active\n", + epath, nlink->nodeinfo.type); + return EX_UNAVAILABLE; + } + break; + } + } + + if (f == ninfo->hooks) { + /* + * Create a new PPPoE node connected to the `ether' node using + * the magic `orphan' and `ethernet' hooks + */ + snprintf(mkp.type, sizeof mkp.type, "%s", NG_PPPOE_NODE_TYPE); + snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", NG_ETHER_HOOK_ORPHAN); + snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", NG_PPPOE_HOOK_ETHERNET); + + if (debug) + fprintf(stderr, "Send MKPEER: %s%s -> [type %s]:%s\n", epath, + mkp.ourhook, mkp.type, mkp.peerhook); + + if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, + NGM_MKPEER, &mkp, sizeof mkp) < 0) { + fprintf(stderr, "%s Cannot create a peer PPPoE node: %s\n", + epath, strerror(errno)); + return EX_OSERR; + } + } + + /* Connect the PPPoE node to our socket node. */ + snprintf(ngc->path, sizeof ngc->path, "%s%s", epath, NG_ETHER_HOOK_ORPHAN); + snprintf(ngc->ourhook, sizeof ngc->ourhook, "pppoe-%ld", (long)getpid()); + memcpy(ngc->peerhook, ngc->ourhook, sizeof ngc->peerhook); + + if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, + NGM_CONNECT, ngc, sizeof *ngc) < 0) { + perror("Cannot CONNECT PPPoE and socket nodes"); + return EX_OSERR; + } + + plen = strlen(provider); + + data = (struct ngpppoe_init_data *)alloca(sizeof *data + plen + 1); + snprintf(data->hook, sizeof data->hook, "%s", ngc->peerhook); + strcpy(data->data, provider); + data->data_len = plen; + + spath = (char *)alloca(strlen(ngc->peerhook) + 3); + strcpy(spath, ".:"); + strcpy(spath + 2, ngc->ourhook); + + if (debug) { + if (provider) + fprintf(stderr, "Sending PPPOE_LISTEN to %s, provider %s\n", + spath, provider); + else + fprintf(stderr, "Sending PPPOE_LISTEN to %s\n", spath); + } + + if (NgSendMsg(cs, spath, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN, + data, sizeof *data + plen) == -1) { + fprintf(stderr, "%s: Cannot LISTEN on netgraph node: %s\n", + spath, strerror(errno)); + return EX_OSERR; + } + + return 0; +} + +static void +Spawn(const char *prog, const char *acname, const char *exec, + struct ngm_connect ngc, int cs, int ds, void *request, int sz, + int debug) +{ + char msgbuf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)]; + struct ng_mesg *rep = (struct ng_mesg *)msgbuf; + struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep); + struct ngpppoe_init_data *data; + char unknown[14], *path; + const char *msg; + int ret, slen; + + switch ((ret = fork())) { + case -1: + syslog(LOG_ERR, "fork: %m"); + break; + + case 0: + switch (fork()) { + case 0: + break; + case -1: + _exit(errno); + default: + _exit(0); + } + close(cs); + close(ds); + + /* Create a new socket node */ + if (debug) + syslog(LOG_INFO, "Creating a new socket node"); + + if (NgMkSockNode(NULL, &cs, &ds) == -1) { + syslog(LOG_ERR, "Cannot create netgraph socket node: %m"); + _exit(EX_CANTCREAT); + } + + /* Connect the PPPoE node to our new socket node. */ + snprintf(ngc.ourhook, sizeof ngc.ourhook, "exec-%ld", (long)getpid()); + memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook); + + if (debug) + syslog(LOG_INFO, "Sending CONNECT from .:%s -> %s.%s", + ngc.ourhook, ngc.path, ngc.peerhook); + if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, + NGM_CONNECT, &ngc, sizeof ngc) < 0) { + syslog(LOG_ERR, "Cannot CONNECT PPPoE and socket nodes: %m"); + _exit(EX_OSERR); + } + + /* + * If we tell the socket node not to LINGER, it will go away when + * the last hook is removed. + */ + if (debug) + syslog(LOG_INFO, "Sending NGM_SOCK_CMD_NOLINGER to socket"); + if (NgSendMsg(cs, ".:", NGM_SOCKET_COOKIE, + NGM_SOCK_CMD_NOLINGER, NULL, 0) < 0) { + syslog(LOG_ERR, "Cannot send NGM_SOCK_CMD_NOLINGER: %m"); + _exit(EX_OSERR); + } + + /* Put the PPPoE node into OFFER mode */ + slen = strlen(acname); + data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen + 1); + snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook); + strcpy(data->data, acname); + data->data_len = slen; + + path = (char *)alloca(strlen(ngc.ourhook) + 3); + strcpy(path, ".:"); + strcpy(path + 2, ngc.ourhook); + + syslog(LOG_INFO, "Offering to %s as access concentrator %s", + path, acname); + if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER, + data, sizeof *data + slen) == -1) { + syslog(LOG_INFO, "%s: Cannot OFFER on netgraph node: %m", path); + _exit(EX_OSERR); + } + + /* And send our request data to the waiting node */ + if (debug) + syslog(LOG_INFO, "Sending original request to %s (%d bytes)", path, sz); + if (NgSendData(ds, ngc.ourhook, request, sz) == -1) { + syslog(LOG_ERR, "Cannot send original request to %s: %m", path); + _exit(EX_OSERR); + } + + /* Then wait for a success indication */ + + if (debug) + syslog(LOG_INFO, "Waiting for a SUCCESS reply %s", path); + + do { + if (NgRecvMsg(cs, rep, sizeof msgbuf, NULL) < 0) { + syslog(LOG_ERR, "%s: Cannot receive a message: %m", path); + _exit(EX_OSERR); + } + + if (rep->header.version != NG_VERSION) { + syslog(LOG_ERR, "%ld: Unexpected netgraph version, expected %ld", + (long)rep->header.version, (long)NG_VERSION); + _exit(EX_PROTOCOL); + } + + if (rep->header.typecookie != NGM_PPPOE_COOKIE) { + syslog(LOG_INFO, "%ld: Unexpected netgraph cookie, expected %ld", + (long)rep->header.typecookie, (long)NGM_PPPOE_COOKIE); + continue; + } + + switch (rep->header.cmd) { + case NGM_PPPOE_SET_FLAG: msg = "SET_FLAG"; break; + case NGM_PPPOE_CONNECT: msg = "CONNECT"; break; + case NGM_PPPOE_LISTEN: msg = "LISTEN"; break; + case NGM_PPPOE_OFFER: msg = "OFFER"; break; + case NGM_PPPOE_SUCCESS: msg = "SUCCESS"; break; + case NGM_PPPOE_FAIL: msg = "FAIL"; break; + case NGM_PPPOE_CLOSE: msg = "CLOSE"; break; + case NGM_PPPOE_GET_STATUS: msg = "GET_STATUS"; break; + default: + snprintf(unknown, sizeof unknown, "<%d>", (int)rep->header.cmd); + msg = unknown; + break; + } + + switch (rep->header.cmd) { + case NGM_PPPOE_FAIL: + case NGM_PPPOE_CLOSE: + syslog(LOG_ERR, "Received NGM_PPPOE_%s (hook \"%s\")", + msg, sts->hook); + _exit(0); + } + + syslog(LOG_INFO, "Received NGM_PPPOE_%s (hook \"%s\")", msg, sts->hook); + } while (rep->header.cmd != NGM_PPPOE_SUCCESS); + + dup2(ds, STDIN_FILENO); + dup2(ds, STDOUT_FILENO); + close(ds); + close(cs); + + setsid(); + syslog(LOG_INFO, "Executing: %s", exec); + execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", exec, NULL); + syslog(LOG_ERR, "execlp failed: %m"); + _exit(EX_OSFILE); + + default: + wait(&ret); + errno = ret; + if (errno) + syslog(LOG_ERR, "Second fork failed: %m"); + break; + } +} + +int +main(int argc, char **argv) +{ + char hostname[MAXHOSTNAMELEN]; + char response[1024], *exec, rhook[NG_HOOKLEN + 1]; + const char *prog, *provider, *acname; + struct ngm_connect ngc; + int ch, cs, ds, ret, optF, optd, sz, f; + + prog = strrchr(argv[0], '/'); + prog = prog ? prog + 1 : argv[0]; + exec = NULL; + acname = NULL; + provider = ""; + optF = optd = 0; + + while ((ch = getopt(argc, argv, "a:Fde:p:")) != -1) { + switch (ch) { + case 'F': + optF = 1; + break; + + case 'a': + acname = optarg; + break; + + case 'd': + optd = 1; + break; + + case 'e': + exec = optarg; + break; + + case 'p': + provider = optarg; + break; + + default: + return usage(prog); + } + } + + if (optind >= argc || optind + 2 < argc) + return usage(prog); + + if (exec == NULL) { + if (provider == NULL) { + fprintf(stderr, "%s: Either a provider or an exec command" + " must be given\n", prog); + return usage(prog); + } + exec = (char *)alloca(sizeof DEFAULT_EXEC_PREFIX + strlen(provider)); + if (exec == NULL) { + fprintf(stderr, "%s: Cannot allocate %d bytes\n", prog, + (int)(sizeof DEFAULT_EXEC_PREFIX) + strlen(provider)); + return EX_OSERR; + } + strcpy(exec, DEFAULT_EXEC_PREFIX); + strcpy(exec + sizeof DEFAULT_EXEC_PREFIX - 1, provider); + } + + if (acname == NULL) { + char *dot; + + if (gethostname(hostname, sizeof hostname)) + strcpy(hostname, "localhost"); + else if ((dot = strchr(hostname, '.'))) + *dot = '\0'; + + acname = hostname; + } + +#ifndef NOKLDLOAD + if (modfind("netgraph") == -1) { + fputs("Can't run without options NETGRAPH in the kernel\n", stderr); + return EX_UNAVAILABLE; + } + + if (modfind("ng_socket") == -1 && kldload("ng_socket") == -1) { + perror("kldload: ng_socket"); + return EX_UNAVAILABLE; + } +#endif + + /* Create a socket node */ + if (NgMkSockNode(NULL, &cs, &ds) == -1) { + perror("Cannot create netgraph socket node"); + return EX_CANTCREAT; + } + + /* Connect it up (and fill in `ngc') */ + if ((ret = ConfigureNode(prog, argv[optind], provider, cs, ds, + optd, &ngc)) != 0) { + close(cs); + close(ds); + return ret; + } + + if (!optF && daemon(1, 0) == -1) { + perror("daemon()"); + return EX_OSERR; + } + + openlog(prog, LOG_PID | (optF ? LOG_PERROR : 0), LOG_DAEMON); + + signal(SIGHUP, Fairwell); + signal(SIGINT, Fairwell); + signal(SIGQUIT, Fairwell); + signal(SIGTERM, Fairwell); + + while (1) { + if (*provider) + syslog(LOG_INFO, "Listening as provider %s", provider); + else + syslog(LOG_INFO, "Listening"); + + switch (sz = NgRecvData(ds, response, sizeof response, rhook)) { + case -1: + syslog(LOG_INFO, "NgRecvData: %m"); + break; + case 0: + syslog(LOG_INFO, "NgRecvData: socket closed"); + break; + default: + if (optd) { + char *dbuf, *ptr; + + ptr = dbuf = alloca(sz * 2 + 1); + for (f = 0; f < sz; f++, ptr += 2) + sprintf(ptr, "%02x", (u_char)response[f]); + *ptr = '\0'; + syslog(LOG_INFO, "Got %d bytes of data: %s", sz, dbuf); + } + } + if (sz <= 0) { + ret = EX_UNAVAILABLE; + break; + } + Spawn(prog, acname, exec, ngc, cs, ds, response, sz, optd); + } + + return ret; +} -- cgit v1.1