1: /* 2: ** kernel/2.11bsd.c Low level kernel access functions for 2.11BSD 3: ** 4: ** This program is in the public domain and may be used freely by anyone 5: ** who wants to. 6: ** 7: ** Last update: 05 December 1999 8: ** 9: ** Please send bug fixes/bug reports to: Steven Schultz <sms@moe.2bsd.com> 10: */ 11: 12: #include <stdio.h> 13: #include <nlist.h> 14: #include <syslog.h> 15: #include <unistd.h> 16: 17: #include "kvm.h" 18: 19: #include <sys/types.h> 20: #include <sys/param.h> 21: #include <sys/socket.h> 22: #include <sys/socketvar.h> 23: 24: #define KERNEL 25: #include <sys/file.h> 26: #undef KERNEL 27: #include <sys/dir.h> 28: #include <sys/user.h> 29: #include <sys/proc.h> 30: #include <fcntl.h> 31: #include <sys/sysctl.h> 32: 33: #include <netinet/in.h> 34: 35: #include <netinet/in_systm.h> 36: #include <netinet/ip.h> 37: #include <net/route.h> 38: #include <netinet/in_pcb.h> 39: 40: #include "identd.h" 41: #include "error.h" 42: 43: struct nlist nl[] = 44: { 45: #define N_NETDATA 0 46: { "_netdata" }, 47: { "" } 48: }; 49: 50: struct nlist snl[] = 51: { 52: #define SN_TCB 0 53: { "_tcb" }, 54: { "" } 55: }; 56: 57: static off_t netoff; 58: static struct inpcb tcb; 59: static int memfd, swapfd; 60: 61: #ifndef _PATH_MEM 62: #define _PATH_MEM "/dev/mem" 63: #endif 64: 65: #ifndef _PATH_SWAP 66: #define _PATH_SWAP "/dev/swap" 67: #endif 68: 69: #ifndef _PATH_UNIX 70: #define _PATH_UNIX "/unix" 71: #endif 72: 73: #ifndef _PATH_NETNIX 74: #define _PATH_NETNIX "/netnix" 75: #endif 76: 77: static char Msg_open[] = "open %s"; 78: static char Msg_nlist[] = "nlist %s"; 79: static char Msg_sysctl[] = "sysctl %s"; 80: static char Msg_readu[] = "can't read u pid %d"; 81: static char Msg_malloc[] = "malloc(%d)"; 82: static char Swap[] = _PATH_SWAP; 83: static char Netnix[] = _PATH_NETNIX; 84: 85: static struct file *sockp2fp(); 86: static void error(), error1(); 87: 88: int 89: k_open() 90: { 91: u_int netdata; 92: char *p; 93: 94: if (path_kmem) 95: p = path_kmem; 96: else 97: p = _PATH_MEM; 98: memfd = open(p, O_RDONLY); 99: if (memfd < 0) 100: error1(Msg_open, p); 101: 102: swapfd = open(Swap, O_RDONLY); 103: if (swapfd < 0) 104: error1(Msg_open, Swap); 105: 106: if (path_unix) 107: p = path_unix; 108: else 109: p = _PATH_UNIX; 110: if (nlist(p, nl) != 0) 111: error1(Msg_nlist, p); 112: 113: if (nlist(Netnix, snl) != 0) 114: error1(Msg_nlist, Netnix); 115: if (getbuf((off_t)nl[N_NETDATA].n_value, &netdata, sizeof (int), 116: "netdata") == 0) 117: exit(1); 118: 119: netoff = (off_t)ctob((long)netdata); 120: return(0); 121: } 122: 123: /* 124: * Get a piece of kernel memory with error handling. 125: * Returns 1 if call succeeded, else 0 (zero). 126: */ 127: static int 128: getbuf(addr, buf, len, what) 129: off_t addr; 130: char *buf; 131: int len; 132: char *what; 133: { 134: 135: if (lseek(memfd, addr, L_SET) == -1) 136: { 137: if (syslog_flag) 138: syslog(LOG_ERR, "getbuf: lseek %ld - %s: %m",what,addr); 139: return(0); 140: } 141: if (read(memfd, buf, len) != len) 142: { 143: if (syslog_flag) 144: syslog(LOG_ERR, "getbuf: read %d bytes - %s : %m", 145: len, what); 146: return(0); 147: } 148: return(1); 149: } 150: 151: /* 152: * Traverse the inpcb list until a match is found. 153: * Returns NULL if no match. 154: */ 155: static struct socket * 156: getlist(pcbp, faddr, fport, laddr, lport) 157: register struct inpcb *pcbp; 158: register struct in_addr *faddr; 159: int fport; 160: register struct in_addr *laddr; 161: int lport; 162: { 163: struct inpcb *head; 164: 165: if (!pcbp) 166: return(NULL); 167: head = pcbp->inp_prev; 168: do 169: { 170: if (pcbp->inp_faddr.s_addr == faddr->s_addr && 171: pcbp->inp_laddr.s_addr == laddr->s_addr && 172: pcbp->inp_fport == fport && 173: pcbp->inp_lport == lport ) 174: return(pcbp->inp_socket); 175: } while (pcbp->inp_next != head && 176: getbuf((off_t)pcbp->inp_next + netoff, 177: pcbp, sizeof(struct inpcb), "tcblist")); 178: return(NULL); 179: } 180: 181: /* 182: * Return the user number for the connection owner 183: */ 184: int 185: k_getuid(faddr, fport, laddr, lport, uid) 186: struct in_addr *faddr; 187: u_short fport; 188: struct in_addr *laddr; 189: u_short lport; 190: uid_t *uid; 191: { 192: register struct proc *pp; 193: register struct user *up; 194: struct file *fp; 195: struct kinfo_proc *kpp, *xproc, *endproc; 196: struct kinfo_file *xfile, *endfile; 197: struct socket *sockp; 198: register int i; 199: int mib[3], size; 200: struct user uarea; 201: 202: /* -------------------- FILE DESCRIPTOR TABLE -------------------- */ 203: 204: mib[0] = CTL_KERN; 205: mib[1] = KERN_FILE; 206: i = sysctl(mib, 2, NULL, &size, NULL, 0); 207: if (i == -1) 208: error1(Msg_sysctl, "1"); 209: xfile = (struct kinfo_file *) malloc(size); 210: if (!xfile) 211: error1(Msg_malloc, size); 212: i = sysctl(mib, 2, xfile, &size, NULL, 0); 213: if (i == -1) 214: error1(Msg_sysctl, "2"); 215: endfile = &xfile[size / sizeof (struct kinfo_file)]; 216: 217: /* -------------------- TCP PCB LIST -------------------- */ 218: if (!getbuf((off_t)snl[SN_TCB].n_value + netoff, &tcb, 219: sizeof(tcb), "tcb")) 220: { 221: free(xfile); 222: return(-1); 223: } 224: tcb.inp_prev = (struct inpcb *) snl[SN_TCB].n_value; 225: sockp = getlist(&tcb, faddr, fport, laddr, lport); 226: if (!sockp) 227: { 228: free(xfile); 229: return(-1); 230: } 231: /* ------------------- FIND FILE CONTAINING TCP CONTROL BLOCK --------- */ 232: fp = sockp2fp(xfile, endfile, sockp); 233: if (!fp) 234: { 235: free(xfile); 236: return(-1); 237: } 238: 239: /* -------------------- PROCESS TABLE ------------------- */ 240: mib[0] = CTL_KERN; 241: mib[1] = KERN_PROC; 242: mib[2] = KERN_PROC_ALL; 243: i = sysctl(mib, 3, NULL, &size, NULL, 0); 244: if (i == -1) 245: error1(Msg_sysctl, "3"); 246: xproc = (struct kinfo_proc *)malloc(size); 247: if (!xproc) 248: error1(Msg_malloc, size); 249: i = sysctl(mib, 3, xproc, &size, NULL, 0); 250: if (i == -1) 251: error1(Msg_sysctl, "4"); 252: endproc = &xproc[size / sizeof (struct kinfo_proc)]; 253: 254: for (kpp = xproc; kpp < endproc; kpp++) 255: { 256: pp = &kpp->kp_proc; 257: if (pp->p_stat == SZOMB) 258: continue; 259: 260: /* ------------------- GET U_AREA FOR PROCESS ----------------- */ 261: if (pp->p_flag & SLOAD) 262: { 263: if (getbuf(ctob((off_t)pp->p_addr),&uarea, 264: sizeof (uarea), "u") == 0) 265: error1(Msg_readu, pp->p_pid); 266: } 267: else 268: { 269: lseek(swapfd, dbtob((off_t)pp->p_addr), L_SET); 270: i = read(swapfd, &uarea, sizeof (uarea)); 271: if (i != sizeof (uarea)) 272: error1(Msg_readu, pp->p_pid); 273: } 274: up = &uarea; 275: 276: /* ----------------- SCAN PROCESS's FILE TABLE ------------------- */ 277: for (i = up->u_lastfile; i >= 0; i--) 278: { 279: if (up->u_ofile[i] == fp) 280: { 281: *uid = up->u_ruid; 282: free(xproc); 283: free(xfile); 284: return(0); 285: } /* if */ 286: } /* for -- ofiles */ 287: } /* for -- proc */ 288: free(xproc); 289: free(xfile); 290: return -1; 291: } 292: 293: static struct file * 294: sockp2fp(xfile, endfile, sockp) 295: struct kinfo_file *xfile, *endfile; 296: struct socket *sockp; 297: { 298: register struct kinfo_file *kfp; 299: register struct file *fp = NULL; 300: 301: for (kfp = xfile; kfp < endfile; kfp++) 302: { 303: if ((kfp->kp_file.f_type == DTYPE_SOCKET) && 304: (kfp->kp_file.f_data == sockp)) 305: { 306: fp = kfp->kp_filep; 307: break; 308: } 309: } 310: return(fp); 311: } 312: 313: /* 314: * These are helper functions which greatly reduce the bloat caused by 315: * inline expansion of the ERROR and ERROR1 macros (this module went from 316: * about 2700 bytes of code to 1400 bytes!). Those macros _should_ 317: * have been written as variadic functions using vfprintf and vsyslog! 318: * 319: * error1() only accepts single word (int, not long) as a second arg. 320: */ 321: 322: static void 323: error(msg) 324: char *msg; 325: { 326: ERROR(msg); 327: /* NOTREACHED */ 328: } 329: 330: /* ARGSUSED1 */ 331: static void 332: error1(msg, arg2) 333: char *msg; 334: int arg2; 335: { 336: ERROR1(msg, arg2); 337: /* NOTREACHED */ 338: }