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