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_sunos58.c
Go to the documentation of this file.
1 /*
2 ** k_sunos58.c - SunOS 5.8 kernel access functions
3 **
4 ** Copyright (c) 1995-1999 Casper Dik <Casper.Dik@Holland.Sun.COM>
5 ** Copyright (c) 1997 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 ** For now, only support IPv4 for Solaris 8
16 */
17 
18 #include "config.h"
19 
20 #include <unistd.h>
21 #include <string.h>
22 #include <stddef.h>
23 
24 #include <stdio.h>
25 #include <nlist.h>
26 #include <math.h>
27 
28 #if 0
29 #define DEBUGHASH
30 #endif
31 
32 #define _KMEMUSER
33 #define _KERNEL
34 
35 #include <kvm.h>
36 
37 /* some definition conflicts. but we must define _KERNEL */
38 
39 #define exit kernel_exit
40 #define strsignal kernel_strsignal
41 #define mutex_init kernel_mutex_init
42 #define mutex_destroy kernel_mutex_destroy
43 #define sema_init kernel_sema_init
44 #define sema_destroy kernel_sema_destroy
45 
46 #include <syslog.h>
47 
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <sys/signal.h>
51 #include <sys/param.h>
52 #include <netinet/in.h>
53 
54 #include <sys/fcntl.h>
55 #include <sys/cred.h>
56 #include <sys/file.h>
57 #include <sys/stream.h>
58 #include <sys/dlpi.h>
59 #include <net/if_types.h>
60 #include <inet/common.h>
61 #include <netinet/ip6.h>
62 #include <inet/ip.h>
63 #include <inet/tcp.h>
64 #include <netinet/ip6.h>
65 #include <net/if.h>
66 
67 #if !defined(IN6_V4_MAPPED_TO_INADDR)
68 
69 #define IPv6_2_IPv4(v6, v4) \
70  ((v4)->s_addr = *((uint32_t *) \
71  (((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12)))
72 
73 #else /* defined(IN6_V4_MAPPED_TO_INADDR) */
74 
75 #define IPv6_2_IPv4(v6, v4) IN6_V4MAPPED_TO_INADDR((struct in6_addr *)v6, v4)
76 
77 #endif /* defined(IN6_V4MAPPED_TO_INADDR) */
78 
79 typedef struct hashentry {
80  tcpb_t *he_tcp;
81  kmutex_t he_lock;
82 } he_t;
83 
84 #define FANOUT_OFFSET(n) (kip->hash_table + (n) * sizeof(he_t) + offsetof(he_t, he_tcp))
85 
86 #undef exit
87 #undef strsignal
88 #undef mutex_init
89 #undef mutex_destroy
90 #undef sema_init
91 #undef sema_destroy
92 
93 #undef SEMA_HELD
94 #undef RW_LOCK_HELD
95 #undef RW_READ_HELD
96 #undef RW_WRITE_HELD
97 #undef MUTEX_HELD
98 
99 #include "pidentd.h"
100 
101 #define N_FANOUT 0
102 #define N_HASH_SIZE 1
103 
104 struct kainfo
105 {
106  kvm_t *kd;
108  unsigned long hash_table;
109  struct nlist nl[3];
110 };
111 
112 
113 /*
114 ** Make sure we are running on a supported OS version
115 */
116 int
117 ka_init(void)
118 {
119  char osinfo_current[256];
120 
121  if (osinfo_get(osinfo_current) == NULL)
122  return -1;
123 
124  return strcmp(osinfo_build, osinfo_current);
125 }
126 
127 
128 /*
129 ** Get a piece of kernel memory with error handling.
130 ** Returns 1 if call succeeded, else 0 (zero).
131 */
132 static int
133 getbuf(kvm_t *kd, off_t addr, char *buf, size_t len, char *what)
134 {
135  int i;
136  ssize_t status;
137 
138 
139  i = 0;
140  while (i < 5 && (status = kvm_read(kd, addr, buf, len)) < 0)
141  ++i;
142 
143  if (status < 0)
144  return 0;
145 
146  return 1;
147 }
148 
149 
150 /*
151 ** Open kernel devices, lookup kernel symbols etc...
152 */
153 int
154 ka_open(void **misc)
155 {
156  struct kainfo *kp;
157 
158 
159  kp = s_malloc(sizeof(*kp));
160 
161  /*
162  ** Open the kernel memory device
163  */
164  if ((kp->kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
165  {
166  syslog(LOG_ERR, "kvm_open: %m");
167  s_free(kp);
168  return -1;
169  }
170 
171 
172  kp->nl[0].n_name = "tcp_conn_fanout";
173  kp->nl[1].n_name = "tcp_conn_hash_size";
174  kp->nl[2].n_name = NULL;
175 
176  /*
177  ** Extract offsets to the needed variables in the kernel
178  */
179  if (kvm_nlist(kp->kd, kp->nl) != 0)
180  {
181  syslog(LOG_ERR, "kvm_nlist: %m");
182  kvm_close(kp->kd);
183  s_free(kp);
184  return -1;
185  }
186 
187  /*
188  * Read the two kernel values we need but won't change
189  */
190  if (!getbuf(kp->kd, kp->nl[N_HASH_SIZE].n_value, (char *) &kp->hash_size,
191  sizeof(kp->hash_size), kp->nl[N_HASH_SIZE].n_name) ||
192  !getbuf(kp->kd, kp->nl[N_FANOUT].n_value, (char *) &kp->hash_table,
193  sizeof(kp->hash_table), kp->nl[N_FANOUT].n_name)) {
194  kvm_close(kp->kd);
195  s_free(kp);
196  syslog(LOG_ERR, "getbuf: can't get needed symbols");
197  return -1;
198  }
199 
200  *misc = (void *) kp;
201  return 0;
202 }
203 
204 
205 /*
206 ** Return the user number for the connection owner
207 */
208 int
209 ka_lookup(void *vp, struct kernel *kp)
210 {
211  struct kainfo *kip;
212  ipc_t ic, *icp;
213  unsigned short uslp, usfp;
214  unsigned int offset;
215  file_t tf;
216  unsigned long zero = 0;
217  uint16_t *ports;
218  uint32_t *locaddr, *raddr;
219 #ifdef DEBUGHASH
220  int i;
221 #endif
222  struct proc *procp;
223  char *faddr;
224  int fport;
225  char *laddr;
226  int lport;
227  struct stdata *std;
228  tcpb_t *tcpb;
229  queue_t *q;
230  tcpb_t tb;
231  char *iphash;
232 
233  kip = (struct kainfo *) vp;
234 
235  faddr = (char *) SGADDRP(kp->remote);
236  laddr = (char *) SGADDRP(kp->local);
237  fport = SGPORT(kp->remote);
238  lport = SGPORT(kp->local);
239 
240  /* XXX: the V4_PART macros don't work and port to well to this */
241  iphash = SGFAM(kp->remote) == AF_INET ? faddr : faddr + 12;
242 
243  usfp = fport;
244  uslp = lport;
245 
246  /*
247  * All tcp connections are in one single hash table; IPV4 connections
248  * over AF_INET6 sockets do not show up in the normal tcp hash tables
249  *
250  * First we need to find the hash entry in the tcp table;
251  * then we need to follow the chain and get the TCP entry.
252  *
253  * In Solaris 8, the tcp structure is split in two: the core part
254  * needed in TIME_WAIT state and the full structure.
255  */
256 
257 #define GETBYTE(x,n) ((unsigned)(((unsigned char*)&x)[n]))
258  offset = GETBYTE(*iphash,3) ^ GETBYTE(usfp,0) ^ GETBYTE(usfp,1) ^
259  GETBYTE(uslp,0) ^ GETBYTE(uslp,1) ^
260  ((GETBYTE(usfp,0) ^ GETBYTE(uslp,0) ^ GETBYTE(*iphash,2)) << 10) ^
261  (GETBYTE(*iphash,1) << 6);
262 
263  offset %= kip->hash_size;
264 
265  if (!getbuf(kip->kd, FANOUT_OFFSET(offset), (char*) &tcpb, sizeof(tcpb),
266  "tcp_conn_fanout[hash]"))
267  return -1;
268 
269  if (tcpb == NULL) {
270  syslog(LOG_DEBUG, "k_getuid: tcp hash miss");
271  return -1;
272  }
273 
274  while (tcpb != NULL) {
275 
276  if (!getbuf(kip->kd, (unsigned long) tcpb, (char *) &tb, sizeof(tb),
277  "struct tcp"))
278  return -1;
279 
280  if (uslp == tb.tcpb_lport && usfp == tb.tcpb_fport) {
281  if (SGFAM(kp->remote) == AF_INET) {
282  struct in_addr fv4, lv4;
283  IPv6_2_IPv4(&tb.tcpb_ip_src_v6, &lv4);
284  IPv6_2_IPv4(&tb.tcpb_remote_v6, &fv4);
285  if (memcmp(&lv4, laddr, 4) == 0 && memcmp(&fv4, faddr, 4) == 0)
286  break;
287  } else if (memcmp(&tb.tcpb_ip_src_v6, laddr, SGSIZE(kp->local))
288  == 0 &&
289  memcmp(&tb.tcpb_remote_v6, faddr, SGSIZE(kp->remote))
290  == 0) {
291  break;
292  }
293  }
294 
295  tcpb = tb.tcpb_conn_hash;
296  }
297 
298  if (tcpb == NULL)
299  return -1;
300 
301  if (!getbuf(kip->kd, (unsigned long) tb.tcpb_tcp + offsetof(tcp_t, tcp_rq),
302  (char *) &q, sizeof(q), "queue *"))
303  return -1;
304 
305  if (!getbuf(kip->kd, (unsigned long) q + offsetof(queue_t, q_stream),
306  (char *) &std, sizeof(std), "tcp_rq->q_stream"))
307  return -1;
308 
309  /* at this point std holds the pointer to the stream we're
310  interested in. Now we're going to find the file pointer
311  that refers to the vnode that refers to this stream stream */
312 
313  if (kvm_setproc(kip->kd) != 0)
314  return -1;
315 
316 
317  /*
318  * In Solaris 8, the file lists changed dramatically.
319  * There's no longer an NFPCHUNK; the uf_entries are
320  * part of a seperate structure inside user.
321  */
322 #define NFPREAD 64
323 
324 #ifndef NFPCHUNK
325 #define uf_ofile uf_file
326 #define u_flist u_finfo.fi_list
327 #define u_nofiles u_finfo.fi_nfiles
328 #endif
329 
330  while ((procp = kvm_nextproc(kip->kd)) != NULL)
331  {
332  struct uf_entry files[NFPREAD];
333  int nfiles = procp->p_user.u_nofiles;
334  off_t addr = (off_t) procp->p_user.u_flist;
335 
336  while (nfiles > 0)
337  {
338  int nread = nfiles > NFPREAD ? NFPREAD : nfiles;
339  int size = nread * sizeof(struct uf_entry);
340  int i;
341  struct file *last = NULL;
342  vnode_t vp;
343 
344  if (!getbuf(kip->kd, addr, (char *) &files[0], size, "ufentries"))
345  {
346  return -1;
347  }
348 
349  for (i = 0; i < nread; i++)
350  {
351  if (files[i].uf_ofile == 0 || files[i].uf_ofile == last)
352  continue;
353  if (!getbuf(kip->kd, (off_t) (last = files[i].uf_ofile),
354  (char *) &tf, sizeof(tf), "file pointer"))
355  {
356  return -1;
357  }
358 
359  if (tf.f_vnode == NULL)
360  continue;
361 
362  if (!getbuf(kip->kd, (off_t) tf.f_vnode +
363  offsetof(vnode_t, v_stream),
364  (char *) &vp.v_stream,
365  sizeof(vp.v_stream), "vnode.v_stream"))
366  return -1;
367 
368  if (vp.v_stream == std)
369  {
370  cred_t cr;
371  struct pid p;
372 
373  if (!getbuf(kip->kd,
374  (off_t) tf.f_cred,
375  (char *) &cr,
376  sizeof(cr),
377  "cred"))
378  return -1;
379 
380  kp->ruid = cr.cr_ruid;
381  kp->euid = cr.cr_uid;
382 
383  if (getbuf(kip->kd,
384  (off_t) procp->p_pidp,
385  (char *) &p,
386  sizeof(struct pid),
387  "pidp"))
388  {
389  kp->pid = p.pid_id;
390  /* get cmd */
391  kp->cmd = s_strdup(procp->p_user.u_comm);
392  /* get cmd args */
393  kp->argv = s_strdup(procp->p_user.u_psargs);
394  }
395 
396  return 1;
397  }
398  }
399  nfiles -= nread;
400  addr += size;
401  }
402  }
403 
404  return 0;
405 }
SGPORT
#define SGPORT(sag)
Definition: sockaddr.h:57
s_free
void s_free(void *p)
Definition: safeio.c:153
s_strdup
char * s_strdup(const char *s)
Definition: safeio.c:161
IPv6_2_IPv4
#define IPv6_2_IPv4(v6, v4)
Definition: k_sunos58.c:69
kainfo
Definition: k_aix42.c:73
hashentry::he_tcp
tcpb_t * he_tcp
Definition: k_sunos58.c:80
kvm_nlist
int kvm_nlist(kvm_t *kd, struct nlist *nl)
pidentd.h
kernel::remote
struct sockaddr_gen remote
Definition: kernel.h:29
N_FANOUT
#define N_FANOUT
Definition: k_sunos58.c:101
kvm_t
Definition: pkvm.h:18
FANOUT_OFFSET
#define FANOUT_OFFSET(n)
Definition: k_sunos58.c:84
kainfo::hash_size
uint_t hash_size
Definition: k_sunos510.c:108
kainfo::kd
int kd
Definition: k_aix42.c:75
kainfo::hash_size
int hash_size
Definition: k_sunos58.c:107
kernel::local
struct sockaddr_gen local
Definition: kernel.h:28
s_malloc
void * s_malloc(size_t size)
Definition: safeio.c:132
NFPREAD
#define NFPREAD
hashentry
Definition: k_sunos58.c:79
uf_ofile
#define uf_ofile
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)
kernel::ruid
uid_t ruid
Definition: kernel.h:36
kainfo::hash_table
unsigned long hash_table
Definition: k_sunos510.c:109
ka_lookup
int ka_lookup(void *vp, struct kernel *kp)
Definition: k_sunos58.c:209
ka_open
int ka_open(void **misc)
Definition: k_sunos58.c:154
SGFAM
#define SGFAM(sag)
Definition: sockaddr.h:54
getbuf
static int getbuf(kvm_t *kd, off_t addr, char *buf, size_t len, char *what)
Definition: k_sunos58.c:133
kernel::pid
pid_t pid
Definition: kernel.h:38
kernel::cmd
char * cmd
Definition: kernel.h:39
SGADDRP
#define SGADDRP(sag)
Definition: sockaddr.h:58
kernel::argv
char * argv
Definition: kernel.h:40
he_t
struct hashentry he_t
N_HASH_SIZE
#define N_HASH_SIZE
Definition: k_sunos58.c:102
hashentry::he_lock
kmutex_t he_lock
Definition: k_sunos58.c:81
GETBYTE
#define GETBYTE(x, n)
osinfo_build
char osinfo_build[]
kernel
Definition: kernel.h:25
SGSIZE
#define SGSIZE(sag)
Definition: sockaddr.h:55
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
ka_init
int ka_init(void)
Definition: k_sunos58.c:117