/* This was written for 3.2; it may not work under 3.1, though I'd be (relatively) happy to have someone try it. Note that this could probably be more efficient if I could figure out how to directly search the TCP control blocks. Unfortunately, I have no idea where they're stored in the kernel, and I didn't really want to spend a lot of time figuring it out. With 20 users logged on and >100 connections, it only takes about .1 second to identify a connection on this 530. Like authd, pauthd, and pidentd, aixident is meant to be started from inetd: ident stream tcp nowait root /usr/local/etc/aixident in.identd -l The name is pronounced like "accident", because that's what I believe RFC931 is. Use at your own risk. */ /* ** aixident -- AIX identification daemon ** version 1.0 ** ** Copyright 1992 by Charles M. Hannum. ** ** Permission is granted to copy, modify, and use this program in any way, ** so long as the above copyright notice, this permission notice, and the ** warranty disclaimer below remain on all copies, and are unaltered. ** ** aixident is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. */ /* ** Usage: ** ** aixident [-l] [-V] [-v] [-d] [kmem_file] ** ** Where: ** ** -l log via syslog ** ** -V print version number and exit ** ** -v verbose (currently useless) ** ** -d enable debugging; lists connections in a lsof-like manner ** ** kmem_file file to read kernel memory from */ char version[] = "aixident, version 1.0"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _KERNEL 1 #include #undef _KERNEL #include int kmem; int kread (); char *printuid (); void printaddr (); int syslog_flag = 0, verbose_flag = 0, debug_flag = 0; #define ERROR(v,m) \ do { \ printf ("%d, %d: ERROR: %s\r\n", local_port, foreign_port, m); \ exit (v); \ } while (0) #define UNKNOWN_ERROR() ERROR (1, "UNKNOWN-ERROR"); int main (argc, argv) int argc; char **argv; { char *path_kmem = "/dev/kmem"; struct sockaddr_in foreign, local; int foreign_len, local_len; int foreign_port = 0, local_port = 0; int max_procs = 64, num_procs, fd; struct procinfo *procinfo; struct user user; struct file *filep, file; struct socket *socketp, socket; struct protosw *protoswp, protosw; struct domain *domainp, domain; struct inpcb *inpcbp, inpcb; struct passwd *passwd; for (--argc; argc && **++argv == '-'; argc--) while (*(++*argv)) switch (**argv) { case 'l': syslog_flag = 1; break; case 'V': puts (version); exit (0); break; case 'v': verbose_flag = 1; break; case 'd': debug_flag = 1; break; } if (argc) { path_kmem = *(argv++); --argc; } foreign_len = sizeof (foreign); if (getpeername (0, &foreign, &foreign_len) == -1) { perror ("getpeername"); exit (1); } local_len = sizeof (local); if (getsockname (0, &local, &local_len) == -1) { perror ("getsockname"); exit (1); } if (syslog_flag) { (void) openlog ("identd", LOG_PID, LOG_DAEMON); (void) syslog (LOG_NOTICE, "Connection from %s", inet_ntoa (foreign.sin_addr.s_addr)); } if (scanf ("%d , %d", &local_port, &foreign_port) != 2 || local_port < 1 || local_port > 65535 || foreign_port < 1 || foreign_port > 65535) { if (syslog_flag) (void) syslog (LOG_INFO, "invalid port(s): %d, %d", local_port, foreign_port); ERROR (0, "INVALID-PORT"); } if ((kmem = open (path_kmem, O_RDONLY)) == -1) { if (syslog_flag) (void) syslog (LOG_ERR, "error opening /dev/kmem: %s", strerror (errno)); UNKNOWN_ERROR (); } while ((procinfo = (struct procinfo *) malloc ((size_t) (max_procs * sizeof (*procinfo)))) && (num_procs = getproc (procinfo, max_procs, sizeof (*procinfo))) == -1 && errno == ENOSPC) { max_procs <<= 1; free (procinfo); } if (! procinfo) { if (syslog_flag) (void) syslog (LOG_ERR, "out of memory allocating %ld procinfo structs\n", max_procs); UNKNOWN_ERROR (); } for (; num_procs; num_procs--, procinfo++) { if (procinfo->pi_stat == 0 || procinfo->pi_stat == SZOMB) continue; if (getuser (procinfo, sizeof (*procinfo), &user, sizeof (user))) continue; for (fd = 0; fd < user.u_maxofile; fd++) { if (! (filep = user.u_ufd[fd].fp)) continue; if (kread ((off_t) filep, (char *) &file, sizeof (file))) { if (syslog_flag) (void) syslog (LOG_ERR, "can't read file struct from %#x", (unsigned) filep); UNKNOWN_ERROR (); } if (file.f_type != DTYPE_SOCKET) continue; if (! (socketp = (struct socket *) file.f_data)) continue; if (kread ((off_t) socketp, (char *) &socket, sizeof (socket))) { if (syslog_flag) (void) syslog (LOG_ERR, "can't read socket struct from %#x", (unsigned) socketp); UNKNOWN_ERROR (); } if (! (protoswp = socket.so_proto)) continue; if (kread ((off_t) protoswp, (char *) &protosw, sizeof (protosw))) { if (syslog_flag) (void) syslog (LOG_ERR, "can't read protosw struct from %#x", (unsigned) protoswp); UNKNOWN_ERROR (); } if (protosw.pr_protocol != IPPROTO_TCP) continue; if (! (domainp = protosw.pr_domain)) continue; if (kread ((off_t) domainp, (char *) &domain, sizeof (domain))) { if (syslog_flag) (void) syslog (LOG_ERR, "can't read domain struct from %#x", (unsigned) domainp); UNKNOWN_ERROR (); } if (domain.dom_family != AF_INET) continue; if (! (inpcbp = (struct inpcb *) socket.so_pcb)) continue; if (kread ((off_t) inpcbp, (char *) &inpcb, sizeof (inpcb))) { if (syslog_flag) (void) syslog (LOG_ERR, "can't read inpcb struct from %#x", (unsigned) inpcbp); UNKNOWN_ERROR (); } if (socketp != inpcb.inp_socket) continue; if (inpcb.inp_faddr.s_addr != foreign.sin_addr.s_addr || inpcb.inp_fport != foreign_port || inpcb.inp_laddr.s_addr != local.sin_addr.s_addr || inpcb.inp_lport != local_port) continue; if (! (passwd = getpwuid (procinfo->pi_uid))) { if (syslog_flag) (void) syslog (LOG_WARNING, "could not map uid to name: %d", procinfo->pi_uid); UNKNOWN_ERROR (); } if (!debug_flag) { if (syslog_flag) (void) syslog (LOG_NOTICE, "identified: %d, %d, %s", local_port, foreign_port, passwd->pw_name); printf ("%d, %d: USERID: UNIX: %s\r\n", local_port, foreign_port, passwd->pw_name); exit (0); } else { printf ("%-9.9s%6d %8s %4d%c %4.4s 0x%08x %8s %7.7s ", user.u_comm, procinfo->pi_pid, printuid (procinfo->pi_uid), fd, ' ', "inet", inpcb.inp_ppcb ? (int) inpcb.inp_ppcb : (int) socket.so_pcb, "", "TCP"); printaddr (&inpcb.inp_laddr, inpcb.inp_lport); if (inpcb.inp_faddr.s_addr != INADDR_ANY || inpcb.inp_fport) { printf ("->"); printaddr (&inpcb.inp_faddr, inpcb.inp_fport); } printf ("\n"); } } } if (syslog_flag) (void) syslog (LOG_DEBUG, "not found: %d, %d", local_port, foreign_port); ERROR (0, "NO-USER"); } int kread (addr, buf, len) off_t addr; char *buf; int len; { int br; if (lseek (kmem, addr, L_SET) == (off_t) -1) return (-1); br = read(kmem, buf, len); return ((br == len) ? 0 : 1); } char * printuid (uid) uid_t uid; { static int used = 0; static uid_t last_uid; struct passwd *passwd; static char user[9]; if (!used || uid != last_uid) { used = 1; last_uid = uid; if (passwd = getpwuid (uid)) (void) strcpy (user, passwd->pw_name); else (void) sprintf (user, "%d", uid); } return (user); } void printaddr (in_addr, port) struct in_addr *in_addr; u_short port; { if (in_addr->s_addr == INADDR_ANY) printf ("*:%d", port); else printf ("%s:%d", inet_ntoa (in_addr->s_addr), port); }