[11719] | 1 | /* $NetBSD: inetd.c,v 1.38.2.2 1998/05/05 08:12:06 mycroft Exp $ */ |
---|
| 2 | |
---|
| 3 | /* |
---|
| 4 | * Copyright (c) 1983, 1991, 1993, 1994 |
---|
| 5 | * The Regents of the University of California. All rights reserved. |
---|
| 6 | * |
---|
| 7 | * Redistribution and use in source and binary forms, with or without |
---|
| 8 | * modification, are permitted provided that the following conditions |
---|
| 9 | * are met: |
---|
| 10 | * 1. Redistributions of source code must retain the above copyright |
---|
| 11 | * notice, this list of conditions and the following disclaimer. |
---|
| 12 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| 13 | * notice, this list of conditions and the following disclaimer in the |
---|
| 14 | * documentation and/or other materials provided with the distribution. |
---|
| 15 | * 3. All advertising materials mentioning features or use of this software |
---|
| 16 | * must display the following acknowledgement: |
---|
| 17 | * This product includes software developed by the University of |
---|
| 18 | * California, Berkeley and its contributors. |
---|
| 19 | * 4. Neither the name of the University nor the names of its contributors |
---|
| 20 | * may be used to endorse or promote products derived from this software |
---|
| 21 | * without specific prior written permission. |
---|
| 22 | * |
---|
| 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
| 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
| 33 | * SUCH DAMAGE. |
---|
| 34 | */ |
---|
| 35 | |
---|
[11726] | 36 | #ifdef __NetBSD__ |
---|
[11719] | 37 | #include <sys/cdefs.h> |
---|
[11726] | 38 | #else |
---|
| 39 | #define __COPYRIGHT(x) char *copyright = x |
---|
| 40 | #define __RCSID(x) char *rcsid = x |
---|
| 41 | char *__progname; |
---|
| 42 | #endif |
---|
| 43 | |
---|
[11719] | 44 | #ifndef lint |
---|
| 45 | __COPYRIGHT("@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ |
---|
| 46 | The Regents of the University of California. All rights reserved.\n"); |
---|
| 47 | #if 0 |
---|
| 48 | static char sccsid[] = "@(#)inetd.c 8.4 (Berkeley) 4/13/94"; |
---|
| 49 | #else |
---|
| 50 | __RCSID("$NetBSD: inetd.c,v 1.38.2.2 1998/05/05 08:12:06 mycroft Exp $"); |
---|
| 51 | #endif |
---|
| 52 | #endif /* not lint */ |
---|
| 53 | |
---|
| 54 | /* |
---|
| 55 | * Inetd - Internet super-server |
---|
| 56 | * |
---|
| 57 | * This program invokes all internet services as needed. Connection-oriented |
---|
| 58 | * services are invoked each time a connection is made, by creating a process. |
---|
| 59 | * This process is passed the connection as file descriptor 0 and is expected |
---|
| 60 | * to do a getpeername to find out the source host and port. |
---|
| 61 | * |
---|
| 62 | * Datagram oriented services are invoked when a datagram |
---|
| 63 | * arrives; a process is created and passed a pending message |
---|
| 64 | * on file descriptor 0. Datagram servers may either connect |
---|
| 65 | * to their peer, freeing up the original socket for inetd |
---|
| 66 | * to receive further messages on, or ``take over the socket'', |
---|
| 67 | * processing all arriving datagrams and, eventually, timing |
---|
| 68 | * out. The first type of server is said to be ``multi-threaded''; |
---|
| 69 | * the second type of server ``single-threaded''. |
---|
| 70 | * |
---|
| 71 | * Inetd uses a configuration file which is read at startup |
---|
| 72 | * and, possibly, at some later time in response to a hangup signal. |
---|
| 73 | * The configuration file is ``free format'' with fields given in the |
---|
| 74 | * order shown below. Continuation lines for an entry must being with |
---|
| 75 | * a space or tab. All fields must be present in each entry. |
---|
| 76 | * |
---|
| 77 | * service name must be in /etc/services or must |
---|
| 78 | * name a tcpmux service |
---|
| 79 | * socket type stream/dgram/raw/rdm/seqpacket |
---|
| 80 | * protocol must be in /etc/protocols |
---|
| 81 | * wait/nowait[.max] single-threaded/multi-threaded, max # |
---|
| 82 | * user[.group] user/group to run daemon as |
---|
| 83 | * server program full path name |
---|
| 84 | * server program arguments maximum of MAXARGS (20) |
---|
| 85 | * |
---|
| 86 | * For RPC services |
---|
| 87 | * service name/version must be in /etc/rpc |
---|
| 88 | * socket type stream/dgram/raw/rdm/seqpacket |
---|
| 89 | * protocol must be in /etc/protocols |
---|
| 90 | * wait/nowait[.max] single-threaded/multi-threaded |
---|
| 91 | * user[.group] user to run daemon as |
---|
| 92 | * server program full path name |
---|
| 93 | * server program arguments maximum of MAXARGS (20) |
---|
| 94 | * |
---|
| 95 | * For non-RPC services, the "service name" can be of the form |
---|
| 96 | * hostaddress:servicename, in which case the hostaddress is used |
---|
| 97 | * as the host portion of the address to listen on. If hostaddress |
---|
| 98 | * consists of a single `*' character, INADDR_ANY is used. |
---|
| 99 | * |
---|
| 100 | * A line can also consist of just |
---|
| 101 | * hostaddress: |
---|
| 102 | * where hostaddress is as in the preceding paragraph. Such a line must |
---|
| 103 | * have no further fields; the specified hostaddress is remembered and |
---|
| 104 | * used for all further lines that have no hostaddress specified, |
---|
| 105 | * until the next such line (or EOF). (This is why * is provided to |
---|
| 106 | * allow explicit specification of INADDR_ANY.) A line |
---|
| 107 | * *: |
---|
| 108 | * is implicitly in effect at the beginning of the file. |
---|
| 109 | * |
---|
| 110 | * The hostaddress specifier may (and often will) contain dots; |
---|
| 111 | * the service name must not. |
---|
| 112 | * |
---|
| 113 | * For RPC services, host-address specifiers are accepted and will |
---|
| 114 | * work to some extent; however, because of limitations in the |
---|
| 115 | * portmapper interface, it will not work to try to give more than |
---|
| 116 | * one line for any given RPC service, even if the host-address |
---|
| 117 | * specifiers are different. |
---|
| 118 | * |
---|
| 119 | * TCP services without official port numbers are handled with the |
---|
| 120 | * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for |
---|
| 121 | * requests. When a connection is made from a foreign host, the service |
---|
| 122 | * requested is passed to tcpmux, which looks it up in the servtab list |
---|
| 123 | * and returns the proper entry for the service. Tcpmux returns a |
---|
| 124 | * negative reply if the service doesn't exist, otherwise the invoked |
---|
| 125 | * server is expected to return the positive reply if the service type in |
---|
| 126 | * inetd.conf file has the prefix "tcpmux/". If the service type has the |
---|
| 127 | * prefix "tcpmux/+", tcpmux will return the positive reply for the |
---|
| 128 | * process; this is for compatibility with older server code, and also |
---|
| 129 | * allows you to invoke programs that use stdin/stdout without putting any |
---|
| 130 | * special server code in them. Services that use tcpmux are "nowait" |
---|
| 131 | * because they do not have a well-known port and hence cannot listen |
---|
| 132 | * for new requests. |
---|
| 133 | * |
---|
| 134 | * Comment lines are indicated by a `#' in column 1. |
---|
| 135 | */ |
---|
| 136 | |
---|
| 137 | /* |
---|
| 138 | * Here's the scoop concerning the user.group feature: |
---|
| 139 | * |
---|
| 140 | * 1) set-group-option off. |
---|
| 141 | * |
---|
| 142 | * a) user = root: NO setuid() or setgid() is done |
---|
| 143 | * |
---|
| 144 | * b) other: setuid() |
---|
| 145 | * setgid(primary group as found in passwd) |
---|
| 146 | * initgroups(name, primary group) |
---|
| 147 | * |
---|
| 148 | * 2) set-group-option on. |
---|
| 149 | * |
---|
| 150 | * a) user = root: NO setuid() |
---|
| 151 | * setgid(specified group) |
---|
| 152 | * NO initgroups() |
---|
| 153 | * |
---|
| 154 | * b) other: setuid() |
---|
| 155 | * setgid(specified group) |
---|
| 156 | * initgroups(name, specified group) |
---|
| 157 | * |
---|
| 158 | */ |
---|
| 159 | |
---|
[13348] | 160 | #include <sys/types.h> |
---|
[11719] | 161 | #include <sys/param.h> |
---|
| 162 | #include <sys/stat.h> |
---|
| 163 | #include <sys/ioctl.h> |
---|
| 164 | #include <sys/socket.h> |
---|
| 165 | #include <sys/un.h> |
---|
| 166 | #include <sys/wait.h> |
---|
| 167 | #include <sys/time.h> |
---|
| 168 | #include <sys/resource.h> |
---|
| 169 | |
---|
| 170 | #ifndef RLIMIT_NOFILE |
---|
| 171 | #define RLIMIT_NOFILE RLIMIT_OFILE |
---|
| 172 | #endif |
---|
| 173 | |
---|
| 174 | #define RPC |
---|
| 175 | |
---|
| 176 | #include <netinet/in.h> |
---|
| 177 | #include <arpa/inet.h> |
---|
| 178 | #ifdef RPC |
---|
| 179 | #include <rpc/rpc.h> |
---|
| 180 | #include <rpc/pmap_clnt.h> |
---|
[11726] | 181 | #ifdef HAVE_RPC_RPCENT_H |
---|
| 182 | #include <rpc/rpcent.h> |
---|
[11719] | 183 | #endif |
---|
[11726] | 184 | #endif |
---|
[11719] | 185 | |
---|
| 186 | #include <errno.h> |
---|
| 187 | #include <fcntl.h> |
---|
| 188 | #include <grp.h> |
---|
| 189 | #include <netdb.h> |
---|
| 190 | #include <pwd.h> |
---|
| 191 | #include <signal.h> |
---|
| 192 | #include <stdio.h> |
---|
| 193 | #include <stdlib.h> |
---|
| 194 | #include <string.h> |
---|
| 195 | #include <syslog.h> |
---|
| 196 | #include <unistd.h> |
---|
| 197 | |
---|
| 198 | #include "pathnames.h" |
---|
| 199 | |
---|
| 200 | #ifdef LIBWRAP |
---|
| 201 | # include <tcpd.h> |
---|
| 202 | #ifndef LIBWRAP_ALLOW_FACILITY |
---|
| 203 | # define LIBWRAP_ALLOW_FACILITY LOG_AUTH |
---|
| 204 | #endif |
---|
| 205 | #ifndef LIBWRAP_ALLOW_SEVERITY |
---|
| 206 | # define LIBWRAP_ALLOW_SEVERITY LOG_INFO |
---|
| 207 | #endif |
---|
| 208 | #ifndef LIBWRAP_DENY_FACILITY |
---|
| 209 | # define LIBWRAP_DENY_FACILITY LOG_AUTH |
---|
| 210 | #endif |
---|
| 211 | #ifndef LIBWRAP_DENY_SEVERITY |
---|
| 212 | # define LIBWRAP_DENY_SEVERITY LOG_WARNING |
---|
| 213 | #endif |
---|
| 214 | int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; |
---|
| 215 | int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; |
---|
| 216 | #endif |
---|
| 217 | |
---|
| 218 | #define TOOMANY 40 /* don't start more than TOOMANY */ |
---|
| 219 | #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ |
---|
| 220 | #define RETRYTIME (60*10) /* retry after bind or server fail */ |
---|
| 221 | |
---|
[11726] | 222 | sigset_t sig_block; |
---|
[11719] | 223 | |
---|
| 224 | int debug; |
---|
| 225 | #ifdef LIBWRAP |
---|
| 226 | int lflag; |
---|
| 227 | #endif |
---|
[11726] | 228 | int access_on; |
---|
[11719] | 229 | int nsock, maxsock; |
---|
| 230 | fd_set allsock; |
---|
| 231 | int options; |
---|
| 232 | int timingout; |
---|
| 233 | struct servent *sp; |
---|
| 234 | char *curdom; |
---|
| 235 | |
---|
| 236 | #ifndef OPEN_MAX |
---|
| 237 | #define OPEN_MAX 64 |
---|
| 238 | #endif |
---|
| 239 | |
---|
| 240 | /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */ |
---|
| 241 | #define FD_MARGIN (8) |
---|
[11726] | 242 | rlim_t rlim_ofile_cur = OPEN_MAX; |
---|
[11719] | 243 | |
---|
| 244 | #ifdef RLIMIT_NOFILE |
---|
| 245 | struct rlimit rlim_ofile; |
---|
| 246 | #endif |
---|
| 247 | |
---|
| 248 | struct servtab { |
---|
| 249 | char *se_hostaddr; /* host address to listen on */ |
---|
| 250 | char *se_service; /* name of service */ |
---|
| 251 | int se_socktype; /* type of socket to use */ |
---|
| 252 | int se_family; /* address family */ |
---|
| 253 | char *se_proto; /* protocol used */ |
---|
| 254 | int se_rpcprog; /* rpc program number */ |
---|
| 255 | int se_rpcversl; /* rpc program lowest version */ |
---|
| 256 | int se_rpcversh; /* rpc program highest version */ |
---|
| 257 | #define isrpcservice(sep) ((sep)->se_rpcversl != 0) |
---|
[13348] | 258 | pid_t se_wait; /* single threaded server */ |
---|
[11726] | 259 | short se_switched; /* switched by access_on/off */ |
---|
[11719] | 260 | short se_checked; /* looked at during merge */ |
---|
| 261 | char *se_user; /* user name to run as */ |
---|
| 262 | char *se_group; /* group name to run as */ |
---|
| 263 | struct biltin *se_bi; /* if built-in, description */ |
---|
| 264 | char *se_server; /* server program */ |
---|
| 265 | #define MAXARGV 20 |
---|
| 266 | char *se_argv[MAXARGV+1]; /* program arguments */ |
---|
| 267 | int se_fd; /* open descriptor */ |
---|
| 268 | int se_type; /* type */ |
---|
| 269 | union { |
---|
| 270 | struct sockaddr se_un_ctrladdr; |
---|
| 271 | struct sockaddr_in se_un_ctrladdr_in; |
---|
| 272 | struct sockaddr_un se_un_ctrladdr_un; |
---|
| 273 | } se_un; /* bound address */ |
---|
| 274 | #define se_ctrladdr se_un.se_un_ctrladdr |
---|
| 275 | #define se_ctrladdr_in se_un.se_un_ctrladdr_in |
---|
| 276 | #define se_ctrladdr_un se_un.se_un_ctrladdr_un |
---|
| 277 | int se_ctrladdr_size; |
---|
| 278 | int se_max; /* max # of instances of this service */ |
---|
| 279 | int se_count; /* number started since se_time */ |
---|
| 280 | struct timeval se_time; /* start of se_count */ |
---|
| 281 | #ifdef MULOG |
---|
| 282 | int se_log; |
---|
| 283 | #define MULOG_RFC931 0x40000000 |
---|
| 284 | #endif |
---|
| 285 | struct servtab *se_next; |
---|
| 286 | } *servtab; |
---|
| 287 | |
---|
| 288 | #define NORM_TYPE 0 |
---|
| 289 | #define MUX_TYPE 1 |
---|
| 290 | #define MUXPLUS_TYPE 2 |
---|
| 291 | #define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ |
---|
| 292 | ((sep)->se_type == MUXPLUS_TYPE)) |
---|
| 293 | #define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) |
---|
| 294 | |
---|
| 295 | |
---|
[11726] | 296 | #ifndef __P |
---|
| 297 | #define __P(x) x |
---|
| 298 | #endif |
---|
| 299 | |
---|
[11719] | 300 | void chargen_dg __P((int, struct servtab *)); |
---|
| 301 | void chargen_stream __P((int, struct servtab *)); |
---|
| 302 | void close_sep __P((struct servtab *)); |
---|
| 303 | void config __P((int)); |
---|
[11726] | 304 | void access_switch __P((int)); |
---|
[11719] | 305 | void daytime_dg __P((int, struct servtab *)); |
---|
| 306 | void daytime_stream __P((int, struct servtab *)); |
---|
| 307 | void discard_dg __P((int, struct servtab *)); |
---|
| 308 | void discard_stream __P((int, struct servtab *)); |
---|
| 309 | void echo_dg __P((int, struct servtab *)); |
---|
| 310 | void echo_stream __P((int, struct servtab *)); |
---|
| 311 | void endconfig __P((void)); |
---|
| 312 | struct servtab *enter __P((struct servtab *)); |
---|
| 313 | void freeconfig __P((struct servtab *)); |
---|
| 314 | struct servtab *getconfigent __P((void)); |
---|
| 315 | void goaway __P((int)); |
---|
| 316 | void machtime_dg __P((int, struct servtab *)); |
---|
| 317 | void machtime_stream __P((int, struct servtab *)); |
---|
| 318 | char *newstr __P((char *)); |
---|
| 319 | char *nextline __P((FILE *)); |
---|
| 320 | void print_service __P((char *, struct servtab *)); |
---|
| 321 | void reapchild __P((int)); |
---|
| 322 | void retry __P((int)); |
---|
| 323 | void run_service __P((int, struct servtab *)); |
---|
| 324 | int setconfig __P((void)); |
---|
| 325 | void setup __P((struct servtab *)); |
---|
| 326 | char *sskip __P((char **)); |
---|
| 327 | char *skip __P((char **)); |
---|
| 328 | void tcpmux __P((int, struct servtab *)); |
---|
| 329 | void usage __P((void)); |
---|
| 330 | void logpid __P((void)); |
---|
| 331 | void register_rpc __P((struct servtab *sep)); |
---|
| 332 | void unregister_rpc __P((struct servtab *sep)); |
---|
| 333 | void bump_nofile __P((void)); |
---|
| 334 | void inetd_setproctitle __P((char *, int)); |
---|
| 335 | void initring __P((void)); |
---|
| 336 | long machtime __P((void)); |
---|
| 337 | static int getline __P((int, char *, int)); |
---|
| 338 | int main __P((int, char *[], char *[])); |
---|
| 339 | |
---|
| 340 | struct biltin { |
---|
| 341 | char *bi_service; /* internally provided service name */ |
---|
| 342 | int bi_socktype; /* type of socket supported */ |
---|
| 343 | short bi_fork; /* 1 if should fork before call */ |
---|
| 344 | short bi_wait; /* 1 if should wait for child */ |
---|
| 345 | void (*bi_fn) __P((int, struct servtab *)); |
---|
| 346 | /* function which performs it */ |
---|
| 347 | } biltins[] = { |
---|
| 348 | /* Echo received data */ |
---|
| 349 | { "echo", SOCK_STREAM, 1, 0, echo_stream }, |
---|
| 350 | { "echo", SOCK_DGRAM, 0, 0, echo_dg }, |
---|
| 351 | |
---|
| 352 | /* Internet /dev/null */ |
---|
| 353 | { "discard", SOCK_STREAM, 1, 0, discard_stream }, |
---|
| 354 | { "discard", SOCK_DGRAM, 0, 0, discard_dg }, |
---|
| 355 | |
---|
| 356 | /* Return 32 bit time since 1970 */ |
---|
| 357 | { "time", SOCK_STREAM, 0, 0, machtime_stream }, |
---|
| 358 | { "time", SOCK_DGRAM, 0, 0, machtime_dg }, |
---|
| 359 | |
---|
| 360 | /* Return human-readable time */ |
---|
| 361 | { "daytime", SOCK_STREAM, 0, 0, daytime_stream }, |
---|
| 362 | { "daytime", SOCK_DGRAM, 0, 0, daytime_dg }, |
---|
| 363 | |
---|
| 364 | /* Familiar character generator */ |
---|
| 365 | { "chargen", SOCK_STREAM, 1, 0, chargen_stream }, |
---|
| 366 | { "chargen", SOCK_DGRAM, 0, 0, chargen_dg }, |
---|
| 367 | |
---|
| 368 | { "tcpmux", SOCK_STREAM, 1, 0, tcpmux }, |
---|
| 369 | |
---|
| 370 | { NULL } |
---|
| 371 | }; |
---|
| 372 | |
---|
| 373 | #define NUMINT (sizeof(intab) / sizeof(struct inent)) |
---|
| 374 | char *CONFIG = _PATH_INETDCONF; |
---|
| 375 | char **Argv; |
---|
| 376 | char *LastArg; |
---|
| 377 | extern char *__progname; |
---|
| 378 | |
---|
| 379 | #ifdef sun |
---|
| 380 | /* |
---|
| 381 | * Sun's RPC library caches the result of `dtablesize()' |
---|
| 382 | * This is incompatible with our "bumping" of file descriptors "on demand" |
---|
| 383 | */ |
---|
| 384 | int |
---|
| 385 | _rpc_dtablesize() |
---|
| 386 | { |
---|
| 387 | return rlim_ofile_cur; |
---|
| 388 | } |
---|
| 389 | #endif |
---|
| 390 | |
---|
| 391 | int |
---|
| 392 | main(argc, argv, envp) |
---|
| 393 | int argc; |
---|
| 394 | char *argv[], *envp[]; |
---|
| 395 | { |
---|
| 396 | struct servtab *sep, *nsep; |
---|
[11726] | 397 | struct sigaction sa; |
---|
[11719] | 398 | int ch, dofork; |
---|
| 399 | pid_t pid; |
---|
| 400 | |
---|
[11726] | 401 | __progname = argv[0]; |
---|
| 402 | if (strchr(__progname, '/')) |
---|
| 403 | __progname = strrchr(__progname, '/') + 1; |
---|
| 404 | |
---|
[11719] | 405 | Argv = argv; |
---|
| 406 | if (envp == 0 || *envp == 0) |
---|
| 407 | envp = argv; |
---|
| 408 | while (*envp) |
---|
| 409 | envp++; |
---|
| 410 | LastArg = envp[-1] + strlen(envp[-1]); |
---|
| 411 | |
---|
| 412 | while ((ch = getopt(argc, argv, |
---|
| 413 | #ifdef LIBWRAP |
---|
[11726] | 414 | "dln" |
---|
[11719] | 415 | #else |
---|
[11726] | 416 | "dn" |
---|
[11719] | 417 | #endif |
---|
| 418 | )) != -1) |
---|
| 419 | switch(ch) { |
---|
| 420 | case 'd': |
---|
| 421 | debug = 1; |
---|
| 422 | options |= SO_DEBUG; |
---|
| 423 | break; |
---|
| 424 | #ifdef LIBWRAP |
---|
| 425 | case 'l': |
---|
| 426 | lflag = 1; |
---|
| 427 | break; |
---|
| 428 | #endif |
---|
[11726] | 429 | case 'n': |
---|
| 430 | access_on = 1; |
---|
| 431 | break; |
---|
[11719] | 432 | case '?': |
---|
| 433 | default: |
---|
| 434 | usage(); |
---|
| 435 | } |
---|
| 436 | argc -= optind; |
---|
| 437 | argv += optind; |
---|
| 438 | |
---|
| 439 | if (argc > 0) |
---|
| 440 | CONFIG = argv[0]; |
---|
| 441 | |
---|
[11726] | 442 | if (debug == 0) { |
---|
| 443 | int fd; |
---|
| 444 | |
---|
| 445 | switch (fork ()) { |
---|
| 446 | case -1: |
---|
| 447 | return (-1); |
---|
| 448 | case 0: |
---|
| 449 | break; |
---|
| 450 | default: |
---|
| 451 | _exit(0); |
---|
| 452 | } |
---|
| 453 | |
---|
| 454 | if (setsid() == -1) { |
---|
| 455 | fprintf(stderr, "%s: couldn't setsid\n", __progname); |
---|
| 456 | exit(1); |
---|
| 457 | } |
---|
| 458 | chdir("/"); |
---|
| 459 | if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { |
---|
| 460 | dup2(fd, STDIN_FILENO); |
---|
| 461 | dup2(fd, STDOUT_FILENO); |
---|
| 462 | dup2(fd, STDERR_FILENO); |
---|
| 463 | if (fd > STDERR_FILENO) |
---|
| 464 | close(fd); |
---|
| 465 | } |
---|
| 466 | } |
---|
[11719] | 467 | openlog(__progname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); |
---|
| 468 | logpid(); |
---|
| 469 | |
---|
| 470 | #ifdef RLIMIT_NOFILE |
---|
| 471 | if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) { |
---|
| 472 | syslog(LOG_ERR, "getrlimit: %m"); |
---|
| 473 | } else { |
---|
| 474 | rlim_ofile_cur = rlim_ofile.rlim_cur; |
---|
| 475 | if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ |
---|
| 476 | rlim_ofile_cur = OPEN_MAX; |
---|
| 477 | } |
---|
| 478 | #endif |
---|
| 479 | |
---|
[11726] | 480 | memset(&sa, 0, sizeof(sa)); |
---|
| 481 | sigemptyset(&sig_block); |
---|
| 482 | sigaddset(&sig_block, SIGCHLD); |
---|
| 483 | sigaddset(&sig_block, SIGHUP); |
---|
| 484 | sigaddset(&sig_block, SIGALRM); |
---|
| 485 | sigaddset(&sig_block, SIGUSR1); |
---|
| 486 | sigaddset(&sig_block, SIGUSR2); |
---|
| 487 | memcpy(&sa.sa_mask, &sig_block, sizeof(sigset_t)); |
---|
| 488 | sa.sa_handler = retry; |
---|
| 489 | sigaction(SIGALRM, &sa, NULL); |
---|
[11719] | 490 | config(SIGHUP); |
---|
[11726] | 491 | sa.sa_handler = config; |
---|
| 492 | sigaction(SIGHUP, &sa, NULL); |
---|
| 493 | sa.sa_handler = access_switch; |
---|
| 494 | sigaction(SIGUSR1, &sa, NULL); |
---|
| 495 | sigaction(SIGUSR2, &sa, NULL); |
---|
| 496 | sa.sa_handler = reapchild; |
---|
| 497 | sigaction(SIGCHLD, &sa, NULL); |
---|
| 498 | sa.sa_handler = goaway; |
---|
| 499 | sigaction(SIGTERM, &sa, NULL); |
---|
| 500 | sa.sa_handler = goaway; |
---|
| 501 | sigaction(SIGINT, &sa, NULL); |
---|
| 502 | sigemptyset(&sa.sa_mask); |
---|
| 503 | sa.sa_handler = SIG_IGN; |
---|
| 504 | sigaction(SIGPIPE, &sa, NULL); |
---|
[11719] | 505 | |
---|
| 506 | { |
---|
| 507 | /* space for daemons to overwrite environment for ps */ |
---|
| 508 | #define DUMMYSIZE 100 |
---|
| 509 | char dummy[DUMMYSIZE]; |
---|
| 510 | |
---|
| 511 | (void)memset(dummy, 'x', DUMMYSIZE - 1); |
---|
| 512 | dummy[DUMMYSIZE - 1] = '\0'; |
---|
| 513 | |
---|
| 514 | (void)setenv("inetd_dummy", dummy, 1); |
---|
| 515 | } |
---|
| 516 | |
---|
| 517 | for (;;) { |
---|
| 518 | int n, ctrl; |
---|
| 519 | fd_set readable; |
---|
| 520 | |
---|
| 521 | if (nsock == 0) { |
---|
[11726] | 522 | sigset_t prev_mask; |
---|
| 523 | sigprocmask(SIG_SETMASK, &sig_block, &prev_mask); |
---|
[11719] | 524 | while (nsock == 0) |
---|
[11726] | 525 | sigsuspend(&prev_mask); |
---|
| 526 | sigprocmask(SIG_SETMASK, &prev_mask, NULL); |
---|
[11719] | 527 | } |
---|
| 528 | readable = allsock; |
---|
| 529 | if ((n = select(maxsock + 1, &readable, (fd_set *)0, |
---|
| 530 | (fd_set *)0, (struct timeval *)0)) <= 0) { |
---|
| 531 | if (n == -1 && errno != EINTR) { |
---|
| 532 | syslog(LOG_WARNING, "select: %m"); |
---|
| 533 | sleep(1); |
---|
| 534 | } |
---|
| 535 | continue; |
---|
| 536 | } |
---|
| 537 | for (sep = servtab; n && sep; sep = nsep) { |
---|
| 538 | nsep = sep->se_next; |
---|
| 539 | if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { |
---|
| 540 | n--; |
---|
| 541 | if (debug) |
---|
| 542 | fprintf(stderr, "someone wants %s\n", sep->se_service); |
---|
| 543 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { |
---|
| 544 | /* XXX here do the libwrap check-before-accept */ |
---|
| 545 | ctrl = accept(sep->se_fd, (struct sockaddr *)0, |
---|
| 546 | (int *)0); |
---|
| 547 | if (debug) |
---|
| 548 | fprintf(stderr, "accept, ctrl %d\n", ctrl); |
---|
| 549 | if (ctrl < 0) { |
---|
| 550 | if (errno != EINTR) |
---|
| 551 | syslog(LOG_WARNING, |
---|
| 552 | "accept (for %s): %m", |
---|
| 553 | sep->se_service); |
---|
| 554 | continue; |
---|
| 555 | } |
---|
| 556 | } else |
---|
| 557 | ctrl = sep->se_fd; |
---|
[11726] | 558 | sigprocmask(SIG_SETMASK, &sig_block, NULL); |
---|
[11719] | 559 | pid = 0; |
---|
| 560 | #ifdef LIBWRAP_INTERNAL |
---|
| 561 | dofork = 1; |
---|
| 562 | #else |
---|
| 563 | dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); |
---|
| 564 | #endif |
---|
| 565 | if (dofork) { |
---|
| 566 | if (sep->se_count++ == 0) |
---|
| 567 | (void)gettimeofday(&sep->se_time, |
---|
| 568 | (struct timezone *)0); |
---|
| 569 | else if (sep->se_count >= sep->se_max) { |
---|
| 570 | struct timeval now; |
---|
| 571 | |
---|
| 572 | (void)gettimeofday(&now, (struct timezone *)0); |
---|
| 573 | if (now.tv_sec - sep->se_time.tv_sec > |
---|
| 574 | CNT_INTVL) { |
---|
| 575 | sep->se_time = now; |
---|
| 576 | sep->se_count = 1; |
---|
| 577 | } else { |
---|
| 578 | syslog(LOG_ERR, |
---|
| 579 | "%s/%s server failing (looping), service terminated\n", |
---|
| 580 | sep->se_service, sep->se_proto); |
---|
| 581 | close_sep(sep); |
---|
[11726] | 582 | sigprocmask(SIG_UNBLOCK, |
---|
| 583 | &sig_block, NULL); |
---|
[11719] | 584 | if (!timingout) { |
---|
| 585 | timingout = 1; |
---|
| 586 | alarm(RETRYTIME); |
---|
| 587 | } |
---|
| 588 | continue; |
---|
| 589 | } |
---|
| 590 | } |
---|
| 591 | pid = fork(); |
---|
| 592 | if (pid < 0) { |
---|
| 593 | syslog(LOG_ERR, "fork: %m"); |
---|
| 594 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) |
---|
| 595 | close(ctrl); |
---|
[11726] | 596 | sigprocmask(SIG_UNBLOCK, &sig_block, NULL); |
---|
[11719] | 597 | sleep(1); |
---|
| 598 | continue; |
---|
| 599 | } |
---|
| 600 | if (pid != 0 && sep->se_wait) { |
---|
| 601 | sep->se_wait = pid; |
---|
| 602 | FD_CLR(sep->se_fd, &allsock); |
---|
| 603 | nsock--; |
---|
| 604 | } |
---|
| 605 | if (pid == 0) { |
---|
[11726] | 606 | sigemptyset(&sa.sa_mask); |
---|
| 607 | sa.sa_handler = SIG_DFL; |
---|
| 608 | sigaction(SIGPIPE, &sa, NULL); |
---|
[11719] | 609 | if (debug) |
---|
| 610 | setsid(); |
---|
| 611 | } |
---|
| 612 | } |
---|
[11726] | 613 | sigprocmask(SIG_UNBLOCK, &sig_block, NULL); |
---|
[11719] | 614 | if (pid == 0) { |
---|
| 615 | run_service(ctrl, sep); |
---|
| 616 | if (dofork) |
---|
| 617 | exit(0); |
---|
| 618 | } |
---|
| 619 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) |
---|
| 620 | close(ctrl); |
---|
| 621 | } |
---|
| 622 | } |
---|
| 623 | } |
---|
| 624 | } |
---|
| 625 | |
---|
| 626 | void |
---|
| 627 | run_service(ctrl, sep) |
---|
| 628 | int ctrl; |
---|
| 629 | struct servtab *sep; |
---|
| 630 | { |
---|
| 631 | struct passwd *pwd; |
---|
| 632 | struct group *grp = NULL; /* XXX gcc */ |
---|
| 633 | #ifdef LIBWRAP |
---|
| 634 | struct request_info req; |
---|
| 635 | int denied; |
---|
| 636 | char buf[7], *service = NULL; /* XXX gcc */ |
---|
| 637 | #endif |
---|
| 638 | |
---|
| 639 | #ifdef LIBWRAP |
---|
| 640 | #ifndef LIBWRAP_INTERNAL |
---|
| 641 | if (sep->se_bi == 0) |
---|
| 642 | #endif |
---|
| 643 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { |
---|
| 644 | request_init(&req, RQ_DAEMON, sep->se_argv[0] ? |
---|
| 645 | sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl, NULL); |
---|
| 646 | fromhost(&req); |
---|
| 647 | denied = !hosts_access(&req); |
---|
| 648 | if (denied || lflag) { |
---|
| 649 | sp = getservbyport(sep->se_ctrladdr_in.sin_port, |
---|
| 650 | sep->se_proto); |
---|
| 651 | if (sp == NULL) { |
---|
[11726] | 652 | (void)sprintf(buf, "%d", |
---|
[11719] | 653 | ntohs(sep->se_ctrladdr_in.sin_port)); |
---|
| 654 | service = buf; |
---|
| 655 | } else |
---|
| 656 | service = sp->s_name; |
---|
| 657 | } |
---|
| 658 | if (denied) { |
---|
| 659 | syslog(deny_severity, |
---|
| 660 | "refused connection from %.500s, service %s (%s)", |
---|
| 661 | eval_client(&req), service, sep->se_proto); |
---|
| 662 | goto reject; |
---|
| 663 | } |
---|
| 664 | if (lflag) { |
---|
| 665 | syslog(allow_severity, |
---|
| 666 | "connection from %.500s, service %s (%s)", |
---|
| 667 | eval_client(&req), service, sep->se_proto); |
---|
| 668 | } |
---|
| 669 | } |
---|
| 670 | #endif /* LIBWRAP */ |
---|
| 671 | |
---|
| 672 | if (sep->se_bi) { |
---|
| 673 | (*sep->se_bi->bi_fn)(ctrl, sep); |
---|
| 674 | } else { |
---|
| 675 | if ((pwd = getpwnam(sep->se_user)) == NULL) { |
---|
| 676 | syslog(LOG_ERR, "%s/%s: %s: No such user", |
---|
| 677 | sep->se_service, sep->se_proto, sep->se_user); |
---|
| 678 | goto reject; |
---|
| 679 | } |
---|
| 680 | if (sep->se_group && |
---|
| 681 | (grp = getgrnam(sep->se_group)) == NULL) { |
---|
| 682 | syslog(LOG_ERR, "%s/%s: %s: No such group", |
---|
| 683 | sep->se_service, sep->se_proto, sep->se_group); |
---|
| 684 | goto reject; |
---|
| 685 | } |
---|
| 686 | if (pwd->pw_uid) { |
---|
| 687 | if (sep->se_group) |
---|
| 688 | pwd->pw_gid = grp->gr_gid; |
---|
| 689 | if (setgid(pwd->pw_gid) < 0) { |
---|
| 690 | syslog(LOG_ERR, |
---|
| 691 | "%s/%s: can't set gid %d: %m", sep->se_service, |
---|
| 692 | sep->se_proto, pwd->pw_gid); |
---|
| 693 | goto reject; |
---|
| 694 | } |
---|
| 695 | (void) initgroups(pwd->pw_name, |
---|
| 696 | pwd->pw_gid); |
---|
| 697 | if (setuid(pwd->pw_uid) < 0) { |
---|
| 698 | syslog(LOG_ERR, |
---|
| 699 | "%s/%s: can't set uid %d: %m", sep->se_service, |
---|
| 700 | sep->se_proto, pwd->pw_uid); |
---|
| 701 | goto reject; |
---|
| 702 | } |
---|
| 703 | } else if (sep->se_group) { |
---|
| 704 | (void) setgid((gid_t)grp->gr_gid); |
---|
| 705 | } |
---|
| 706 | if (debug) |
---|
| 707 | fprintf(stderr, "%d execl %s\n", |
---|
| 708 | getpid(), sep->se_server); |
---|
| 709 | #ifdef MULOG |
---|
| 710 | if (sep->se_log) |
---|
| 711 | dolog(sep, ctrl); |
---|
| 712 | #endif |
---|
| 713 | /* Set our control descriptor to not close-on-exec... */ |
---|
| 714 | if (fcntl(ctrl, F_SETFD, 0) < 0) |
---|
| 715 | syslog(LOG_ERR, "fcntl (F_SETFD, 0): %m"); |
---|
| 716 | /* ...and dup it to stdin, stdout, and stderr. */ |
---|
| 717 | if (ctrl != 0) { |
---|
| 718 | dup2(ctrl, 0); |
---|
| 719 | close(ctrl); |
---|
| 720 | ctrl = 0; |
---|
| 721 | } |
---|
| 722 | dup2(0, 1); |
---|
| 723 | dup2(0, 2); |
---|
| 724 | #ifdef RLIMIT_NOFILE |
---|
| 725 | if (rlim_ofile.rlim_cur != rlim_ofile_cur && |
---|
| 726 | setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) |
---|
| 727 | syslog(LOG_ERR, "setrlimit: %m"); |
---|
| 728 | #endif |
---|
| 729 | execv(sep->se_server, sep->se_argv); |
---|
| 730 | syslog(LOG_ERR, "cannot execute %s: %m", sep->se_server); |
---|
| 731 | reject: |
---|
| 732 | if (sep->se_socktype != SOCK_STREAM) |
---|
| 733 | recv(ctrl, buf, sizeof (buf), 0); |
---|
| 734 | _exit(1); |
---|
| 735 | } |
---|
| 736 | } |
---|
| 737 | |
---|
| 738 | void |
---|
| 739 | reapchild(signo) |
---|
| 740 | int signo; |
---|
| 741 | { |
---|
| 742 | int status; |
---|
| 743 | pid_t pid; |
---|
| 744 | struct servtab *sep; |
---|
| 745 | |
---|
| 746 | for (;;) { |
---|
| 747 | pid = wait3(&status, WNOHANG, (struct rusage *)0); |
---|
| 748 | if (pid <= 0) |
---|
| 749 | break; |
---|
| 750 | if (debug) |
---|
| 751 | fprintf(stderr, "%d reaped, status %#x\n", |
---|
| 752 | pid, status); |
---|
| 753 | for (sep = servtab; sep; sep = sep->se_next) |
---|
| 754 | if (sep->se_wait == pid) { |
---|
| 755 | if (WIFEXITED(status) && WEXITSTATUS(status)) |
---|
| 756 | syslog(LOG_WARNING, |
---|
| 757 | "%s: exit status 0x%x", |
---|
| 758 | sep->se_server, WEXITSTATUS(status)); |
---|
| 759 | else if (WIFSIGNALED(status)) |
---|
| 760 | syslog(LOG_WARNING, |
---|
| 761 | "%s: exit signal 0x%x", |
---|
| 762 | sep->se_server, WTERMSIG(status)); |
---|
| 763 | sep->se_wait = 1; |
---|
| 764 | FD_SET(sep->se_fd, &allsock); |
---|
| 765 | nsock++; |
---|
| 766 | if (debug) |
---|
| 767 | fprintf(stderr, "restored %s, fd %d\n", |
---|
| 768 | sep->se_service, sep->se_fd); |
---|
| 769 | } |
---|
| 770 | } |
---|
| 771 | } |
---|
| 772 | |
---|
| 773 | void |
---|
| 774 | config(signo) |
---|
| 775 | int signo; |
---|
| 776 | { |
---|
| 777 | struct servtab *sep, *cp, **sepp; |
---|
[11726] | 778 | sigset_t omask; |
---|
[11719] | 779 | int n; |
---|
| 780 | |
---|
| 781 | if (!setconfig()) { |
---|
| 782 | syslog(LOG_ERR, "%s: %m", CONFIG); |
---|
| 783 | return; |
---|
| 784 | } |
---|
| 785 | for (sep = servtab; sep; sep = sep->se_next) |
---|
| 786 | sep->se_checked = 0; |
---|
| 787 | while ((cp = getconfigent())) { |
---|
| 788 | for (sep = servtab; sep; sep = sep->se_next) |
---|
| 789 | if (strcmp(sep->se_service, cp->se_service) == 0 && |
---|
| 790 | strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 && |
---|
| 791 | strcmp(sep->se_proto, cp->se_proto) == 0 && |
---|
| 792 | ISMUX(sep) == ISMUX(cp)) |
---|
| 793 | break; |
---|
| 794 | if (sep != 0) { |
---|
| 795 | int i; |
---|
| 796 | |
---|
[11726] | 797 | #define SWAP(type, a, b) {type c=a; a=b; b=c;} |
---|
[11719] | 798 | |
---|
[11726] | 799 | sigprocmask(SIG_BLOCK, &sig_block, &omask); |
---|
[11719] | 800 | /* |
---|
| 801 | * sep->se_wait may be holding the pid of a daemon |
---|
| 802 | * that we're waiting for. If so, don't overwrite |
---|
| 803 | * it unless the config file explicitly says don't |
---|
| 804 | * wait. |
---|
| 805 | */ |
---|
| 806 | if (cp->se_bi == 0 && |
---|
| 807 | (sep->se_wait == 1 || cp->se_wait == 0)) |
---|
| 808 | sep->se_wait = cp->se_wait; |
---|
| 809 | SWAP(char *, sep->se_user, cp->se_user); |
---|
| 810 | SWAP(char *, sep->se_group, cp->se_group); |
---|
| 811 | SWAP(char *, sep->se_server, cp->se_server); |
---|
| 812 | for (i = 0; i < MAXARGV; i++) |
---|
| 813 | SWAP(char *, sep->se_argv[i], cp->se_argv[i]); |
---|
| 814 | SWAP(int, cp->se_type, sep->se_type); |
---|
| 815 | SWAP(int, cp->se_max, sep->se_max); |
---|
| 816 | #undef SWAP |
---|
| 817 | if (isrpcservice(sep)) |
---|
| 818 | unregister_rpc(sep); |
---|
| 819 | sep->se_rpcversl = cp->se_rpcversl; |
---|
| 820 | sep->se_rpcversh = cp->se_rpcversh; |
---|
[11726] | 821 | sigprocmask(SIG_SETMASK, &omask, NULL); |
---|
[11719] | 822 | freeconfig(cp); |
---|
| 823 | if (debug) |
---|
| 824 | print_service("REDO", sep); |
---|
| 825 | } else { |
---|
| 826 | sep = enter(cp); |
---|
| 827 | if (debug) |
---|
| 828 | print_service("ADD ", sep); |
---|
| 829 | } |
---|
| 830 | sep->se_checked = 1; |
---|
| 831 | |
---|
| 832 | switch (sep->se_family) { |
---|
| 833 | case AF_UNIX: |
---|
| 834 | if (sep->se_fd != -1) |
---|
| 835 | break; |
---|
| 836 | n = strlen(sep->se_service); |
---|
| 837 | if (n > sizeof(sep->se_ctrladdr_un.sun_path)) { |
---|
| 838 | syslog(LOG_ERR, "%s: address too long", |
---|
| 839 | sep->se_service); |
---|
| 840 | sep->se_checked = 0; |
---|
| 841 | continue; |
---|
| 842 | } |
---|
| 843 | (void)unlink(sep->se_service); |
---|
| 844 | strncpy(sep->se_ctrladdr_un.sun_path, |
---|
| 845 | sep->se_service, n); |
---|
| 846 | sep->se_ctrladdr_un.sun_family = AF_UNIX; |
---|
| 847 | sep->se_ctrladdr_size = n + |
---|
| 848 | sizeof(sep->se_ctrladdr_un) - |
---|
| 849 | sizeof(sep->se_ctrladdr_un.sun_path); |
---|
[13559] | 850 | if (!ISMUX(sep) && (!sep->se_switched || access_on)) |
---|
[11719] | 851 | setup(sep); |
---|
| 852 | break; |
---|
| 853 | case AF_INET: |
---|
| 854 | sep->se_ctrladdr_in.sin_family = AF_INET; |
---|
| 855 | if (!strcmp(sep->se_hostaddr,"*")) |
---|
| 856 | sep->se_ctrladdr_in.sin_addr.s_addr = |
---|
| 857 | INADDR_ANY; |
---|
[11726] | 858 | else if ((sep->se_ctrladdr_in.sin_addr.s_addr = |
---|
| 859 | inet_addr(sep->se_hostaddr)) == -1) { |
---|
[11719] | 860 | /* Do we really want to support hostname lookups here? */ |
---|
| 861 | struct hostent *hp; |
---|
| 862 | hp = gethostbyname(sep->se_hostaddr); |
---|
| 863 | if (hp == 0) { |
---|
| 864 | syslog(LOG_ERR, "%s: unknown host", |
---|
| 865 | sep->se_hostaddr); |
---|
| 866 | sep->se_checked = 0; |
---|
| 867 | continue; |
---|
| 868 | } else if (hp->h_addrtype != AF_INET) { |
---|
| 869 | syslog(LOG_ERR, |
---|
| 870 | "%s: address isn't an Internet address", |
---|
| 871 | sep->se_hostaddr); |
---|
| 872 | sep->se_checked = 0; |
---|
| 873 | continue; |
---|
| 874 | } else if (hp->h_length != sizeof(struct in_addr)) { |
---|
| 875 | syslog(LOG_ERR, |
---|
| 876 | "%s: address size wrong (under DNS corruption attack?)", |
---|
| 877 | sep->se_hostaddr); |
---|
| 878 | sep->se_checked = 0; |
---|
| 879 | continue; |
---|
| 880 | } else { |
---|
| 881 | memcpy(&sep->se_ctrladdr_in.sin_addr, |
---|
| 882 | hp->h_addr_list[0], |
---|
| 883 | sizeof(struct in_addr)); |
---|
| 884 | } |
---|
| 885 | } |
---|
| 886 | if (ISMUX(sep)) { |
---|
| 887 | sep->se_fd = -1; |
---|
| 888 | continue; |
---|
| 889 | } |
---|
| 890 | sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr_in); |
---|
| 891 | if (isrpcservice(sep)) { |
---|
| 892 | struct rpcent *rp; |
---|
| 893 | |
---|
| 894 | sep->se_rpcprog = atoi(sep->se_service); |
---|
| 895 | if (sep->se_rpcprog == 0) { |
---|
| 896 | rp = getrpcbyname(sep->se_service); |
---|
| 897 | if (rp == 0) { |
---|
| 898 | syslog(LOG_ERR, |
---|
| 899 | "%s/%s: unknown service", |
---|
| 900 | sep->se_service, |
---|
| 901 | sep->se_proto); |
---|
| 902 | sep->se_checked = 0; |
---|
| 903 | continue; |
---|
| 904 | } |
---|
| 905 | sep->se_rpcprog = rp->r_number; |
---|
| 906 | } |
---|
[13559] | 907 | if (sep->se_fd == -1 && !ISMUX(sep) && |
---|
| 908 | (!sep->se_switched || access_on)) |
---|
[11719] | 909 | setup(sep); |
---|
| 910 | if (sep->se_fd != -1) |
---|
| 911 | register_rpc(sep); |
---|
| 912 | } else { |
---|
| 913 | u_short port = htons(atoi(sep->se_service)); |
---|
| 914 | |
---|
| 915 | if (!port) { |
---|
| 916 | sp = getservbyname(sep->se_service, |
---|
| 917 | sep->se_proto); |
---|
| 918 | if (sp == 0) { |
---|
| 919 | syslog(LOG_ERR, |
---|
| 920 | "%s/%s: unknown service", |
---|
| 921 | sep->se_service, |
---|
| 922 | sep->se_proto); |
---|
| 923 | sep->se_checked = 0; |
---|
| 924 | continue; |
---|
| 925 | } |
---|
| 926 | port = sp->s_port; |
---|
| 927 | } |
---|
| 928 | if (port != sep->se_ctrladdr_in.sin_port) { |
---|
| 929 | sep->se_ctrladdr_in.sin_port = port; |
---|
| 930 | if (sep->se_fd >= 0) |
---|
| 931 | close_sep(sep); |
---|
| 932 | } |
---|
[11726] | 933 | if (sep->se_fd == -1 && !ISMUX(sep) && |
---|
| 934 | (!sep->se_switched || access_on)) |
---|
[11719] | 935 | setup(sep); |
---|
| 936 | } |
---|
| 937 | } |
---|
| 938 | } |
---|
| 939 | endconfig(); |
---|
| 940 | /* |
---|
| 941 | * Purge anything not looked at above. |
---|
| 942 | */ |
---|
[11726] | 943 | sigprocmask(SIG_BLOCK, &sig_block, &omask); |
---|
[11719] | 944 | sepp = &servtab; |
---|
| 945 | while ((sep = *sepp)) { |
---|
| 946 | if (sep->se_checked) { |
---|
| 947 | sepp = &sep->se_next; |
---|
| 948 | continue; |
---|
| 949 | } |
---|
| 950 | *sepp = sep->se_next; |
---|
| 951 | if (sep->se_fd >= 0) |
---|
| 952 | close_sep(sep); |
---|
| 953 | if (isrpcservice(sep)) |
---|
| 954 | unregister_rpc(sep); |
---|
| 955 | if (sep->se_family == AF_UNIX) |
---|
| 956 | (void)unlink(sep->se_service); |
---|
| 957 | if (debug) |
---|
| 958 | print_service("FREE", sep); |
---|
| 959 | freeconfig(sep); |
---|
| 960 | free((char *)sep); |
---|
| 961 | } |
---|
[11726] | 962 | sigprocmask(SIG_SETMASK, &omask, NULL); |
---|
[11719] | 963 | } |
---|
| 964 | |
---|
| 965 | void |
---|
[11726] | 966 | access_switch(signo) |
---|
| 967 | int signo; |
---|
| 968 | { |
---|
| 969 | struct servtab *sep, **sepp; |
---|
| 970 | sigset_t omask; |
---|
| 971 | int on; |
---|
| 972 | |
---|
| 973 | on = signo == SIGUSR1; |
---|
| 974 | if (on == access_on) |
---|
| 975 | return; |
---|
| 976 | |
---|
| 977 | sigprocmask(SIG_BLOCK, &sig_block, &omask); |
---|
[13452] | 978 | access_on = on; |
---|
[11726] | 979 | sepp = &servtab; |
---|
| 980 | while (sep = *sepp) { |
---|
| 981 | sepp = &sep->se_next; |
---|
| 982 | if (!sep->se_switched) |
---|
| 983 | continue; |
---|
| 984 | if (access_on) |
---|
| 985 | setup(sep); |
---|
| 986 | else |
---|
| 987 | close_sep(sep); |
---|
| 988 | } |
---|
| 989 | sigprocmask(SIG_SETMASK, &omask, NULL); |
---|
| 990 | } |
---|
| 991 | |
---|
| 992 | void |
---|
[11719] | 993 | retry(signo) |
---|
| 994 | int signo; |
---|
| 995 | { |
---|
| 996 | struct servtab *sep; |
---|
| 997 | |
---|
| 998 | timingout = 0; |
---|
| 999 | for (sep = servtab; sep; sep = sep->se_next) { |
---|
[13559] | 1000 | if (sep->se_fd == -1 && !ISMUX(sep) && |
---|
| 1001 | (!sep->se_switched || access_on)) { |
---|
[11719] | 1002 | switch (sep->se_family) { |
---|
| 1003 | case AF_UNIX: |
---|
| 1004 | case AF_INET: |
---|
| 1005 | setup(sep); |
---|
| 1006 | if (sep->se_fd != -1 && isrpcservice(sep)) |
---|
| 1007 | register_rpc(sep); |
---|
| 1008 | break; |
---|
| 1009 | } |
---|
| 1010 | } |
---|
| 1011 | } |
---|
| 1012 | } |
---|
| 1013 | |
---|
| 1014 | void |
---|
| 1015 | goaway(signo) |
---|
| 1016 | int signo; |
---|
| 1017 | { |
---|
| 1018 | struct servtab *sep; |
---|
| 1019 | |
---|
| 1020 | for (sep = servtab; sep; sep = sep->se_next) { |
---|
| 1021 | if (sep->se_fd == -1) |
---|
| 1022 | continue; |
---|
| 1023 | |
---|
| 1024 | switch (sep->se_family) { |
---|
| 1025 | case AF_UNIX: |
---|
| 1026 | (void)unlink(sep->se_service); |
---|
| 1027 | break; |
---|
| 1028 | case AF_INET: |
---|
| 1029 | if (sep->se_wait == 1 && isrpcservice(sep)) |
---|
| 1030 | unregister_rpc(sep); |
---|
| 1031 | break; |
---|
| 1032 | } |
---|
| 1033 | (void)close(sep->se_fd); |
---|
| 1034 | } |
---|
| 1035 | (void)unlink(_PATH_INETDPID); |
---|
| 1036 | exit(0); |
---|
| 1037 | } |
---|
| 1038 | |
---|
| 1039 | void |
---|
| 1040 | setup(sep) |
---|
| 1041 | struct servtab *sep; |
---|
| 1042 | { |
---|
| 1043 | int on = 1; |
---|
| 1044 | |
---|
| 1045 | if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { |
---|
| 1046 | if (debug) |
---|
| 1047 | fprintf(stderr, "socket failed on %s/%s: %s\n", |
---|
| 1048 | sep->se_service, sep->se_proto, strerror(errno)); |
---|
| 1049 | syslog(LOG_ERR, "%s/%s: socket: %m", |
---|
| 1050 | sep->se_service, sep->se_proto); |
---|
| 1051 | return; |
---|
| 1052 | } |
---|
| 1053 | /* Set all listening sockets to close-on-exec. */ |
---|
| 1054 | if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) |
---|
| 1055 | syslog(LOG_ERR, "fcntl (F_SETFD, FD_CLOEXEC): %m"); |
---|
| 1056 | #define turnon(fd, opt) \ |
---|
| 1057 | setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) |
---|
| 1058 | if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && |
---|
| 1059 | turnon(sep->se_fd, SO_DEBUG) < 0) |
---|
| 1060 | syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); |
---|
| 1061 | if (turnon(sep->se_fd, SO_REUSEADDR) < 0) |
---|
| 1062 | syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); |
---|
| 1063 | #undef turnon |
---|
| 1064 | if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) { |
---|
| 1065 | if (debug) |
---|
| 1066 | fprintf(stderr, "bind failed on %s/%s: %s\n", |
---|
| 1067 | sep->se_service, sep->se_proto, strerror(errno)); |
---|
| 1068 | syslog(LOG_ERR, "%s/%s: bind: %m", |
---|
| 1069 | sep->se_service, sep->se_proto); |
---|
| 1070 | (void) close(sep->se_fd); |
---|
| 1071 | sep->se_fd = -1; |
---|
| 1072 | if (!timingout) { |
---|
| 1073 | timingout = 1; |
---|
| 1074 | alarm(RETRYTIME); |
---|
| 1075 | } |
---|
| 1076 | return; |
---|
| 1077 | } |
---|
| 1078 | if (sep->se_socktype == SOCK_STREAM) |
---|
| 1079 | listen(sep->se_fd, 10); |
---|
| 1080 | |
---|
| 1081 | FD_SET(sep->se_fd, &allsock); |
---|
| 1082 | nsock++; |
---|
| 1083 | if (sep->se_fd > maxsock) { |
---|
| 1084 | maxsock = sep->se_fd; |
---|
| 1085 | if (maxsock > rlim_ofile_cur - FD_MARGIN) |
---|
| 1086 | bump_nofile(); |
---|
| 1087 | } |
---|
| 1088 | if (debug) |
---|
| 1089 | fprintf(stderr, "registered %s on %d\n", |
---|
| 1090 | sep->se_server, sep->se_fd); |
---|
| 1091 | } |
---|
| 1092 | |
---|
| 1093 | /* |
---|
| 1094 | * Finish with a service and its socket. |
---|
| 1095 | */ |
---|
| 1096 | void |
---|
| 1097 | close_sep(sep) |
---|
| 1098 | struct servtab *sep; |
---|
| 1099 | { |
---|
| 1100 | if (sep->se_fd >= 0) { |
---|
| 1101 | nsock--; |
---|
| 1102 | FD_CLR(sep->se_fd, &allsock); |
---|
| 1103 | (void) close(sep->se_fd); |
---|
| 1104 | sep->se_fd = -1; |
---|
| 1105 | } |
---|
| 1106 | sep->se_count = 0; |
---|
| 1107 | /* |
---|
| 1108 | * Don't keep the pid of this running deamon: when reapchild() |
---|
| 1109 | * reaps this pid, it would erroneously increment nsock. |
---|
| 1110 | */ |
---|
| 1111 | if (sep->se_wait > 1) |
---|
| 1112 | sep->se_wait = 1; |
---|
| 1113 | } |
---|
| 1114 | |
---|
| 1115 | void |
---|
| 1116 | register_rpc(sep) |
---|
| 1117 | struct servtab *sep; |
---|
| 1118 | { |
---|
| 1119 | #ifdef RPC |
---|
| 1120 | int n; |
---|
| 1121 | struct sockaddr_in sin; |
---|
| 1122 | struct protoent *pp; |
---|
| 1123 | |
---|
| 1124 | if ((pp = getprotobyname(sep->se_proto+4)) == NULL) { |
---|
| 1125 | syslog(LOG_ERR, "%s: getproto: %m", |
---|
| 1126 | sep->se_proto); |
---|
| 1127 | return; |
---|
| 1128 | } |
---|
| 1129 | n = sizeof sin; |
---|
| 1130 | if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) { |
---|
| 1131 | syslog(LOG_ERR, "%s/%s: getsockname: %m", |
---|
| 1132 | sep->se_service, sep->se_proto); |
---|
| 1133 | return; |
---|
| 1134 | } |
---|
| 1135 | |
---|
| 1136 | for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { |
---|
| 1137 | if (debug) |
---|
| 1138 | fprintf(stderr, "pmap_set: %u %u %u %u\n", |
---|
| 1139 | sep->se_rpcprog, n, pp->p_proto, |
---|
| 1140 | ntohs(sin.sin_port)); |
---|
| 1141 | (void)pmap_unset(sep->se_rpcprog, n); |
---|
| 1142 | if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port))) |
---|
| 1143 | syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m", |
---|
| 1144 | sep->se_rpcprog, n, pp->p_proto, |
---|
| 1145 | ntohs(sin.sin_port)); |
---|
| 1146 | } |
---|
| 1147 | #endif /* RPC */ |
---|
| 1148 | } |
---|
| 1149 | |
---|
| 1150 | void |
---|
| 1151 | unregister_rpc(sep) |
---|
| 1152 | struct servtab *sep; |
---|
| 1153 | { |
---|
| 1154 | #ifdef RPC |
---|
| 1155 | int n; |
---|
| 1156 | |
---|
| 1157 | for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { |
---|
| 1158 | if (debug) |
---|
| 1159 | fprintf(stderr, "pmap_unset(%u, %u)\n", |
---|
| 1160 | sep->se_rpcprog, n); |
---|
| 1161 | if (!pmap_unset(sep->se_rpcprog, n)) |
---|
| 1162 | syslog(LOG_ERR, "pmap_unset(%u, %u)\n", |
---|
| 1163 | sep->se_rpcprog, n); |
---|
| 1164 | } |
---|
| 1165 | #endif /* RPC */ |
---|
| 1166 | } |
---|
| 1167 | |
---|
| 1168 | |
---|
| 1169 | struct servtab * |
---|
| 1170 | enter(cp) |
---|
| 1171 | struct servtab *cp; |
---|
| 1172 | { |
---|
| 1173 | struct servtab *sep; |
---|
[11726] | 1174 | sigset_t omask; |
---|
[11719] | 1175 | |
---|
| 1176 | sep = (struct servtab *)malloc(sizeof (*sep)); |
---|
| 1177 | if (sep == (struct servtab *)0) { |
---|
| 1178 | syslog(LOG_ERR, "Out of memory."); |
---|
| 1179 | exit(-1); |
---|
| 1180 | } |
---|
| 1181 | *sep = *cp; |
---|
| 1182 | sep->se_fd = -1; |
---|
| 1183 | sep->se_rpcprog = -1; |
---|
[11726] | 1184 | sigprocmask(SIG_BLOCK, &sig_block, &omask); |
---|
[11719] | 1185 | sep->se_next = servtab; |
---|
| 1186 | servtab = sep; |
---|
[11726] | 1187 | sigprocmask(SIG_SETMASK, &omask, NULL); |
---|
[11719] | 1188 | return (sep); |
---|
| 1189 | } |
---|
| 1190 | |
---|
| 1191 | FILE *fconfig = NULL; |
---|
| 1192 | struct servtab serv; |
---|
[11726] | 1193 | char line[BUFSIZ]; |
---|
[11719] | 1194 | char *defhost; |
---|
| 1195 | |
---|
| 1196 | int |
---|
| 1197 | setconfig() |
---|
| 1198 | { |
---|
| 1199 | if (defhost) free(defhost); |
---|
| 1200 | defhost = newstr("*"); |
---|
| 1201 | if (fconfig != NULL) { |
---|
| 1202 | fseek(fconfig, 0L, SEEK_SET); |
---|
| 1203 | return (1); |
---|
| 1204 | } |
---|
| 1205 | fconfig = fopen(CONFIG, "r"); |
---|
| 1206 | return (fconfig != NULL); |
---|
| 1207 | } |
---|
| 1208 | |
---|
| 1209 | void |
---|
| 1210 | endconfig() |
---|
| 1211 | { |
---|
| 1212 | if (fconfig) { |
---|
| 1213 | (void) fclose(fconfig); |
---|
| 1214 | fconfig = NULL; |
---|
| 1215 | } |
---|
| 1216 | if (defhost) { |
---|
| 1217 | free(defhost); |
---|
| 1218 | defhost = 0; |
---|
| 1219 | } |
---|
| 1220 | } |
---|
| 1221 | |
---|
| 1222 | struct servtab * |
---|
| 1223 | getconfigent() |
---|
| 1224 | { |
---|
| 1225 | struct servtab *sep = &serv; |
---|
| 1226 | int argc; |
---|
| 1227 | char *cp, *arg; |
---|
| 1228 | static char TCPMUX_TOKEN[] = "tcpmux/"; |
---|
| 1229 | #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) |
---|
| 1230 | char *hostdelim; |
---|
| 1231 | |
---|
| 1232 | more: |
---|
| 1233 | #ifdef MULOG |
---|
| 1234 | while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) { |
---|
| 1235 | /* Avoid use of `skip' if there is a danger of it looking |
---|
| 1236 | * at continuation lines. |
---|
| 1237 | */ |
---|
| 1238 | do { |
---|
| 1239 | cp++; |
---|
| 1240 | } while (*cp == ' ' || *cp == '\t'); |
---|
| 1241 | if (*cp == '\0') |
---|
| 1242 | continue; |
---|
| 1243 | if ((arg = skip(&cp)) == NULL) |
---|
| 1244 | continue; |
---|
| 1245 | if (strcmp(arg, "DOMAIN")) |
---|
| 1246 | continue; |
---|
| 1247 | if (curdom) |
---|
| 1248 | free(curdom); |
---|
| 1249 | curdom = NULL; |
---|
| 1250 | while (*cp == ' ' || *cp == '\t') |
---|
| 1251 | cp++; |
---|
| 1252 | if (*cp == '\0') |
---|
| 1253 | continue; |
---|
| 1254 | arg = cp; |
---|
| 1255 | while (*cp && *cp != ' ' && *cp != '\t') |
---|
| 1256 | cp++; |
---|
| 1257 | if (*cp != '\0') |
---|
| 1258 | *cp++ = '\0'; |
---|
| 1259 | curdom = newstr(arg); |
---|
| 1260 | } |
---|
| 1261 | #else |
---|
| 1262 | while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) |
---|
| 1263 | ; |
---|
| 1264 | #endif |
---|
| 1265 | if (cp == NULL) |
---|
| 1266 | return ((struct servtab *)0); |
---|
| 1267 | /* |
---|
| 1268 | * clear the static buffer, since some fields (se_ctrladdr, |
---|
| 1269 | * for example) don't get initialized here. |
---|
| 1270 | */ |
---|
| 1271 | memset((caddr_t)sep, 0, sizeof *sep); |
---|
| 1272 | arg = skip(&cp); |
---|
| 1273 | if (cp == NULL) { |
---|
| 1274 | /* got an empty line containing just blanks/tabs. */ |
---|
| 1275 | goto more; |
---|
| 1276 | } |
---|
| 1277 | /* Check for a host name. */ |
---|
| 1278 | hostdelim = strrchr(arg, ':'); |
---|
| 1279 | if (hostdelim) { |
---|
| 1280 | *hostdelim = '\0'; |
---|
| 1281 | sep->se_hostaddr = newstr(arg); |
---|
| 1282 | arg = hostdelim + 1; |
---|
| 1283 | /* |
---|
| 1284 | * If the line is of the form `host:', then just change the |
---|
| 1285 | * default host for the following lines. |
---|
| 1286 | */ |
---|
| 1287 | if (*arg == '\0') { |
---|
| 1288 | arg = skip(&cp); |
---|
| 1289 | if (cp == NULL) { |
---|
| 1290 | free(defhost); |
---|
| 1291 | defhost = sep->se_hostaddr; |
---|
| 1292 | goto more; |
---|
| 1293 | } |
---|
| 1294 | } |
---|
| 1295 | } else |
---|
| 1296 | sep->se_hostaddr = newstr(defhost); |
---|
| 1297 | if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { |
---|
| 1298 | char *c = arg + MUX_LEN; |
---|
| 1299 | if (*c == '+') { |
---|
| 1300 | sep->se_type = MUXPLUS_TYPE; |
---|
| 1301 | c++; |
---|
| 1302 | } else |
---|
| 1303 | sep->se_type = MUX_TYPE; |
---|
| 1304 | sep->se_service = newstr(c); |
---|
| 1305 | } else { |
---|
| 1306 | sep->se_service = newstr(arg); |
---|
| 1307 | sep->se_type = NORM_TYPE; |
---|
| 1308 | } |
---|
| 1309 | |
---|
| 1310 | arg = sskip(&cp); |
---|
| 1311 | if (strcmp(arg, "stream") == 0) |
---|
| 1312 | sep->se_socktype = SOCK_STREAM; |
---|
| 1313 | else if (strcmp(arg, "dgram") == 0) |
---|
| 1314 | sep->se_socktype = SOCK_DGRAM; |
---|
| 1315 | else if (strcmp(arg, "rdm") == 0) |
---|
| 1316 | sep->se_socktype = SOCK_RDM; |
---|
| 1317 | else if (strcmp(arg, "seqpacket") == 0) |
---|
| 1318 | sep->se_socktype = SOCK_SEQPACKET; |
---|
| 1319 | else if (strcmp(arg, "raw") == 0) |
---|
| 1320 | sep->se_socktype = SOCK_RAW; |
---|
| 1321 | else |
---|
| 1322 | sep->se_socktype = -1; |
---|
| 1323 | |
---|
| 1324 | sep->se_proto = newstr(sskip(&cp)); |
---|
| 1325 | if (strcmp(sep->se_proto, "unix") == 0) { |
---|
| 1326 | sep->se_family = AF_UNIX; |
---|
| 1327 | } else { |
---|
| 1328 | sep->se_family = AF_INET; |
---|
| 1329 | if (strncmp(sep->se_proto, "rpc/", 4) == 0) { |
---|
| 1330 | #ifdef RPC |
---|
| 1331 | char *cp, *ccp; |
---|
| 1332 | cp = strchr(sep->se_service, '/'); |
---|
| 1333 | if (cp == 0) { |
---|
| 1334 | syslog(LOG_ERR, "%s: no rpc version", |
---|
| 1335 | sep->se_service); |
---|
| 1336 | goto more; |
---|
| 1337 | } |
---|
| 1338 | *cp++ = '\0'; |
---|
| 1339 | sep->se_rpcversl = sep->se_rpcversh = |
---|
| 1340 | strtol(cp, &ccp, 0); |
---|
| 1341 | if (ccp == cp) { |
---|
| 1342 | badafterall: |
---|
| 1343 | syslog(LOG_ERR, "%s/%s: bad rpc version", |
---|
| 1344 | sep->se_service, cp); |
---|
| 1345 | goto more; |
---|
| 1346 | } |
---|
| 1347 | if (*ccp == '-') { |
---|
| 1348 | cp = ccp + 1; |
---|
| 1349 | sep->se_rpcversh = strtol(cp, &ccp, 0); |
---|
| 1350 | if (ccp == cp) |
---|
| 1351 | goto badafterall; |
---|
| 1352 | } |
---|
| 1353 | #else |
---|
| 1354 | syslog(LOG_ERR, "%s: rpc services not suported", |
---|
| 1355 | sep->se_service); |
---|
| 1356 | goto more; |
---|
| 1357 | #endif /* RPC */ |
---|
| 1358 | } |
---|
| 1359 | } |
---|
| 1360 | arg = sskip(&cp); |
---|
| 1361 | { |
---|
| 1362 | char *cp; |
---|
| 1363 | cp = strchr(arg, '.'); |
---|
| 1364 | if (cp) { |
---|
| 1365 | *cp++ = '\0'; |
---|
| 1366 | sep->se_max = atoi(cp); |
---|
| 1367 | } else |
---|
| 1368 | sep->se_max = TOOMANY; |
---|
| 1369 | } |
---|
| 1370 | sep->se_wait = strcmp(arg, "wait") == 0; |
---|
| 1371 | if (ISMUX(sep)) { |
---|
| 1372 | /* |
---|
| 1373 | * Silently enforce "nowait" for TCPMUX services since |
---|
| 1374 | * they don't have an assigned port to listen on. |
---|
| 1375 | */ |
---|
| 1376 | sep->se_wait = 0; |
---|
| 1377 | |
---|
| 1378 | if (strcmp(sep->se_proto, "tcp")) { |
---|
| 1379 | syslog(LOG_ERR, |
---|
| 1380 | "%s: bad protocol for tcpmux service %s", |
---|
| 1381 | CONFIG, sep->se_service); |
---|
| 1382 | goto more; |
---|
| 1383 | } |
---|
| 1384 | if (sep->se_socktype != SOCK_STREAM) { |
---|
| 1385 | syslog(LOG_ERR, |
---|
| 1386 | "%s: bad socket type for tcpmux service %s", |
---|
| 1387 | CONFIG, sep->se_service); |
---|
| 1388 | goto more; |
---|
| 1389 | } |
---|
| 1390 | } |
---|
[11726] | 1391 | arg = sskip(&cp); |
---|
| 1392 | sep->se_switched = strcmp(arg, "switched") == 0; |
---|
[11719] | 1393 | sep->se_user = newstr(sskip(&cp)); |
---|
| 1394 | if ((sep->se_group = strchr(sep->se_user, '.'))) |
---|
| 1395 | *sep->se_group++ = '\0'; |
---|
| 1396 | sep->se_server = newstr(sskip(&cp)); |
---|
| 1397 | if (strcmp(sep->se_server, "internal") == 0) { |
---|
| 1398 | struct biltin *bi; |
---|
| 1399 | |
---|
| 1400 | for (bi = biltins; bi->bi_service; bi++) |
---|
| 1401 | if (bi->bi_socktype == sep->se_socktype && |
---|
| 1402 | strcmp(bi->bi_service, sep->se_service) == 0) |
---|
| 1403 | break; |
---|
| 1404 | if (bi->bi_service == 0) { |
---|
| 1405 | syslog(LOG_ERR, "internal service %s unknown", |
---|
| 1406 | sep->se_service); |
---|
| 1407 | goto more; |
---|
| 1408 | } |
---|
| 1409 | sep->se_bi = bi; |
---|
| 1410 | sep->se_wait = bi->bi_wait; |
---|
| 1411 | } else |
---|
| 1412 | sep->se_bi = NULL; |
---|
| 1413 | argc = 0; |
---|
| 1414 | for (arg = skip(&cp); cp; arg = skip(&cp)) { |
---|
| 1415 | #if MULOG |
---|
| 1416 | char *colon; |
---|
| 1417 | |
---|
| 1418 | if (argc == 0 && (colon = strrchr(arg, ':'))) { |
---|
| 1419 | while (arg < colon) { |
---|
| 1420 | int x; |
---|
| 1421 | char *ccp; |
---|
| 1422 | |
---|
| 1423 | switch (*arg++) { |
---|
| 1424 | case 'l': |
---|
| 1425 | x = 1; |
---|
| 1426 | if (isdigit(*arg)) { |
---|
| 1427 | x = strtol(arg, &ccp, 0); |
---|
| 1428 | if (ccp == arg) |
---|
| 1429 | break; |
---|
| 1430 | arg = ccp; |
---|
| 1431 | } |
---|
| 1432 | sep->se_log &= ~MULOG_RFC931; |
---|
| 1433 | sep->se_log |= x; |
---|
| 1434 | break; |
---|
| 1435 | case 'a': |
---|
| 1436 | sep->se_log |= MULOG_RFC931; |
---|
| 1437 | break; |
---|
| 1438 | default: |
---|
| 1439 | break; |
---|
| 1440 | } |
---|
| 1441 | } |
---|
| 1442 | arg = colon + 1; |
---|
| 1443 | } |
---|
| 1444 | #endif |
---|
| 1445 | if (argc < MAXARGV) |
---|
| 1446 | sep->se_argv[argc++] = newstr(arg); |
---|
| 1447 | } |
---|
| 1448 | while (argc <= MAXARGV) |
---|
| 1449 | sep->se_argv[argc++] = NULL; |
---|
| 1450 | return (sep); |
---|
| 1451 | } |
---|
| 1452 | |
---|
| 1453 | void |
---|
| 1454 | freeconfig(cp) |
---|
| 1455 | struct servtab *cp; |
---|
| 1456 | { |
---|
| 1457 | int i; |
---|
| 1458 | |
---|
| 1459 | if (cp->se_hostaddr) |
---|
| 1460 | free(cp->se_hostaddr); |
---|
| 1461 | if (cp->se_service) |
---|
| 1462 | free(cp->se_service); |
---|
| 1463 | if (cp->se_proto) |
---|
| 1464 | free(cp->se_proto); |
---|
| 1465 | if (cp->se_user) |
---|
| 1466 | free(cp->se_user); |
---|
| 1467 | /* Note: se_group is part of the newstr'ed se_user */ |
---|
| 1468 | if (cp->se_server) |
---|
| 1469 | free(cp->se_server); |
---|
| 1470 | for (i = 0; i < MAXARGV; i++) |
---|
| 1471 | if (cp->se_argv[i]) |
---|
| 1472 | free(cp->se_argv[i]); |
---|
| 1473 | } |
---|
| 1474 | |
---|
| 1475 | |
---|
| 1476 | /* |
---|
| 1477 | * Safe skip - if skip returns null, log a syntax error in the |
---|
| 1478 | * configuration file and exit. |
---|
| 1479 | */ |
---|
| 1480 | char * |
---|
| 1481 | sskip(cpp) |
---|
| 1482 | char **cpp; |
---|
| 1483 | { |
---|
| 1484 | char *cp; |
---|
| 1485 | |
---|
| 1486 | cp = skip(cpp); |
---|
| 1487 | if (cp == NULL) { |
---|
| 1488 | syslog(LOG_ERR, "%s: syntax error", CONFIG); |
---|
| 1489 | exit(-1); |
---|
| 1490 | } |
---|
| 1491 | return (cp); |
---|
| 1492 | } |
---|
| 1493 | |
---|
| 1494 | char * |
---|
| 1495 | skip(cpp) |
---|
| 1496 | char **cpp; |
---|
| 1497 | { |
---|
| 1498 | char *cp = *cpp; |
---|
| 1499 | char *start; |
---|
| 1500 | |
---|
| 1501 | if (*cpp == NULL) |
---|
| 1502 | return ((char *)0); |
---|
| 1503 | |
---|
| 1504 | again: |
---|
| 1505 | while (*cp == ' ' || *cp == '\t') |
---|
| 1506 | cp++; |
---|
| 1507 | if (*cp == '\0') { |
---|
| 1508 | int c; |
---|
| 1509 | |
---|
| 1510 | c = getc(fconfig); |
---|
| 1511 | (void) ungetc(c, fconfig); |
---|
| 1512 | if (c == ' ' || c == '\t') |
---|
| 1513 | if ((cp = nextline(fconfig))) |
---|
| 1514 | goto again; |
---|
| 1515 | *cpp = (char *)0; |
---|
| 1516 | return ((char *)0); |
---|
| 1517 | } |
---|
| 1518 | start = cp; |
---|
| 1519 | while (*cp && *cp != ' ' && *cp != '\t') |
---|
| 1520 | cp++; |
---|
| 1521 | if (*cp != '\0') |
---|
| 1522 | *cp++ = '\0'; |
---|
| 1523 | *cpp = cp; |
---|
| 1524 | return (start); |
---|
| 1525 | } |
---|
| 1526 | |
---|
| 1527 | char * |
---|
| 1528 | nextline(fd) |
---|
| 1529 | FILE *fd; |
---|
| 1530 | { |
---|
| 1531 | char *cp; |
---|
| 1532 | |
---|
| 1533 | if (fgets(line, sizeof (line), fd) == NULL) |
---|
| 1534 | return ((char *)0); |
---|
| 1535 | cp = strchr(line, '\n'); |
---|
| 1536 | if (cp) |
---|
| 1537 | *cp = '\0'; |
---|
| 1538 | return (line); |
---|
| 1539 | } |
---|
| 1540 | |
---|
| 1541 | char * |
---|
| 1542 | newstr(cp) |
---|
| 1543 | char *cp; |
---|
| 1544 | { |
---|
| 1545 | if ((cp = strdup(cp ? cp : ""))) |
---|
| 1546 | return (cp); |
---|
| 1547 | syslog(LOG_ERR, "strdup: %m"); |
---|
| 1548 | exit(-1); |
---|
| 1549 | } |
---|
| 1550 | |
---|
| 1551 | void |
---|
| 1552 | inetd_setproctitle(a, s) |
---|
| 1553 | char *a; |
---|
| 1554 | int s; |
---|
| 1555 | { |
---|
| 1556 | int size; |
---|
| 1557 | char *cp; |
---|
| 1558 | struct sockaddr_in sin; |
---|
| 1559 | char buf[80]; |
---|
| 1560 | |
---|
| 1561 | cp = Argv[0]; |
---|
| 1562 | size = sizeof(sin); |
---|
| 1563 | if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) |
---|
[11726] | 1564 | (void)sprintf(buf, "-%.*s [%s]", sizeof(buf) - 20, a, |
---|
[11719] | 1565 | inet_ntoa(sin.sin_addr)); |
---|
| 1566 | else |
---|
[11726] | 1567 | (void)sprintf(buf, "-%.*s", sizeof(buf) - 2, a); |
---|
[11719] | 1568 | strncpy(cp, buf, LastArg - cp); |
---|
| 1569 | cp += strlen(cp); |
---|
| 1570 | while (cp < LastArg) |
---|
| 1571 | *cp++ = ' '; |
---|
| 1572 | } |
---|
| 1573 | |
---|
| 1574 | void |
---|
| 1575 | logpid() |
---|
| 1576 | { |
---|
| 1577 | FILE *fp; |
---|
| 1578 | |
---|
| 1579 | if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) { |
---|
| 1580 | fprintf(fp, "%u\n", getpid()); |
---|
| 1581 | (void)fclose(fp); |
---|
| 1582 | } |
---|
| 1583 | } |
---|
| 1584 | |
---|
| 1585 | void |
---|
| 1586 | bump_nofile() |
---|
| 1587 | { |
---|
| 1588 | #ifdef RLIMIT_NOFILE |
---|
| 1589 | |
---|
| 1590 | #define FD_CHUNK 32 |
---|
| 1591 | |
---|
| 1592 | struct rlimit rl; |
---|
| 1593 | |
---|
| 1594 | if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { |
---|
| 1595 | syslog(LOG_ERR, "getrlimit: %m"); |
---|
| 1596 | return; |
---|
| 1597 | } |
---|
[11726] | 1598 | #ifndef MIN |
---|
| 1599 | #define MIN(x,y) ( (x) < (y) ? (x) : (y) ) |
---|
| 1600 | #endif |
---|
[11719] | 1601 | rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK); |
---|
| 1602 | if (rl.rlim_cur <= rlim_ofile_cur) { |
---|
| 1603 | syslog(LOG_ERR, |
---|
| 1604 | "bump_nofile: cannot extend file limit, max = %d", |
---|
| 1605 | (int)rl.rlim_cur); |
---|
| 1606 | return; |
---|
| 1607 | } |
---|
| 1608 | |
---|
| 1609 | if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { |
---|
| 1610 | syslog(LOG_ERR, "setrlimit: %m"); |
---|
| 1611 | return; |
---|
| 1612 | } |
---|
| 1613 | |
---|
| 1614 | rlim_ofile_cur = rl.rlim_cur; |
---|
| 1615 | return; |
---|
| 1616 | |
---|
| 1617 | #else |
---|
| 1618 | syslog(LOG_ERR, "bump_nofile: cannot extend file limit"); |
---|
| 1619 | return; |
---|
| 1620 | #endif |
---|
| 1621 | } |
---|
| 1622 | |
---|
| 1623 | /* |
---|
| 1624 | * Internet services provided internally by inetd: |
---|
| 1625 | */ |
---|
| 1626 | #define BUFSIZE 4096 |
---|
| 1627 | |
---|
| 1628 | /* ARGSUSED */ |
---|
| 1629 | void |
---|
| 1630 | echo_stream(s, sep) /* Echo service -- echo data back */ |
---|
| 1631 | int s; |
---|
| 1632 | struct servtab *sep; |
---|
| 1633 | { |
---|
| 1634 | char buffer[BUFSIZE]; |
---|
| 1635 | int i; |
---|
| 1636 | |
---|
| 1637 | inetd_setproctitle(sep->se_service, s); |
---|
| 1638 | while ((i = read(s, buffer, sizeof(buffer))) > 0 && |
---|
| 1639 | write(s, buffer, i) > 0) |
---|
| 1640 | ; |
---|
| 1641 | } |
---|
| 1642 | |
---|
| 1643 | /* ARGSUSED */ |
---|
| 1644 | void |
---|
| 1645 | echo_dg(s, sep) /* Echo service -- echo data back */ |
---|
| 1646 | int s; |
---|
| 1647 | struct servtab *sep; |
---|
| 1648 | { |
---|
| 1649 | char buffer[BUFSIZE]; |
---|
| 1650 | int i, size; |
---|
| 1651 | struct sockaddr sa; |
---|
| 1652 | |
---|
| 1653 | size = sizeof(sa); |
---|
| 1654 | if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) |
---|
| 1655 | return; |
---|
| 1656 | (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); |
---|
| 1657 | } |
---|
| 1658 | |
---|
| 1659 | /* ARGSUSED */ |
---|
| 1660 | void |
---|
| 1661 | discard_stream(s, sep) /* Discard service -- ignore data */ |
---|
| 1662 | int s; |
---|
| 1663 | struct servtab *sep; |
---|
| 1664 | { |
---|
| 1665 | char buffer[BUFSIZE]; |
---|
| 1666 | |
---|
| 1667 | inetd_setproctitle(sep->se_service, s); |
---|
| 1668 | while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) || |
---|
| 1669 | errno == EINTR) |
---|
| 1670 | ; |
---|
| 1671 | } |
---|
| 1672 | |
---|
| 1673 | /* ARGSUSED */ |
---|
| 1674 | void |
---|
| 1675 | discard_dg(s, sep) /* Discard service -- ignore data */ |
---|
| 1676 | int s; |
---|
| 1677 | struct servtab *sep; |
---|
| 1678 | { |
---|
| 1679 | char buffer[BUFSIZE]; |
---|
| 1680 | |
---|
| 1681 | (void) read(s, buffer, sizeof(buffer)); |
---|
| 1682 | } |
---|
| 1683 | |
---|
| 1684 | #include <ctype.h> |
---|
| 1685 | #define LINESIZ 72 |
---|
| 1686 | char ring[128]; |
---|
| 1687 | char *endring; |
---|
| 1688 | |
---|
| 1689 | void |
---|
| 1690 | initring() |
---|
| 1691 | { |
---|
| 1692 | int i; |
---|
| 1693 | |
---|
| 1694 | endring = ring; |
---|
| 1695 | |
---|
| 1696 | for (i = 0; i <= 128; ++i) |
---|
| 1697 | if (isprint(i)) |
---|
| 1698 | *endring++ = i; |
---|
| 1699 | } |
---|
| 1700 | |
---|
| 1701 | /* ARGSUSED */ |
---|
| 1702 | void |
---|
| 1703 | chargen_stream(s, sep) /* Character generator */ |
---|
| 1704 | int s; |
---|
| 1705 | struct servtab *sep; |
---|
| 1706 | { |
---|
| 1707 | int len; |
---|
| 1708 | char *rs, text[LINESIZ+2]; |
---|
| 1709 | |
---|
| 1710 | inetd_setproctitle(sep->se_service, s); |
---|
| 1711 | |
---|
| 1712 | if (!endring) { |
---|
| 1713 | initring(); |
---|
| 1714 | rs = ring; |
---|
| 1715 | } |
---|
| 1716 | |
---|
| 1717 | text[LINESIZ] = '\r'; |
---|
| 1718 | text[LINESIZ + 1] = '\n'; |
---|
| 1719 | for (rs = ring;;) { |
---|
| 1720 | if ((len = endring - rs) >= LINESIZ) |
---|
| 1721 | memmove(text, rs, LINESIZ); |
---|
| 1722 | else { |
---|
| 1723 | memmove(text, rs, len); |
---|
| 1724 | memmove(text + len, ring, LINESIZ - len); |
---|
| 1725 | } |
---|
| 1726 | if (++rs == endring) |
---|
| 1727 | rs = ring; |
---|
| 1728 | if (write(s, text, sizeof(text)) != sizeof(text)) |
---|
| 1729 | break; |
---|
| 1730 | } |
---|
| 1731 | } |
---|
| 1732 | |
---|
| 1733 | /* ARGSUSED */ |
---|
| 1734 | void |
---|
| 1735 | chargen_dg(s, sep) /* Character generator */ |
---|
| 1736 | int s; |
---|
| 1737 | struct servtab *sep; |
---|
| 1738 | { |
---|
| 1739 | struct sockaddr sa; |
---|
| 1740 | static char *rs; |
---|
| 1741 | int len, size; |
---|
| 1742 | char text[LINESIZ+2]; |
---|
| 1743 | |
---|
| 1744 | if (endring == 0) { |
---|
| 1745 | initring(); |
---|
| 1746 | rs = ring; |
---|
| 1747 | } |
---|
| 1748 | |
---|
| 1749 | size = sizeof(sa); |
---|
| 1750 | if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) |
---|
| 1751 | return; |
---|
| 1752 | |
---|
| 1753 | if ((len = endring - rs) >= LINESIZ) |
---|
| 1754 | memmove(text, rs, LINESIZ); |
---|
| 1755 | else { |
---|
| 1756 | memmove(text, rs, len); |
---|
| 1757 | memmove(text + len, ring, LINESIZ - len); |
---|
| 1758 | } |
---|
| 1759 | if (++rs == endring) |
---|
| 1760 | rs = ring; |
---|
| 1761 | text[LINESIZ] = '\r'; |
---|
| 1762 | text[LINESIZ + 1] = '\n'; |
---|
| 1763 | (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); |
---|
| 1764 | } |
---|
| 1765 | |
---|
| 1766 | /* |
---|
| 1767 | * Return a machine readable date and time, in the form of the |
---|
| 1768 | * number of seconds since midnight, Jan 1, 1900. Since gettimeofday |
---|
| 1769 | * returns the number of seconds since midnight, Jan 1, 1970, |
---|
| 1770 | * we must add 2208988800 seconds to this figure to make up for |
---|
| 1771 | * some seventy years Bell Labs was asleep. |
---|
| 1772 | */ |
---|
| 1773 | |
---|
| 1774 | long |
---|
| 1775 | machtime() |
---|
| 1776 | { |
---|
| 1777 | struct timeval tv; |
---|
| 1778 | |
---|
| 1779 | if (gettimeofday(&tv, (struct timezone *)0) < 0) { |
---|
| 1780 | if (debug) |
---|
| 1781 | fprintf(stderr, "Unable to get time of day\n"); |
---|
| 1782 | return (0L); |
---|
| 1783 | } |
---|
| 1784 | #define OFFSET ((u_long)25567 * 24*60*60) |
---|
| 1785 | return (htonl((long)(tv.tv_sec + OFFSET))); |
---|
| 1786 | #undef OFFSET |
---|
| 1787 | } |
---|
| 1788 | |
---|
| 1789 | /* ARGSUSED */ |
---|
| 1790 | void |
---|
| 1791 | machtime_stream(s, sep) |
---|
| 1792 | int s; |
---|
| 1793 | struct servtab *sep; |
---|
| 1794 | { |
---|
| 1795 | long result; |
---|
| 1796 | |
---|
| 1797 | result = machtime(); |
---|
| 1798 | (void) write(s, (char *) &result, sizeof(result)); |
---|
| 1799 | } |
---|
| 1800 | |
---|
| 1801 | /* ARGSUSED */ |
---|
| 1802 | void |
---|
| 1803 | machtime_dg(s, sep) |
---|
| 1804 | int s; |
---|
| 1805 | struct servtab *sep; |
---|
| 1806 | { |
---|
| 1807 | long result; |
---|
| 1808 | struct sockaddr sa; |
---|
| 1809 | int size; |
---|
| 1810 | |
---|
| 1811 | size = sizeof(sa); |
---|
| 1812 | if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) |
---|
| 1813 | return; |
---|
| 1814 | result = machtime(); |
---|
| 1815 | (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); |
---|
| 1816 | } |
---|
| 1817 | |
---|
| 1818 | /* ARGSUSED */ |
---|
| 1819 | void |
---|
| 1820 | daytime_stream(s, sep) /* Return human-readable time of day */ |
---|
| 1821 | int s; |
---|
| 1822 | struct servtab *sep; |
---|
| 1823 | { |
---|
| 1824 | char buffer[256]; |
---|
| 1825 | time_t clock; |
---|
| 1826 | int len; |
---|
| 1827 | |
---|
| 1828 | clock = time((time_t *) 0); |
---|
| 1829 | |
---|
[11726] | 1830 | len = sprintf(buffer, "%.24s\r\n", ctime(&clock)); |
---|
[11719] | 1831 | (void) write(s, buffer, len); |
---|
| 1832 | } |
---|
| 1833 | |
---|
| 1834 | /* ARGSUSED */ |
---|
| 1835 | void |
---|
| 1836 | daytime_dg(s, sep) /* Return human-readable time of day */ |
---|
| 1837 | int s; |
---|
| 1838 | struct servtab *sep; |
---|
| 1839 | { |
---|
| 1840 | char buffer[256]; |
---|
| 1841 | time_t clock; |
---|
| 1842 | struct sockaddr sa; |
---|
| 1843 | int size, len; |
---|
| 1844 | |
---|
| 1845 | clock = time((time_t *) 0); |
---|
| 1846 | |
---|
| 1847 | size = sizeof(sa); |
---|
| 1848 | if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) |
---|
| 1849 | return; |
---|
[11726] | 1850 | len = sprintf(buffer, "%.24s\r\n", ctime(&clock)); |
---|
[11719] | 1851 | (void) sendto(s, buffer, len, 0, &sa, sizeof(sa)); |
---|
| 1852 | } |
---|
| 1853 | |
---|
| 1854 | /* |
---|
| 1855 | * print_service: |
---|
| 1856 | * Dump relevant information to stderr |
---|
| 1857 | */ |
---|
| 1858 | void |
---|
| 1859 | print_service(action, sep) |
---|
| 1860 | char *action; |
---|
| 1861 | struct servtab *sep; |
---|
| 1862 | { |
---|
| 1863 | if (isrpcservice(sep)) |
---|
| 1864 | fprintf(stderr, |
---|
[11726] | 1865 | "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, switched=%d, user.group=%s.%s builtin=%lx server=%s\n", |
---|
[11719] | 1866 | action, sep->se_service, |
---|
| 1867 | sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto, |
---|
[11726] | 1868 | sep->se_wait, sep->se_max, sep->se_switched, sep->se_user, |
---|
| 1869 | sep->se_group ? sep->se_group : "", |
---|
[11719] | 1870 | (long)sep->se_bi, sep->se_server); |
---|
| 1871 | else |
---|
| 1872 | fprintf(stderr, |
---|
[11726] | 1873 | "%s: %s proto=%s, wait.max=%d.%d, switched=%d, user.group=%s.%s builtin=%lx server=%s\n", |
---|
[11719] | 1874 | action, sep->se_service, sep->se_proto, |
---|
[11726] | 1875 | sep->se_wait, sep->se_max, sep->se_switched, sep->se_user, |
---|
| 1876 | sep->se_group ? sep->se_group : "", |
---|
[11719] | 1877 | (long)sep->se_bi, sep->se_server); |
---|
| 1878 | } |
---|
| 1879 | |
---|
| 1880 | void |
---|
| 1881 | usage() |
---|
| 1882 | { |
---|
| 1883 | |
---|
| 1884 | #ifdef LIBWRAP |
---|
| 1885 | (void)fprintf(stderr, "usage: %s [-dl] [conf]\n", __progname); |
---|
| 1886 | #else |
---|
| 1887 | (void)fprintf(stderr, "usage: %s [-d] [conf]\n", __progname); |
---|
| 1888 | #endif |
---|
| 1889 | exit(1); |
---|
| 1890 | } |
---|
| 1891 | |
---|
| 1892 | |
---|
| 1893 | /* |
---|
| 1894 | * Based on TCPMUX.C by Mark K. Lottor November 1988 |
---|
| 1895 | * sri-nic::ps:<mkl>tcpmux.c |
---|
| 1896 | */ |
---|
| 1897 | |
---|
| 1898 | static int /* # of characters upto \r,\n or \0 */ |
---|
| 1899 | getline(fd, buf, len) |
---|
| 1900 | int fd; |
---|
| 1901 | char *buf; |
---|
| 1902 | int len; |
---|
| 1903 | { |
---|
| 1904 | int count = 0, n; |
---|
| 1905 | |
---|
| 1906 | do { |
---|
| 1907 | n = read(fd, buf, len-count); |
---|
| 1908 | if (n == 0) |
---|
| 1909 | return (count); |
---|
| 1910 | if (n < 0) |
---|
| 1911 | return (-1); |
---|
| 1912 | while (--n >= 0) { |
---|
| 1913 | if (*buf == '\r' || *buf == '\n' || *buf == '\0') |
---|
| 1914 | return (count); |
---|
| 1915 | count++; |
---|
| 1916 | buf++; |
---|
| 1917 | } |
---|
| 1918 | } while (count < len); |
---|
| 1919 | return (count); |
---|
| 1920 | } |
---|
| 1921 | |
---|
| 1922 | #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ |
---|
| 1923 | |
---|
| 1924 | #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) |
---|
| 1925 | |
---|
| 1926 | void |
---|
| 1927 | tcpmux(ctrl, sep) |
---|
| 1928 | int ctrl; |
---|
| 1929 | struct servtab *sep; |
---|
| 1930 | { |
---|
| 1931 | char service[MAX_SERV_LEN+1]; |
---|
| 1932 | int len; |
---|
| 1933 | |
---|
| 1934 | /* Get requested service name */ |
---|
| 1935 | if ((len = getline(ctrl, service, MAX_SERV_LEN)) < 0) { |
---|
| 1936 | strwrite(ctrl, "-Error reading service name\r\n"); |
---|
| 1937 | goto reject; |
---|
| 1938 | } |
---|
| 1939 | service[len] = '\0'; |
---|
| 1940 | |
---|
| 1941 | if (debug) |
---|
| 1942 | fprintf(stderr, "tcpmux: someone wants %s\n", service); |
---|
| 1943 | |
---|
| 1944 | /* |
---|
| 1945 | * Help is a required command, and lists available services, |
---|
| 1946 | * one per line. |
---|
| 1947 | */ |
---|
| 1948 | if (!strcasecmp(service, "help")) { |
---|
| 1949 | strwrite(ctrl, "+Available services:\r\n"); |
---|
| 1950 | strwrite(ctrl, "help\r\n"); |
---|
| 1951 | for (sep = servtab; sep; sep = sep->se_next) { |
---|
| 1952 | if (!ISMUX(sep)) |
---|
| 1953 | continue; |
---|
| 1954 | (void)write(ctrl, sep->se_service, |
---|
| 1955 | strlen(sep->se_service)); |
---|
| 1956 | strwrite(ctrl, "\r\n"); |
---|
| 1957 | } |
---|
| 1958 | goto reject; |
---|
| 1959 | } |
---|
| 1960 | |
---|
| 1961 | /* Try matching a service in inetd.conf with the request */ |
---|
| 1962 | for (sep = servtab; sep; sep = sep->se_next) { |
---|
| 1963 | if (!ISMUX(sep)) |
---|
| 1964 | continue; |
---|
| 1965 | if (!strcasecmp(service, sep->se_service)) { |
---|
| 1966 | if (ISMUXPLUS(sep)) |
---|
| 1967 | strwrite(ctrl, "+Go\r\n"); |
---|
| 1968 | run_service(ctrl, sep); |
---|
| 1969 | return; |
---|
| 1970 | } |
---|
| 1971 | } |
---|
| 1972 | strwrite(ctrl, "-Service not available\r\n"); |
---|
| 1973 | reject: |
---|
| 1974 | _exit(1); |
---|
| 1975 | } |
---|
| 1976 | |
---|
| 1977 | |
---|
| 1978 | #ifdef MULOG |
---|
| 1979 | dolog(sep, ctrl) |
---|
| 1980 | struct servtab *sep; |
---|
| 1981 | int ctrl; |
---|
| 1982 | { |
---|
| 1983 | struct sockaddr sa; |
---|
| 1984 | struct sockaddr_in *sin = (struct sockaddr_in *)&sa; |
---|
| 1985 | int len = sizeof(sa); |
---|
| 1986 | struct hostent *hp; |
---|
| 1987 | char *host, *dp, buf[BUFSIZ], *rfc931_name(); |
---|
| 1988 | int connected = 1; |
---|
| 1989 | |
---|
| 1990 | if (sep->se_family != AF_INET) |
---|
| 1991 | return; |
---|
| 1992 | |
---|
| 1993 | if (getpeername(ctrl, &sa, &len) < 0) { |
---|
| 1994 | if (errno != ENOTCONN) { |
---|
| 1995 | syslog(LOG_ERR, "getpeername: %m"); |
---|
| 1996 | return; |
---|
| 1997 | } |
---|
| 1998 | if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) { |
---|
| 1999 | syslog(LOG_ERR, "recvfrom: %m"); |
---|
| 2000 | return; |
---|
| 2001 | } |
---|
| 2002 | connected = 0; |
---|
| 2003 | } |
---|
| 2004 | if (sa.sa_family != AF_INET) { |
---|
| 2005 | syslog(LOG_ERR, "unexpected address family %u", sa.sa_family); |
---|
| 2006 | return; |
---|
| 2007 | } |
---|
| 2008 | |
---|
| 2009 | hp = gethostbyaddr((char *) &sin->sin_addr.s_addr, |
---|
| 2010 | sizeof (sin->sin_addr.s_addr), AF_INET); |
---|
| 2011 | |
---|
| 2012 | host = hp?hp->h_name:inet_ntoa(sin->sin_addr); |
---|
| 2013 | |
---|
| 2014 | switch (sep->se_log & ~MULOG_RFC931) { |
---|
| 2015 | case 0: |
---|
| 2016 | return; |
---|
| 2017 | case 1: |
---|
| 2018 | if (curdom == NULL || *curdom == '\0') |
---|
| 2019 | break; |
---|
| 2020 | dp = host + strlen(host) - strlen(curdom); |
---|
| 2021 | if (dp < host) |
---|
| 2022 | break; |
---|
| 2023 | if (debug) |
---|
| 2024 | fprintf(stderr, "check \"%s\" against curdom \"%s\"\n", |
---|
| 2025 | host, curdom); |
---|
| 2026 | if (strcasecmp(dp, curdom) == 0) |
---|
| 2027 | return; |
---|
| 2028 | break; |
---|
| 2029 | case 2: |
---|
| 2030 | default: |
---|
| 2031 | break; |
---|
| 2032 | } |
---|
| 2033 | |
---|
| 2034 | openlog("", LOG_NOWAIT, MULOG); |
---|
| 2035 | |
---|
| 2036 | if (connected && (sep->se_log & MULOG_RFC931)) |
---|
| 2037 | syslog(LOG_INFO, "%s@%s wants %s", |
---|
| 2038 | rfc931_name(sin, ctrl), host, sep->se_service); |
---|
| 2039 | else |
---|
| 2040 | syslog(LOG_INFO, "%s wants %s", |
---|
| 2041 | host, sep->se_service); |
---|
| 2042 | } |
---|
| 2043 | |
---|
| 2044 | /* |
---|
| 2045 | * From tcp_log by |
---|
| 2046 | * Wietse Venema, Eindhoven University of Technology, The Netherlands. |
---|
| 2047 | */ |
---|
| 2048 | #if 0 |
---|
| 2049 | static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46"; |
---|
| 2050 | #endif |
---|
| 2051 | |
---|
| 2052 | #include <setjmp.h> |
---|
| 2053 | |
---|
| 2054 | #define RFC931_PORT 113 /* Semi-well-known port */ |
---|
| 2055 | #define TIMEOUT 4 |
---|
| 2056 | #define TIMEOUT2 10 |
---|
| 2057 | |
---|
[11726] | 2058 | static sigjmp_buf timebuf; |
---|
[11719] | 2059 | |
---|
| 2060 | /* timeout - handle timeouts */ |
---|
| 2061 | |
---|
| 2062 | static void timeout(sig) |
---|
| 2063 | int sig; |
---|
| 2064 | { |
---|
[11726] | 2065 | siglongjmp(timebuf, sig); |
---|
[11719] | 2066 | } |
---|
| 2067 | |
---|
| 2068 | /* rfc931_name - return remote user name */ |
---|
| 2069 | |
---|
| 2070 | char * |
---|
| 2071 | rfc931_name(there, ctrl) |
---|
| 2072 | struct sockaddr_in *there; /* remote link information */ |
---|
| 2073 | int ctrl; |
---|
| 2074 | { |
---|
| 2075 | struct sockaddr_in here; /* local link information */ |
---|
| 2076 | struct sockaddr_in sin; /* for talking to RFC931 daemon */ |
---|
| 2077 | int length; |
---|
| 2078 | int s; |
---|
| 2079 | unsigned remote; |
---|
| 2080 | unsigned local; |
---|
| 2081 | static char user[256]; /* XXX */ |
---|
| 2082 | char buf[256]; |
---|
| 2083 | char *cp; |
---|
| 2084 | char *result = "USER_UNKNOWN"; |
---|
| 2085 | int len; |
---|
[11726] | 2086 | struct sigaction sa; |
---|
[11719] | 2087 | |
---|
| 2088 | /* Find out local port number of our stdin. */ |
---|
| 2089 | |
---|
| 2090 | length = sizeof(here); |
---|
| 2091 | if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) { |
---|
| 2092 | syslog(LOG_ERR, "getsockname: %m"); |
---|
| 2093 | return (result); |
---|
| 2094 | } |
---|
| 2095 | /* Set up timer so we won't get stuck. */ |
---|
| 2096 | |
---|
| 2097 | if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { |
---|
| 2098 | syslog(LOG_ERR, "socket: %m"); |
---|
| 2099 | return (result); |
---|
| 2100 | } |
---|
| 2101 | |
---|
| 2102 | sin = here; |
---|
| 2103 | sin.sin_port = htons(0); |
---|
| 2104 | if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) { |
---|
| 2105 | syslog(LOG_ERR, "bind: %m"); |
---|
| 2106 | return (result); |
---|
| 2107 | } |
---|
| 2108 | |
---|
[11726] | 2109 | memset(&sa, 0, sizeof(sa)); |
---|
| 2110 | sa_handler = timeout; |
---|
| 2111 | sigaction(SIGALRM, &sa, NULL); |
---|
| 2112 | if (sigsetjmp(timebuf)) { |
---|
[11719] | 2113 | close(s); /* not: fclose(fp) */ |
---|
| 2114 | return (result); |
---|
| 2115 | } |
---|
| 2116 | alarm(TIMEOUT); |
---|
| 2117 | |
---|
| 2118 | /* Connect to the RFC931 daemon. */ |
---|
| 2119 | |
---|
| 2120 | sin = *there; |
---|
| 2121 | sin.sin_port = htons(RFC931_PORT); |
---|
| 2122 | if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) { |
---|
| 2123 | close(s); |
---|
| 2124 | alarm(0); |
---|
| 2125 | return (result); |
---|
| 2126 | } |
---|
| 2127 | |
---|
| 2128 | /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */ |
---|
[11726] | 2129 | (void)sprintf(buf, "%u,%u\r\n", ntohs(there->sin_port), |
---|
[11719] | 2130 | ntohs(here.sin_port)); |
---|
| 2131 | |
---|
| 2132 | |
---|
| 2133 | for (len = 0, cp = buf; len < strlen(buf); ) { |
---|
| 2134 | int n; |
---|
| 2135 | |
---|
| 2136 | if ((n = write(s, cp, strlen(buf) - len)) == -1) { |
---|
| 2137 | close(s); |
---|
| 2138 | alarm(0); |
---|
| 2139 | return (result); |
---|
| 2140 | } |
---|
| 2141 | cp += n; |
---|
| 2142 | len += n; |
---|
| 2143 | } |
---|
| 2144 | |
---|
| 2145 | /* Read response */ |
---|
| 2146 | for (cp = buf; cp < buf + sizeof(buf) - 1; ) { |
---|
| 2147 | char c; |
---|
| 2148 | if (read(s, &c, 1) != 1) { |
---|
| 2149 | close(s); |
---|
| 2150 | alarm(0); |
---|
| 2151 | return (result); |
---|
| 2152 | } |
---|
| 2153 | if (c == '\n') |
---|
| 2154 | break; |
---|
| 2155 | *cp++ = c; |
---|
| 2156 | } |
---|
| 2157 | *cp = '\0'; |
---|
| 2158 | |
---|
| 2159 | if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3 |
---|
| 2160 | && ntohs(there->sin_port) == remote |
---|
| 2161 | && ntohs(here.sin_port) == local) { |
---|
| 2162 | |
---|
| 2163 | /* Strip trailing carriage return. */ |
---|
| 2164 | if (cp = strchr(user, '\r')) |
---|
| 2165 | *cp = 0; |
---|
| 2166 | result = user; |
---|
| 2167 | } |
---|
| 2168 | |
---|
| 2169 | alarm(0); |
---|
| 2170 | close(s); |
---|
| 2171 | return (result); |
---|
| 2172 | } |
---|
| 2173 | #endif |
---|