Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/networking/inetd.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/networking/inetd.c
r821 r1770 1 /* vi: set sw=4 ts=4: */ 1 2 /* $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $ */ 2 3 /* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */ … … 23 24 * without specific prior written permission. 24 25 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''AND26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND 26 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE … … 36 37 */ 37 38 38 /* 39 * Inetd - Internet super-server 39 /* Inetd - Internet super-server 40 40 * 41 41 * This program invokes all internet services as needed. … … 50 50 * on file descriptor 0. Datagram servers may either connect 51 51 * to their peer, freeing up the original socket for inetd 52 * to receive further messages on, or ``take over the socket'',52 * to receive further messages on, or "take over the socket", 53 53 * processing all arriving datagrams and, eventually, timing 54 * out. The first type of server is said to be ``multi-threaded'';55 * the second type of server ``single-threaded''.54 * out. The first type of server is said to be "multi-threaded"; 55 * the second type of server "single-threaded". 56 56 * 57 57 * Inetd uses a configuration file which is read at startup 58 58 * and, possibly, at some later time in response to a hangup signal. 59 * The configuration file is ``free format''with fields given in the59 * The configuration file is "free format" with fields given in the 60 60 * order shown below. Continuation lines for an entry must begin with 61 61 * a space or tab. All fields must be present in each entry. … … 105 105 */ 106 106 107 /* 108 * Here's the scoop concerning the user[.:]group feature: 107 /* inetd rules for passing file descriptors to children 108 * (http://www.freebsd.org/cgi/man.cgi?query=inetd): 109 * 110 * The wait/nowait entry specifies whether the server that is invoked by 111 * inetd will take over the socket associated with the service access point, 112 * and thus whether inetd should wait for the server to exit before listen- 113 * ing for new service requests. Datagram servers must use "wait", as 114 * they are always invoked with the original datagram socket bound to the 115 * specified service address. These servers must read at least one datagram 116 * from the socket before exiting. If a datagram server connects to its 117 * peer, freeing the socket so inetd can receive further messages on the 118 * socket, it is said to be a "multi-threaded" server; it should read one 119 * datagram from the socket and create a new socket connected to the peer. 120 * It should fork, and the parent should then exit to allow inetd to check 121 * for new service requests to spawn new servers. Datagram servers which 122 * process all incoming datagrams on a socket and eventually time out are 123 * said to be "single-threaded". The comsat(8), (biff(1)) and talkd(8) 124 * utilities are both examples of the latter type of datagram server. The 125 * tftpd(8) utility is an example of a multi-threaded datagram server. 126 * 127 * Servers using stream sockets generally are multi-threaded and use the 128 * "nowait" entry. Connection requests for these services are accepted by 129 * inetd, and the server is given only the newly-accepted socket connected 130 * to a client of the service. Most stream-based services operate in this 131 * manner. Stream-based servers that use "wait" are started with the lis- 132 * tening service socket, and must accept at least one connection request 133 * before exiting. Such a server would normally accept and process incoming 134 * connection requests until a timeout. 135 */ 136 137 /* Here's the scoop concerning the user[.:]group feature: 109 138 * 110 139 * 1) set-group-option off. … … 125 154 * initgroups(name, specified group) 126 155 * setuid() 127 *128 156 */ 129 157 130 #include <sys/param.h> 131 #include <sys/stat.h> 132 #include <sys/ioctl.h> 133 #include <sys/socket.h> 158 #include "libbb.h" 159 #include <syslog.h> 134 160 #include <sys/un.h> 135 #include <sys/file.h> 136 #include <sys/wait.h> 137 #include <sys/resource.h> 138 139 140 #include <netinet/in.h> 141 #include <arpa/inet.h> 142 143 #include <errno.h> 144 #include <signal.h> 145 #include <netdb.h> 146 #include <syslog.h> 147 #include <stdio.h> 148 #include <stdlib.h> 149 #include <unistd.h> 150 #include <string.h> 151 #include <ctype.h> 152 #include <time.h> 153 154 #include "busybox.h" 155 156 //#define CONFIG_FEATURE_INETD_RPC 157 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 158 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 159 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME 160 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 161 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 162 //#define CONFIG_FEATURE_IPV6 163 164 #ifdef CONFIG_FEATURE_INETD_RPC 161 162 //#define ENABLE_FEATURE_INETD_RPC 1 163 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1 164 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1 165 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1 166 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1 167 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1 168 //#define ENABLE_FEATURE_IPV6 1 169 170 #if ENABLE_FEATURE_INETD_RPC 165 171 #include <rpc/rpc.h> 166 172 #include <rpc/pmap_clnt.h> 167 173 #endif 168 174 169 #define _PATH_INETDCONF "/etc/inetd.conf" 175 extern char **environ; 176 177 170 178 #define _PATH_INETDPID "/var/run/inetd.pid" 171 172 173 #define TOOMANY 0 /* don't start more than TOOMANY */174 179 175 180 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ … … 185 190 186 191 /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */ 187 #define FD_MARGIN (8)192 #define FD_MARGIN 8 188 193 static rlim_t rlim_ofile_cur = OPEN_MAX; 189 194 static struct rlimit rlim_ofile; … … 191 196 192 197 /* Check unsupporting builtin */ 193 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \194 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \195 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \196 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \197 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN198 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \ 199 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \ 200 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \ 201 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \ 202 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 198 203 # define INETD_FEATURE_ENABLED 199 204 #endif 200 205 201 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \202 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \203 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN206 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \ 207 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \ 208 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 204 209 # define INETD_SETPROCTITLE 205 210 #endif 206 211 207 typedef struct servtab 208 { 209 char *se_hostaddr; /* host address to listen on */ 210 char *se_service; /* name of service */ 211 int se_socktype; /* type of socket to use */ 212 int se_family; /* address family */ 213 char *se_proto; /* protocol used */ 214 #ifdef CONFIG_FEATURE_INETD_RPC 215 int se_rpcprog; /* rpc program number */ 216 int se_rpcversl; /* rpc program lowest version */ 217 int se_rpcversh; /* rpc program highest version */ 212 typedef struct servtab { 213 char *se_hostaddr; /* host address to listen on */ 214 char *se_service; /* name of service */ 215 int se_socktype; /* type of socket to use */ 216 int se_family; /* address family */ 217 char *se_proto; /* protocol used */ 218 #if ENABLE_FEATURE_INETD_RPC 219 int se_rpcprog; /* rpc program number */ 220 int se_rpcversl; /* rpc program lowest version */ 221 int se_rpcversh; /* rpc program highest version */ 218 222 #define isrpcservice(sep) ((sep)->se_rpcversl != 0) 219 223 #else 220 224 #define isrpcservice(sep) 0 221 225 #endif 222 223 224 225 226 pid_t se_wait; /* single threaded server */ 227 short se_checked; /* looked at during merge */ 228 char *se_user; /* user name to run as */ 229 char *se_group; /* group name to run as */ 226 230 #ifdef INETD_FEATURE_ENABLED 227 const struct builtin *se_bi;/* if built-in, description */228 #endif 229 231 const struct builtin *se_bi; /* if built-in, description */ 232 #endif 233 char *se_server; /* server program */ 230 234 #define MAXARGV 20 231 char *se_argv[MAXARGV + 1]; /* program arguments */ 232 int se_fd; /* open descriptor */ 233 union 234 { 235 struct sockaddr se_un_ctrladdr; 236 struct sockaddr_in se_un_ctrladdr_in; 237 #ifdef CONFIG_FEATURE_IPV6 238 struct sockaddr_in6 se_un_ctrladdr_in6; 239 #endif 240 struct sockaddr_un se_un_ctrladdr_un; 241 } se_un; /* bound address */ 235 char *se_argv[MAXARGV + 1]; /* program arguments */ 236 int se_fd; /* open descriptor */ 237 union { 238 struct sockaddr se_un_ctrladdr; 239 struct sockaddr_in se_un_ctrladdr_in; 240 #if ENABLE_FEATURE_IPV6 241 struct sockaddr_in6 se_un_ctrladdr_in6; 242 #endif 243 struct sockaddr_un se_un_ctrladdr_un; 244 } se_un; /* bound address */ 242 245 #define se_ctrladdr se_un.se_un_ctrladdr 243 246 #define se_ctrladdr_in se_un.se_un_ctrladdr_in 244 247 #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6 245 248 #define se_ctrladdr_un se_un.se_un_ctrladdr_un 246 247 248 249 250 249 int se_ctrladdr_size; 250 int se_max; /* max # of instances of this service */ 251 int se_count; /* number started since se_time */ 252 struct timeval se_time; /* start of se_count */ 253 struct servtab *se_next; 251 254 } servtab_t; 252 255 … … 254 257 255 258 #ifdef INETD_FEATURE_ENABLED 256 struct builtin 257 { 258 const char *bi_service; /* internally provided service name */ 259 int bi_socktype; /* type of socket supported */ 260 short bi_fork; /* 1 if should fork before call */ 261 short bi_wait; /* 1 if should wait for child */ 262 void (*bi_fn) (int, servtab_t *); 259 struct builtin { 260 const char *bi_service; /* internally provided service name */ 261 int bi_socktype; /* type of socket supported */ 262 short bi_fork; /* 1 if should fork before call */ 263 short bi_wait; /* 1 if should wait for child */ 264 void (*bi_fn) (int, servtab_t *); 263 265 }; 264 266 267 /* Echo received data */ 268 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 269 static void echo_stream(int, servtab_t *); 270 static void echo_dg(int, servtab_t *); 271 #endif 272 /* Internet /dev/null */ 273 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 274 static void discard_stream(int, servtab_t *); 275 static void discard_dg(int, servtab_t *); 276 #endif 277 /* Return 32 bit time since 1900 */ 278 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 279 static void machtime_stream(int, servtab_t *); 280 static void machtime_dg(int, servtab_t *); 281 #endif 282 /* Return human-readable time */ 283 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 284 static void daytime_stream(int, servtab_t *); 285 static void daytime_dg(int, servtab_t *); 286 #endif 287 /* Familiar character generator */ 288 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 289 static void chargen_stream(int, servtab_t *); 290 static void chargen_dg(int, servtab_t *); 291 #endif 292 293 static const struct builtin builtins[] = { 294 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 265 295 /* Echo received data */ 266 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 267 static void echo_stream (int, servtab_t *); 268 static void echo_dg (int, servtab_t *); 269 # endif296 {"echo", SOCK_STREAM, 1, 0, echo_stream,}, 297 {"echo", SOCK_DGRAM, 0, 0, echo_dg,}, 298 #endif 299 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 270 300 /* Internet /dev/null */ 271 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 272 static void discard_stream (int, servtab_t *); 273 static void discard_dg (int, servtab_t *); 274 # endif301 {"discard", SOCK_STREAM, 1, 0, discard_stream,}, 302 {"discard", SOCK_DGRAM, 0, 0, discard_dg,}, 303 #endif 304 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 275 305 /* Return 32 bit time since 1900 */ 276 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME 277 static void machtime_stream (int, servtab_t *); 278 static void machtime_dg (int, servtab_t *); 279 # endif306 {"time", SOCK_STREAM, 0, 0, machtime_stream,}, 307 {"time", SOCK_DGRAM, 0, 0, machtime_dg,}, 308 #endif 309 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 280 310 /* Return human-readable time */ 281 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 282 static void daytime_stream (int, servtab_t *); 283 static void daytime_dg (int, servtab_t *); 284 # endif311 {"daytime", SOCK_STREAM, 0, 0, daytime_stream,}, 312 {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,}, 313 #endif 314 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 285 315 /* Familiar character generator */ 286 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 287 static void chargen_stream (int, servtab_t *); 288 static void chargen_dg (int, servtab_t *); 289 #endif 290 291 static const struct builtin builtins[] = { 292 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 293 /* Echo received data */ 294 {"echo", SOCK_STREAM, 1, 0, echo_stream,}, 295 {"echo", SOCK_DGRAM, 0, 0, echo_dg,}, 296 #endif 297 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 298 /* Internet /dev/null */ 299 {"discard", SOCK_STREAM, 1, 0, discard_stream,}, 300 {"discard", SOCK_DGRAM, 0, 0, discard_dg,}, 301 #endif 302 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME 303 /* Return 32 bit time since 1900 */ 304 {"time", SOCK_STREAM, 0, 0, machtime_stream,}, 305 {"time", SOCK_DGRAM, 0, 0, machtime_dg,}, 306 #endif 307 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 308 /* Return human-readable time */ 309 {"daytime", SOCK_STREAM, 0, 0, daytime_stream,}, 310 {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,}, 311 #endif 312 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 313 /* Familiar character generator */ 314 {"chargen", SOCK_STREAM, 1, 0, chargen_stream,}, 315 {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,}, 316 #endif 317 {NULL, 0, 0, 0, NULL} 316 {"chargen", SOCK_STREAM, 1, 0, chargen_stream,}, 317 {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,}, 318 #endif 319 {NULL, 0, 0, 0, NULL} 318 320 }; 319 321 #endif /* INETD_FEATURE_ENABLED */ … … 322 324 static int nsock, maxsock; 323 325 static fd_set allsock; 324 static int toomany = TOOMANY;326 static int toomany; 325 327 static int timingout; 326 328 static struct servent *sp; 327 329 static uid_t uid; 328 330 329 static c har *CONFIG = _PATH_INETDCONF;331 static const char *config_filename = "/etc/inetd.conf"; 330 332 331 333 static FILE *fconfig; 332 static char line[1024];333 334 static char *defhost; 334 335 335 static char *newstr (char *cp) 336 { 337 if ((cp = strdup (cp ? cp : ""))) 338 return (cp); 339 syslog (LOG_ERR, "strdup: %m"); 340 exit (1); 341 } 342 343 static int setconfig (void) 344 { 345 free (defhost); 346 defhost = newstr ("*"); 347 if (fconfig != NULL) { 348 fseek (fconfig, 0L, SEEK_SET); 349 return (1); 350 } 351 fconfig = fopen (CONFIG, "r"); 352 return (fconfig != NULL); 353 } 354 355 static void endconfig (void) 356 { 357 if (fconfig) { 358 (void) fclose (fconfig); 359 fconfig = NULL; 360 } 361 free (defhost); 362 defhost = 0; 363 } 364 365 #ifdef CONFIG_FEATURE_INETD_RPC 366 static void register_rpc (servtab_t *sep) 367 { 368 int n; 369 struct sockaddr_in ir_sin; 370 struct protoent *pp; 371 socklen_t size; 372 373 if ((pp = getprotobyname (sep->se_proto + 4)) == NULL) { 374 syslog (LOG_ERR, "%s: getproto: %m", sep->se_proto); 375 return; 376 } 377 size = sizeof ir_sin; 378 if (getsockname (sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) { 379 syslog (LOG_ERR, "%s/%s: getsockname: %m", 380 sep->se_service, sep->se_proto); 381 return; 382 } 383 384 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { 385 (void) pmap_unset (sep->se_rpcprog, n); 386 if (!pmap_set (sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port))) 387 syslog (LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m", 388 sep->se_service, sep->se_proto, 389 sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port)); 390 } 391 } 392 393 static void unregister_rpc (servtab_t *sep) 394 { 395 int n; 396 397 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { 398 if (!pmap_unset (sep->se_rpcprog, n)) 399 syslog (LOG_ERR, "pmap_unset(%u, %u)", sep->se_rpcprog, n); 400 } 401 } 402 #endif /* CONFIG_FEATURE_INETD_RPC */ 403 404 static void freeconfig (servtab_t *cp) 405 { 406 int i; 407 408 free (cp->se_hostaddr); 409 free (cp->se_service); 410 free (cp->se_proto); 411 free (cp->se_user); 412 free (cp->se_group); 413 free (cp->se_server); 414 for (i = 0; i < MAXARGV; i++) 415 free (cp->se_argv[i]); 416 } 417 418 static int bump_nofile (void) 336 /* xstrdup(NULL) returns NULL, but this one 337 * will return newly-allocated "" if called with NULL arg 338 * TODO: audit whether this makes any real difference 339 */ 340 static char *xxstrdup(char *cp) 341 { 342 return xstrdup(cp ? cp : ""); 343 } 344 345 static int setconfig(void) 346 { 347 free(defhost); 348 defhost = xstrdup("*"); 349 if (fconfig != NULL) { 350 fseek(fconfig, 0L, SEEK_SET); 351 return 1; 352 } 353 fconfig = fopen(config_filename, "r"); 354 return (fconfig != NULL); 355 } 356 357 static void endconfig(void) 358 { 359 if (fconfig) { 360 (void) fclose(fconfig); 361 fconfig = NULL; 362 } 363 free(defhost); 364 defhost = 0; 365 } 366 367 #if ENABLE_FEATURE_INETD_RPC 368 static void register_rpc(servtab_t *sep) 369 { 370 int n; 371 struct sockaddr_in ir_sin; 372 struct protoent *pp; 373 socklen_t size; 374 375 if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) { 376 bb_perror_msg("%s: getproto", sep->se_proto); 377 return; 378 } 379 size = sizeof ir_sin; 380 if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) { 381 bb_perror_msg("%s/%s: getsockname", 382 sep->se_service, sep->se_proto); 383 return; 384 } 385 386 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { 387 (void) pmap_unset(sep->se_rpcprog, n); 388 if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port))) 389 bb_perror_msg("%s %s: pmap_set: %u %u %u %u", 390 sep->se_service, sep->se_proto, 391 sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port)); 392 } 393 } 394 395 static void unregister_rpc(servtab_t *sep) 396 { 397 int n; 398 399 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { 400 if (!pmap_unset(sep->se_rpcprog, n)) 401 bb_error_msg("pmap_unset(%u, %u)", sep->se_rpcprog, n); 402 } 403 } 404 #endif /* FEATURE_INETD_RPC */ 405 406 static void freeconfig(servtab_t *cp) 407 { 408 int i; 409 410 free(cp->se_hostaddr); 411 free(cp->se_service); 412 free(cp->se_proto); 413 free(cp->se_user); 414 free(cp->se_group); 415 free(cp->se_server); 416 for (i = 0; i < MAXARGV; i++) 417 free(cp->se_argv[i]); 418 } 419 420 static int bump_nofile(void) 419 421 { 420 422 #define FD_CHUNK 32 421 423 422 struct rlimit rl; 423 424 if (getrlimit (RLIMIT_NOFILE, &rl) < 0) { 425 syslog (LOG_ERR, "getrlimit: %m"); 426 return -1; 427 } 428 rl.rlim_cur = MIN (rl.rlim_max, rl.rlim_cur + FD_CHUNK); 429 rl.rlim_cur = MIN (FD_SETSIZE, rl.rlim_cur + FD_CHUNK); 430 if (rl.rlim_cur <= rlim_ofile_cur) { 431 syslog (LOG_ERR, "bump_nofile: cannot extend file limit, max = %d", 432 (int) rl.rlim_cur); 433 return -1; 434 } 435 436 if (setrlimit (RLIMIT_NOFILE, &rl) < 0) { 437 syslog (LOG_ERR, "setrlimit: %m"); 438 return -1; 439 } 440 441 rlim_ofile_cur = rl.rlim_cur; 442 return 0; 443 } 444 445 static void setup (servtab_t *sep) 446 { 447 int on = 1; 448 int r; 449 450 if ((sep->se_fd = socket (sep->se_family, sep->se_socktype, 0)) < 0) { 451 syslog (LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto); 452 return; 453 } 454 #define turnon(fd, opt) \ 455 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 456 if (turnon (sep->se_fd, SO_REUSEADDR) < 0) 457 syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 458 #undef turnon 459 460 #ifdef CONFIG_FEATURE_INETD_RPC 461 if (isrpcservice (sep)) { 462 struct passwd *pwd; 424 struct rlimit rl; 425 426 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { 427 bb_perror_msg("getrlimit"); 428 return -1; 429 } 430 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK); 431 rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK); 432 if (rl.rlim_cur <= rlim_ofile_cur) { 433 bb_error_msg("bump_nofile: cannot extend file limit, max = %d", 434 (int) rl.rlim_cur); 435 return -1; 436 } 437 438 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { 439 bb_perror_msg("setrlimit"); 440 return -1; 441 } 442 443 rlim_ofile_cur = rl.rlim_cur; 444 return 0; 445 } 446 447 static void setup(servtab_t *sep) 448 { 449 int r; 450 451 sep->se_fd = socket(sep->se_family, sep->se_socktype, 0); 452 if (sep->se_fd < 0) { 453 bb_perror_msg("%s/%s: socket", sep->se_service, sep->se_proto); 454 return; 455 } 456 setsockopt_reuseaddr(sep->se_fd); 457 458 #if ENABLE_FEATURE_INETD_RPC 459 if (isrpcservice(sep)) { 460 struct passwd *pwd; 461 462 /* 463 * for RPC services, attempt to use a reserved port 464 * if they are going to be running as root. 465 * 466 * Also, zero out the port for all RPC services; let bind() 467 * find one. 468 */ 469 sep->se_ctrladdr_in.sin_port = 0; 470 if (sep->se_user && (pwd = getpwnam(sep->se_user)) && 471 pwd->pw_uid == 0 && uid == 0) 472 r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in); 473 else { 474 r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); 475 if (r == 0) { 476 socklen_t len = sep->se_ctrladdr_size; 477 int saveerrno = errno; 478 479 /* update se_ctrladdr_in.sin_port */ 480 r = getsockname(sep->se_fd, &sep->se_ctrladdr, &len); 481 if (r <= 0) 482 errno = saveerrno; 483 } 484 } 485 } else 486 #endif 487 r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); 488 if (r < 0) { 489 bb_perror_msg("%s/%s (%d): bind", 490 sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family); 491 close(sep->se_fd); 492 sep->se_fd = -1; 493 if (!timingout) { 494 timingout = 1; 495 alarm(RETRYTIME); 496 } 497 return; 498 } 499 if (sep->se_socktype == SOCK_STREAM) 500 listen(sep->se_fd, global_queuelen); 501 502 FD_SET(sep->se_fd, &allsock); 503 nsock++; 504 if (sep->se_fd > maxsock) { 505 maxsock = sep->se_fd; 506 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) 507 bump_nofile(); 508 } 509 } 510 511 static char *nextline(void) 512 { 513 #define line bb_common_bufsiz1 514 515 char *cp; 516 FILE *fd = fconfig; 517 518 if (fgets(line, sizeof(line), fd) == NULL) 519 return NULL; 520 cp = strchr(line, '\n'); 521 if (cp) 522 *cp = '\0'; 523 return line; 524 } 525 526 static char *skip(char **cpp) /* int report; */ 527 { 528 char *cp = *cpp; 529 char *start; 530 531 /* erp: */ 532 if (*cpp == NULL) { 533 /* if (report) */ 534 /* bb_error_msg("syntax error in inetd config file"); */ 535 return NULL; 536 } 537 538 again: 539 while (*cp == ' ' || *cp == '\t') 540 cp++; 541 if (*cp == '\0') { 542 int c; 543 544 c = getc(fconfig); 545 ungetc(c, fconfig); 546 if (c == ' ' || c == '\t') { 547 cp = nextline(); 548 if (cp) 549 goto again; 550 } 551 *cpp = NULL; 552 /* goto erp; */ 553 return NULL; 554 } 555 start = cp; 556 while (*cp && *cp != ' ' && *cp != '\t') 557 cp++; 558 if (*cp != '\0') 559 *cp++ = '\0'; 560 /* if ((*cpp = cp) == NULL) */ 561 /* goto erp; */ 562 563 *cpp = cp; 564 return start; 565 } 566 567 static servtab_t *new_servtab(void) 568 { 569 return xmalloc(sizeof(servtab_t)); 570 } 571 572 static servtab_t *dupconfig(servtab_t *sep) 573 { 574 servtab_t *newtab; 575 int argc; 576 577 newtab = new_servtab(); 578 memset(newtab, 0, sizeof(servtab_t)); 579 newtab->se_service = xstrdup(sep->se_service); 580 newtab->se_socktype = sep->se_socktype; 581 newtab->se_family = sep->se_family; 582 newtab->se_proto = xstrdup(sep->se_proto); 583 #if ENABLE_FEATURE_INETD_RPC 584 newtab->se_rpcprog = sep->se_rpcprog; 585 newtab->se_rpcversl = sep->se_rpcversl; 586 newtab->se_rpcversh = sep->se_rpcversh; 587 #endif 588 newtab->se_wait = sep->se_wait; 589 newtab->se_user = xstrdup(sep->se_user); 590 newtab->se_group = xstrdup(sep->se_group); 591 #ifdef INETD_FEATURE_ENABLED 592 newtab->se_bi = sep->se_bi; 593 #endif 594 newtab->se_server = xstrdup(sep->se_server); 595 596 for (argc = 0; argc <= MAXARGV; argc++) 597 newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]); 598 newtab->se_max = sep->se_max; 599 600 return newtab; 601 } 602 603 static servtab_t *getconfigent(void) 604 { 605 servtab_t *sep; 606 int argc; 607 char *cp, *arg; 608 char *hostdelim; 609 servtab_t *nsep; 610 servtab_t *psep; 611 612 sep = new_servtab(); 613 614 /* memset(sep, 0, sizeof *sep); */ 615 more: 616 /* freeconfig(sep); */ 617 618 while ((cp = nextline()) && *cp == '#') /* skip comment line */; 619 if (cp == NULL) { 620 /* free(sep); */ 621 return NULL; 622 } 623 624 memset((char *) sep, 0, sizeof *sep); 625 arg = skip(&cp); 626 if (arg == NULL) { 627 /* A blank line. */ 628 goto more; 629 } 630 631 /* Check for a host name. */ 632 hostdelim = strrchr(arg, ':'); 633 if (hostdelim) { 634 *hostdelim = '\0'; 635 sep->se_hostaddr = xstrdup(arg); 636 arg = hostdelim + 1; 637 /* 638 * If the line is of the form `host:', then just change the 639 * default host for the following lines. 640 */ 641 if (*arg == '\0') { 642 arg = skip(&cp); 643 if (cp == NULL) { 644 free(defhost); 645 defhost = sep->se_hostaddr; 646 goto more; 647 } 648 } 649 } else 650 sep->se_hostaddr = xxstrdup(defhost); 651 652 sep->se_service = xxstrdup(arg); 653 arg = skip(&cp); 654 655 if (strcmp(arg, "stream") == 0) 656 sep->se_socktype = SOCK_STREAM; 657 else if (strcmp(arg, "dgram") == 0) 658 sep->se_socktype = SOCK_DGRAM; 659 else if (strcmp(arg, "rdm") == 0) 660 sep->se_socktype = SOCK_RDM; 661 else if (strcmp(arg, "seqpacket") == 0) 662 sep->se_socktype = SOCK_SEQPACKET; 663 else if (strcmp(arg, "raw") == 0) 664 sep->se_socktype = SOCK_RAW; 665 else 666 sep->se_socktype = -1; 667 668 sep->se_proto = xxstrdup(skip(&cp)); 669 670 if (strcmp(sep->se_proto, "unix") == 0) { 671 sep->se_family = AF_UNIX; 672 } else { 673 sep->se_family = AF_INET; 674 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') 675 #if ENABLE_FEATURE_IPV6 676 sep->se_family = AF_INET6; 677 #else 678 bb_error_msg("%s: IPV6 not supported", sep->se_proto); 679 #endif 680 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 681 #if ENABLE_FEATURE_INETD_RPC 682 char *p, *ccp; 683 long l; 684 685 p = strchr(sep->se_service, '/'); 686 if (p == 0) { 687 bb_error_msg("%s: no rpc version", sep->se_service); 688 goto more; 689 } 690 *p++ = '\0'; 691 l = strtol(p, &ccp, 0); 692 if (ccp == p || l < 0 || l > INT_MAX) { 693 badafterall: 694 bb_error_msg("%s/%s: bad rpc version", sep->se_service, p); 695 goto more; 696 } 697 sep->se_rpcversl = sep->se_rpcversh = l; 698 if (*ccp == '-') { 699 p = ccp + 1; 700 l = strtol(p, &ccp, 0); 701 if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp) 702 goto badafterall; 703 sep->se_rpcversh = l; 704 } else if (*ccp != '\0') 705 goto badafterall; 706 #else 707 bb_error_msg("%s: rpc services not supported", sep->se_service); 708 #endif 709 } 710 } 711 arg = skip(&cp); 712 if (arg == NULL) 713 goto more; 714 715 { 716 char *s = strchr(arg, '.'); 717 if (s) { 718 *s++ = '\0'; 719 sep->se_max = xatoi(s); 720 } else 721 sep->se_max = toomany; 722 } 723 sep->se_wait = strcmp(arg, "wait") == 0; 724 /* if ((arg = skip(&cp, 1)) == NULL) */ 725 /* goto more; */ 726 sep->se_user = xxstrdup(skip(&cp)); 727 arg = strchr(sep->se_user, '.'); 728 if (arg == NULL) 729 arg = strchr(sep->se_user, ':'); 730 if (arg) { 731 *arg++ = '\0'; 732 sep->se_group = xstrdup(arg); 733 } 734 /* if ((arg = skip(&cp, 1)) == NULL) */ 735 /* goto more; */ 736 737 sep->se_server = xxstrdup(skip(&cp)); 738 if (strcmp(sep->se_server, "internal") == 0) { 739 #ifdef INETD_FEATURE_ENABLED 740 const struct builtin *bi; 741 742 for (bi = builtins; bi->bi_service; bi++) 743 if (bi->bi_socktype == sep->se_socktype && 744 strcmp(bi->bi_service, sep->se_service) == 0) 745 break; 746 if (bi->bi_service == 0) { 747 bb_error_msg("internal service %s unknown", sep->se_service); 748 goto more; 749 } 750 sep->se_bi = bi; 751 sep->se_wait = bi->bi_wait; 752 #else 753 bb_perror_msg("internal service %s unknown", sep->se_service); 754 goto more; 755 #endif 756 } 757 #ifdef INETD_FEATURE_ENABLED 758 else 759 sep->se_bi = NULL; 760 #endif 761 argc = 0; 762 for (arg = skip(&cp); cp; arg = skip(&cp)) { 763 if (argc < MAXARGV) 764 sep->se_argv[argc++] = xxstrdup(arg); 765 } 766 while (argc <= MAXARGV) 767 sep->se_argv[argc++] = NULL; 463 768 464 769 /* 465 * for RPC services, attempt to use a reserved port 466 * if they are going to be running as root. 467 * 468 * Also, zero out the port for all RPC services; let bind() 469 * find one. 770 * Now that we've processed the entire line, check if the hostname 771 * specifier was a comma separated list of hostnames. If so 772 * we'll make new entries for each address. 470 773 */ 471 sep->se_ctrladdr_in.sin_port = 0; 472 if (sep->se_user && (pwd = getpwnam (sep->se_user)) && 473 pwd->pw_uid == 0 && uid == 0) 474 r = bindresvport (sep->se_fd, &sep->se_ctrladdr_in); 475 else { 476 r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); 477 if (r == 0) { 478 socklen_t len = sep->se_ctrladdr_size; 479 int saveerrno = errno; 480 481 /* update se_ctrladdr_in.sin_port */ 482 r = getsockname (sep->se_fd, &sep->se_ctrladdr, &len); 483 if (r <= 0) 484 errno = saveerrno; 485 } 486 } 487 } else 488 #endif 489 r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); 490 if (r < 0) { 491 syslog (LOG_ERR, "%s/%s (%d): bind: %m", 492 sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family); 493 close (sep->se_fd); 774 while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) { 775 nsep = dupconfig(sep); 776 777 /* 778 * NULL terminate the hostname field of the existing entry, 779 * and make a dup for the new entry. 780 */ 781 *hostdelim++ = '\0'; 782 nsep->se_hostaddr = xstrdup(hostdelim); 783 784 nsep->se_next = sep->se_next; 785 sep->se_next = nsep; 786 } 787 788 nsep = sep; 789 while (nsep != NULL) { 790 nsep->se_checked = 1; 791 if (nsep->se_family == AF_INET) { 792 if (LONE_CHAR(nsep->se_hostaddr, '*')) 793 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY; 794 else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) { 795 struct hostent *hp; 796 797 hp = gethostbyname(nsep->se_hostaddr); 798 if (hp == 0) { 799 bb_error_msg("%s: unknown host", nsep->se_hostaddr); 800 nsep->se_checked = 0; 801 goto skip; 802 } else if (hp->h_addrtype != AF_INET) { 803 bb_error_msg("%s: address isn't an Internet " 804 "address", nsep->se_hostaddr); 805 nsep->se_checked = 0; 806 goto skip; 807 } else { 808 int i = 1; 809 810 memmove(&nsep->se_ctrladdr_in.sin_addr, 811 hp->h_addr_list[0], sizeof(struct in_addr)); 812 while (hp->h_addr_list[i] != NULL) { 813 psep = dupconfig(nsep); 814 psep->se_hostaddr = xxstrdup(nsep->se_hostaddr); 815 psep->se_checked = 1; 816 memmove(&psep->se_ctrladdr_in.sin_addr, 817 hp->h_addr_list[i], sizeof(struct in_addr)); 818 psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in); 819 i++; 820 /* Prepend to list, don't want to look up */ 821 /* its hostname again. */ 822 psep->se_next = sep; 823 sep = psep; 824 } 825 } 826 } 827 } 828 /* XXX BUG?: is this skip: label supposed to remain? */ 829 skip: 830 nsep = nsep->se_next; 831 } 832 833 /* 834 * Finally, free any entries which failed the gethostbyname 835 * check. 836 */ 837 psep = NULL; 838 nsep = sep; 839 while (nsep != NULL) { 840 servtab_t *tsep; 841 842 if (nsep->se_checked == 0) { 843 tsep = nsep; 844 if (psep == NULL) { 845 sep = nsep->se_next; 846 nsep = sep; 847 } else { 848 nsep = nsep->se_next; 849 psep->se_next = nsep; 850 } 851 freeconfig(tsep); 852 } else { 853 nsep->se_checked = 0; 854 psep = nsep; 855 nsep = nsep->se_next; 856 } 857 } 858 859 return sep; 860 } 861 862 #define Block_Using_Signals(m) do { \ 863 sigemptyset(&m); \ 864 sigaddset(&m, SIGCHLD); \ 865 sigaddset(&m, SIGHUP); \ 866 sigaddset(&m, SIGALRM); \ 867 sigprocmask(SIG_BLOCK, &m, NULL); \ 868 } while (0) 869 870 static servtab_t *enter(servtab_t *cp) 871 { 872 servtab_t *sep; 873 sigset_t omask; 874 875 sep = new_servtab(); 876 *sep = *cp; 494 877 sep->se_fd = -1; 495 if (!timingout) { 496 timingout = 1; 497 alarm (RETRYTIME); 498 } 499 return; 500 } 501 if (sep->se_socktype == SOCK_STREAM) 502 listen (sep->se_fd, global_queuelen); 503 504 FD_SET (sep->se_fd, &allsock); 505 nsock++; 506 if (sep->se_fd > maxsock) { 507 maxsock = sep->se_fd; 508 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) 509 bump_nofile (); 510 } 511 } 512 513 static char *nextline (void) 514 { 515 char *cp; 516 FILE *fd = fconfig; 517 518 if (fgets (line, sizeof (line), fd) == NULL) 519 return (NULL); 520 cp = strchr (line, '\n'); 521 if (cp) 522 *cp = '\0'; 523 return (line); 524 } 525 526 static char *skip (char **cpp) /* int report; */ 527 { 528 char *cp = *cpp; 529 char *start; 530 531 /* erp: */ 532 if (*cpp == NULL) { 533 /* if (report) */ 534 /* syslog(LOG_ERR, "syntax error in inetd config file"); */ 535 return (NULL); 536 } 537 538 again: 539 while (*cp == ' ' || *cp == '\t') 540 cp++; 541 if (*cp == '\0') { 542 int c; 543 544 c = getc (fconfig); 545 (void) ungetc (c, fconfig); 546 if (c == ' ' || c == '\t') 547 if ((cp = nextline ())) 548 goto again; 549 *cpp = NULL; 550 /* goto erp; */ 551 return (NULL); 552 } 553 start = cp; 554 while (*cp && *cp != ' ' && *cp != '\t') 555 cp++; 556 if (*cp != '\0') 557 *cp++ = '\0'; 558 /* if ((*cpp = cp) == NULL) */ 559 /* goto erp; */ 560 561 *cpp = cp; 562 return (start); 563 } 564 565 static servtab_t *new_servtab(void) 566 { 567 servtab_t *sep; 568 569 sep = (servtab_t *) malloc (sizeof (servtab_t)); 570 if (sep == NULL) { 571 syslog (LOG_ERR, bb_msg_memory_exhausted); 572 exit (1); 573 } 574 return sep; 575 } 576 577 static servtab_t *dupconfig (servtab_t *sep) 578 { 579 servtab_t *newtab; 580 int argc; 581 582 newtab = new_servtab(); 583 memset (newtab, 0, sizeof (servtab_t)); 584 newtab->se_service = sep->se_service ? newstr (sep->se_service) : NULL; 585 newtab->se_socktype = sep->se_socktype; 586 newtab->se_family = sep->se_family; 587 newtab->se_proto = sep->se_proto ? newstr (sep->se_proto) : NULL; 588 #ifdef CONFIG_FEATURE_INETD_RPC 589 newtab->se_rpcprog = sep->se_rpcprog; 590 newtab->se_rpcversl = sep->se_rpcversl; 591 newtab->se_rpcversh = sep->se_rpcversh; 592 #endif 593 newtab->se_wait = sep->se_wait; 594 newtab->se_user = sep->se_user ? newstr (sep->se_user) : NULL; 595 newtab->se_group = sep->se_group ? newstr (sep->se_group) : NULL; 878 #if ENABLE_FEATURE_INETD_RPC 879 sep->se_rpcprog = -1; 880 #endif 881 Block_Using_Signals(omask); 882 sep->se_next = servtab; 883 servtab = sep; 884 sigprocmask(SIG_UNBLOCK, &omask, NULL); 885 return sep; 886 } 887 888 static int matchconf(servtab_t *old, servtab_t *new) 889 { 890 if (strcmp(old->se_service, new->se_service) != 0) 891 return 0; 892 893 if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0) 894 return 0; 895 896 if (strcmp(old->se_proto, new->se_proto) != 0) 897 return 0; 898 899 /* 900 * If the new servtab is bound to a specific address, check that the 901 * old servtab is bound to the same entry. If the new service is not 902 * bound to a specific address then the check of se_hostaddr above 903 * is sufficient. 904 */ 905 906 if (old->se_family == AF_INET && new->se_family == AF_INET && 907 memcmp(&old->se_ctrladdr_in.sin_addr, 908 &new->se_ctrladdr_in.sin_addr, 909 sizeof(new->se_ctrladdr_in.sin_addr)) != 0) 910 return 0; 911 912 #if ENABLE_FEATURE_IPV6 913 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 && 914 memcmp(&old->se_ctrladdr_in6.sin6_addr, 915 &new->se_ctrladdr_in6.sin6_addr, 916 sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0) 917 return 0; 918 #endif 919 return 1; 920 } 921 922 static void config(int sig ATTRIBUTE_UNUSED) 923 { 924 servtab_t *sep, *cp, **sepp; 925 sigset_t omask; 926 size_t n; 927 char protoname[10]; 928 929 if (!setconfig()) { 930 bb_perror_msg("%s", config_filename); 931 return; 932 } 933 for (sep = servtab; sep; sep = sep->se_next) 934 sep->se_checked = 0; 935 cp = getconfigent(); 936 while (cp != NULL) { 937 for (sep = servtab; sep; sep = sep->se_next) 938 if (matchconf(sep, cp)) 939 break; 940 941 if (sep != 0) { 942 int i; 943 944 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0) 945 946 Block_Using_Signals(omask); 947 /* 948 * sep->se_wait may be holding the pid of a daemon 949 * that we're waiting for. If so, don't overwrite 950 * it unless the config file explicitly says don't 951 * wait. 952 */ 953 if ( 596 954 #ifdef INETD_FEATURE_ENABLED 597 newtab->se_bi = sep->se_bi; 598 #endif 599 newtab->se_server = sep->se_server ? newstr (sep->se_server) : 0; 600 601 for (argc = 0; argc <= MAXARGV; argc++) 602 newtab->se_argv[argc] = sep->se_argv[argc] ? 603 newstr (sep->se_argv[argc]) : NULL; 604 newtab->se_max = sep->se_max; 605 606 return (newtab); 607 } 608 609 static servtab_t *getconfigent (void) 610 { 611 servtab_t *sep; 612 int argc; 613 char *cp, *arg; 614 char *hostdelim; 615 servtab_t *nsep; 616 servtab_t *psep; 617 618 sep = new_servtab(); 619 620 /* memset(sep, 0, sizeof *sep); */ 621 more: 622 /* freeconfig(sep); */ 623 624 while ((cp = nextline ()) && *cp == '#'); 625 if (cp == NULL) { 626 /* free(sep); */ 627 return (NULL); 628 } 629 630 memset ((char *) sep, 0, sizeof *sep); 631 arg = skip (&cp); 632 if (arg == NULL) { 633 /* A blank line. */ 634 goto more; 635 } 636 637 /* Check for a host name. */ 638 hostdelim = strrchr (arg, ':'); 639 if (hostdelim) { 640 *hostdelim = '\0'; 641 sep->se_hostaddr = newstr (arg); 642 arg = hostdelim + 1; 955 cp->se_bi == 0 && 956 #endif 957 (sep->se_wait == 1 || cp->se_wait == 0)) 958 sep->se_wait = cp->se_wait; 959 SWAP(int, cp->se_max, sep->se_max); 960 SWAP(char *, sep->se_user, cp->se_user); 961 SWAP(char *, sep->se_group, cp->se_group); 962 SWAP(char *, sep->se_server, cp->se_server); 963 for (i = 0; i < MAXARGV; i++) 964 SWAP(char *, sep->se_argv[i], cp->se_argv[i]); 965 #undef SWAP 966 967 #if ENABLE_FEATURE_INETD_RPC 968 if (isrpcservice(sep)) 969 unregister_rpc(sep); 970 sep->se_rpcversl = cp->se_rpcversl; 971 sep->se_rpcversh = cp->se_rpcversh; 972 #endif 973 sigprocmask(SIG_UNBLOCK, &omask, NULL); 974 freeconfig(cp); 975 } else { 976 sep = enter(cp); 977 } 978 sep->se_checked = 1; 979 980 switch (sep->se_family) { 981 case AF_UNIX: 982 if (sep->se_fd != -1) 983 break; 984 (void) unlink(sep->se_service); 985 n = strlen(sep->se_service); 986 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) 987 n = sizeof sep->se_ctrladdr_un.sun_path - 1; 988 safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1); 989 sep->se_ctrladdr_un.sun_family = AF_UNIX; 990 sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family; 991 setup(sep); 992 break; 993 case AF_INET: 994 sep->se_ctrladdr_in.sin_family = AF_INET; 995 /* se_ctrladdr_in was set in getconfigent */ 996 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in; 997 998 #if ENABLE_FEATURE_INETD_RPC 999 if (isrpcservice(sep)) { 1000 struct rpcent *rp; 1001 // FIXME: atoi_or_else(str, 0) would be handy here 1002 sep->se_rpcprog = atoi(sep->se_service); 1003 if (sep->se_rpcprog == 0) { 1004 rp = getrpcbyname(sep->se_service); 1005 if (rp == 0) { 1006 bb_error_msg("%s: unknown rpc service", sep->se_service); 1007 goto serv_unknown; 1008 } 1009 sep->se_rpcprog = rp->r_number; 1010 } 1011 if (sep->se_fd == -1) 1012 setup(sep); 1013 if (sep->se_fd != -1) 1014 register_rpc(sep); 1015 } else 1016 #endif 1017 { 1018 uint16_t port = htons(atoi(sep->se_service)); 1019 // FIXME: atoi_or_else(str, 0) would be handy here 1020 if (!port) { 1021 /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname)); 1022 if (isdigit(protoname[strlen(protoname) - 1])) 1023 protoname[strlen(protoname) - 1] = '\0'; 1024 sp = getservbyname(sep->se_service, protoname); 1025 if (sp == 0) { 1026 bb_error_msg("%s/%s: unknown service", 1027 sep->se_service, sep->se_proto); 1028 goto serv_unknown; 1029 } 1030 port = sp->s_port; 1031 } 1032 if (port != sep->se_ctrladdr_in.sin_port) { 1033 sep->se_ctrladdr_in.sin_port = port; 1034 if (sep->se_fd != -1) { 1035 FD_CLR(sep->se_fd, &allsock); 1036 nsock--; 1037 (void) close(sep->se_fd); 1038 } 1039 sep->se_fd = -1; 1040 } 1041 if (sep->se_fd == -1) 1042 setup(sep); 1043 } 1044 break; 1045 #if ENABLE_FEATURE_IPV6 1046 case AF_INET6: 1047 sep->se_ctrladdr_in6.sin6_family = AF_INET6; 1048 /* se_ctrladdr_in was set in getconfigent */ 1049 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6; 1050 1051 #if ENABLE_FEATURE_INETD_RPC 1052 if (isrpcservice(sep)) { 1053 struct rpcent *rp; 1054 1055 sep->se_rpcprog = atoi(sep->se_service); 1056 if (sep->se_rpcprog == 0) { 1057 rp = getrpcbyname(sep->se_service); 1058 if (rp == 0) { 1059 bb_error_msg("%s: unknown rpc service", sep->se_service); 1060 goto serv_unknown; 1061 } 1062 sep->se_rpcprog = rp->r_number; 1063 } 1064 if (sep->se_fd == -1) 1065 setup(sep); 1066 if (sep->se_fd != -1) 1067 register_rpc(sep); 1068 } else 1069 #endif 1070 { 1071 uint16_t port = htons(atoi(sep->se_service)); 1072 1073 if (!port) { 1074 /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname)); 1075 if (isdigit(protoname[strlen(protoname) - 1])) 1076 protoname[strlen(protoname) - 1] = '\0'; 1077 sp = getservbyname(sep->se_service, protoname); 1078 if (sp == 0) { 1079 bb_error_msg("%s/%s: unknown service", 1080 sep->se_service, sep->se_proto); 1081 goto serv_unknown; 1082 } 1083 port = sp->s_port; 1084 } 1085 if (port != sep->se_ctrladdr_in6.sin6_port) { 1086 sep->se_ctrladdr_in6.sin6_port = port; 1087 if (sep->se_fd != -1) { 1088 FD_CLR(sep->se_fd, &allsock); 1089 nsock--; 1090 (void) close(sep->se_fd); 1091 } 1092 sep->se_fd = -1; 1093 } 1094 if (sep->se_fd == -1) 1095 setup(sep); 1096 } 1097 break; 1098 #endif /* FEATURE_IPV6 */ 1099 } 1100 serv_unknown: 1101 if (cp->se_next != NULL) { 1102 servtab_t *tmp = cp; 1103 1104 cp = cp->se_next; 1105 free(tmp); 1106 } else { 1107 free(cp); 1108 cp = getconfigent(); 1109 } 1110 } 1111 endconfig(); 643 1112 /* 644 * If the line is of the form `host:', then just change the 645 * default host for the following lines. 1113 * Purge anything not looked at above. 646 1114 */ 647 if (*arg == '\0') { 648 arg = skip (&cp); 649 if (cp == NULL) { 650 free (defhost); 651 defhost = sep->se_hostaddr; 652 goto more; 653 } 654 } 655 } else 656 sep->se_hostaddr = newstr (defhost); 657 658 sep->se_service = newstr (arg); 659 arg = skip (&cp); 660 661 if (strcmp (arg, "stream") == 0) 662 sep->se_socktype = SOCK_STREAM; 663 else if (strcmp (arg, "dgram") == 0) 664 sep->se_socktype = SOCK_DGRAM; 665 else if (strcmp (arg, "rdm") == 0) 666 sep->se_socktype = SOCK_RDM; 667 else if (strcmp (arg, "seqpacket") == 0) 668 sep->se_socktype = SOCK_SEQPACKET; 669 else if (strcmp (arg, "raw") == 0) 670 sep->se_socktype = SOCK_RAW; 671 else 672 sep->se_socktype = -1; 673 674 sep->se_proto = newstr (skip (&cp)); 675 676 if (strcmp (sep->se_proto, "unix") == 0) { 677 sep->se_family = AF_UNIX; 678 } else { 679 sep->se_family = AF_INET; 680 if (sep->se_proto[strlen (sep->se_proto) - 1] == '6') 681 #ifdef CONFIG_FEATURE_IPV6 682 sep->se_family = AF_INET6; 683 #else 684 syslog (LOG_ERR, "%s: IPV6 not supported", sep->se_proto); 685 #endif 686 if (strncmp (sep->se_proto, "rpc/", 4) == 0) { 687 #ifdef CONFIG_FEATURE_INETD_RPC 688 char *p, *ccp; 689 long l; 690 691 p = strchr (sep->se_service, '/'); 692 if (p == 0) { 693 syslog (LOG_ERR, "%s: no rpc version", sep->se_service); 694 goto more; 695 } 696 *p++ = '\0'; 697 l = strtol (p, &ccp, 0); 698 if (ccp == p || l < 0 || l > INT_MAX) { 699 badafterall: 700 syslog (LOG_ERR, "%s/%s: bad rpc version", sep->se_service, p); 701 goto more; 702 } 703 sep->se_rpcversl = sep->se_rpcversh = l; 704 if (*ccp == '-') { 705 p = ccp + 1; 706 l = strtol (p, &ccp, 0); 707 if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp) 708 goto badafterall; 709 sep->se_rpcversh = l; 710 } else if (*ccp != '\0') 711 goto badafterall; 712 #else 713 syslog (LOG_ERR, "%s: rpc services not supported", sep->se_service); 714 #endif 715 } 716 } 717 arg = skip (&cp); 718 if (arg == NULL) 719 goto more; 720 721 { 722 char *s = strchr (arg, '.'); 723 if (s) { 724 *s++ = '\0'; 725 sep->se_max = atoi (s); 726 } else 727 sep->se_max = toomany; 728 } 729 sep->se_wait = strcmp (arg, "wait") == 0; 730 /* if ((arg = skip(&cp, 1)) == NULL) */ 731 /* goto more; */ 732 sep->se_user = newstr (skip (&cp)); 733 arg = strchr (sep->se_user, '.'); 734 if (arg == NULL) 735 arg = strchr (sep->se_user, ':'); 736 if (arg) { 737 *arg++ = '\0'; 738 sep->se_group = newstr (arg); 739 } 740 /* if ((arg = skip(&cp, 1)) == NULL) */ 741 /* goto more; */ 742 743 sep->se_server = newstr (skip (&cp)); 744 if (strcmp (sep->se_server, "internal") == 0) { 745 #ifdef INETD_FEATURE_ENABLED 746 const struct builtin *bi; 747 748 for (bi = builtins; bi->bi_service; bi++) 749 if (bi->bi_socktype == sep->se_socktype && 750 strcmp (bi->bi_service, sep->se_service) == 0) 751 break; 752 if (bi->bi_service == 0) { 753 syslog (LOG_ERR, "internal service %s unknown", sep->se_service); 754 goto more; 755 } 756 sep->se_bi = bi; 757 sep->se_wait = bi->bi_wait; 758 #else 759 syslog (LOG_ERR, "internal service %s unknown", sep->se_service); 760 goto more; 761 #endif 762 } 763 #ifdef INETD_FEATURE_ENABLED 764 else 765 sep->se_bi = NULL; 766 #endif 767 argc = 0; 768 for (arg = skip (&cp); cp; arg = skip (&cp)) { 769 if (argc < MAXARGV) 770 sep->se_argv[argc++] = newstr (arg); 771 } 772 while (argc <= MAXARGV) 773 sep->se_argv[argc++] = NULL; 774 775 /* 776 * Now that we've processed the entire line, check if the hostname 777 * specifier was a comma separated list of hostnames. If so 778 * we'll make new entries for each address. 779 */ 780 while ((hostdelim = strrchr (sep->se_hostaddr, ',')) != NULL) { 781 nsep = dupconfig (sep); 782 783 /* 784 * NULL terminate the hostname field of the existing entry, 785 * and make a dup for the new entry. 786 */ 787 *hostdelim++ = '\0'; 788 nsep->se_hostaddr = newstr (hostdelim); 789 790 nsep->se_next = sep->se_next; 791 sep->se_next = nsep; 792 } 793 794 nsep = sep; 795 while (nsep != NULL) { 796 nsep->se_checked = 1; 797 if (nsep->se_family == AF_INET) { 798 if (!strcmp (nsep->se_hostaddr, "*")) 799 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY; 800 else if (!inet_aton (nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) { 801 struct hostent *hp; 802 803 hp = gethostbyname (nsep->se_hostaddr); 804 if (hp == 0) { 805 syslog (LOG_ERR, "%s: unknown host", nsep->se_hostaddr); 806 nsep->se_checked = 0; 807 goto skip; 808 } else if (hp->h_addrtype != AF_INET) { 809 syslog (LOG_ERR, 810 "%s: address isn't an Internet " 811 "address", nsep->se_hostaddr); 812 nsep->se_checked = 0; 813 goto skip; 814 } else { 815 int i = 1; 816 817 memmove (&nsep->se_ctrladdr_in.sin_addr, 818 hp->h_addr_list[0], sizeof (struct in_addr)); 819 while (hp->h_addr_list[i] != NULL) { 820 psep = dupconfig (nsep); 821 psep->se_hostaddr = newstr (nsep->se_hostaddr); 822 psep->se_checked = 1; 823 memmove (&psep->se_ctrladdr_in.sin_addr, 824 hp->h_addr_list[i], sizeof (struct in_addr)); 825 psep->se_ctrladdr_size = sizeof (psep->se_ctrladdr_in); 826 i++; 827 /* Prepend to list, don't want to look up its */ 828 /* hostname again. */ 829 psep->se_next = sep; 830 sep = psep; 831 } 1115 Block_Using_Signals(omask); 1116 sepp = &servtab; 1117 while ((sep = *sepp)) { 1118 if (sep->se_checked) { 1119 sepp = &sep->se_next; 1120 continue; 832 1121 } 833 } 834 } 835 /* XXX BUG?: is this skip: label supposed to remain? */ 836 skip: 837 nsep = nsep->se_next; 838 } 839 840 /* 841 * Finally, free any entries which failed the gethostbyname 842 * check. 843 */ 844 psep = NULL; 845 nsep = sep; 846 while (nsep != NULL) { 847 servtab_t *tsep; 848 849 if (nsep->se_checked == 0) { 850 tsep = nsep; 851 if (psep == NULL) { 852 sep = nsep->se_next; 853 nsep = sep; 854 } else { 855 nsep = nsep->se_next; 856 psep->se_next = nsep; 857 } 858 freeconfig (tsep); 859 } else { 860 nsep->se_checked = 0; 861 psep = nsep; 862 nsep = nsep->se_next; 863 } 864 } 865 866 return (sep); 867 } 868 869 #define Block_Using_Signals(m) do { sigemptyset(&m); \ 870 sigaddset(&m, SIGCHLD); \ 871 sigaddset(&m, SIGHUP); \ 872 sigaddset(&m, SIGALRM); \ 873 sigprocmask(SIG_BLOCK, &m, NULL); \ 874 } while(0) 875 876 877 static servtab_t *enter (servtab_t *cp) 878 { 879 servtab_t *sep; 880 sigset_t omask; 881 882 sep = new_servtab(); 883 *sep = *cp; 884 sep->se_fd = -1; 885 #ifdef CONFIG_FEATURE_INETD_RPC 886 sep->se_rpcprog = -1; 887 #endif 888 Block_Using_Signals(omask); 889 sep->se_next = servtab; 890 servtab = sep; 891 sigprocmask(SIG_UNBLOCK, &omask, NULL); 892 return (sep); 893 } 894 895 static int matchconf (servtab_t *old, servtab_t *new) 896 { 897 if (strcmp (old->se_service, new->se_service) != 0) 898 return (0); 899 900 if (strcmp (old->se_hostaddr, new->se_hostaddr) != 0) 901 return (0); 902 903 if (strcmp (old->se_proto, new->se_proto) != 0) 904 return (0); 905 906 /* 907 * If the new servtab is bound to a specific address, check that the 908 * old servtab is bound to the same entry. If the new service is not 909 * bound to a specific address then the check of se_hostaddr above 910 * is sufficient. 911 */ 912 913 if (old->se_family == AF_INET && new->se_family == AF_INET && 914 memcmp (&old->se_ctrladdr_in.sin_addr, 915 &new->se_ctrladdr_in.sin_addr, 916 sizeof (new->se_ctrladdr_in.sin_addr)) != 0) 917 return (0); 918 919 #ifdef CONFIG_FEATURE_IPV6 920 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 && 921 memcmp (&old->se_ctrladdr_in6.sin6_addr, 922 &new->se_ctrladdr_in6.sin6_addr, 923 sizeof (new->se_ctrladdr_in6.sin6_addr)) != 0) 924 return (0); 925 #endif 926 return (1); 927 } 928 929 static void config (int sig ATTRIBUTE_UNUSED) 930 { 931 servtab_t *sep, *cp, **sepp; 932 sigset_t omask; 933 int add; 934 size_t n; 935 char protoname[10]; 936 937 if (!setconfig ()) { 938 syslog (LOG_ERR, "%s: %m", CONFIG); 939 return; 940 } 941 for (sep = servtab; sep; sep = sep->se_next) 942 sep->se_checked = 0; 943 cp = getconfigent (); 944 while (cp != NULL) { 945 for (sep = servtab; sep; sep = sep->se_next) 946 if (matchconf (sep, cp)) 947 break; 948 add = 0; 949 if (sep != 0) { 950 int i; 951 952 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0) 953 954 Block_Using_Signals(omask); 955 /* 956 * sep->se_wait may be holding the pid of a daemon 957 * that we're waiting for. If so, don't overwrite 958 * it unless the config file explicitly says don't 959 * wait. 960 */ 961 if ( 962 #ifdef INETD_FEATURE_ENABLED 963 cp->se_bi == 0 && 964 #endif 965 (sep->se_wait == 1 || cp->se_wait == 0)) 966 sep->se_wait = cp->se_wait; 967 SWAP (int, cp->se_max, sep->se_max); 968 SWAP (char *, sep->se_user, cp->se_user); 969 SWAP (char *, sep->se_group, cp->se_group); 970 SWAP (char *, sep->se_server, cp->se_server); 971 for (i = 0; i < MAXARGV; i++) 972 SWAP (char *, sep->se_argv[i], cp->se_argv[i]); 973 #undef SWAP 974 975 #ifdef CONFIG_FEATURE_INETD_RPC 976 if (isrpcservice (sep)) 977 unregister_rpc (sep); 978 sep->se_rpcversl = cp->se_rpcversl; 979 sep->se_rpcversh = cp->se_rpcversh; 980 #endif 981 sigprocmask(SIG_UNBLOCK, &omask, NULL); 982 freeconfig (cp); 983 add = 1; 984 } else { 985 sep = enter (cp); 986 } 987 sep->se_checked = 1; 988 989 switch (sep->se_family) { 990 case AF_UNIX: 991 if (sep->se_fd != -1) 992 break; 993 (void) unlink (sep->se_service); 994 n = strlen (sep->se_service); 995 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) 996 n = sizeof sep->se_ctrladdr_un.sun_path - 1; 997 safe_strncpy (sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1); 998 sep->se_ctrladdr_un.sun_family = AF_UNIX; 999 sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family; 1000 setup (sep); 1001 break; 1002 case AF_INET: 1003 sep->se_ctrladdr_in.sin_family = AF_INET; 1004 /* se_ctrladdr_in was set in getconfigent */ 1005 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in; 1006 1007 #ifdef CONFIG_FEATURE_INETD_RPC 1008 if (isrpcservice (sep)) { 1009 struct rpcent *rp; 1010 1011 sep->se_rpcprog = atoi (sep->se_service); 1012 if (sep->se_rpcprog == 0) { 1013 rp = getrpcbyname (sep->se_service); 1014 if (rp == 0) { 1015 syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service); 1016 goto serv_unknown; 1017 } 1018 sep->se_rpcprog = rp->r_number; 1122 *sepp = sep->se_next; 1123 if (sep->se_fd != -1) { 1124 FD_CLR(sep->se_fd, &allsock); 1125 nsock--; 1126 (void) close(sep->se_fd); 1019 1127 } 1128 #if ENABLE_FEATURE_INETD_RPC 1129 if (isrpcservice(sep)) 1130 unregister_rpc(sep); 1131 #endif 1132 if (sep->se_family == AF_UNIX) 1133 (void) unlink(sep->se_service); 1134 freeconfig(sep); 1135 free(sep); 1136 } 1137 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1138 } 1139 1140 1141 static void reapchild(int sig ATTRIBUTE_UNUSED) 1142 { 1143 pid_t pid; 1144 int save_errno = errno, status; 1145 servtab_t *sep; 1146 1147 for (;;) { 1148 pid = wait3(&status, WNOHANG, NULL); 1149 if (pid <= 0) 1150 break; 1151 for (sep = servtab; sep; sep = sep->se_next) 1152 if (sep->se_wait == pid) { 1153 if (WIFEXITED(status) && WEXITSTATUS(status)) 1154 bb_error_msg("%s: exit status 0x%x", 1155 sep->se_server, WEXITSTATUS(status)); 1156 else if (WIFSIGNALED(status)) 1157 bb_error_msg("%s: exit signal 0x%x", 1158 sep->se_server, WTERMSIG(status)); 1159 sep->se_wait = 1; 1160 FD_SET(sep->se_fd, &allsock); 1161 nsock++; 1162 } 1163 } 1164 errno = save_errno; 1165 } 1166 1167 static void retry(int sig ATTRIBUTE_UNUSED) 1168 { 1169 servtab_t *sep; 1170 1171 timingout = 0; 1172 for (sep = servtab; sep; sep = sep->se_next) { 1173 if (sep->se_fd == -1) { 1174 switch (sep->se_family) { 1175 case AF_UNIX: 1176 case AF_INET: 1177 #if ENABLE_FEATURE_IPV6 1178 case AF_INET6: 1179 #endif 1180 setup(sep); 1181 #if ENABLE_FEATURE_INETD_RPC 1182 if (sep->se_fd != -1 && isrpcservice(sep)) 1183 register_rpc(sep); 1184 #endif 1185 break; 1186 } 1187 } 1188 } 1189 } 1190 1191 static void goaway(int sig ATTRIBUTE_UNUSED) 1192 { 1193 servtab_t *sep; 1194 1195 /* XXX signal race walking sep list */ 1196 for (sep = servtab; sep; sep = sep->se_next) { 1020 1197 if (sep->se_fd == -1) 1021 setup (sep); 1022 if (sep->se_fd != -1) 1023 register_rpc (sep); 1024 } else 1025 #endif 1026 { 1027 u_short port = htons (atoi (sep->se_service)); 1028 1029 if (!port) { 1030 /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname)); 1031 if (isdigit (protoname[strlen (protoname) - 1])) 1032 protoname[strlen (protoname) - 1] = '\0'; 1033 sp = getservbyname (sep->se_service, protoname); 1034 if (sp == 0) { 1035 syslog (LOG_ERR, 1036 "%s/%s: unknown service", sep->se_service, sep->se_proto); 1037 goto serv_unknown; 1038 } 1039 port = sp->s_port; 1198 continue; 1199 1200 switch (sep->se_family) { 1201 case AF_UNIX: 1202 (void) unlink(sep->se_service); 1203 break; 1204 case AF_INET: 1205 #if ENABLE_FEATURE_IPV6 1206 case AF_INET6: 1207 #endif 1208 #if ENABLE_FEATURE_INETD_RPC 1209 if (sep->se_wait == 1 && isrpcservice(sep)) 1210 unregister_rpc(sep); /* XXX signal race */ 1211 #endif 1212 break; 1040 1213 } 1041 if (port != sep->se_ctrladdr_in.sin_port) { 1042 sep->se_ctrladdr_in.sin_port = port; 1043 if (sep->se_fd != -1) { 1044 FD_CLR (sep->se_fd, &allsock); 1045 nsock--; 1046 (void) close (sep->se_fd); 1047 } 1048 sep->se_fd = -1; 1049 } 1050 if (sep->se_fd == -1) 1051 setup (sep); 1052 } 1053 break; 1054 #ifdef CONFIG_FEATURE_IPV6 1055 case AF_INET6: 1056 sep->se_ctrladdr_in6.sin6_family = AF_INET6; 1057 /* se_ctrladdr_in was set in getconfigent */ 1058 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6; 1059 1060 #ifdef CONFIG_FEATURE_INETD_RPC 1061 if (isrpcservice (sep)) { 1062 struct rpcent *rp; 1063 1064 sep->se_rpcprog = atoi (sep->se_service); 1065 if (sep->se_rpcprog == 0) { 1066 rp = getrpcbyname (sep->se_service); 1067 if (rp == 0) { 1068 syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service); 1069 goto serv_unknown; 1070 } 1071 sep->se_rpcprog = rp->r_number; 1072 } 1073 if (sep->se_fd == -1) 1074 setup (sep); 1075 if (sep->se_fd != -1) 1076 register_rpc (sep); 1077 } else 1078 #endif 1079 { 1080 u_short port = htons (atoi (sep->se_service)); 1081 1082 if (!port) { 1083 /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname)); 1084 if (isdigit (protoname[strlen (protoname) - 1])) 1085 protoname[strlen (protoname) - 1] = '\0'; 1086 sp = getservbyname (sep->se_service, protoname); 1087 if (sp == 0) { 1088 syslog (LOG_ERR, 1089 "%s/%s: unknown service", sep->se_service, sep->se_proto); 1090 goto serv_unknown; 1091 } 1092 port = sp->s_port; 1093 } 1094 if (port != sep->se_ctrladdr_in6.sin6_port) { 1095 sep->se_ctrladdr_in6.sin6_port = port; 1096 if (sep->se_fd != -1) { 1097 FD_CLR (sep->se_fd, &allsock); 1098 nsock--; 1099 (void) close (sep->se_fd); 1100 } 1101 sep->se_fd = -1; 1102 } 1103 if (sep->se_fd == -1) 1104 setup (sep); 1105 } 1106 break; 1107 #endif /* CONFIG_FEATURE_IPV6 */ 1108 } 1109 serv_unknown: 1110 if (cp->se_next != NULL) { 1111 servtab_t *tmp = cp; 1112 1113 cp = cp->se_next; 1114 free (tmp); 1115 } else { 1116 free (cp); 1117 cp = getconfigent (); 1118 } 1119 } 1120 endconfig (); 1121 /* 1122 * Purge anything not looked at above. 1123 */ 1124 Block_Using_Signals(omask); 1125 sepp = &servtab; 1126 while ((sep = *sepp)) { 1127 if (sep->se_checked) { 1128 sepp = &sep->se_next; 1129 continue; 1130 } 1131 *sepp = sep->se_next; 1132 if (sep->se_fd != -1) { 1133 FD_CLR (sep->se_fd, &allsock); 1134 nsock--; 1135 (void) close (sep->se_fd); 1136 } 1137 #ifdef CONFIG_FEATURE_INETD_RPC 1138 if (isrpcservice (sep)) 1139 unregister_rpc (sep); 1140 #endif 1141 if (sep->se_family == AF_UNIX) 1142 (void) unlink (sep->se_service); 1143 freeconfig (sep); 1144 free (sep); 1145 } 1146 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1147 } 1148 1149 1150 static void reapchild (int sig ATTRIBUTE_UNUSED) 1151 { 1152 pid_t pid; 1153 int save_errno = errno, status; 1154 servtab_t *sep; 1155 1156 for (;;) { 1157 pid = wait3 (&status, WNOHANG, NULL); 1158 if (pid <= 0) 1159 break; 1160 for (sep = servtab; sep; sep = sep->se_next) 1161 if (sep->se_wait == pid) { 1162 if (WIFEXITED (status) && WEXITSTATUS (status)) 1163 syslog (LOG_WARNING, 1164 "%s: exit status 0x%x", 1165 sep->se_server, WEXITSTATUS (status)); 1166 else if (WIFSIGNALED (status)) 1167 syslog (LOG_WARNING, 1168 "%s: exit signal 0x%x", sep->se_server, WTERMSIG (status)); 1169 sep->se_wait = 1; 1170 FD_SET (sep->se_fd, &allsock); 1171 nsock++; 1172 } 1173 } 1174 errno = save_errno; 1175 } 1176 1177 static void retry (int sig ATTRIBUTE_UNUSED) 1178 { 1179 servtab_t *sep; 1180 1181 timingout = 0; 1182 for (sep = servtab; sep; sep = sep->se_next) { 1183 if (sep->se_fd == -1) { 1184 switch (sep->se_family) { 1185 case AF_UNIX: 1186 case AF_INET: 1187 #ifdef CONFIG_FEATURE_IPV6 1188 case AF_INET6: 1189 #endif 1190 setup (sep); 1191 #ifdef CONFIG_FEATURE_INETD_RPC 1192 if (sep->se_fd != -1 && isrpcservice (sep)) 1193 register_rpc (sep); 1194 #endif 1195 break; 1196 } 1197 } 1198 } 1199 } 1200 1201 static void goaway (int sig ATTRIBUTE_UNUSED) 1202 { 1203 servtab_t *sep; 1204 1205 /* XXX signal race walking sep list */ 1206 for (sep = servtab; sep; sep = sep->se_next) { 1207 if (sep->se_fd == -1) 1208 continue; 1209 1210 switch (sep->se_family) { 1211 case AF_UNIX: 1212 (void) unlink (sep->se_service); 1213 break; 1214 case AF_INET: 1215 #ifdef CONFIG_FEATURE_IPV6 1216 case AF_INET6: 1217 #endif 1218 #ifdef CONFIG_FEATURE_INETD_RPC 1219 if (sep->se_wait == 1 && isrpcservice (sep)) 1220 unregister_rpc (sep); /* XXX signal race */ 1221 #endif 1222 break; 1223 } 1224 (void) close (sep->se_fd); 1225 } 1226 (void) unlink (_PATH_INETDPID); 1227 exit (0); 1214 (void) close(sep->se_fd); 1215 } 1216 remove_pidfile(_PATH_INETDPID); 1217 exit(0); 1228 1218 } 1229 1219 … … 1234 1224 1235 1225 static void 1236 inetd_setproctitle 1237 { 1238 1239 1240 1241 1242 1243 1244 size = sizeof(prt_sin);1245 (void) snprintf(buf, sizeof buf, "-%s", a);1246 if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) {1247 char *sa = inet_ntoa(prt_sin.sin_addr);1248 1249 buf[sizeof (buf) - 1 - strlen(sa) - 3] = '\0';1250 strcat(buf, " [");1251 strcat(buf, sa);1252 strcat(buf, "]");1253 1254 strncpy(cp, buf, LastArg - cp);1255 cp += strlen(cp);1256 1257 *cp++ = ' ';1258 } 1259 #endif 1260 1261 1262 int 1263 in etd_main (int argc, char *argv[])1264 { 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1226 inetd_setproctitle(char *a, int s) 1227 { 1228 socklen_t size; 1229 char *cp; 1230 struct sockaddr_in prt_sin; 1231 char buf[80]; 1232 1233 cp = Argv[0]; 1234 size = sizeof(prt_sin); 1235 (void) snprintf(buf, sizeof buf, "-%s", a); 1236 if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) { 1237 char *sa = inet_ntoa(prt_sin.sin_addr); 1238 1239 buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0'; 1240 strcat(buf, " ["); 1241 strcat(buf, sa); 1242 strcat(buf, "]"); 1243 } 1244 strncpy(cp, buf, LastArg - cp); 1245 cp += strlen(cp); 1246 while (cp < LastArg) 1247 *cp++ = ' '; 1248 } 1249 #endif 1250 1251 1252 int inetd_main(int argc, char **argv); 1253 int inetd_main(int argc, char **argv) 1254 { 1255 servtab_t *sep; 1256 struct passwd *pwd; 1257 struct group *grp = NULL; 1258 int tmpint; 1259 struct sigaction sa, sapipe; 1260 int opt; 1261 pid_t pid; 1262 char buf[50]; 1263 char *stoomany; 1264 sigset_t omask, wait_mask; 1275 1265 1276 1266 #ifdef INETD_SETPROCTITLE 1277 extern char **environ; 1278 char **envp = environ; 1279 1280 Argv = argv; 1281 if (envp == 0 || *envp == 0) 1282 envp = argv; 1283 while (*envp) 1284 envp++; 1285 LastArg = envp[-1] + strlen (envp[-1]); 1286 #endif 1287 1288 openlog (bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 1289 1290 opt = bb_getopt_ulflags (argc, argv, "R:f", &stoomany); 1291 if(opt & 1) { 1292 char *e; 1293 1294 toomany = strtoul (stoomany, &e, 0); 1295 if (!(toomany >= 0 && *e == '\0')) { 1296 toomany = TOOMANY; 1297 syslog (LOG_ERR, "-R %s: bad value for service invocation rate", stoomany); 1298 } 1299 } 1300 argc -= optind; 1301 argv += optind; 1302 1303 uid = getuid (); 1304 if (uid != 0) 1305 CONFIG = NULL; 1306 if (argc > 0) 1307 CONFIG = argv[0]; 1308 if (CONFIG == NULL) 1309 bb_error_msg_and_die ("non-root must specify a config file"); 1310 1311 if (!(opt & 2)) { 1312 #ifdef BB_NOMMU 1313 /* reexec for vfork() do continue parent */ 1314 vfork_daemon_rexec (0, 0, argc, argv, "-f"); 1315 #else 1316 bb_xdaemon (0, 0); 1317 #endif 1318 } else { 1319 setsid (); 1320 } 1321 1322 if (uid == 0) { 1323 gid_t gid = getgid (); 1324 1325 /* If run by hand, ensure groups vector gets trashed */ 1326 setgroups (1, &gid); 1327 } 1328 1329 { 1330 FILE *fp; 1331 1332 if ((fp = fopen (_PATH_INETDPID, "w")) != NULL) { 1333 fprintf (fp, "%u\n", getpid ()); 1334 (void) fclose (fp); 1335 } 1336 } 1337 1338 if (getrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) { 1339 syslog (LOG_ERR, "getrlimit: %m"); 1340 } else { 1341 rlim_ofile_cur = rlim_ofile.rlim_cur; 1342 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ 1343 rlim_ofile_cur = OPEN_MAX; 1344 } 1345 1346 memset ((char *) &sa, 0, sizeof (sa)); 1347 sigemptyset (&sa.sa_mask); 1348 sigaddset (&sa.sa_mask, SIGALRM); 1349 sigaddset (&sa.sa_mask, SIGCHLD); 1350 sigaddset (&sa.sa_mask, SIGHUP); 1351 sa.sa_handler = retry; 1352 sigaction (SIGALRM, &sa, NULL); 1353 /* doconfig(); */ 1354 config (SIGHUP); 1355 sa.sa_handler = config; 1356 sigaction (SIGHUP, &sa, NULL); 1357 sa.sa_handler = reapchild; 1358 sigaction (SIGCHLD, &sa, NULL); 1359 sa.sa_handler = goaway; 1360 sigaction (SIGTERM, &sa, NULL); 1361 sa.sa_handler = goaway; 1362 sigaction (SIGINT, &sa, NULL); 1363 sa.sa_handler = SIG_IGN; 1364 sigaction (SIGPIPE, &sa, &sapipe); 1365 memset(&wait_mask, 0, sizeof(wait_mask)); 1366 { 1367 /* space for daemons to overwrite environment for ps */ 1267 char **envp = environ; 1268 1269 Argv = argv; 1270 if (envp == 0 || *envp == 0) 1271 envp = argv; 1272 while (*envp) 1273 envp++; 1274 LastArg = envp[-1] + strlen(envp[-1]); 1275 #endif 1276 1277 uid = getuid(); 1278 if (uid != 0) 1279 config_filename = NULL; 1280 1281 opt = getopt32(argv, "R:f", &stoomany); 1282 if (opt & 1) 1283 toomany = xatoi_u(stoomany); 1284 argv += optind; 1285 argc -= optind; 1286 if (argc) 1287 config_filename = argv[0]; 1288 if (config_filename == NULL) 1289 bb_error_msg_and_die("non-root must specify a config file"); 1290 1291 if (!(opt & 2)) 1292 bb_daemonize_or_rexec(0, argv - optind); 1293 else 1294 bb_sanitize_stdio(); 1295 openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 1296 logmode = LOGMODE_SYSLOG; 1297 1298 if (uid == 0) { 1299 /* If run by hand, ensure groups vector gets trashed */ 1300 gid_t gid = getgid(); 1301 setgroups(1, &gid); 1302 } 1303 1304 write_pidfile(_PATH_INETDPID); 1305 1306 if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) { 1307 bb_perror_msg("getrlimit"); 1308 } else { 1309 rlim_ofile_cur = rlim_ofile.rlim_cur; 1310 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ 1311 rlim_ofile_cur = OPEN_MAX; 1312 } 1313 1314 memset((char *) &sa, 0, sizeof(sa)); 1315 sigemptyset(&sa.sa_mask); 1316 sigaddset(&sa.sa_mask, SIGALRM); 1317 sigaddset(&sa.sa_mask, SIGCHLD); 1318 sigaddset(&sa.sa_mask, SIGHUP); 1319 sa.sa_handler = retry; 1320 sigaction(SIGALRM, &sa, NULL); 1321 config(SIGHUP); 1322 sa.sa_handler = config; 1323 sigaction(SIGHUP, &sa, NULL); 1324 sa.sa_handler = reapchild; 1325 sigaction(SIGCHLD, &sa, NULL); 1326 sa.sa_handler = goaway; 1327 sigaction(SIGTERM, &sa, NULL); 1328 sa.sa_handler = goaway; 1329 sigaction(SIGINT, &sa, NULL); 1330 sa.sa_handler = SIG_IGN; 1331 sigaction(SIGPIPE, &sa, &sapipe); 1332 memset(&wait_mask, 0, sizeof(wait_mask)); 1333 { 1334 /* space for daemons to overwrite environment for ps */ 1368 1335 #define DUMMYSIZE 100 1369 char dummy[DUMMYSIZE]; 1370 1371 (void) memset (dummy, 'x', DUMMYSIZE - 1); 1372 dummy[DUMMYSIZE - 1] = '\0'; 1373 1374 (void) setenv ("inetd_dummy", dummy, 1); 1375 } 1376 1377 for (;;) { 1378 int n, ctrl = -1; 1379 fd_set readable; 1380 1381 if (nsock == 0) { 1382 Block_Using_Signals(omask); 1383 while (nsock == 0) 1384 sigsuspend (&wait_mask); 1385 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1386 } 1387 1388 readable = allsock; 1389 if ((n = select (maxsock + 1, &readable, NULL, NULL, NULL)) <= 0) { 1390 if (n < 0 && errno != EINTR) { 1391 syslog (LOG_WARNING, "select: %m"); 1392 sleep (1); 1393 } 1394 continue; 1395 } 1396 for (sep = servtab; n && sep; sep = sep->se_next) 1397 if (sep->se_fd != -1 && FD_ISSET (sep->se_fd, &readable)) { 1398 n--; 1399 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 1400 ctrl = accept (sep->se_fd, NULL, NULL); 1401 if (ctrl < 0) { 1402 if (errno == EINTR) 1403 continue; 1404 syslog (LOG_WARNING, "accept (for %s): %m", sep->se_service); 1336 char dummy[DUMMYSIZE]; 1337 1338 (void) memset(dummy, 'x', DUMMYSIZE - 1); 1339 dummy[DUMMYSIZE - 1] = '\0'; 1340 1341 (void) setenv("inetd_dummy", dummy, 1); 1342 } 1343 1344 for (;;) { 1345 int n, ctrl = -1; 1346 fd_set readable; 1347 1348 if (nsock == 0) { 1349 Block_Using_Signals(omask); 1350 while (nsock == 0) 1351 sigsuspend(&wait_mask); 1352 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1353 } 1354 1355 readable = allsock; 1356 n = select(maxsock + 1, &readable, NULL, NULL, NULL); 1357 if (n <= 0) { 1358 if (n < 0 && errno != EINTR) { 1359 bb_perror_msg("select"); 1360 sleep(1); 1361 } 1405 1362 continue; 1406 } 1407 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) { 1408 struct sockaddr_in peer; 1409 socklen_t plen = sizeof (peer); 1410 1411 if (getpeername (ctrl, (struct sockaddr *) &peer, &plen) < 0) { 1412 syslog (LOG_WARNING, "could not getpeername"); 1413 close (ctrl); 1414 continue; 1363 } 1364 1365 for (sep = servtab; n && sep; sep = sep->se_next) { 1366 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) 1367 continue; 1368 1369 n--; 1370 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 1371 ctrl = accept(sep->se_fd, NULL, NULL); 1372 if (ctrl < 0) { 1373 if (errno == EINTR) 1374 continue; 1375 bb_perror_msg("accept (for %s)", sep->se_service); 1376 continue; 1377 } 1378 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) { 1379 struct sockaddr_in peer; 1380 socklen_t plen = sizeof(peer); 1381 1382 if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) { 1383 bb_error_msg("cannot getpeername"); 1384 close(ctrl); 1385 continue; 1386 } 1387 if (ntohs(peer.sin_port) == 20) { 1388 /* XXX ftp bounce */ 1389 close(ctrl); 1390 continue; 1391 } 1392 } 1393 } else 1394 ctrl = sep->se_fd; 1395 1396 Block_Using_Signals(omask); 1397 pid = 0; 1398 #ifdef INETD_FEATURE_ENABLED 1399 if (sep->se_bi == 0 || sep->se_bi->bi_fork) 1400 #endif 1401 { 1402 if (sep->se_count++ == 0) 1403 (void) gettimeofday(&sep->se_time, NULL); 1404 else if (toomany > 0 && sep->se_count >= sep->se_max) { 1405 struct timeval now; 1406 1407 (void) gettimeofday(&now, NULL); 1408 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { 1409 sep->se_time = now; 1410 sep->se_count = 1; 1411 } else { 1412 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1413 close(ctrl); 1414 if (sep->se_family == AF_INET && 1415 ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) { 1416 /* 1417 * Cannot close it -- there are 1418 * thieves on the system. 1419 * Simply ignore the connection. 1420 */ 1421 --sep->se_count; 1422 continue; 1423 } 1424 bb_error_msg("%s/%s server failing (looping), service terminated", 1425 sep->se_service, sep->se_proto); 1426 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1427 close(ctrl); 1428 FD_CLR(sep->se_fd, &allsock); 1429 (void) close(sep->se_fd); 1430 sep->se_fd = -1; 1431 sep->se_count = 0; 1432 nsock--; 1433 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1434 if (!timingout) { 1435 timingout = 1; 1436 alarm(RETRYTIME); 1437 } 1438 continue; 1439 } 1440 } 1441 pid = fork(); 1415 1442 } 1416 if (ntohs (peer.sin_port) == 20) { 1417 /* XXX ftp bounce */ 1418 close (ctrl); 1419 continue; 1443 if (pid < 0) { 1444 bb_perror_msg("fork"); 1445 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1446 close(ctrl); 1447 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1448 sleep(1); 1449 continue; 1420 1450 } 1421 } 1422 } else 1423 ctrl = sep->se_fd; 1424 Block_Using_Signals(omask); 1425 pid = 0; 1451 if (pid && sep->se_wait) { 1452 sep->se_wait = pid; 1453 FD_CLR(sep->se_fd, &allsock); 1454 nsock--; 1455 } 1456 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1457 if (pid == 0) { 1426 1458 #ifdef INETD_FEATURE_ENABLED 1427 if (sep->se_bi == 0 || sep->se_bi->bi_fork) 1428 #endif 1429 { 1430 if (sep->se_count++ == 0) 1431 (void) gettimeofday (&sep->se_time, NULL); 1432 else if (toomany > 0 && sep->se_count >= sep->se_max) { 1433 struct timeval now; 1434 1435 (void) gettimeofday (&now, NULL); 1436 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { 1437 sep->se_time = now; 1438 sep->se_count = 1; 1439 } else { 1440 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1441 close (ctrl); 1442 if (sep->se_family == AF_INET && 1443 ntohs (sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) { 1444 /* 1445 * Cannot close it -- there are 1446 * thieves on the system. 1447 * Simply ignore the connection. 1448 */ 1449 --sep->se_count; 1450 continue; 1451 } 1452 syslog (LOG_ERR, 1453 "%s/%s server failing (looping), service terminated", 1454 sep->se_service, sep->se_proto); 1455 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1456 close (ctrl); 1457 FD_CLR (sep->se_fd, &allsock); 1458 (void) close (sep->se_fd); 1459 sep->se_fd = -1; 1460 sep->se_count = 0; 1461 nsock--; 1462 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1463 if (!timingout) { 1464 timingout = 1; 1465 alarm (RETRYTIME); 1466 } 1467 continue; 1459 if (sep->se_bi) { 1460 (*sep->se_bi->bi_fn)(ctrl, sep); 1461 } else 1462 #endif 1463 { 1464 pwd = getpwnam(sep->se_user); 1465 if (pwd == NULL) { 1466 bb_error_msg("getpwnam: %s: no such user", sep->se_user); 1467 goto do_exit1; 1468 } 1469 if (setsid() < 0) 1470 bb_perror_msg("%s: setsid", sep->se_service); 1471 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) { 1472 bb_error_msg("getgrnam: %s: no such group", sep->se_group); 1473 goto do_exit1; 1474 } 1475 if (uid != 0) { 1476 /* a user running private inetd */ 1477 if (uid != pwd->pw_uid) 1478 _exit(1); 1479 } else if (pwd->pw_uid) { 1480 if (sep->se_group) 1481 pwd->pw_gid = grp->gr_gid; 1482 xsetgid((gid_t) pwd->pw_gid); 1483 initgroups(pwd->pw_name, pwd->pw_gid); 1484 xsetuid((uid_t) pwd->pw_uid); 1485 } else if (sep->se_group) { 1486 xsetgid(grp->gr_gid); 1487 setgroups(1, &grp->gr_gid); 1488 } 1489 dup2(ctrl, 0); 1490 if (ctrl) close(ctrl); 1491 dup2(0, 1); 1492 dup2(0, 2); 1493 if (rlim_ofile.rlim_cur != rlim_ofile_cur) 1494 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) 1495 bb_perror_msg("setrlimit"); 1496 closelog(); 1497 for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;) 1498 (void) close(tmpint); 1499 sigaction(SIGPIPE, &sapipe, NULL); 1500 execv(sep->se_server, sep->se_argv); 1501 bb_perror_msg("execv %s", sep->se_server); 1502 do_exit1: 1503 if (sep->se_socktype != SOCK_STREAM) 1504 recv(0, buf, sizeof(buf), 0); 1505 _exit(1); 1506 } 1468 1507 } 1469 } 1470 pid = fork (); 1471 } 1472 if (pid < 0) { 1473 syslog (LOG_ERR, "fork: %m"); 1474 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1475 close (ctrl); 1476 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1477 sleep (1); 1478 continue; 1479 } 1480 if (pid && sep->se_wait) { 1481 sep->se_wait = pid; 1482 FD_CLR (sep->se_fd, &allsock); 1483 nsock--; 1484 } 1485 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1486 if (pid == 0) { 1487 #ifdef INETD_FEATURE_ENABLED 1488 if (sep->se_bi) { 1489 (*sep->se_bi->bi_fn) (ctrl, sep); 1490 } else 1491 #endif 1492 { 1493 if ((pwd = getpwnam (sep->se_user)) == NULL) { 1494 syslog (LOG_ERR, "getpwnam: %s: No such user", sep->se_user); 1495 if (sep->se_socktype != SOCK_STREAM) 1496 recv (0, buf, sizeof (buf), 0); 1497 _exit (1); 1498 } 1499 if (setsid () < 0) 1500 syslog (LOG_ERR, "%s: setsid: %m", sep->se_service); 1501 if (sep->se_group && (grp = getgrnam (sep->se_group)) == NULL) { 1502 syslog (LOG_ERR, "getgrnam: %s: No such group", sep->se_group); 1503 if (sep->se_socktype != SOCK_STREAM) 1504 recv (0, buf, sizeof (buf), 0); 1505 _exit (1); 1506 } 1507 if (uid != 0) { 1508 /* a user running private inetd */ 1509 if (uid != pwd->pw_uid) 1510 _exit (1); 1511 } else if (pwd->pw_uid) { 1512 if (sep->se_group) { 1513 pwd->pw_gid = grp->gr_gid; 1514 } 1515 xsetgid ((gid_t) pwd->pw_gid); 1516 initgroups (pwd->pw_name, pwd->pw_gid); 1517 xsetuid((uid_t) pwd->pw_uid); 1518 } else if (sep->se_group) { 1519 xsetgid(grp->gr_gid); 1520 setgroups (1, &grp->gr_gid); 1521 } 1522 dup2 (ctrl, 0); 1523 close (ctrl); 1524 dup2 (0, 1); 1525 dup2 (0, 2); 1526 if (rlim_ofile.rlim_cur != rlim_ofile_cur) 1527 if (setrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) 1528 syslog (LOG_ERR, "setrlimit: %m"); 1529 closelog (); 1530 for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;) 1531 (void) close (tmpint); 1532 sigaction (SIGPIPE, &sapipe, NULL); 1533 execv (sep->se_server, sep->se_argv); 1534 if (sep->se_socktype != SOCK_STREAM) 1535 recv (0, buf, sizeof (buf), 0); 1536 syslog (LOG_ERR, "execv %s: %m", sep->se_server); 1537 _exit (1); 1538 } 1539 } 1540 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1541 close (ctrl); 1542 } 1543 } 1508 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1509 close(ctrl); 1510 } /* for (sep = servtab...) */ 1511 } /* for (;;) */ 1544 1512 } 1545 1513 … … 1549 1517 #define BUFSIZE 4096 1550 1518 1551 #if defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO)|| \1552 defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN)|| \1553 defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME) 1554 static int dg_badinput 1555 { 1556 if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)1557 return (1);1558 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))1559 return (1);1560 1561 return (0);1562 } 1563 #endif 1564 1565 #if def CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO1519 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \ 1520 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \ 1521 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1522 static int dg_badinput(struct sockaddr_in *dg_sin) 1523 { 1524 if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED) 1525 return 1; 1526 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST)) 1527 return 1; 1528 /* XXX compare against broadcast addresses in SIOCGIFCONF list? */ 1529 return 0; 1530 } 1531 #endif 1532 1533 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1566 1534 /* Echo service -- echo data back */ 1567 1535 /* ARGSUSED */ 1568 1536 static void 1569 echo_stream (int s, servtab_t *sep) 1570 { 1571 char buffer[BUFSIZE]; 1572 int i; 1573 1574 inetd_setproctitle (sep->se_service, s); 1575 while ((i = read (s, buffer, sizeof (buffer))) > 0 && 1576 write (s, buffer, i) > 0); 1577 exit (0); 1537 echo_stream(int s, servtab_t *sep) 1538 { 1539 char buffer[BUFSIZE]; 1540 int i; 1541 1542 inetd_setproctitle(sep->se_service, s); 1543 while (1) { 1544 i = read(s, buffer, sizeof(buffer)); 1545 if (i <= 0) break; 1546 /* FIXME: this isnt correct - safe_write()? */ 1547 if (write(s, buffer, i) <= 0) break; 1548 } 1549 exit(0); 1578 1550 } 1579 1551 … … 1581 1553 /* ARGSUSED */ 1582 1554 static void 1583 echo_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED) 1584 { 1585 char buffer[BUFSIZE]; 1586 int i; 1587 socklen_t size; 1588 /* struct sockaddr_storage ss; */ 1589 struct sockaddr sa; 1590 1591 size = sizeof (sa); 1592 if ((i = recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size)) < 0) 1593 return; 1594 if (dg_badinput ((struct sockaddr_in *) &sa)) 1595 return; 1596 (void) sendto (s, buffer, i, 0, &sa, sizeof (sa)); 1597 } 1598 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO */ 1599 1600 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1555 echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1556 { 1557 char buffer[BUFSIZE]; 1558 int i; 1559 socklen_t size; 1560 /* struct sockaddr_storage ss; */ 1561 struct sockaddr sa; 1562 1563 size = sizeof(sa); 1564 i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size); 1565 if (i < 0) 1566 return; 1567 if (dg_badinput((struct sockaddr_in *) &sa)) 1568 return; 1569 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 1570 } 1571 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */ 1572 1573 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1601 1574 /* Discard service -- ignore data */ 1602 1575 /* ARGSUSED */ 1603 1576 static void 1604 discard_stream (int s, servtab_t *sep) 1605 { 1606 char buffer[BUFSIZE]; 1607 1608 inetd_setproctitle (sep->se_service, s); 1609 while ((errno = 0, read (s, buffer, sizeof (buffer)) > 0) || 1610 errno == EINTR); 1611 exit (0); 1577 discard_stream(int s, servtab_t *sep) 1578 { 1579 char buffer[BUFSIZE]; 1580 1581 inetd_setproctitle(sep->se_service, s); 1582 while (1) { 1583 errno = 0; 1584 if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR) 1585 exit(0); 1586 } 1612 1587 } 1613 1588 … … 1615 1590 /* ARGSUSED */ 1616 1591 static void 1617 discard_dg 1618 { 1619 1620 1621 (void) read (s, buffer, sizeof(buffer));1622 } 1623 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */1624 1625 1626 #if def CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN1592 discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1593 { 1594 char buffer[BUFSIZE]; 1595 1596 (void) read(s, buffer, sizeof(buffer)); 1597 } 1598 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */ 1599 1600 1601 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1627 1602 #define LINESIZ 72 1628 1603 static char ring[128]; … … 1630 1605 1631 1606 static void 1632 initring 1633 { 1634 1635 1636 1637 1638 1639 if (isprint(i))1640 1607 initring(void) 1608 { 1609 int i; 1610 1611 endring = ring; 1612 1613 for (i = 0; i <= 128; ++i) 1614 if (isprint(i)) 1615 *endring++ = i; 1641 1616 } 1642 1617 … … 1644 1619 /* ARGSUSED */ 1645 1620 static void 1646 chargen_stream (int s, servtab_t *sep) 1647 { 1648 char *rs; 1649 int len; 1650 char text[LINESIZ + 2]; 1651 1652 inetd_setproctitle (sep->se_service, s); 1653 1654 if (!endring) { 1655 initring (); 1621 chargen_stream(int s, servtab_t *sep) 1622 { 1623 char *rs; 1624 int len; 1625 char text[LINESIZ + 2]; 1626 1627 inetd_setproctitle(sep->se_service, s); 1628 1629 if (!endring) { 1630 initring(); 1631 rs = ring; 1632 } 1633 1634 text[LINESIZ] = '\r'; 1635 text[LINESIZ + 1] = '\n'; 1656 1636 rs = ring; 1657 } 1658 1659 text[LINESIZ] = '\r'; 1660 text[LINESIZ + 1] = '\n'; 1661 for (rs = ring;;) { 1662 if ((len = endring - rs) >= LINESIZ) 1663 memmove (text, rs, LINESIZ); 1664 else { 1665 memmove (text, rs, len); 1666 memmove (text + len, ring, LINESIZ - len); 1667 } 1668 if (++rs == endring) 1669 rs = ring; 1670 if (write (s, text, sizeof (text)) != sizeof (text)) 1671 break; 1672 } 1673 exit (0); 1637 for (;;) { 1638 len = endring - rs; 1639 if (len >= LINESIZ) 1640 memmove(text, rs, LINESIZ); 1641 else { 1642 memmove(text, rs, len); 1643 memmove(text + len, ring, LINESIZ - len); 1644 } 1645 if (++rs == endring) 1646 rs = ring; 1647 if (write(s, text, sizeof(text)) != sizeof(text)) 1648 break; 1649 } 1650 exit(0); 1674 1651 } 1675 1652 … … 1677 1654 /* ARGSUSED */ 1678 1655 static void 1679 chargen_dg 1680 { 1681 1682 1683 1684 1685 1686 1687 1688 1689 initring();1690 rs = ring;1691 1692 1693 size = sizeof(sa);1694 if (recvfrom (s, text, sizeof(text), 0, &sa, &size) < 0)1695 return;1696 if (dg_badinput((struct sockaddr_in *) &sa))1697 return;1698 1699 1700 memmove(text, rs, LINESIZ);1701 1702 memmove(text, rs, len);1703 memmove(text + len, ring, LINESIZ - len);1704 1705 1706 rs = ring;1707 1708 1709 (void) sendto (s, text, sizeof (text), 0, &sa, sizeof(sa));1710 } 1711 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */1712 1713 1714 #if def CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME1656 chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1657 { 1658 /* struct sockaddr_storage ss; */ 1659 struct sockaddr sa; 1660 static char *rs; 1661 int len; 1662 char text[LINESIZ + 2]; 1663 socklen_t size; 1664 1665 if (endring == 0) { 1666 initring(); 1667 rs = ring; 1668 } 1669 1670 size = sizeof(sa); 1671 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 1672 return; 1673 if (dg_badinput((struct sockaddr_in *) &sa)) 1674 return; 1675 1676 if ((len = endring - rs) >= LINESIZ) 1677 memmove(text, rs, LINESIZ); 1678 else { 1679 memmove(text, rs, len); 1680 memmove(text + len, ring, LINESIZ - len); 1681 } 1682 if (++rs == endring) 1683 rs = ring; 1684 text[LINESIZ] = '\r'; 1685 text[LINESIZ + 1] = '\n'; 1686 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 1687 } 1688 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */ 1689 1690 1691 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1715 1692 /* 1716 1693 * Return a machine readable date and time, in the form of the … … 1721 1698 */ 1722 1699 1723 static u _int machtime(void)1724 { 1725 1726 1727 if (gettimeofday(&tv, NULL) < 0) {1728 fprintf(stderr, "Unable to get time of day\n");1729 return (0L);1730 1731 return (htonl ((u_int) tv.tv_sec + 2208988800UL));1700 static unsigned machtime(void) 1701 { 1702 struct timeval tv; 1703 1704 if (gettimeofday(&tv, NULL) < 0) { 1705 fprintf(stderr, "Unable to get time of day\n"); 1706 return 0L; 1707 } 1708 return htonl((unsigned) tv.tv_sec + 2208988800UL); 1732 1709 } 1733 1710 1734 1711 /* ARGSUSED */ 1735 1712 static void 1736 machtime_stream 1737 { 1738 u_intresult;1739 1740 result = machtime();1741 (void) write (s, (char *) &result, sizeof(result));1713 machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1714 { 1715 unsigned result; 1716 1717 result = machtime(); 1718 (void) write(s, (char *) &result, sizeof(result)); 1742 1719 } 1743 1720 1744 1721 /* ARGSUSED */ 1745 1722 static void 1746 machtime_dg 1747 { 1748 u_intresult;1749 1750 1751 1752 1753 1754 size = sizeof(sa);1755 if (recvfrom (s, (char *) &result, sizeof(result), 0, &sa, &size) < 0)1756 return;1757 1758 1759 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||1760 ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2)1761 return;1762 result = machtime();1763 (void) sendto (s, (char *) &result, sizeof (result), 0, &sa, sizeof(sa));1764 } 1765 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME */1766 1767 1768 #if def CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME1723 machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1724 { 1725 unsigned result; 1726 /* struct sockaddr_storage ss; */ 1727 struct sockaddr sa; 1728 struct sockaddr_in *dg_sin; 1729 socklen_t size; 1730 1731 size = sizeof(sa); 1732 if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0) 1733 return; 1734 /* if (dg_badinput((struct sockaddr *)&ss)) */ 1735 dg_sin = (struct sockaddr_in *) &sa; 1736 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) || 1737 ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2) 1738 return; 1739 result = machtime(); 1740 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 1741 } 1742 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */ 1743 1744 1745 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1769 1746 /* Return human-readable time of day */ 1770 1747 /* ARGSUSED */ 1771 static void daytime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED) 1772 { 1773 char buffer[256]; 1774 time_t t; 1775 1776 t = time (NULL); 1777 1778 (void) sprintf (buffer, "%.24s\r\n", ctime (&t)); 1779 (void) write (s, buffer, strlen (buffer)); 1748 static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1749 { 1750 char buffer[32]; 1751 time_t t; 1752 1753 t = time(NULL); 1754 1755 // fdprintf instead? 1756 (void) sprintf(buffer, "%.24s\r\n", ctime(&t)); 1757 (void) write(s, buffer, strlen(buffer)); 1780 1758 } 1781 1759 … … 1783 1761 /* ARGSUSED */ 1784 1762 void 1785 daytime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED) 1786 { 1787 char buffer[256]; 1788 time_t t; 1789 /* struct sockaddr_storage ss; */ 1790 struct sockaddr sa; 1791 socklen_t size; 1792 1793 t = time ((time_t *) 0); 1794 1795 size = sizeof (sa); 1796 if (recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size) < 0) 1797 return; 1798 if (dg_badinput ((struct sockaddr_in *) &sa)) 1799 return; 1800 (void) sprintf (buffer, "%.24s\r\n", ctime (&t)); 1801 (void) sendto (s, buffer, strlen (buffer), 0, &sa, sizeof (sa)); 1802 } 1803 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */ 1804 /* vi: set sw=4 ts=4: */ 1763 daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1764 { 1765 char buffer[256]; 1766 time_t t; 1767 /* struct sockaddr_storage ss; */ 1768 struct sockaddr sa; 1769 socklen_t size; 1770 1771 t = time(NULL); 1772 1773 size = sizeof(sa); 1774 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 1775 return; 1776 if (dg_badinput((struct sockaddr_in *) &sa)) 1777 return; 1778 (void) sprintf(buffer, "%.24s\r\n", ctime(&t)); 1779 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 1780 } 1781 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
Note:
See TracChangeset
for help on using the changeset viewer.