diff options
Diffstat (limited to 'ax25')
-rw-r--r-- | ax25/ax25d.c | 915 |
1 files changed, 454 insertions, 461 deletions
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,388 +249,6 @@ static void reload_timer(int sec) /*--------------------------------------------------------------------------*/ -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; - } - - 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(); @@ -795,6 +406,94 @@ static void SetupOptions(int new, struct axlist *axl) /**************************** 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; @@ -1284,103 +983,397 @@ Error: return -1; } -static unsigned long ParseFlags(const char *kp, int line) +static char *stripssid(const char *call) { - unsigned long flags = 0UL; + static char newcall[10]; + char *s; - for (; *kp != '\0'; kp++) { - switch (*kp) { - case 'v': - case 'V': - flags |= FLAG_VALIDCALL; - break; + strcpy(newcall, call); - case 'q': - case 'Q': - flags |= FLAG_NOLOGGING; - break; + if ((s = strchr(newcall, '-')) != NULL) + *s = '\0'; - case 'n': - case 'N': - flags |= FLAG_CHKNRN; - break; + return newcall; +} - case 'd': - case 'D': - flags |= FLAG_NODIGIS; +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': - case 'L': - flags |= FLAG_LOCKOUT; + Logging = TRUE; break; - case '0': - case '*': - case '-': /* Be compatible and allow markers */ - break; + case 'v': + printf("ax25d: %s\n", FULL_VER); + return 1; default: - fprintf(stderr, "ax25d: config file line %d bad flag option '%c'.\n", line, *kp); - break; + fprintf(stderr, "Usage: ax25d [-v] [-c altfile] [-l]\n"); + return 1; } } - return flags; -} + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "ax25d: no AX.25 port data configured\n"); + return 1; + } -static struct axlist *ClearList(struct axlist *list) -{ - struct axlist *tp1, *tp2, *tmp; + nr_config_load_ports(); - 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); + rs_config_load_ports(); - tmp = tp2->ents; - free(tp2); - tp2 = tmp; + 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 (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); + if (select(maxfd + 1, &fdread, NULL, NULL, NULL) <= 0) + continue; - close(tp1->fd); + 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; - tmp = tp1->next; - free(tp1); - tp1 = tmp; - } + /* + * 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); - return NULL; -} + addrlen = sizeof(struct full_sockaddr_ax25); + new = accept(paxl->fd, (struct sockaddr *)&sockaddr, &addrlen); -static char *stripssid(const char *call) -{ - static char newcall[10]; - char *s; + i = FALSE; + ioctl(paxl->fd, FIONBIO, &i); - strcpy(newcall, call); + if (new < 0) { + if (errno == EWOULDBLOCK) + continue; /* It's gone ??? */ - if ((s = strchr(newcall, '-')) != NULL) - *s = '\0'; + 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; + } - return newcall; + 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; + } + + 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; } |