3
0

inetd.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804
  1. /* $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $ */
  2. /* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */
  3. /* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */
  4. /* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */
  5. /*
  6. * Copyright (c) 1983,1991 The Regents of the University of California.
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. All advertising materials mentioning features or use of this software
  18. * must display the following acknowledgement:
  19. * This product includes software developed by the University of
  20. * California, Berkeley and its contributors.
  21. * 4. Neither the name of the University nor the names of its contributors
  22. * may be used to endorse or promote products derived from this software
  23. * without specific prior written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35. * SUCH DAMAGE.
  36. */
  37. /*
  38. * Inetd - Internet super-server
  39. *
  40. * This program invokes all internet services as needed.
  41. * connection-oriented services are invoked each time a
  42. * connection is made, by creating a process. This process
  43. * is passed the connection as file descriptor 0 and is
  44. * expected to do a getpeername to find out the source host
  45. * and port.
  46. *
  47. * Datagram oriented services are invoked when a datagram
  48. * arrives; a process is created and passed a pending message
  49. * on file descriptor 0. Datagram servers may either connect
  50. * to their peer, freeing up the original socket for inetd
  51. * to receive further messages on, or ``take over the socket'',
  52. * processing all arriving datagrams and, eventually, timing
  53. * out. The first type of server is said to be ``multi-threaded'';
  54. * the second type of server ``single-threaded''.
  55. *
  56. * Inetd uses a configuration file which is read at startup
  57. * and, possibly, at some later time in response to a hangup signal.
  58. * The configuration file is ``free format'' with fields given in the
  59. * order shown below. Continuation lines for an entry must begin with
  60. * a space or tab. All fields must be present in each entry.
  61. *
  62. * service name must be in /etc/services
  63. * socket type stream/dgram/raw/rdm/seqpacket
  64. * protocol must be in /etc/protocols
  65. * wait/nowait[.max] single-threaded/multi-threaded, max #
  66. * user[.group] or user[:group] user/group to run daemon as
  67. * server program full path name
  68. * server program arguments maximum of MAXARGS (20)
  69. *
  70. * For RPC services
  71. * service name/version must be in /etc/rpc
  72. * socket type stream/dgram/raw/rdm/seqpacket
  73. * protocol must be in /etc/protocols
  74. * wait/nowait[.max] single-threaded/multi-threaded
  75. * user[.group] or user[:group] user to run daemon as
  76. * server program full path name
  77. * server program arguments maximum of MAXARGS (20)
  78. *
  79. * For non-RPC services, the "service name" can be of the form
  80. * hostaddress:servicename, in which case the hostaddress is used
  81. * as the host portion of the address to listen on. If hostaddress
  82. * consists of a single `*' character, INADDR_ANY is used.
  83. *
  84. * A line can also consist of just
  85. * hostaddress:
  86. * where hostaddress is as in the preceding paragraph. Such a line must
  87. * have no further fields; the specified hostaddress is remembered and
  88. * used for all further lines that have no hostaddress specified,
  89. * until the next such line (or EOF). (This is why * is provided to
  90. * allow explicit specification of INADDR_ANY.) A line
  91. * *:
  92. * is implicitly in effect at the beginning of the file.
  93. *
  94. * The hostaddress specifier may (and often will) contain dots;
  95. * the service name must not.
  96. *
  97. * For RPC services, host-address specifiers are accepted and will
  98. * work to some extent; however, because of limitations in the
  99. * portmapper interface, it will not work to try to give more than
  100. * one line for any given RPC service, even if the host-address
  101. * specifiers are different.
  102. *
  103. * Comment lines are indicated by a `#' in column 1.
  104. */
  105. /*
  106. * Here's the scoop concerning the user[.:]group feature:
  107. *
  108. * 1) set-group-option off.
  109. *
  110. * a) user = root: NO setuid() or setgid() is done
  111. *
  112. * b) other: setgid(primary group as found in passwd)
  113. * initgroups(name, primary group)
  114. * setuid()
  115. *
  116. * 2) set-group-option on.
  117. *
  118. * a) user = root: setgid(specified group)
  119. * NO initgroups()
  120. * NO setuid()
  121. *
  122. * b) other: setgid(specified group)
  123. * initgroups(name, specified group)
  124. * setuid()
  125. *
  126. */
  127. #include <sys/param.h>
  128. #include <sys/stat.h>
  129. #include <sys/ioctl.h>
  130. #include <sys/socket.h>
  131. #include <sys/un.h>
  132. #include <sys/file.h>
  133. #include <sys/wait.h>
  134. #include <sys/time.h>
  135. #include <sys/resource.h>
  136. #include <netinet/in.h>
  137. #include <arpa/inet.h>
  138. #include <errno.h>
  139. #include <signal.h>
  140. #include <netdb.h>
  141. #include <syslog.h>
  142. #include <stdio.h>
  143. #include <stdlib.h>
  144. #include <unistd.h>
  145. #include <string.h>
  146. #include <ctype.h>
  147. #include <time.h>
  148. #include "busybox.h"
  149. //#define CONFIG_FEATURE_INETD_RPC
  150. //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
  151. //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
  152. //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
  153. //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
  154. //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
  155. //#define CONFIG_FEATURE_IPV6
  156. #ifdef CONFIG_FEATURE_INETD_RPC
  157. #include <rpc/rpc.h>
  158. #include <rpc/pmap_clnt.h>
  159. #endif
  160. #define _PATH_INETDCONF "/etc/inetd.conf"
  161. #define _PATH_INETDPID "/var/run/inetd.pid"
  162. #define TOOMANY 0 /* don't start more than TOOMANY */
  163. #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
  164. #define RETRYTIME (60*10) /* retry after bind or server fail */
  165. #ifndef RLIMIT_NOFILE
  166. #define RLIMIT_NOFILE RLIMIT_OFILE
  167. #endif
  168. #ifndef OPEN_MAX
  169. #define OPEN_MAX 64
  170. #endif
  171. /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
  172. #define FD_MARGIN (8)
  173. static rlim_t rlim_ofile_cur = OPEN_MAX;
  174. static struct rlimit rlim_ofile;
  175. /* Check unsupporting builtin */
  176. #if defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO || \
  177. defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD || \
  178. defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME || \
  179. defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME || \
  180. defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
  181. # define INETD_FEATURE_ENABLED
  182. #endif
  183. #if defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO || \
  184. defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD || \
  185. defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
  186. # define INETD_SETPROCTITLE
  187. #endif
  188. typedef struct servtab
  189. {
  190. char *se_hostaddr; /* host address to listen on */
  191. char *se_service; /* name of service */
  192. int se_socktype; /* type of socket to use */
  193. int se_family; /* address family */
  194. char *se_proto; /* protocol used */
  195. #ifdef CONFIG_FEATURE_INETD_RPC
  196. int se_rpcprog; /* rpc program number */
  197. int se_rpcversl; /* rpc program lowest version */
  198. int se_rpcversh; /* rpc program highest version */
  199. #define isrpcservice(sep) ((sep)->se_rpcversl != 0)
  200. #else
  201. #define isrpcservice(sep) 0
  202. #endif
  203. pid_t se_wait; /* single threaded server */
  204. short se_checked; /* looked at during merge */
  205. char *se_user; /* user name to run as */
  206. char *se_group; /* group name to run as */
  207. #ifdef INETD_FEATURE_ENABLED
  208. const struct biltin *se_bi; /* if built-in, description */
  209. #endif
  210. char *se_server; /* server program */
  211. #define MAXARGV 20
  212. char *se_argv[MAXARGV + 1]; /* program arguments */
  213. int se_fd; /* open descriptor */
  214. union
  215. {
  216. struct sockaddr se_un_ctrladdr;
  217. struct sockaddr_in se_un_ctrladdr_in;
  218. #ifdef CONFIG_FEATURE_IPV6
  219. struct sockaddr_in6 se_un_ctrladdr_in6;
  220. #endif
  221. struct sockaddr_un se_un_ctrladdr_un;
  222. } se_un; /* bound address */
  223. #define se_ctrladdr se_un.se_un_ctrladdr
  224. #define se_ctrladdr_in se_un.se_un_ctrladdr_in
  225. #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
  226. #define se_ctrladdr_un se_un.se_un_ctrladdr_un
  227. int se_ctrladdr_size;
  228. int se_max; /* max # of instances of this service */
  229. int se_count; /* number started since se_time */
  230. struct timeval se_time; /* start of se_count */
  231. struct servtab *se_next;
  232. } servtab_t;
  233. static servtab_t *servtab;
  234. #ifdef INETD_FEATURE_ENABLED
  235. struct biltin
  236. {
  237. const char *bi_service; /* internally provided service name */
  238. int bi_socktype; /* type of socket supported */
  239. short bi_fork; /* 1 if should fork before call */
  240. short bi_wait; /* 1 if should wait for child */
  241. void (*bi_fn) (int, servtab_t *);
  242. };
  243. /* Echo received data */
  244. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
  245. static void echo_stream (int, servtab_t *);
  246. static void echo_dg (int, servtab_t *);
  247. #endif
  248. /* Internet /dev/null */
  249. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
  250. static void discard_stream (int, servtab_t *);
  251. static void discard_dg (int, servtab_t *);
  252. #endif
  253. /* Return 32 bit time since 1900 */
  254. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
  255. static void machtime_stream (int, servtab_t *);
  256. static void machtime_dg (int, servtab_t *);
  257. #endif
  258. /* Return human-readable time */
  259. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
  260. static void daytime_stream (int, servtab_t *);
  261. static void daytime_dg (int, servtab_t *);
  262. #endif
  263. /* Familiar character generator */
  264. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
  265. static void chargen_stream (int, servtab_t *);
  266. static void chargen_dg (int, servtab_t *);
  267. #endif
  268. static const struct biltin biltins[] = {
  269. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
  270. /* Echo received data */
  271. {"echo", SOCK_STREAM, 1, 0, echo_stream,},
  272. {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
  273. #endif
  274. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
  275. /* Internet /dev/null */
  276. {"discard", SOCK_STREAM, 1, 0, discard_stream,},
  277. {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
  278. #endif
  279. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
  280. /* Return 32 bit time since 1900 */
  281. {"time", SOCK_STREAM, 0, 0, machtime_stream,},
  282. {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
  283. #endif
  284. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
  285. /* Return human-readable time */
  286. {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
  287. {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
  288. #endif
  289. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
  290. /* Familiar character generator */
  291. {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
  292. {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
  293. #endif
  294. {NULL, 0, 0, 0, NULL}
  295. };
  296. #endif /* INETD_FEATURE_ENABLED */
  297. static int global_queuelen = 128;
  298. static int nsock, maxsock;
  299. static fd_set allsock;
  300. static int toomany = TOOMANY;
  301. static int timingout;
  302. static struct servent *sp;
  303. static uid_t uid;
  304. static char *CONFIG = _PATH_INETDCONF;
  305. static FILE *fconfig;
  306. static char line[1024];
  307. static char *defhost;
  308. static char *newstr (char *cp)
  309. {
  310. if ((cp = strdup (cp ? cp : "")))
  311. return (cp);
  312. syslog (LOG_ERR, "strdup: %m");
  313. exit (1);
  314. }
  315. static int setconfig (void)
  316. {
  317. free (defhost);
  318. defhost = newstr ("*");
  319. if (fconfig != NULL) {
  320. fseek (fconfig, 0L, SEEK_SET);
  321. return (1);
  322. }
  323. fconfig = fopen (CONFIG, "r");
  324. return (fconfig != NULL);
  325. }
  326. static void endconfig (void)
  327. {
  328. if (fconfig) {
  329. (void) fclose (fconfig);
  330. fconfig = NULL;
  331. }
  332. free (defhost);
  333. defhost = 0;
  334. }
  335. #ifdef CONFIG_FEATURE_INETD_RPC
  336. static void register_rpc (servtab_t *sep)
  337. {
  338. int n;
  339. struct sockaddr_in ir_sin;
  340. struct protoent *pp;
  341. socklen_t size;
  342. if ((pp = getprotobyname (sep->se_proto + 4)) == NULL) {
  343. syslog (LOG_ERR, "%s: getproto: %m", sep->se_proto);
  344. return;
  345. }
  346. size = sizeof ir_sin;
  347. if (getsockname (sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
  348. syslog (LOG_ERR, "%s/%s: getsockname: %m",
  349. sep->se_service, sep->se_proto);
  350. return;
  351. }
  352. for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
  353. (void) pmap_unset (sep->se_rpcprog, n);
  354. if (!pmap_set (sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port)))
  355. syslog (LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
  356. sep->se_service, sep->se_proto,
  357. sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port));
  358. }
  359. }
  360. static void unregister_rpc (servtab_t *sep)
  361. {
  362. int n;
  363. for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
  364. if (!pmap_unset (sep->se_rpcprog, n))
  365. syslog (LOG_ERR, "pmap_unset(%u, %u)", sep->se_rpcprog, n);
  366. }
  367. }
  368. #endif /* CONFIG_FEATURE_INETD_RPC */
  369. static void freeconfig (servtab_t *cp)
  370. {
  371. int i;
  372. free (cp->se_hostaddr);
  373. free (cp->se_service);
  374. free (cp->se_proto);
  375. free (cp->se_user);
  376. free (cp->se_group);
  377. free (cp->se_server);
  378. for (i = 0; i < MAXARGV; i++)
  379. free (cp->se_argv[i]);
  380. }
  381. static int bump_nofile (void)
  382. {
  383. #define FD_CHUNK 32
  384. struct rlimit rl;
  385. if (getrlimit (RLIMIT_NOFILE, &rl) < 0) {
  386. syslog (LOG_ERR, "getrlimit: %m");
  387. return -1;
  388. }
  389. rl.rlim_cur = MIN (rl.rlim_max, rl.rlim_cur + FD_CHUNK);
  390. rl.rlim_cur = MIN (FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
  391. if (rl.rlim_cur <= rlim_ofile_cur) {
  392. syslog (LOG_ERR, "bump_nofile: cannot extend file limit, max = %d",
  393. (int) rl.rlim_cur);
  394. return -1;
  395. }
  396. if (setrlimit (RLIMIT_NOFILE, &rl) < 0) {
  397. syslog (LOG_ERR, "setrlimit: %m");
  398. return -1;
  399. }
  400. rlim_ofile_cur = rl.rlim_cur;
  401. return 0;
  402. }
  403. static void setup (servtab_t *sep)
  404. {
  405. int on = 1;
  406. int r;
  407. if ((sep->se_fd = socket (sep->se_family, sep->se_socktype, 0)) < 0) {
  408. syslog (LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto);
  409. return;
  410. }
  411. #define turnon(fd, opt) \
  412. setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  413. if (turnon (sep->se_fd, SO_REUSEADDR) < 0)
  414. syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  415. #undef turnon
  416. #ifdef CONFIG_FEATURE_INETD_RPC
  417. if (isrpcservice (sep)) {
  418. struct passwd *pwd;
  419. /*
  420. * for RPC services, attempt to use a reserved port
  421. * if they are going to be running as root.
  422. *
  423. * Also, zero out the port for all RPC services; let bind()
  424. * find one.
  425. */
  426. sep->se_ctrladdr_in.sin_port = 0;
  427. if (sep->se_user && (pwd = getpwnam (sep->se_user)) &&
  428. pwd->pw_uid == 0 && uid == 0)
  429. r = bindresvport (sep->se_fd, &sep->se_ctrladdr_in);
  430. else {
  431. r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
  432. if (r == 0) {
  433. socklen_t len = sep->se_ctrladdr_size;
  434. int saveerrno = errno;
  435. /* update se_ctrladdr_in.sin_port */
  436. r = getsockname (sep->se_fd, &sep->se_ctrladdr, &len);
  437. if (r <= 0)
  438. errno = saveerrno;
  439. }
  440. }
  441. } else
  442. #endif
  443. r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
  444. if (r < 0) {
  445. syslog (LOG_ERR, "%s/%s (%d): bind: %m",
  446. sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
  447. close (sep->se_fd);
  448. sep->se_fd = -1;
  449. if (!timingout) {
  450. timingout = 1;
  451. alarm (RETRYTIME);
  452. }
  453. return;
  454. }
  455. if (sep->se_socktype == SOCK_STREAM)
  456. listen (sep->se_fd, global_queuelen);
  457. FD_SET (sep->se_fd, &allsock);
  458. nsock++;
  459. if (sep->se_fd > maxsock) {
  460. maxsock = sep->se_fd;
  461. if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
  462. bump_nofile ();
  463. }
  464. }
  465. static char *nextline (void)
  466. {
  467. char *cp;
  468. FILE *fd = fconfig;
  469. if (fgets (line, sizeof (line), fd) == NULL)
  470. return (NULL);
  471. cp = strchr (line, '\n');
  472. if (cp)
  473. *cp = '\0';
  474. return (line);
  475. }
  476. static char *skip (char **cpp) /* int report; */
  477. {
  478. char *cp = *cpp;
  479. char *start;
  480. /* erp: */
  481. if (*cpp == NULL) {
  482. /* if (report) */
  483. /* syslog(LOG_ERR, "syntax error in inetd config file"); */
  484. return (NULL);
  485. }
  486. again:
  487. while (*cp == ' ' || *cp == '\t')
  488. cp++;
  489. if (*cp == '\0') {
  490. int c;
  491. c = getc (fconfig);
  492. (void) ungetc (c, fconfig);
  493. if (c == ' ' || c == '\t')
  494. if ((cp = nextline ()))
  495. goto again;
  496. *cpp = NULL;
  497. /* goto erp; */
  498. return (NULL);
  499. }
  500. start = cp;
  501. while (*cp && *cp != ' ' && *cp != '\t')
  502. cp++;
  503. if (*cp != '\0')
  504. *cp++ = '\0';
  505. /* if ((*cpp = cp) == NULL) */
  506. /* goto erp; */
  507. *cpp = cp;
  508. return (start);
  509. }
  510. static servtab_t *new_servtab(void)
  511. {
  512. servtab_t *sep;
  513. sep = (servtab_t *) malloc (sizeof (servtab_t));
  514. if (sep == NULL) {
  515. syslog (LOG_ERR, bb_msg_memory_exhausted);
  516. exit (1);
  517. }
  518. return sep;
  519. }
  520. static servtab_t *dupconfig (servtab_t *sep)
  521. {
  522. servtab_t *newtab;
  523. int argc;
  524. newtab = new_servtab();
  525. memset (newtab, 0, sizeof (servtab_t));
  526. newtab->se_service = sep->se_service ? newstr (sep->se_service) : NULL;
  527. newtab->se_socktype = sep->se_socktype;
  528. newtab->se_family = sep->se_family;
  529. newtab->se_proto = sep->se_proto ? newstr (sep->se_proto) : NULL;
  530. #ifdef CONFIG_FEATURE_INETD_RPC
  531. newtab->se_rpcprog = sep->se_rpcprog;
  532. newtab->se_rpcversl = sep->se_rpcversl;
  533. newtab->se_rpcversh = sep->se_rpcversh;
  534. #endif
  535. newtab->se_wait = sep->se_wait;
  536. newtab->se_user = sep->se_user ? newstr (sep->se_user) : NULL;
  537. newtab->se_group = sep->se_group ? newstr (sep->se_group) : NULL;
  538. #ifdef INETD_FEATURE_ENABLED
  539. newtab->se_bi = sep->se_bi;
  540. #endif
  541. newtab->se_server = sep->se_server ? newstr (sep->se_server) : 0;
  542. for (argc = 0; argc <= MAXARGV; argc++)
  543. newtab->se_argv[argc] = sep->se_argv[argc] ?
  544. newstr (sep->se_argv[argc]) : NULL;
  545. newtab->se_max = sep->se_max;
  546. return (newtab);
  547. }
  548. static servtab_t *getconfigent (void)
  549. {
  550. servtab_t *sep;
  551. int argc;
  552. char *cp, *arg;
  553. char *hostdelim;
  554. servtab_t *nsep;
  555. servtab_t *psep;
  556. sep = new_servtab();
  557. /* memset(sep, 0, sizeof *sep); */
  558. more:
  559. /* freeconfig(sep); */
  560. while ((cp = nextline ()) && *cp == '#');
  561. if (cp == NULL) {
  562. /* free(sep); */
  563. return (NULL);
  564. }
  565. memset ((char *) sep, 0, sizeof *sep);
  566. arg = skip (&cp);
  567. if (arg == NULL) {
  568. /* A blank line. */
  569. goto more;
  570. }
  571. /* Check for a host name. */
  572. hostdelim = strrchr (arg, ':');
  573. if (hostdelim) {
  574. *hostdelim = '\0';
  575. sep->se_hostaddr = newstr (arg);
  576. arg = hostdelim + 1;
  577. /*
  578. * If the line is of the form `host:', then just change the
  579. * default host for the following lines.
  580. */
  581. if (*arg == '\0') {
  582. arg = skip (&cp);
  583. if (cp == NULL) {
  584. free (defhost);
  585. defhost = sep->se_hostaddr;
  586. goto more;
  587. }
  588. }
  589. } else
  590. sep->se_hostaddr = newstr (defhost);
  591. sep->se_service = newstr (arg);
  592. arg = skip (&cp);
  593. if (strcmp (arg, "stream") == 0)
  594. sep->se_socktype = SOCK_STREAM;
  595. else if (strcmp (arg, "dgram") == 0)
  596. sep->se_socktype = SOCK_DGRAM;
  597. else if (strcmp (arg, "rdm") == 0)
  598. sep->se_socktype = SOCK_RDM;
  599. else if (strcmp (arg, "seqpacket") == 0)
  600. sep->se_socktype = SOCK_SEQPACKET;
  601. else if (strcmp (arg, "raw") == 0)
  602. sep->se_socktype = SOCK_RAW;
  603. else
  604. sep->se_socktype = -1;
  605. sep->se_proto = newstr (skip (&cp));
  606. if (strcmp (sep->se_proto, "unix") == 0) {
  607. sep->se_family = AF_UNIX;
  608. } else {
  609. sep->se_family = AF_INET;
  610. if (sep->se_proto[strlen (sep->se_proto) - 1] == '6')
  611. #ifdef CONFIG_FEATURE_IPV6
  612. sep->se_family = AF_INET6;
  613. #else
  614. syslog (LOG_ERR, "%s: IPV6 not supported", sep->se_proto);
  615. #endif
  616. if (strncmp (sep->se_proto, "rpc/", 4) == 0) {
  617. #ifdef CONFIG_FEATURE_INETD_RPC
  618. char *p, *ccp;
  619. long l;
  620. p = strchr (sep->se_service, '/');
  621. if (p == 0) {
  622. syslog (LOG_ERR, "%s: no rpc version", sep->se_service);
  623. goto more;
  624. }
  625. *p++ = '\0';
  626. l = strtol (p, &ccp, 0);
  627. if (ccp == p || l < 0 || l > INT_MAX) {
  628. badafterall:
  629. syslog (LOG_ERR, "%s/%s: bad rpc version", sep->se_service, p);
  630. goto more;
  631. }
  632. sep->se_rpcversl = sep->se_rpcversh = l;
  633. if (*ccp == '-') {
  634. p = ccp + 1;
  635. l = strtol (p, &ccp, 0);
  636. if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
  637. goto badafterall;
  638. sep->se_rpcversh = l;
  639. } else if (*ccp != '\0')
  640. goto badafterall;
  641. #else
  642. syslog (LOG_ERR, "%s: rpc services not supported", sep->se_service);
  643. #endif
  644. }
  645. }
  646. arg = skip (&cp);
  647. if (arg == NULL)
  648. goto more;
  649. {
  650. char *s = strchr (arg, '.');
  651. if (s) {
  652. *s++ = '\0';
  653. sep->se_max = atoi (s);
  654. } else
  655. sep->se_max = toomany;
  656. }
  657. sep->se_wait = strcmp (arg, "wait") == 0;
  658. /* if ((arg = skip(&cp, 1)) == NULL) */
  659. /* goto more; */
  660. sep->se_user = newstr (skip (&cp));
  661. arg = strchr (sep->se_user, '.');
  662. if (arg == NULL)
  663. arg = strchr (sep->se_user, ':');
  664. if (arg) {
  665. *arg++ = '\0';
  666. sep->se_group = newstr (arg);
  667. }
  668. /* if ((arg = skip(&cp, 1)) == NULL) */
  669. /* goto more; */
  670. sep->se_server = newstr (skip (&cp));
  671. if (strcmp (sep->se_server, "internal") == 0) {
  672. #ifdef INETD_FEATURE_ENABLED
  673. const struct biltin *bi;
  674. for (bi = biltins; bi->bi_service; bi++)
  675. if (bi->bi_socktype == sep->se_socktype &&
  676. strcmp (bi->bi_service, sep->se_service) == 0)
  677. break;
  678. if (bi->bi_service == 0) {
  679. syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
  680. goto more;
  681. }
  682. sep->se_bi = bi;
  683. sep->se_wait = bi->bi_wait;
  684. #else
  685. syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
  686. goto more;
  687. #endif
  688. }
  689. #ifdef INETD_FEATURE_ENABLED
  690. else
  691. sep->se_bi = NULL;
  692. #endif
  693. argc = 0;
  694. for (arg = skip (&cp); cp; arg = skip (&cp)) {
  695. if (argc < MAXARGV)
  696. sep->se_argv[argc++] = newstr (arg);
  697. }
  698. while (argc <= MAXARGV)
  699. sep->se_argv[argc++] = NULL;
  700. /*
  701. * Now that we've processed the entire line, check if the hostname
  702. * specifier was a comma separated list of hostnames. If so
  703. * we'll make new entries for each address.
  704. */
  705. while ((hostdelim = strrchr (sep->se_hostaddr, ',')) != NULL) {
  706. nsep = dupconfig (sep);
  707. /*
  708. * NULL terminate the hostname field of the existing entry,
  709. * and make a dup for the new entry.
  710. */
  711. *hostdelim++ = '\0';
  712. nsep->se_hostaddr = newstr (hostdelim);
  713. nsep->se_next = sep->se_next;
  714. sep->se_next = nsep;
  715. }
  716. nsep = sep;
  717. while (nsep != NULL) {
  718. nsep->se_checked = 1;
  719. if (nsep->se_family == AF_INET) {
  720. if (!strcmp (nsep->se_hostaddr, "*"))
  721. nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
  722. else if (!inet_aton (nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
  723. struct hostent *hp;
  724. hp = gethostbyname (nsep->se_hostaddr);
  725. if (hp == 0) {
  726. syslog (LOG_ERR, "%s: unknown host", nsep->se_hostaddr);
  727. nsep->se_checked = 0;
  728. goto skip;
  729. } else if (hp->h_addrtype != AF_INET) {
  730. syslog (LOG_ERR,
  731. "%s: address isn't an Internet "
  732. "address", nsep->se_hostaddr);
  733. nsep->se_checked = 0;
  734. goto skip;
  735. } else {
  736. int i = 1;
  737. memmove (&nsep->se_ctrladdr_in.sin_addr,
  738. hp->h_addr_list[0], sizeof (struct in_addr));
  739. while (hp->h_addr_list[i] != NULL) {
  740. psep = dupconfig (nsep);
  741. psep->se_hostaddr = newstr (nsep->se_hostaddr);
  742. psep->se_checked = 1;
  743. memmove (&psep->se_ctrladdr_in.sin_addr,
  744. hp->h_addr_list[i], sizeof (struct in_addr));
  745. psep->se_ctrladdr_size = sizeof (psep->se_ctrladdr_in);
  746. i++;
  747. /* Prepend to list, don't want to look up its */
  748. /* hostname again. */
  749. psep->se_next = sep;
  750. sep = psep;
  751. }
  752. }
  753. }
  754. }
  755. /* XXX BUG?: is this skip: label supposed to remain? */
  756. skip:
  757. nsep = nsep->se_next;
  758. }
  759. /*
  760. * Finally, free any entries which failed the gethostbyname
  761. * check.
  762. */
  763. psep = NULL;
  764. nsep = sep;
  765. while (nsep != NULL) {
  766. servtab_t *tsep;
  767. if (nsep->se_checked == 0) {
  768. tsep = nsep;
  769. if (psep == NULL) {
  770. sep = nsep->se_next;
  771. nsep = sep;
  772. } else {
  773. nsep = nsep->se_next;
  774. psep->se_next = nsep;
  775. }
  776. freeconfig (tsep);
  777. } else {
  778. nsep->se_checked = 0;
  779. psep = nsep;
  780. nsep = nsep->se_next;
  781. }
  782. }
  783. return (sep);
  784. }
  785. #define Block_Using_Signals(m) do { sigemptyset(&m); \
  786. sigaddset(&m, SIGCHLD); \
  787. sigaddset(&m, SIGHUP); \
  788. sigaddset(&m, SIGALRM); \
  789. sigprocmask(SIG_BLOCK, &m, NULL); \
  790. } while(0)
  791. static servtab_t *enter (servtab_t *cp)
  792. {
  793. servtab_t *sep;
  794. sigset_t omask;
  795. sep = new_servtab();
  796. *sep = *cp;
  797. sep->se_fd = -1;
  798. #ifdef CONFIG_FEATURE_INETD_RPC
  799. sep->se_rpcprog = -1;
  800. #endif
  801. Block_Using_Signals(omask);
  802. sep->se_next = servtab;
  803. servtab = sep;
  804. sigprocmask(SIG_UNBLOCK, &omask, NULL);
  805. return (sep);
  806. }
  807. static int matchconf (servtab_t *old, servtab_t *new)
  808. {
  809. if (strcmp (old->se_service, new->se_service) != 0)
  810. return (0);
  811. if (strcmp (old->se_hostaddr, new->se_hostaddr) != 0)
  812. return (0);
  813. if (strcmp (old->se_proto, new->se_proto) != 0)
  814. return (0);
  815. /*
  816. * If the new servtab is bound to a specific address, check that the
  817. * old servtab is bound to the same entry. If the new service is not
  818. * bound to a specific address then the check of se_hostaddr above
  819. * is sufficient.
  820. */
  821. if (old->se_family == AF_INET && new->se_family == AF_INET &&
  822. memcmp (&old->se_ctrladdr_in.sin_addr,
  823. &new->se_ctrladdr_in.sin_addr,
  824. sizeof (new->se_ctrladdr_in.sin_addr)) != 0)
  825. return (0);
  826. #ifdef CONFIG_FEATURE_IPV6
  827. if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
  828. memcmp (&old->se_ctrladdr_in6.sin6_addr,
  829. &new->se_ctrladdr_in6.sin6_addr,
  830. sizeof (new->se_ctrladdr_in6.sin6_addr)) != 0)
  831. return (0);
  832. #endif
  833. return (1);
  834. }
  835. static void config (int sig ATTRIBUTE_UNUSED)
  836. {
  837. servtab_t *sep, *cp, **sepp;
  838. sigset_t omask;
  839. int add;
  840. size_t n;
  841. char protoname[10];
  842. if (!setconfig ()) {
  843. syslog (LOG_ERR, "%s: %m", CONFIG);
  844. return;
  845. }
  846. for (sep = servtab; sep; sep = sep->se_next)
  847. sep->se_checked = 0;
  848. cp = getconfigent ();
  849. while (cp != NULL) {
  850. for (sep = servtab; sep; sep = sep->se_next)
  851. if (matchconf (sep, cp))
  852. break;
  853. add = 0;
  854. if (sep != 0) {
  855. int i;
  856. #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
  857. Block_Using_Signals(omask);
  858. /*
  859. * sep->se_wait may be holding the pid of a daemon
  860. * that we're waiting for. If so, don't overwrite
  861. * it unless the config file explicitly says don't
  862. * wait.
  863. */
  864. if (
  865. #ifdef INETD_FEATURE_ENABLED
  866. cp->se_bi == 0 &&
  867. #endif
  868. (sep->se_wait == 1 || cp->se_wait == 0))
  869. sep->se_wait = cp->se_wait;
  870. SWAP (int, cp->se_max, sep->se_max);
  871. SWAP (char *, sep->se_user, cp->se_user);
  872. SWAP (char *, sep->se_group, cp->se_group);
  873. SWAP (char *, sep->se_server, cp->se_server);
  874. for (i = 0; i < MAXARGV; i++)
  875. SWAP (char *, sep->se_argv[i], cp->se_argv[i]);
  876. #undef SWAP
  877. #ifdef CONFIG_FEATURE_INETD_RPC
  878. if (isrpcservice (sep))
  879. unregister_rpc (sep);
  880. sep->se_rpcversl = cp->se_rpcversl;
  881. sep->se_rpcversh = cp->se_rpcversh;
  882. #endif
  883. sigprocmask(SIG_UNBLOCK, &omask, NULL);
  884. freeconfig (cp);
  885. add = 1;
  886. } else {
  887. sep = enter (cp);
  888. }
  889. sep->se_checked = 1;
  890. switch (sep->se_family) {
  891. case AF_UNIX:
  892. if (sep->se_fd != -1)
  893. break;
  894. (void) unlink (sep->se_service);
  895. n = strlen (sep->se_service);
  896. if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
  897. n = sizeof sep->se_ctrladdr_un.sun_path - 1;
  898. safe_strncpy (sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
  899. sep->se_ctrladdr_un.sun_family = AF_UNIX;
  900. sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
  901. setup (sep);
  902. break;
  903. case AF_INET:
  904. sep->se_ctrladdr_in.sin_family = AF_INET;
  905. /* se_ctrladdr_in was set in getconfigent */
  906. sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
  907. #ifdef CONFIG_FEATURE_INETD_RPC
  908. if (isrpcservice (sep)) {
  909. struct rpcent *rp;
  910. sep->se_rpcprog = atoi (sep->se_service);
  911. if (sep->se_rpcprog == 0) {
  912. rp = getrpcbyname (sep->se_service);
  913. if (rp == 0) {
  914. syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
  915. goto serv_unknown;
  916. }
  917. sep->se_rpcprog = rp->r_number;
  918. }
  919. if (sep->se_fd == -1)
  920. setup (sep);
  921. if (sep->se_fd != -1)
  922. register_rpc (sep);
  923. } else
  924. #endif
  925. {
  926. u_short port = htons (atoi (sep->se_service));
  927. if (!port) {
  928. /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
  929. if (isdigit (protoname[strlen (protoname) - 1]))
  930. protoname[strlen (protoname) - 1] = '\0';
  931. sp = getservbyname (sep->se_service, protoname);
  932. if (sp == 0) {
  933. syslog (LOG_ERR,
  934. "%s/%s: unknown service", sep->se_service, sep->se_proto);
  935. goto serv_unknown;
  936. }
  937. port = sp->s_port;
  938. }
  939. if (port != sep->se_ctrladdr_in.sin_port) {
  940. sep->se_ctrladdr_in.sin_port = port;
  941. if (sep->se_fd != -1) {
  942. FD_CLR (sep->se_fd, &allsock);
  943. nsock--;
  944. (void) close (sep->se_fd);
  945. }
  946. sep->se_fd = -1;
  947. }
  948. if (sep->se_fd == -1)
  949. setup (sep);
  950. }
  951. break;
  952. #ifdef CONFIG_FEATURE_IPV6
  953. case AF_INET6:
  954. sep->se_ctrladdr_in6.sin6_family = AF_INET6;
  955. /* se_ctrladdr_in was set in getconfigent */
  956. sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
  957. #ifdef CONFIG_FEATURE_INETD_RPC
  958. if (isrpcservice (sep)) {
  959. struct rpcent *rp;
  960. sep->se_rpcprog = atoi (sep->se_service);
  961. if (sep->se_rpcprog == 0) {
  962. rp = getrpcbyname (sep->se_service);
  963. if (rp == 0) {
  964. syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
  965. goto serv_unknown;
  966. }
  967. sep->se_rpcprog = rp->r_number;
  968. }
  969. if (sep->se_fd == -1)
  970. setup (sep);
  971. if (sep->se_fd != -1)
  972. register_rpc (sep);
  973. } else
  974. #endif
  975. {
  976. u_short port = htons (atoi (sep->se_service));
  977. if (!port) {
  978. /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
  979. if (isdigit (protoname[strlen (protoname) - 1]))
  980. protoname[strlen (protoname) - 1] = '\0';
  981. sp = getservbyname (sep->se_service, protoname);
  982. if (sp == 0) {
  983. syslog (LOG_ERR,
  984. "%s/%s: unknown service", sep->se_service, sep->se_proto);
  985. goto serv_unknown;
  986. }
  987. port = sp->s_port;
  988. }
  989. if (port != sep->se_ctrladdr_in6.sin6_port) {
  990. sep->se_ctrladdr_in6.sin6_port = port;
  991. if (sep->se_fd != -1) {
  992. FD_CLR (sep->se_fd, &allsock);
  993. nsock--;
  994. (void) close (sep->se_fd);
  995. }
  996. sep->se_fd = -1;
  997. }
  998. if (sep->se_fd == -1)
  999. setup (sep);
  1000. }
  1001. break;
  1002. #endif /* CONFIG_FEATURE_IPV6 */
  1003. }
  1004. serv_unknown:
  1005. if (cp->se_next != NULL) {
  1006. servtab_t *tmp = cp;
  1007. cp = cp->se_next;
  1008. free (tmp);
  1009. } else {
  1010. free (cp);
  1011. cp = getconfigent ();
  1012. }
  1013. }
  1014. endconfig ();
  1015. /*
  1016. * Purge anything not looked at above.
  1017. */
  1018. Block_Using_Signals(omask);
  1019. sepp = &servtab;
  1020. while ((sep = *sepp)) {
  1021. if (sep->se_checked) {
  1022. sepp = &sep->se_next;
  1023. continue;
  1024. }
  1025. *sepp = sep->se_next;
  1026. if (sep->se_fd != -1) {
  1027. FD_CLR (sep->se_fd, &allsock);
  1028. nsock--;
  1029. (void) close (sep->se_fd);
  1030. }
  1031. #ifdef CONFIG_FEATURE_INETD_RPC
  1032. if (isrpcservice (sep))
  1033. unregister_rpc (sep);
  1034. #endif
  1035. if (sep->se_family == AF_UNIX)
  1036. (void) unlink (sep->se_service);
  1037. freeconfig (sep);
  1038. free (sep);
  1039. }
  1040. sigprocmask(SIG_UNBLOCK, &omask, NULL);
  1041. }
  1042. static void reapchild (int sig ATTRIBUTE_UNUSED)
  1043. {
  1044. pid_t pid;
  1045. int save_errno = errno, status;
  1046. servtab_t *sep;
  1047. for (;;) {
  1048. pid = wait3 (&status, WNOHANG, NULL);
  1049. if (pid <= 0)
  1050. break;
  1051. for (sep = servtab; sep; sep = sep->se_next)
  1052. if (sep->se_wait == pid) {
  1053. if (WIFEXITED (status) && WEXITSTATUS (status))
  1054. syslog (LOG_WARNING,
  1055. "%s: exit status 0x%x",
  1056. sep->se_server, WEXITSTATUS (status));
  1057. else if (WIFSIGNALED (status))
  1058. syslog (LOG_WARNING,
  1059. "%s: exit signal 0x%x", sep->se_server, WTERMSIG (status));
  1060. sep->se_wait = 1;
  1061. FD_SET (sep->se_fd, &allsock);
  1062. nsock++;
  1063. }
  1064. }
  1065. errno = save_errno;
  1066. }
  1067. static void retry (int sig ATTRIBUTE_UNUSED)
  1068. {
  1069. servtab_t *sep;
  1070. timingout = 0;
  1071. for (sep = servtab; sep; sep = sep->se_next) {
  1072. if (sep->se_fd == -1) {
  1073. switch (sep->se_family) {
  1074. case AF_UNIX:
  1075. case AF_INET:
  1076. #ifdef CONFIG_FEATURE_IPV6
  1077. case AF_INET6:
  1078. #endif
  1079. setup (sep);
  1080. #ifdef CONFIG_FEATURE_INETD_RPC
  1081. if (sep->se_fd != -1 && isrpcservice (sep))
  1082. register_rpc (sep);
  1083. #endif
  1084. break;
  1085. }
  1086. }
  1087. }
  1088. }
  1089. static void goaway (int sig ATTRIBUTE_UNUSED)
  1090. {
  1091. servtab_t *sep;
  1092. /* XXX signal race walking sep list */
  1093. for (sep = servtab; sep; sep = sep->se_next) {
  1094. if (sep->se_fd == -1)
  1095. continue;
  1096. switch (sep->se_family) {
  1097. case AF_UNIX:
  1098. (void) unlink (sep->se_service);
  1099. break;
  1100. case AF_INET:
  1101. #ifdef CONFIG_FEATURE_IPV6
  1102. case AF_INET6:
  1103. #endif
  1104. #ifdef CONFIG_FEATURE_INETD_RPC
  1105. if (sep->se_wait == 1 && isrpcservice (sep))
  1106. unregister_rpc (sep); /* XXX signal race */
  1107. #endif
  1108. break;
  1109. }
  1110. (void) close (sep->se_fd);
  1111. }
  1112. (void) unlink (_PATH_INETDPID);
  1113. exit (0);
  1114. }
  1115. #ifdef INETD_SETPROCTITLE
  1116. static char **Argv;
  1117. static char *LastArg;
  1118. static void
  1119. inetd_setproctitle (char *a, int s)
  1120. {
  1121. socklen_t size;
  1122. char *cp;
  1123. struct sockaddr_in prt_sin;
  1124. char buf[80];
  1125. cp = Argv[0];
  1126. size = sizeof (prt_sin);
  1127. (void) snprintf (buf, sizeof buf, "-%s", a);
  1128. if (getpeername (s, (struct sockaddr *) &prt_sin, &size) == 0) {
  1129. char *sa = inet_ntoa (prt_sin.sin_addr);
  1130. buf[sizeof (buf) - 1 - strlen (sa) - 3] = '\0';
  1131. strcat (buf, " [");
  1132. strcat (buf, sa);
  1133. strcat (buf, "]");
  1134. }
  1135. strncpy (cp, buf, LastArg - cp);
  1136. cp += strlen (cp);
  1137. while (cp < LastArg)
  1138. *cp++ = ' ';
  1139. }
  1140. #endif
  1141. int
  1142. inetd_main (int argc, char *argv[])
  1143. {
  1144. servtab_t *sep;
  1145. struct passwd *pwd;
  1146. struct group *grp = NULL;
  1147. int tmpint;
  1148. struct sigaction sa, sapipe;
  1149. int opt;
  1150. pid_t pid;
  1151. char buf[50];
  1152. char *stoomany;
  1153. sigset_t omask, wait_mask;
  1154. #ifdef INETD_SETPROCTITLE
  1155. extern char **environ;
  1156. char **envp = environ;
  1157. Argv = argv;
  1158. if (envp == 0 || *envp == 0)
  1159. envp = argv;
  1160. while (*envp)
  1161. envp++;
  1162. LastArg = envp[-1] + strlen (envp[-1]);
  1163. #endif
  1164. openlog (bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  1165. opt = bb_getopt_ulflags (argc, argv, "R:f", &stoomany);
  1166. if(opt & 1) {
  1167. char *e;
  1168. toomany = strtoul (stoomany, &e, 0);
  1169. if (!(toomany >= 0 && *e == '\0')) {
  1170. toomany = TOOMANY;
  1171. syslog (LOG_ERR, "-R %s: bad value for service invocation rate", stoomany);
  1172. }
  1173. }
  1174. argc -= optind;
  1175. argv += optind;
  1176. uid = getuid ();
  1177. if (uid != 0)
  1178. CONFIG = NULL;
  1179. if (argc > 0)
  1180. CONFIG = argv[0];
  1181. if (CONFIG == NULL)
  1182. bb_error_msg_and_die ("non-root must specify a config file");
  1183. if (!(opt & 2)) {
  1184. #if defined(__uClinux__)
  1185. /* reexec for vfork() do continue parent */
  1186. vfork_daemon_rexec (0, 0, argc, argv, "-f");
  1187. #else
  1188. daemon (0, 0);
  1189. #endif /* uClinux */
  1190. } else {
  1191. setsid ();
  1192. }
  1193. if (uid == 0) {
  1194. gid_t gid = getgid ();
  1195. /* If run by hand, ensure groups vector gets trashed */
  1196. setgroups (1, &gid);
  1197. }
  1198. {
  1199. FILE *fp;
  1200. if ((fp = fopen (_PATH_INETDPID, "w")) != NULL) {
  1201. fprintf (fp, "%u\n", getpid ());
  1202. (void) fclose (fp);
  1203. }
  1204. }
  1205. if (getrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) {
  1206. syslog (LOG_ERR, "getrlimit: %m");
  1207. } else {
  1208. rlim_ofile_cur = rlim_ofile.rlim_cur;
  1209. if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
  1210. rlim_ofile_cur = OPEN_MAX;
  1211. }
  1212. memset ((char *) &sa, 0, sizeof (sa));
  1213. sigemptyset (&sa.sa_mask);
  1214. sigaddset (&sa.sa_mask, SIGALRM);
  1215. sigaddset (&sa.sa_mask, SIGCHLD);
  1216. sigaddset (&sa.sa_mask, SIGHUP);
  1217. sa.sa_handler = retry;
  1218. sigaction (SIGALRM, &sa, NULL);
  1219. /* doconfig(); */
  1220. config (SIGHUP);
  1221. sa.sa_handler = config;
  1222. sigaction (SIGHUP, &sa, NULL);
  1223. sa.sa_handler = reapchild;
  1224. sigaction (SIGCHLD, &sa, NULL);
  1225. sa.sa_handler = goaway;
  1226. sigaction (SIGTERM, &sa, NULL);
  1227. sa.sa_handler = goaway;
  1228. sigaction (SIGINT, &sa, NULL);
  1229. sa.sa_handler = SIG_IGN;
  1230. sigaction (SIGPIPE, &sa, &sapipe);
  1231. memset(&wait_mask, 0, sizeof(wait_mask));
  1232. {
  1233. /* space for daemons to overwrite environment for ps */
  1234. #define DUMMYSIZE 100
  1235. char dummy[DUMMYSIZE];
  1236. (void) memset (dummy, 'x', DUMMYSIZE - 1);
  1237. dummy[DUMMYSIZE - 1] = '\0';
  1238. (void) setenv ("inetd_dummy", dummy, 1);
  1239. }
  1240. for (;;) {
  1241. int n, ctrl = -1;
  1242. fd_set readable;
  1243. if (nsock == 0) {
  1244. Block_Using_Signals(omask);
  1245. while (nsock == 0)
  1246. sigsuspend (&wait_mask);
  1247. sigprocmask(SIG_UNBLOCK, &omask, NULL);
  1248. }
  1249. readable = allsock;
  1250. if ((n = select (maxsock + 1, &readable, NULL, NULL, NULL)) <= 0) {
  1251. if (n < 0 && errno != EINTR) {
  1252. syslog (LOG_WARNING, "select: %m");
  1253. sleep (1);
  1254. }
  1255. continue;
  1256. }
  1257. for (sep = servtab; n && sep; sep = sep->se_next)
  1258. if (sep->se_fd != -1 && FD_ISSET (sep->se_fd, &readable)) {
  1259. n--;
  1260. if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
  1261. ctrl = accept (sep->se_fd, NULL, NULL);
  1262. if (ctrl < 0) {
  1263. if (errno == EINTR)
  1264. continue;
  1265. syslog (LOG_WARNING, "accept (for %s): %m", sep->se_service);
  1266. continue;
  1267. }
  1268. if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
  1269. struct sockaddr_in peer;
  1270. socklen_t plen = sizeof (peer);
  1271. if (getpeername (ctrl, (struct sockaddr *) &peer, &plen) < 0) {
  1272. syslog (LOG_WARNING, "could not getpeername");
  1273. close (ctrl);
  1274. continue;
  1275. }
  1276. if (ntohs (peer.sin_port) == 20) {
  1277. /* XXX ftp bounce */
  1278. close (ctrl);
  1279. continue;
  1280. }
  1281. }
  1282. } else
  1283. ctrl = sep->se_fd;
  1284. Block_Using_Signals(omask);
  1285. pid = 0;
  1286. #ifdef INETD_FEATURE_ENABLED
  1287. if (sep->se_bi == 0 || sep->se_bi->bi_fork)
  1288. #endif
  1289. {
  1290. if (sep->se_count++ == 0)
  1291. (void) gettimeofday (&sep->se_time, NULL);
  1292. else if (toomany > 0 && sep->se_count >= sep->se_max) {
  1293. struct timeval now;
  1294. (void) gettimeofday (&now, NULL);
  1295. if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
  1296. sep->se_time = now;
  1297. sep->se_count = 1;
  1298. } else {
  1299. if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  1300. close (ctrl);
  1301. if (sep->se_family == AF_INET &&
  1302. ntohs (sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
  1303. /*
  1304. * Cannot close it -- there are
  1305. * thieves on the system.
  1306. * Simply ignore the connection.
  1307. */
  1308. --sep->se_count;
  1309. continue;
  1310. }
  1311. syslog (LOG_ERR,
  1312. "%s/%s server failing (looping), service terminated",
  1313. sep->se_service, sep->se_proto);
  1314. if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  1315. close (ctrl);
  1316. FD_CLR (sep->se_fd, &allsock);
  1317. (void) close (sep->se_fd);
  1318. sep->se_fd = -1;
  1319. sep->se_count = 0;
  1320. nsock--;
  1321. sigprocmask(SIG_UNBLOCK, &omask, NULL);
  1322. if (!timingout) {
  1323. timingout = 1;
  1324. alarm (RETRYTIME);
  1325. }
  1326. continue;
  1327. }
  1328. }
  1329. pid = fork ();
  1330. }
  1331. if (pid < 0) {
  1332. syslog (LOG_ERR, "fork: %m");
  1333. if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  1334. close (ctrl);
  1335. sigprocmask(SIG_UNBLOCK, &omask, NULL);
  1336. sleep (1);
  1337. continue;
  1338. }
  1339. if (pid && sep->se_wait) {
  1340. sep->se_wait = pid;
  1341. FD_CLR (sep->se_fd, &allsock);
  1342. nsock--;
  1343. }
  1344. sigprocmask(SIG_UNBLOCK, &omask, NULL);
  1345. if (pid == 0) {
  1346. #ifdef INETD_FEATURE_ENABLED
  1347. if (sep->se_bi) {
  1348. (*sep->se_bi->bi_fn) (ctrl, sep);
  1349. } else
  1350. #endif
  1351. {
  1352. if ((pwd = getpwnam (sep->se_user)) == NULL) {
  1353. syslog (LOG_ERR, "getpwnam: %s: No such user", sep->se_user);
  1354. if (sep->se_socktype != SOCK_STREAM)
  1355. recv (0, buf, sizeof (buf), 0);
  1356. _exit (1);
  1357. }
  1358. if (setsid () < 0)
  1359. syslog (LOG_ERR, "%s: setsid: %m", sep->se_service);
  1360. if (sep->se_group && (grp = getgrnam (sep->se_group)) == NULL) {
  1361. syslog (LOG_ERR, "getgrnam: %s: No such group", sep->se_group);
  1362. if (sep->se_socktype != SOCK_STREAM)
  1363. recv (0, buf, sizeof (buf), 0);
  1364. _exit (1);
  1365. }
  1366. if (uid != 0) {
  1367. /* a user running private inetd */
  1368. if (uid != pwd->pw_uid)
  1369. _exit (1);
  1370. } else if (pwd->pw_uid) {
  1371. if (sep->se_group) {
  1372. pwd->pw_gid = grp->gr_gid;
  1373. }
  1374. setgid ((gid_t) pwd->pw_gid);
  1375. initgroups (pwd->pw_name, pwd->pw_gid);
  1376. setuid ((uid_t) pwd->pw_uid);
  1377. } else if (sep->se_group) {
  1378. setgid (grp->gr_gid);
  1379. setgroups (1, &grp->gr_gid);
  1380. }
  1381. dup2 (ctrl, 0);
  1382. close (ctrl);
  1383. dup2 (0, 1);
  1384. dup2 (0, 2);
  1385. if (rlim_ofile.rlim_cur != rlim_ofile_cur)
  1386. if (setrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0)
  1387. syslog (LOG_ERR, "setrlimit: %m");
  1388. closelog ();
  1389. for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
  1390. (void) close (tmpint);
  1391. sigaction (SIGPIPE, &sapipe, NULL);
  1392. execv (sep->se_server, sep->se_argv);
  1393. if (sep->se_socktype != SOCK_STREAM)
  1394. recv (0, buf, sizeof (buf), 0);
  1395. syslog (LOG_ERR, "execv %s: %m", sep->se_server);
  1396. _exit (1);
  1397. }
  1398. }
  1399. if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  1400. close (ctrl);
  1401. }
  1402. }
  1403. }
  1404. /*
  1405. * Internet services provided internally by inetd:
  1406. */
  1407. #define BUFSIZE 4096
  1408. #if defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO) || \
  1409. defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN) || \
  1410. defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME)
  1411. static int dg_badinput (struct sockaddr_in *dg_sin)
  1412. {
  1413. if (ntohs (dg_sin->sin_port) < IPPORT_RESERVED)
  1414. return (1);
  1415. if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST))
  1416. return (1);
  1417. /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
  1418. return (0);
  1419. }
  1420. #endif
  1421. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
  1422. /* Echo service -- echo data back */
  1423. /* ARGSUSED */
  1424. static void
  1425. echo_stream (int s, servtab_t *sep)
  1426. {
  1427. char buffer[BUFSIZE];
  1428. int i;
  1429. inetd_setproctitle (sep->se_service, s);
  1430. while ((i = read (s, buffer, sizeof (buffer))) > 0 &&
  1431. write (s, buffer, i) > 0);
  1432. exit (0);
  1433. }
  1434. /* Echo service -- echo data back */
  1435. /* ARGSUSED */
  1436. static void
  1437. echo_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
  1438. {
  1439. char buffer[BUFSIZE];
  1440. int i;
  1441. socklen_t size;
  1442. /* struct sockaddr_storage ss; */
  1443. struct sockaddr sa;
  1444. size = sizeof (sa);
  1445. if ((i = recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size)) < 0)
  1446. return;
  1447. if (dg_badinput ((struct sockaddr_in *) &sa))
  1448. return;
  1449. (void) sendto (s, buffer, i, 0, &sa, sizeof (sa));
  1450. }
  1451. #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO */
  1452. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
  1453. /* Discard service -- ignore data */
  1454. /* ARGSUSED */
  1455. static void
  1456. discard_stream (int s, servtab_t *sep)
  1457. {
  1458. char buffer[BUFSIZE];
  1459. inetd_setproctitle (sep->se_service, s);
  1460. while ((errno = 0, read (s, buffer, sizeof (buffer)) > 0) ||
  1461. errno == EINTR);
  1462. exit (0);
  1463. }
  1464. /* Discard service -- ignore data */
  1465. /* ARGSUSED */
  1466. static void
  1467. discard_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
  1468. {
  1469. char buffer[BUFSIZE];
  1470. (void) read (s, buffer, sizeof (buffer));
  1471. }
  1472. #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD */
  1473. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
  1474. #define LINESIZ 72
  1475. static char ring[128];
  1476. static char *endring;
  1477. static void
  1478. initring (void)
  1479. {
  1480. int i;
  1481. endring = ring;
  1482. for (i = 0; i <= 128; ++i)
  1483. if (isprint (i))
  1484. *endring++ = i;
  1485. }
  1486. /* Character generator */
  1487. /* ARGSUSED */
  1488. static void
  1489. chargen_stream (int s, servtab_t *sep)
  1490. {
  1491. char *rs;
  1492. int len;
  1493. char text[LINESIZ + 2];
  1494. inetd_setproctitle (sep->se_service, s);
  1495. if (!endring) {
  1496. initring ();
  1497. rs = ring;
  1498. }
  1499. text[LINESIZ] = '\r';
  1500. text[LINESIZ + 1] = '\n';
  1501. for (rs = ring;;) {
  1502. if ((len = endring - rs) >= LINESIZ)
  1503. memmove (text, rs, LINESIZ);
  1504. else {
  1505. memmove (text, rs, len);
  1506. memmove (text + len, ring, LINESIZ - len);
  1507. }
  1508. if (++rs == endring)
  1509. rs = ring;
  1510. if (write (s, text, sizeof (text)) != sizeof (text))
  1511. break;
  1512. }
  1513. exit (0);
  1514. }
  1515. /* Character generator */
  1516. /* ARGSUSED */
  1517. static void
  1518. chargen_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
  1519. {
  1520. /* struct sockaddr_storage ss; */
  1521. struct sockaddr sa;
  1522. static char *rs;
  1523. int len;
  1524. char text[LINESIZ + 2];
  1525. socklen_t size;
  1526. if (endring == 0) {
  1527. initring ();
  1528. rs = ring;
  1529. }
  1530. size = sizeof (sa);
  1531. if (recvfrom (s, text, sizeof (text), 0, &sa, &size) < 0)
  1532. return;
  1533. if (dg_badinput ((struct sockaddr_in *) &sa))
  1534. return;
  1535. if ((len = endring - rs) >= LINESIZ)
  1536. memmove (text, rs, LINESIZ);
  1537. else {
  1538. memmove (text, rs, len);
  1539. memmove (text + len, ring, LINESIZ - len);
  1540. }
  1541. if (++rs == endring)
  1542. rs = ring;
  1543. text[LINESIZ] = '\r';
  1544. text[LINESIZ + 1] = '\n';
  1545. (void) sendto (s, text, sizeof (text), 0, &sa, sizeof (sa));
  1546. }
  1547. #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN */
  1548. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
  1549. /*
  1550. * Return a machine readable date and time, in the form of the
  1551. * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
  1552. * returns the number of seconds since midnight, Jan 1, 1970,
  1553. * we must add 2208988800 seconds to this figure to make up for
  1554. * some seventy years Bell Labs was asleep.
  1555. */
  1556. static u_int machtime (void)
  1557. {
  1558. struct timeval tv;
  1559. if (gettimeofday (&tv, NULL) < 0) {
  1560. fprintf (stderr, "Unable to get time of day\n");
  1561. return (0L);
  1562. }
  1563. return (htonl ((u_int) tv.tv_sec + 2208988800UL));
  1564. }
  1565. /* ARGSUSED */
  1566. static void
  1567. machtime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
  1568. {
  1569. u_int result;
  1570. result = machtime ();
  1571. (void) write (s, (char *) &result, sizeof (result));
  1572. }
  1573. /* ARGSUSED */
  1574. static void
  1575. machtime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
  1576. {
  1577. u_int result;
  1578. /* struct sockaddr_storage ss; */
  1579. struct sockaddr sa;
  1580. struct sockaddr_in *dg_sin;
  1581. socklen_t size;
  1582. size = sizeof (sa);
  1583. if (recvfrom (s, (char *) &result, sizeof (result), 0, &sa, &size) < 0)
  1584. return;
  1585. /* if (dg_badinput((struct sockaddr *)&ss)) */
  1586. dg_sin = (struct sockaddr_in *) &sa;
  1587. if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST) ||
  1588. ntohs (dg_sin->sin_port) < IPPORT_RESERVED / 2)
  1589. return;
  1590. result = machtime ();
  1591. (void) sendto (s, (char *) &result, sizeof (result), 0, &sa, sizeof (sa));
  1592. }
  1593. #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME */
  1594. #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
  1595. /* Return human-readable time of day */
  1596. /* ARGSUSED */
  1597. static void daytime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
  1598. {
  1599. char buffer[256];
  1600. time_t t;
  1601. t = time (NULL);
  1602. (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
  1603. (void) write (s, buffer, strlen (buffer));
  1604. }
  1605. /* Return human-readable time of day */
  1606. /* ARGSUSED */
  1607. void
  1608. daytime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
  1609. {
  1610. char buffer[256];
  1611. time_t t;
  1612. /* struct sockaddr_storage ss; */
  1613. struct sockaddr sa;
  1614. socklen_t size;
  1615. t = time ((time_t *) 0);
  1616. size = sizeof (sa);
  1617. if (recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size) < 0)
  1618. return;
  1619. if (dg_badinput ((struct sockaddr_in *) &sa))
  1620. return;
  1621. (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
  1622. (void) sendto (s, buffer, strlen (buffer), 0, &sa, sizeof (sa));
  1623. }
  1624. #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME */