identd.c revision 1.10 1 1.10 jwise /* $NetBSD: identd.c,v 1.10 1999/05/18 04:49:41 jwise Exp $ */
2 1.8 mrg
3 1.1 cgd /*
4 1.1 cgd ** identd.c A TCP/IP link identification protocol server
5 1.1 cgd **
6 1.1 cgd ** This program is in the public domain and may be used freely by anyone
7 1.1 cgd ** who wants to.
8 1.1 cgd **
9 1.9 msaitoh ** Last update: 7 Oct 1993
10 1.1 cgd **
11 1.1 cgd ** Please send bug fixes/bug reports to: Peter Eriksson <pen (at) lysator.liu.se>
12 1.1 cgd */
13 1.1 cgd
14 1.9 msaitoh #if !defined(__STDC__) && !defined(_AIX)
15 1.9 msaitoh #define void int
16 1.9 msaitoh #endif
17 1.9 msaitoh
18 1.9 msaitoh #if defined(IRIX) || defined(SVR4) || defined(NeXT) || (defined(sco) && sco >= 42) || defined(_AIX4) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(ultrix)
19 1.1 cgd # define SIGRETURN_TYPE void
20 1.1 cgd # define SIGRETURN_TYPE_IS_VOID
21 1.1 cgd #else
22 1.1 cgd # define SIGRETURN_TYPE int
23 1.1 cgd #endif
24 1.1 cgd
25 1.1 cgd #ifdef SVR4
26 1.1 cgd # define STRNET
27 1.1 cgd #endif
28 1.1 cgd
29 1.9 msaitoh #ifdef NeXT31
30 1.9 msaitoh # include <libc.h>
31 1.9 msaitoh #endif
32 1.9 msaitoh
33 1.9 msaitoh #ifdef sco
34 1.9 msaitoh # define USE_SIGALARM
35 1.9 msaitoh #endif
36 1.9 msaitoh
37 1.9 msaitoh #include <stdio.h>
38 1.9 msaitoh #include <ctype.h>
39 1.9 msaitoh #include <errno.h>
40 1.9 msaitoh #include <netdb.h>
41 1.9 msaitoh #include <signal.h>
42 1.9 msaitoh #include <fcntl.h>
43 1.9 msaitoh
44 1.1 cgd #include <sys/types.h>
45 1.1 cgd #include <sys/param.h>
46 1.1 cgd #include <sys/ioctl.h>
47 1.1 cgd #include <sys/socket.h>
48 1.1 cgd #ifndef _AUX_SOURCE
49 1.1 cgd # include <sys/file.h>
50 1.1 cgd #endif
51 1.1 cgd #include <sys/time.h>
52 1.1 cgd #include <sys/wait.h>
53 1.1 cgd
54 1.1 cgd #include <pwd.h>
55 1.1 cgd #include <grp.h>
56 1.1 cgd
57 1.1 cgd #include <netinet/in.h>
58 1.1 cgd
59 1.1 cgd #ifndef HPUX7
60 1.1 cgd # include <arpa/inet.h>
61 1.1 cgd #endif
62 1.1 cgd
63 1.9 msaitoh #ifdef _AIX32
64 1.9 msaitoh # include <sys/select.h>
65 1.9 msaitoh #endif
66 1.9 msaitoh
67 1.1 cgd #if defined(MIPS) || defined(BSD43)
68 1.1 cgd extern int errno;
69 1.1 cgd #endif
70 1.1 cgd
71 1.9 msaitoh #if defined(SOLARIS) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(_AIX)
72 1.9 msaitoh # include <unistd.h>
73 1.9 msaitoh # include <stdlib.h>
74 1.9 msaitoh # include <string.h>
75 1.9 msaitoh #endif
76 1.9 msaitoh
77 1.1 cgd #include "identd.h"
78 1.1 cgd #include "error.h"
79 1.9 msaitoh #include "paths.h"
80 1.9 msaitoh
81 1.1 cgd
82 1.1 cgd /* Antique unixes do not have these things defined... */
83 1.1 cgd #ifndef FD_SETSIZE
84 1.1 cgd # define FD_SETSIZE 256
85 1.1 cgd #endif
86 1.1 cgd
87 1.1 cgd #ifndef FD_SET
88 1.1 cgd # ifndef NFDBITS
89 1.1 cgd # define NFDBITS (sizeof(int) * NBBY) /* bits per mask */
90 1.1 cgd # endif
91 1.1 cgd # define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
92 1.1 cgd #endif
93 1.1 cgd
94 1.1 cgd #ifndef FD_ZERO
95 1.1 cgd # define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
96 1.1 cgd #endif
97 1.1 cgd
98 1.1 cgd
99 1.9 msaitoh char *path_unix = (char *) NULL;
100 1.9 msaitoh char *path_kmem = (char *) NULL;
101 1.1 cgd
102 1.1 cgd int verbose_flag = 0;
103 1.1 cgd int debug_flag = 0;
104 1.1 cgd int syslog_flag = 0;
105 1.1 cgd int multi_flag = 0;
106 1.1 cgd int other_flag = 0;
107 1.1 cgd int unknown_flag = 0;
108 1.1 cgd int noident_flag = 0;
109 1.9 msaitoh int crypto_flag = 0;
110 1.10 jwise int liar_flag = 0;
111 1.1 cgd
112 1.1 cgd int lport = 0;
113 1.1 cgd int fport = 0;
114 1.1 cgd
115 1.9 msaitoh char *charset_name = (char *) NULL;
116 1.9 msaitoh char *indirect_host = (char *) NULL;
117 1.9 msaitoh char *indirect_password = (char *) NULL;
118 1.10 jwise char *lie_string = (char *) NULL;
119 1.9 msaitoh
120 1.9 msaitoh #ifdef ALLOW_FORMAT
121 1.9 msaitoh int format_flag = 0;
122 1.9 msaitoh char *format = "%u";
123 1.9 msaitoh #endif
124 1.1 cgd
125 1.1 cgd static int child_pid;
126 1.1 cgd
127 1.1 cgd #ifdef LOG_DAEMON
128 1.1 cgd static int syslog_facility = LOG_DAEMON;
129 1.1 cgd #endif
130 1.1 cgd
131 1.9 msaitoh static int comparemem __P((void *, void *, int));
132 1.9 msaitoh char *clearmem __P((void *, int));
133 1.9 msaitoh static SIGRETURN_TYPE child_handler __P((int));
134 1.8 mrg int main __P((int, char *[]));
135 1.8 mrg
136 1.1 cgd /*
137 1.1 cgd ** The structure passing convention for GCC is incompatible with
138 1.1 cgd ** Suns own C compiler, so we define our own inet_ntoa() function.
139 1.1 cgd ** (This should only affect GCC version 1 I think, a well, this works
140 1.1 cgd ** for version 2 also so why bother.. :-)
141 1.1 cgd */
142 1.9 msaitoh #if defined(__GNUC__) && defined(__sparc__) && !defined(NeXT)
143 1.1 cgd
144 1.1 cgd #ifdef inet_ntoa
145 1.1 cgd #undef inet_ntoa
146 1.1 cgd #endif
147 1.1 cgd
148 1.1 cgd char *inet_ntoa(ad)
149 1.9 msaitoh struct in_addr ad;
150 1.1 cgd {
151 1.9 msaitoh unsigned long int s_ad;
152 1.9 msaitoh int a, b, c, d;
153 1.9 msaitoh static char addr[20];
154 1.9 msaitoh
155 1.9 msaitoh s_ad = ad.s_addr;
156 1.9 msaitoh d = s_ad % 256;
157 1.9 msaitoh s_ad /= 256;
158 1.9 msaitoh c = s_ad % 256;
159 1.9 msaitoh s_ad /= 256;
160 1.9 msaitoh b = s_ad % 256;
161 1.9 msaitoh a = s_ad / 256;
162 1.9 msaitoh sprintf(addr, "%d.%d.%d.%d", a, b, c, d);
163 1.9 msaitoh
164 1.9 msaitoh return addr;
165 1.1 cgd }
166 1.1 cgd #endif
167 1.1 cgd
168 1.9 msaitoh static int comparemem(vp1, vp2, len)
169 1.9 msaitoh void *vp1;
170 1.9 msaitoh void *vp2;
171 1.9 msaitoh int len;
172 1.9 msaitoh {
173 1.9 msaitoh unsigned char *p1 = (unsigned char *) vp1;
174 1.9 msaitoh unsigned char *p2 = (unsigned char *) vp2;
175 1.9 msaitoh int c;
176 1.9 msaitoh
177 1.9 msaitoh while (len-- > 0)
178 1.9 msaitoh if ((c = (int) *p1++ - (int) *p2++) != 0)
179 1.9 msaitoh return c;
180 1.9 msaitoh
181 1.9 msaitoh return 0;
182 1.9 msaitoh }
183 1.1 cgd
184 1.1 cgd /*
185 1.1 cgd ** Return the name of the connecting host, or the IP number as a string.
186 1.1 cgd */
187 1.1 cgd char *gethost(addr)
188 1.9 msaitoh struct in_addr *addr;
189 1.1 cgd {
190 1.9 msaitoh int i;
191 1.9 msaitoh struct hostent *hp;
192 1.1 cgd
193 1.1 cgd
194 1.9 msaitoh hp = gethostbyaddr((char *) addr, sizeof(struct in_addr), AF_INET);
195 1.9 msaitoh if (hp)
196 1.9 msaitoh {
197 1.9 msaitoh char *hname = strdup(hp->h_name);
198 1.9 msaitoh
199 1.9 msaitoh if (! hname) {
200 1.9 msaitoh syslog(LOG_ERR, "strdup(%s): %m", hp->h_name);
201 1.9 msaitoh exit(1);
202 1.9 msaitoh }
203 1.9 msaitoh /* Found a IP -> Name match, now try the reverse for security reasons */
204 1.9 msaitoh hp = gethostbyname(hname);
205 1.9 msaitoh (void) free(hname);
206 1.9 msaitoh if (hp)
207 1.9 msaitoh #ifdef h_addr
208 1.9 msaitoh for (i = 0; hp->h_addr_list[i]; i++)
209 1.9 msaitoh if (comparemem(hp->h_addr_list[i],
210 1.9 msaitoh (unsigned char *) addr,
211 1.9 msaitoh (int) sizeof(struct in_addr)) == 0)
212 1.9 msaitoh return (char *) hp->h_name;
213 1.9 msaitoh #else
214 1.9 msaitoh if (comparemem(hp->h_addr, addr, sizeof(struct in_addr)) == 0)
215 1.9 msaitoh return hp->h_name;
216 1.9 msaitoh #endif
217 1.9 msaitoh }
218 1.9 msaitoh
219 1.9 msaitoh return inet_ntoa(*addr);
220 1.1 cgd }
221 1.1 cgd
222 1.9 msaitoh #ifdef USE_SIGALARM
223 1.1 cgd /*
224 1.1 cgd ** Exit cleanly after our time's up.
225 1.1 cgd */
226 1.1 cgd static SIGRETURN_TYPE
227 1.9 msaitoh alarm_handler(int s)
228 1.1 cgd {
229 1.9 msaitoh if (syslog_flag)
230 1.9 msaitoh syslog(LOG_DEBUG, "SIGALRM triggered, exiting");
231 1.9 msaitoh
232 1.9 msaitoh exit(0);
233 1.1 cgd }
234 1.9 msaitoh #endif
235 1.9 msaitoh
236 1.1 cgd
237 1.9 msaitoh #if !defined(hpux) && !defined(__hpux) && !defined(SVR4) && \
238 1.9 msaitoh !defined(_CRAY) && !defined(sco) && !defined(LINUX)
239 1.1 cgd /*
240 1.1 cgd ** This is used to clean up zombie child processes
241 1.1 cgd ** if the -w or -b options are used.
242 1.1 cgd */
243 1.1 cgd static SIGRETURN_TYPE
244 1.9 msaitoh child_handler(dummy)
245 1.9 msaitoh int dummy;
246 1.1 cgd {
247 1.9 msaitoh #if defined(NeXT) || (defined(__sgi) && defined(__SVR3))
248 1.9 msaitoh union wait status;
249 1.1 cgd #else
250 1.9 msaitoh int status;
251 1.1 cgd #endif
252 1.9 msaitoh int saved_errno = errno;
253 1.9 msaitoh
254 1.9 msaitoh while (wait3(&status, WNOHANG, NULL) > 0)
255 1.9 msaitoh ;
256 1.1 cgd
257 1.9 msaitoh errno = saved_errno;
258 1.9 msaitoh
259 1.1 cgd #ifndef SIGRETURN_TYPE_IS_VOID
260 1.9 msaitoh return 0;
261 1.1 cgd #endif
262 1.1 cgd }
263 1.1 cgd #endif
264 1.1 cgd
265 1.9 msaitoh
266 1.9 msaitoh char *clearmem(vbp, len)
267 1.9 msaitoh void *vbp;
268 1.9 msaitoh int len;
269 1.1 cgd {
270 1.9 msaitoh char *bp = (char *) vbp;
271 1.9 msaitoh char *cp;
272 1.1 cgd
273 1.9 msaitoh cp = bp;
274 1.9 msaitoh while (len-- > 0)
275 1.9 msaitoh *cp++ = 0;
276 1.9 msaitoh
277 1.9 msaitoh return bp;
278 1.1 cgd }
279 1.1 cgd
280 1.1 cgd
281 1.1 cgd /*
282 1.1 cgd ** Main entry point into this daemon
283 1.1 cgd */
284 1.1 cgd int main(argc,argv)
285 1.9 msaitoh int argc;
286 1.9 msaitoh char *argv[];
287 1.1 cgd {
288 1.9 msaitoh int i, len;
289 1.9 msaitoh struct sockaddr_in sin;
290 1.9 msaitoh struct in_addr laddr, faddr;
291 1.9 msaitoh #ifndef USE_SIGALARM
292 1.9 msaitoh struct timeval tv;
293 1.9 msaitoh #endif
294 1.9 msaitoh int one = 1;
295 1.9 msaitoh
296 1.9 msaitoh int background_flag = 0;
297 1.9 msaitoh int timeout = 0;
298 1.9 msaitoh char *portno = "113";
299 1.9 msaitoh char *bind_address = (char *) NULL;
300 1.9 msaitoh int set_uid = 0;
301 1.9 msaitoh int set_gid = 0;
302 1.9 msaitoh int inhibit_default_config = 0;
303 1.9 msaitoh int opt_count = 0; /* Count of option flags */
304 1.1 cgd
305 1.1 cgd #ifdef __convex__
306 1.9 msaitoh argc--; /* get rid of extra argument passed by inetd */
307 1.1 cgd #endif
308 1.1 cgd
309 1.9 msaitoh
310 1.9 msaitoh if (isatty(0))
311 1.9 msaitoh background_flag = 1;
312 1.9 msaitoh
313 1.9 msaitoh /*
314 1.9 msaitoh ** Prescan the arguments for "-f<config-file>" switches
315 1.9 msaitoh */
316 1.9 msaitoh inhibit_default_config = 0;
317 1.9 msaitoh for (i = 1; i < argc && argv[i][0] == '-'; i++)
318 1.9 msaitoh if (argv[i][1] == 'f')
319 1.9 msaitoh inhibit_default_config = 1;
320 1.9 msaitoh
321 1.9 msaitoh /*
322 1.9 msaitoh ** Parse the default config file - if it exists
323 1.9 msaitoh */
324 1.9 msaitoh if (!inhibit_default_config)
325 1.9 msaitoh parse_config(NULL, 1);
326 1.1 cgd
327 1.9 msaitoh /*
328 1.9 msaitoh ** Parse the command line arguments
329 1.9 msaitoh */
330 1.9 msaitoh for (i = 1; i < argc && argv[i][0] == '-'; i++) {
331 1.9 msaitoh opt_count++;
332 1.9 msaitoh switch (argv[i][1])
333 1.9 msaitoh {
334 1.9 msaitoh case 'b': /* Start as standalone daemon */
335 1.9 msaitoh background_flag = 1;
336 1.9 msaitoh break;
337 1.9 msaitoh
338 1.9 msaitoh case 'w': /* Start from Inetd, wait mode */
339 1.9 msaitoh background_flag = 2;
340 1.9 msaitoh break;
341 1.9 msaitoh
342 1.9 msaitoh case 'i': /* Start from Inetd, nowait mode */
343 1.9 msaitoh background_flag = 0;
344 1.9 msaitoh break;
345 1.9 msaitoh
346 1.9 msaitoh case 't':
347 1.9 msaitoh timeout = atoi(argv[i]+2);
348 1.9 msaitoh break;
349 1.9 msaitoh
350 1.9 msaitoh case 'p':
351 1.9 msaitoh portno = argv[i]+2;
352 1.9 msaitoh break;
353 1.9 msaitoh
354 1.9 msaitoh case 'a':
355 1.9 msaitoh bind_address = argv[i]+2;
356 1.9 msaitoh break;
357 1.9 msaitoh
358 1.9 msaitoh case 'u':
359 1.9 msaitoh if (isdigit(argv[i][2]))
360 1.9 msaitoh set_uid = atoi(argv[i]+2);
361 1.9 msaitoh else
362 1.9 msaitoh {
363 1.9 msaitoh struct passwd *pwd;
364 1.9 msaitoh
365 1.9 msaitoh pwd = getpwnam(argv[i]+2);
366 1.9 msaitoh if (!pwd)
367 1.9 msaitoh ERROR1("no such user (%s) for -u option", argv[i]+2);
368 1.9 msaitoh else
369 1.9 msaitoh {
370 1.9 msaitoh set_uid = pwd->pw_uid;
371 1.9 msaitoh set_gid = pwd->pw_gid;
372 1.9 msaitoh }
373 1.9 msaitoh }
374 1.9 msaitoh break;
375 1.9 msaitoh
376 1.9 msaitoh case 'g':
377 1.9 msaitoh if (isdigit(argv[i][2]))
378 1.9 msaitoh set_gid = atoi(argv[i]+2);
379 1.9 msaitoh else
380 1.9 msaitoh {
381 1.9 msaitoh struct group *grp;
382 1.9 msaitoh
383 1.9 msaitoh grp = getgrnam(argv[i]+2);
384 1.9 msaitoh if (!grp)
385 1.9 msaitoh ERROR1("no such group (%s) for -g option", argv[i]+2);
386 1.9 msaitoh else
387 1.9 msaitoh set_gid = grp->gr_gid;
388 1.9 msaitoh }
389 1.9 msaitoh break;
390 1.9 msaitoh
391 1.9 msaitoh case 'c':
392 1.9 msaitoh charset_name = argv[i]+2;
393 1.9 msaitoh break;
394 1.9 msaitoh
395 1.9 msaitoh case 'r':
396 1.9 msaitoh indirect_host = argv[i]+2;
397 1.9 msaitoh break;
398 1.9 msaitoh
399 1.9 msaitoh case 'l': /* Use the Syslog daemon for logging */
400 1.9 msaitoh syslog_flag++;
401 1.9 msaitoh #ifdef LOG_DAEMON
402 1.9 msaitoh openlog("identd", LOG_PID, syslog_facility);
403 1.9 msaitoh #else
404 1.9 msaitoh openlog("identd", LOG_PID);
405 1.9 msaitoh #endif
406 1.9 msaitoh break;
407 1.9 msaitoh
408 1.9 msaitoh case 'o':
409 1.9 msaitoh other_flag = 1;
410 1.9 msaitoh break;
411 1.9 msaitoh
412 1.9 msaitoh case 'e':
413 1.9 msaitoh unknown_flag = 1;
414 1.9 msaitoh break;
415 1.9 msaitoh
416 1.9 msaitoh case 'V': /* Give version of this daemon */
417 1.9 msaitoh printf("[in.identd, version %s]\r\n", version);
418 1.9 msaitoh exit(0);
419 1.9 msaitoh break;
420 1.9 msaitoh
421 1.9 msaitoh case 'v': /* Be verbose */
422 1.9 msaitoh verbose_flag++;
423 1.9 msaitoh break;
424 1.9 msaitoh
425 1.9 msaitoh case 'd': /* Enable debugging */
426 1.9 msaitoh debug_flag++;
427 1.9 msaitoh break;
428 1.9 msaitoh
429 1.9 msaitoh case 'm': /* Enable multiline queries */
430 1.9 msaitoh multi_flag++;
431 1.9 msaitoh break;
432 1.9 msaitoh
433 1.9 msaitoh case 'N': /* Enable users ".noident" files */
434 1.9 msaitoh noident_flag++;
435 1.9 msaitoh break;
436 1.9 msaitoh
437 1.9 msaitoh #ifdef INCLUDE_CRYPT
438 1.9 msaitoh case 'C': /* Enable encryption. */
439 1.9 msaitoh {
440 1.9 msaitoh FILE *keyfile;
441 1.9 msaitoh
442 1.9 msaitoh if (argv[i][2])
443 1.9 msaitoh keyfile = fopen(argv[i]+2, "r");
444 1.9 msaitoh else
445 1.9 msaitoh keyfile = fopen(PATH_DESKEY, "r");
446 1.9 msaitoh
447 1.9 msaitoh if (keyfile == NULL)
448 1.9 msaitoh {
449 1.9 msaitoh ERROR("cannot open key file for option -C");
450 1.9 msaitoh }
451 1.9 msaitoh else
452 1.9 msaitoh {
453 1.9 msaitoh char buf[1024];
454 1.9 msaitoh
455 1.9 msaitoh if (fgets(buf, 1024, keyfile) == NULL)
456 1.9 msaitoh {
457 1.9 msaitoh ERROR("cannot read key file for option -C");
458 1.9 msaitoh }
459 1.9 msaitoh else
460 1.9 msaitoh {
461 1.9 msaitoh init_encryption(buf);
462 1.9 msaitoh crypto_flag++;
463 1.9 msaitoh }
464 1.9 msaitoh fclose(keyfile);
465 1.9 msaitoh }
466 1.9 msaitoh }
467 1.9 msaitoh break;
468 1.9 msaitoh #endif
469 1.9 msaitoh
470 1.9 msaitoh #ifdef ALLOW_FORMAT
471 1.9 msaitoh case 'n': /* Compatibility flag - just send the user number */
472 1.9 msaitoh format_flag = 1;
473 1.9 msaitoh format = "%U";
474 1.9 msaitoh break;
475 1.9 msaitoh
476 1.9 msaitoh case 'F': /* Output format */
477 1.9 msaitoh format_flag = 1;
478 1.9 msaitoh format = argv[i]+2;
479 1.9 msaitoh break;
480 1.9 msaitoh #endif
481 1.10 jwise
482 1.10 jwise case 'L': /* lie brazenly */
483 1.10 jwise liar_flag = 1;
484 1.10 jwise if (*(argv[i]+2) != '\0')
485 1.10 jwise lie_string = argv[i]+2;
486 1.10 jwise else
487 1.10 jwise #ifdef DEFAULT_LIE_USER
488 1.10 jwise lie_string = DEFAULT_LIE_USER;
489 1.10 jwise #else
490 1.10 jwise ERROR("-L specified with no user name");
491 1.10 jwise #endif
492 1.10 jwise break;
493 1.9 msaitoh
494 1.9 msaitoh default:
495 1.9 msaitoh ERROR1("Bad option %s", argv[i]);
496 1.9 msaitoh break;
497 1.9 msaitoh }
498 1.9 msaitoh }
499 1.9 msaitoh
500 1.9 msaitoh #if defined(_AUX_SOURCE) || defined (SUNOS35)
501 1.9 msaitoh /* A/UX 2.0* & SunOS 3.5 calls us with an argument XXXXXXXX.YYYY
502 1.9 msaitoh ** where XXXXXXXXX is the hexadecimal version of the callers
503 1.9 msaitoh ** IP number, and YYYY is the port/socket or something.
504 1.9 msaitoh ** It seems to be impossible to pass arguments to a daemon started
505 1.9 msaitoh ** by inetd.
506 1.9 msaitoh **
507 1.9 msaitoh ** Just in case it is started from something else, then we only
508 1.9 msaitoh ** skip the argument if no option flags have been seen.
509 1.9 msaitoh */
510 1.9 msaitoh if (opt_count == 0)
511 1.9 msaitoh argc--;
512 1.9 msaitoh #endif
513 1.9 msaitoh
514 1.9 msaitoh /*
515 1.9 msaitoh ** Path to kernel namelist file specified on command line
516 1.9 msaitoh */
517 1.9 msaitoh if (i < argc)
518 1.9 msaitoh path_unix = argv[i++];
519 1.9 msaitoh
520 1.9 msaitoh /*
521 1.9 msaitoh ** Path to kernel memory device specified on command line
522 1.9 msaitoh */
523 1.9 msaitoh if (i < argc)
524 1.9 msaitoh path_kmem = argv[i++];
525 1.9 msaitoh
526 1.9 msaitoh
527 1.9 msaitoh if (i < argc)
528 1.9 msaitoh ERROR1("Too many arguments: ignored from %s", argv[i]);
529 1.9 msaitoh
530 1.9 msaitoh
531 1.9 msaitoh /*
532 1.9 msaitoh ** We used to call k_open here. But then the file descriptor
533 1.9 msaitoh ** kd->fd open on /dev/kmem is shared by all child processes.
534 1.9 msaitoh ** From the fork(2) man page:
535 1.9 msaitoh ** o The child process has its own copy of the parent's descriptors. These
536 1.9 msaitoh ** descriptors reference the same underlying objects. For instance, file
537 1.9 msaitoh ** pointers in file objects are shared between the child and the parent
538 1.9 msaitoh ** so that an lseek(2) on a descriptor in the child process can affect a
539 1.9 msaitoh ** subsequent read(2) or write(2) by the parent.
540 1.9 msaitoh ** Thus with concurrent (simultaneous) identd client processes,
541 1.9 msaitoh ** they step on each other's toes when they use kvm_read.
542 1.9 msaitoh **
543 1.9 msaitoh ** Calling k_open here was a mistake for another reason too: we
544 1.9 msaitoh ** did not yet honor -u and -g options. Presumably we are
545 1.9 msaitoh ** running as root (unless the in.identd file is setuid), and
546 1.9 msaitoh ** then we can open kmem regardless of -u and -g values.
547 1.9 msaitoh **
548 1.9 msaitoh **
549 1.9 msaitoh ** Open the kernel memory device and read the nlist table
550 1.9 msaitoh **
551 1.9 msaitoh ** if (k_open() < 0)
552 1.9 msaitoh ** ERROR("main: k_open");
553 1.9 msaitoh */
554 1.9 msaitoh
555 1.9 msaitoh /*
556 1.9 msaitoh ** Do the special handling needed for the "-b" flag
557 1.9 msaitoh */
558 1.9 msaitoh if (background_flag == 1)
559 1.1 cgd {
560 1.9 msaitoh struct sockaddr_in addr;
561 1.9 msaitoh struct servent *sp;
562 1.9 msaitoh int fd;
563 1.9 msaitoh
564 1.9 msaitoh
565 1.9 msaitoh if (!debug_flag)
566 1.9 msaitoh {
567 1.9 msaitoh if (fork())
568 1.9 msaitoh exit(0);
569 1.9 msaitoh
570 1.9 msaitoh close(0);
571 1.9 msaitoh close(1);
572 1.9 msaitoh close(2);
573 1.9 msaitoh
574 1.9 msaitoh if (fork())
575 1.9 msaitoh exit(0);
576 1.9 msaitoh }
577 1.9 msaitoh
578 1.9 msaitoh fd = socket(AF_INET, SOCK_STREAM, 0);
579 1.9 msaitoh if (fd == -1)
580 1.9 msaitoh ERROR("main: socket");
581 1.9 msaitoh
582 1.9 msaitoh if (fd != 0)
583 1.9 msaitoh dup2(fd, 0);
584 1.9 msaitoh
585 1.9 msaitoh clearmem((void *) &addr, (int) sizeof(addr));
586 1.9 msaitoh
587 1.9 msaitoh addr.sin_family = AF_INET;
588 1.9 msaitoh if (bind_address == (char *) NULL)
589 1.9 msaitoh addr.sin_addr.s_addr = htonl(INADDR_ANY);
590 1.1 cgd else
591 1.9 msaitoh {
592 1.9 msaitoh if (isdigit(bind_address[0]))
593 1.9 msaitoh addr.sin_addr.s_addr = inet_addr(bind_address);
594 1.9 msaitoh else
595 1.9 msaitoh {
596 1.9 msaitoh struct hostent *hp;
597 1.9 msaitoh
598 1.9 msaitoh hp = gethostbyname(bind_address);
599 1.9 msaitoh if (!hp)
600 1.9 msaitoh ERROR1("no such address (%s) for -a switch", bind_address);
601 1.9 msaitoh
602 1.9 msaitoh /* This is ugly, should use memcpy() or bcopy() but... */
603 1.9 msaitoh addr.sin_addr.s_addr = * (unsigned long *) (hp->h_addr);
604 1.9 msaitoh }
605 1.1 cgd }
606 1.1 cgd
607 1.9 msaitoh if (isdigit(portno[0]))
608 1.9 msaitoh addr.sin_port = htons(atoi(portno));
609 1.1 cgd else
610 1.9 msaitoh {
611 1.9 msaitoh sp = getservbyname(portno, "tcp");
612 1.9 msaitoh if (sp == (struct servent *) NULL)
613 1.9 msaitoh ERROR1("main: getservbyname: %s", portno);
614 1.9 msaitoh addr.sin_port = sp->s_port;
615 1.9 msaitoh }
616 1.1 cgd
617 1.9 msaitoh #ifdef SO_REUSEADDR
618 1.9 msaitoh setsockopt(0, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one));
619 1.9 msaitoh #endif
620 1.1 cgd
621 1.9 msaitoh if (bind(0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
622 1.9 msaitoh ERROR("main: bind");
623 1.1 cgd }
624 1.9 msaitoh
625 1.9 msaitoh if (background_flag)
626 1.9 msaitoh {
627 1.9 msaitoh if (listen(0, 3) < 0)
628 1.9 msaitoh ERROR("main: listen");
629 1.9 msaitoh }
630 1.9 msaitoh
631 1.9 msaitoh if (set_gid)
632 1.1 cgd {
633 1.9 msaitoh if (setgid(set_gid) == -1)
634 1.9 msaitoh ERROR("main: setgid");
635 1.9 msaitoh /* Call me paranoid... PSz */
636 1.9 msaitoh if (getgid() != set_gid)
637 1.9 msaitoh ERROR2("main: setgid failed: wanted %d, got GID %d", set_gid, getgid());
638 1.9 msaitoh if (getegid() != set_gid)
639 1.9 msaitoh ERROR2("main: setgid failed: wanted %d, got EGID %d", set_gid, getegid());
640 1.1 cgd }
641 1.9 msaitoh
642 1.9 msaitoh if (set_uid)
643 1.1 cgd {
644 1.9 msaitoh if (setuid(set_uid) == -1)
645 1.9 msaitoh ERROR("main: setuid");
646 1.9 msaitoh /* Call me paranoid... PSz */
647 1.9 msaitoh if (getuid() != set_uid)
648 1.9 msaitoh ERROR2("main: setuid failed: wanted %d, got UID %d", set_uid, getuid());
649 1.9 msaitoh if (geteuid() != set_uid)
650 1.9 msaitoh ERROR2("main: setuid failed: wanted %d, got EUID %d", set_uid, geteuid());
651 1.1 cgd }
652 1.1 cgd
653 1.1 cgd /*
654 1.9 msaitoh ** Do some special handling if the "-b" or "-w" flags are used
655 1.9 msaitoh */
656 1.9 msaitoh if (background_flag)
657 1.9 msaitoh {
658 1.9 msaitoh int nfds, fd;
659 1.9 msaitoh fd_set read_set;
660 1.9 msaitoh struct sockaddr sad;
661 1.9 msaitoh int sadlen;
662 1.9 msaitoh
663 1.9 msaitoh
664 1.9 msaitoh /*
665 1.9 msaitoh ** Set up the SIGCHLD signal child termination handler so
666 1.9 msaitoh ** that we can avoid zombie processes hanging around and
667 1.9 msaitoh ** handle childs terminating before being able to complete the
668 1.9 msaitoh ** handshake.
669 1.9 msaitoh */
670 1.9 msaitoh #if (defined(SVR4) || defined(hpux) || defined(__hpux) || defined(IRIX) || \
671 1.9 msaitoh defined(_CRAY) || defined(_AUX_SOURCE) || defined(sco) || \
672 1.9 msaitoh defined(LINUX))
673 1.9 msaitoh signal(SIGCHLD, SIG_IGN);
674 1.1 cgd #else
675 1.9 msaitoh signal(SIGCHLD, child_handler);
676 1.1 cgd #endif
677 1.1 cgd
678 1.9 msaitoh /*
679 1.9 msaitoh ** Loop and dispatch client handling processes
680 1.9 msaitoh */
681 1.9 msaitoh do
682 1.9 msaitoh {
683 1.9 msaitoh #ifdef USE_SIGALARM
684 1.9 msaitoh /*
685 1.9 msaitoh ** Terminate if we've been idle for 'timeout' seconds
686 1.9 msaitoh */
687 1.9 msaitoh if (background_flag == 2 && timeout)
688 1.9 msaitoh {
689 1.9 msaitoh signal(SIGALRM, alarm_handler);
690 1.9 msaitoh alarm(timeout);
691 1.9 msaitoh }
692 1.9 msaitoh #endif
693 1.1 cgd
694 1.9 msaitoh /*
695 1.9 msaitoh ** Wait for a connection request to occur.
696 1.9 msaitoh ** Ignore EINTR (Interrupted System Call).
697 1.9 msaitoh */
698 1.9 msaitoh do
699 1.9 msaitoh {
700 1.9 msaitoh FD_ZERO(&read_set);
701 1.9 msaitoh FD_SET(0, &read_set);
702 1.9 msaitoh
703 1.9 msaitoh #ifndef USE_SIGALARM
704 1.9 msaitoh if (timeout)
705 1.9 msaitoh {
706 1.9 msaitoh tv.tv_sec = timeout;
707 1.9 msaitoh tv.tv_usec = 0;
708 1.9 msaitoh #ifdef __hpux
709 1.9 msaitoh nfds = select(FD_SETSIZE,
710 1.9 msaitoh (int *) &read_set, NULL, NULL, &tv);
711 1.9 msaitoh #else
712 1.9 msaitoh nfds = select(FD_SETSIZE, &read_set, NULL, NULL, &tv);
713 1.9 msaitoh #endif
714 1.9 msaitoh }
715 1.9 msaitoh else
716 1.9 msaitoh #endif
717 1.1 cgd
718 1.9 msaitoh #ifdef __hpux
719 1.9 msaitoh nfds = select(FD_SETSIZE, (int *) &read_set, NULL, NULL, NULL);
720 1.9 msaitoh #else
721 1.9 msaitoh nfds = select(FD_SETSIZE, &read_set, NULL, NULL, NULL);
722 1.9 msaitoh #endif
723 1.9 msaitoh } while (nfds < 0 && errno == EINTR);
724 1.9 msaitoh
725 1.9 msaitoh /*
726 1.9 msaitoh ** An error occured in select? Just die
727 1.9 msaitoh */
728 1.9 msaitoh if (nfds < 0)
729 1.9 msaitoh ERROR("main: select");
730 1.9 msaitoh
731 1.9 msaitoh /*
732 1.9 msaitoh ** Timeout limit reached. Exit nicely
733 1.9 msaitoh */
734 1.9 msaitoh if (nfds == 0)
735 1.9 msaitoh exit(0);
736 1.1 cgd
737 1.9 msaitoh #ifdef USE_SIGALARM
738 1.9 msaitoh /*
739 1.9 msaitoh ** Disable the alarm timeout
740 1.9 msaitoh */
741 1.9 msaitoh alarm(0);
742 1.9 msaitoh #endif
743 1.1 cgd
744 1.9 msaitoh /*
745 1.9 msaitoh ** Accept the new client
746 1.9 msaitoh */
747 1.9 msaitoh sadlen = sizeof(sad);
748 1.9 msaitoh errno = 0;
749 1.9 msaitoh fd = accept(0, &sad, &sadlen);
750 1.9 msaitoh if (fd == -1)
751 1.9 msaitoh ERROR1("main: accept. errno = %d", errno);
752 1.1 cgd
753 1.9 msaitoh /*
754 1.9 msaitoh ** And fork, then close the fd if we are the parent.
755 1.9 msaitoh */
756 1.9 msaitoh child_pid = fork();
757 1.9 msaitoh } while (child_pid && (close(fd), 1));
758 1.9 msaitoh
759 1.9 msaitoh /*
760 1.9 msaitoh ** We are now in child, the parent has returned to "do" above.
761 1.9 msaitoh */
762 1.9 msaitoh if (dup2(fd, 0) == -1)
763 1.9 msaitoh ERROR("main: dup2: failed fd 0");
764 1.9 msaitoh
765 1.9 msaitoh if (dup2(fd, 1) == -1)
766 1.9 msaitoh ERROR("main: dup2: failed fd 1");
767 1.9 msaitoh
768 1.9 msaitoh if (dup2(fd, 2) == -1)
769 1.9 msaitoh ERROR("main: dup2: failed fd 2");
770 1.9 msaitoh }
771 1.9 msaitoh
772 1.1 cgd /*
773 1.9 msaitoh ** Get foreign internet address
774 1.1 cgd */
775 1.9 msaitoh len = sizeof(sin);
776 1.9 msaitoh if (getpeername(0, (struct sockaddr *) &sin, &len) == -1)
777 1.9 msaitoh {
778 1.9 msaitoh /*
779 1.9 msaitoh ** A user has tried to start us from the command line or
780 1.9 msaitoh ** the network link died, in which case this message won't
781 1.9 msaitoh ** reach to other end anyway, so lets give the poor user some
782 1.9 msaitoh ** errors.
783 1.9 msaitoh */
784 1.9 msaitoh perror("in.identd: getpeername()");
785 1.9 msaitoh exit(1);
786 1.9 msaitoh }
787 1.9 msaitoh
788 1.9 msaitoh faddr = sin.sin_addr;
789 1.1 cgd
790 1.1 cgd
791 1.9 msaitoh #ifdef STRONG_LOG
792 1.9 msaitoh if (syslog_flag)
793 1.9 msaitoh syslog(LOG_INFO, "Connection from %s", gethost(&faddr));
794 1.9 msaitoh #endif
795 1.1 cgd
796 1.9 msaitoh
797 1.9 msaitoh /*
798 1.9 msaitoh ** Get local internet address
799 1.1 cgd */
800 1.9 msaitoh len = sizeof(sin);
801 1.9 msaitoh #ifdef ATTSVR4
802 1.9 msaitoh if (t_getsockname(0, (struct sockaddr *) &sin, &len) == -1)
803 1.1 cgd #else
804 1.9 msaitoh if (getsockname(0, (struct sockaddr *) &sin, &len) == -1)
805 1.1 cgd #endif
806 1.9 msaitoh {
807 1.9 msaitoh /*
808 1.9 msaitoh ** We can just die here, because if this fails then the
809 1.9 msaitoh ** network has died and we haven't got anyone to return
810 1.9 msaitoh ** errors to.
811 1.9 msaitoh */
812 1.9 msaitoh exit(1);
813 1.9 msaitoh }
814 1.9 msaitoh laddr = sin.sin_addr;
815 1.1 cgd
816 1.1 cgd
817 1.1 cgd /*
818 1.9 msaitoh ** Get the local/foreign port pair from the luser
819 1.1 cgd */
820 1.9 msaitoh parse(stdin, &laddr, &faddr);
821 1.1 cgd
822 1.9 msaitoh exit(0);
823 1.1 cgd }
824