📄 servtab.c
字号:
/* * Copyright (c) 1983, 1991 The Regents of the University of California. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */#include <sys/types.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/un.h>#include <netdb.h>#include <syslog.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include "inetd.h"#include "servtab.h"#include "builtins.h"#include "sig.h"#include "mysleep.h"char servtab_rcsid[] = "$Id: servtab.c,v 1.6 2000/07/22 20:20:50 dholland Exp $";static struct biltin biltins[] = { /* service socktype fork,wait function */ /* Echo received data */ { "echo", SOCK_STREAM, 1, 0, echo_stream, }, { "echo", SOCK_DGRAM, 0, 0, echo_dg, }, /* Internet /dev/null */ { "discard", SOCK_STREAM, 1, 0, discard_stream, }, { "discard", SOCK_DGRAM, 0, 0, discard_dg, }, /* Return 32 bit time since 1900 */ { "time", SOCK_STREAM, 0, 0, machtime_stream, }, { "time", SOCK_DGRAM, 0, 0, machtime_dg, }, /* Return human-readable time */ { "daytime", SOCK_STREAM, 0, 0, daytime_stream, }, { "daytime", SOCK_DGRAM, 0, 0, daytime_dg, }, /* Familiar character generator */ { "chargen", SOCK_STREAM, 1, 0, chargen_stream, }, { "chargen", SOCK_DGRAM, 0, 0, chargen_dg, }, { NULL, 0, 0, 0, NULL }};struct servtab *find_service_by_fd(int fd){ struct servtab *sep; for (sep = servtab; sep; sep = sep->se_next) { if (sep->se_fd == fd) return sep; } return NULL;}struct servtab *find_service_by_pid(pid_t pid){ struct servtab *sep; for (sep = servtab; sep; sep = sep->se_next) { if (sep->se_wait == pid) return sep; } return NULL;}staticstruct servtab *find_same_service(struct servtab *cp){ struct servtab *sep; for (sep = servtab; sep; sep = sep->se_next) { if (strcmp(sep->se_service, cp->se_service)) continue; if (strcmp(sep->se_proto, cp->se_proto)) continue; /* * At this point they're the same up to bind address. * Catch 1: se_address can be null. * Catch 2: two different se_addresses can give the same IP. * Catch 3: contents of se_ctrladdr_in.sin_addr are undefined * if they're unix sockets. But we do know that this * isn't the case if se_address isn't null. */ /* Easy case: both null (cannot point to the same string) */ if (sep->se_address == cp->se_address) return sep; /* Now, if one is null, the other isn't */ if (sep->se_address==NULL || cp->se_address==NULL) continue; /* Don't bother to compare the hostnames, just the IPs */ if (sep->se_ctrladdr_in.sin_addr.s_addr == cp->se_ctrladdr_in.sin_addr.s_addr) return sep; } return NULL;}const char *service_name(struct servtab *sep){ static char rv[256]; if (sep->se_address) { snprintf(rv, sizeof(rv), "%s/%s@%s", sep->se_service, sep->se_proto, sep->se_address); } else { snprintf(rv, sizeof(rv), "%s/%s", sep->se_service, sep->se_proto); } return rv;}/********* exit-resistant malloc ************************//* * On many systems, including presently Linux, this is bloat because * malloc never returns null - if the system runs out of swap, it * panics or randomly starts killing processes or does other weird * stuff. However, it doesn't hurt to be prepared. This is the only * place inetd can actually exit due to failure, now. */void *domalloc(size_t len){ static int retries[] = { 2, 10, 60, 600, -1 }; void *p; int try = 0; while (retries[try]>0) { p = malloc(len); if (p != NULL) { return p; } syslog(LOG_ERR, "Out of memory - retrying in %d seconds.", retries[try]); mysleep(retries[try]); try++; } /* Should this be LOG_EMERG? */ syslog(LOG_ALERT, "Out of memory - GIVING UP!"); exit(100); return NULL; /* unreachable */}char *dostrdup(const char *cp){ char *x = domalloc(strlen(cp)+1); strcpy(x, cp); return x;}/********* config parser ********************************/static void loadconfigent(struct servtab *cp);static FILE *fconfig = NULL;#if 0 /* old version */static struct servtab serv;static char line[256];staticchar *nextline(FILE *fd){ char *cp; if (fgets(line, sizeof (line), fd) == NULL) return ((char *)0); cp = strchr(line, '\n'); if (cp) *cp = '\0'; return (line);}static char *skip(char **cpp){ register char *cp = *cpp; char *start; if (*cpp == NULL) return ((char *)0);again: while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0') { int c; c = getc(fconfig); (void) ungetc(c, fconfig); if (c == ' ' || c == '\t') if ((cp = nextline(fconfig))!=NULL) goto again; *cpp = NULL; return NULL; } start = cp; while (*cp && *cp != ' ' && *cp != '\t') cp++; if (*cp != '\0') *cp++ = '\0'; *cpp = cp; return (start);}staticstruct servtab *getconfigent(void){ register struct servtab *sep = &serv; int argc; char *cp, *arg;more: while ((cp = nextline(fconfig)) && *cp == '#') ; if (cp == NULL) { return NULL; } memset(sep, 0, sizeof(*sep)); sep->se_service = dostrdup(skip(&cp)); arg = skip(&cp); if (arg == NULL) goto more; if (strcmp(arg, "stream") == 0) sep->se_socktype = SOCK_STREAM; else if (strcmp(arg, "dgram") == 0) sep->se_socktype = SOCK_DGRAM; else if (strcmp(arg, "rdm") == 0) sep->se_socktype = SOCK_RDM; else if (strcmp(arg, "seqpacket") == 0) sep->se_socktype = SOCK_SEQPACKET; else if (strcmp(arg, "raw") == 0) sep->se_socktype = SOCK_RAW; else sep->se_socktype = -1; sep->se_proto = dostrdup(skip(&cp)); if (strcmp(sep->se_proto, "unix") == 0) { sep->se_family = AF_UNIX; } else { sep->se_family = AF_INET; if (strncmp(sep->se_proto, "rpc/", 4) == 0) {#ifdef RPC char *cp1, *ccp; cp1 = index(sep->se_service, '/'); if (cp1 == NULL) { syslog(LOG_ERR, "%s: no rpc version", sep->se_service); goto more; } *cp1++ = '\0'; sep->se_rpcversl = sep->se_rpcversh = strtol(cp1, &ccp, 0); if (ccp == cp1) { badafterall: syslog(LOG_ERR, "%s/%s: bad rpc version", sep->se_service, cp1); goto more; } if (*ccp == '-') { cp1 = ccp + 1; sep->se_rpcversh = strtol(cp1, &ccp, 0); if (ccp == cp1) goto badafterall; }#else syslog(LOG_ERR, "%s: rpc services not supported", sep->se_service); goto more;#endif /* RPC */ } } arg = skip(&cp); if (arg == NULL) goto more; { char *s = index(arg, '.'); if (s) { *s++ = '\0'; sep->se_max = atoi(s); } else sep->se_max = TOOMANY; } sep->se_wait = strcmp(arg, "wait") == 0; sep->se_user = dostrdup(skip(&cp)); sep->se_group = strchr(sep->se_user, '.'); if (sep->se_group) { *sep->se_group++ = '\0'; } sep->se_server = dostrdup(skip(&cp)); if (strcmp(sep->se_server, "internal") == 0) { register struct biltin *bi; for (bi = biltins; bi->bi_service; bi++) if (bi->bi_socktype == sep->se_socktype && strcmp(bi->bi_service, sep->se_service) == 0) break; if (bi->bi_service == 0) { syslog(LOG_ERR, "internal service %s unknown\n", sep->se_service); goto more; } sep->se_bi = bi; sep->se_wait = bi->bi_wait; } else sep->se_bi = NULL; argc = 0; for (arg = skip(&cp); cp; arg = skip(&cp)) {#if MULOG char *colon, *rindex(); if (argc == 0 && (colon = rindex(arg, ':'))) { while (arg < colon) { int x; char *ccp; switch (*arg++) { case 'l': x = 1; if (isdigit(*arg)) { x = strtol(arg, &ccp, 0); if (ccp == arg) break; arg = ccp; } sep->se_log &= ~MULOG_RFC931; sep->se_log |= x; break; case 'a': sep->se_log |= MULOG_RFC931; break; default: break; } } arg = colon + 1; }#endif if (argc < MAXARGV) sep->se_argv[argc++] = dostrdup(arg); } while (argc <= MAXARGV) sep->se_argv[argc++] = NULL; return (sep);}#else /* new version begins here */struct wordmap { const char *word; int val;};static struct wordmap socket_types[] = { { "stream", SOCK_STREAM }, { "dgram", SOCK_DGRAM }, { "rdm", SOCK_RDM }, { "seqpacket", SOCK_SEQPACKET }, { "raw", SOCK_RAW }, { NULL, -1 }};staticintmap_word(struct wordmap *wm, const char *word){ int i; for (i=0; wm[i].word!=NULL; i++) { if (!strcmp(wm[i].word, word)) return wm[i].val; } return -1;}staticstruct biltin *find_builtin(int socktype, const char *service){ int i; for (i=0; biltins[i].bi_service; i++) { if (biltins[i].bi_socktype != socktype) continue; if (strcmp(biltins[i].bi_service, service)) continue; return &biltins[i]; } return NULL;}staticconst char *assemble_entry(struct servtab *sep, int nfields, char **fields){ struct in_addr service_home; struct hostent *hp; char *s, *t; int i; if (nfields < 6) { return "Incomplete config entry"; } memset(sep, 0, sizeof(*sep)); s = strchr(fields[0], '@'); if (s) { *s++ = 0; sep->se_address = s; hp = gethostbyname(s); if (hp==NULL) return "Service hostname/address not found"; memcpy(&service_home, hp->h_addr, sizeof(service_home)); } else { service_home.s_addr = INADDR_ANY; } sep->se_service = fields[0]; sep->se_socktype = map_word(socket_types, fields[1]); free(fields[1]); sep->se_proto = fields[2]; if (!strcmp(sep->se_proto, "unix")) { sep->se_family = AF_UNIX; if (sep->se_address!=NULL) { return "@host given for unix socket"; } } else { sep->se_family = AF_INET; sep->se_ctrladdr_in.sin_addr = service_home; if (!strncmp(sep->se_proto, "rpc/", 4)) {#ifdef RPC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -