From f55a99c6cdf5a9d64ca5a2179649f94435d1260e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 30 Jan 2017 12:26:07 +0100 Subject: ax25d: Reorder code to avoid the need for forward declarations. And then delete those now useless declarations. Signed-off-by: Ralf Baechle --- ax25/ax25d.c | 1145 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 569 insertions(+), 576 deletions(-) (limited to 'ax25') diff --git a/ax25/ax25d.c b/ax25/ax25d.c index a172c27..30aa0af 100644 --- a/ax25/ax25d.c +++ b/ax25/ax25d.c @@ -191,14 +191,7 @@ static char myAX25Name[10]; /* Room for 'GB9ZZZ-15\0' */ static char *Port; static int Logging = FALSE; -static void SignalHUP(int); -static void SignalTERM(int); -static void WorkoutArgs(int, char *, int *, char **); -static void SetupOptions(int, struct axlist *); static int ReadConfig(void); -static unsigned long ParseFlags(const char *, int); -static struct axlist *ClearList(struct axlist *); -static char *stripssid(const char *); static fd_set fdread; static int maxfd = -1; @@ -256,490 +249,108 @@ static void reload_timer(int sec) /*--------------------------------------------------------------------------*/ -int main(int argc, char *argv[]) +static void SignalHUP(int code) { - struct axlist *axltmp, *paxl, *raxl; - union { - struct full_sockaddr_ax25 ax25; - struct sockaddr_rose rose; - } sockaddr; - struct sigaction act, oact; - socklen_t addrlen; - int cnt; - char buf[1024]; - char *p; - char *mesg; - - while ((cnt = getopt(argc, argv, "c:lv")) != EOF) { - switch (cnt) { - case 'c': - ConfigFile = optarg; - break; - - case 'l': - Logging = TRUE; - break; - - case 'v': - printf("ax25d: %s\n", FULL_VER); - return 1; - - default: - fprintf(stderr, "Usage: ax25d [-v] [-c altfile] [-l]\n"); - return 1; - } - } - - if (ax25_config_load_ports() == 0) { - fprintf(stderr, "ax25d: no AX.25 port data configured\n"); - return 1; - } - - nr_config_load_ports(); - - rs_config_load_ports(); - - if (!daemon_start(TRUE)) { - fprintf(stderr, "ax25d: cannot become a daemon\n"); - return 1; - } + ReadConfig(); +} +static void SignalTERM(int code) +{ if (Logging) { - openlog("ax25d", LOG_PID, LOG_DAEMON); - syslog(LOG_INFO, "starting"); + syslog(LOG_INFO, "terminating on SIGTERM\n"); + closelog(); } - act.sa_handler = SignalHUP; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - sigaction(SIGHUP, &act, &oact); + exit(0); +} - act.sa_handler = SignalTERM; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - sigaction(SIGTERM, &act, &oact); +static void WorkoutArgs(int af_type, char *shell, int *argc, char **argv) +{ + char buffer[1024]; /* Maximum arg size */ + char *sp, *cp; + int cnt = 0; + int args = 0; - ReadConfig(); + for (cp = shell; *cp != '\0'; cp++) { + if (isspace(*cp) && cnt != 0) { + buffer[cnt] = '\0'; + argv[args++] = strdup(buffer); + cnt = 0; - for (;;) { + if (args == MAX_ARGS - 1) { + argv[args] = NULL; + *argc = args; + return; + } - update_maxfd(); - if (maxfd < 0) { - sleep(10); continue; - } - - if (select(maxfd + 1, &fdread, NULL, NULL, NULL) <= 0) + } else if (isspace(*cp)) /* && !cnt */ continue; - for (paxl = AXL; paxl != NULL; paxl = paxl->next) { - if (paxl->fd > 0 && FD_ISSET(paxl->fd, &fdread)) { - pid_t pid; - gid_t grps[2]; - char *argv[MAX_ARGS]; - int argc; - int new; - int i; + if (*cp == '%') { + cp++; - /* - * Setting up a non-blocking accept() so is does not hang up - * - I am not sure at this time why I didn't/don't assign - * the socket non-blocking to start with. - */ - /* - * We really need to setup the netrom window option here so - * that it's negotiated correctly on accepting the connection. - */ - /* - * It would be very useful if recvmsg/sendmsg were supported - * then we can move the call checking up here. - */ - i = TRUE; - ioctl(paxl->fd, FIONBIO, &i); + switch (*cp) { + case 'd': /* portname */ + for (sp = Port; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = *sp; + break; - addrlen = sizeof(struct full_sockaddr_ax25); - new = accept(paxl->fd, (struct sockaddr *)&sockaddr, &addrlen); + case 'U': /* username in UPPER */ + for (sp = User; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = toupper(*sp); + break; - i = FALSE; - ioctl(paxl->fd, FIONBIO, &i); + case 'u': /* USERNAME IN lower */ + for (sp = User; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = tolower(*sp); + break; - if (new < 0) { - if (errno == EWOULDBLOCK) - continue; /* It's gone ??? */ + case 'S': /* username in UPPER (with SSID) */ + for (sp = User; *sp != '\0'; sp++) + buffer[cnt++] = toupper(*sp); + break; - if (Logging) - syslog(LOG_ERR, "accept error %m, closing socket on port %s", paxl->port); - close(paxl->fd); - paxl->fd = -1; - reload_timer(10); - continue; - } + case 's': /* USERNAME IN lower (with SSID) */ + for (sp = User; *sp != '\0'; sp++) + buffer[cnt++] = tolower(*sp); + break; - switch (paxl->af_type) { - case AF_AX25: - strcpy(User, ax25_ntoa(&sockaddr.ax25.fsa_ax25.sax25_call)); - strcpy(Node, ""); - break; - case AF_NETROM: - strcpy(User, ax25_ntoa(&sockaddr.ax25.fsa_ax25.sax25_call)); - strcpy(Node, ax25_ntoa(&sockaddr.ax25.fsa_digipeater[0])); - break; - case AF_ROSE: - strcpy(User, ax25_ntoa(&sockaddr.rose.srose_call)); - strcpy(Node, rose_ntoa(&sockaddr.rose.srose_addr)); - break; + case 'P': /* nodename in UPPER */ + if (af_type == AF_NETROM) { + for (sp = Node; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = toupper(*sp); + } else { + buffer[cnt++] = '%'; } + break; - for (raxl = paxl->ents; raxl != NULL; raxl = raxl->ents) { - if (paxl->af_type == AF_NETROM && raxl->node != NULL && Node[0] != '\0') { - if (strchr(raxl->node, '-') == NULL) { - if (strcasecmp(raxl->node, stripssid(Node)) != 0) - continue; /* Found no match (for any SSID) */ - } else { - if (strcasecmp(raxl->node, Node) != 0) - continue; /* Found no match */ - } - } - - if (raxl->call == NULL) /* default */ - break; - - if (strchr(raxl->call, '-') == NULL) { - if (strcasecmp(raxl->call, stripssid(User)) == 0) - break; /* Found a match (for any SSID) */ - } else { - if (strcasecmp(raxl->call, User) == 0) - break; /* Found a match */ - } + case 'p': /* NODENAME IN lower */ + if (af_type == AF_NETROM) { + for (sp = Node; *sp != '\0' && *sp != '-'; sp++) + buffer[cnt++] = tolower(*sp); + } else { + buffer[cnt++] = '%'; } + break; - addrlen = sizeof(struct full_sockaddr_ax25); - getsockname(new, (struct sockaddr *)&sockaddr, &addrlen); - - switch (paxl->af_type) { - case AF_AX25: - Port = ax25_config_get_port(&sockaddr.ax25.fsa_digipeater[0]); - break; - case AF_NETROM: - Port = nr_config_get_port(&sockaddr.ax25.fsa_ax25.sax25_call); - break; - case AF_ROSE: - Port = rs_config_get_port(&sockaddr.rose.srose_addr); - break; - default: - Port = "???"; - break; + case 'R': /* nodename in UPPER (with SSID) */ + if (af_type == AF_NETROM) { + for (sp = Node; *sp != '\0'; sp++) + buffer[cnt++] = toupper(*sp); + } else { + buffer[cnt++] = '%'; } + break; - if (raxl == NULL) { - /* No default */ - if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { - switch (paxl->af_type) { - case AF_AX25: - syslog(LOG_INFO, "AX.25 %s (%s) rejected - no default", User, Port); - break; - case AF_NETROM: - syslog(LOG_INFO, "NET/ROM %s@%s (%s) rejected - no default", User, Node, Port); - break; - case AF_ROSE: - syslog(LOG_INFO, "Rose %s@%s (%s) rejected - no default", User, Node, Port); - break; - } - } - close(new); - continue; + case 'r': /* NODENAME IN lower (with SSID) */ + if (af_type == AF_NETROM) { + for (sp = Node; *sp != '\0'; sp++) + buffer[cnt++] = tolower(*sp); + } else { + buffer[cnt++] = '%'; } - - if (raxl->flags & FLAG_LOCKOUT) { - /* Not allowed to connect */ - if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { - switch (raxl->af_type) { - case AF_AX25: - syslog(LOG_INFO, "AX.25 %s (%s) rejected - port locked", User, Port); - break; - case AF_NETROM: - syslog(LOG_INFO, "NET/ROM %s@%s (%s) rejected - port locked", User, Node, Port); - break; - case AF_ROSE: - syslog(LOG_INFO, "Rose %s@%s (%s) rejected - port locked", User, Node, Port); - break; - } - } - close(new); - continue; - } - - if (raxl->af_type == AF_AX25 && (raxl->flags & FLAG_NODIGIS) && sockaddr.ax25.fsa_ax25.sax25_ndigis != 0) { - /* Not allowed to uplink via digi's */ - if (Logging && !(paxl->flags & FLAG_NOLOGGING)) - syslog(LOG_INFO, "AX.25 %s (%s) rejected - digipeaters", User, Port); - close(new); - continue; - } - - pid = fork(); - - switch (pid) { - case -1: - if (Logging) - syslog(LOG_ERR, "fork error %m"); - /* - * I don't think AX25 at the moment will hold the - * connection open, if the above does not make it - * through first time. - */ - close(new); - break; /* Oh well... */ - - case 0: - - if (raxl->af_type == AF_AX25 && raxl->checkVC) { - /* to which of my own addresses has the user connected? */ - getsockname(new, (struct sockaddr *)&sockaddr, &addrlen); - strcpy(myAX25Name, ax25_ntoa(&sockaddr.ax25.fsa_ax25.sax25_call)); - - sprintf(buf, "/usr/sbin/ax25rtctl -l ip | grep -i ' %s ' | /bin/grep 'v ' >/dev/null", User); - - /* he's not a VC user? */ - if (system(buf) != 0) - goto login; - - if (raxl->checkVC > 1) { - /* setproctitle("ax25d [%d]: rejecting, User); */ - } else { - /* setproctitle("ax25d [%d]: %s, User, (VCloginEnable ? "waiting" : "discarding")); */ - } - - /* is a VC user. checkVC > 0? then reject now, or fork and wait for pid=textdata.. */ - if (raxl->VCsendFailureMsg) { - sprintf(buf, "*** %s: NO MODE VC with %s\r", myAX25Name, myAX25Name); - write(new, buf, strlen(buf)); - if (raxl->checkVC > 1) - sleep(1); - } - - if (raxl->checkVC > 1) { - if (Logging && (!(paxl->flags & FLAG_NOLOGGING) || raxl->LoggingVC)) - syslog((raxl->LoggingVC ? LOG_NOTICE : LOG_INFO), "AX.25 %s (%s:%s) rejected - AX25.IP-VC entry found", User, Port, myAX25Name); - goto close_link; - } - - /* checkVC == 1: wait for data */ - if (Logging && (!(paxl->flags & FLAG_NOLOGGING) || raxl->LoggingVC)) { - syslog((raxl->LoggingVC ? LOG_NOTICE : LOG_INFO), "AX.25 %s (%s:%s) AX25.IP-VC host connected. %s", - User, Port, myAX25Name, - (raxl->VCloginEnable ? "waiting for first PID=text packet for triggered login" : "discarding PID=text packets")); - } - - *buf = 0; - mesg = 0; - while ((i = read(new, buf, (sizeof(buf)-1))) > 0) { - buf[i] = 0; - if (Logging && raxl->LoggingVC > 1) { - /* debug */ - syslog((LOG_DEBUG), "DEBUG: AX.25 %s (%s:%s) AX25.IP-VC host said: >%s<", User, Port, myAX25Name, buf); - } - /* skip leading mess */ - for (p = buf; *p && (isspace(*p & 0xff) || *p == '\r'); p++) ; - if (raxl->VCdiscOnLinkfailureMsg && !strncmp(p, "***", 3)) { - /* format received line for debug purposes */ - /* 1. skip "***" */ - for (p += 3; *p && isspace(*p & 0xff); p++ ) ; - mesg = p; - /* 2. get rid off EOL delimiters */ - while (*p) { - if (*p == '\r' || *p == '\n') { - *p = 0; - break; - } - p++; - } - /* end read loop */ - break; - } - /* per default, we discard all messages, - * because there's no useful combination - * using VC and pidText togegther - */ - if (raxl->VCloginEnable) - goto login; - } - - if (Logging && (!(paxl->flags & FLAG_NOLOGGING) || raxl->LoggingVC)) { - syslog((raxl->LoggingVC ? LOG_NOTICE : LOG_INFO), - "AX.25 %s (%s:%s) AX25.IP-VC host disconnected%s%s", - User, - Port, - myAX25Name, - (mesg ? ": " : "."), - (mesg ? mesg : "")); - } - /* point of no return */ -close_link: - /* close link */ - /* setproctitle("ax25d [%s]: disconnecting", User); */ - close(new); - exit(0); - } -login: - /* setproctitle("ax25d [%s]: login", User); */ - - SetupOptions(new, raxl); - WorkoutArgs(raxl->af_type, raxl->shell, &argc, argv); - - if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { - switch (paxl->af_type) { - case AF_AX25: - syslog(LOG_INFO, "AX.25 %s (%s) %s", User, Port, argv[0]); - break; - case AF_NETROM: - syslog(LOG_INFO, "NET/ROM %s@%s (%s) %s", User, Node, Port, argv[0]); - break; - case AF_ROSE: - syslog(LOG_INFO, "Rose %s@%s (%s) %s", User, Node, Port, argv[0]); - break; - } - } - - dup2(new, STDIN_FILENO); - dup2(new, STDOUT_FILENO); - close(new); - - /* - * Might be more efficient if we just went down AXL, - * we cleaned up our parents left overs on bootup. - */ - for (axltmp = AXL; axltmp != NULL; axltmp = axltmp->next) - close(axltmp->fd); - - if (Logging) - closelog(); - - /* Make root secure, before we exec() */ - /* Strip any supplementary gid's */ - if (setgroups(0, grps) == -1) - exit(1); - if (setgid(raxl->gid) == -1) - exit(1); - if (setuid(raxl->uid) == -1) - exit(1); - execve(raxl->exec, argv, NULL); - exit(1); - - default: - close(new); - break; - } - } - } - } - - /* NOT REACHED */ - return 0; -} - -static void SignalHUP(int code) -{ - ReadConfig(); -} - -static void SignalTERM(int code) -{ - if (Logging) { - syslog(LOG_INFO, "terminating on SIGTERM\n"); - closelog(); - } - - exit(0); -} - -static void WorkoutArgs(int af_type, char *shell, int *argc, char **argv) -{ - char buffer[1024]; /* Maximum arg size */ - char *sp, *cp; - int cnt = 0; - int args = 0; - - for (cp = shell; *cp != '\0'; cp++) { - if (isspace(*cp) && cnt != 0) { - buffer[cnt] = '\0'; - argv[args++] = strdup(buffer); - cnt = 0; - - if (args == MAX_ARGS - 1) { - argv[args] = NULL; - *argc = args; - return; - } - - continue; - } else if (isspace(*cp)) /* && !cnt */ - continue; - - if (*cp == '%') { - cp++; - - switch (*cp) { - case 'd': /* portname */ - for (sp = Port; *sp != '\0' && *sp != '-'; sp++) - buffer[cnt++] = *sp; - break; - - case 'U': /* username in UPPER */ - for (sp = User; *sp != '\0' && *sp != '-'; sp++) - buffer[cnt++] = toupper(*sp); - break; - - case 'u': /* USERNAME IN lower */ - for (sp = User; *sp != '\0' && *sp != '-'; sp++) - buffer[cnt++] = tolower(*sp); - break; - - case 'S': /* username in UPPER (with SSID) */ - for (sp = User; *sp != '\0'; sp++) - buffer[cnt++] = toupper(*sp); - break; - - case 's': /* USERNAME IN lower (with SSID) */ - for (sp = User; *sp != '\0'; sp++) - buffer[cnt++] = tolower(*sp); - break; - - case 'P': /* nodename in UPPER */ - if (af_type == AF_NETROM) { - for (sp = Node; *sp != '\0' && *sp != '-'; sp++) - buffer[cnt++] = toupper(*sp); - } else { - buffer[cnt++] = '%'; - } - break; - - case 'p': /* NODENAME IN lower */ - if (af_type == AF_NETROM) { - for (sp = Node; *sp != '\0' && *sp != '-'; sp++) - buffer[cnt++] = tolower(*sp); - } else { - buffer[cnt++] = '%'; - } - break; - - case 'R': /* nodename in UPPER (with SSID) */ - if (af_type == AF_NETROM) { - for (sp = Node; *sp != '\0'; sp++) - buffer[cnt++] = toupper(*sp); - } else { - buffer[cnt++] = '%'; - } - break; - - case 'r': /* NODENAME IN lower (with SSID) */ - if (af_type == AF_NETROM) { - for (sp = Node; *sp != '\0'; sp++) - buffer[cnt++] = tolower(*sp); - } else { - buffer[cnt++] = '%'; - } - break; + break; case '\0': case '%': @@ -793,8 +404,96 @@ static void SetupOptions(int new, struct axlist *axl) } } -/**************************** CONFIGURATION STUFF ***************************/ - +/**************************** CONFIGURATION STUFF ***************************/ + +static unsigned long ParseFlags(const char *kp, int line) +{ + unsigned long flags = 0UL; + + for (; *kp != '\0'; kp++) { + switch (*kp) { + case 'v': + case 'V': + flags |= FLAG_VALIDCALL; + break; + + case 'q': + case 'Q': + flags |= FLAG_NOLOGGING; + break; + + case 'n': + case 'N': + flags |= FLAG_CHKNRN; + break; + + case 'd': + case 'D': + flags |= FLAG_NODIGIS; + break; + + case 'l': + case 'L': + flags |= FLAG_LOCKOUT; + break; + + case '0': + case '*': + case '-': /* Be compatible and allow markers */ + break; + + default: + fprintf(stderr, "ax25d: config file line %d bad flag option '%c'.\n", line, *kp); + break; + } + } + + return flags; +} + +static struct axlist *ClearList(struct axlist *list) +{ + struct axlist *tp1, *tp2, *tmp; + + for (tp1 = list; tp1 != NULL; ) { + for (tp2 = tp1->ents; tp2 != NULL; ) { + if (tp2->port != NULL) + free(tp2->port); + if (tp2->call != NULL) + free(tp2->call); + if (tp2->node != NULL) + free(tp2->node); + if (tp2->exec != NULL) + free(tp2->exec); + if (tp2->shell != NULL) + free(tp2->shell); + + tmp = tp2->ents; + free(tp2); + tp2 = tmp; + } + + if (tp1->port != NULL) + free(tp1->port); + if (tp1->call != NULL) + free(tp1->call); + if (tp1->node != NULL) + free(tp1->node); + if (tp1->exec != NULL) + free(tp1->exec); + if (tp1->shell != NULL) + free(tp1->shell); + + close(tp1->fd); + + tmp = tp1->next; + free(tp1); + tp1 = tmp; + } + + return NULL; +} + static int ReadConfig(void) { struct axlist axl_defaults; @@ -1253,134 +952,428 @@ BadUID: free(axl_ent); continue; -BadArgsFree2: - if (axl_ent->exec != NULL) - free(axl_ent->exec); -BadArgsFree: - if (axl_ent->call != NULL) - free(axl_ent->call); - free(axl_ent); +BadArgsFree2: + if (axl_ent->exec != NULL) + free(axl_ent->exec); +BadArgsFree: + if (axl_ent->call != NULL) + free(axl_ent->call); + free(axl_ent); + + /* BadArgs: */ + fprintf(stderr, "ax25d: bad config entry on line %d, not enough fields.\n", line); + continue; + } + + fclose(fp); + + AXL = ClearList(AXL); + AXL = axl_build; /* Assign our built list to AXL */ + + if (Logging) + syslog(LOG_INFO, "new config file loaded successfuly"); + + update_maxfd(); + return 0; + +Error: + axl_build = ClearList(axl_build); + err_config(); + + return -1; +} + +static char *stripssid(const char *call) +{ + static char newcall[10]; + char *s; + + strcpy(newcall, call); + + if ((s = strchr(newcall, '-')) != NULL) + *s = '\0'; + + return newcall; +} + +int main(int argc, char *argv[]) +{ + struct axlist *axltmp, *paxl, *raxl; + union { + struct full_sockaddr_ax25 ax25; + struct sockaddr_rose rose; + } sockaddr; + struct sigaction act, oact; + socklen_t addrlen; + int cnt; + char buf[1024]; + char *p; + char *mesg; + + while ((cnt = getopt(argc, argv, "c:lv")) != EOF) { + switch (cnt) { + case 'c': + ConfigFile = optarg; + break; + + case 'l': + Logging = TRUE; + break; + + case 'v': + printf("ax25d: %s\n", FULL_VER); + return 1; + + default: + fprintf(stderr, "Usage: ax25d [-v] [-c altfile] [-l]\n"); + return 1; + } + } + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "ax25d: no AX.25 port data configured\n"); + return 1; + } + + nr_config_load_ports(); + + rs_config_load_ports(); + + if (!daemon_start(TRUE)) { + fprintf(stderr, "ax25d: cannot become a daemon\n"); + return 1; + } + + if (Logging) { + openlog("ax25d", LOG_PID, LOG_DAEMON); + syslog(LOG_INFO, "starting"); + } + + act.sa_handler = SignalHUP; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGHUP, &act, &oact); + + act.sa_handler = SignalTERM; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGTERM, &act, &oact); + + ReadConfig(); + + for (;;) { + + update_maxfd(); + if (maxfd < 0) { + sleep(10); + continue; + } + + if (select(maxfd + 1, &fdread, NULL, NULL, NULL) <= 0) + continue; + + for (paxl = AXL; paxl != NULL; paxl = paxl->next) { + if (paxl->fd > 0 && FD_ISSET(paxl->fd, &fdread)) { + pid_t pid; + gid_t grps[2]; + char *argv[MAX_ARGS]; + int argc; + int new; + int i; + + /* + * Setting up a non-blocking accept() so is does not hang up + * - I am not sure at this time why I didn't/don't assign + * the socket non-blocking to start with. + */ + /* + * We really need to setup the netrom window option here so + * that it's negotiated correctly on accepting the connection. + */ + /* + * It would be very useful if recvmsg/sendmsg were supported + * then we can move the call checking up here. + */ + i = TRUE; + ioctl(paxl->fd, FIONBIO, &i); + + addrlen = sizeof(struct full_sockaddr_ax25); + new = accept(paxl->fd, (struct sockaddr *)&sockaddr, &addrlen); + + i = FALSE; + ioctl(paxl->fd, FIONBIO, &i); + + if (new < 0) { + if (errno == EWOULDBLOCK) + continue; /* It's gone ??? */ + + if (Logging) + syslog(LOG_ERR, "accept error %m, closing socket on port %s", paxl->port); + close(paxl->fd); + paxl->fd = -1; + reload_timer(10); + continue; + } + + switch (paxl->af_type) { + case AF_AX25: + strcpy(User, ax25_ntoa(&sockaddr.ax25.fsa_ax25.sax25_call)); + strcpy(Node, ""); + break; + case AF_NETROM: + strcpy(User, ax25_ntoa(&sockaddr.ax25.fsa_ax25.sax25_call)); + strcpy(Node, ax25_ntoa(&sockaddr.ax25.fsa_digipeater[0])); + break; + case AF_ROSE: + strcpy(User, ax25_ntoa(&sockaddr.rose.srose_call)); + strcpy(Node, rose_ntoa(&sockaddr.rose.srose_addr)); + break; + } + + for (raxl = paxl->ents; raxl != NULL; raxl = raxl->ents) { + if (paxl->af_type == AF_NETROM && raxl->node != NULL && Node[0] != '\0') { + if (strchr(raxl->node, '-') == NULL) { + if (strcasecmp(raxl->node, stripssid(Node)) != 0) + continue; /* Found no match (for any SSID) */ + } else { + if (strcasecmp(raxl->node, Node) != 0) + continue; /* Found no match */ + } + } + + if (raxl->call == NULL) /* default */ + break; + + if (strchr(raxl->call, '-') == NULL) { + if (strcasecmp(raxl->call, stripssid(User)) == 0) + break; /* Found a match (for any SSID) */ + } else { + if (strcasecmp(raxl->call, User) == 0) + break; /* Found a match */ + } + } + + addrlen = sizeof(struct full_sockaddr_ax25); + getsockname(new, (struct sockaddr *)&sockaddr, &addrlen); + + switch (paxl->af_type) { + case AF_AX25: + Port = ax25_config_get_port(&sockaddr.ax25.fsa_digipeater[0]); + break; + case AF_NETROM: + Port = nr_config_get_port(&sockaddr.ax25.fsa_ax25.sax25_call); + break; + case AF_ROSE: + Port = rs_config_get_port(&sockaddr.rose.srose_addr); + break; + default: + Port = "???"; + break; + } + + if (raxl == NULL) { + /* No default */ + if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { + switch (paxl->af_type) { + case AF_AX25: + syslog(LOG_INFO, "AX.25 %s (%s) rejected - no default", User, Port); + break; + case AF_NETROM: + syslog(LOG_INFO, "NET/ROM %s@%s (%s) rejected - no default", User, Node, Port); + break; + case AF_ROSE: + syslog(LOG_INFO, "Rose %s@%s (%s) rejected - no default", User, Node, Port); + break; + } + } + close(new); + continue; + } + + if (raxl->flags & FLAG_LOCKOUT) { + /* Not allowed to connect */ + if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { + switch (raxl->af_type) { + case AF_AX25: + syslog(LOG_INFO, "AX.25 %s (%s) rejected - port locked", User, Port); + break; + case AF_NETROM: + syslog(LOG_INFO, "NET/ROM %s@%s (%s) rejected - port locked", User, Node, Port); + break; + case AF_ROSE: + syslog(LOG_INFO, "Rose %s@%s (%s) rejected - port locked", User, Node, Port); + break; + } + } + close(new); + continue; + } + + if (raxl->af_type == AF_AX25 && (raxl->flags & FLAG_NODIGIS) && sockaddr.ax25.fsa_ax25.sax25_ndigis != 0) { + /* Not allowed to uplink via digi's */ + if (Logging && !(paxl->flags & FLAG_NOLOGGING)) + syslog(LOG_INFO, "AX.25 %s (%s) rejected - digipeaters", User, Port); + close(new); + continue; + } - /* BadArgs: */ - fprintf(stderr, "ax25d: bad config entry on line %d, not enough fields.\n", line); - continue; - } + pid = fork(); - fclose(fp); + switch (pid) { + case -1: + if (Logging) + syslog(LOG_ERR, "fork error %m"); + /* + * I don't think AX25 at the moment will hold the + * connection open, if the above does not make it + * through first time. + */ + close(new); + break; /* Oh well... */ - AXL = ClearList(AXL); - AXL = axl_build; /* Assign our built list to AXL */ + case 0: - if (Logging) - syslog(LOG_INFO, "new config file loaded successfuly"); + if (raxl->af_type == AF_AX25 && raxl->checkVC) { + /* to which of my own addresses has the user connected? */ + getsockname(new, (struct sockaddr *)&sockaddr, &addrlen); + strcpy(myAX25Name, ax25_ntoa(&sockaddr.ax25.fsa_ax25.sax25_call)); - update_maxfd(); - return 0; + sprintf(buf, "/usr/sbin/ax25rtctl -l ip | grep -i ' %s ' | /bin/grep 'v ' >/dev/null", User); -Error: - axl_build = ClearList(axl_build); - err_config(); + /* he's not a VC user? */ + if (system(buf) != 0) + goto login; - return -1; -} + if (raxl->checkVC > 1) { + /* setproctitle("ax25d [%d]: rejecting, User); */ + } else { + /* setproctitle("ax25d [%d]: %s, User, (VCloginEnable ? "waiting" : "discarding")); */ + } -static unsigned long ParseFlags(const char *kp, int line) -{ - unsigned long flags = 0UL; + /* is a VC user. checkVC > 0? then reject now, or fork and wait for pid=textdata.. */ + if (raxl->VCsendFailureMsg) { + sprintf(buf, "*** %s: NO MODE VC with %s\r", myAX25Name, myAX25Name); + write(new, buf, strlen(buf)); + if (raxl->checkVC > 1) + sleep(1); + } - for (; *kp != '\0'; kp++) { - switch (*kp) { - case 'v': - case 'V': - flags |= FLAG_VALIDCALL; - break; + if (raxl->checkVC > 1) { + if (Logging && (!(paxl->flags & FLAG_NOLOGGING) || raxl->LoggingVC)) + syslog((raxl->LoggingVC ? LOG_NOTICE : LOG_INFO), "AX.25 %s (%s:%s) rejected - AX25.IP-VC entry found", User, Port, myAX25Name); + goto close_link; + } - case 'q': - case 'Q': - flags |= FLAG_NOLOGGING; - break; + /* checkVC == 1: wait for data */ + if (Logging && (!(paxl->flags & FLAG_NOLOGGING) || raxl->LoggingVC)) { + syslog((raxl->LoggingVC ? LOG_NOTICE : LOG_INFO), "AX.25 %s (%s:%s) AX25.IP-VC host connected. %s", + User, Port, myAX25Name, + (raxl->VCloginEnable ? "waiting for first PID=text packet for triggered login" : "discarding PID=text packets")); + } - case 'n': - case 'N': - flags |= FLAG_CHKNRN; - break; + *buf = 0; + mesg = 0; + while ((i = read(new, buf, (sizeof(buf)-1))) > 0) { + buf[i] = 0; + if (Logging && raxl->LoggingVC > 1) { + /* debug */ + syslog((LOG_DEBUG), "DEBUG: AX.25 %s (%s:%s) AX25.IP-VC host said: >%s<", User, Port, myAX25Name, buf); + } + /* skip leading mess */ + for (p = buf; *p && (isspace(*p & 0xff) || *p == '\r'); p++) ; + if (raxl->VCdiscOnLinkfailureMsg && !strncmp(p, "***", 3)) { + /* format received line for debug purposes */ + /* 1. skip "***" */ + for (p += 3; *p && isspace(*p & 0xff); p++ ) ; + mesg = p; + /* 2. get rid off EOL delimiters */ + while (*p) { + if (*p == '\r' || *p == '\n') { + *p = 0; + break; + } + p++; + } + /* end read loop */ + break; + } + /* per default, we discard all messages, + * because there's no useful combination + * using VC and pidText togegther + */ + if (raxl->VCloginEnable) + goto login; + } - case 'd': - case 'D': - flags |= FLAG_NODIGIS; - break; + if (Logging && (!(paxl->flags & FLAG_NOLOGGING) || raxl->LoggingVC)) { + syslog((raxl->LoggingVC ? LOG_NOTICE : LOG_INFO), + "AX.25 %s (%s:%s) AX25.IP-VC host disconnected%s%s", + User, + Port, + myAX25Name, + (mesg ? ": " : "."), + (mesg ? mesg : "")); + } + /* point of no return */ +close_link: + /* close link */ + /* setproctitle("ax25d [%s]: disconnecting", User); */ + close(new); + exit(0); + } +login: + /* setproctitle("ax25d [%s]: login", User); */ - case 'l': - case 'L': - flags |= FLAG_LOCKOUT; - break; + SetupOptions(new, raxl); + WorkoutArgs(raxl->af_type, raxl->shell, &argc, argv); - case '0': - case '*': - case '-': /* Be compatible and allow markers */ - break; + if (Logging && !(paxl->flags & FLAG_NOLOGGING)) { + switch (paxl->af_type) { + case AF_AX25: + syslog(LOG_INFO, "AX.25 %s (%s) %s", User, Port, argv[0]); + break; + case AF_NETROM: + syslog(LOG_INFO, "NET/ROM %s@%s (%s) %s", User, Node, Port, argv[0]); + break; + case AF_ROSE: + syslog(LOG_INFO, "Rose %s@%s (%s) %s", User, Node, Port, argv[0]); + break; + } + } - default: - fprintf(stderr, "ax25d: config file line %d bad flag option '%c'.\n", line, *kp); - break; - } - } + dup2(new, STDIN_FILENO); + dup2(new, STDOUT_FILENO); + close(new); - return flags; -} + /* + * Might be more efficient if we just went down AXL, + * we cleaned up our parents left overs on bootup. + */ + for (axltmp = AXL; axltmp != NULL; axltmp = axltmp->next) + close(axltmp->fd); -static struct axlist *ClearList(struct axlist *list) -{ - struct axlist *tp1, *tp2, *tmp; + if (Logging) + closelog(); - for (tp1 = list; tp1 != NULL; ) { - for (tp2 = tp1->ents; tp2 != NULL; ) { - if (tp2->port != NULL) - free(tp2->port); - if (tp2->call != NULL) - free(tp2->call); - if (tp2->node != NULL) - free(tp2->node); - if (tp2->exec != NULL) - free(tp2->exec); - if (tp2->shell != NULL) - free(tp2->shell); + /* Make root secure, before we exec() */ + /* Strip any supplementary gid's */ + if (setgroups(0, grps) == -1) + exit(1); + if (setgid(raxl->gid) == -1) + exit(1); + if (setuid(raxl->uid) == -1) + exit(1); + execve(raxl->exec, argv, NULL); + exit(1); - tmp = tp2->ents; - free(tp2); - tp2 = tmp; + default: + close(new); + break; + } + } } - - if (tp1->port != NULL) - free(tp1->port); - if (tp1->call != NULL) - free(tp1->call); - if (tp1->node != NULL) - free(tp1->node); - if (tp1->exec != NULL) - free(tp1->exec); - if (tp1->shell != NULL) - free(tp1->shell); - - close(tp1->fd); - - tmp = tp1->next; - free(tp1); - tp1 = tmp; } - return NULL; -} - -static char *stripssid(const char *call) -{ - static char newcall[10]; - char *s; - - strcpy(newcall, call); - - if ((s = strchr(newcall, '-')) != NULL) - *s = '\0'; - - return newcall; + /* NOT REACHED */ + return 0; } -- cgit v1.2.3