This is identd.c in view mode; [Download] [Up]
/** $Header: /usr/src/nidentd-2.0/RCS/identd.c,v 2.0 92/05/04 17:42:54 nigelm Exp $ *** *** identd.c - An implementation of an RFC931 Authentication Daemon *** ~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *** *** *** Author: Nigel Metheringham *** Department of Electronics, University of York, UK *** nigelm@ohm.york.ac.uk *** *** Very heavily based on:- *** pauthd version 1.2 *** by Peter Eriksson (pen@lysator.liu.se) 30 Oct 1991 *** and *** authd version 3.01 *** by Dan Bernstein (brnstnd@nyu.edu) 7 Feb 1991 *** *** $Log: identd.c,v $ *** Revision 2.0 92/05/04 17:42:54 nigelm *** Version for release at base 2.0 version. *** *** *** **/ /** *** *** Include files - it needs tons of these, and every system has *** a slightly different set!!!!! *** **/ #include <stdio.h> #include <errno.h> #include <ctype.h> #include <sys/types.h> #ifdef SYS5_INCLUDES #include <bsd/sys/types.h> #endif #include <sys/param.h> #include <netdb.h> #include <nlist.h> #include <pwd.h> #include <signal.h> #include "paths.h" #ifdef SYS5_INCLUDES #include <bsd/sys/socket.h> #include <bsd/sys/socketvar.h> #else #include <sys/socket.h> #include <sys/socketvar.h> #endif #include <sys/ioctl.h> #define KERNEL #define KERNEL_FEATURES #include <sys/file.h> #undef KERNEL #undef KERNEL_FEATURES #ifdef SYS5_INCLUDES #include <sys/pcb.h> #endif #include <sys/user.h> #ifdef SYS5_INCLUDES #include <bsd/net/if.h> #include <bsd/net/route.h> #include <bsd/netinet/in.h> #include <bsd/netinet/in_pcb.h> #include <bsd/netinet/ip_var.h> #include <bsd/netinet/tcp.h> #include <bsd/netinet/tcp_timer.h> #include <bsd/netinet/tcp_var.h> #else #include <net/if.h> #include <net/route.h> #include <netinet/in.h> #include <netinet/in_pcb.h> #include <netinet/ip_var.h> #include <netinet/tcp.h> #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> #endif #ifdef SYS5_KERNEL /* This declares the kernel structures and is needed even if you are compiling for a BSD universe on a mainly sys5 machine */ #include <sysv/sys/var.h> #endif /** *** *** Global variables and things that go bump in the night *** **/ int flagidentd = 0; /* Are we running as identd */ int flagpwnam = 0; /* Do we want the user name returned */ int debug_flag = 0; /* Squash that bug.... */ char * progname = "NOT-SET"; /* The name of this here program */ int local_port = 0; /* The local port for identd checking */ int remote_port = 0; /* The remote port for identd checking */ extern char optarg; /* For getopt */ extern int optind; /* For getopt */ extern int opterr; /* For getopt */ int kmemfd; /* File handle for kmem */ /** *** *** Name list of things to fish out the kernel... *** Of course this is different for every machine! *** NB some compilers may gripe at the initialisers! **/ struct nlist nl[] = { #ifdef SYS5_KERNEL { "file" }, { "v" }, { "tcb" }, { "" } #else #ifdef NeXT { {"_file_list"} }, { {"_max_file"} }, { {"_tcb"} }, { {""} } #else { "_file" }, { "_nfile" }, { "_tcb" }, { "" } #endif #endif #define N_FILE 0 /* These are common for all architectures */ #define N_NFILE 1 /* at present, but may need moving into the */ #define N_TCB 2 /* machine dependant bits for wierder machines */ }; /** *** *** Usage instructions *** **/ usage() { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\tidentd [-d]\n"); fprintf(stderr, "\ttcpuname [-d] remote-addr remote-port local-addr local-port\n"); fprintf(stderr, "\ttcpuid [-d] remote-addr remote-port local-addr local-port\n"); fprintf(stderr, "\n"); exit(1); } /** *** *** Version *** **/ version() { fprintf(stderr, "%s\n\t$Revision: 2.0 $\n\t$Date\n"); fprintf(stderr, "\tby\tNigel Metheringham, University of York, UK (nigelm@ohm.york.ac.uk)\n"); fprintf(stderr, "\t\tPeter Eriksson (pen@lysator.liu.se)\n"); fprintf(stderr, "\t\tDan Bernstein (brnstnd@nyu.edu)\n"); exit(1); } /** *** *** Last despairing message and suicide....! *** **/ Error_Die(char * where, char * message, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long x4) { if (flagidentd && !debug_flag) { printf("%d, %d: ERROR: UNKNOWN-ERROR\r\n", local_port, remote_port); } else { fprintf(stderr, "%s: ", progname); fprintf(stderr, message, x1, x2, x3, x4); fprintf(stderr, "/"); perror(where); } exit(3); } /** *** *** Get a piece of kernel memory *** The "what" parameter is just for error messages *** **/ getbuf( unsigned long addr, void * buf, int len, char * what) { if (lseek(kmemfd, addr, 0) == -1) { Error_Die("getbuf", "lseek(0x%08x, \"%s\")/", (unsigned long) addr, (unsigned long) what, 0, 0); } if (read(kmemfd, buf, len) < len) { Error_Die("getbuf", "&%08x: read(%08x, %d, \"%s\")/", (unsigned long) addr, (unsigned long) buf, (unsigned long) len, (unsigned long) what); } } /** *** *** Traverse the inpcb list until a match is found *** *** **/ struct socket *getlist( struct inpcb *pcbp, struct in_addr faddr, int fport, struct in_addr laddr, int lport) { struct inpcb *head; if (!pcbp) return NULL; /* Someone gave us a duff one here */ head = pcbp->inp_prev; do { if (pcbp->inp_faddr.s_addr == faddr.s_addr && pcbp->inp_laddr.s_addr == laddr.s_addr && pcbp->inp_fport == fport && pcbp->inp_lport == lport ) return pcbp->inp_socket; } while (pcbp->inp_next != head && getbuf((long) pcbp->inp_next, pcbp, sizeof(struct inpcb), "tcblist")); return NULL; /* Not found */ } /** *** *** Locate the 'ucred' information *** This routine varies a lot according to the type of machine *** its being compiled for **/ struct ucred *getinfo(struct in_addr faddr, int fport, struct in_addr laddr, int lport) { static struct ucred ucb; struct socket *sockp; int i; int nfile; struct inpcb tcb; /* */ #ifdef NeXT struct file file_entry; #else struct file * file_tab; #endif void * addr; #ifdef SYS5_KERNEL struct var kernel_params; #endif void * calloc(); /* I hate it when things are missed from header files */ /* -------------------- TCP PCB LIST -------------------- */ getbuf(nl[N_TCB].n_value, &tcb, sizeof(tcb), "tcb"); tcb.inp_prev = (struct inpcb *) nl[N_TCB].n_value; sockp = getlist(&tcb, faddr, fport, laddr, lport); if (!sockp) return NULL; /* -------------------- FILE DESCRIPTOR TABLE -------------------- */ /* These bits are for semi-conventional - ie non-Mach - machines */ #ifndef NeXT /* Get the size of the file table */ #ifdef SYS5_KERNEL getbuf(nl[N_NFILE].n_value, &kernel_params, sizeof(kernel_params), "kernel_params"); nfile = kernel_params.v_file; /* Size of file table */ #else SYS5_KERNEL getbuf(nl[N_NFILE].n_value, &nfile, sizeof(nfile), "nfile"); #endif SYS5_KERNEL /* Allocate space for a file table copy */ if ((file_tab = calloc((size_t) nfile, (size_t) sizeof(struct file))) == NULL) { Error_Die("getinfo", "No memory", 0, 0, 0, 0); } /* Now get a copy of the file table */ #ifdef SYS5_KERNEL /* NB for SYS5 the file parameter points directly to the start of the file table */ getbuf(nl[N_FILE].n_value, file_tab, sizeof(struct file)*nfile, "file[]"); #else SYS5_KERNEL getbuf(nl[N_FILE].n_value, &addr, sizeof(addr), "&file"); getbuf(addr, file_tab, sizeof(struct file)*nfile, "file[]"); #endif SYS5_KERNEL /* Locate the file descriptor that has the socket in question open so that we can get the 'ucred' information */ for (i = 0; i < nfile; i++) { /* This next bit is implemented as 2 ifs, cos its easier to debug that way! */ if (file_tab[i].f_count && file_tab[i].f_type == DTYPE_SOCKET) { if ((struct socket *) file_tab[i].f_data == sockp) { getbuf(file_tab[i].f_cred, &ucb, sizeof(ucb), "ucb"); return &ucb; } } } #else NeXT /* So now we hit the fun Mach kernel structures */ getbuf(nl[N_FILE].n_value, &addr, sizeof(addr), "&file_table"); /* We only use nfile as a failsafe in case something goes wrong! */ getbuf(nl[N_NFILE].n_value, &nfile, sizeof(nfile), "nfile"); file_entry.links.next = addr; do { getbuf((unsigned long) file_entry.links.next, &file_entry, sizeof(file_entry), "struct file"); if (file_entry.f_count && file_entry.f_type == DTYPE_SOCKET) { if ((void *) file_entry.f_data == (void *) sockp) { getbuf((unsigned long) file_entry.f_cred, &ucb, sizeof(ucb), "ucb"); return &ucb; } } } while ((file_entry.links.next != addr) && (--nfile)); #endif NeXT return NULL; } /** *** *** Processes the flag arguments to the program, *** also determines the invoking name of the program. *** **/ void process_flags(int argc, char * argv[]) { int c; char * ptr; /* Set up program name variable */ progname = argv[0]; for(ptr = argv[0]; *ptr; ptr++) { if (*ptr == '/') progname = ptr; } if (*progname == '/') progname++; /* Check the program name and modify behavior accordingly */ if ((!strcmp(progname,"identd")) || (!strcmp(progname,"in.identd"))) { flagidentd = flagpwnam = 1; } else { if (!strcmp(progname,"tcpuname")) flagpwnam = 1; } /* Work through any command line flags */ while ((c = getopt(argc, argv, "dV")) != EOF) { switch (c) { case 'V': version(); break; case 'd': debug_flag = 1; break; default: usage(); } } } /** *** *** Gets addresses of the current machine and the *** Querying machine, reads socket numbers from stdin *** **/ void get_identd_addresses(struct in_addr * local_addr, int * local_port, struct in_addr * remote_addr, int * remote_port) { struct sockaddr_in sin; int len; /* Get the local/foreign port pair from the luser */ if (scanf("%d , %d", local_port, remote_port) != 2) { Error_Die("get_identd_addresses", "Incorrect input/", 0, 0, 0, 0); } /* Foreign internet address */ len = sizeof(struct sockaddr_in); if (getpeername(0,&sin,&len) == -1) { Error_Die("get_identd_addresses", "getpeername failed/", 0, 0, 0, 0); } *remote_addr = sin.sin_addr; /* Local internet address */ len = sizeof(struct sockaddr_in); if (getsockname(0,&sin,&len) == -1) { Error_Die("get_identd_addresses", "getsockname failed/", 0, 0, 0, 0); } *local_addr = sin.sin_addr; } /** *** *** Gets addresses of the current machine and the *** Querying machine, reads socket numbers from command line. *** **/ void get_given_addresses(int argc, char * argv[], struct in_addr * local_addr, int * local_port, struct in_addr * remote_addr, int * remote_port) { int x1, x2, x3, x4; if(optind == 0) optind++; /* Tacky getopts bug - grrrgh! */ if ((argc - optind) < 3) Error_Die("get_given_addresses","need four arguments", 0, 0, 0, 0); if(sscanf(argv[optind++],"%d.%d.%d.%d",&x1,&x2,&x3,&x4) < 4) Error_Die("get_given_addresses","arg 1 must be a.b.c.d", 0, 0, 0, 0); remote_addr->s_addr = (x1 << 24) | (x2 << 16) | (x3 <<8) | x4; if(sscanf(argv[optind++],"%d",remote_port) < 1) Error_Die("get_given_addresses","arg 2 must be integer", 0, 0, 0, 0); if(sscanf(argv[optind++],"%d.%d.%d.%d",&x1,&x2,&x3,&x4) <4) Error_Die("get_given_addresses","arg 3 must be a.b.c.d", 0, 0, 0, 0); local_addr->s_addr = (x1 << 24) | (x2 << 16) | (x3 <<8) | x4; if(sscanf(argv[optind++],"%d",local_port) < 1) Error_Die("get_given_addresses","arg 4 must be integer", 0, 0, 0, 0); } /** *** *** Dives into the deep end and drags out the kernel *** addresses for required things from the name list *** The list of things looked for is set at compile *** time but may (will!) be different for each type *** of machine!! *** **/ void kernel_namelist(struct nlist nl[]) { /* There are (of course) two main ways of doing this, and one assumes that people will find other ways as well! The #ifdef-ed sections select out the different techniques. ** The KVM method has been removed since I can't test it ** */ #ifdef NeXT /* I normally quite like NeXT, but fiddling with the names of components of the nlist structure could change that, hence the horrible defines just here */ #define N_NAME n_un.n_name #else #define N_NAME n_name #endif /* First we open the kernel memory special file */ if ((kmemfd = open(_PATH_KMEM, 0)) <= 0) { Error_Die("kernel_namelist", "open %s", _PATH_KMEM, 0, 0, 0); } /* Dig into the Unix kernel... */ if (nlist(_PATH_UNIX, nl) != 0) { if (debug_flag) { /* Here's some additional debug tracking */ int i; for (i=0; (*(nl[i].N_NAME)); i++) { if (nl[i].n_type == 0) fprintf(stderr, "\t%s not found.\n", nl[i].N_NAME); } } Error_Die("kernel_namelist", "nlist", 0, 0, 0 , 0); } } /** *** *** The main bit... *** **/ main(int argc, char * argv[]) { struct sockaddr_in sin; int len; struct in_addr local_addr, remote_addr; struct ucred *ucp; struct passwd *pwp; /* Process the command flags, and figure out what program we are! */ process_flags(argc, argv); /* Get the ether & socket addresses involved */ if (flagidentd) { get_identd_addresses(&local_addr, &local_port, &remote_addr, &remote_port); } else { get_given_addresses(argc, argv, &local_addr, &local_port, &remote_addr, &remote_port); } /* Get data from the kernel namelists */ kernel_namelist(nl); /* Next - get locate the specific TCP connection and return the 'ucred' - user credentials - information */ if ((ucp = getinfo(remote_addr, htons(remote_port), local_addr, htons(local_port))) == NULL) { /* This bit is done as a discrete error message because its a different message to all the others! */ printf("%d, %d: ERROR: NO-USER\r\n", local_port, remote_port); exit(37); } /* Then we should try to get the username - when required */ if (flagpwnam) { if ((pwp = getpwuid(ucp->cr_ruid)) == NULL) { Error_Die("main", "unable to lookup UID", 0, 0, 0, 0); } /* Hey! We finally made it!!! - output style depends on what we are! */ if (flagidentd) { printf("%d, %d: USERID: UNIX: %s\r\n", local_port, remote_port, pwp->pw_name); fflush(stdout); } else printf("%s\n", pwp->pw_name); } else { /* Just need to print UID */ printf("%d\n", ucp->cr_ruid); } /* Time for bed said..... */ exit(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.