/* * kernel/sco3242_325.c - kernel access functions for SCO 3.2v4.2 * and 3.2v5.0.0 */ /* * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ /* * MODIFICATION HISTORY * * 95/06/05 created by Victor A. Abell * * * 95/07/30 modified by Bela Lubkin * -- Added code to find the real socket head, which may be hidden * behind an in-kernel rlogind/telnetd stream head. * * 95/07/31 modified by Victor A. Abell * -- Moved reading of TCP control block into k_getuid() so it will * be initialized at each call of k_getuid(), thus enabling the * -b abd -w modes to function properly. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if sco<500 #include #include #else /* sco>=500 */ #include #include #endif /* sco<500 */ #include #include #include #include #include #include #include #if sco>=500 #define _INKERNEL #include #undef _INKERNEL #endif /* sco>=500 */ /* * This confusing sequence of redefinitions of xdevmap allows the sizing * of the copy of the kernel's xdevmap[] table to be dynamic, based on the * kernel's nxdevmaps value. * * The net result is that there is a dummy struct XDEVMAP[1] that is never * used. The copy of the kernel's xdevmap[] table is stored in the space * malloc()'d in k_open() and addressed by Xdevmap. The last redefinition * of xdevmap to Xdevmap causes the macroes of to use * Xdevmap. * * All this is done: 1) to avoid having to allocate a large amount of fixed * space in advance to a copy of the kernel's xdevmap; and 2) to keep CC from * complaining about the absence of a "struct xdevmap xdevmap[]," matching * the "extern struct xdevmap xdevmap[]" declaration in , * while still allowing the use of the equivalent of a "struct xdevmap *" * construct instead, particularly with the kernel forms of the major() and * minor() macroes. */ #define xdevmap XDEVMAP #define _INKERNEL #include #undef _INKERNEL static struct XDEVMAP XDEVMAP[1], *Xdevmap; #undef xdevmap #define xdevmap Xdevmap #include "identd.h" #include "error.h" /* * Local definitions */ #define KMEM "/dev/kmem" /* kernel memory device */ #define N_UNIX "/unix" /* kernel image */ #define PROCBFRD 32 /* proc structure buffer size */ /* * Local variables */ static int Kmem = -1; /* kernel memory file descriptor */ static off_t Kp = (off_t)NULL; /* proc table address */ static int nxdevmaps = -1; /* maximum kernel xdevmap[] index */ struct nlist Nl[] = { /* kernel image name list */ { "nxdevmaps", 0, 0, 0, 0, 0 }, #define X_NXD 0 { "proc", 0, 0, 0, 0, 0 }, #define X_PROC 1 { "sockdev", 0, 0, 0, 0, 0 }, #define X_SDEV 2 { "socktab", 0, 0, 0, 0, 0 }, #define X_STAB 3 { "tcb", 0, 0, 0, 0, 0 }, #define X_TCB 4 { "v", 0, 0, 0, 0, 0 }, #define X_VAR 5 { "xdevmap", 0, 0, 0, 0, 0 }, #define X_XDEV 6 #if sco>=500 { "ikntrinit", 0, 0, 0, 0, 0 }, #define X_IKNTR 7 #endif /* sco>=500 */ { NULL, 0, 0, 0, 0, 0 } }; static char *Psb; /* proc structure buffer */ static int Sdev; /* kernel's socket device */ static off_t Stab; /* kernel's socket table address */ static char *Uab; /* user area buffer */ static struct var Var; /* kernel var struct */ /* * k_open() - open access to kernel memory */ int k_open() { int err, i; size_t len; if ((Kmem = open(KMEM, O_RDONLY, 0)) < 0) ERROR1("main: open(%s)", KMEM); /* * Get the kernel name list and check it. */ if (nlist(N_UNIX, Nl) < 0) ERROR1("main: nlist(%s)", N_UNIX); for (err = i = 0; Nl[i].n_name; i++) { if (Nl[i].n_value == (long)NULL) { #if sco>=500 if (i == X_IKNTR) /* * The ikntrinit kernel entry point is optional, so * it's OK if nlist() fails to find its address. */ continue; #endif /* sco>=500 */ if (syslog_flag) syslog(LOG_ERR, "no kernel address for %s", Nl[i].n_name); (void) fprintf(stderr, "no kernel address for %s\n", Nl[i].n_value); err++; } } if (err) k_open_err_exit: ERROR("main: k_open"); /* * Read or set kernel values: * * Kp = process table address; * Sdev = socket device major number; * Stab = socket table address; * Var = kernel environment structure. */ Kp = (off_t)Nl[X_PROC].n_value; if (kread((off_t)Nl[X_SDEV].n_value, (char *)&Sdev, sizeof(Sdev))) { if (syslog_flag) syslog(LOG_ERR, "sockdev read (%#x)", Nl[X_SDEV].n_name); (void) fprintf(stderr, "sockdev read (%#x)\n", Nl[X_SDEV].n_name); err++; } Stab = (off_t)Nl[X_STAB].n_value; if (kread((off_t)Nl[X_VAR].n_value, (char *)&Var, sizeof(Var))) { if (syslog_flag) syslog(LOG_ERR, "var struct read (%#x)", Nl[X_VAR].n_name); (void) fprintf(stderr, "var struct read (%#x)\n", Nl[X_VAR].n_name); err++; } if (err) goto k_open_err_exit; /* * Get extended device table parameters. These are needed by the kernel * versions of the major() and minor() device numbers; they identify socket * devices and assist in the conversion of socket device numbers to socket * table addresses. */ if (kread((off_t)Nl[X_NXD].n_value, (char *)&nxdevmaps, sizeof(nxdevmaps)) ) ERROR1("main: k_open nxdevmaps read (%#x)", Nl[X_NXD].n_name); if (nxdevmaps < 0) ERROR1("main: k_open nxdevmaps size (%d)", nxdevmaps); len = (size_t)((nxdevmaps + 1) * sizeof(struct XDEVMAP)); if ((Xdevmap = (struct XDEVMAP *)malloc(len)) == (struct XDEVMAP *)NULL) ERROR1("main: xdevmap malloc (%d)", len); if (kread((off_t)Nl[X_XDEV].n_value, (char *)Xdevmap, len)) ERROR1("main: xdevmap read (%#x)", Nl[X_XDEV].n_value); /* * Allocate user area and proc structure buffers. */ if ((Uab = (char *)malloc(MAXUSIZE * NBPC)) == (char *)NULL) ERROR1("main: k_open user struct size (%d)", MAXUSIZE * NBPC); if ((Psb = (char *)malloc(sizeof(struct proc) * PROCBFRD)) == NULL) ERROR1("main: k_open proc stuct size (%d)", sizeof(struct proc) * PROCBFRD); return(0); } /* * k_getuid() - get User ID for local and foreign TCP address combination * * returns: -1 if address combination not found * 0 if address combination found and: * *uid = User ID of process with open socket file * having the address combination */ int k_getuid(faddr, fport, laddr, lport, uid) struct in_addr *faddr; /* foreign network address */ int fport; /* foreign port */ struct in_addr *laddr; /* local network address */ int lport; /* local port */ int *uid; /* returned UID pointer */ { struct file f; int i, j, nf, pbc, px; struct inode in; struct proc *p; struct inpcb pcb, tcb; struct queue *q, qb; off_t sa, spa; struct user *u; #if sco>=500 iknt_t ikb; #endif /* sco>=500 */ /* * Search the kernel's TCP control block chain for one whose local and foreign * addresses match. */ if (kread((off_t)Nl[X_TCB].n_value, (char *)&tcb, sizeof(tcb))) { if (syslog_flag) syslog(LOG_ERR, "TCP struct read (%#x)", Nl[X_TCB].n_name); (void) fprintf(stderr, "TCB struct read (%#x)\n", Nl[X_TCB].n_name); ERROR("k_getuid: no TCP control block head"); } i = 0; pcb = tcb; do { if (pcb.inp_faddr.s_addr == faddr->s_addr && pcb.inp_laddr.s_addr == laddr->s_addr && pcb.inp_fport == fport && pcb.inp_lport == lport) { i = 1; break; } } while (pcb.inp_next != (struct inpcb *)NULL && pcb.inp_next != tcb.inp_prev && kread((off_t)pcb.inp_next, (char *)&pcb, sizeof(pcb)) == 0); if ( ! i) return(-1); /* * Follow the stream input queue for the TCP control block to its end * to get the socket address. */ for (q = pcb.inp_q, qb.q_ptr = (caddr_t)NULL; q; q = qb.q_next) { if (kread((off_t)q, (char *)&qb, sizeof(qb))) return(-1); } #if sco>=500 /* * If this is an in-kernel rlogind/telnetd stream head, follow its private * pointer back to the original stream head where the socket address may * be found. */ if (Nl[X_IKNTR].n_value && qb.q_qinfo && qb.q_qinfo == (struct qinit *)Nl[X_IKNTR].n_value) { if (kread((off_t)qb.q_ptr, (char *)&ikb, sizeof(ikb))) return(-1); qb.q_ptr = ikb.ik_oqptr; } #endif /* sco>=500 */ if (qb.q_ptr == (caddr_t)NULL) return(-1); /* * Search the process table, the user structures associated with its proc * structures, and the open file structures associated with the user structs * to find an inode whose major device is Sdev and whose socket structure's * address matches the address identified from the TCB control block scan. */ for (pbc = px = 0, u = (struct user *)Uab; px < Var.v_proc; px++) { if (px >= pbc) { /* * Refill the proc struct buffer. */ i = Var.v_proc - px; if (i > PROCBFRD) i = PROCBFRD; j = kread((off_t)(Kp + (px * sizeof(struct proc))), Psb, sizeof(struct proc) * i); pbc = px + i; if (j) { px += i; continue; } p = (struct proc *)Psb; } else p++; if (p->p_stat == 0 || p->p_stat == SZOMB) continue; /* * Get the user area for the process and follow its file structure * pointers to their inodes. Compare the addresses of socket * structures to the address located in the TCP control block scan * and return the User ID of the first process that has a match. */ if (sysi86(RDUBLK, (int)p->p_pid, Uab, MAXUSIZE * NBPC) == -1) continue; nf = u->u_nofiles ? u->u_nofiles : Var.v_nofiles; for (i = 0; i < nf; i++) { if (u->u_ofile[i] == (struct file *)NULL || kread((off_t)u->u_ofile[i], (char *)&f, sizeof(f)) || f.f_count == 0 || f.f_inode == (struct inode *)NULL || kread((off_t)f.f_inode, (char *)&in, sizeof(in))) continue; if ((in.i_ftype & IFMT) != IFCHR || major(in.i_rdev) != Sdev) continue; spa = Stab + (minor(in.i_rdev)*sizeof(struct socket *)); if (kread(spa, (char *)&sa, sizeof(sa))) continue; if ((caddr_t)sa == qb.q_ptr) { *uid = (int)p->p_uid; return(0); } } } return(-1); } /* * kread() - read from kernel memory */ int kread(addr, buf, len) off_t addr; /* kernel memory address */ char *buf; /* buffer to receive data */ unsigned len; /* length to read */ { int br; if (lseek(Kmem, (off_t)addr, SEEK_SET) == (off_t)-1L) return(1); if ((br = read(Kmem, buf, len)) < 0) return(1); return(((unsigned)br == len) ? 0 : 1); }