"Fossies" - the Fresh Open Source Software Archive

Member "pidentd-3.0.19/src/k_sunos54.c" (10 Aug 1999, 9571 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_sunos54.c" see the Fossies "Dox" file reference documentation.

    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
  145 getbuf(kvm_t *kd,
  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 *
  188 xkvm_nextproc(struct kainfo *kp)
  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 }