"Fossies" - the Fresh Open Source Software Archive

Member "pidentd-3.0.19/src/k_sunos58.c" (13 Jun 2004, 9171 Bytes) of package /linux/misc/old/pidentd-3.0.19.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "k_sunos58.c" see the Fossies "Dox" file reference documentation.

    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;
  107     int hash_size;
  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 }