pppoed.c revision 90975
153537Sbrian/*- 280728Sbrian * Copyright (c) 1999-2001 Brian Somers <brian@Awfulhak.org> 353537Sbrian * All rights reserved. 453537Sbrian * 553537Sbrian * Redistribution and use in source and binary forms, with or without 653537Sbrian * modification, are permitted provided that the following conditions 753537Sbrian * are met: 853537Sbrian * 1. Redistributions of source code must retain the above copyright 953537Sbrian * notice, this list of conditions and the following disclaimer. 1053537Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1153537Sbrian * notice, this list of conditions and the following disclaimer in the 1253537Sbrian * documentation and/or other materials provided with the distribution. 1353537Sbrian * 1453537Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1553537Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1653537Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1753537Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1853537Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1953537Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2053537Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2153537Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2253537Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2353537Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2453537Sbrian * SUCH DAMAGE. 2553537Sbrian * 2653537Sbrian * $FreeBSD: head/libexec/pppoed/pppoed.c 90975 2002-02-20 15:52:20Z brian $ 2753537Sbrian */ 2853537Sbrian 2953537Sbrian#include <sys/param.h> 3053537Sbrian#include <sys/socket.h> 3153537Sbrian#include <sys/un.h> 3253537Sbrian#include <netinet/in.h> 3353537Sbrian#include <arpa/inet.h> 3453537Sbrian#include <netdb.h> 3553537Sbrian#include <netgraph.h> 3653537Sbrian#include <net/ethernet.h> 3753537Sbrian#include <netinet/in_systm.h> 3853537Sbrian#include <netinet/ip.h> 3953537Sbrian#include <netgraph/ng_ether.h> 4053537Sbrian#include <netgraph/ng_message.h> 4153537Sbrian#include <netgraph/ng_pppoe.h> 4253537Sbrian#include <netgraph/ng_socket.h> 4353537Sbrian 4453537Sbrian#include <errno.h> 4553537Sbrian#include <paths.h> 4653537Sbrian#include <signal.h> 4753537Sbrian#include <stdio.h> 4866602Sbrian#include <stdarg.h> 4953537Sbrian#include <stdlib.h> 5053537Sbrian#include <string.h> 5153537Sbrian#include <sysexits.h> 5253537Sbrian#include <sys/fcntl.h> 5353537Sbrian#ifndef NOKLDLOAD 5453537Sbrian#include <sys/linker.h> 5553537Sbrian#include <sys/module.h> 5653537Sbrian#endif 5753537Sbrian#include <sys/uio.h> 5853537Sbrian#include <sys/wait.h> 5953537Sbrian#include <syslog.h> 6053537Sbrian#include <termios.h> 6153537Sbrian#include <unistd.h> 6253537Sbrian 6353537Sbrian 6486705Sbrian#define DEFAULT_EXEC_PREFIX "exec /usr/sbin/ppp -direct " 6586705Sbrian#define HISMACADDR "HISMACADDR" 6653537Sbrian 6790160Skrisstatic void nglogx(const char *, ...) __printflike(1, 2); 6890160Skris 6969582Sbrianstatic int ReceivedSignal; 7069582Sbrian 7153537Sbrianstatic int 7253537Sbrianusage(const char *prog) 7353537Sbrian{ 7480728Sbrian fprintf(stderr, "Usage: %s [-Fd] [-P pidfile] [-a name] [-e exec | -l label]" 7553609Sbrian " [-p provider] interface\n", prog); 7653537Sbrian return EX_USAGE; 7753537Sbrian} 7853537Sbrian 7953537Sbrianstatic void 8069582SbrianFarewell(int sig) 8153537Sbrian{ 8269582Sbrian ReceivedSignal = sig; 8353537Sbrian} 8453537Sbrian 8553537Sbrianstatic int 8653537SbrianConfigureNode(const char *prog, const char *iface, const char *provider, 8753537Sbrian int cs, int ds, int debug, struct ngm_connect *ngc) 8853537Sbrian{ 8953537Sbrian /* 9053537Sbrian * We're going to do this with the passed `ds' & `cs' descriptors: 9153537Sbrian * 9253537Sbrian * .---------. 9353537Sbrian * | ether | 9453537Sbrian * | <iface> | 9553537Sbrian * `---------' 9653537Sbrian * (orphan) ds cs 9753537Sbrian * | | | 9853537Sbrian * | | | 9953537Sbrian * (ethernet) | | 10053537Sbrian * .---------. .-----------. 10153537Sbrian * | pppoe | | socket | 10253537Sbrian * | <iface> |(pppoe-<pid>)<---->(pppoe-<pid>)| <unnamed> | 10353537Sbrian * `--------- `-----------' 10453537Sbrian * (exec-<pid>) 10553537Sbrian * ^ .-----------. .-------------. 10653537Sbrian * | | socket | | ppp -direct | 10753537Sbrian * `--->(exec-<pid>)| <unnamed> |--fd--| provider | 10853537Sbrian * `-----------' `-------------' 10953537Sbrian * 11053537Sbrian * where there are potentially many ppp processes running off of the 11153537Sbrian * same PPPoE node. 11253537Sbrian * The exec-<pid> hook isn't made 'till we Spawn(). 11353537Sbrian */ 11453537Sbrian 11553537Sbrian char *epath, *spath; 11653537Sbrian struct ngpppoe_init_data *data; 11753537Sbrian const struct hooklist *hlist; 11853537Sbrian const struct nodeinfo *ninfo; 11953537Sbrian const struct linkinfo *nlink; 12053537Sbrian struct ngm_mkpeer mkp; 12153537Sbrian struct ng_mesg *resp; 12253537Sbrian u_char rbuf[2048]; 12353537Sbrian int f, plen; 12453537Sbrian 12553537Sbrian /* 12653537Sbrian * Ask for a list of hooks attached to the "ether" node. This node should 12753537Sbrian * magically exist as a way of hooking stuff onto an ethernet device 12853537Sbrian */ 12953537Sbrian epath = (char *)alloca(strlen(iface) + 2); 13053537Sbrian sprintf(epath, "%s:", iface); 13153537Sbrian 13253537Sbrian if (debug) 13353537Sbrian fprintf(stderr, "Sending NGM_LISTHOOKS to %s\n", epath); 13453537Sbrian 13553537Sbrian if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) { 13653537Sbrian if (errno == ENOENT) 13753537Sbrian fprintf(stderr, "%s Cannot send a netgraph message: Invalid interface\n", 13853537Sbrian epath); 13953537Sbrian else 14053537Sbrian fprintf(stderr, "%s Cannot send a netgraph message: %s\n", 14153537Sbrian epath, strerror(errno)); 14253537Sbrian return EX_UNAVAILABLE; 14353537Sbrian } 14453537Sbrian 14553537Sbrian /* Get our list back */ 14653537Sbrian resp = (struct ng_mesg *)rbuf; 14782276Sbrian if (NgRecvMsg(cs, resp, sizeof rbuf, NULL) <= 0) { 14853537Sbrian perror("Cannot get netgraph response"); 14953537Sbrian return EX_UNAVAILABLE; 15053537Sbrian } 15153537Sbrian 15253537Sbrian hlist = (const struct hooklist *)resp->data; 15353537Sbrian ninfo = &hlist->nodeinfo; 15453537Sbrian 15553537Sbrian if (debug) 15653537Sbrian fprintf(stderr, "Got reply from id [%x]: Type %s with %d hooks\n", 15753537Sbrian ninfo->id, ninfo->type, ninfo->hooks); 15853537Sbrian 15953537Sbrian /* Make sure we've got the right type of node */ 16053537Sbrian if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, sizeof NG_ETHER_NODE_TYPE - 1)) { 16153537Sbrian fprintf(stderr, "%s Unexpected node type ``%s'' (wanted ``" 16253537Sbrian NG_ETHER_NODE_TYPE "'')\n", epath, ninfo->type); 16353537Sbrian return EX_DATAERR; 16453537Sbrian } 16553537Sbrian 16653537Sbrian /* look for a hook already attached. */ 16753537Sbrian for (f = 0; f < ninfo->hooks; f++) { 16853537Sbrian nlink = &hlist->link[f]; 16953537Sbrian 17053537Sbrian if (debug) 17153537Sbrian fprintf(stderr, " Got [%x]:%s -> [%x]:%s\n", ninfo->id, 17253537Sbrian nlink->ourhook, nlink->nodeinfo.id, nlink->peerhook); 17353537Sbrian 17453537Sbrian if (!strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) || 17553537Sbrian !strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT)) { 17653537Sbrian /* 17753537Sbrian * Something is using the data coming out of this `ether' node. 17853537Sbrian * If it's a PPPoE node, we use that node, otherwise we complain that 17953537Sbrian * someone else is using the node. 18053537Sbrian */ 18153537Sbrian if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) { 18253537Sbrian fprintf(stderr, "%s Node type %s is currently active\n", 18353537Sbrian epath, nlink->nodeinfo.type); 18453537Sbrian return EX_UNAVAILABLE; 18553537Sbrian } 18653537Sbrian break; 18753537Sbrian } 18853537Sbrian } 18953537Sbrian 19053537Sbrian if (f == ninfo->hooks) { 19153537Sbrian /* 19253537Sbrian * Create a new PPPoE node connected to the `ether' node using 19353537Sbrian * the magic `orphan' and `ethernet' hooks 19453537Sbrian */ 19553537Sbrian snprintf(mkp.type, sizeof mkp.type, "%s", NG_PPPOE_NODE_TYPE); 19653537Sbrian snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", NG_ETHER_HOOK_ORPHAN); 19753537Sbrian snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", NG_PPPOE_HOOK_ETHERNET); 19853537Sbrian 19953537Sbrian if (debug) 20053537Sbrian fprintf(stderr, "Send MKPEER: %s%s -> [type %s]:%s\n", epath, 20153537Sbrian mkp.ourhook, mkp.type, mkp.peerhook); 20253537Sbrian 20353537Sbrian if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, 20453537Sbrian NGM_MKPEER, &mkp, sizeof mkp) < 0) { 20553537Sbrian fprintf(stderr, "%s Cannot create a peer PPPoE node: %s\n", 20653537Sbrian epath, strerror(errno)); 20753537Sbrian return EX_OSERR; 20853537Sbrian } 20953537Sbrian } 21053537Sbrian 21153537Sbrian /* Connect the PPPoE node to our socket node. */ 21253537Sbrian snprintf(ngc->path, sizeof ngc->path, "%s%s", epath, NG_ETHER_HOOK_ORPHAN); 21353537Sbrian snprintf(ngc->ourhook, sizeof ngc->ourhook, "pppoe-%ld", (long)getpid()); 21453537Sbrian memcpy(ngc->peerhook, ngc->ourhook, sizeof ngc->peerhook); 21553537Sbrian 21653537Sbrian if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, 21753537Sbrian NGM_CONNECT, ngc, sizeof *ngc) < 0) { 21853537Sbrian perror("Cannot CONNECT PPPoE and socket nodes"); 21953537Sbrian return EX_OSERR; 22053537Sbrian } 22153537Sbrian 22253537Sbrian plen = strlen(provider); 22353537Sbrian 22468032Sbrian data = (struct ngpppoe_init_data *)alloca(sizeof *data + plen); 22553537Sbrian snprintf(data->hook, sizeof data->hook, "%s", ngc->peerhook); 22668846Sbrian memcpy(data->data, provider, plen); 22768846Sbrian data->data_len = plen; 22853537Sbrian 22953537Sbrian spath = (char *)alloca(strlen(ngc->peerhook) + 3); 23053537Sbrian strcpy(spath, ".:"); 23153537Sbrian strcpy(spath + 2, ngc->ourhook); 23253537Sbrian 23353537Sbrian if (debug) { 23453537Sbrian if (provider) 23553537Sbrian fprintf(stderr, "Sending PPPOE_LISTEN to %s, provider %s\n", 23653537Sbrian spath, provider); 23753537Sbrian else 23853537Sbrian fprintf(stderr, "Sending PPPOE_LISTEN to %s\n", spath); 23953537Sbrian } 24053537Sbrian 24153537Sbrian if (NgSendMsg(cs, spath, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN, 24253537Sbrian data, sizeof *data + plen) == -1) { 24353537Sbrian fprintf(stderr, "%s: Cannot LISTEN on netgraph node: %s\n", 24453537Sbrian spath, strerror(errno)); 24553537Sbrian return EX_OSERR; 24653537Sbrian } 24753537Sbrian 24853537Sbrian return 0; 24953537Sbrian} 25053537Sbrian 25153537Sbrianstatic void 25269948SjulianSpawn(const char *prog, const char *acname, const char *provider, 25386705Sbrian const char *exec, struct ngm_connect ngc, int cs, int ds, void *request, 25486705Sbrian int sz, int debug) 25553537Sbrian{ 25653537Sbrian char msgbuf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)]; 25753537Sbrian struct ng_mesg *rep = (struct ng_mesg *)msgbuf; 25853537Sbrian struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep); 25953537Sbrian struct ngpppoe_init_data *data; 26086705Sbrian unsigned char *macaddr; 26186705Sbrian char env[sizeof(HISMACADDR)+18], unknown[14], *path; 26253537Sbrian const char *msg; 26353537Sbrian int ret, slen; 26453537Sbrian 26553537Sbrian switch ((ret = fork())) { 26653537Sbrian case -1: 26753537Sbrian syslog(LOG_ERR, "fork: %m"); 26853537Sbrian break; 26953537Sbrian 27053537Sbrian case 0: 27153537Sbrian switch (fork()) { 27253537Sbrian case 0: 27353537Sbrian break; 27453537Sbrian case -1: 27553537Sbrian _exit(errno); 27653537Sbrian default: 27753537Sbrian _exit(0); 27853537Sbrian } 27953537Sbrian close(cs); 28053537Sbrian close(ds); 28153537Sbrian 28253537Sbrian /* Create a new socket node */ 28353537Sbrian if (debug) 28453537Sbrian syslog(LOG_INFO, "Creating a new socket node"); 28553537Sbrian 28653537Sbrian if (NgMkSockNode(NULL, &cs, &ds) == -1) { 28753537Sbrian syslog(LOG_ERR, "Cannot create netgraph socket node: %m"); 28853537Sbrian _exit(EX_CANTCREAT); 28953537Sbrian } 29053537Sbrian 29153537Sbrian /* Connect the PPPoE node to our new socket node. */ 29253537Sbrian snprintf(ngc.ourhook, sizeof ngc.ourhook, "exec-%ld", (long)getpid()); 29353537Sbrian memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook); 29453537Sbrian 29553537Sbrian if (debug) 29653537Sbrian syslog(LOG_INFO, "Sending CONNECT from .:%s -> %s.%s", 29753537Sbrian ngc.ourhook, ngc.path, ngc.peerhook); 29853537Sbrian if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, 29953537Sbrian NGM_CONNECT, &ngc, sizeof ngc) < 0) { 30053537Sbrian syslog(LOG_ERR, "Cannot CONNECT PPPoE and socket nodes: %m"); 30153537Sbrian _exit(EX_OSERR); 30253537Sbrian } 30353537Sbrian 30453537Sbrian /* 30553537Sbrian * If we tell the socket node not to LINGER, it will go away when 30653537Sbrian * the last hook is removed. 30753537Sbrian */ 30853537Sbrian if (debug) 30953537Sbrian syslog(LOG_INFO, "Sending NGM_SOCK_CMD_NOLINGER to socket"); 31053537Sbrian if (NgSendMsg(cs, ".:", NGM_SOCKET_COOKIE, 31153537Sbrian NGM_SOCK_CMD_NOLINGER, NULL, 0) < 0) { 31253537Sbrian syslog(LOG_ERR, "Cannot send NGM_SOCK_CMD_NOLINGER: %m"); 31353537Sbrian _exit(EX_OSERR); 31453537Sbrian } 31553537Sbrian 31653537Sbrian /* Put the PPPoE node into OFFER mode */ 31753537Sbrian slen = strlen(acname); 31868032Sbrian data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen); 31953537Sbrian snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook); 32068846Sbrian memcpy(data->data, acname, slen); 32168846Sbrian data->data_len = slen; 32253537Sbrian 32353537Sbrian path = (char *)alloca(strlen(ngc.ourhook) + 3); 32453537Sbrian strcpy(path, ".:"); 32553537Sbrian strcpy(path + 2, ngc.ourhook); 32653537Sbrian 32753537Sbrian syslog(LOG_INFO, "Offering to %s as access concentrator %s", 32853537Sbrian path, acname); 32953537Sbrian if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER, 33053537Sbrian data, sizeof *data + slen) == -1) { 33153537Sbrian syslog(LOG_INFO, "%s: Cannot OFFER on netgraph node: %m", path); 33253537Sbrian _exit(EX_OSERR); 33353537Sbrian } 33469948Sjulian /* If we have a provider code, set it */ 33579597Sbrian if (provider) { 33669948Sjulian slen = strlen(provider); 33769948Sjulian data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen); 33869948Sjulian snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook); 33969948Sjulian memcpy(data->data, provider, slen); 34069948Sjulian data->data_len = slen; 34153537Sbrian 34269948Sjulian syslog(LOG_INFO, "adding to %s as offered service %s", 34369948Sjulian path, acname); 34469948Sjulian if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_SERVICE, 34569948Sjulian data, sizeof *data + slen) == -1) { 34669948Sjulian syslog(LOG_INFO, "%s: Cannot add service on netgraph node: %m", path); 34769948Sjulian _exit(EX_OSERR); 34869948Sjulian } 34969948Sjulian } 35069948Sjulian 35186705Sbrian /* Put the peer's MAC address in the environment */ 35286705Sbrian if (sz >= sizeof(struct ether_header)) { 35386705Sbrian 35486705Sbrian macaddr = ((struct ether_header *)request)->ether_shost; 35586762Sbrian snprintf(env, sizeof(env), "%s=%x:%x:%x:%x:%x:%x", HISMACADDR, 35686762Sbrian macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], 35786762Sbrian macaddr[5]); 35886705Sbrian if (putenv(env) != 0) 35986705Sbrian syslog(LOG_INFO, "putenv: cannot set %s: %m", env); 36086705Sbrian } 36186705Sbrian 36253537Sbrian /* And send our request data to the waiting node */ 36353537Sbrian if (debug) 36453537Sbrian syslog(LOG_INFO, "Sending original request to %s (%d bytes)", path, sz); 36553537Sbrian if (NgSendData(ds, ngc.ourhook, request, sz) == -1) { 36653537Sbrian syslog(LOG_ERR, "Cannot send original request to %s: %m", path); 36753537Sbrian _exit(EX_OSERR); 36853537Sbrian } 36953537Sbrian 37053537Sbrian /* Then wait for a success indication */ 37153537Sbrian 37253537Sbrian if (debug) 37353537Sbrian syslog(LOG_INFO, "Waiting for a SUCCESS reply %s", path); 37453537Sbrian 37553537Sbrian do { 37682333Sbrian if ((ret = NgRecvMsg(cs, rep, sizeof msgbuf, NULL)) < 0) { 37753537Sbrian syslog(LOG_ERR, "%s: Cannot receive a message: %m", path); 37853537Sbrian _exit(EX_OSERR); 37953537Sbrian } 38053537Sbrian 38182276Sbrian if (ret == 0) { 38282276Sbrian /* The socket has been closed */ 38382276Sbrian syslog(LOG_INFO, "%s: Client timed out", path); 38482276Sbrian _exit(EX_TEMPFAIL); 38582276Sbrian } 38682276Sbrian 38753537Sbrian if (rep->header.version != NG_VERSION) { 38853537Sbrian syslog(LOG_ERR, "%ld: Unexpected netgraph version, expected %ld", 38953537Sbrian (long)rep->header.version, (long)NG_VERSION); 39053537Sbrian _exit(EX_PROTOCOL); 39153537Sbrian } 39253537Sbrian 39353537Sbrian if (rep->header.typecookie != NGM_PPPOE_COOKIE) { 39453537Sbrian syslog(LOG_INFO, "%ld: Unexpected netgraph cookie, expected %ld", 39553537Sbrian (long)rep->header.typecookie, (long)NGM_PPPOE_COOKIE); 39653537Sbrian continue; 39753537Sbrian } 39853537Sbrian 39953537Sbrian switch (rep->header.cmd) { 40053537Sbrian case NGM_PPPOE_SET_FLAG: msg = "SET_FLAG"; break; 40153537Sbrian case NGM_PPPOE_CONNECT: msg = "CONNECT"; break; 40253537Sbrian case NGM_PPPOE_LISTEN: msg = "LISTEN"; break; 40353537Sbrian case NGM_PPPOE_OFFER: msg = "OFFER"; break; 40453537Sbrian case NGM_PPPOE_SUCCESS: msg = "SUCCESS"; break; 40553537Sbrian case NGM_PPPOE_FAIL: msg = "FAIL"; break; 40653537Sbrian case NGM_PPPOE_CLOSE: msg = "CLOSE"; break; 40753537Sbrian case NGM_PPPOE_GET_STATUS: msg = "GET_STATUS"; break; 40890975Sbrian case NGM_PPPOE_ACNAME: 40990975Sbrian msg = "ACNAME"; 41090975Sbrian if (setenv("ACNAME", sts->hook, 1) != 0) 41190975Sbrian syslog(LOG_WARNING, "setenv: cannot set ACNAME=%s: %m", 41290975Sbrian sts->hook); 41390975Sbrian break; 41453537Sbrian default: 41553537Sbrian snprintf(unknown, sizeof unknown, "<%d>", (int)rep->header.cmd); 41653537Sbrian msg = unknown; 41753537Sbrian break; 41853537Sbrian } 41953537Sbrian 42053537Sbrian switch (rep->header.cmd) { 42153537Sbrian case NGM_PPPOE_FAIL: 42253537Sbrian case NGM_PPPOE_CLOSE: 42353537Sbrian syslog(LOG_ERR, "Received NGM_PPPOE_%s (hook \"%s\")", 42453537Sbrian msg, sts->hook); 42553537Sbrian _exit(0); 42653537Sbrian } 42753537Sbrian 42853537Sbrian syslog(LOG_INFO, "Received NGM_PPPOE_%s (hook \"%s\")", msg, sts->hook); 42953537Sbrian } while (rep->header.cmd != NGM_PPPOE_SUCCESS); 43053537Sbrian 43153537Sbrian dup2(ds, STDIN_FILENO); 43253537Sbrian dup2(ds, STDOUT_FILENO); 43353537Sbrian close(ds); 43453537Sbrian close(cs); 43553537Sbrian 43653537Sbrian setsid(); 43753537Sbrian syslog(LOG_INFO, "Executing: %s", exec); 43879452Sbrian execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", exec, (char *)NULL); 43953537Sbrian syslog(LOG_ERR, "execlp failed: %m"); 44053537Sbrian _exit(EX_OSFILE); 44153537Sbrian 44253537Sbrian default: 44353537Sbrian wait(&ret); 44453537Sbrian errno = ret; 44553537Sbrian if (errno) 44653537Sbrian syslog(LOG_ERR, "Second fork failed: %m"); 44753537Sbrian break; 44853537Sbrian } 44953537Sbrian} 45053537Sbrian 45166602Sbrian#ifndef NOKLDLOAD 45269582Sbrianstatic int 45366602SbrianLoadModules(void) 45466602Sbrian{ 45566602Sbrian const char *module[] = { "netgraph", "ng_socket", "ng_ether", "ng_pppoe" }; 45666602Sbrian int f; 45766602Sbrian 45866602Sbrian for (f = 0; f < sizeof module / sizeof *module; f++) 45966602Sbrian if (modfind(module[f]) == -1 && kldload(module[f]) == -1) { 46066602Sbrian fprintf(stderr, "kldload: %s: %s\n", module[f], strerror(errno)); 46166602Sbrian return 0; 46266602Sbrian } 46366602Sbrian 46466602Sbrian return 1; 46566602Sbrian} 46666602Sbrian#endif 46766602Sbrian 46869582Sbrianstatic void 46966602Sbriannglog(const char *fmt, ...) 47066602Sbrian{ 47166602Sbrian char nfmt[256]; 47266602Sbrian va_list ap; 47366602Sbrian 47466602Sbrian snprintf(nfmt, sizeof nfmt, "%s: %s", fmt, strerror(errno)); 47566602Sbrian va_start(ap, fmt); 47666602Sbrian vsyslog(LOG_INFO, nfmt, ap); 47766602Sbrian va_end(ap); 47866602Sbrian} 47966602Sbrian 48069582Sbrianstatic void 48166602Sbriannglogx(const char *fmt, ...) 48266602Sbrian{ 48366602Sbrian va_list ap; 48466602Sbrian 48566602Sbrian va_start(ap, fmt); 48666602Sbrian vsyslog(LOG_INFO, fmt, ap); 48766602Sbrian va_end(ap); 48866602Sbrian} 48966602Sbrian 49066602Sbrianint 49190779Simpmain(int argc, char *argv[]) 49253537Sbrian{ 49366602Sbrian char hostname[MAXHOSTNAMELEN], *exec, rhook[NG_HOOKLEN + 1]; 49466602Sbrian unsigned char response[1024]; 49580728Sbrian const char *label, *prog, *provider, *acname; 49653537Sbrian struct ngm_connect ngc; 49780724Sbrian struct sigaction act; 49866602Sbrian int ch, cs, ds, ret, optF, optd, optn, sz, f; 49969582Sbrian const char *pidfile; 50053537Sbrian 50153537Sbrian prog = strrchr(argv[0], '/'); 50253537Sbrian prog = prog ? prog + 1 : argv[0]; 50353609Sbrian pidfile = NULL; 50453537Sbrian exec = NULL; 50580728Sbrian label = NULL; 50653537Sbrian acname = NULL; 50753537Sbrian provider = ""; 50866602Sbrian optF = optd = optn = 0; 50953537Sbrian 51080728Sbrian while ((ch = getopt(argc, argv, "FP:a:de:l:n:p:")) != -1) { 51153537Sbrian switch (ch) { 51253537Sbrian case 'F': 51353537Sbrian optF = 1; 51453537Sbrian break; 51553537Sbrian 51653609Sbrian case 'P': 51753609Sbrian pidfile = optarg; 51853609Sbrian break; 51953609Sbrian 52053537Sbrian case 'a': 52153537Sbrian acname = optarg; 52253537Sbrian break; 52353537Sbrian 52453537Sbrian case 'd': 52553537Sbrian optd = 1; 52653537Sbrian break; 52753537Sbrian 52853537Sbrian case 'e': 52953537Sbrian exec = optarg; 53053537Sbrian break; 53153537Sbrian 53280728Sbrian case 'l': 53380728Sbrian label = optarg; 53480728Sbrian break; 53580728Sbrian 53666602Sbrian case 'n': 53766602Sbrian optn = 1; 53866602Sbrian NgSetDebug(atoi(optarg)); 53966602Sbrian break; 54066602Sbrian 54153537Sbrian case 'p': 54253537Sbrian provider = optarg; 54353537Sbrian break; 54453537Sbrian 54553537Sbrian default: 54653537Sbrian return usage(prog); 54753537Sbrian } 54853537Sbrian } 54953537Sbrian 55053537Sbrian if (optind >= argc || optind + 2 < argc) 55153537Sbrian return usage(prog); 55253537Sbrian 55380728Sbrian if (exec != NULL && label != NULL) 55480728Sbrian return usage(prog); 55580728Sbrian 55653537Sbrian if (exec == NULL) { 55780728Sbrian if (label == NULL) 55880728Sbrian label = provider; 55980728Sbrian if (label == NULL) { 56080728Sbrian fprintf(stderr, "%s: Either a provider, a label or an exec command" 56153537Sbrian " must be given\n", prog); 56253537Sbrian return usage(prog); 56353537Sbrian } 56480728Sbrian exec = (char *)alloca(sizeof DEFAULT_EXEC_PREFIX + strlen(label)); 56553537Sbrian if (exec == NULL) { 56653537Sbrian fprintf(stderr, "%s: Cannot allocate %d bytes\n", prog, 56780728Sbrian (int)(sizeof DEFAULT_EXEC_PREFIX) + strlen(label)); 56853537Sbrian return EX_OSERR; 56953537Sbrian } 57053537Sbrian strcpy(exec, DEFAULT_EXEC_PREFIX); 57180728Sbrian strcpy(exec + sizeof DEFAULT_EXEC_PREFIX - 1, label); 57253537Sbrian } 57353537Sbrian 57453537Sbrian if (acname == NULL) { 57553537Sbrian char *dot; 57653537Sbrian 57753537Sbrian if (gethostname(hostname, sizeof hostname)) 57853537Sbrian strcpy(hostname, "localhost"); 57953537Sbrian else if ((dot = strchr(hostname, '.'))) 58053537Sbrian *dot = '\0'; 58153537Sbrian 58253537Sbrian acname = hostname; 58353537Sbrian } 58453537Sbrian 58553537Sbrian#ifndef NOKLDLOAD 58666602Sbrian if (!LoadModules()) 58753537Sbrian return EX_UNAVAILABLE; 58853537Sbrian#endif 58953537Sbrian 59053537Sbrian /* Create a socket node */ 59153537Sbrian if (NgMkSockNode(NULL, &cs, &ds) == -1) { 59253537Sbrian perror("Cannot create netgraph socket node"); 59353537Sbrian return EX_CANTCREAT; 59453537Sbrian } 59553537Sbrian 59653537Sbrian /* Connect it up (and fill in `ngc') */ 59753537Sbrian if ((ret = ConfigureNode(prog, argv[optind], provider, cs, ds, 59853537Sbrian optd, &ngc)) != 0) { 59953537Sbrian close(cs); 60053537Sbrian close(ds); 60153537Sbrian return ret; 60253537Sbrian } 60353537Sbrian 60453537Sbrian if (!optF && daemon(1, 0) == -1) { 60553537Sbrian perror("daemon()"); 60653609Sbrian close(cs); 60753609Sbrian close(ds); 60853537Sbrian return EX_OSERR; 60953537Sbrian } 61053537Sbrian 61153609Sbrian 61253609Sbrian if (pidfile != NULL) { 61353609Sbrian FILE *fp; 61453609Sbrian 61553609Sbrian if ((fp = fopen(pidfile, "w")) == NULL) { 61653609Sbrian perror(pidfile); 61753609Sbrian close(cs); 61853609Sbrian close(ds); 61953609Sbrian return EX_CANTCREAT; 62053609Sbrian } else { 62153609Sbrian fprintf(fp, "%d\n", (int)getpid()); 62253609Sbrian fclose(fp); 62353609Sbrian } 62453609Sbrian } 62553609Sbrian 62653537Sbrian openlog(prog, LOG_PID | (optF ? LOG_PERROR : 0), LOG_DAEMON); 62766602Sbrian if (!optF && optn) 62866602Sbrian NgSetErrLog(nglog, nglogx); 62953537Sbrian 63080724Sbrian memset(&act, '\0', sizeof act); 63180724Sbrian act.sa_handler = Farewell; 63280733Sbrian act.sa_flags = 0; 63380724Sbrian sigemptyset(&act.sa_mask); 63480724Sbrian sigaction(SIGHUP, &act, NULL); 63580724Sbrian sigaction(SIGINT, &act, NULL); 63680724Sbrian sigaction(SIGQUIT, &act, NULL); 63780724Sbrian sigaction(SIGTERM, &act, NULL); 63853537Sbrian 63969582Sbrian while (!ReceivedSignal) { 64053537Sbrian if (*provider) 64153537Sbrian syslog(LOG_INFO, "Listening as provider %s", provider); 64253537Sbrian else 64353537Sbrian syslog(LOG_INFO, "Listening"); 64453537Sbrian 64553537Sbrian switch (sz = NgRecvData(ds, response, sizeof response, rhook)) { 64653537Sbrian case -1: 64753537Sbrian syslog(LOG_INFO, "NgRecvData: %m"); 64853537Sbrian break; 64953537Sbrian case 0: 65053537Sbrian syslog(LOG_INFO, "NgRecvData: socket closed"); 65153537Sbrian break; 65253537Sbrian default: 65353537Sbrian if (optd) { 65453537Sbrian char *dbuf, *ptr; 65553537Sbrian 65653537Sbrian ptr = dbuf = alloca(sz * 2 + 1); 65753537Sbrian for (f = 0; f < sz; f++, ptr += 2) 65853537Sbrian sprintf(ptr, "%02x", (u_char)response[f]); 65953537Sbrian *ptr = '\0'; 66053537Sbrian syslog(LOG_INFO, "Got %d bytes of data: %s", sz, dbuf); 66153537Sbrian } 66253537Sbrian } 66353537Sbrian if (sz <= 0) { 66453537Sbrian ret = EX_UNAVAILABLE; 66553537Sbrian break; 66653537Sbrian } 66769948Sjulian Spawn(prog, acname, provider, exec, ngc, cs, ds, response, sz, optd); 66853537Sbrian } 66953537Sbrian 67069582Sbrian if (pidfile) 67169582Sbrian remove(pidfile); 67269582Sbrian 67369582Sbrian if (ReceivedSignal) { 67469582Sbrian syslog(LOG_INFO, "Received signal %d, exiting", ReceivedSignal); 67569582Sbrian 67669582Sbrian signal(ReceivedSignal, SIG_DFL); 67769582Sbrian raise(ReceivedSignal); 67869582Sbrian 67969582Sbrian /* NOTREACHED */ 68069582Sbrian 68169582Sbrian ret = -ReceivedSignal; 68269582Sbrian } 68369582Sbrian 68453537Sbrian return ret; 68553537Sbrian} 686