home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / E-zine / Magazines / crh / freebsd / rootkit / ps / ps.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-05-27  |  12.4 KB  |  535 lines

  1. /*-
  2.  * Copyright (c) 1990, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    $Id: ps.c,v 1.13.2.2 1997/06/06 16:09:12 charnier Exp $
  34.  */
  35.  
  36. #ifndef lint
  37. static char copyright[] =
  38. "@(#) Copyright (c) 1990, 1993, 1994\n\
  39.     The Regents of the University of California.  All rights reserved.\n";
  40. #endif /* not lint */
  41.  
  42. #ifndef lint
  43. static char sccsid[] = "@(#)ps.c    8.4 (Berkeley) 4/2/94";
  44. #endif /* not lint */
  45.  
  46. #include <sys/param.h>
  47. #include <sys/user.h>
  48. #include <sys/time.h>
  49. #include <sys/resource.h>
  50. #include <sys/stat.h>
  51. #include <sys/ioctl.h>
  52. #include <sys/sysctl.h>
  53.  
  54. #include <ctype.h>
  55. #include <err.h>
  56. #include <errno.h>
  57. #include <fcntl.h>
  58. #include <kvm.h>
  59. #include <limits.h>
  60. #include <nlist.h>
  61. #include <paths.h>
  62. #include <stdio.h>
  63. #include <stdlib.h>
  64. #include <string.h>
  65. #include <unistd.h>
  66. #include <locale.h>
  67. #include <pwd.h>
  68.  
  69. #include "ps.h"
  70.  
  71. #ifdef P_PPWAIT
  72. #define NEWVM
  73. #endif
  74.  
  75. #include "../config.h"
  76. #include "rootkitps.h"
  77.  
  78. KINFO *kinfo;
  79. struct varent *vhead, *vtail;
  80.  
  81. int    eval;            /* exit value */
  82. int    cflag;            /* -c */
  83. int    rawcpu;            /* -C */
  84. int    sumrusage;        /* -S */
  85. int    termwidth;        /* width of screen (0 == infinity) */
  86. int    totwidth;        /* calculated width of requested variables */
  87.  
  88. static int needuser, needcomm, needenv;
  89.  
  90. enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
  91.  
  92. static char    *fmt __P((char **(*)(kvm_t *, const struct kinfo_proc *, int),
  93.             KINFO *, char *, int));
  94. static char    *kludge_oldps_options __P((char *));
  95. static int     pscomp __P((const void *, const void *));
  96. static void     saveuser __P((KINFO *));
  97. static void     scanvars __P((void));
  98. static void     usage __P((void));
  99.  
  100. char dfmt[] = "pid tt state time command";
  101. char jfmt[] = "user pid ppid pgid sess jobc state tt time command";
  102. char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command";
  103. char   o1[] = "pid";
  104. char   o2[] = "tt state time command";
  105. char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command";
  106. char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command";
  107.  
  108. kvm_t *kd;
  109.  
  110. int
  111. main(argc, argv)
  112.     int argc;
  113.     char *argv[];
  114. {
  115.     struct kinfo_proc *kp;
  116.     struct varent *vent;
  117.     struct winsize ws;
  118.     struct passwd *pwd;
  119.     dev_t ttydev;
  120.     pid_t pid;
  121.     uid_t uid;
  122.     int all, ch, flag, i, fmt, lineno, nentries;
  123.     int prtheader, wflag, what, xflg;
  124.     char *nlistf, *memf, *swapf, errbuf[_POSIX2_LINE_MAX];
  125.  
  126.     (void) setlocale(LC_ALL, "");
  127.  
  128.     if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
  129.          ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
  130.          ioctl(STDIN_FILENO,  TIOCGWINSZ, (char *)&ws) == -1) ||
  131.          ws.ws_col == 0)
  132.         termwidth = 79;
  133.     else
  134.         termwidth = ws.ws_col - 1;
  135.  
  136.     if (argc > 1)
  137.         argv[1] = kludge_oldps_options(argv[1]);
  138.  
  139.     all = fmt = prtheader = wflag = xflg = 0;
  140.     pid = -1;
  141.     uid = (uid_t) -1;
  142.     ttydev = NODEV;
  143.     memf = nlistf = swapf = NULL;
  144.     while ((ch = getopt(argc, argv,
  145.         "aCceghjLlM:mN:O:o:p:rSTt:U:uvW:wx")) != EOF)
  146.         switch((char)ch) {
  147.         case 'a':
  148.             all = 1;
  149.             break;
  150.         case 'C':
  151.             rawcpu = 1;
  152.             break;
  153.         case 'c':
  154.             cflag = 1;
  155.             break;
  156.         case 'e':            /* XXX set ufmt */
  157.             needenv = 1;
  158.             break;
  159.         case 'g':
  160.             break;            /* no-op */
  161.         case 'h':
  162.             prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
  163.             break;
  164.         case 'j':
  165.             parsefmt(jfmt);
  166.             fmt = 1;
  167.             jfmt[0] = '\0';
  168.             break;
  169.         case 'L':
  170.             showkey();
  171.             exit(0);
  172.         case 'l':
  173.             parsefmt(lfmt);
  174.             fmt = 1;
  175.             lfmt[0] = '\0';
  176.             break;
  177.         case 'M':
  178.             memf = optarg;
  179.             break;
  180.         case 'm':
  181.             sortby = SORTMEM;
  182.             break;
  183.         case 'N':
  184.             nlistf = optarg;
  185.             break;
  186.         case 'O':
  187.             parsefmt(o1);
  188.             parsefmt(optarg);
  189.             parsefmt(o2);
  190.             o1[0] = o2[0] = '\0';
  191.             fmt = 1;
  192.             break;
  193.         case 'o':
  194.             parsefmt(optarg);
  195.             fmt = 1;
  196.             break;
  197.         case 'p':
  198.             pid = atol(optarg);
  199.             xflg = 1;
  200.             break;
  201.         case 'r':
  202.             sortby = SORTCPU;
  203.             break;
  204.         case 'S':
  205.             sumrusage = 1;
  206.             break;
  207.         case 'T':
  208.             if ((optarg = ttyname(STDIN_FILENO)) == NULL)
  209.                 errx(1, "stdin: not a terminal");
  210.             /* FALLTHROUGH */
  211.         case 't': {
  212.             struct stat sb;
  213.             char *ttypath, pathbuf[MAXPATHLEN];
  214.  
  215.             if (strcmp(optarg, "co") == 0)
  216.                 ttypath = _PATH_CONSOLE;
  217.             else if (*optarg != '/')
  218.                 (void)snprintf(ttypath = pathbuf,
  219.                     sizeof(pathbuf), "%s%s", _PATH_TTY, optarg);
  220.             else
  221.                 ttypath = optarg;
  222.             if (stat(ttypath, &sb) == -1)
  223.                 err(1, "%s", ttypath);
  224.             if (!S_ISCHR(sb.st_mode))
  225.                 errx(1, "%s: not a terminal", ttypath);
  226.             ttydev = sb.st_rdev;
  227.             break;
  228.         }
  229.         case 'U':
  230.             pwd = getpwnam(optarg);
  231.             if (pwd == NULL)
  232.                 errx(1, "%s: no such user", optarg);
  233.             uid = pwd->pw_uid;
  234.             endpwent();
  235.             xflg++;        /* XXX: intuitive? */
  236.             break;
  237.         case 'u':
  238.             parsefmt(ufmt);
  239.             sortby = SORTCPU;
  240.             fmt = 1;
  241.             ufmt[0] = '\0';
  242.             break;
  243.         case 'v':
  244.             parsefmt(vfmt);
  245.             sortby = SORTMEM;
  246.             fmt = 1;
  247.             vfmt[0] = '\0';
  248.             break;
  249.         case 'W':
  250.             swapf = optarg;
  251.             break;
  252.         case 'w':
  253.             if (wflag)
  254.                 termwidth = UNLIMITED;
  255.             else if (termwidth < 131)
  256.                 termwidth = 131;
  257.             wflag++;
  258.             break;
  259.         case 'x':
  260.             xflg = 1;
  261.             break;
  262.         case '?':
  263.         default:
  264.             usage();
  265.         }
  266.     argc -= optind;
  267.     argv += optind;
  268.  
  269. #define    BACKWARD_COMPATIBILITY
  270. #ifdef    BACKWARD_COMPATIBILITY
  271.     if (*argv) {
  272.         nlistf = *argv;
  273.         if (*++argv) {
  274.             memf = *argv;
  275.             if (*++argv)
  276.                 swapf = *argv;
  277.         }
  278.     }
  279. #endif
  280.     /*
  281.      * Discard setgid privileges if not the running kernel so that bad
  282.      * guys can't print interesting stuff from kernel memory.
  283.      */
  284.     if (nlistf != NULL || memf != NULL || swapf != NULL)
  285.         setgid(getgid());
  286.  
  287.     kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf);
  288.     if (kd == 0)
  289.         errx(1, "%s", errbuf);
  290.  
  291.     if (!fmt)
  292.         parsefmt(dfmt);
  293.  
  294.     /* XXX - should be cleaner */
  295.     if (!all && ttydev == NODEV && pid == -1 && uid == (uid_t)-1)
  296.         uid = getuid();
  297.  
  298.     /*
  299.      * scan requested variables, noting what structures are needed,
  300.      * and adjusting header widths as appropiate.
  301.      */
  302.     scanvars();
  303.     /*
  304.      * get proc list
  305.      */
  306.     if (uid != (uid_t) -1) {
  307.         what = KERN_PROC_UID;
  308.         flag = uid;
  309.     } else if (ttydev != NODEV) {
  310.         what = KERN_PROC_TTY;
  311.         flag = ttydev;
  312.     } else if (pid != -1) {
  313.         what = KERN_PROC_PID;
  314.         flag = pid;
  315.     } else {
  316.         what = KERN_PROC_ALL;
  317.         flag = 0;
  318.     }
  319.     /*
  320.      * select procs
  321.      */
  322.  
  323.     if (!show_all)
  324.         process_block_list();
  325.  
  326.     if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0)
  327.         errx(1, "%s", kvm_geterr(kd));
  328.     if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL)
  329.         err(1, NULL);
  330.     for (i = nentries; --i >= 0; ++kp) {
  331.         kinfo[i].ki_p = kp;
  332.         if (needuser)
  333.             saveuser(&kinfo[i]);
  334.     }
  335.     /*
  336.      * print header
  337.      */
  338.     printheader();
  339.     if (nentries == 0)
  340.         exit(0);
  341.     /*
  342.      * sort proc list
  343.      */
  344.     qsort(kinfo, nentries, sizeof(KINFO), pscomp);
  345.     /*
  346.      * for each proc, call each variable output function.
  347.      */
  348.     for (i = lineno = 0; i < nentries; i++) {
  349.     if (!show_all && check_process(kinfo[i].ki_p))
  350.         continue;
  351.         if (xflg == 0 && (KI_EPROC(&kinfo[i])->e_tdev == NODEV ||
  352.             (KI_PROC(&kinfo[i])->p_flag & P_CONTROLT ) == 0))
  353.             continue;
  354.         for (vent = vhead; vent; vent = vent->next) {
  355.             (vent->var->oproc)(&kinfo[i], vent);
  356.             if (vent->next != NULL)
  357.                 (void)putchar(' ');
  358.         }
  359.         (void)putchar('\n');
  360.         if (prtheader && lineno++ == prtheader - 4) {
  361.             (void)putchar('\n');
  362.             printheader();
  363.             lineno = 0;
  364.         }
  365.     }
  366.     exit(eval);
  367. }
  368.  
  369. static void
  370. scanvars()
  371. {
  372.     struct varent *vent;
  373.     VAR *v;
  374.     int i;
  375.  
  376.     for (vent = vhead; vent; vent = vent->next) {
  377.         v = vent->var;
  378.         i = strlen(v->header);
  379.         if (v->width < i)
  380.             v->width = i;
  381.         totwidth += v->width + 1;    /* +1 for space */
  382.         if (v->flag & USER)
  383.             needuser = 1;
  384.         if (v->flag & COMM)
  385.             needcomm = 1;
  386.     }
  387.     totwidth--;
  388. }
  389.  
  390. static char *
  391. fmt(fn, ki, comm, maxlen)
  392.     char **(*fn) __P((kvm_t *, const struct kinfo_proc *, int));
  393.     KINFO *ki;
  394.     char *comm;
  395.     int maxlen;
  396. {
  397.     char *s;
  398.  
  399.     if ((s =
  400.         fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen)) == NULL)
  401.         err(1, NULL);
  402.     return (s);
  403. }
  404.  
  405. static void
  406. saveuser(ki)
  407.     KINFO *ki;
  408. {
  409.     struct pstats pstats;
  410.     struct usave *usp;
  411.     struct user *u_addr = (struct user *)USRSTACK;
  412.  
  413.     usp = &ki->ki_u;
  414.     if (kvm_uread(kd, KI_PROC(ki), (unsigned long)&u_addr->u_stats,
  415.         (char *)&pstats, sizeof(pstats)) == sizeof(pstats)) {
  416.         /*
  417.          * The u-area might be swapped out, and we can't get
  418.          * at it because we have a crashdump and no swap.
  419.          * If it's here fill in these fields, otherwise, just
  420.          * leave them 0.
  421.          */
  422.         usp->u_start = pstats.p_start;
  423.         usp->u_ru = pstats.p_ru;
  424.         usp->u_cru = pstats.p_cru;
  425.         usp->u_valid = 1;
  426.     } else
  427.         usp->u_valid = 0;
  428.     /*
  429.      * save arguments if needed
  430.      */
  431.     if (needcomm)
  432.         ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm,
  433.             MAXCOMLEN);
  434.     else
  435.         ki->ki_args = NULL;
  436.     if (needenv)
  437.         ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0);
  438.     else
  439.         ki->ki_env = NULL;
  440. }
  441.  
  442. static int
  443. pscomp(a, b)
  444.     const void *a, *b;
  445. {
  446.     int i;
  447. #ifdef NEWVM
  448. #define VSIZE(k) (KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + \
  449.           KI_EPROC(k)->e_vm.vm_tsize)
  450. #else
  451. #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize)
  452. #endif
  453.  
  454.     if (sortby == SORTCPU)
  455.         return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a));
  456.     if (sortby == SORTMEM)
  457.         return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a));
  458.     i =  KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev;
  459.     if (i == 0)
  460.         i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid;
  461.     return (i);
  462. }
  463.  
  464. /*
  465.  * ICK (all for getopt), would rather hide the ugliness
  466.  * here than taint the main code.
  467.  *
  468.  *  ps foo -> ps -foo
  469.  *  ps 34 -> ps -p34
  470.  *
  471.  * The old convention that 't' with no trailing tty arg means the users
  472.  * tty, is only supported if argv[1] doesn't begin with a '-'.  This same
  473.  * feature is available with the option 'T', which takes no argument.
  474.  */
  475. static char *
  476. kludge_oldps_options(s)
  477.     char *s;
  478. {
  479.     size_t len;
  480.     char *newopts, *ns, *cp;
  481.  
  482.     len = strlen(s);
  483.     if ((newopts = ns = malloc(len + 2)) == NULL)
  484.         err(1, NULL);
  485.     /*
  486.      * options begin with '-'
  487.      */
  488.     if (*s != '-')
  489.         *ns++ = '-';    /* add option flag */
  490.     /*
  491.      * gaze to end of argv[1]
  492.      */
  493.     cp = s + len - 1;
  494.     /*
  495.      * if last letter is a 't' flag with no argument (in the context
  496.      * of the oldps options -- option string NOT starting with a '-' --
  497.      * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
  498.      */
  499.     if (*cp == 't' && *s != '-')
  500.         *cp = 'T';
  501.     else {
  502.         /*
  503.          * otherwise check for trailing number, which *may* be a
  504.          * pid.
  505.          */
  506.         while (cp >= s && isdigit(*cp))
  507.             --cp;
  508.     }
  509.     cp++;
  510.     memmove(ns, s, (size_t)(cp - s));    /* copy up to trailing number */
  511.     ns += cp - s;
  512.     /*
  513.      * if there's a trailing number, and not a preceding 'p' (pid) or
  514.      * 't' (tty) flag, then assume it's a pid and insert a 'p' flag.
  515.      */
  516.     if (isdigit(*cp) &&
  517.         (cp == s || (cp[-1] != 't' && cp[-1] != 'p')) &&
  518.         (cp - 1 == s || cp[-2] != 't'))
  519.         *ns++ = 'p';
  520.     (void)strcpy(ns, cp);        /* and append the number */
  521.  
  522.     return (newopts);
  523. }
  524.  
  525. static void
  526. usage()
  527. {
  528.  
  529.     (void)fprintf(stderr, "%s\n%s\n%s\n",
  530.         "usage: ps [-aChjlmrSTuvwx] [-O|o fmt] [-p pid] [-t tty] [-U user]",
  531.         "          [-M core] [-N system] [-W swap]",
  532.         "       ps [-L]");
  533.     exit(1);
  534. }
  535.