summaryrefslogtreecommitdiff
path: root/libexec/identd
diff options
context:
space:
mode:
authorchristos <christos@NetBSD.org>2004-01-31 21:47:17 +0000
committerchristos <christos@NetBSD.org>2004-01-31 21:47:17 +0000
commit6310d36554b6280128ae168b79b2d7afd80128cc (patch)
treeacc68fb5a840844089b09d222894c6f2dddefc1a /libexec/identd
parenta71e78c796edda21a044bcafb625c26f0e7efbd3 (diff)
new identd from Peter Postma.
Diffstat (limited to 'libexec/identd')
-rw-r--r--libexec/identd/Makefile12
-rw-r--r--libexec/identd/identd.8606
-rw-r--r--libexec/identd/identd.c1451
3 files changed, 881 insertions, 1188 deletions
diff --git a/libexec/identd/Makefile b/libexec/identd/Makefile
index f77725b74fb..2462ab6f6c8 100644
--- a/libexec/identd/Makefile
+++ b/libexec/identd/Makefile
@@ -1,13 +1,7 @@
-# $NetBSD: Makefile,v 1.9 2003/04/19 20:57:35 christos Exp $
+# $NetBSD: Makefile,v 1.10 2004/01/31 21:47:17 christos Exp $
+WARNS=3
PROG= identd
-MAN= identd.8
-
-CPPFLAGS+= -DINCLUDE_EXTENSIONS -DSTRONG_LOG -DALLOW_FORMAT
-.ifdef DEFAULT_LIE_USER
-CPPFLAGS+= -DDEFAULT_LIE_USER=\"${DEFAULT_LIE_USER}\"
-.endif
-
-SRCS= netbsd.c version.c proxy.c config.c parse.c identd.c
+MAN= identd.8
.include <bsd.prog.mk>
diff --git a/libexec/identd/identd.8 b/libexec/identd/identd.8
index 7a901698dcf..cbee33b01af 100644
--- a/libexec/identd/identd.8
+++ b/libexec/identd/identd.8
@@ -1,447 +1,185 @@
-.\" $NetBSD: identd.8,v 1.16 2003/03/15 23:48:30 wiz Exp $
+.\" $NetBSD: identd.8,v 1.17 2004/01/31 21:47:17 christos Exp $
.\"
-.\" @(#)identd.8 1.9 92/02/11 Lysator
-.\" Copyright (c) 1992 Peter Eriksson, Lysator, Linkoping University.
-.\" This software has been released into the public domain.
+.\" This software is in the public domain.
+.\" Written by Peter Postma <peter@pointless.nl>
.\"
-.TH IDENTD 8 "27 May 1992"
-.SH NAME
-identd \- TCP/IP IDENT protocol server
-.SH SYNOPSIS
-.B identd
-.RB [ \-i | \-w | \-b ]
-.RB [ \-t\*[Lt]seconds\*[Gt] ]
-.RB [ \-u\*[Lt]uid\*[Gt] ]
-.RB [ \-g\*[Lt]gid\*[Gt] ]
-.RB [ \-p\*[Lt]port\*[Gt] ]
-.RB [ \-a\*[Lt]address\*[Gt] ]
-.RB [ \-c\*[Lt]charset\*[Gt] ]
-.\".RB [ \-C [ \*[Lt]keyfile\*[Gt] ]]
-.RB [ \-o ]
-.RB [ \-e ]
-.RB [ \-l ]
-.RB [ \-V ]
-.RB [ \-m ]
-.RB [ \-N ]
-.RB [ \-d ]
-.RB [ \-F\*[Lt]format\*[Gt] ]
-.RB [ \-L\*[Lt]user name\*[Gt] ]
-.RB [ "kernelfile" [ "kmemfile" ] ]
-.SH DESCRIPTION
-.IX "identd daemon" "" \fLidentd\fP daemon"
-.B identd
-is a server which implements the ill-conceived
-.SM IDENT
-protocol specified in
-.SM RFC\s0 1413.
-.PP
-.B identd
-operates by looking up specific
-.SM TCP/IP
-connections and returning information which may or may not be
-associated with the process owning the connection.
-.PP
-The
-.B identd
-server provides little other than a false sense of security; however,
-some legacy services require their clients to run ident servers.
-.SH ARGUMENTS
-The highly-recommended
-.B \-L\*[Lt]user name\*[Gt]
-option instructs
-.B identd
-to always return a fixed user identity in response to all requests,
-resulting in both improved efficiency and increased user privacy (you didn't
-.I really
-intend to trust my assertion about who I was anyway, right?)
-.PP
-This flag provides a way for a site to support services requiring the ident
-protocol while providing a standard answer to all ident queries.
-All queries to identd will respond with a host type
-of `OTHER' and a username of
-.B \*[Lt]user name\*[Gt].
-.PP
-The
-.B \-i
-flag, enabled by default, should be used when starting the daemon from
-.B inetd
-with the "nowait" option in the
-.B /etc/inetd.conf
-file.
-Use of this mode will make
-.B inetd
-start one
-.B identd
-daemon for each connection request.
-.PP
-The
-.B \-w
-flag should be used when starting the daemon from
-.B inetd
-with the "wait" option in the
-.B /etc/inetd.conf
-file.
-This is the preferred mode of operation since that will start a copy of
-.B identd
-at the first connection request and then
-.B identd
-will handle subsequent requests without having to do the
-nlist lookup in the kernel file for every request as in the
-.B \-i
-mode above.
-The
-.B identd
-daemon will run either forever, until a bug
-makes it crash or a timeout, as specified by the
-.B \-t
-flag, occurs.
-.PP
-The
-.B \-b
-flag can be used to make the daemon run in standalone
-mode without the assistance from
-.BR inetd.
-This mode is the least preferred mode since
-a bug or any other fatal condition in the server will make it terminate
-and it will then have to be restarted manually.
-Other than that it has the same advantage as the
-.B \-w
-mode in that it parses the nlist only once.
-.PP
-The
-.B \-t\*[Lt]seconds\*[Gt]
-option is used to specify the timeout limit.
-This is the number of seconds a server started with the
-.B \-w
-flag will wait for new connections before terminating.
-The server is automatically restarted by
-.B inetd
-whenever a new connection is requested if it has terminated.
-A suitable value for this is 120 (2 minutes), if used.
-It defaults to no timeout (i.e. will wait forever, or until a
-fatal condition occurs in the server).
-.PP
-The
-.B \-u\*[Lt]uid\*[Gt]
-option is used to specify a user id number which the
-.BR ident
-server should switch to after binding itself to the
-.SM TCP/IP
-port if using the
-.B \-b
-mode of operation.
-.PP
-The
-.B \-g\*[Lt]gid\*[Gt]
-option is used to specify a group id number which the
-.BR ident
-server should switch to after binding itself to the
-.SM TCP/IP
-port if using the
-.B \-b
-mode of operation.
-.PP
-The
-.B \-p\*[Lt]port\*[Gt]
-option is used to specify an alternative port number
-to bind to if using the
-.B \-b
-mode of operation.
-It can be specified by name or by number.
-Defaults to the
-.SM IDENT
-port (113).
-.PP
-The
-.B \-a\*[Lt]address\*[Gt]
-option is used to specify the local address to bind
-the socket to if using the
-.B \-b
-mode of operation.
-Can only be specified by IP address and not by domain name.
-Defaults to the
-.SM INADDR_ANY
-address which normally means all local addresses.
-.PP
-The
-.B \-V
-flag makes
-.B identd
-display the version number and then exit.
-.PP
-The
-.B \-l
-flag tells
-.B identd
-to use the System logging daemon
-.B syslogd
-for logging purposes.
-.PP
-The
-.B \-o
-flag tells
-.B identd
-to not reveal the operating system type it is run on and to instead
-always return "OTHER".
-.PP
-The
-.B \-e
-flag tells
-.B identd
-to always return "UNKNOWN-ERROR" instead of the "NO-USER" or
-"INVALID-PORT" errors.
-.PP
-The
-.B \-c\*[Lt]charset\*[Gt]
-flags tells
-.B identd
-to add the optional (according to the IDENT protocol) character set
-designator to the reply generated.
-.I charset
-should be a valid character set as described in the MIME RFC in upper
-case characters.
-.\".PP
-.\"The
-.\".BR \-C [ \*[Lt]keyfile\*[Gt] ]
-.\"option tells
-.\".B identd
-.\"to return encrypted tokens instead of user names.
-.\"The local and remote IP
-.\"addresses and TCP port numbers, the local user's uid number, a timestamp,
-.\"a random number, and a checksum, are all encrypted using DES
-.\"with a secret key derived from the first line of the
-.\".I keyfile
-.\"(using
-.\".BR des_string_to_key (3)).
-.\"The encrypted binary information is then encoded in a base64 string
-.\"(32 characters in length) and enclosed in square brackets to produce
-.\"a token that is transmitted to the remote client.
-.\"The encrypted token can later be decrypted by
-.\".BR idecrypt (8).
-.\"There may not be a space between the
-.\".B \-C
-.\"and the name of the
-.\".IR keyfile .
-.\"If the
-.\".I keyfile
-.\"is not specified, it defaults to
-.\".BR /etc/identd.key .
-.PP
-The
-.B \-n
-flag tells
-.B identd
-to always return user numbers instead of user names if you wish to
-keep the user names a secret.
-The
-.B \-N
-flag makes
-.B identd
-check for a file ".noident" in each home directory for a user which the
-daemon is about to return the user name for.
-It that file exists then the daemon will give the error
-.B HIDDEN-USER
-instead of the normal USERID response.
-.PP
-.B \-m
-flag makes
-.B identd
-use a mode of operation that will allow multiple requests to be
-processed per session.
-Each request is specified one per line and
-the responses will be returned one per line.
-The connection will not be closed until the connecting
-part closes its end of the line.
-PLEASE NOTE THAT THIS MODE VIOLATES THE PROTOCOL SPECIFICATION AS
-IT CURRENTLY STANDS.
-.PP
-The
-.B \-d
-flag enables some debugging code that normally should NOT
-be enabled since that breaks the protocol and may reveal information
-that should not be available to outsiders.
-.PP
-The
-.B \-F\*[Lt]format\*[Gt]
-option makes
-.B identd
-use the specified format to display info.
+.Dd January 31, 2004
+.Dt IDENTD 8
+.Os
+.Sh NAME
+.Nm identd
+.Nd TCP/IP Ident protocol server.
+.Sh SYNOPSIS
+.Nm
+.Op Fl 4
+.Op Fl 6
+.Op Fl a Ar address
+.Op Fl b
+.Op Fl c Ar charset
+.Op Fl e
+.Op Fl f Ar fallback
+.Op Fl F Ar format
+.Op Fl g Ar uid
+.Op Fl i
+.Op Fl I
+.Op Fl l
+.Op Fl L Ar username
+.Op Fl n
+.Op Fl N
+.Op Fl o Ar osname
+.Op Fl p Ar portno
+.Op Fl r
+.Op Fl t Ar seconds
+.Op Fl u Ar uid
+.Sh DESCRIPTION
+.Nm
+is a TCP/IP server which implements the user identification protocol
+as specified in RFC 1413.
+.Pp
+.Nm
+operates by looking up specific TCP/IP connections and returning
+information which may or may not be associated with the process owning
+the connection.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl 4
+Bind to IPv4 addresses only. (flag
+.Fl b
+only)
+.It Fl 6
+Bind to IPv6 addresses only. (flag
+.Fl b
+only)
+.It Fl a Ar address
+Bind to the specified
+.Ar address .
+This may be an IPv4 or IPv6 address or even a hostname.
+If a hostname is specified then
+.Nm
+will resolve it to an address (or addresses) and will bind this address. (flag
+.Fl b
+only)
+.It Fl b
+Run in the background (as daemon).
+.It Fl c Ar charset
+Specfify an optional character set designator to be included in replies.
+.Ar charset
+should be a valid charset set as described in the
+.Tn MIME RFC
+in upper case characters.
+.It Fl e
+Return
+.Dq UNKNOWN-ERROR
+instead of the usual
+.Dq NO-USER
+or
+.Dq INVALID-PORT
+error reply's.
+.It Fl f Ar fallback
+Specify a
+.Ar fallback
+username.
+If the lookup fails then this username will be returned.
+This can be useful for when running this service on a NAT host.
+.It Fl F Ar format
+Specify the format to display info.
The allowed format specifiers are:
.in +.5i
.nf
-%u print user name
-%U print user number
-%g print (primary) group name
-%G print (primary) group number
-%l print list of all groups by name
-%L print list of all groups by number
-%p print process ID of running process
-%c print command name
-%C print command and arguments
+%u print user name
+%U print user number
+%g print (primary) group name
+%G print (primary) group number
+%l print list of all groups by name
+%L print list of all groups by number
.in -.5i
.fi
+.Pp
The lists of groups (%l, %L) are comma-separated, and start with the primary
group which is not repeated.
-The %p and the %c and %C formats are not supported on all architecture
-implementations (printing 0 or empty string instead).
-.br
Any other characters (preceded by %, and those not preceded by it)
are printed literally.
The "default" format is %u, and you should not use
-anything else without the
-.B \-o
-flag.
-.br
-Not implemented yet, but on my wish-list are the following:
-.in +.5i
-.nf
-%w print working (current) directory
-%h print home (login, naming) directory
-%e print the environment
-.in -.5i
-.fi
-.PP
-.B kernelfile
-defaults to the normally running kernel file.
-.PP
-.B kmemfile
-defaults to the memory space of the normally running kernel.
-.SH UNDERDOCUMENTED FLAGS
-The
-.B \-v
-flag enables more verbose output or messages.
-(Further occurrences of the
-.B -v
-flag make things even more verbose.)
-Currently not used: ignored.
-.PP
-The
-.B \-f\*[Lt]config-file\*[Gt]
-option causes
-.B identd
-to use the named config file (instead of the default /etc/identd.conf ?).
-Currently not used: ignored, no config files are used.
-.PP
-The
-.B \-r\*[Lt]indirect_host\*[Gt]
-option is used in some way (for proxy queries?).
-.PP
-The
-.B \-C\*[Lt]keyfile\*[Gt]
-option is used in some way for DES encryption.
-.SH INSTALLATION
-.B identd
-is invoked either by the internet server (see
-.BR inetd (8C)
-) for requests to connect to the
-.SM IDENT
-port as indicated by the
-.B /etc/services
-file (see
-.BR services (5)
-) when using the
-.B \-w
-or
-.B \-i
-modes of operation or started manually by using the
-.B \-b
-mode of operation.
-.SH EXAMPLES
-Assuming the server is located in
-.B /usr/libexec/identd
-one can put either:
-.PP
-ident stream tcp wait sys /usr/libexec/identd identd -w -t120
-.PP
-or:
-.PP
-ident stream tcp nowait sys /usr/libexec/identd identd -i
-.PP
-into the
-.B /etc/inetd.conf
-file.
-User "sys" should have enough rights to READ the kernel
-but NOT to write to it.
-.PP
-To start it using the
-.B \-b
-mode of operation one can put a line like this into the
-.B /etc/rc.local
-file:
-.PP
-/usr/libexec/identd -b -u2 -g2
-.PP
-This will make it run in the background as user 2, group 2
-(user "sys", group "kmem" on SunOS 4.1.1).
-.SH NOTES
-There should be no need to ever use this;
-if you think you need this, you really need protocols
-which do strong host and/or user authentication such as ssh and IPsec
-in conjunction with audit trails.
+anything else without using the flag
+.Ar -o OTHER .
+.It Fl g Ar gid
+Specify the group id number or name which the server should switch to after
+binding itself to the TCP/IP port.
+.It Fl i
+If the
+.Pa .ident
+file exists in the home directory of the identified user, return the username
+found in that file instead of the real username.
+If the username found in
+.Pa .ident
+is that of an existing user, then the real username will be returned.
+.It Fl I
+Same as
+.Fl i
+but without the restriction that the username in
+.Pa .ident
+must not match an existing user.
+.It Fl l
+Use syslog for logging.
+.It Fl L Ar username
+Specify a
+.Dq lie
+.Ar username .
+Return this name for all ident requests.
+.It Fl n
+Return numeric user IDs instead of usernames.
+.It Fl N
+Enable
+.Pa .noident
+files.
+If this file exists in the home directory of the identified user then return
+.Dq HIDDEN-USER
+instead of the normal USERID response.
+.It Fl o Ar osname
+Return
+.Ar osname
+instead of the default
+.Dq UNIX .
+.It Fl p Ar portno
+Specify an alternative port number where the server should run under.
+The default is port 113. (flag
+.Fl b
+only)
+.It Fl r
+Return a random name of alphanumeric characters.
+If the
+.Fl n
+flag is also enabled then a random number will be returned.
+.It Fl t Ar seconds
+Specify a timeout for the service.
+The default timeout is 30 seconds.
+.It Fl u Ar uid
+Specify the user id number or name which the server should switch to after
+binding itself to the TCP/IP port.
+.El
+.Sh EXAMPLES
+.Nm
+operates from
+.Xr inetd 8
+or as standalone daemon.
+Put the following lines into
+.Xr inetd.conf 5
+to enable
+.Nm
+as an IPv4 and IPv6 service via inetd:
+.Pp
+ident stream tcp nowait nobody /usr/libexec/identd identd -l
+.Pp
+ident stream tcp6 nowait nobody /usr/libexec/identd identd -l
.Pp
-The username (or UID) returned ought to be the login name.
-However it (probably, for most architecture implementations)
-is the "real user ID" as stored with the process;
-there is no provision for returning the "effective user ID".
-Thus the UID returned may be different from the login name for
-setuid programs (or those running as root) which done a
-.BR setuid (2)
-call and their children.
-For example, it may (should?) be wrong for an incoming
-.B ftpd
-; and we are probably interested in the running shell, not the
-.B telnetd
-for an incoming telnet session.
-(But of course
-.B identd
-returns info for outgoing connections, not incoming ones.)
-.PP
-The group or list of groups returned (with the
-.B \-F
-option) are as looked up in the
-.B /etc/passwd
-and
-.B /etc/group
-files, based on the UID returned.
-Thus these may not relate well to the group(s) of the running
-process for setuid or setgid programs or their children.
-.PP
-The command names returned with formats %c and %C may be different,
-use one or the other or both.
-.SH FILES
-.TP
-.B /etc/identd.conf
-This file is as yet un-used, but will eventually contain configuration
-options for
-.B identd
-.TP
-.B /etc/identd.key
-If compiled with
-.I \-ldes
-this file can be used to specify a secret key for encrypting replies.
-.SH SECURITY CONSIDERATIONS
-May leak information generally considered "private" unless the
-.B \-e
-flag or
-.\"either the
-.B \-L
-.\"or
-.\".B \-C
-flags are used.
-.PP
-The protocol is unprotected and is vulnerable to man-in-the-middle
-attacks.
-.SH "SEE ALSO"
-.BR inetd.conf (5)
-.SH BUGS
-The
-.B \-e
-and
-.B \-L
-flags should be enabled by default.
-.PP
-The whole concept of this service is a bug; cryptographic
-authentication should be integrated into services which think they
-need this.
-.PP
-The handling of fatal errors could be better.
+If you want to run
+.Nm
+as standalone daemon then please use the
+.Fl b
+flag (background).
+.Sh FILES
+/etc/inetd.conf
+.Sh SEE ALSO
+.Xr inetd 8 ,
+.Xr inetd.conf 5
diff --git a/libexec/identd/identd.c b/libexec/identd/identd.c
index fa799ff9ba1..2a5c9782d1d 100644
--- a/libexec/identd/identd.c
+++ b/libexec/identd/identd.c
@@ -1,806 +1,767 @@
-/* $NetBSD: identd.c,v 1.19 2003/09/14 22:38:23 christos Exp $ */
+/* $NetBSD: identd.c,v 1.20 2004/01/31 21:47:17 christos Exp $ */
/*
-** identd.c A TCP/IP link identification protocol server
-**
-** This program is in the public domain and may be used freely by anyone
-** who wants to.
-**
-** Last update: 7 Oct 1993
-**
-** Please send bug fixes/bug reports to: Peter Eriksson <pen@lysator.liu.se>
-*/
-
-#if defined(IRIX) || defined(SVR4) || defined(NeXT) || (defined(sco) && sco >= 42) || defined(_AIX4) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(ultrix)
-# define SIGRETURN_TYPE void
-# define SIGRETURN_TYPE_IS_VOID
-#else
-# define SIGRETURN_TYPE int
-#endif
-
-#ifdef SVR4
-# define STRNET
-#endif
-
-#ifdef NeXT31
-# include <libc.h>
-#endif
-
-#ifdef sco
-# define USE_SIGALARM
-#endif
+ * identd.c - TCP/IP Ident protocol server.
+ *
+ * This software is in the public domain.
+ * Written by Peter Postma <peter@pointless.nl>
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+
+#include <arpa/inet.h>
-#include <stdio.h>
#include <ctype.h>
+#include <err.h>
#include <errno.h>
-#include <netdb.h>
-#include <signal.h>
#include <fcntl.h>
+#include <grp.h>
+#include <netdb.h>
#include <poll.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define OPSYS_NAME "UNIX"
+#define IDENT_SERVICE "auth"
+#define TIMEOUT 30 /* seconds */
+
+static int idhandle(int, const char *, const char *, const char *,
+ const char *, int);
+static void idparse(int, int, int, const char *, const char *, const char *);
+static void iderror(int, int, int, const char *);
+static const char *gethost(struct sockaddr_storage *);
+static int *socketsetup(const char *, const char *, int);
+static int sysctl_getuid(struct sockaddr_storage *, socklen_t, uid_t *);
+static int check_noident(const char *);
+static int check_userident(const char *, char *, size_t);
+static void random_string(char *, size_t);
+static void change_format(const char *, struct passwd *, char *, size_t);
+static void timeout_handler(int);
+static void waitchild(int);
+static void fatal(const char *);
+
+static int bflag, eflag, fflag, Fflag, iflag, Iflag;
+static int lflag, Lflag, nflag, Nflag, rflag;
+
+int
+main(int argc, char *argv[])
+{
+ int IPv4or6, ch, *socks, timeout;
+ char *address, *charset, *fmt;
+ const char *osname, *portno;
+ char *p;
+ char user[LOGIN_NAME_MAX];
+ struct group *grp;
+ struct passwd *pw;
+ gid_t gid;
+ uid_t uid;
+
+ IPv4or6 = AF_UNSPEC;
+ osname = OPSYS_NAME;
+ portno = IDENT_SERVICE;
+ timeout = TIMEOUT;
+ address = NULL;
+ charset = NULL;
+ fmt = NULL;
+ socks = NULL;
+ gid = uid = 0;
+ bflag = eflag = fflag = Fflag = iflag = Iflag = 0;
+ lflag = Lflag = nflag = Nflag = rflag = 0;
+
+ /* Started from a tty? then run as daemon */
+ if (isatty(0))
+ bflag = 1;
+
+ /* Parse arguments */
+ while ((ch = getopt(argc, argv, "46a:bceF:f:g:IiL:lNno:p:rt:u:")) != -1)
+ switch (ch) {
+ case '4':
+ IPv4or6 = AF_INET;
+ break;
+ case '6':
+ IPv4or6 = AF_INET6;
+ break;
+ case 'a':
+ address = optarg;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'c':
+ charset = optarg;
+ break;
+ case 'e':
+ eflag = 1;
+ break;
+ case 'F':
+ Fflag = 1;
+ fmt = optarg;
+ break;
+ case 'f':
+ fflag = 1;
+ (void)strlcpy(user, optarg, sizeof(user));
+ break;
+ case 'g':
+ gid = (gid_t)strtol(optarg, &p, 0);
+ if (*p != '\0') {
+ if ((grp = getgrnam(optarg)) != NULL)
+ gid = grp->gr_gid;
+ else
+ errx(1, "No such group '%s'", optarg);
+ }
+ break;
+ case 'I':
+ Iflag = 1;
+ /* FALLTHROUGH */
+ case 'i':
+ iflag = 1;
+ break;
+ case 'L':
+ Lflag = 1;
+ (void)strlcpy(user, optarg, sizeof(user));
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'N':
+ Nflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'o':
+ osname = optarg;
+ break;
+ case 'p':
+ portno = optarg;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 't':
+ timeout = (int)strtol(optarg, &p, 0);
+ if (*p != '\0')
+ errx(1, "Invalid timeout value '%s'", optarg);
+ break;
+ case 'u':
+ uid = (uid_t)strtol(optarg, &p, 0);
+ if (*p != '\0') {
+ if ((pw = getpwnam(optarg)) != NULL) {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ } else
+ errx(1, "No such user '%s'", optarg);
+ }
+ break;
+ default:
+ exit(1);
+ }
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#ifndef _AUX_SOURCE
-# include <sys/file.h>
-#endif
-#include <sys/time.h>
-#include <sys/wait.h>
+ if (lflag)
+ openlog("identd", LOG_PID, LOG_DAEMON);
-#include <pwd.h>
-#include <grp.h>
+ /* Setup sockets if -b flag */
+ if (bflag) {
+ socks = socketsetup(address, portno, IPv4or6);
+ if (socks == NULL)
+ return 1;
+ }
-#include <netinet/in.h>
+ /* Switch to another uid/gid ? */
+ if (gid && setgid(gid) == -1) {
+ if (lflag)
+ syslog(LOG_ERR, "setgid: %m");
+ if (bflag)
+ warn("setgid");
+ exit(1);
+ }
+ if (uid && setuid(uid) == -1) {
+ if (lflag)
+ syslog(LOG_ERR, "setuid: %m");
+ if (bflag)
+ warn("setuid");
+ exit(1);
+ }
-#ifndef HPUX7
-# include <arpa/inet.h>
-#endif
+ /* Daemonize, setup pollfds and start mainloop if -b flag */
+ if (bflag) {
+ int fd, i, nfds, rv;
+ struct pollfd *rfds;
+
+ (void)signal(SIGCHLD, waitchild);
+ (void)daemon(0, 0);
+
+ rfds = malloc(*socks * sizeof(struct pollfd));
+ if (rfds == NULL)
+ fatal("malloc");
+ nfds = *socks;
+ for (i = 0; i < nfds; i++) {
+ rfds[i].fd = socks[i+1];
+ rfds[i].events = POLLIN;
+ rfds[i].revents = 0;
+ }
+ /* Mainloop for daemon */
+ for (;;) {
+ rv = poll(rfds, nfds, INFTIM);
+ if (rv < 0 && errno == EINTR)
+ continue;
+ if (rv < 0)
+ fatal("poll");
+ for (i = 0; i < nfds; i++) {
+ if (rfds[i].revents & POLLIN) {
+ fd = accept(rfds[i].fd, NULL, NULL);
+ if (fd < 0) {
+ if (lflag)
+ syslog(LOG_ERR,
+ "accept: %m");
+ continue;
+ }
+ switch (fork()) {
+ case -1: /* error */
+ if (lflag)
+ syslog(LOG_ERR,
+ "fork: %m");
+ (void)sleep(1);
+ break;
+ case 0: /* child */
+ (void)idhandle(fd, charset,
+ fmt, osname, user, timeout);
+ _exit(0);
+ default: /* parent */
+ (void)close(fd);
+ }
+ }
+ }
+ }
+ } else
+ (void)idhandle(STDIN_FILENO, charset, fmt, osname, user,
+ timeout);
-#if defined(MIPS) || defined(BSD43)
-extern int errno;
-#endif
+ return 0;
+}
-#if defined(SOLARIS) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(_AIX)
-# include <unistd.h>
-# include <stdlib.h>
-# include <string.h>
-#endif
+static int
+idhandle(int fd, const char *charset, const char *fmt, const char *osname,
+ const char *user, int timeout)
+{
+ struct sockaddr_storage ss[2];
+ char userbuf[LOGIN_NAME_MAX];
+ char idbuf[LOGIN_NAME_MAX];
+ char buf[BUFSIZ], *p;
+ int n, lport, fport;
+ struct passwd *pw;
+ socklen_t len;
+ uid_t uid;
+
+ lport = fport = 0;
+
+ (void)strlcpy(idbuf, user, sizeof(idbuf));
+ (void)signal(SIGALRM, timeout_handler);
+ (void)alarm(timeout);
+
+ /* Get foreign internet address */
+ len = sizeof(ss[0]);
+ if (getpeername(fd, (struct sockaddr *)&ss[0], &len) < 0)
+ fatal("getpeername");
+
+ if (lflag)
+ syslog(LOG_INFO, "Connection from %s", gethost(&ss[0]));
+
+ /* Get local internet address */
+ len = sizeof(ss[1]);
+ if (getsockname(fd, (struct sockaddr *)&ss[1], &len) < 0)
+ fatal("getsockname");
+
+ /* Be sure to have the same address family's */
+ if (ss[0].ss_family != ss[1].ss_family) {
+ if (lflag)
+ syslog(LOG_ERR, "Foreign/local AF are different!");
+ return 1;
+ }
-#include "identd.h"
-#include "error.h"
-#include "paths.h"
+ /* Receive data from the client */
+ if ((n = recv(fd, buf, sizeof(buf) - 1, 0)) < 0) {
+ fatal("recv");
+ } else if (n == 0) {
+ if (lflag)
+ syslog(LOG_NOTICE, "recv: EOF");
+ iderror(fd, 0, 0, "UNKNOWN-ERROR");
+ return 1;
+ }
+ buf[n] = '\0';
+
+ /* Get local and remote ports from the received data */
+ p = buf;
+ while (*p != '\0' && isspace(*p))
+ p++;
+ if ((p = strtok(p, " \t,")) != NULL) {
+ lport = atoi(p);
+ if ((p = strtok(NULL, " \t,")) != NULL)
+ fport = atoi(p);
+ }
+ /* Are the ports valid? */
+ if (lport < 1 || lport > 65535 || fport < 1 || fport > 65535) {
+ if (lflag)
+ syslog(LOG_NOTICE, "Invalid port(s): %d, %d from %s",
+ lport, fport, gethost(&ss[0]));
+ iderror(fd, 0, 0, eflag ? "UNKNOWN-ERROR" : "INVALID-PORT");
+ return 1;
+ }
-/* Antique unixes do not have these things defined... */
-#ifndef FD_SETSIZE
-# define FD_SETSIZE 256
-#endif
+ /* If there is a 'lie' user enabled, then handle it now and quit */
+ if (Lflag) {
+ if (lflag)
+ syslog(LOG_NOTICE, "Lying with name %s to %s",
+ idbuf, gethost(&ss[0]));
+ idparse(fd, lport, fport, charset, osname, idbuf);
+ return 0;
+ }
-#ifndef FD_SET
-# ifndef NFDBITS
-# define NFDBITS (sizeof(int) * NBBY) /* bits per mask */
-# endif
-# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
-#endif
+ /* Protocol dependent stuff */
+ switch (ss[0].ss_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)&ss[0])->sin_port = htons(fport);
+ ((struct sockaddr_in *)&ss[1])->sin_port = htons(lport);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&ss[0])->sin6_port = htons(fport);
+ ((struct sockaddr_in6 *)&ss[1])->sin6_port = htons(lport);
+ break;
+ default:
+ if (lflag)
+ syslog(LOG_ERR, "Unsupported protocol, proto no. %d",
+ ss[0].ss_family);
+ return 1;
+ }
-#ifndef FD_ZERO
-# define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
-#endif
+ /* Do sysctl call */
+ if (sysctl_getuid(ss, sizeof(ss), &uid) == -1) {
+ if (lflag)
+ syslog(LOG_ERR, "sysctl: %m");
+ if (fflag) {
+ if (lflag)
+ syslog(LOG_NOTICE, "Using fallback name %s "
+ "to %s", idbuf, gethost(&ss[0]));
+ idparse(fd, lport, fport, charset, osname, idbuf);
+ return 0;
+ }
+ iderror(fd, lport, fport, eflag ? "UNKNOWN-ERROR" : "NO-USER");
+ return 1;
+ }
+ /* Get username with the uid */
+ if ((pw = getpwuid(uid)) == NULL) {
+ if (lflag)
+ syslog(LOG_ERR, "Couldn't map uid (%u) to name", uid);
+ (void)snprintf(idbuf, sizeof(idbuf), "%u", uid);
+ idparse(fd, lport, fport, charset, osname, idbuf);
+ return 0;
+ }
-char *path_unix = (char *) NULL;
-char *path_kmem = (char *) NULL;
+ if (lflag)
+ syslog(LOG_INFO, "Successfull lookup: %d, %d: %s for %s",
+ lport, fport, pw->pw_name, gethost(&ss[0]));
+
+ /* No ident enabled? */
+ if (Nflag && check_noident(pw->pw_dir)) {
+ if (lflag)
+ syslog(LOG_NOTICE, "Returning HIDDEN-USER for user %s"
+ " to %s", pw->pw_name, gethost(&ss[0]));
+ iderror(fd, lport, fport, "HIDDEN-USER");
+ return 1;
+ }
-int verbose_flag = 0;
-int debug_flag = 0;
-int syslog_flag = 0;
-int multi_flag = 0;
-int other_flag = 0;
-int unknown_flag = 0;
-int noident_flag = 0;
-int crypto_flag = 0;
-int liar_flag = 0;
+ /* User ident enabled ? */
+ if (iflag && check_userident(pw->pw_dir, idbuf, sizeof(idbuf))) {
+ (void)strlcpy(userbuf, pw->pw_name, sizeof(userbuf));
+ if (!Iflag) {
+ if (strspn(idbuf, "0123456789") &&
+ getpwuid(atoi(idbuf)) != NULL)
+ (void)strlcpy(idbuf, userbuf, sizeof(idbuf));
+ else if (getpwnam(idbuf) != NULL)
+ (void)strlcpy(idbuf, userbuf, sizeof(idbuf));
+ }
+ if (lflag)
+ syslog(LOG_NOTICE, "Returning user specified '%s' for "
+ "user %s to %s", idbuf, userbuf, gethost(&ss[0]));
+ idparse(fd, lport, fport, charset, osname, idbuf);
+ return 0;
+ }
-int lport = 0;
-int fport = 0;
+ /* Send random crap? */
+ if (rflag) {
+ /* Random number or string? */
+ if (nflag)
+ (void)snprintf(idbuf, sizeof(idbuf), "%u",
+ (unsigned int)(arc4random() % 65535));
+ else
+ random_string(idbuf, sizeof(idbuf));
-char *charset_name = (char *) NULL;
-char *indirect_host = (char *) NULL;
-char *indirect_password = (char *) NULL;
-char *lie_string = (char *) NULL;
+ if (lflag)
+ syslog(LOG_NOTICE, "Returning random '%s' for user %s"
+ " to %s", idbuf, pw->pw_name, gethost(&ss[0]));
+ idparse(fd, lport, fport, charset, osname, idbuf);
+ return 0;
+ }
-#ifdef ALLOW_FORMAT
- int format_flag = 0;
- char *format = "%u";
-#endif
+ /* Return number? */
+ if (nflag)
+ (void)snprintf(idbuf, sizeof(idbuf), "%u", uid);
+ else
+ (void)strlcpy(idbuf, pw->pw_name, sizeof(idbuf));
-static int child_pid;
+ if (Fflag) {
+ /* RFC 1413 says that 512 is the limit */
+ change_format(fmt, pw, buf, 512);
+ idparse(fd, lport, fport, charset, osname, buf);
+ } else
+ idparse(fd, lport, fport, charset, osname, idbuf);
-#ifdef LOG_DAEMON
-static int syslog_facility = LOG_DAEMON;
-#endif
+ return 0;
+}
-static int comparemem __P((void *, void *, int));
-char *clearmem __P((void *, int));
-static SIGRETURN_TYPE child_handler __P((int));
-int main __P((int, char *[]));
+/* Send/parse the ident result */
+static void
+idparse(int fd, int lport, int fport, const char *charset, const char *osname,
+ const char *user)
+{
+ char *p;
+
+ if (asprintf(&p, "%d , %d : USERID : %s%s%s : %s\r\n", lport, fport,
+ osname, charset ? " , " : "", charset ? charset : "", user) < 0)
+ fatal("asprintf");
+ if (send(fd, p, strlen(p), 0) < 0) {
+ free(p);
+ fatal("send");
+ }
+ free(p);
+}
-/*
-** The structure passing convention for GCC is incompatible with
-** Suns own C compiler, so we define our own inet_ntoa() function.
-** (This should only affect GCC version 1 I think, a well, this works
-** for version 2 also so why bother.. :-)
-*/
-#if defined(__GNUC__) && defined(__sparc__) && !defined(NeXT)
-
-#ifdef inet_ntoa
-#undef inet_ntoa
-#endif
-
-char *inet_ntoa(ad)
- struct in_addr ad;
+/* Return a specified ident error */
+static void
+iderror(int fd, int lport, int fport, const char *error)
{
- unsigned long int s_ad;
- int a, b, c, d;
- static char addr[20];
-
- s_ad = ad.s_addr;
- d = s_ad % 256;
- s_ad /= 256;
- c = s_ad % 256;
- s_ad /= 256;
- b = s_ad % 256;
- a = s_ad / 256;
- snprintf(addr, sizeof(addr), "%d.%d.%d.%d", a, b, c, d);
-
- return addr;
+ char *p;
+
+ if (asprintf(&p, "%d , %d : ERROR : %s\r\n", lport, fport, error) < 0)
+ fatal("asprintf");
+ if (send(fd, p, strlen(p), 0) < 0) {
+ free(p);
+ fatal("send");
+ }
+ free(p);
}
-#endif
-static int comparemem(vp1, vp2, len)
- void *vp1;
- void *vp2;
- int len;
+/* Return the IP address of the connecting host */
+static const char *
+gethost(struct sockaddr_storage *ss)
{
- unsigned char *p1 = (unsigned char *) vp1;
- unsigned char *p2 = (unsigned char *) vp2;
- int c;
+ static char host[NI_MAXHOST];
- while (len-- > 0)
- if ((c = (int) *p1++ - (int) *p2++) != 0)
- return c;
+ if (getnameinfo((struct sockaddr *)ss, ss->ss_len, host,
+ sizeof(host), NULL, 0, NI_NUMERICHOST) == 0)
+ return host;
- return 0;
+ return "UNKNOWN";
}
-/*
-** Return the name of the connecting host, or the IP number as a string.
-*/
-char *gethost(addr)
- struct in_addr *addr;
+/* Setup sockets, for daemon mode */
+static int *
+socketsetup(const char *address, const char *port, int af)
{
- int i;
- struct hostent *hp;
-
-
- hp = gethostbyaddr((char *) addr, sizeof(struct in_addr), AF_INET);
- if (hp)
- {
- char *hname = strdup(hp->h_name);
-
- if (! hname) {
- syslog(LOG_ERR, "strdup(%s): %m", hp->h_name);
- exit(1);
+ struct addrinfo hints, *res, *res0;
+ int error, maxs, *s, *socks, y = 1;
+ const char *cause = NULL;
+
+ (void)memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(address, port, &hints, &res0);
+ if (error) {
+ if (lflag)
+ syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(error));
+ errx(1, "%s", gai_strerror(error));
+ /*NOTREACHED*/
+ }
+
+ /* Count max number of sockets we may open */
+ for (maxs = 0, res = res0; res != NULL; res = res->ai_next)
+ maxs++;
+
+ socks = malloc((maxs + 1) * sizeof(int));
+ if (socks == NULL) {
+ if (lflag)
+ syslog(LOG_ERR, "malloc: %m");
+ err(1, "malloc");
+ /* NOTREACHED */
}
- /* Found a IP -> Name match, now try the reverse for security reasons */
- hp = gethostbyname(hname);
- (void) free(hname);
- if (hp)
-#ifdef h_addr
- for (i = 0; hp->h_addr_list[i]; i++)
- if (comparemem(hp->h_addr_list[i],
- (unsigned char *) addr,
- (int) sizeof(struct in_addr)) == 0)
- return (char *) hp->h_name;
-#else
- if (comparemem(hp->h_addr, addr, sizeof(struct in_addr)) == 0)
- return hp->h_name;
-#endif
- }
-
- return inet_ntoa(*addr);
+
+ *socks = 0;
+ s = socks + 1;
+ for (res = res0; res != NULL; res = res->ai_next) {
+ *s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (*s < 0) {
+ cause = "socket";
+ continue;
+ }
+ (void)setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y));
+ if (bind(*s, res->ai_addr, res->ai_addrlen) < 0) {
+ cause = "bind";
+ (void)close(*s);
+ continue;
+ }
+ if (listen(*s, 5) < 0) {
+ cause = "listen";
+ (void)close(*s);
+ continue;
+ }
+ *socks = *socks + 1;
+ s++;
+ }
+
+ if (*socks == 0) {
+ free(socks);
+ if (lflag)
+ syslog(LOG_ERR, "%s: %m", cause);
+ err(1, "%s", cause);
+ /* NOTREACHED */
+ }
+ if (res0)
+ freeaddrinfo(res0);
+
+ return socks;
}
-#ifdef USE_SIGALARM
-/*
-** Exit cleanly after our time's up.
-*/
-static SIGRETURN_TYPE
-alarm_handler(int s)
+/* Return the UID for the connection owner */
+static int
+sysctl_getuid(struct sockaddr_storage *ss, socklen_t len, uid_t *uid)
{
- if (syslog_flag)
- syslog(LOG_DEBUG, "SIGALRM triggered, exiting");
-
- exit(0);
+ int mib[4];
+ uid_t myuid;
+ size_t uidlen;
+
+ uidlen = sizeof(myuid);
+
+ mib[0] = CTL_NET;
+ mib[1] = ss->ss_family;
+ mib[2] = IPPROTO_TCP;
+ mib[3] = TCPCTL_IDENT;
+
+ if (sysctl(mib, sizeof(mib)/ sizeof(int), &myuid, &uidlen, ss, len) < 0)
+ return -1;
+ *uid = myuid;
+
+ return 0;
}
-#endif
+/* Check if a .noident file exists in the user home directory */
+static int
+check_noident(const char *homedir)
+{
+ struct stat sb;
+ char *path;
+ int ret;
+
+ if (homedir == NULL)
+ return 0;
+ if (asprintf(&path, "%s/.noident", homedir) < 0)
+ return 0;
+ ret = stat(path, &sb);
+
+ free(path);
+ return (ret == 0);
+}
-#if !defined(hpux) && !defined(__hpux) && !defined(SVR4) && \
- !defined(_CRAY) && !defined(sco) && !defined(LINUX)
/*
-** This is used to clean up zombie child processes
-** if the -w or -b options are used.
-*/
-static SIGRETURN_TYPE
-child_handler(dummy)
- int dummy;
+ * Check if a .ident file exists in the user home directory and
+ * return the contents of that file.
+ */
+static int
+check_userident(const char *homedir, char *username, size_t len)
{
-#if defined(NeXT) || (defined(__sgi) && defined(__SVR3))
- union wait status;
-#else
- int status;
-#endif
- int saved_errno = errno;
-
- while (wait3(&status, WNOHANG, NULL) > 0)
- ;
-
- errno = saved_errno;
-
-#ifndef SIGRETURN_TYPE_IS_VOID
- return 0;
-#endif
-}
-#endif
+ struct stat sb;
+ char *path, *p;
+ int fd, n;
+
+ if (len == 0 || homedir == NULL)
+ return 0;
+ if (asprintf(&path, "%s/.ident", homedir) < 0)
+ return 0;
+ if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < 0) {
+ free(path);
+ return 0;
+ }
+ if (fstat(fd, &sb) < 0 || !S_ISREG(sb.st_mode)) {
+ (void)close(fd);
+ free(path);
+ return 0;
+ }
+ if ((n = read(fd, username, len - 1)) < 1) {
+ (void)close(fd);
+ free(path);
+ return 0;
+ }
+ username[n] = '\0';
+ if ((p = strpbrk(username, "\r\n")))
+ *p = '\0';
-char *clearmem(vbp, len)
- void *vbp;
- int len;
-{
- char *bp = (char *) vbp;
- char *cp;
-
- cp = bp;
- while (len-- > 0)
- *cp++ = 0;
-
- return bp;
+ (void)close(fd);
+ free(path);
+ return 1;
}
+/* Generate a random string */
+static void
+random_string(char *str, size_t len)
+{
+ static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
+ char *p;
+
+ if (len == 0)
+ return;
+ for (p = str; len > 1; len--)
+ *p++ = chars[arc4random() % (sizeof(chars) - 1)];
+ *p = '\0';
+}
-/*
-** Main entry point into this daemon
-*/
-int main(argc,argv)
- int argc;
- char *argv[];
+/* Change the output format */
+static void
+change_format(const char *format, struct passwd *pw, char *dest, size_t len)
{
- int i, len;
- struct sockaddr_in sin;
- struct in_addr laddr, faddr;
- int one = 1;
-
- int background_flag = 0;
- int timeout = 0;
- char *portno = "113";
- char *bind_address = (char *) NULL;
- int set_uid = 0;
- int set_gid = 0;
- int inhibit_default_config = 0;
- int opt_count = 0; /* Count of option flags */
-
-#ifdef __convex__
- argc--; /* get rid of extra argument passed by inetd */
-#endif
-
-
- if (isatty(0))
- background_flag = 1;
-
- /*
- ** Prescan the arguments for "-f<config-file>" switches
- */
- inhibit_default_config = 0;
- for (i = 1; i < argc && argv[i][0] == '-'; i++)
- if (argv[i][1] == 'f')
- inhibit_default_config = 1;
-
- /*
- ** Parse the default config file - if it exists
- */
- if (!inhibit_default_config)
- parse_config(NULL, 1);
-
- /*
- ** Parse the command line arguments
- */
- for (i = 1; i < argc && argv[i][0] == '-'; i++) {
- opt_count++;
- switch (argv[i][1])
- {
- case 'b': /* Start as standalone daemon */
- background_flag = 1;
- break;
-
- case 'w': /* Start from Inetd, wait mode */
- background_flag = 2;
- break;
-
- case 'i': /* Start from Inetd, nowait mode */
- background_flag = 0;
- break;
-
- case 't':
- timeout = atoi(argv[i]+2);
- break;
-
- case 'p':
- portno = argv[i]+2;
- break;
-
- case 'a':
- bind_address = argv[i]+2;
- break;
-
- case 'u':
- if (isdigit(argv[i][2]))
- set_uid = atoi(argv[i]+2);
- else
- {
- struct passwd *pwd;
-
- pwd = getpwnam(argv[i]+2);
- if (!pwd)
- ERROR1("no such user (%s) for -u option", argv[i]+2);
- else
- {
- set_uid = pwd->pw_uid;
- set_gid = pwd->pw_gid;
+ struct group *gr;
+ const char *cp;
+ char **gmp;
+ int bp;
+
+ if (len == 0)
+ return;
+ if ((gr = getgrgid(pw->pw_gid)) == NULL)
+ return;
+
+ for (bp = 0, cp = format; *cp != '\0' && bp < 490; cp++) {
+ if (*cp != '%') {
+ dest[bp++] = *cp;
+ continue;
}
- }
- break;
-
- case 'g':
- if (isdigit(argv[i][2]))
- set_gid = atoi(argv[i]+2);
- else
- {
- struct group *grp;
-
- grp = getgrnam(argv[i]+2);
- if (!grp)
- ERROR1("no such group (%s) for -g option", argv[i]+2);
- else
- set_gid = grp->gr_gid;
- }
- break;
-
- case 'c':
- charset_name = argv[i]+2;
- break;
-
- case 'r':
- indirect_host = argv[i]+2;
- break;
-
- case 'l': /* Use the Syslog daemon for logging */
- syslog_flag++;
- break;
-
- case 'o':
- other_flag = 1;
- break;
-
- case 'e':
- unknown_flag = 1;
- break;
-
- case 'V': /* Give version of this daemon */
- printf("[in.identd, version %s]\r\n", version);
- exit(0);
- break;
-
- case 'v': /* Be verbose */
- verbose_flag++;
- break;
-
- case 'd': /* Enable debugging */
- debug_flag++;
- break;
-
- case 'm': /* Enable multiline queries */
- multi_flag++;
- break;
-
- case 'N': /* Enable users ".noident" files */
- noident_flag++;
- break;
-
-#ifdef INCLUDE_CRYPT
- case 'C': /* Enable encryption. */
- {
- FILE *keyfile;
-
- if (argv[i][2])
- keyfile = fopen(argv[i]+2, "r");
- else
- keyfile = fopen(PATH_DESKEY, "r");
-
- if (keyfile == NULL)
- {
- ERROR("cannot open key file for option -C");
- }
- else
- {
- char buf[1024];
-
- if (fgets(buf, 1024, keyfile) == NULL)
- {
- ERROR("cannot read key file for option -C");
- }
- else
- {
- init_encryption(buf);
- crypto_flag++;
- }
- fclose(keyfile);
+ if (*++cp == '\0')
+ break;
+ switch (*cp) {
+ case 'u':
+ (void)snprintf(&dest[bp], len - bp, "%.*s", 490 - bp,
+ pw->pw_name);
+ break;
+ case 'U':
+ (void)snprintf(&dest[bp], len - bp, "%d", pw->pw_uid);
+ break;
+ case 'g':
+ (void)snprintf(&dest[bp], len - bp, "%.*s", 490 - bp,
+ gr->gr_name);
+ break;
+ case 'G':
+ (void)snprintf(&dest[bp], len - bp, "%d", gr->gr_gid);
+ break;
+ case 'l':
+ (void)snprintf(&dest[bp], len - bp, "%.*s", 490 - bp,
+ gr->gr_name);
+ bp += strlen(&dest[bp]);
+ if (bp >= 490)
+ break;
+ setgrent();
+ while ((gr = getgrent()) != NULL) {
+ if (gr->gr_gid == pw->pw_gid)
+ continue;
+ for (gmp = gr->gr_mem; *gmp && **gmp; gmp++) {
+ if (strcmp(*gmp, pw->pw_name) == 0) {
+ (void)snprintf(&dest[bp],
+ len - bp, ",%.*s",
+ 490 - bp, gr->gr_name);
+ bp += strlen(&dest[bp]);
+ break;
+ }
+ }
+ if (bp >= 490)
+ break;
+ }
+ endgrent();
+ break;
+ case 'L':
+ (void)snprintf(&dest[bp], len - bp, "%u", gr->gr_gid);
+ bp += strlen(&dest[bp]);
+ if (bp >= 490)
+ break;
+ setgrent();
+ while ((gr = getgrent()) != NULL) {
+ if (gr->gr_gid == pw->pw_gid)
+ continue;
+ for (gmp = gr->gr_mem; *gmp && **gmp; gmp++) {
+ if (strcmp(*gmp, pw->pw_name) == 0) {
+ (void)snprintf(&dest[bp],
+ len - bp, ",%u",
+ gr->gr_gid);
+ bp += strlen(&dest[bp]);
+ break;
+ }
+ }
+ if (bp >= 490)
+ break;
+ }
+ endgrent();
+ break;
+ default:
+ dest[bp] = *cp;
+ dest[bp+1] = '\0';
+ break;
}
- }
- break;
-#endif
-
-#ifdef ALLOW_FORMAT
- case 'n': /* Compatibility flag - just send the user number */
- format_flag = 1;
- format = "%U";
- break;
-
- case 'F': /* Output format */
- format_flag = 1;
- format = argv[i]+2;
- break;
-#endif
-
- case 'L': /* lie brazenly */
- liar_flag = 1;
- if (*(argv[i]+2) != '\0')
- lie_string = argv[i]+2;
- else
-#ifdef DEFAULT_LIE_USER
- lie_string = DEFAULT_LIE_USER;
-#else
- ERROR("-L specified with no user name");
-#endif
- break;
-
- default:
- ERROR1("Bad option %s", argv[i]);
- break;
+ bp += strlen(&dest[bp]);
}
- }
-
-#if defined(_AUX_SOURCE) || defined (SUNOS35)
- /* A/UX 2.0* & SunOS 3.5 calls us with an argument XXXXXXXX.YYYY
- ** where XXXXXXXXX is the hexadecimal version of the callers
- ** IP number, and YYYY is the port/socket or something.
- ** It seems to be impossible to pass arguments to a daemon started
- ** by inetd.
- **
- ** Just in case it is started from something else, then we only
- ** skip the argument if no option flags have been seen.
- */
- if (opt_count == 0)
- argc--;
-#endif
-
- /*
- ** Path to kernel namelist file specified on command line
- */
- if (i < argc)
- path_unix = argv[i++];
-
- /*
- ** Path to kernel memory device specified on command line
- */
- if (i < argc)
- path_kmem = argv[i++];
-
-
- if (i < argc)
- ERROR1("Too many arguments: ignored from %s", argv[i]);
-
-
- /*
- ** We used to call k_open here. But then the file descriptor
- ** kd->fd open on /dev/kmem is shared by all child processes.
- ** From the fork(2) man page:
- ** o The child process has its own copy of the parent's descriptors. These
- ** descriptors reference the same underlying objects. For instance, file
- ** pointers in file objects are shared between the child and the parent
- ** so that an lseek(2) on a descriptor in the child process can affect a
- ** subsequent read(2) or write(2) by the parent.
- ** Thus with concurrent (simultaneous) identd client processes,
- ** they step on each other's toes when they use kvm_read.
- **
- ** Calling k_open here was a mistake for another reason too: we
- ** did not yet honor -u and -g options. Presumably we are
- ** running as root (unless the in.identd file is setuid), and
- ** then we can open kmem regardless of -u and -g values.
- **
- **
- ** Open the kernel memory device and read the nlist table
- **
- ** if (k_open() < 0)
- ** ERROR("main: k_open");
- */
-
- /*
- ** Do the special handling needed for the "-b" flag
- */
- if (background_flag == 1)
- {
- struct sockaddr_in addr;
- struct servent *sp;
- int fd;
-
-
- if (!debug_flag)
- {
- if (fork())
- exit(0);
-
- close(0);
- close(1);
- close(2);
-
- if (fork())
- exit(0);
- }
-
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd == -1)
- ERROR("main: socket");
-
- if (fd != 0)
- dup2(fd, 0);
-
- clearmem((void *) &addr, (int) sizeof(addr));
-
- addr.sin_family = AF_INET;
- if (bind_address == (char *) NULL)
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- else
- {
- if (isdigit(bind_address[0]))
- addr.sin_addr.s_addr = inet_addr(bind_address);
- else
- {
- struct hostent *hp;
-
- hp = gethostbyname(bind_address);
- if (!hp)
- ERROR1("no such address (%s) for -a switch", bind_address);
-
- /* This is ugly, should use memcpy() or bcopy() but... */
- addr.sin_addr.s_addr = * (unsigned long *) (hp->h_addr);
- }
- }
-
- if (isdigit(portno[0]))
- addr.sin_port = htons(atoi(portno));
- else
- {
- sp = getservbyname(portno, "tcp");
- if (sp == (struct servent *) NULL)
- ERROR1("main: getservbyname: %s", portno);
- addr.sin_port = sp->s_port;
+ if (bp >= 490) {
+ (void)snprintf(&dest[490], len - 490, "...");
+ bp = 493;
}
+ dest[bp] = '\0';
+}
-#ifdef SO_REUSEADDR
- setsockopt(0, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one));
-#endif
-
- if (bind(0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
- ERROR("main: bind");
- }
-
- if (background_flag)
- {
- if (listen(0, 3) < 0)
- ERROR("main: listen");
- }
-
- if (set_gid)
- {
- if (setgid(set_gid) == -1)
- ERROR("main: setgid");
- /* Call me paranoid... PSz */
- if (getgid() != set_gid)
- ERROR2("main: setgid failed: wanted %d, got GID %d", set_gid, getgid());
- if (getegid() != set_gid)
- ERROR2("main: setgid failed: wanted %d, got EGID %d", set_gid, getegid());
- }
-
- if (set_uid)
- {
- if (setuid(set_uid) == -1)
- ERROR("main: setuid");
- /* Call me paranoid... PSz */
- if (getuid() != set_uid)
- ERROR2("main: setuid failed: wanted %d, got UID %d", set_uid, getuid());
- if (geteuid() != set_uid)
- ERROR2("main: setuid failed: wanted %d, got EUID %d", set_uid, geteuid());
- }
-
- if (syslog_flag) {
-#ifdef LOG_DAEMON
- openlog("identd", LOG_PID, syslog_facility);
-#else
- openlog("identd", LOG_PID);
-#endif
- }
- (void)getpwnam("xyzzy");
- (void)gethostbyname("xyzzy");
-
- /*
- ** Do some special handling if the "-b" or "-w" flags are used
- */
- if (background_flag)
- {
- int nfds, fd;
- struct pollfd set[1];
- struct sockaddr sad;
- int sadlen;
-
-
- /*
- ** Set up the SIGCHLD signal child termination handler so
- ** that we can avoid zombie processes hanging around and
- ** handle childs terminating before being able to complete the
- ** handshake.
- */
-#if (defined(SVR4) || defined(hpux) || defined(__hpux) || defined(IRIX) || \
- defined(_CRAY) || defined(_AUX_SOURCE) || defined(sco) || \
- defined(LINUX))
- signal(SIGCHLD, SIG_IGN);
-#else
- signal(SIGCHLD, child_handler);
-#endif
-
- set[0].fd = 0;
- set[0].events = POLLIN;
-
- /*
- ** Loop and dispatch client handling processes
- */
- do
- {
-#ifdef USE_SIGALARM
- /*
- ** Terminate if we've been idle for 'timeout' seconds
- */
- if (background_flag == 2 && timeout)
- {
- signal(SIGALRM, alarm_handler);
- alarm(timeout);
- }
-#endif
-
- /*
- ** Wait for a connection request to occur.
- ** Ignore EINTR (Interrupted System Call).
- */
- do
- {
-#ifndef USE_SIGALARM
- if (timeout)
- nfds = poll(set, 1, timeout * 1000);
- else
-#endif
- nfds = poll(set, 1, INFTIM);
- } while (nfds < 0 && errno == EINTR);
-
- /*
- ** An error occurred in select? Just die
- */
- if (nfds < 0)
- ERROR("main: poll");
-
- /*
- ** Timeout limit reached. Exit nicely
- */
- if (nfds == 0)
- exit(0);
-
-#ifdef USE_SIGALARM
- /*
- ** Disable the alarm timeout
- */
- alarm(0);
-#endif
-
- /*
- ** Accept the new client
- */
- sadlen = sizeof(sad);
- errno = 0;
- fd = accept(0, &sad, &sadlen);
- if (fd == -1) {
- WARNING1("main: accept. errno = %d", errno);
- continue;
- }
-
- /*
- ** And fork, then close the fd if we are the parent.
- */
- child_pid = fork();
- } while (child_pid && (close(fd), 1));
-
- /*
- ** We are now in child, the parent has returned to "do" above.
- */
- if (dup2(fd, 0) == -1)
- ERROR("main: dup2: failed fd 0");
-
- if (dup2(fd, 1) == -1)
- ERROR("main: dup2: failed fd 1");
-
- if (dup2(fd, 2) == -1)
- ERROR("main: dup2: failed fd 2");
- }
-
- /*
- ** Get foreign internet address
- */
- len = sizeof(sin);
- if (getpeername(0, (struct sockaddr *) &sin, &len) == -1)
- {
- /*
- ** A user has tried to start us from the command line or
- ** the network link died, in which case this message won't
- ** reach to other end anyway, so lets give the poor user some
- ** errors.
- */
- perror("in.identd: getpeername()");
- exit(1);
- }
-
- faddr = sin.sin_addr;
-
-
-#ifdef STRONG_LOG
- if (syslog_flag)
- syslog(LOG_INFO, "Connection from %s", gethost(&faddr));
-#endif
-
-
- /*
- ** Get local internet address
- */
- len = sizeof(sin);
-#ifdef ATTSVR4
- if (t_getsockname(0, (struct sockaddr *) &sin, &len) == -1)
-#else
- if (getsockname(0, (struct sockaddr *) &sin, &len) == -1)
-#endif
- {
- /*
- ** We can just die here, because if this fails then the
- ** network has died and we haven't got anyone to return
- ** errors to.
- */
+/* Just exit when we caught SIGALRM */
+static void
+timeout_handler(int s)
+{
+ if (lflag)
+ syslog(LOG_DEBUG, "SIGALRM triggered, exiting...");
exit(1);
- }
- laddr = sin.sin_addr;
-
+}
- /*
- ** Get the local/foreign port pair from the luser
- */
- parse(stdin, &laddr, &faddr);
+/* This is to clean up zombie processes when in daemon mode */
+static void
+waitchild(int s)
+{
+ while (waitpid(-1, NULL, WNOHANG) > 0)
+ continue;
+}
- exit(0);
+/* Report errno through syslog and quit */
+static void
+fatal(const char *func)
+{
+ if (lflag)
+ syslog(LOG_ERR, "%s: %m", func);
+ exit(1);
}