pidentd  3.0.19
About: implementation of the RFC1413 identification server (more or less complete rewrite compared to version 2)
  Fossies Dox: pidentd-3.0.19.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

k_sunos54.c
Go to the documentation of this file.
1 /*
2 ** k_sunos54.c - SunOS 5.4 kernel access functions.
3 **
4 ** Copyright (c) 1995-1997 Casper Dik <Casper.Dik@Holland.Sun.COM>
5 ** Copyright (c) 1997-1999 Peter Eriksson <pen@lysator.liu.se>
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it as you wish - as long as you don't claim that you wrote
9 ** it.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 */
15 
16 #include "config.h"
17 
18 #include <syslog.h>
19 
20 #define DEBUGHASH
21 
22 #include "pidentd.h"
23 
24 #define _KMEMUSER
25 #define _KERNEL
26 
27 /* some definition conflicts. but we must define _KERNEL */
28 
29 #define exit kernel_exit
30 #define strsignal kernel_strsignal
31 
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/signal.h>
35 #include <sys/param.h>
36 #include <netinet/in.h>
37 
38 #include <stdio.h>
39 #include <kvm.h>
40 #include <nlist.h>
41 #include <math.h>
42 #include <sys/fcntl.h>
43 #include <sys/cred.h>
44 #include <sys/file.h>
45 #include <sys/stream.h>
46 #include <inet/common.h>
47 #include <inet/ip.h>
48 
49 
50 #define BROKEN_HASH
51 
52 /*
53  * In Solaris 2.4 there have been a number of changes:
54  * - the ipc_s structure had its field names changed
55  * - the file global no longer exists in the kernel.
56  * (this sort of makes sense for MP machines: having to go through
57  * one global lock for all file opens/closes doesn't scale
58  * very well)
59  */
60 
61 #undef exit
62 #undef strsignal
63 
64 #include <unistd.h>
65 #include <string.h>
66 #include <stddef.h>
67 
68 
69 #define N_FANOUT 0
70 #define N_PRACTIVE 1
71 
72 struct kainfo
73 {
74  kvm_t *kd;
75  struct proc *nextp, currentp;
76  struct nlist nl[3];
77 };
78 
79 
80 /*
81 ** Make sure we are running on a supported OS version
82 */
83 int
84 ka_init(void)
85 {
86  char osinfo_current[256];
87 
88  /* The kvm routines are not MT-Safe! */
89  kernel_threads = 1;
90 
91  if (osinfo_get(osinfo_current) == NULL)
92  return -1;
93 
94  return strcmp(osinfo_build, osinfo_current);
95 }
96 
97 
98 /*
99 ** Open kernel devices, lookup kernel symbols etc...
100 */
101 int
102 ka_open(void **misc)
103 {
104  struct kainfo *kp;
105 
106 
107  kp = s_malloc(sizeof(*kp));
108 
109  /*
110  ** Open the kernel memory device
111  */
112  if ((kp->kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
113  {
114  syslog(LOG_ERR, "kvm_open: %m");
115  s_free(kp);
116  return -1;
117  }
118 
119 
120  kp->nl[0].n_name = "ipc_tcp_fanout";
121  kp->nl[1].n_name = "practive";
122  kp->nl[2].n_name = NULL;
123 
124  /*
125  ** Extract offsets to the needed variables in the kernel
126  */
127  if (kvm_nlist(kp->kd, kp->nl) != 0)
128  {
129  syslog(LOG_ERR, "kvm_nlist: %m");
130  kvm_close(kp->kd);
131  s_free(kp);
132  return -1;
133  }
134 
135  *misc = (void *) kp;
136  return 0;
137 }
138 
139 
140 /*
141 ** Get a piece of kernel memory with error handling.
142 ** Returns 1 if call succeeded, else 0 (zero).
143 */
144 static int
146  off_t addr,
147  char *buf,
148  size_t len,
149  char *what)
150 {
151  int i;
152  ssize_t status;
153 
154 
155  i = 0;
156  while (i < 5 && (status = kvm_read(kd, addr, buf, len)) < 0)
157  ++i;
158 
159  if (status < 0)
160  {
161  syslog(LOG_DEBUG, "kvm_read(\"%s\", %lx, %lu): %m", what, addr, len);
162  return 0;
163  }
164 
165  return 1;
166 }
167 
168 
169 
170 
171 /* Work around for Solaris 2.x bug in kvm_setproc,
172  * kvm_setproc doesn't reread practive */
173 
174 static int
175 xkvm_setproc (struct kainfo *kp)
176 {
177  if (!getbuf(kp->kd,
178  (off_t) kp->nl[N_PRACTIVE].n_value,
179  (char *) &kp->nextp,
180  sizeof(kp->nextp),
181  "practive"))
182  return -1;
183 
184  return 0;
185 }
186 
187 static struct proc *
189 {
190  if (!getbuf(kp->kd,
191  (off_t) kp->nextp,
192  (char*) &kp->currentp,
193  sizeof(kp->currentp),
194  "kvm_nextproc"))
195  return 0;
196 
197  kp->nextp = kp->currentp.p_next;
198  return &kp->currentp;
199 }
200 
201 /*
202 ** Return the user number for the connection owner
203 */
204 int
205 ka_lookup(void *vp, struct kernel *kp)
206 {
207  struct kainfo *kip;
208 
209  struct in_addr *faddr;
210  int fport;
211  struct in_addr *laddr;
212  int lport;
213 
214  queue_t sqr;
215  ipc_t ic, *icp;
216  unsigned short uslp, usfp;
217  unsigned int offset;
218  file_t tf;
219  unsigned long zero = 0;
220  u16 *ports;
221  u32 *locaddr, *raddr;
222 #ifdef DEBUGHASH
223  int i;
224 #endif
225  struct proc *procp;
226 #ifdef BROKEN_HASH
227  ipc_t *alticp = 0;
228  unsigned int altoffset;
229 #endif
230 
231  kip = (struct kainfo *) vp;
232 
233  faddr = &kp->remote.sin_addr;
234  laddr = &kp->local.sin_addr;
235  fport = kp->remote.sin_port;
236  lport = kp->local.sin_port;
237 
238  usfp = fport;
239  uslp = lport;
240 
241  if (debug)
242  fprintf(stderr, "Scanning for %d:%d\n", fport, lport);
243 
244 #ifdef BROKEN_HASH
245  /* code used (ports > 8) instead of (ports >> 8)
246  low byte of local port number not used, low byte of
247  local addres is used
248  ip_bind in the kernel (+ approx 0x4c0)
249  srl %i3, 0x18, %o0
250  xor %i2, %o0, %o0
251  srl %i3, 0x10, %o1
252  xor %o0, %o1, %o0
253  xor %o0, %l0, %o0
254  xor %o0, %i3, %o0
255  and %o0, 0xff, %o0
256  sethi %hi(0xfc1d9c00), %o2
257  or %o2, 0x1c0, %o2 ! ipc_tcp_fanout
258 
259  */
260 #if (defined(BIG_ENDIAN) || defined(_BIG_ENDIAN))
261  altoffset = usfp >> 8;
262 #else
263  altoffset = uslp >> 8;
264 #endif
265  altoffset ^= usfp ^ uslp;
266  altoffset ^= faddr->S_un.S_un_b.s_b4;
267  if (uslp > 8 || usfp != 0)
268  altoffset ^= 1;
269  altoffset &= 0xff;
270  if (!getbuf(kip->kd,
271  (off_t) kip->nl[N_FANOUT].n_value + sizeof(ipc_t *) * altoffset,
272  (char *) &alticp,
273  sizeof(ipc_t *),
274  "ipc_tcp_fanout[altoffset]"))
275  alticp = NULL;
276 #endif
277 
278  offset = usfp ^ uslp;
279  offset ^= (unsigned) faddr->S_un.S_un_b.s_b4 ^ (offset >> 8);
280  offset &= 0xff;
281 
282  if (!getbuf(kip->kd, (off_t) kip->nl[N_FANOUT].n_value + sizeof(ipc_t *) * offset,
283  (char *) &icp,
284  sizeof(ipc_t *),
285  "ipc_tcp_fanout[offset]"))
286  return -1;
287 
288 #ifdef BROKEN_HASH
289  if (icp == NULL && alticp != NULL) {
290  icp = alticp;
291  alticp = NULL;
292  }
293 #endif
294 #ifndef DEBUGHASH
295  if (icp == 0) {
296  syslog(LOG_DEBUG, "ka_lookup: hash miss");
297  return -1;
298  }
299 #endif
300 
301  locaddr = &ic.ipc_tcp_laddr;
302  raddr = &ic.ipc_tcp_faddr;
303  ports = (u16 *) &ic.ipc_tcp_ports;
304 
305 #ifdef DEBUGHASH
306  for (i = 0; i < 256; i++) {
307  if (!getbuf(kip->kd,
308  (off_t) kip->nl[N_FANOUT].n_value + sizeof(ipc_t *) * i,
309  (char *) &icp,
310  sizeof(ipc_t *),
311  "ipc_tcp_fanout[offset]"))
312  return -1;
313  if (icp == NULL)
314  continue;
315 #endif
316 
317  while (icp != NULL) {
318  if (!getbuf(kip->kd,
319  (off_t) icp,
320  (char *) &ic,
321  sizeof(ic),
322  "hash entry"))
323  return -1;
324 
325  if (usfp == ports[0] && /* remote port */
326  uslp == ports[1] && /* local port */
327 #if 0
328  memcmp(&laddr->s_addr, locaddr, 4) == 0 && /* local */
329 #else
330  (memcmp(&laddr->s_addr, locaddr, 4) == 0 ||
331  /* In SunOS 5.3, the local part can be all zeros */
332  memcmp(&zero, locaddr, 4) == 0) /* local */ &&
333 #endif
334  memcmp(&faddr->s_addr, raddr, 4) == 0)
335  break;
336  icp = ic.ipc_hash_next;
337 #ifdef BROKEN_HASH
338  if (icp == NULL && alticp != NULL) {
339  icp = alticp;
340  alticp = NULL;
341  }
342 #endif
343  }
344 #ifdef DEBUGHASH
345  if (icp != NULL)
346  break;
347  } /* for i */
348  if (icp != NULL && debug)
349  fprintf(stderr,
350  "found, offset = %x, i = %x, i ^ offset = %x\n", offset, i,
351  offset ^ i);
352 #endif
353 
354  if (icp == NULL) {
355  syslog(LOG_INFO, "ka_lookup: port not found");
356  return -1;
357  }
358 
359  if (!getbuf(kip->kd,
360  (off_t) ic.ipc_rq+offsetof(queue_t, q_stream),
361  (char *) &sqr.q_stream,
362  sizeof(sqr.q_stream),
363  "queue.q_stream"))
364  return -1;
365 
366  /* at this point sqr.q_stream holds the pointer to the stream we're
367  interested in. Now we're going to find the file pointer
368  that refers to the vnode that refers to this stream stream */
369 
370  /* Solaris 2.4 no longer links all file pointers together with
371  * f_next, the only way seems to be scrounging them from
372  * the proc/user structure, ugh.
373  */
374 
375  if (xkvm_setproc(kip) != 0)
376  {
377  syslog(LOG_ERR, "kvm_setproc(): %m");
378  return -1;
379  }
380 
381  while ((procp = xkvm_nextproc(kip)) != NULL)
382  {
383  struct uf_entry files[NFPCHUNK];
384  int nfiles = procp->p_user.u_nofiles;
385  off_t addr = (off_t) procp->p_user.u_flist;
386 
387  while (nfiles > 0) {
388  int nread = nfiles > NFPCHUNK ? NFPCHUNK : nfiles;
389  int size = nread * sizeof(struct uf_entry);
390  int i;
391  struct file *last = 0;
392  vnode_t vp;
393 
394  if (!getbuf(kip->kd, addr, (char*) &files[0], size, "ufentries"))
395  return -1;
396 
397  for (i = 0; i < nread; i++) {
398  if (files[i].uf_ofile == 0 || files[i].uf_ofile == last)
399  continue;
400  if (!getbuf(kip->kd,(unsigned long) (last = files[i].uf_ofile),
401  (char *) &tf, sizeof(tf), "file pointer")) {
402  return -1;
403  }
404 
405  if (tf.f_vnode == NULL)
406  continue;
407 
408  if (!getbuf(kip->kd,
409  (off_t) tf.f_vnode + offsetof(vnode_t,v_stream),
410  (char *) &vp.v_stream,
411  sizeof(vp.v_stream),
412  "vnode.v_stream"))
413  return -1;
414 
415  if (vp.v_stream == sqr.q_stream)
416  {
417  cred_t cr;
418  struct pid p;
419 
420  if (!getbuf(kip->kd,
421  (off_t) tf.f_cred,
422  (char *) &cr,
423  sizeof(cr),
424  "cred"))
425  return -1;
426 
427  kp->ruid = cr.cr_ruid;
428  kp->euid = cr.cr_uid;
429 
430  if (getbuf(kip->kd,
431  (off_t) procp->p_pidp,
432  (char *) &p,
433  sizeof(struct pid),
434  "pidp"))
435  {
436  kp->pid = p.pid_id;
437  /* get cmd */
438  kp->cmd = s_strdup(procp->p_user.u_comm);
439  /* get cmd args */
440  kp->argv = s_strdup(procp->p_user.u_psargs);
441  }
442 
443  return 1;
444  }
445  }
446  nfiles -= nread;
447  addr += size;
448  }
449  }
450 
451  return -1;
452 }
s_free
void s_free(void *p)
Definition: safeio.c:153
s_strdup
char * s_strdup(const char *s)
Definition: safeio.c:161
kainfo
Definition: k_aix42.c:73
N_PRACTIVE
#define N_PRACTIVE
Definition: k_sunos54.c:70
ka_init
int ka_init(void)
Definition: k_sunos54.c:84
kvm_nlist
int kvm_nlist(kvm_t *kd, struct nlist *nl)
xkvm_setproc
static int xkvm_setproc(struct kainfo *kp)
Definition: k_sunos54.c:175
pidentd.h
kernel::remote
struct sockaddr_gen remote
Definition: kernel.h:29
kvm_t
Definition: pkvm.h:18
kainfo::kd
int kd
Definition: k_aix42.c:75
kernel::local
struct sockaddr_gen local
Definition: kernel.h:28
kernel_threads
int kernel_threads
Definition: kernel.c:34
ka_lookup
int ka_lookup(void *vp, struct kernel *kp)
Definition: k_sunos54.c:205
s_malloc
void * s_malloc(size_t size)
Definition: safeio.c:132
ka_open
int ka_open(void **misc)
Definition: k_sunos54.c:102
xkvm_nextproc
static struct proc * xkvm_nextproc(struct kainfo *kp)
Definition: k_sunos54.c:188
uf_ofile
#define uf_ofile
N_FANOUT
#define N_FANOUT
Definition: k_sunos54.c:69
kernel::euid
uid_t euid
Definition: kernel.h:35
kvm_close
int kvm_close(kvm_t *kd)
osinfo_get
char * osinfo_get(char *buf)
Definition: support.c:39
kvm_open
kvm_t * kvm_open(const char *namelist, const char *corefile, const char *swapfile, int flag, const char *errstr)
debug
int debug
Definition: gen_osinfo.c:23
kernel::ruid
uid_t ruid
Definition: kernel.h:36
DEBUGHASH
#define DEBUGHASH
Definition: k_sunos54.c:20
kernel::pid
pid_t pid
Definition: kernel.h:38
kernel::cmd
char * cmd
Definition: kernel.h:39
kernel::argv
char * argv
Definition: kernel.h:40
getbuf
static int getbuf(kvm_t *kd, off_t addr, char *buf, size_t len, char *what)
Definition: k_sunos54.c:145
osinfo_build
char osinfo_build[]
kainfo::nextp
struct proc * nextp
Definition: k_sunos54.c:75
kernel
Definition: kernel.h:25
kvm_read
ssize_t kvm_read(kvm_t *kd, off_t addr, void *buf, size_t len)
kainfo::nl
struct nlist nl[4]
Definition: k_bsd42.c:74
kainfo::currentp
struct proc currentp
Definition: k_sunos54.c:75