Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking/inetd.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/networking/inetd.c
r1772 r2725 4 4 /* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */ 5 5 /* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */ 6 /* IPv6 support, many bug fixes by Denys Vlasenko (c) 2008 */ 6 7 /* 7 8 * Copyright (c) 1983,1991 The Regents of the University of California. … … 39 40 /* Inetd - Internet super-server 40 41 * 41 * This program invokes all internet services as needed. 42 * connection-oriented services are invoked each time a 42 * This program invokes configured services when a connection 43 * from a peer is established or a datagram arrives. 44 * Connection-oriented services are invoked each time a 43 45 * connection is made, by creating a process. This process 44 46 * is passed the connection as file descriptor 0 and is 45 * expected to do a getpeername to find out the sourcehost47 * expected to do a getpeername to find out peer's host 46 48 * and port. 47 *48 49 * Datagram oriented services are invoked when a datagram 49 50 * arrives; a process is created and passed a pending message 50 * on file descriptor 0. Datagram servers may either connect 51 * to their peer, freeing up the original socket for inetd 52 * to receive further messages on, or "take over the socket", 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". 51 * on file descriptor 0. peer's address can be obtained 52 * using recvfrom. 56 53 * 57 54 * Inetd uses a configuration file which is read at startup … … 61 58 * a space or tab. All fields must be present in each entry. 62 59 * 63 * service 64 * socket 60 * service_name must be in /etc/services 61 * socket_type stream/dgram/raw/rdm/seqpacket 65 62 * protocol must be in /etc/protocols 63 * (usually "tcp" or "udp") 66 64 * wait/nowait[.max] single-threaded/multi-threaded, max # 67 65 * user[.group] or user[:group] user/group to run daemon as 68 * server 69 * server programarguments maximum of MAXARGS (20)66 * server_program full path name 67 * server_program_arguments maximum of MAXARGS (20) 70 68 * 71 69 * For RPC services 72 * service 73 * socket 74 * protocol must be in /etc/protocols70 * service_name/version must be in /etc/rpc 71 * socket_type stream/dgram/raw/rdm/seqpacket 72 * rpc/protocol "rpc/tcp" etc 75 73 * wait/nowait[.max] single-threaded/multi-threaded 76 74 * user[.group] or user[:group] user to run daemon as 77 * server 78 * server programarguments maximum of MAXARGS (20)75 * server_program full path name 76 * server_program_arguments maximum of MAXARGS (20) 79 77 * 80 78 * For non-RPC services, the "service name" can be of the form 81 79 * hostaddress:servicename, in which case the hostaddress is used 82 80 * as the host portion of the address to listen on. If hostaddress 83 * consists of a single `*' character, INADDR_ANY is used.81 * consists of a single '*' character, INADDR_ANY is used. 84 82 * 85 83 * A line can also consist of just … … 102 100 * specifiers are different. 103 101 * 104 * Comment lines are indicated by a `#' in column 1.102 * Comment lines are indicated by a '#' in column 1. 105 103 */ 106 104 … … 121 119 * for new service requests to spawn new servers. Datagram servers which 122 120 * 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)121 * said to be "single-threaded". The comsat(8), biff(1) and talkd(8) 124 122 * utilities are both examples of the latter type of datagram server. The 125 123 * tftpd(8) utility is an example of a multi-threaded datagram server. … … 135 133 */ 136 134 137 /* Here's the scoop concerning the user[.:]group feature: 138 * 139 * 1) set-group-option off. 140 * 135 /* Despite of above doc saying that dgram services must use "wait", 136 * "udp nowait" servers are implemented in busyboxed inetd. 137 * IPv6 addresses are also implemented. However, they may look ugly - 138 * ":::service..." means "address '::' (IPv6 wildcard addr)":"service"... 139 * You have to put "tcp6"/"udp6" in protocol field to select IPv6. 140 */ 141 142 /* Here's the scoop concerning the user[:group] feature: 143 * 1) group is not specified: 141 144 * a) user = root: NO setuid() or setgid() is done 142 * 143 * b) other: setgid(primary group as found in passwd) 144 * initgroups(name, primary group) 145 * b) other: initgroups(name, primary group) 146 * setgid(primary group as found in passwd) 145 147 * setuid() 146 * 147 * 2) set-group-option on. 148 * 148 * 2) group is specified: 149 149 * a) user = root: setgid(specified group) 150 150 * NO initgroups() 151 151 * NO setuid() 152 * 153 * b) other: setgid(specified group) 154 * initgroups(name, specified group) 152 * b) other: initgroups(name, specified group) 153 * setgid(specified group) 155 154 * setuid() 156 155 */ 157 156 158 #include "libbb.h"159 157 #include <syslog.h> 160 158 #include <sys/un.h> 161 159 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 160 #include "libbb.h" 169 161 170 162 #if ENABLE_FEATURE_INETD_RPC … … 173 165 #endif 174 166 175 extern char **environ; 176 167 #if !BB_MMU 168 /* stream version of chargen is forking but not execing, 169 * can't do that (easily) on NOMMU */ 170 #undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 171 #define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0 172 #endif 177 173 178 174 #define _PATH_INETDPID "/var/run/inetd.pid" 179 175 180 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 181 #define RETRYTIME (60*10) /* retry after bind or server fail */ 176 #define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */ 177 #define RETRYTIME 60 /* retry after bind or server fail */ 178 179 // TODO: explain, or get rid of setrlimit games 182 180 183 181 #ifndef RLIMIT_NOFILE … … 191 189 /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */ 192 190 #define FD_MARGIN 8 193 static rlim_t rlim_ofile_cur = OPEN_MAX; 194 static struct rlimit rlim_ofile; 195 196 197 /* Check unsupporting builtin */ 198 #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 203 # define INETD_FEATURE_ENABLED 204 #endif 205 206 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \ 207 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \ 208 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 209 # define INETD_SETPROCTITLE 210 #endif 211 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 */ 191 192 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD \ 193 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO \ 194 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN \ 195 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME \ 196 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 197 # define INETD_BUILTINS_ENABLED 198 #endif 199 200 typedef struct servtab_t { 201 /* The most frequently referenced one: */ 202 int se_fd; /* open descriptor */ 203 /* NB: 'biggest fields last' saves on code size (~250 bytes) */ 204 /* [addr:]service socktype proto wait user[:group] prog [args] */ 205 char *se_local_hostname; /* addr to listen on */ 206 char *se_service; /* "80" or "www" or "mount/2[-3]" */ 207 /* socktype is in se_socktype */ /* "stream" "dgram" "raw" "rdm" "seqpacket" */ 208 char *se_proto; /* "unix" or "[rpc/]tcp[6]" */ 218 209 #if ENABLE_FEATURE_INETD_RPC 219 210 int se_rpcprog; /* rpc program number */ 220 int se_rpcver sl;/* rpc program lowest version */221 int se_rpcver sh;/* rpc program highest version */222 #define is rpcservice(sep) ((sep)->se_rpcversl!= 0)211 int se_rpcver_lo; /* rpc program lowest version */ 212 int se_rpcver_hi; /* rpc program highest version */ 213 #define is_rpc_service(sep) ((sep)->se_rpcver_lo != 0) 223 214 #else 224 #define isrpcservice(sep) 0 225 #endif 226 pid_t se_wait; /* single threaded server */ 227 short se_checked; /* looked at during merge */ 215 #define is_rpc_service(sep) 0 216 #endif 217 pid_t se_wait; /* 0:"nowait", 1:"wait", >1:"wait" */ 218 /* and waiting for this pid */ 219 socktype_t se_socktype; /* SOCK_STREAM/DGRAM/RDM/... */ 220 family_t se_family; /* AF_UNIX/INET[6] */ 221 /* se_proto_no is used by RPC code only... hmm */ 222 smallint se_proto_no; /* IPPROTO_TCP/UDP, n/a for AF_UNIX */ 223 smallint se_checked; /* looked at during merge */ 224 unsigned se_max; /* allowed instances per minute */ 225 unsigned se_count; /* number started since se_time */ 226 unsigned se_time; /* when we started counting */ 228 227 char *se_user; /* user name to run as */ 229 char *se_group; /* group name to run as */ 230 #ifdef INETD_FEATURE_ENABLED 231 const struct builtin *se_bi; /* if built-in, description */ 232 #endif 233 char *se_server; /* server program */ 228 char *se_group; /* group name to run as, can be NULL */ 229 #ifdef INETD_BUILTINS_ENABLED 230 const struct builtin *se_builtin; /* if built-in, description */ 231 #endif 232 struct servtab_t *se_next; 233 len_and_sockaddr *se_lsa; 234 char *se_program; /* server program */ 234 235 #define MAXARGV 20 235 236 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_IPV6241 struct sockaddr_in6 se_un_ctrladdr_in6;242 #endif243 struct sockaddr_un se_un_ctrladdr_un;244 } se_un; /* bound address */245 #define se_ctrladdr se_un.se_un_ctrladdr246 #define se_ctrladdr_in se_un.se_un_ctrladdr_in247 #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6248 #define se_ctrladdr_un se_un.se_un_ctrladdr_un249 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;254 237 } servtab_t; 255 238 256 static servtab_t *servtab; 257 258 #ifdef INETD_FEATURE_ENABLED 239 #ifdef INETD_BUILTINS_ENABLED 240 /* Echo received data */ 241 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 242 static void FAST_FUNC echo_stream(int, servtab_t *); 243 static void FAST_FUNC echo_dg(int, servtab_t *); 244 #endif 245 /* Internet /dev/null */ 246 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 247 static void FAST_FUNC discard_stream(int, servtab_t *); 248 static void FAST_FUNC discard_dg(int, servtab_t *); 249 #endif 250 /* Return 32 bit time since 1900 */ 251 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 252 static void FAST_FUNC machtime_stream(int, servtab_t *); 253 static void FAST_FUNC machtime_dg(int, servtab_t *); 254 #endif 255 /* Return human-readable time */ 256 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 257 static void FAST_FUNC daytime_stream(int, servtab_t *); 258 static void FAST_FUNC daytime_dg(int, servtab_t *); 259 #endif 260 /* Familiar character generator */ 261 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 262 static void FAST_FUNC chargen_stream(int, servtab_t *); 263 static void FAST_FUNC chargen_dg(int, servtab_t *); 264 #endif 265 259 266 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 *);267 /* NB: not necessarily NUL terminated */ 268 char bi_service7[7]; /* internally provided service name */ 269 uint8_t bi_fork; /* 1 if stream fn should run in child */ 270 void (*bi_stream_fn)(int, servtab_t *) FAST_FUNC; 271 void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC; 265 272 }; 266 267 /* Echo received data */268 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO269 static void echo_stream(int, servtab_t *);270 static void echo_dg(int, servtab_t *);271 #endif272 /* Internet /dev/null */273 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD274 static void discard_stream(int, servtab_t *);275 static void discard_dg(int, servtab_t *);276 #endif277 /* Return 32 bit time since 1900 */278 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME279 static void machtime_stream(int, servtab_t *);280 static void machtime_dg(int, servtab_t *);281 #endif282 /* Return human-readable time */283 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME284 static void daytime_stream(int, servtab_t *);285 static void daytime_dg(int, servtab_t *);286 #endif287 /* Familiar character generator */288 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN289 static void chargen_stream(int, servtab_t *);290 static void chargen_dg(int, servtab_t *);291 #endif292 273 293 274 static const struct builtin builtins[] = { 294 275 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 295 /* Echo received data */ 296 {"echo", SOCK_STREAM, 1, 0, echo_stream,}, 297 {"echo", SOCK_DGRAM, 0, 0, echo_dg,}, 276 { "echo", 1, echo_stream, echo_dg }, 298 277 #endif 299 278 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 300 /* Internet /dev/null */ 301 {"discard", SOCK_STREAM, 1, 0, discard_stream,}, 302 {"discard", SOCK_DGRAM, 0, 0, discard_dg,}, 279 { "discard", 1, discard_stream, discard_dg }, 280 #endif 281 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 282 { "chargen", 1, chargen_stream, chargen_dg }, 303 283 #endif 304 284 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 305 /* Return 32 bit time since 1900 */ 306 {"time", SOCK_STREAM, 0, 0, machtime_stream,}, 307 {"time", SOCK_DGRAM, 0, 0, machtime_dg,}, 285 { "time", 0, machtime_stream, machtime_dg }, 308 286 #endif 309 287 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 310 /* Return human-readable time */ 311 {"daytime", SOCK_STREAM, 0, 0, daytime_stream,}, 312 {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,}, 313 #endif 288 { "daytime", 0, daytime_stream, daytime_dg }, 289 #endif 290 }; 291 #endif /* INETD_BUILTINS_ENABLED */ 292 293 struct globals { 294 rlim_t rlim_ofile_cur; 295 struct rlimit rlim_ofile; 296 servtab_t *serv_list; 297 int global_queuelen; 298 int maxsock; /* max fd# in allsock, -1: unknown */ 299 /* whenever maxsock grows, prev_maxsock is set to new maxsock, 300 * but if maxsock is set to -1, prev_maxsock is not changed */ 301 int prev_maxsock; 302 unsigned max_concurrency; 303 smallint alarm_armed; 304 uid_t real_uid; /* user ID who ran us */ 305 const char *config_filename; 306 parser_t *parser; 307 char *default_local_hostname; 314 308 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 315 /* Familiar character generator */ 316 {"chargen", SOCK_STREAM, 1, 0, chargen_stream,}, 317 {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,}, 318 #endif 319 {NULL, 0, 0, 0, NULL} 309 char *end_ring; 310 char *ring_pos; 311 char ring[128]; 312 #endif 313 fd_set allsock; 314 /* Used in next_line(), and as scratch read buffer */ 315 char line[256]; /* _at least_ 256, see LINE_SIZE */ 316 } FIX_ALIASING; 317 #define G (*(struct globals*)&bb_common_bufsiz1) 318 enum { LINE_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line) }; 319 struct BUG_G_too_big { 320 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; 320 321 }; 321 #endif /* INETD_FEATURE_ENABLED */ 322 323 static int global_queuelen = 128; 324 static int nsock, maxsock; 325 static fd_set allsock; 326 static int toomany; 327 static int timingout; 328 static struct servent *sp; 329 static uid_t uid; 330 331 static const char *config_filename = "/etc/inetd.conf"; 332 333 static FILE *fconfig; 334 static char *defhost; 335 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; 322 #define rlim_ofile_cur (G.rlim_ofile_cur ) 323 #define rlim_ofile (G.rlim_ofile ) 324 #define serv_list (G.serv_list ) 325 #define global_queuelen (G.global_queuelen) 326 #define maxsock (G.maxsock ) 327 #define prev_maxsock (G.prev_maxsock ) 328 #define max_concurrency (G.max_concurrency) 329 #define alarm_armed (G.alarm_armed ) 330 #define real_uid (G.real_uid ) 331 #define config_filename (G.config_filename) 332 #define parser (G.parser ) 333 #define default_local_hostname (G.default_local_hostname) 334 #define first_ps_byte (G.first_ps_byte ) 335 #define last_ps_byte (G.last_ps_byte ) 336 #define end_ring (G.end_ring ) 337 #define ring_pos (G.ring_pos ) 338 #define ring (G.ring ) 339 #define allsock (G.allsock ) 340 #define line (G.line ) 341 #define INIT_G() do { \ 342 rlim_ofile_cur = OPEN_MAX; \ 343 global_queuelen = 128; \ 344 config_filename = "/etc/inetd.conf"; \ 345 } while (0) 346 347 static void maybe_close(int fd) 348 { 349 if (fd >= 0) 350 close(fd); 351 } 352 353 // TODO: move to libbb? 354 static len_and_sockaddr *xzalloc_lsa(int family) 355 { 356 len_and_sockaddr *lsa; 357 int sz; 358 359 sz = sizeof(struct sockaddr_in); 360 if (family == AF_UNIX) 361 sz = sizeof(struct sockaddr_un); 362 #if ENABLE_FEATURE_IPV6 363 if (family == AF_INET6) 364 sz = sizeof(struct sockaddr_in6); 365 #endif 366 lsa = xzalloc(LSA_LEN_SIZE + sz); 367 lsa->len = sz; 368 lsa->u.sa.sa_family = family; 369 return lsa; 370 } 371 372 static void rearm_alarm(void) 373 { 374 if (!alarm_armed) { 375 alarm_armed = 1; 376 alarm(RETRYTIME); 377 } 378 } 379 380 static void block_CHLD_HUP_ALRM(sigset_t *m) 381 { 382 sigemptyset(m); 383 sigaddset(m, SIGCHLD); 384 sigaddset(m, SIGHUP); 385 sigaddset(m, SIGALRM); 386 sigprocmask(SIG_BLOCK, m, m); /* old sigmask is stored in m */ 387 } 388 389 static void restore_sigmask(sigset_t *m) 390 { 391 sigprocmask(SIG_SETMASK, m, NULL); 365 392 } 366 393 … … 370 397 int n; 371 398 struct sockaddr_in ir_sin; 372 struct protoent *pp;373 399 socklen_t size; 374 400 375 if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) { 376 bb_perror_msg("%s: getproto", sep->se_proto); 401 size = sizeof(ir_sin); 402 if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) { 403 bb_perror_msg("getsockname"); 377 404 return; 378 405 } 379 size = sizeof ir_sin; 380 if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) { 381 bb_perror_msg("%s/%s: getsockname", 406 407 for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) { 408 pmap_unset(sep->se_rpcprog, n); 409 if (!pmap_set(sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port))) 410 bb_perror_msg("%s %s: pmap_set(%u,%u,%u,%u)", 411 sep->se_service, sep->se_proto, 412 sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port)); 413 } 414 } 415 416 static void unregister_rpc(servtab_t *sep) 417 { 418 int n; 419 420 for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) { 421 if (!pmap_unset(sep->se_rpcprog, n)) 422 bb_perror_msg("pmap_unset(%u,%u)", sep->se_rpcprog, n); 423 } 424 } 425 #endif /* FEATURE_INETD_RPC */ 426 427 static void bump_nofile(void) 428 { 429 enum { FD_CHUNK = 32 }; 430 struct rlimit rl; 431 432 /* Never fails under Linux (except if you pass it bad arguments) */ 433 getrlimit(RLIMIT_NOFILE, &rl); 434 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK); 435 rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK); 436 if (rl.rlim_cur <= rlim_ofile_cur) { 437 bb_error_msg("can't extend file limit, max = %d", 438 (int) rl.rlim_cur); 439 return; 440 } 441 442 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { 443 bb_perror_msg("setrlimit"); 444 return; 445 } 446 447 rlim_ofile_cur = rl.rlim_cur; 448 } 449 450 static void remove_fd_from_set(int fd) 451 { 452 if (fd >= 0) { 453 FD_CLR(fd, &allsock); 454 maxsock = -1; 455 } 456 } 457 458 static void add_fd_to_set(int fd) 459 { 460 if (fd >= 0) { 461 FD_SET(fd, &allsock); 462 if (maxsock >= 0 && fd > maxsock) { 463 prev_maxsock = maxsock = fd; 464 if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) 465 bump_nofile(); 466 } 467 } 468 } 469 470 static void recalculate_maxsock(void) 471 { 472 int fd = 0; 473 474 /* We may have no services, in this case maxsock should still be >= 0 475 * (code elsewhere is not happy with maxsock == -1) */ 476 maxsock = 0; 477 while (fd <= prev_maxsock) { 478 if (FD_ISSET(fd, &allsock)) 479 maxsock = fd; 480 fd++; 481 } 482 prev_maxsock = maxsock; 483 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) 484 bump_nofile(); 485 } 486 487 static void prepare_socket_fd(servtab_t *sep) 488 { 489 int r, fd; 490 491 fd = socket(sep->se_family, sep->se_socktype, 0); 492 if (fd < 0) { 493 bb_perror_msg("socket"); 494 return; 495 } 496 setsockopt_reuseaddr(fd); 497 498 #if ENABLE_FEATURE_INETD_RPC 499 if (is_rpc_service(sep)) { 500 struct passwd *pwd; 501 502 /* zero out the port for all RPC services; let bind() 503 * find one. */ 504 set_nport(sep->se_lsa, 0); 505 506 /* for RPC services, attempt to use a reserved port 507 * if they are going to be running as root. */ 508 if (real_uid == 0 && sep->se_family == AF_INET 509 && (pwd = getpwnam(sep->se_user)) != NULL 510 && pwd->pw_uid == 0 511 ) { 512 r = bindresvport(fd, &sep->se_lsa->u.sin); 513 } else { 514 r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len); 515 } 516 if (r == 0) { 517 int saveerrno = errno; 518 /* update lsa with port# */ 519 getsockname(fd, &sep->se_lsa->u.sa, &sep->se_lsa->len); 520 errno = saveerrno; 521 } 522 } else 523 #endif 524 { 525 if (sep->se_family == AF_UNIX) { 526 struct sockaddr_un *sun; 527 sun = (struct sockaddr_un*)&(sep->se_lsa->u.sa); 528 unlink(sun->sun_path); 529 } 530 r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len); 531 } 532 if (r < 0) { 533 bb_perror_msg("%s/%s: bind", 382 534 sep->se_service, sep->se_proto); 535 close(fd); 536 rearm_alarm(); 383 537 return; 384 538 } 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) 539 if (sep->se_socktype == SOCK_STREAM) 540 listen(fd, global_queuelen); 541 542 add_fd_to_set(fd); 543 sep->se_fd = fd; 544 } 545 546 static int reopen_config_file(void) 547 { 548 free(default_local_hostname); 549 default_local_hostname = xstrdup("*"); 550 if (parser != NULL) 551 config_close(parser); 552 parser = config_open(config_filename); 553 return (parser != NULL); 554 } 555 556 static void close_config_file(void) 557 { 558 if (parser) { 559 config_close(parser); 560 parser = NULL; 561 } 562 } 563 564 static void free_servtab_strings(servtab_t *cp) 407 565 { 408 566 int i; 409 567 410 free(cp->se_ hostaddr);568 free(cp->se_local_hostname); 411 569 free(cp->se_service); 412 570 free(cp->se_proto); 413 571 free(cp->se_user); 414 572 free(cp->se_group); 415 free(cp->se_server); 573 free(cp->se_lsa); /* not a string in fact */ 574 free(cp->se_program); 416 575 for (i = 0; i < MAXARGV; i++) 417 576 free(cp->se_argv[i]); 418 577 } 419 578 420 static int bump_nofile(void)421 {422 #define FD_CHUNK 32423 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_RPC459 if (isrpcservice(sep)) {460 struct passwd *pwd;461 462 /*463 * for RPC services, attempt to use a reserved port464 * 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 } else486 #endif487 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_bufsiz1514 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 579 static servtab_t *new_servtab(void) 568 580 { 569 return xmalloc(sizeof(servtab_t)); 570 } 571 572 static servtab_t *dupconfig(servtab_t *sep) 581 servtab_t *newtab = xzalloc(sizeof(servtab_t)); 582 newtab->se_fd = -1; /* paranoia */ 583 return newtab; 584 } 585 586 static servtab_t *dup_servtab(servtab_t *sep) 573 587 { 574 588 servtab_t *newtab; … … 576 590 577 591 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 592 *newtab = *sep; /* struct copy */ 593 /* deep-copying strings */ 594 newtab->se_service = xstrdup(newtab->se_service); 595 newtab->se_proto = xstrdup(newtab->se_proto); 596 newtab->se_user = xstrdup(newtab->se_user); 597 newtab->se_group = xstrdup(newtab->se_group); 598 newtab->se_program = xstrdup(newtab->se_program); 596 599 for (argc = 0; argc <= MAXARGV; argc++) 597 newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]); 598 newtab->se_max = sep->se_max; 600 newtab->se_argv[argc] = xstrdup(newtab->se_argv[argc]); 601 /* NB: se_fd, se_hostaddr and se_next are always 602 * overwrittend by callers, so we don't bother resetting them 603 * to NULL/0/-1 etc */ 599 604 600 605 return newtab; 601 606 } 602 607 603 static servtab_t *getconfigent(void) 604 { 608 /* gcc generates much more code if this is inlined */ 609 static servtab_t *parse_one_line(void) 610 { 611 int argc; 612 char *token[6+MAXARGV]; 613 char *p, *arg; 614 char *hostdelim; 605 615 servtab_t *sep; 606 int argc;607 char *cp, *arg;608 char *hostdelim;609 616 servtab_t *nsep; 610 servtab_t *psep; 611 617 new: 612 618 sep = new_servtab(); 613 614 /* memset(sep, 0, sizeof *sep); */615 619 more: 616 /* freeconfig(sep); */ 617 618 while ((cp = nextline()) && *cp == '#') /* skip comment line */; 619 if (cp == NULL) { 620 /* free(sep); */ 620 argc = config_read(parser, token, 6+MAXARGV, 1, "# \t", PARSE_NORMAL); 621 if (!argc) { 622 free(sep); 621 623 return NULL; 622 624 } 623 625 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. */ 626 /* [host:]service socktype proto wait user[:group] prog [args] */ 627 /* Check for "host:...." line */ 628 arg = token[0]; 632 629 hostdelim = strrchr(arg, ':'); 633 630 if (hostdelim) { 634 631 *hostdelim = '\0'; 635 sep->se_ hostaddr= xstrdup(arg);632 sep->se_local_hostname = xstrdup(arg); 636 633 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 } 634 if (*arg == '\0' && argc == 1) { 635 /* Line has just "host:", change the 636 * default host for the following lines. */ 637 free(default_local_hostname); 638 default_local_hostname = sep->se_local_hostname; 639 goto more; 648 640 } 649 641 } 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) { 642 sep->se_local_hostname = xstrdup(default_local_hostname); 643 644 /* service socktype proto wait user[:group] prog [args] */ 645 sep->se_service = xstrdup(arg); 646 647 /* socktype proto wait user[:group] prog [args] */ 648 if (argc < 6) { 649 parse_err: 650 bb_error_msg("parse error on line %u, line is ignored", 651 parser->lineno); 652 free_servtab_strings(sep); 653 /* Just "goto more" can make sep to carry over e.g. 654 * "rpc"-ness (by having se_rpcver_lo != 0). 655 * We will be more paranoid: */ 656 free(sep); 657 goto new; 658 } 659 660 { 661 static const int8_t SOCK_xxx[] ALIGN1 = { 662 -1, 663 SOCK_STREAM, SOCK_DGRAM, SOCK_RDM, 664 SOCK_SEQPACKET, SOCK_RAW 665 }; 666 sep->se_socktype = SOCK_xxx[1 + index_in_strings( 667 "stream""\0" "dgram""\0" "rdm""\0" 668 "seqpacket""\0" "raw""\0" 669 , token[1])]; 670 } 671 672 /* {unix,[rpc/]{tcp,udp}[6]} wait user[:group] prog [args] */ 673 sep->se_proto = arg = xstrdup(token[2]); 674 if (strcmp(arg, "unix") == 0) { 671 675 sep->se_family = AF_UNIX; 672 676 } else { 677 char *six; 673 678 sep->se_family = AF_INET; 674 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') 679 six = last_char_is(arg, '6'); 680 if (six) { 675 681 #if ENABLE_FEATURE_IPV6 682 *six = '\0'; 676 683 sep->se_family = AF_INET6; 677 684 #else 678 bb_error_msg("%s: IPV6 not supported", sep->se_proto); 679 #endif 680 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 685 bb_error_msg("%s: no support for IPv6", sep->se_proto); 686 goto parse_err; 687 #endif 688 } 689 if (strncmp(arg, "rpc/", 4) == 0) { 681 690 #if ENABLE_FEATURE_INETD_RPC 682 char *p, *ccp; 683 long l; 684 691 unsigned n; 692 arg += 4; 685 693 p = strchr(sep->se_service, '/'); 686 if (p == 0) {687 bb_error_msg(" %s: no rpc version", sep->se_service);688 goto more;694 if (p == NULL) { 695 bb_error_msg("no rpc version: '%s'", sep->se_service); 696 goto parse_err; 689 697 } 690 698 *p++ = '\0'; 691 l = strtol(p, &ccp,0);692 if ( ccp == p || l < 0 || l> INT_MAX) {693 bad afterall:694 bb_error_msg(" %s/%s: bad rpc version", sep->se_service, p);695 goto more;699 n = bb_strtou(p, &p, 10); 700 if (n > INT_MAX) { 701 bad_ver_spec: 702 bb_error_msg("bad rpc version"); 703 goto parse_err; 696 704 } 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; 705 sep->se_rpcver_lo = sep->se_rpcver_hi = n; 706 if (*p == '-') { 707 p++; 708 n = bb_strtou(p, &p, 10); 709 if (n > INT_MAX || (int)n < sep->se_rpcver_lo) 710 goto bad_ver_spec; 711 sep->se_rpcver_hi = n; 712 } 713 if (*p != '\0') 714 goto bad_ver_spec; 706 715 #else 707 bb_error_msg("%s: rpc services not supported", sep->se_service); 716 bb_error_msg("no support for rpc services"); 717 goto parse_err; 708 718 #endif 709 719 } 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)); 720 /* we don't really need getprotobyname()! */ 721 if (strcmp(arg, "tcp") == 0) 722 sep->se_proto_no = IPPROTO_TCP; /* = 6 */ 723 if (strcmp(arg, "udp") == 0) 724 sep->se_proto_no = IPPROTO_UDP; /* = 17 */ 725 if (six) 726 *six = '6'; 727 if (!sep->se_proto_no) /* not tcp/udp?? */ 728 goto parse_err; 729 } 730 731 /* [no]wait[.max] user[:group] prog [args] */ 732 arg = token[3]; 733 sep->se_max = max_concurrency; 734 p = strchr(arg, '.'); 735 if (p) { 736 *p++ = '\0'; 737 sep->se_max = bb_strtou(p, NULL, 10); 738 if (errno) 739 goto parse_err; 740 } 741 sep->se_wait = (arg[0] != 'n' || arg[1] != 'o'); 742 if (!sep->se_wait) /* "no" seen */ 743 arg += 2; 744 if (strcmp(arg, "wait") != 0) 745 goto parse_err; 746 747 /* user[:group] prog [args] */ 748 sep->se_user = xstrdup(token[4]); 727 749 arg = strchr(sep->se_user, '.'); 728 750 if (arg == NULL) … … 732 754 sep->se_group = xstrdup(arg); 733 755 } 734 /* if ((arg = skip(&cp, 1)) == NULL) */ 735 /* goto more; */ 736 737 arg = skip(&cp); 738 sep->se_server = xxstrdup(arg); 739 if (strcmp(sep->se_server, "internal") == 0) { 740 #ifdef INETD_FEATURE_ENABLED 741 const struct builtin *bi; 742 743 for (bi = builtins; bi->bi_service; bi++) 744 if (bi->bi_socktype == sep->se_socktype && 745 strcmp(bi->bi_service, sep->se_service) == 0) 746 break; 747 if (bi->bi_service == 0) { 748 bb_error_msg("internal service %s unknown", sep->se_service); 749 goto more; 750 } 751 sep->se_bi = bi; 752 sep->se_wait = bi->bi_wait; 753 #else 754 bb_perror_msg("internal service %s unknown", sep->se_service); 755 goto more; 756 #endif 757 } 758 #ifdef INETD_FEATURE_ENABLED 759 else 760 sep->se_bi = NULL; 756 757 /* prog [args] */ 758 sep->se_program = xstrdup(token[5]); 759 #ifdef INETD_BUILTINS_ENABLED 760 if (strcmp(sep->se_program, "internal") == 0 761 && strlen(sep->se_service) <= 7 762 && (sep->se_socktype == SOCK_STREAM 763 || sep->se_socktype == SOCK_DGRAM) 764 ) { 765 unsigned i; 766 for (i = 0; i < ARRAY_SIZE(builtins); i++) 767 if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0) 768 goto found_bi; 769 bb_error_msg("unknown internal service %s", sep->se_service); 770 goto parse_err; 771 found_bi: 772 sep->se_builtin = &builtins[i]; 773 /* stream builtins must be "nowait", dgram must be "wait" */ 774 if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM)) 775 goto parse_err; 776 } 761 777 #endif 762 778 argc = 0; 763 for (; cp; arg = skip(&cp)) { 764 if (argc < MAXARGV) 765 sep->se_argv[argc++] = xxstrdup(arg); 766 } 767 while (argc <= MAXARGV) 768 sep->se_argv[argc++] = NULL; 769 770 /* 771 * Now that we've processed the entire line, check if the hostname 772 * specifier was a comma separated list of hostnames. If so 773 * we'll make new entries for each address. 774 */ 775 while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) { 776 nsep = dupconfig(sep); 777 778 /* 779 * NULL terminate the hostname field of the existing entry, 780 * and make a dup for the new entry. 781 */ 779 while ((arg = token[6+argc]) != NULL && argc < MAXARGV) 780 sep->se_argv[argc++] = xstrdup(arg); 781 /* Some inetd.conf files have no argv's, not even argv[0]. 782 * Fix them up. 783 * (Technically, programs can be execed with argv[0] = NULL, 784 * but many programs do not like that at all) */ 785 if (argc == 0) 786 sep->se_argv[0] = xstrdup(sep->se_program); 787 788 /* catch mixups. "<service> stream udp ..." == wtf */ 789 if (sep->se_socktype == SOCK_STREAM) { 790 if (sep->se_proto_no == IPPROTO_UDP) 791 goto parse_err; 792 } 793 if (sep->se_socktype == SOCK_DGRAM) { 794 if (sep->se_proto_no == IPPROTO_TCP) 795 goto parse_err; 796 } 797 798 // bb_info_msg( 799 // "ENTRY[%s][%s][%s][%d][%d][%d][%d][%d][%s][%s][%s]", 800 // sep->se_local_hostname, sep->se_service, sep->se_proto, sep->se_wait, sep->se_proto_no, 801 // sep->se_max, sep->se_count, sep->se_time, sep->se_user, sep->se_group, sep->se_program); 802 803 /* check if the hostname specifier is a comma separated list 804 * of hostnames. we'll make new entries for each address. */ 805 while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) { 806 nsep = dup_servtab(sep); 807 /* NUL terminate the hostname field of the existing entry, 808 * and make a dup for the new entry. */ 782 809 *hostdelim++ = '\0'; 783 nsep->se_hostaddr = xstrdup(hostdelim); 784 810 nsep->se_local_hostname = xstrdup(hostdelim); 785 811 nsep->se_next = sep->se_next; 786 812 sep->se_next = nsep; 787 813 } 788 814 789 nsep = sep; 790 while (nsep != NULL) { 791 nsep->se_checked = 1; 792 if (nsep->se_family == AF_INET) { 793 if (LONE_CHAR(nsep->se_hostaddr, '*')) 794 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY; 795 else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) { 796 struct hostent *hp; 797 798 hp = gethostbyname(nsep->se_hostaddr); 799 if (hp == 0) { 800 bb_error_msg("%s: unknown host", nsep->se_hostaddr); 801 nsep->se_checked = 0; 802 goto skip; 803 } else if (hp->h_addrtype != AF_INET) { 804 bb_error_msg("%s: address isn't an Internet " 805 "address", nsep->se_hostaddr); 806 nsep->se_checked = 0; 807 goto skip; 808 } else { 809 int i = 1; 810 811 memmove(&nsep->se_ctrladdr_in.sin_addr, 812 hp->h_addr_list[0], sizeof(struct in_addr)); 813 while (hp->h_addr_list[i] != NULL) { 814 psep = dupconfig(nsep); 815 psep->se_hostaddr = xxstrdup(nsep->se_hostaddr); 816 psep->se_checked = 1; 817 memmove(&psep->se_ctrladdr_in.sin_addr, 818 hp->h_addr_list[i], sizeof(struct in_addr)); 819 psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in); 820 i++; 821 /* Prepend to list, don't want to look up */ 822 /* its hostname again. */ 823 psep->se_next = sep; 824 sep = psep; 825 } 826 } 827 } 828 } 829 /* XXX BUG?: is this skip: label supposed to remain? */ 830 skip: 831 nsep = nsep->se_next; 832 } 833 834 /* 835 * Finally, free any entries which failed the gethostbyname 836 * check. 837 */ 838 psep = NULL; 839 nsep = sep; 840 while (nsep != NULL) { 841 servtab_t *tsep; 842 843 if (nsep->se_checked == 0) { 844 tsep = nsep; 845 if (psep == NULL) { 846 sep = nsep->se_next; 847 nsep = sep; 848 } else { 849 nsep = nsep->se_next; 850 psep->se_next = nsep; 851 } 852 freeconfig(tsep); 853 } else { 854 nsep->se_checked = 0; 855 psep = nsep; 856 nsep = nsep->se_next; 857 } 858 } 815 /* was doing it here: */ 816 /* DNS resolution, create copies for each IP address */ 817 /* IPv6-ization destroyed it :( */ 859 818 860 819 return sep; 861 820 } 862 821 863 #define Block_Using_Signals(m) do { \ 864 sigemptyset(&m); \ 865 sigaddset(&m, SIGCHLD); \ 866 sigaddset(&m, SIGHUP); \ 867 sigaddset(&m, SIGALRM); \ 868 sigprocmask(SIG_BLOCK, &m, NULL); \ 869 } while (0) 870 871 static servtab_t *enter(servtab_t *cp) 822 static servtab_t *insert_in_servlist(servtab_t *cp) 872 823 { 873 824 servtab_t *sep; … … 875 826 876 827 sep = new_servtab(); 877 *sep = *cp; 828 *sep = *cp; /* struct copy */ 878 829 sep->se_fd = -1; 879 830 #if ENABLE_FEATURE_INETD_RPC 880 831 sep->se_rpcprog = -1; 881 832 #endif 882 Block_Using_Signals(omask);883 sep->se_next = serv tab;884 serv tab= sep;885 sigprocmask(SIG_UNBLOCK, &omask, NULL);833 block_CHLD_HUP_ALRM(&omask); 834 sep->se_next = serv_list; 835 serv_list = sep; 836 restore_sigmask(&omask); 886 837 return sep; 887 838 } 888 839 889 static int matchconf(servtab_t *old, servtab_t *new) 890 { 840 static int same_serv_addr_proto(servtab_t *old, servtab_t *new) 841 { 842 if (strcmp(old->se_local_hostname, new->se_local_hostname) != 0) 843 return 0; 891 844 if (strcmp(old->se_service, new->se_service) != 0) 892 845 return 0; 893 894 if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)895 return 0;896 897 846 if (strcmp(old->se_proto, new->se_proto) != 0) 898 847 return 0; 899 900 /*901 * If the new servtab is bound to a specific address, check that the902 * old servtab is bound to the same entry. If the new service is not903 * bound to a specific address then the check of se_hostaddr above904 * is sufficient.905 */906 907 if (old->se_family == AF_INET && new->se_family == AF_INET &&908 memcmp(&old->se_ctrladdr_in.sin_addr,909 &new->se_ctrladdr_in.sin_addr,910 sizeof(new->se_ctrladdr_in.sin_addr)) != 0)911 return 0;912 913 #if ENABLE_FEATURE_IPV6914 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&915 memcmp(&old->se_ctrladdr_in6.sin6_addr,916 &new->se_ctrladdr_in6.sin6_addr,917 sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)918 return 0;919 #endif920 848 return 1; 921 849 } 922 850 923 static void config(int sig ATTRIBUTE_UNUSED)851 static void reread_config_file(int sig UNUSED_PARAM) 924 852 { 925 853 servtab_t *sep, *cp, **sepp; 854 len_and_sockaddr *lsa; 926 855 sigset_t omask; 927 size_t n; 928 char protoname[10]; 929 930 if (!setconfig()) { 931 bb_perror_msg("%s", config_filename); 932 return; 933 } 934 for (sep = servtab; sep; sep = sep->se_next) 856 unsigned n; 857 uint16_t port; 858 int save_errno = errno; 859 860 if (!reopen_config_file()) 861 goto ret; 862 for (sep = serv_list; sep; sep = sep->se_next) 935 863 sep->se_checked = 0; 936 cp = getconfigent(); 937 while (cp != NULL) { 938 for (sep = servtab; sep; sep = sep->se_next) 939 if (matchconf(sep, cp)) 864 865 goto first_line; 866 while (1) { 867 if (cp == NULL) { 868 first_line: 869 cp = parse_one_line(); 870 if (cp == NULL) 940 871 break; 941 942 if (sep != 0) { 872 } 873 for (sep = serv_list; sep; sep = sep->se_next) 874 if (same_serv_addr_proto(sep, cp)) 875 goto equal_servtab; 876 /* not an "equal" servtab */ 877 sep = insert_in_servlist(cp); 878 goto after_check; 879 equal_servtab: 880 { 943 881 int i; 944 882 945 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0) 946 947 Block_Using_Signals(omask); 948 /* 949 * sep->se_wait may be holding the pid of a daemon 950 * that we're waiting for. If so, don't overwrite 951 * it unless the config file explicitly says don't 952 * wait. 953 */ 954 if ( 955 #ifdef INETD_FEATURE_ENABLED 956 cp->se_bi == 0 && 957 #endif 958 (sep->se_wait == 1 || cp->se_wait == 0)) 959 sep->se_wait = cp->se_wait; 960 SWAP(int, cp->se_max, sep->se_max); 961 SWAP(char *, sep->se_user, cp->se_user); 962 SWAP(char *, sep->se_group, cp->se_group); 963 SWAP(char *, sep->se_server, cp->se_server); 883 block_CHLD_HUP_ALRM(&omask); 884 #if ENABLE_FEATURE_INETD_RPC 885 if (is_rpc_service(sep)) 886 unregister_rpc(sep); 887 sep->se_rpcver_lo = cp->se_rpcver_lo; 888 sep->se_rpcver_hi = cp->se_rpcver_hi; 889 #endif 890 if (cp->se_wait == 0) { 891 /* New config says "nowait". If old one 892 * was "wait", we currently may be waiting 893 * for a child (and not accepting connects). 894 * Stop waiting, start listening again. 895 * (if it's not true, this op is harmless) */ 896 add_fd_to_set(sep->se_fd); 897 } 898 sep->se_wait = cp->se_wait; 899 sep->se_max = cp->se_max; 900 /* string fields need more love - we don't want to leak them */ 901 #define SWAP(type, a, b) do { type c = (type)a; a = (type)b; b = (type)c; } while (0) 902 SWAP(char*, sep->se_user, cp->se_user); 903 SWAP(char*, sep->se_group, cp->se_group); 904 SWAP(char*, sep->se_program, cp->se_program); 964 905 for (i = 0; i < MAXARGV; i++) 965 SWAP(char 906 SWAP(char*, sep->se_argv[i], cp->se_argv[i]); 966 907 #undef SWAP 967 908 restore_sigmask(&omask); 909 free_servtab_strings(cp); 910 } 911 after_check: 912 /* cp->string_fields are consumed by insert_in_servlist() 913 * or freed at this point, cp itself is not yet freed. */ 914 sep->se_checked = 1; 915 916 /* create new len_and_sockaddr */ 917 switch (sep->se_family) { 918 struct sockaddr_un *sun; 919 case AF_UNIX: 920 lsa = xzalloc_lsa(AF_UNIX); 921 sun = (struct sockaddr_un*)&lsa->u.sa; 922 safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path)); 923 break; 924 925 default: /* case AF_INET, case AF_INET6 */ 926 n = bb_strtou(sep->se_service, NULL, 10); 968 927 #if ENABLE_FEATURE_INETD_RPC 969 if (isrpcservice(sep)) 970 unregister_rpc(sep); 971 sep->se_rpcversl = cp->se_rpcversl; 972 sep->se_rpcversh = cp->se_rpcversh; 973 #endif 974 sigprocmask(SIG_UNBLOCK, &omask, NULL); 975 freeconfig(cp); 976 } else { 977 sep = enter(cp); 978 } 979 sep->se_checked = 1; 980 981 switch (sep->se_family) { 982 case AF_UNIX: 983 if (sep->se_fd != -1) 984 break; 985 (void) unlink(sep->se_service); 986 n = strlen(sep->se_service); 987 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) 988 n = sizeof sep->se_ctrladdr_un.sun_path - 1; 989 safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1); 990 sep->se_ctrladdr_un.sun_family = AF_UNIX; 991 sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family; 992 setup(sep); 993 break; 994 case AF_INET: 995 sep->se_ctrladdr_in.sin_family = AF_INET; 996 /* se_ctrladdr_in was set in getconfigent */ 997 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in; 998 999 #if ENABLE_FEATURE_INETD_RPC 1000 if (isrpcservice(sep)) { 1001 struct rpcent *rp; 1002 // FIXME: atoi_or_else(str, 0) would be handy here 1003 sep->se_rpcprog = atoi(sep->se_service); 1004 if (sep->se_rpcprog == 0) { 1005 rp = getrpcbyname(sep->se_service); 1006 if (rp == 0) { 928 if (is_rpc_service(sep)) { 929 sep->se_rpcprog = n; 930 if (errno) { /* se_service is not numeric */ 931 struct rpcent *rp = getrpcbyname(sep->se_service); 932 if (rp == NULL) { 1007 933 bb_error_msg("%s: unknown rpc service", sep->se_service); 1008 goto serv_unknown;934 goto next_cp; 1009 935 } 1010 936 sep->se_rpcprog = rp->r_number; 1011 937 } 1012 938 if (sep->se_fd == -1) 1013 setup(sep);939 prepare_socket_fd(sep); 1014 940 if (sep->se_fd != -1) 1015 941 register_rpc(sep); 1016 } else 1017 #endif 1018 { 1019 uint16_t port = htons(atoi(sep->se_service)); 1020 // FIXME: atoi_or_else(str, 0) would be handy here 1021 if (!port) { 1022 /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname)); 1023 if (isdigit(protoname[strlen(protoname) - 1])) 1024 protoname[strlen(protoname) - 1] = '\0'; 1025 sp = getservbyname(sep->se_service, protoname); 1026 if (sp == 0) { 1027 bb_error_msg("%s/%s: unknown service", 1028 sep->se_service, sep->se_proto); 1029 goto serv_unknown; 1030 } 1031 port = sp->s_port; 942 goto next_cp; 943 } 944 #endif 945 /* what port to listen on? */ 946 port = htons(n); 947 if (errno || n > 0xffff) { /* se_service is not numeric */ 948 char protoname[4]; 949 struct servent *sp; 950 /* can result only in "tcp" or "udp": */ 951 safe_strncpy(protoname, sep->se_proto, 4); 952 sp = getservbyname(sep->se_service, protoname); 953 if (sp == NULL) { 954 bb_error_msg("%s/%s: unknown service", 955 sep->se_service, sep->se_proto); 956 goto next_cp; 1032 957 } 1033 if (port != sep->se_ctrladdr_in.sin_port) { 1034 sep->se_ctrladdr_in.sin_port = port; 1035 if (sep->se_fd != -1) { 1036 FD_CLR(sep->se_fd, &allsock); 1037 nsock--; 1038 (void) close(sep->se_fd); 1039 } 1040 sep->se_fd = -1; 958 port = sp->s_port; 959 } 960 if (LONE_CHAR(sep->se_local_hostname, '*')) { 961 lsa = xzalloc_lsa(sep->se_family); 962 set_nport(lsa, port); 963 } else { 964 lsa = host_and_af2sockaddr(sep->se_local_hostname, 965 ntohs(port), sep->se_family); 966 if (!lsa) { 967 bb_error_msg("%s/%s: unknown host '%s'", 968 sep->se_service, sep->se_proto, 969 sep->se_local_hostname); 970 goto next_cp; 1041 971 } 1042 if (sep->se_fd == -1)1043 setup(sep);1044 972 } 1045 973 break; 1046 #if ENABLE_FEATURE_IPV6 1047 case AF_INET6: 1048 sep->se_ctrladdr_in6.sin6_family = AF_INET6; 1049 /* se_ctrladdr_in was set in getconfigent */ 1050 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6; 1051 1052 #if ENABLE_FEATURE_INETD_RPC 1053 if (isrpcservice(sep)) { 1054 struct rpcent *rp; 1055 1056 sep->se_rpcprog = atoi(sep->se_service); 1057 if (sep->se_rpcprog == 0) { 1058 rp = getrpcbyname(sep->se_service); 1059 if (rp == 0) { 1060 bb_error_msg("%s: unknown rpc service", sep->se_service); 1061 goto serv_unknown; 1062 } 1063 sep->se_rpcprog = rp->r_number; 1064 } 1065 if (sep->se_fd == -1) 1066 setup(sep); 1067 if (sep->se_fd != -1) 1068 register_rpc(sep); 1069 } else 1070 #endif 1071 { 1072 uint16_t port = htons(atoi(sep->se_service)); 1073 1074 if (!port) { 1075 /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname)); 1076 if (isdigit(protoname[strlen(protoname) - 1])) 1077 protoname[strlen(protoname) - 1] = '\0'; 1078 sp = getservbyname(sep->se_service, protoname); 1079 if (sp == 0) { 1080 bb_error_msg("%s/%s: unknown service", 1081 sep->se_service, sep->se_proto); 1082 goto serv_unknown; 1083 } 1084 port = sp->s_port; 1085 } 1086 if (port != sep->se_ctrladdr_in6.sin6_port) { 1087 sep->se_ctrladdr_in6.sin6_port = port; 1088 if (sep->se_fd != -1) { 1089 FD_CLR(sep->se_fd, &allsock); 1090 nsock--; 1091 (void) close(sep->se_fd); 1092 } 1093 sep->se_fd = -1; 1094 } 1095 if (sep->se_fd == -1) 1096 setup(sep); 1097 } 1098 break; 1099 #endif /* FEATURE_IPV6 */ 974 } /* end of "switch (sep->se_family)" */ 975 976 /* did lsa change? Then close/open */ 977 if (sep->se_lsa == NULL 978 || lsa->len != sep->se_lsa->len 979 || memcmp(&lsa->u.sa, &sep->se_lsa->u.sa, lsa->len) != 0 980 ) { 981 remove_fd_from_set(sep->se_fd); 982 maybe_close(sep->se_fd); 983 free(sep->se_lsa); 984 sep->se_lsa = lsa; 985 sep->se_fd = -1; 986 } else { 987 free(lsa); 1100 988 } 1101 serv_unknown: 1102 if (cp->se_next != NULL) { 1103 servtab_t *tmp = cp; 1104 1105 cp = cp->se_next; 1106 free(tmp); 1107 } else { 1108 free(cp); 1109 cp = getconfigent(); 1110 } 1111 } 1112 endconfig(); 1113 /* 1114 * Purge anything not looked at above. 1115 */ 1116 Block_Using_Signals(omask); 1117 sepp = &servtab; 989 if (sep->se_fd == -1) 990 prepare_socket_fd(sep); 991 next_cp: 992 sep = cp->se_next; 993 free(cp); 994 cp = sep; 995 } /* end of "while (1) parse lines" */ 996 close_config_file(); 997 998 /* Purge anything not looked at above - these are stale entries, 999 * new config file doesnt have them. */ 1000 block_CHLD_HUP_ALRM(&omask); 1001 sepp = &serv_list; 1118 1002 while ((sep = *sepp)) { 1119 1003 if (sep->se_checked) { … … 1122 1006 } 1123 1007 *sepp = sep->se_next; 1124 if (sep->se_fd != -1) { 1125 FD_CLR(sep->se_fd, &allsock); 1126 nsock--; 1127 (void) close(sep->se_fd); 1128 } 1008 remove_fd_from_set(sep->se_fd); 1009 maybe_close(sep->se_fd); 1129 1010 #if ENABLE_FEATURE_INETD_RPC 1130 if (is rpcservice(sep))1011 if (is_rpc_service(sep)) 1131 1012 unregister_rpc(sep); 1132 1013 #endif 1133 1014 if (sep->se_family == AF_UNIX) 1134 (void)unlink(sep->se_service);1135 free config(sep);1015 unlink(sep->se_service); 1016 free_servtab_strings(sep); 1136 1017 free(sep); 1137 1018 } 1138 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1139 } 1140 1141 1142 static void reapchild(int sig ATTRIBUTE_UNUSED) 1019 restore_sigmask(&omask); 1020 ret: 1021 errno = save_errno; 1022 } 1023 1024 static void reap_child(int sig UNUSED_PARAM) 1143 1025 { 1144 1026 pid_t pid; 1145 int s ave_errno = errno, status;1027 int status; 1146 1028 servtab_t *sep; 1029 int save_errno = errno; 1147 1030 1148 1031 for (;;) { 1149 pid = wait 3(&status, WNOHANG, NULL);1032 pid = wait_any_nohang(&status); 1150 1033 if (pid <= 0) 1151 1034 break; 1152 for (sep = servtab; sep; sep = sep->se_next) 1153 if (sep->se_wait == pid) { 1154 if (WIFEXITED(status) && WEXITSTATUS(status)) 1155 bb_error_msg("%s: exit status 0x%x", 1156 sep->se_server, WEXITSTATUS(status)); 1157 else if (WIFSIGNALED(status)) 1158 bb_error_msg("%s: exit signal 0x%x", 1159 sep->se_server, WTERMSIG(status)); 1160 sep->se_wait = 1; 1161 FD_SET(sep->se_fd, &allsock); 1162 nsock++; 1163 } 1035 for (sep = serv_list; sep; sep = sep->se_next) { 1036 if (sep->se_wait != pid) 1037 continue; 1038 /* One of our "wait" services */ 1039 if (WIFEXITED(status) && WEXITSTATUS(status)) 1040 bb_error_msg("%s: exit status %u", 1041 sep->se_program, WEXITSTATUS(status)); 1042 else if (WIFSIGNALED(status)) 1043 bb_error_msg("%s: exit signal %u", 1044 sep->se_program, WTERMSIG(status)); 1045 sep->se_wait = 1; 1046 add_fd_to_set(sep->se_fd); 1047 break; 1048 } 1164 1049 } 1165 1050 errno = save_errno; 1166 1051 } 1167 1052 1168 static void retry(int sig ATTRIBUTE_UNUSED) 1169 { 1053 static void retry_network_setup(int sig UNUSED_PARAM) 1054 { 1055 int save_errno = errno; 1170 1056 servtab_t *sep; 1171 1057 1172 timingout= 0;1173 for (sep = serv tab; sep; sep = sep->se_next) {1058 alarm_armed = 0; 1059 for (sep = serv_list; sep; sep = sep->se_next) { 1174 1060 if (sep->se_fd == -1) { 1175 switch (sep->se_family) { 1176 case AF_UNIX: 1177 case AF_INET: 1178 #if ENABLE_FEATURE_IPV6 1179 case AF_INET6: 1180 #endif 1181 setup(sep); 1061 prepare_socket_fd(sep); 1182 1062 #if ENABLE_FEATURE_INETD_RPC 1183 if (sep->se_fd != -1 && isrpcservice(sep)) 1184 register_rpc(sep); 1185 #endif 1186 break; 1187 } 1063 if (sep->se_fd != -1 && is_rpc_service(sep)) 1064 register_rpc(sep); 1065 #endif 1188 1066 } 1189 1067 } 1190 } 1191 1192 static void goaway(int sig ATTRIBUTE_UNUSED) 1068 errno = save_errno; 1069 } 1070 1071 static void clean_up_and_exit(int sig UNUSED_PARAM) 1193 1072 { 1194 1073 servtab_t *sep; 1195 1074 1196 1075 /* XXX signal race walking sep list */ 1197 for (sep = serv tab; sep; sep = sep->se_next) {1076 for (sep = serv_list; sep; sep = sep->se_next) { 1198 1077 if (sep->se_fd == -1) 1199 1078 continue; … … 1201 1080 switch (sep->se_family) { 1202 1081 case AF_UNIX: 1203 (void)unlink(sep->se_service);1082 unlink(sep->se_service); 1204 1083 break; 1205 case AF_INET: 1206 #if ENABLE_FEATURE_IPV6 1207 case AF_INET6: 1208 #endif 1084 default: /* case AF_INET, AF_INET6 */ 1209 1085 #if ENABLE_FEATURE_INETD_RPC 1210 if (sep->se_wait == 1 && is rpcservice(sep))1086 if (sep->se_wait == 1 && is_rpc_service(sep)) 1211 1087 unregister_rpc(sep); /* XXX signal race */ 1212 1088 #endif 1213 1089 break; 1214 1090 } 1215 (void) close(sep->se_fd); 1091 if (ENABLE_FEATURE_CLEAN_UP) 1092 close(sep->se_fd); 1216 1093 } 1217 1094 remove_pidfile(_PATH_INETDPID); 1218 exit(0); 1219 } 1220 1221 1222 #ifdef INETD_SETPROCTITLE 1223 static char **Argv; 1224 static char *LastArg; 1225 1226 static void 1227 inetd_setproctitle(char *a, int s) 1228 { 1229 socklen_t size; 1230 char *cp; 1231 struct sockaddr_in prt_sin; 1232 char buf[80]; 1233 1234 cp = Argv[0]; 1235 size = sizeof(prt_sin); 1236 (void) snprintf(buf, sizeof buf, "-%s", a); 1237 if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) { 1238 char *sa = inet_ntoa(prt_sin.sin_addr); 1239 1240 buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0'; 1241 strcat(buf, " ["); 1242 strcat(buf, sa); 1243 strcat(buf, "]"); 1244 } 1245 strncpy(cp, buf, LastArg - cp); 1246 cp += strlen(cp); 1247 while (cp < LastArg) 1248 *cp++ = ' '; 1249 } 1250 #endif 1251 1252 1253 int inetd_main(int argc, char **argv); 1254 int inetd_main(int argc, char **argv) 1255 { 1256 servtab_t *sep; 1095 exit(EXIT_SUCCESS); 1096 } 1097 1098 int inetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1099 int inetd_main(int argc UNUSED_PARAM, char **argv) 1100 { 1101 struct sigaction sa, saved_pipe_handler; 1102 servtab_t *sep, *sep2; 1257 1103 struct passwd *pwd; 1258 struct group *grp = NULL; 1259 int tmpint; 1260 struct sigaction sa, sapipe; 1104 struct group *grp = grp; /* for compiler */ 1261 1105 int opt; 1262 1106 pid_t pid; 1263 char buf[50]; 1264 char *stoomany; 1265 sigset_t omask, wait_mask; 1266 1267 #ifdef INETD_SETPROCTITLE 1268 char **envp = environ; 1269 1270 Argv = argv; 1271 if (envp == 0 || *envp == 0) 1272 envp = argv; 1273 while (*envp) 1274 envp++; 1275 LastArg = envp[-1] + strlen(envp[-1]); 1276 #endif 1277 1278 uid = getuid(); 1279 if (uid != 0) 1107 sigset_t omask; 1108 1109 INIT_G(); 1110 1111 real_uid = getuid(); 1112 if (real_uid != 0) /* run by non-root user */ 1280 1113 config_filename = NULL; 1281 1114 1282 opt = getopt32(argv, "R:f", &stoomany); 1283 if (opt & 1) 1284 toomany = xatoi_u(stoomany); 1115 opt_complementary = "R+:q+"; /* -q N, -R N */ 1116 opt = getopt32(argv, "R:feq:", &max_concurrency, &global_queuelen); 1285 1117 argv += optind; 1286 argc -= optind;1287 if (arg c)1118 //argc -= optind; 1119 if (argv[0]) 1288 1120 config_filename = argv[0]; 1289 1121 if (config_filename == NULL) 1290 bb_error_msg_and_die("non-root must specify a config file"); 1291 1122 bb_error_msg_and_die("non-root must specify config file"); 1292 1123 if (!(opt & 2)) 1293 1124 bb_daemonize_or_rexec(0, argv - optind); 1294 1125 else 1295 1126 bb_sanitize_stdio(); 1296 openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 1297 logmode = LOGMODE_SYSLOG; 1298 1299 if (uid == 0) { 1300 /* If run by hand, ensure groups vector gets trashed */ 1127 if (!(opt & 4)) { 1128 /* LOG_NDELAY: connect to syslog daemon NOW. 1129 * Otherwise, we may open syslog socket 1130 * in vforked child, making opened fds and syslog() 1131 * internal state inconsistent. 1132 * This was observed to leak file descriptors. */ 1133 openlog(applet_name, LOG_PID | LOG_NDELAY, LOG_DAEMON); 1134 logmode = LOGMODE_SYSLOG; 1135 } 1136 1137 if (real_uid == 0) { 1138 /* run by root, ensure groups vector gets trashed */ 1301 1139 gid_t gid = getgid(); 1302 1140 setgroups(1, &gid); … … 1305 1143 write_pidfile(_PATH_INETDPID); 1306 1144 1307 if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) { 1308 bb_perror_msg("getrlimit"); 1309 } else { 1310 rlim_ofile_cur = rlim_ofile.rlim_cur; 1311 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ 1312 rlim_ofile_cur = OPEN_MAX; 1313 } 1314 1315 memset((char *) &sa, 0, sizeof(sa)); 1316 sigemptyset(&sa.sa_mask); 1145 /* never fails under Linux (except if you pass it bad arguments) */ 1146 getrlimit(RLIMIT_NOFILE, &rlim_ofile); 1147 rlim_ofile_cur = rlim_ofile.rlim_cur; 1148 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ 1149 rlim_ofile_cur = OPEN_MAX; 1150 1151 memset(&sa, 0, sizeof(sa)); 1152 /*sigemptyset(&sa.sa_mask); - memset did it */ 1317 1153 sigaddset(&sa.sa_mask, SIGALRM); 1318 1154 sigaddset(&sa.sa_mask, SIGCHLD); 1319 1155 sigaddset(&sa.sa_mask, SIGHUP); 1320 sa.sa_handler = retry; 1321 sigaction(SIGALRM, &sa, NULL); 1322 config(SIGHUP); 1323 sa.sa_handler = config; 1324 sigaction(SIGHUP, &sa, NULL); 1325 sa.sa_handler = reapchild; 1326 sigaction(SIGCHLD, &sa, NULL); 1327 sa.sa_handler = goaway; 1328 sigaction(SIGTERM, &sa, NULL); 1329 sa.sa_handler = goaway; 1330 sigaction(SIGINT, &sa, NULL); 1156 sa.sa_handler = retry_network_setup; 1157 sigaction_set(SIGALRM, &sa); 1158 sa.sa_handler = reread_config_file; 1159 sigaction_set(SIGHUP, &sa); 1160 sa.sa_handler = reap_child; 1161 sigaction_set(SIGCHLD, &sa); 1162 sa.sa_handler = clean_up_and_exit; 1163 sigaction_set(SIGTERM, &sa); 1164 sa.sa_handler = clean_up_and_exit; 1165 sigaction_set(SIGINT, &sa); 1331 1166 sa.sa_handler = SIG_IGN; 1332 sigaction(SIGPIPE, &sa, &sapipe); 1333 memset(&wait_mask, 0, sizeof(wait_mask)); 1334 { 1335 /* space for daemons to overwrite environment for ps */ 1336 #define DUMMYSIZE 100 1337 char dummy[DUMMYSIZE]; 1338 1339 (void) memset(dummy, 'x', DUMMYSIZE - 1); 1340 dummy[DUMMYSIZE - 1] = '\0'; 1341 1342 (void) setenv("inetd_dummy", dummy, 1); 1343 } 1167 sigaction(SIGPIPE, &sa, &saved_pipe_handler); 1168 1169 reread_config_file(SIGHUP); /* load config from file */ 1344 1170 1345 1171 for (;;) { 1346 int n, ctrl = -1; 1172 int ready_fd_cnt; 1173 int ctrl, accepted_fd, new_udp_fd; 1347 1174 fd_set readable; 1348 1175 1349 if (nsock == 0) { 1350 Block_Using_Signals(omask); 1351 while (nsock == 0) 1352 sigsuspend(&wait_mask); 1353 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1354 } 1355 1356 readable = allsock; 1357 n = select(maxsock + 1, &readable, NULL, NULL, NULL); 1358 if (n <= 0) { 1359 if (n < 0 && errno != EINTR) { 1176 if (maxsock < 0) 1177 recalculate_maxsock(); 1178 1179 readable = allsock; /* struct copy */ 1180 /* if there are no fds to wait on, we will block 1181 * until signal wakes us up (maxsock == 0, but readable 1182 * never contains fds 0 and 1...) */ 1183 ready_fd_cnt = select(maxsock + 1, &readable, NULL, NULL, NULL); 1184 if (ready_fd_cnt < 0) { 1185 if (errno != EINTR) { 1360 1186 bb_perror_msg("select"); 1361 1187 sleep(1); … … 1364 1190 } 1365 1191 1366 for (sep = serv tab; n&& sep; sep = sep->se_next) {1192 for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { 1367 1193 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) 1368 1194 continue; 1369 1195 1370 n--; 1371 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 1372 ctrl = accept(sep->se_fd, NULL, NULL); 1373 if (ctrl < 0) { 1374 if (errno == EINTR) 1375 continue; 1376 bb_perror_msg("accept (for %s)", sep->se_service); 1377 continue; 1378 } 1379 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) { 1380 struct sockaddr_in peer; 1381 socklen_t plen = sizeof(peer); 1382 1383 if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) { 1384 bb_error_msg("cannot getpeername"); 1385 close(ctrl); 1386 continue; 1387 } 1388 if (ntohs(peer.sin_port) == 20) { 1389 /* XXX ftp bounce */ 1390 close(ctrl); 1196 ready_fd_cnt--; 1197 ctrl = sep->se_fd; 1198 accepted_fd = -1; 1199 new_udp_fd = -1; 1200 if (!sep->se_wait) { 1201 if (sep->se_socktype == SOCK_STREAM) { 1202 ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); 1203 if (ctrl < 0) { 1204 if (errno != EINTR) 1205 bb_perror_msg("accept (for %s)", sep->se_service); 1391 1206 continue; 1392 1207 } 1393 1208 } 1394 } else 1395 ctrl = sep->se_fd; 1396 1397 Block_Using_Signals(omask); 1398 pid = 0; 1399 #ifdef INETD_FEATURE_ENABLED 1400 if (sep->se_bi == 0 || sep->se_bi->bi_fork) 1401 #endif 1402 { 1403 if (sep->se_count++ == 0) 1404 (void) gettimeofday(&sep->se_time, NULL); 1405 else if (toomany > 0 && sep->se_count >= sep->se_max) { 1406 struct timeval now; 1407 1408 (void) gettimeofday(&now, NULL); 1409 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { 1410 sep->se_time = now; 1411 sep->se_count = 1; 1412 } else { 1413 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1414 close(ctrl); 1415 if (sep->se_family == AF_INET && 1416 ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) { 1417 /* 1418 * Cannot close it -- there are 1419 * thieves on the system. 1420 * Simply ignore the connection. 1421 */ 1422 --sep->se_count; 1423 continue; 1424 } 1425 bb_error_msg("%s/%s server failing (looping), service terminated", 1426 sep->se_service, sep->se_proto); 1427 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1428 close(ctrl); 1429 FD_CLR(sep->se_fd, &allsock); 1430 (void) close(sep->se_fd); 1431 sep->se_fd = -1; 1432 sep->se_count = 0; 1433 nsock--; 1434 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1435 if (!timingout) { 1436 timingout = 1; 1437 alarm(RETRYTIME); 1438 } 1209 /* "nowait" udp */ 1210 if (sep->se_socktype == SOCK_DGRAM 1211 && sep->se_family != AF_UNIX 1212 ) { 1213 /* How udp "nowait" works: 1214 * child peeks at (received and buffered by kernel) UDP packet, 1215 * performs connect() on the socket so that it is linked only 1216 * to this peer. But this also affects parent, because descriptors 1217 * are shared after fork() a-la dup(). When parent performs 1218 * select(), it will see this descriptor connected to the peer (!) 1219 * and still readable, will act on it and mess things up 1220 * (can create many copies of same child, etc). 1221 * Parent must create and use new socket instead. */ 1222 new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); 1223 if (new_udp_fd < 0) { /* error: eat packet, forget about it */ 1224 udp_err: 1225 recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); 1439 1226 continue; 1440 1227 } 1441 } 1442 pid = fork(); 1443 } 1444 if (pid < 0) { 1445 bb_perror_msg("fork"); 1446 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1447 close(ctrl); 1448 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1449 sleep(1); 1450 continue; 1451 } 1452 if (pid && sep->se_wait) { 1453 sep->se_wait = pid; 1454 FD_CLR(sep->se_fd, &allsock); 1455 nsock--; 1456 } 1457 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1458 if (pid == 0) { 1459 #ifdef INETD_FEATURE_ENABLED 1460 if (sep->se_bi) { 1461 (*sep->se_bi->bi_fn)(ctrl, sep); 1462 } else 1463 #endif 1464 { 1465 pwd = getpwnam(sep->se_user); 1466 if (pwd == NULL) { 1467 bb_error_msg("getpwnam: %s: no such user", sep->se_user); 1468 goto do_exit1; 1228 setsockopt_reuseaddr(new_udp_fd); 1229 /* TODO: better do bind after vfork in parent, 1230 * so that we don't have two wildcard bound sockets 1231 * even for a brief moment? */ 1232 if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { 1233 close(new_udp_fd); 1234 goto udp_err; 1469 1235 } 1470 if (setsid() < 0)1471 bb_perror_msg("%s: setsid", sep->se_service);1472 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {1473 bb_error_msg("getgrnam: %s: no such group", sep->se_group);1474 goto do_exit1;1475 }1476 if (uid != 0) {1477 /* a user running private inetd */1478 if (uid != pwd->pw_uid)1479 _exit(1);1480 } else if (pwd->pw_uid) {1481 if (sep->se_group)1482 pwd->pw_gid = grp->gr_gid;1483 xsetgid((gid_t) pwd->pw_gid);1484 initgroups(pwd->pw_name, pwd->pw_gid);1485 xsetuid((uid_t) pwd->pw_uid);1486 } else if (sep->se_group) {1487 xsetgid(grp->gr_gid);1488 setgroups(1, &grp->gr_gid);1489 }1490 dup2(ctrl, 0);1491 if (ctrl) close(ctrl);1492 dup2(0, 1);1493 dup2(0, 2);1494 if (rlim_ofile.rlim_cur != rlim_ofile_cur)1495 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)1496 bb_perror_msg("setrlimit");1497 closelog();1498 for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)1499 (void) close(tmpint);1500 sigaction(SIGPIPE, &sapipe, NULL);1501 execv(sep->se_server, sep->se_argv);1502 bb_perror_msg("execv %s", sep->se_server);1503 do_exit1:1504 if (sep->se_socktype != SOCK_STREAM)1505 recv(0, buf, sizeof(buf), 0);1506 _exit(1);1507 1236 } 1508 1237 } 1509 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1510 close(ctrl); 1238 1239 block_CHLD_HUP_ALRM(&omask); 1240 pid = 0; 1241 #ifdef INETD_BUILTINS_ENABLED 1242 /* do we need to fork? */ 1243 if (sep->se_builtin == NULL 1244 || (sep->se_socktype == SOCK_STREAM 1245 && sep->se_builtin->bi_fork)) 1246 #endif 1247 { 1248 if (sep->se_max != 0) { 1249 if (++sep->se_count == 1) 1250 sep->se_time = monotonic_sec(); 1251 else if (sep->se_count >= sep->se_max) { 1252 unsigned now = monotonic_sec(); 1253 /* did we accumulate se_max connects too quickly? */ 1254 if (now - sep->se_time <= CNT_INTERVAL) { 1255 bb_error_msg("%s/%s: too many connections, pausing", 1256 sep->se_service, sep->se_proto); 1257 remove_fd_from_set(sep->se_fd); 1258 close(sep->se_fd); 1259 sep->se_fd = -1; 1260 sep->se_count = 0; 1261 rearm_alarm(); /* will revive it in RETRYTIME sec */ 1262 restore_sigmask(&omask); 1263 maybe_close(accepted_fd); 1264 continue; /* -> check next fd in fd set */ 1265 } 1266 sep->se_count = 0; 1267 } 1268 } 1269 /* on NOMMU, streamed chargen 1270 * builtin wouldn't work, but it is 1271 * not allowed on NOMMU (ifdefed out) */ 1272 #ifdef INETD_BUILTINS_ENABLED 1273 if (BB_MMU && sep->se_builtin) 1274 pid = fork(); 1275 else 1276 #endif 1277 pid = vfork(); 1278 1279 if (pid < 0) { /* fork error */ 1280 bb_perror_msg("vfork"+1); 1281 sleep(1); 1282 restore_sigmask(&omask); 1283 maybe_close(accepted_fd); 1284 continue; /* -> check next fd in fd set */ 1285 } 1286 if (pid == 0) 1287 pid--; /* -1: "we did fork and we are child" */ 1288 } 1289 /* if pid == 0 here, we never forked */ 1290 1291 if (pid > 0) { /* parent */ 1292 if (sep->se_wait) { 1293 /* tcp wait: we passed listening socket to child, 1294 * will wait for child to terminate */ 1295 sep->se_wait = pid; 1296 remove_fd_from_set(sep->se_fd); 1297 } 1298 if (new_udp_fd >= 0) { 1299 /* udp nowait: child connected the socket, 1300 * we created and will use new, unconnected one */ 1301 xmove_fd(new_udp_fd, sep->se_fd); 1302 } 1303 restore_sigmask(&omask); 1304 maybe_close(accepted_fd); 1305 continue; /* -> check next fd in fd set */ 1306 } 1307 1308 /* we are either child or didn't vfork at all */ 1309 #ifdef INETD_BUILTINS_ENABLED 1310 if (sep->se_builtin) { 1311 if (pid) { /* "pid" is -1: we did vfork */ 1312 close(sep->se_fd); /* listening socket */ 1313 logmode = LOGMODE_NONE; /* make xwrite etc silent */ 1314 } 1315 restore_sigmask(&omask); 1316 if (sep->se_socktype == SOCK_STREAM) 1317 sep->se_builtin->bi_stream_fn(ctrl, sep); 1318 else 1319 sep->se_builtin->bi_dgram_fn(ctrl, sep); 1320 if (pid) /* we did vfork */ 1321 _exit(EXIT_FAILURE); 1322 maybe_close(accepted_fd); 1323 continue; /* -> check next fd in fd set */ 1324 } 1325 #endif 1326 /* child */ 1327 setsid(); 1328 /* "nowait" udp */ 1329 if (new_udp_fd >= 0) { 1330 len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family); 1331 /* peek at the packet and remember peer addr */ 1332 int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, 1333 &lsa->u.sa, &lsa->len); 1334 if (r < 0) 1335 goto do_exit1; 1336 /* make this socket "connected" to peer addr: 1337 * only packets from this peer will be recv'ed, 1338 * and bare write()/send() will work on it */ 1339 connect(ctrl, &lsa->u.sa, lsa->len); 1340 free(lsa); 1341 } 1342 /* prepare env and exec program */ 1343 pwd = getpwnam(sep->se_user); 1344 if (pwd == NULL) { 1345 bb_error_msg("%s: no such %s", sep->se_user, "user"); 1346 goto do_exit1; 1347 } 1348 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) { 1349 bb_error_msg("%s: no such %s", sep->se_group, "group"); 1350 goto do_exit1; 1351 } 1352 if (real_uid != 0 && real_uid != pwd->pw_uid) { 1353 /* a user running private inetd */ 1354 bb_error_msg("non-root must run services as himself"); 1355 goto do_exit1; 1356 } 1357 if (pwd->pw_uid) { 1358 if (sep->se_group) 1359 pwd->pw_gid = grp->gr_gid; 1360 /* initgroups, setgid, setuid: */ 1361 change_identity(pwd); 1362 } else if (sep->se_group) { 1363 xsetgid(grp->gr_gid); 1364 setgroups(1, &grp->gr_gid); 1365 } 1366 if (rlim_ofile.rlim_cur != rlim_ofile_cur) 1367 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) 1368 bb_perror_msg("setrlimit"); 1369 1370 /* closelog(); - WRONG. we are after vfork, 1371 * this may confuse syslog() internal state. 1372 * Let's hope libc sets syslog fd to CLOEXEC... 1373 */ 1374 xmove_fd(ctrl, STDIN_FILENO); 1375 xdup2(STDIN_FILENO, STDOUT_FILENO); 1376 /* manpages of inetd I managed to find either say 1377 * that stderr is also redirected to the network, 1378 * or do not talk about redirection at all (!) */ 1379 if (!sep->se_wait) /* only for usual "tcp nowait" */ 1380 xdup2(STDIN_FILENO, STDERR_FILENO); 1381 /* NB: among others, this loop closes listening sockets 1382 * for nowait stream children */ 1383 for (sep2 = serv_list; sep2; sep2 = sep2->se_next) 1384 if (sep2->se_fd != ctrl) 1385 maybe_close(sep2->se_fd); 1386 sigaction_set(SIGPIPE, &saved_pipe_handler); 1387 restore_sigmask(&omask); 1388 BB_EXECVP(sep->se_program, sep->se_argv); 1389 bb_perror_msg("can't execute '%s'", sep->se_program); 1390 do_exit1: 1391 /* eat packet in udp case */ 1392 if (sep->se_socktype != SOCK_STREAM) 1393 recv(0, line, LINE_SIZE, MSG_DONTWAIT); 1394 _exit(EXIT_FAILURE); 1511 1395 } /* for (sep = servtab...) */ 1512 1396 } /* for (;;) */ 1513 1397 } 1398 1399 #if !BB_MMU 1400 static const char *const cat_args[] = { "cat", NULL }; 1401 #endif 1514 1402 1515 1403 /* 1516 1404 * Internet services provided internally by inetd: 1517 1405 */ 1518 #define BUFSIZE 40961519 1520 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \1521 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \1522 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME1523 static int dg_badinput(struct sockaddr_in *dg_sin)1524 {1525 if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)1526 return 1;1527 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))1528 return 1;1529 /* XXX compare against broadcast addresses in SIOCGIFCONF list? */1530 return 0;1531 }1532 #endif1533 1534 1406 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1535 /* Echo service -- echo data back */1407 /* Echo service -- echo data back. */ 1536 1408 /* ARGSUSED */ 1537 static void 1538 echo_stream(int s, servtab_t *sep) 1539 { 1540 char buffer[BUFSIZE]; 1541 int i; 1542 1543 inetd_setproctitle(sep->se_service, s); 1409 static void FAST_FUNC echo_stream(int s, servtab_t *sep UNUSED_PARAM) 1410 { 1411 #if BB_MMU 1544 1412 while (1) { 1545 i = read(s, buffer, sizeof(buffer)); 1546 if (i <= 0) break; 1547 /* FIXME: this isnt correct - safe_write()? */ 1548 if (write(s, buffer, i) <= 0) break; 1549 } 1550 exit(0); 1551 } 1552 1553 /* Echo service -- echo data back */ 1413 ssize_t sz = safe_read(s, line, LINE_SIZE); 1414 if (sz <= 0) 1415 break; 1416 xwrite(s, line, sz); 1417 } 1418 #else 1419 /* We are after vfork here! */ 1420 /* move network socket to stdin/stdout */ 1421 xmove_fd(s, STDIN_FILENO); 1422 xdup2(STDIN_FILENO, STDOUT_FILENO); 1423 /* no error messages please... */ 1424 close(STDERR_FILENO); 1425 xopen(bb_dev_null, O_WRONLY); 1426 BB_EXECVP("cat", (char**)cat_args); 1427 /* on failure we return to main, which does exit(EXIT_FAILURE) */ 1428 #endif 1429 } 1430 static void FAST_FUNC echo_dg(int s, servtab_t *sep) 1431 { 1432 enum { BUFSIZE = 12*1024 }; /* for jumbo sized packets! :) */ 1433 char *buf = xmalloc(BUFSIZE); /* too big for stack */ 1434 int sz; 1435 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len); 1436 1437 lsa->len = sep->se_lsa->len; 1438 /* dgram builtins are non-forking - DONT BLOCK! */ 1439 sz = recvfrom(s, buf, BUFSIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len); 1440 if (sz > 0) 1441 sendto(s, buf, sz, 0, &lsa->u.sa, lsa->len); 1442 free(buf); 1443 } 1444 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */ 1445 1446 1447 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1448 /* Discard service -- ignore data. */ 1554 1449 /* ARGSUSED */ 1555 static void 1556 echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1557 { 1558 char buffer[BUFSIZE]; 1559 int i; 1560 socklen_t size; 1561 /* struct sockaddr_storage ss; */ 1562 struct sockaddr sa; 1563 1564 size = sizeof(sa); 1565 i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size); 1566 if (i < 0) 1567 return; 1568 if (dg_badinput((struct sockaddr_in *) &sa)) 1569 return; 1570 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 1571 } 1572 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */ 1573 1574 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1575 /* Discard service -- ignore data */ 1450 static void FAST_FUNC discard_stream(int s, servtab_t *sep UNUSED_PARAM) 1451 { 1452 #if BB_MMU 1453 while (safe_read(s, line, LINE_SIZE) > 0) 1454 continue; 1455 #else 1456 /* We are after vfork here! */ 1457 /* move network socket to stdin */ 1458 xmove_fd(s, STDIN_FILENO); 1459 /* discard output */ 1460 close(STDOUT_FILENO); 1461 xopen(bb_dev_null, O_WRONLY); 1462 /* no error messages please... */ 1463 xdup2(STDOUT_FILENO, STDERR_FILENO); 1464 BB_EXECVP("cat", (char**)cat_args); 1465 /* on failure we return to main, which does exit(EXIT_FAILURE) */ 1466 #endif 1467 } 1576 1468 /* ARGSUSED */ 1577 static void 1578 discard_stream(int s, servtab_t *sep) 1579 { 1580 char buffer[BUFSIZE]; 1581 1582 inetd_setproctitle(sep->se_service, s); 1583 while (1) { 1584 errno = 0; 1585 if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR) 1586 exit(0); 1587 } 1588 } 1589 1590 /* Discard service -- ignore data */ 1591 /* ARGSUSED */ 1592 static void 1593 discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1594 { 1595 char buffer[BUFSIZE]; 1596 1597 (void) read(s, buffer, sizeof(buffer)); 1469 static void FAST_FUNC discard_dg(int s, servtab_t *sep UNUSED_PARAM) 1470 { 1471 /* dgram builtins are non-forking - DONT BLOCK! */ 1472 recv(s, line, LINE_SIZE, MSG_DONTWAIT); 1598 1473 } 1599 1474 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */ … … 1602 1477 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1603 1478 #define LINESIZ 72 1604 static char ring[128]; 1605 static char *endring; 1606 1607 static void 1608 initring(void) 1479 static void init_ring(void) 1609 1480 { 1610 1481 int i; 1611 1482 1612 endring = ring; 1613 1614 for (i = 0; i <= 128; ++i) 1615 if (isprint(i)) 1616 *endring++ = i; 1617 } 1618 1619 /* Character generator */ 1483 end_ring = ring; 1484 for (i = ' '; i < 127; i++) 1485 *end_ring++ = i; 1486 } 1487 /* Character generator. MMU arches only. */ 1620 1488 /* ARGSUSED */ 1621 static void 1622 chargen_stream(int s, servtab_t *sep) 1489 static void FAST_FUNC chargen_stream(int s, servtab_t *sep UNUSED_PARAM) 1623 1490 { 1624 1491 char *rs; … … 1626 1493 char text[LINESIZ + 2]; 1627 1494 1628 inetd_setproctitle(sep->se_service, s); 1629 1630 if (!endring) { 1631 initring(); 1495 if (!end_ring) { 1496 init_ring(); 1632 1497 rs = ring; 1633 1498 } … … 1637 1502 rs = ring; 1638 1503 for (;;) { 1639 len = end ring - rs;1504 len = end_ring - rs; 1640 1505 if (len >= LINESIZ) 1641 1506 memmove(text, rs, LINESIZ); … … 1644 1509 memmove(text + len, ring, LINESIZ - len); 1645 1510 } 1646 if (++rs == end ring)1511 if (++rs == end_ring) 1647 1512 rs = ring; 1648 if (write(s, text, sizeof(text)) != sizeof(text)) 1649 break; 1650 } 1651 exit(0); 1652 } 1653 1654 /* Character generator */ 1513 xwrite(s, text, sizeof(text)); 1514 } 1515 } 1655 1516 /* ARGSUSED */ 1656 static void 1657 chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1658 { 1659 /* struct sockaddr_storage ss; */ 1660 struct sockaddr sa; 1661 static char *rs; 1517 static void FAST_FUNC chargen_dg(int s, servtab_t *sep) 1518 { 1662 1519 int len; 1663 1520 char text[LINESIZ + 2]; 1664 socklen_t size; 1665 1666 if (endring == 0) { 1667 initring(); 1668 rs = ring; 1669 } 1670 1671 size = sizeof(sa); 1672 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 1521 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len); 1522 1523 /* Eat UDP packet which started it all */ 1524 /* dgram builtins are non-forking - DONT BLOCK! */ 1525 lsa->len = sep->se_lsa->len; 1526 if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0) 1673 1527 return; 1674 if (dg_badinput((struct sockaddr_in *) &sa)) 1675 return; 1676 1677 if ((len = endring - rs) >= LINESIZ) 1678 memmove(text, rs, LINESIZ); 1528 1529 if (!end_ring) { 1530 init_ring(); 1531 ring_pos = ring; 1532 } 1533 1534 len = end_ring - ring_pos; 1535 if (len >= LINESIZ) 1536 memmove(text, ring_pos, LINESIZ); 1679 1537 else { 1680 memmove(text, r s, len);1538 memmove(text, ring_pos, len); 1681 1539 memmove(text + len, ring, LINESIZ - len); 1682 1540 } 1683 if (++r s == endring)1684 r s = ring;1541 if (++ring_pos == end_ring) 1542 ring_pos = ring; 1685 1543 text[LINESIZ] = '\r'; 1686 1544 text[LINESIZ + 1] = '\n'; 1687 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));1545 sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len); 1688 1546 } 1689 1547 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */ … … 1698 1556 * some seventy years Bell Labs was asleep. 1699 1557 */ 1700 1701 static unsigned machtime(void) 1558 static uint32_t machtime(void) 1702 1559 { 1703 1560 struct timeval tv; 1704 1561 1705 if (gettimeofday(&tv, NULL) < 0) { 1706 fprintf(stderr, "Unable to get time of day\n"); 1707 return 0L; 1708 } 1709 return htonl((unsigned) tv.tv_sec + 2208988800UL); 1710 } 1711 1562 gettimeofday(&tv, NULL); 1563 return htonl((uint32_t)(tv.tv_sec + 2208988800)); 1564 } 1712 1565 /* ARGSUSED */ 1713 static void 1714 machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1715 { 1716 unsigned result; 1566 static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM) 1567 { 1568 uint32_t result; 1717 1569 1718 1570 result = machtime(); 1719 (void) write(s, (char *) &result, sizeof(result)); 1720 } 1721 1722 /* ARGSUSED */ 1723 static void 1724 machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1725 { 1726 unsigned result; 1727 /* struct sockaddr_storage ss; */ 1728 struct sockaddr sa; 1729 struct sockaddr_in *dg_sin; 1730 socklen_t size; 1731 1732 size = sizeof(sa); 1733 if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0) 1571 full_write(s, &result, sizeof(result)); 1572 } 1573 static void FAST_FUNC machtime_dg(int s, servtab_t *sep) 1574 { 1575 uint32_t result; 1576 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len); 1577 1578 lsa->len = sep->se_lsa->len; 1579 if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0) 1734 1580 return; 1735 /* if (dg_badinput((struct sockaddr *)&ss)) */ 1736 dg_sin = (struct sockaddr_in *) &sa; 1737 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) || 1738 ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2) 1739 return; 1581 1740 1582 result = machtime(); 1741 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));1583 sendto(s, &result, sizeof(result), 0, &lsa->u.sa, lsa->len); 1742 1584 } 1743 1585 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */ … … 1747 1589 /* Return human-readable time of day */ 1748 1590 /* ARGSUSED */ 1749 static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1750 { 1751 char buffer[32]; 1591 static void FAST_FUNC daytime_stream(int s, servtab_t *sep UNUSED_PARAM) 1592 { 1752 1593 time_t t; 1753 1594 1754 1595 t = time(NULL); 1755 1756 // fdprintf instead? 1757 (void) sprintf(buffer, "%.24s\r\n", ctime(&t)); 1758 (void) write(s, buffer, strlen(buffer)); 1759 } 1760 1761 /* Return human-readable time of day */ 1762 /* ARGSUSED */ 1763 void 1764 daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1765 { 1766 char buffer[256]; 1596 fdprintf(s, "%.24s\r\n", ctime(&t)); 1597 } 1598 static void FAST_FUNC daytime_dg(int s, servtab_t *sep) 1599 { 1767 1600 time_t t; 1768 /* struct sockaddr_storage ss; */ 1769 struct sockaddr sa; 1770 socklen_t size; 1601 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len); 1602 1603 lsa->len = sep->se_lsa->len; 1604 if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0) 1605 return; 1771 1606 1772 1607 t = time(NULL); 1773 1774 size = sizeof(sa); 1775 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 1776 return; 1777 if (dg_badinput((struct sockaddr_in *) &sa)) 1778 return; 1779 (void) sprintf(buffer, "%.24s\r\n", ctime(&t)); 1780 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 1608 sprintf(line, "%.24s\r\n", ctime(&t)); 1609 sendto(s, line, strlen(line), 0, &lsa->u.sa, lsa->len); 1781 1610 } 1782 1611 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
Note:
See TracChangeset
for help on using the changeset viewer.