void freeconfig (struct servtab *cp) { free (cp->se_node); free (cp->se_service); free (cp->se_proto); free (cp->se_user); free (cp->se_server); argcv_free (cp->se_argc, cp->se_argv); }
int argcv_get_np (const char *command, int len, const char *delim, const char *cmnt, int flags, int *pargc, char ***pargv, char **endp) { int i = 0; struct argcv_info info; int argc; char **argv; if (!delim) delim = ""; if (!cmnt) cmnt = ""; init_argcv_info (&info, flags, len, command, delim, cmnt); /* Count number of arguments */ argc = 0; while (argcv_scan (&info) <= len) argc++; argv = calloc ((argc + 1), sizeof (char *)); if (argv == NULL) return ENOMEM; i = 0; info.save = 0; for (i = 0; i < argc; i++) { int n; int unquote; argcv_scan (&info); if ((command[info.start] == '"' || command[info.end] == '\'') && command[info.end] == command[info.start]) { if (info.start < info.end) { info.start++; info.end--; } unquote = 0; } else unquote = 1; n = info.end - info.start + 1; argv[i] = calloc (n + 1, sizeof (char)); if (argv[i] == NULL) { argcv_free (i, argv); return ENOMEM; } if (unquote) argcv_unquote_copy (argv[i], &command[info.start], n); else memcpy (argv[i], &command[info.start], n); argv[i][n] = 0; } argv[i] = NULL; *pargc = argc; *pargv = argv; if (endp) *endp = (char*) (command + info.finish_pos); return 0; }
struct servtab * getconfigent (FILE *fconfig, const char *file, size_t *line) { static struct servtab serv; struct servtab *sep = &serv; int argc = 0; size_t i; char **argv = NULL; char *node, *service; static char TCPMUX_TOKEN[] = "tcpmux/"; #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) if (serv_node) return next_node_sep (sep); memset ((caddr_t) sep, 0, sizeof *sep); while (1) { argcv_free (argc, argv); freeconfig (sep); memset ((caddr_t) sep, 0, sizeof *sep); do { ssize_t n = getline (&linebuf, &linebufsize, fconfig); if (n < 0) return 0; else if (n == 0) continue; if (linebuf[n-1] == '\n') linebuf[n-1] = 0; ++ *line; } while (*linebuf == '#' || *linebuf == 0); if (argcv_get (linebuf, "", &argc, &argv)) continue; if (argc < INETD_FIELDS_MIN) { if (argc == 1 && argv[0][strlen (argv[0]) - 1] == ':') { argv[0][strlen (argv[0]) - 1] = 0; free (global_serv_node); if (strcmp (argv[0], "*")) global_serv_node = newstr (argv[0]); } else syslog (LOG_ERR, "%s:%lu: not enough fields", file, (unsigned long) *line); continue; } sep->se_file = file; sep->se_line = *line; node = argv[INETD_SERVICE]; service = strchr (node, ':'); if (!service) { if (global_serv_node) { node = global_serv_node; serv_node = newstr (node); serv_node_offset = 0; } else node = NULL; service = argv[INETD_SERVICE]; } else { *service++ = 0; if (strcmp (node, "*") == 0) node = NULL; else { serv_node = newstr (node); serv_node_offset = 0; } } if (strncmp (service, TCPMUX_TOKEN, MUX_LEN) == 0) { char *c = service + MUX_LEN; if (*c == '+') { sep->se_type = MUXPLUS_TYPE; c++; } else sep->se_type = MUX_TYPE; sep->se_service = newstr (c); } else { sep->se_service = newstr (service); sep->se_type = NORM_TYPE; } if (strcmp (argv[INETD_SOCKET], "stream") == 0) sep->se_socktype = SOCK_STREAM; else if (strcmp (argv[INETD_SOCKET], "dgram") == 0) sep->se_socktype = SOCK_DGRAM; else if (strcmp (argv[INETD_SOCKET], "rdm") == 0) sep->se_socktype = SOCK_RDM; else if (strcmp (argv[INETD_SOCKET], "seqpacket") == 0) sep->se_socktype = SOCK_SEQPACKET; else if (strcmp (argv[INETD_SOCKET], "raw") == 0) sep->se_socktype = SOCK_RAW; else { syslog (LOG_WARNING, "%s:%lu: bad socket type", file, (unsigned long) *line); sep->se_socktype = -1; } sep->se_proto = newstr (argv[INETD_PROTOCOL]); #ifdef IPV6 /* We default to IPv6, in setup() we'll fall back to IPv4 if it doesn't work. */ sep->se_family = AF_INET6; sep->se_v4mapped = 1; if ((strncmp (sep->se_proto, "tcp", 3) == 0) || (strncmp (sep->se_proto, "udp", 3) == 0)) { if (sep->se_proto[3] == '6') { sep->se_family = AF_INET6; sep->se_v4mapped = 0; } else if (sep->se_proto[3] == '4') { sep->se_family = AF_INET; } } #else if ((strncmp (sep->se_proto, "tcp6", 4) == 0) || (strncmp (sep->se_proto, "udp6", 4) == 0)) { syslog (LOG_ERR, "%s:%lu: %s: IPv6 support isn't enabled", file, (unsigned long) *line, sep->se_proto); continue; } sep->se_family = AF_INET; #endif { char *p, *q; p = strchr(argv[INETD_WAIT], '.'); if (p) *p++ = 0; if (strcmp (argv[INETD_WAIT], "wait") == 0) sep->se_wait = 1; else if (strcmp (argv[INETD_WAIT], "nowait") == 0) sep->se_wait = 0; else { syslog (LOG_WARNING, "%s:%lu: bad wait type", file, (unsigned long) *line); } if (p) { sep->se_max = strtoul(p, &q, 10); if (*q) syslog (LOG_WARNING, "%s:%lu: invalid number (%s)", file, (unsigned long) *line, p); } } if (ISMUX (sep)) { /* * Silently enforce "nowait" for TCPMUX services since * they don't have an assigned port to listen on. */ sep->se_wait = 0; if (strncmp (sep->se_proto, "tcp", 3)) { syslog (LOG_ERR, "%s:%lu: bad protocol for tcpmux service %s", file, (unsigned long) *line, sep->se_service); continue; } if (sep->se_socktype != SOCK_STREAM) { syslog (LOG_ERR, "%s:%lu: bad socket type for tcpmux service %s", file, (unsigned long) *line, sep->se_service); continue; } } sep->se_user = newstr (argv[INETD_USER]); sep->se_server = newstr (argv[INETD_SERVER_PATH]); if (strcmp (sep->se_server, "internal") == 0) { sep->se_bi = bi_lookup (sep); if (!sep->se_bi) { syslog (LOG_ERR, "%s:%lu: internal service %s unknown", file, (unsigned long) *line, sep->se_service); continue; } sep->se_wait = sep->se_bi->bi_wait; } else sep->se_bi = NULL; sep->se_argc = argc - INETD_FIELDS_MIN + 1; sep->se_argv = calloc (sep->se_argc + 1, sizeof sep->se_argv[0]); if (!sep->se_argv) { syslog (LOG_ERR, "%s:%lu: Out of memory.", file, (unsigned long) *line); exit (-1); } for (i = 0; i < sep->se_argc; i++) { sep->se_argv[i] = argv[INETD_SERVER_ARGS + i]; argv[INETD_SERVER_ARGS + i] = 0; } sep->se_argv[i] = NULL; break; } argcv_free (argc, argv); return next_node_sep (sep); }
struct servtab * enter (struct servtab *cp) { struct servtab *sep; SIGSTATUS sigstatus; int i; /* Checking/Removing duplicates */ for (sep = servtab; sep; sep = sep->se_next) if (memcmp (&sep->se_ctrladdr, &cp->se_ctrladdr, sizeof (sep->se_ctrladdr)) == 0 && strcmp (sep->se_service, cp->se_service) == 0 && strcmp (sep->se_proto, cp->se_proto) == 0 && ISMUX (sep) == ISMUX (cp)) break; if (sep != 0) { signal_block (&sigstatus); /* * sep->se_wait may be holding the pid of a daemon * that we're waiting for. If so, don't overwrite * it unless the config file explicitly says don't * wait. */ if (cp->se_bi == 0 && (sep->se_wait == 1 || cp->se_wait == 0)) sep->se_wait = cp->se_wait; #define SWAP(a, b) { char *c = a; a = b; b = c; } if (cp->se_user) SWAP (sep->se_user, cp->se_user); if (cp->se_server) SWAP (sep->se_server, cp->se_server); argcv_free (sep->se_argc, sep->se_argv); sep->se_argc = cp->se_argc; sep->se_argv = cp->se_argv; cp->se_argc = 0; cp->se_argv = NULL; sep->se_checked = 1; signal_unblock (&sigstatus); if (debug) print_service ("REDO", sep); return sep; } if (debug) print_service ("ADD ", cp); sep = (struct servtab *) malloc (sizeof (*sep)); if (sep == NULL) { syslog (LOG_ERR, "Out of memory."); exit (-1); } *sep = *cp; dupstr (&sep->se_node); dupstr (&sep->se_service); dupstr (&sep->se_proto); dupstr (&sep->se_user); dupstr (&sep->se_server); dupmem ((void**)&sep->se_argv, sep->se_argc * sizeof (sep->se_argv[0])); for (i = 0; i < sep->se_argc; i++) dupstr (&sep->se_argv[i]); sep->se_fd = -1; signal_block (&sigstatus); sep->se_next = servtab; servtab = sep; signal_unblock (&sigstatus); return sep; }