/* * arg.c - common argument processing support functions for lsof */ /* * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #ifndef lint static char copyright[] = "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; static char *rcsid = "$Id: arg.c,v 1.51 2012/04/10 16:30:06 abe Exp $"; #endif #include "lsof.h" /* * Local definitions */ #define CMDRXINCR 32 /* CmdRx[] allocation increment */ /* * Local static variables */ static int NCmdRxA = 0; /* space allocated to CmdRx[] */ /* * Local function prototypes */ _PROTOTYPE(static int ckfd_range,(char *first, char *dash, char *last, int *lo, int *hi)); _PROTOTYPE(static int enter_fd_lst,(char *nm, int lo, int hi, int excl)); _PROTOTYPE(static int enter_nwad,(struct nwad *n, int sp, int ep, char *s, struct hostent *he)); _PROTOTYPE(static struct hostent *lkup_hostnm,(char *hn, struct nwad *n)); _PROTOTYPE(static char *isIPv4addr,(char *hn, unsigned char *a, int al)); /* * ckfd_range() - check fd range */ static int ckfd_range(first, dash, last, lo, hi) char *first; /* starting character */ char *dash; /* '-' location */ char *last; /* '\0' location */ int *lo; /* returned low value */ int *hi; /* returned high value */ { char *cp; /* * See if the range character pointers make sense. */ if (first >= dash || dash >= last) { (void) fprintf(stderr, "%s: illegal FD range for -d: ", Pn); safestrprt(first, stderr, 1); return(1); } /* * Assemble and check the high and low values. */ for (cp = first, *lo = 0; *cp && cp < dash; cp++) { if (!isdigit((unsigned char)*cp)) { FD_range_nondigit: (void) fprintf(stderr, "%s: non-digit in -d FD range: ", Pn); safestrprt(first, stderr, 1); return(1); } *lo = (*lo * 10) + (int)(*cp - '0'); } for (cp = dash+1, *hi = 0; *cp && cp < last; cp++) { if (!isdigit((unsigned char)*cp)) goto FD_range_nondigit; *hi = (*hi * 10) + (int)(*cp - '0'); } if (*lo >= *hi) { (void) fprintf(stderr, "%s: -d FD range's low >= its high: ", Pn); safestrprt(first, stderr, 1); return(1); } return(0); } /* * ck_file_arg() - check file arguments */ int ck_file_arg(i, ac, av, fv, rs, sbp) int i; /* first file argument index */ int ac; /* argument count */ char *av[]; /* argument vector */ int fv; /* Ffilesys value (real or temporary) */ int rs; /* Readlink() status if argument count == 1: * 0 = undone; 1 = done */ struct stat *sbp; /* if non-NULL, pointer to stat(2) buffer * when argument count == 1 */ { char *ap, *fnm, *fsnm, *path; short err = 0; int fsm, ftype, j, k; MALLOC_S l; struct mounts *mp; static struct mounts **mmp = (struct mounts **)NULL; int mx, nm; static int nma = 0; struct stat sb; struct sfile *sfp; short ss = 0; #if defined(CKFA_EXPDEV) dev_t dev, rdev; #endif /* defined(CKFA_EXPDEV) */ #if defined(HASPROCFS) unsigned char ad, an; int pfsnl = -1; pid_t pid; struct procfsid *pfi; #endif /* defined(HASPROCFS) */ /* * Loop through arguments. */ for (; i < ac; i++) { if (rs && (ac == 1) && (i == 0)) path = av[i]; else { if (!(path = Readlink(av[i]))) { ErrStat = 1; continue; } } /* * Remove terminating `/' characters from paths longer than one. */ j = k = strlen(path); while ((k > 1) && (path[k-1] == '/')) { k--; } if (k < j) { if (path != av[i]) path[k] = '\0'; else { if (!(ap = (char *)malloc((MALLOC_S)(k + 1)))) { (void) fprintf(stderr, "%s: no space for copy of %s\n", Pn, path); Exit(1); } (void) strncpy(ap, path, k); ap[k] = '\0'; path = ap; } } /* * Check for file system argument. */ for (ftype = 1, mp = readmnt(), nm = 0; (fv != 1) && mp; mp = mp->next) { fsm = 0; if (strcmp(mp->dir, path) == 0) fsm++; else if (fv == 2 || (mp->fs_mode & S_IFMT) == S_IFBLK) { if (mp->fsnmres && strcmp(mp->fsnmres, path) == 0) fsm++; } if (!fsm) continue; ftype = 0; /* * Skip duplicates. */ for (mx = 0; mx < nm; mx++) { if (strcmp(mp->dir, mmp[mx]->dir) == 0 && mp->dev == mmp[mx]->dev && mp->rdev == mmp[mx]->rdev && mp->inode == mmp[mx]->inode) break; } if (mx < nm) continue; /* * Allocate space for and save another mount point match and * the type of match -- directory name (mounted) or file system * name (mounted-on). */ if (nm >= nma) { nma += 5; l = (MALLOC_S)(nma * sizeof(struct mounts *)); if (mmp) mmp = (struct mounts **)realloc((MALLOC_P *)mmp, l); else mmp = (struct mounts **)malloc(l); if (!mmp) { (void) fprintf(stderr, "%s: no space for mount pointers\n", Pn); Exit(1); } } mmp[nm++] = mp; } if (fv == 2 && nm == 0) { (void) fprintf(stderr, "%s: not a file system: ", Pn); safestrprt(av[i], stderr, 1); ErrStat = 1; continue; } /* * Loop through the file system matches. If there were none, make one * pass through the loop, using simply the path name. */ mx = 0; do { /* * Allocate an sfile structure and fill in the type and link. */ if (!(sfp = (struct sfile *)malloc(sizeof(struct sfile)))) { (void) fprintf(stderr, "%s: no space for files\n", Pn); Exit(1); } sfp->next = Sfile; Sfile = sfp; sfp->f = 0; if ((sfp->type = ftype)) { /* * For a non-file system path, use the path as the file name * and set a NULL file system name. */ fnm = path; fsnm = (char *)NULL; /* * Stat the path to obtain its characteristics. */ if (sbp && (ac == 1)) sb = *sbp; else { if (statsafely(fnm, &sb) != 0) { int en = errno; (void) fprintf(stderr, "%s: status error on ", Pn); safestrprt(fnm, stderr, 0); (void) fprintf(stderr, ": %s\n", strerror(en)); Sfile = sfp->next; (void) free((FREE_P *)sfp); ErrStat = 1; continue; } #if defined(HASSPECDEVD) (void) HASSPECDEVD(fnm, &sb); #endif /* defined(HASSPECDEVD) */ } sfp->i = (INODETYPE)sb.st_ino; sfp->mode = sb.st_mode & S_IFMT; #if defined(CKFA_EXPDEV) /* * Expand device numbers before saving, so that they match the * already-expanded local mount info table device numbers. * (This is an EP/IX 2.1.1 and above artifact.) */ sfp->dev = expdev(sb.st_dev); sfp->rdev = expdev(sb.st_rdev); #else /* !defined(CKFA_EXPDEV) */ sfp->dev = sb.st_dev; sfp->rdev = sb.st_rdev; #endif /* defined(CKFA_EXPDEV) */ #if defined(CKFA_MPXCHAN) /* * Save a (possible) multiplexed channel number. (This is an * AIX artifact.) */ sfp->ch = getchan(path); #endif /* defined(CKFA_MPXCHAN) */ } else { #if defined(SAVE_MP_IN_SFILE) sfp->mp = mp = mmp[mx++]; #else /* !defined(SAVE_MP_IN_SFILE) */ mp = mmp[mx++]; #endif /* defined(SAVE_MP_IN_SFILE) */ ss++; #if defined(HASPROCFS) /* * If this is a /proc file system, set the search flag and * abandon the sfile entry. */ if (mp == Mtprocfs) { Sfile = sfp->next; (void) free((FREE_P *)sfp); Procsrch = 1; continue; } #endif /* defined(HASPROCFS) */ /* * Derive file name and file system name for a mount point. * * Save the device numbers, inode number, and modes. */ fnm = mp->dir; fsnm = mp->fsname; sfp->dev = mp->dev; sfp->rdev = mp->rdev; sfp->i = mp->inode; sfp->mode = mp->mode & S_IFMT; } ss = 1; /* indicate a "safe" stat() */ /* * Store the file name and file system name pointers in the sfile * structure, allocating space as necessary. */ if (!fnm || fnm == path) { sfp->name = fnm; #if defined(HASPROCFS) an = 0; #endif /* defined(HASPROCFS) */ } else { if (!(sfp->name = mkstrcpy(fnm, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for file name: ", Pn); safestrprt(fnm, stderr, 1); Exit(1); } #if defined(HASPROCFS) an = 1; #endif /* defined(HASPROCFS) */ } if (!fsnm || fsnm == path) { sfp->devnm = fsnm; #if defined(HASPROCFS) ad = 0; #endif /* defined(HASPROCFS) */ } else { if (!(sfp->devnm = mkstrcpy(fsnm, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for file system name: ", Pn); safestrprt(fsnm, stderr, 1); Exit(1); } #if defined(HASPROCFS) ad = 1; #endif /* defined(HASPROCFS) */ } if (!(sfp->aname = mkstrcpy(av[i], (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for argument file name: ", Pn); safestrprt(av[i], stderr, 1); Exit(1); } #if defined(HASPROCFS) /* * See if this is an individual member of a proc file system. */ if (!Mtprocfs || Procsrch) continue; # if defined(HASFSTYPE) && HASFSTYPE==1 if (strcmp(sb.st_fstype, HASPROCFS) != 0) continue; # endif /* defined(HASFSTYPE) && HASFSTYPE==1 */ if (pfsnl == -1) pfsnl = strlen(Mtprocfs->dir); if (!pfsnl) continue; if (strncmp(Mtprocfs->dir, path, pfsnl) != 0) continue; if (path[pfsnl] != '/') # if defined(HASPINODEN) pid = 0; # else /* !defined(HASPINODEN) */ continue; # endif /* defined(HASPINODEN) */ else { for (j = pfsnl+1; path[j]; j++) { if (!isdigit((unsigned char)path[j])) break; } if (path[j] || (j - pfsnl - 1) < 1 || (sfp->mode & S_IFMT) != S_IFREG) # if defined(HASPINODEN) pid = 0; # else /* !defined(HASPINODEN) */ continue; # endif /* defined(HASPINODEN) */ else pid = atoi(&path[pfsnl+1]); } if (!(pfi = (struct procfsid *)malloc((MALLOC_S) sizeof(struct procfsid)))) { (void) fprintf(stderr, "%s: no space for %s ID: ", Pn, Mtprocfs->dir); safestrprt(path, stderr, 1); Exit(1); } pfi->pid = pid; pfi->f = 0; pfi->nm = sfp->aname; pfi->next = Procfsid; Procfsid = pfi; # if defined(HASPINODEN) pfi->inode = (INODETYPE)sfp->i; # endif /* defined(HASPINODEN) */ /* * Abandon the Sfile entry, lest it be used in is_file_named(). */ Sfile = sfp->next; if (ad) (void) free((FREE_P *)sfp->devnm); if (an) (void) free((FREE_P *)sfp->name); (void) free((FREE_P *)sfp); #endif /* defined(HASPROCFS) */ } while (mx < nm); } if (!ss) err = 1; return((int)err); } #if defined(HASDCACHE) /* * ctrl_dcache() - enter device cache control */ int ctrl_dcache(c) char *c; /* control string */ { int rc = 0; if (!c) { (void) fprintf(stderr, "%s: no device cache option control string\n", Pn); return(1); } /* * Decode argument function character. */ switch (*c) { case '?': if (*(c+1) != '\0') { (void) fprintf(stderr, "%s: nothing should follow -D?\n", Pn); return(1); } DChelp = 1; return(0); case 'b': case 'B': if (Setuidroot #if !defined(WILLDROPGID) || Myuid #endif /* !defined(WILLDROPGID) */ ) rc = 1; else DCstate = 1; break; case 'r': case 'R': if (Setuidroot && *(c+1)) rc = 1; else DCstate = 2; break; case 'u': case 'U': if (Setuidroot #if !defined(WILLDROPGID) || Myuid #endif /* !defined(WILLDROPGID) */ ) rc = 1; else DCstate = 3; break; case 'i': case 'I': if (*(c+1) == '\0') { DCstate = 0; return(0); } /* fall through */ default: (void) fprintf(stderr, "%s: unknown -D option: ", Pn); safestrprt(c, stderr, 1); return(1); } if (rc) { (void) fprintf(stderr, "%s: -D option restricted to root: ", Pn); safestrprt(c, stderr, 1); return(1); } /* * Skip to optional path name and save it. */ for (c++; *c && (*c == ' ' || *c == '\t'); c++) ; if (strlen(c)) { if (!(DCpathArg = mkstrcpy(c, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for -D path: ", Pn); safestrprt(c, stderr, 1); Exit(1); } } return(0); } #endif /* defined(HASDCACHE) */ /* * enter_cmd_rx() - enter command regular expression */ int enter_cmd_rx(x) char *x; /* regular expression */ { int bmod = 0; int bxmod = 0; int i, re; int imod = 0; int xmod = 0; int co = REG_NOSUB|REG_EXTENDED; char reb[256], *xb, *xe, *xm; MALLOC_S xl; char *xp = (char *)NULL; /* * Make sure the supplied string starts a regular expression. */ if (!*x || (*x != '/')) { (void) fprintf(stderr, "%s: regexp doesn't begin with '/': ", Pn); if (x) safestrprt(x, stderr, 1); return(1); } /* * Skip to the end ('/') of the regular expression. */ xb = x + 1; for (xe = xb; *xe; xe++) { if (*xe == '/') break; } if (*xe != '/') { (void) fprintf(stderr, "%s: regexp doesn't end with '/': ", Pn); safestrprt(x, stderr, 1); return(1); } /* * Decode any regular expression modifiers. */ for (i = 0, xm = xe + 1; *xm; xm++) { switch(*xm) { case 'b': /* This is a basic expression. */ if (++bmod > 1) { if (bmod == 2) { (void) fprintf(stderr, "%s: b regexp modifier already used: ", Pn); safestrprt(x, stderr, 1); } i = 1; } else if (xmod) { if (++bxmod == 1) { (void) fprintf(stderr, "%s: b and x regexp modifiers conflict: ", Pn); safestrprt(x, stderr, 1); } i = 1; } else co &= ~REG_EXTENDED; break; case 'i': /* Ignore case. */ if (++imod > 1) { if (imod == 2) { (void) fprintf(stderr, "%s: i regexp modifier already used: ", Pn); safestrprt(x, stderr, 1); } i = 1; } else co |= REG_ICASE; break; case 'x': /* This is an extended expression. */ if (++xmod > 1) { if (xmod == 2) { (void) fprintf(stderr, "%s: x regexp modifier already used: ", Pn); safestrprt(x, stderr, 1); } i = 1; } else if (bmod) { if (++bxmod == 1) { (void) fprintf(stderr, "%s: b and x regexp modifiers conflict: ", Pn); safestrprt(x, stderr, 1); } i = 1; } else co |= REG_EXTENDED; break; default: (void) fprintf(stderr, "%s: invalid regexp modifier: %c\n", Pn, (int)*xm); i = 1; } } if (i) return(1); /* * Allocate space to hold expression and copy it there. */ xl = (MALLOC_S)(xe - xb); if (!(xp = (char *)malloc(xl + 1))) { (void) fprintf(stderr, "%s: no regexp space for: ", Pn); safestrprt(x, stderr, 1); Exit(1); } (void) strncpy(xp, xb, xl); xp[(int)xl] = '\0'; /* * Assign a new CmdRx[] slot for this expression. */ if (NCmdRxA >= NCmdRxU) { /* * More CmdRx[] space must be assigned. */ NCmdRxA += CMDRXINCR; xl = (MALLOC_S)(NCmdRxA * sizeof(lsof_rx_t)); if (CmdRx) CmdRx = (lsof_rx_t *)realloc((MALLOC_P *)CmdRx, xl); else CmdRx = (lsof_rx_t *)malloc(xl); if (!CmdRx) { (void) fprintf(stderr, "%s: no space for regexp: ", Pn); safestrprt(x, stderr, 1); Exit(1); } } i = NCmdRxU; CmdRx[i].exp = xp; /* * Compile the expression. */ if ((re = regcomp(&CmdRx[i].cx, xp, co))) { (void) fprintf(stderr, "%s: regexp error: ", Pn); safestrprt(x, stderr, 0); (void) regerror(re, &CmdRx[i].cx, &reb[0], sizeof(reb)); (void) fprintf(stderr, ": %s\n", reb); if (xp) { (void) free((FREE_P *)xp); xp = (char *)NULL; } return(1); } /* * Complete the CmdRx[] table entry. */ CmdRx[i].mc = 0; CmdRx[i].exp = xp; NCmdRxU++; return(0); } #if defined(HASEOPT) /* * enter_efsys() -- enter path of file system whose kernel blocks are to be * eliminated */ int enter_efsys(e, rdlnk) char *e; /* file system path */ int rdlnk; /* avoid readlink(2) if non-zero */ { char *ec; /* pointer to copy of path */ efsys_list_t *ep; /* file system path list pointer */ int i; /* temporary index */ char *path; /* Readlink() of file system path */ if (!e || (*e != '/')) { if (!Fwarn) (void) fprintf(stderr, "%s: -e not followed by a file system path: \"%s\"\n", Pn, e); return(1); } if (!(ec = mkstrcpy(e, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for -e string: ", Pn); safestrprt(e, stderr, 1); Exit(1); } if (rdlnk) path = ec; else { if (!(path = Readlink(ec))) return(1); } /* * Remove terminating `/' characters from paths longer than one. */ for (i = (int)strlen(path); (i > 1) && (path[i - 1] == '/'); i--) { path[i - 1] = '\0'; } /* * Enter file system path on list, avoiding duplicates. */ for (ep = Efsysl; ep; ep = ep->next) { if (!strcmp(ep->path, path)) return(0); } if (!(ep = (efsys_list_t *)malloc((MALLOC_S)(sizeof(efsys_list_t))))) { (void) fprintf(stderr, "%s: no space for \"-e %s\" entry\n", Pn, e); Exit(1); } ep->path = path; ep->pathl = i; ep->rdlnk = rdlnk; ep->mp = (struct mounts *)NULL; ep->next = Efsysl; Efsysl = ep; return(0); } #endif /* defined(HASEOPT) */ /* * enter_fd() - enter file descriptor list for searching */ int enter_fd(f) char *f; /* file descriptor list pointer */ { char c, *cp1, *cp2, *dash; int err, excl, hi, lo; char *fc; /* * Check for non-empty list and make a copy. */ if (!f || (strlen(f) + 1) < 2) { (void) fprintf(stderr, "%s: no file descriptor specified\n", Pn); return(1); } if (!(fc = mkstrcpy(f, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for fd string: ", Pn); safestrprt(f, stderr, 1); Exit(1); } /* * Isolate each file descriptor in the comma-separated list, then enter it * in the file descriptor string list. If a descriptor has the form: * * [0-9]+-[0-9]+ * * treat it as an ascending range of file descriptor numbers. * * Accept a leading '^' as an excusion on match. */ for (cp1 = fc, err = 0; *cp1;) { if (*cp1 == '^') { excl = 1; cp1++; } else excl = 0; for (cp2 = cp1, dash = (char *)NULL; *cp2 && *cp2 != ','; cp2++) { if (*cp2 == '-') dash = cp2; } if ((c = *cp2) != '\0') *cp2 = '\0'; if (cp2 > cp1) { if (dash) { if (ckfd_range(cp1, dash, cp2, &lo, &hi)) err = 1; else { if (enter_fd_lst((char *)NULL, lo, hi, excl)) err = 1; } } else { if (enter_fd_lst(cp1, 0, 0, excl)) err = 1; } } if (c == '\0') break; cp1 = cp2 + 1; } (void) free((FREE_P *)fc); return(err); } /* * enter_fd_lst() - make an entry in the FD list, Fdl */ static int enter_fd_lst(nm, lo, hi, excl) char *nm; /* FD name (none if NULL) */ int lo; /* FD low boundary (if nm NULL) */ int hi; /* FD high boundary (if nm NULL) */ int excl; /* exclusion on match */ { char buf[256], *cp; int n; struct fd_lst *f, *ft; /* * Don't allow a mixture of exclusions and inclusions. */ if (FdlTy >= 0) { if (FdlTy != excl) { if (!Fwarn) { /* * If warnings are enabled, report a mixture. */ if (nm) { (void) snpf(buf, sizeof(buf) - 1, "%s%s", excl ? "^" : "", nm); } else { if (lo != hi) { (void) snpf(buf, sizeof(buf) - 1, "%s%d-%d", excl ? "^" : "", lo, hi); } else { (void) snpf(buf, sizeof(buf) - 1, "%s%d", excl ? "^" : "", lo); } } buf[sizeof(buf) - 1] = '\0'; (void) fprintf(stderr, "%s: %s in an %s -d list: %s\n", Pn, excl ? "exclude" : "include", FdlTy ? "exclude" : "include", buf); } return(1); } } /* * Allocate an fd_lst entry. */ if (!(f = (struct fd_lst *)malloc((MALLOC_S)sizeof(struct fd_lst)))) { (void) fprintf(stderr, "%s: no space for FD list entry\n", Pn); Exit(1); } if (nm) { /* * Process an FD name. First see if it contains only digits; if it * does, convert them to an integer and set the low and high * boundaries to the result. * * If the name has a non-digit, store it as a string, and set the * boundaries to impossible values (i.e., low > high). */ for (cp = nm, n = 0; *cp; cp++) { if (!isdigit((unsigned char)*cp)) break; n = (n * 10) + (int)(*cp - '0'); } if (*cp) { if (!(f->nm = mkstrcpy(nm, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for copy of: %s\n", Pn, nm); Exit(1); } lo = 1; hi = 0; } else { f->nm = (char *)NULL; lo = hi = n; } } else f->nm = (char *)NULL; /* * Skip duplicates. */ for (ft = Fdl; ft; ft = ft->next) { if (f->nm) { if (!ft->nm || strcmp(f->nm, ft->nm)) continue; } else if ((lo != ft->lo) || (hi != ft->hi)) continue; (void) free((FREE_P *)f); return(0); } /* * Complete the fd_lst entry and link it to the head of the chain. */ f->hi = hi; f->lo = lo; f->next = Fdl; Fdl = f; FdlTy = excl; return(0); } /* * enter_dir() - enter the files of a directory for searching */ #define EDDEFFNL 128 /* default file name length */ int enter_dir(d, descend) char *d; /* directory path name pointer */ int descend; /* subdirectory descend flag: * 0 = don't descend * 1 = descend */ { char *av[2]; dev_t ddev; DIR *dfp; char *dn = (char *)NULL; MALLOC_S dnl, dnamlen; struct DIRTYPE *dp; int en, sl; int fct = 0; char *fp = (char *)NULL; MALLOC_S fpl = (MALLOC_S)0; MALLOC_S fpli = (MALLOC_S)0; struct stat sb; /* * Check the directory path; reduce symbolic links; stat(2) it; make sure it's * really a directory. */ if (!d || !*d || *d == '+' || *d == '-') { if (!Fwarn) (void) fprintf(stderr, "%s: +d not followed by a directory path\n", Pn); return(1); } if (!(dn = Readlink(d))) return(1); if (statsafely(dn, &sb)) { if (!Fwarn) { en = errno; (void) fprintf(stderr, "%s: WARNING: can't stat(", Pn); safestrprt(dn, stderr, 0); (void) fprintf(stderr, "): %s\n", strerror(en)); } if (dn && dn != d) { (void) free((FREE_P *)dn); dn = (char *)NULL; } return(1); } if ((sb.st_mode & S_IFMT) != S_IFDIR) { if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: not a directory: ", Pn); safestrprt(dn, stderr, 1); } if (dn && dn != d) { (void) free((FREE_P *)dn); dn = (char *)NULL; } return(1); } #if defined(HASSPECDEVD) (void) HASSPECDEVD(dn, &sb); #endif /* defined(HASSPECDEVD) */ ddev = sb.st_dev; /* * Stack the directory and record it in Sfile for searching. */ Dstkn = Dstkx = 0; Dstk = (char **)NULL; (void) stkdir(dn); av[0] = (dn == d) ? mkstrcpy(dn, (MALLOC_S *)NULL) : dn; av[1] = (char *)NULL; dn = (char *)NULL; if (!ck_file_arg(0, 1, av, 1, 1, &sb)) { av[0] = (char *)NULL; fct++; } /* * Unstack the next directory and examine it. */ while (--Dstkx >= 0) { if (!(dn = Dstk[Dstkx])) continue; Dstk[Dstkx] = (char *)NULL; /* * Open the directory path and prepare its name for use with the * files in the directory. */ if (!(dfp = OpenDir(dn))) { if (!Fwarn) { if ((en = errno) != ENOENT) { (void) fprintf(stderr, "%s: WARNING: can't opendir(", Pn); safestrprt(dn, stderr, 0); (void) fprintf(stderr, "): %s\n", strerror(en)); } } (void) free((FREE_P *)dn); dn = (char *)NULL; continue; } dnl = strlen(dn); sl = ((dnl > 0) && (*(dn + dnl - 1) == '/')) ? 0 : 1; /* * Define space for possible addition to the directory path. */ fpli = (MALLOC_S)(dnl + sl + EDDEFFNL + 1); if ((int)fpli > (int)fpl) { fpl = fpli; if (!fp) fp = (char *)malloc(fpl); else fp = (char *)realloc(fp, fpl); if (!fp) { (void) fprintf(stderr, "%s: no space for path to entries in directory: %s\n", Pn, dn); Exit(1); } } (void) snpf(fp, (size_t)fpl, "%s%s", dn, sl ? "/" : ""); (void) free((FREE_P *)dn); dn = (char *)NULL; /* * Read the contents of the directory. */ for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) { /* * Skip: entries with no inode number; * entries with a zero length name; * "."; * and "..". */ if (!dp->d_ino) continue; #if defined(HASDNAMLEN) dnamlen = (MALLOC_S)dp->d_namlen; #else /* !defined(HASDNAMLEN) */ dnamlen = (MALLOC_S)strlen(dp->d_name); #endif /* defined(HASDNAMLEN) */ if (!dnamlen) continue; if (dnamlen <= 2 && dp->d_name[0] == '.') { if (dnamlen == 1) continue; if (dp->d_name[1] == '.') continue; } /* * Form the entry's path name. */ fpli = (MALLOC_S)(dnamlen - (fpl - dnl - sl - 1)); if ((int)fpli > 0) { fpl += fpli; if (!(fp = (char *)realloc(fp, fpl))) { (void) fprintf(stderr, "%s: no space for: ", Pn); safestrprt(dn, stderr, 0); putc('/', stderr); safestrprtn(dp->d_name, dnamlen, stderr, 1); Exit(1); } } (void) strncpy(fp + dnl + sl, dp->d_name, dnamlen); fp[dnl + sl + dnamlen] = '\0'; /* * Lstatsafely() the entry; complain if that fails. * * Stack entries that represent subdirectories. */ if (lstatsafely(fp, &sb)) { if ((en = errno) != ENOENT) { if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: can't lstat(", Pn); safestrprt(fp, stderr, 0); (void) fprintf(stderr, "): %s\n", strerror(en)); } } continue; } #if defined(HASSPECDEVD) (void) HASSPECDEVD(fp, &sb); #endif /* defined(HASSPECDEVD) */ if (!(Fxover & XO_FILESYS)) { /* * Unless "-x" or "-x f" was specified, don't cross over file * system mount points. */ if (sb.st_dev != ddev) continue; } if ((sb.st_mode & S_IFMT) == S_IFLNK) { /* * If this is a symbolic link and "-x_ or "-x l" was specified, * Statsafely() the entry and process it. * * Otherwise skip symbolic links. */ if (Fxover & XO_SYMLINK) { if (statsafely(fp, &sb)) { if ((en = errno) != ENOENT) { if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: can't stat(", Pn); safestrprt(fp, stderr, 0); (void) fprintf(stderr, ") symbolc link: %s\n", strerror(en)); } } continue; } } else continue; } if (av[0]) { (void) free((FREE_P *)av[0]); av[0] = (char *)NULL; } av[0] = mkstrcpy(fp, (MALLOC_S *)NULL); if ((sb.st_mode & S_IFMT) == S_IFDIR && descend) /* * Stack a subdirectory according to the descend argument. */ stkdir(av[0]); /* * Use ck_file_arg() to record the entry for searching. Force it * to consider the entry a file, not a file system. */ if (!ck_file_arg(0, 1, av, 1, 1, &sb)) { av[0] = (char *)NULL; fct++; } } (void) CloseDir(dfp); if (dn && dn != d) { (void) free((FREE_P *)dn); dn = (char *)NULL; } } /* * Free malloc()'d space. */ if (dn && dn != d) { (void) free((FREE_P *)dn); dn = (char *)NULL; } if (av[0] && av[0] != fp) { (void) free((FREE_P *)av[0]); av[0] = (char *)NULL; } if (fp) { (void) free((FREE_P *)fp); fp = (char *)NULL; } if (Dstk) { (void) free((FREE_P *)Dstk); Dstk = (char **)NULL; } if (!fct) { /* * Warn if no files were recorded for searching. */ if (!Fwarn) { (void) fprintf(stderr, "%s: WARNING: no files found in directory: ", Pn); safestrprt(d, stderr, 1); } return(1); } return(0); } /* * enter_id() - enter PGID or PID for searching */ int enter_id(ty, p) enum IDType ty; /* type: PGID or PID */ char *p; /* process group ID string pointer */ { char *cp; int err, i, id, j, mx, n, ni, nx, x; struct int_lst *s; if (!p) { (void) fprintf(stderr, "%s: no process%s ID specified\n", Pn, (ty == PGID) ? " group" : ""); return(1); } /* * Set up variables for the type of ID. */ switch (ty) { case PGID: mx = Mxpgid; n = Npgid; ni = Npgidi; nx = Npgidx; s = Spgid; break; case PID: mx = Mxpid; n = Npid; ni = Npidi; nx = Npidx; s = Spid; break; default: (void) fprintf(stderr, "%s: enter_id \"", Pn); safestrprt(p, stderr, 0); (void) fprintf(stderr, "\", invalid type: %d\n", ty); Exit(1); } /* * Convert and store the ID. */ for (cp = p, err = 0; *cp;) { /* * Assemble ID. */ for (i = id = x = 0; *cp && *cp != ','; cp++) { if (!i) { i = 1; if (*cp == '^') { x = 1; continue; } } #if defined(__STDC__) if (!isdigit((unsigned char)*cp)) #else /* !defined(__STDC__) */ if (!isascii(*cp) || ! isdigit((unsigned char)*cp)) #endif /* __STDC__ */ { (void) fprintf(stderr, "%s: illegal process%s ID: ", Pn, (ty == PGID) ? " group" : ""); safestrprt(p, stderr, 1); return(1); } id = (id * 10) + *cp - '0'; } if (*cp) cp++; /* * Avoid entering duplicates and conflicts. */ for (i = j = 0; i < n; i++) { if (id == s[i].i) { if (x == s[i].x) { j = 1; continue; } (void) fprintf(stderr, "%s: P%sID %d has been included and excluded.\n", Pn, (ty == PGID) ? "G" : "", id); err = j = 1; break; } } if (j) continue; /* * Allocate table table space. */ if (n >= mx) { mx += IDINCR; if (!s) s = (struct int_lst *)malloc( (MALLOC_S)(sizeof(struct int_lst) * mx)); else s = (struct int_lst *)realloc((MALLOC_P *)s, (MALLOC_S)(sizeof(struct int_lst) * mx)); if (!s) { (void) fprintf(stderr, "%s: no space for %d process%s IDs", Pn, mx, (ty == PGID) ? " group" : ""); Exit(1); } } s[n].f = 0; s[n].i = id; s[n++].x = x; if (x) nx++; else ni++; } /* * Save variables for the type of ID. */ if (ty == PGID) { Mxpgid = mx; Npgid = n; Npgidi = ni; Npgidx = nx; Spgid = s; } else { Mxpid = mx; Npid = Npuns = n; Npidi = ni; Npidx = nx; Spid = s; } return(err); } /* * enter_network_address() - enter Internet address for searching */ int enter_network_address(na) char *na; /* Internet address string pointer */ { int ae, i, pr; int ep = -1; int ft = 0; struct hostent *he = (struct hostent *)NULL; char *hn = (char *)NULL; MALLOC_S l; struct nwad n; char *p, *wa; int pt = 0; int pu = 0; struct servent *se, *se1; char *sn = (char *)NULL; int sp = -1; MALLOC_S snl = 0; #if defined(HASIPv6) char *cp; #endif /* defined(HASIPv6) */ if (!na) { (void) fprintf(stderr, "%s: no network address specified\n", Pn); return(1); } zeromem((char *)&n, sizeof(n)); wa = na; /* * Process an IP version type specification, IPv4 or IPv6, optionally followed * by a '@' and a host name or Internet address, or a ':' and a service name or * port number. */ if ((*wa == '4') || (*wa == '6')) { if (*wa == '4') ft = 4; else if (*wa == '6') { #if defined(HASIPv6) ft = 6; #else /* !defined(HASIPv6) */ (void) fprintf(stderr, "%s: IPv6 not supported: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; #endif /* defined(HASIPv6) */ } wa++; if (!*wa) { /* * If nothing follows 4 or 6, then all network files of the * specified IP version are selected. Sequential -i, -i4, and * -i6 specifications interact logically -- e.g., -i[46] followed * by -i[64] is the same as -i. */ if (!Fnet) { Fnet = 1; FnetTy = ft; } else { if (FnetTy) { if (FnetTy != ft) FnetTy = 0; } else FnetTy = ft; } return(0); } } else if (Fnet) ft = FnetTy; /* * If an IP version has been specified, use it to set the address family. */ switch (ft) { case 4: n.af = AF_INET; break; #if defined(HASIPv6) case 6: n.af = AF_INET6; break; #endif /* defined(HASIPv6) */ } /* * Process protocol name, optionally followed by a '@' and a host name or * Internet address, or a ':' and a service name or port number. */ if (*wa && *wa != '@' && *wa != ':') { for (p = wa; *wa && *wa != '@' && *wa != ':'; wa++) ; if ((l = wa - p)) { if (!(n.proto = mkstrcat(p, l, (char *)NULL, -1, (char *)NULL, -1, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for protocol name from: -i ", Pn); safestrprt(na, stderr, 1); nwad_exit: if (n.proto) (void) free((FREE_P *)n.proto); if (hn) (void) free((FREE_P *)hn); if (sn) (void) free((FREE_P *)sn); return(1); } /* * The protocol name should be "tcp", "udp" or "udplite". */ if ((strcasecmp(n.proto, "tcp") != 0) && (strcasecmp(n.proto, "udp") != 0) && (strcasecmp(n.proto, "udplite") != 0)) { (void) fprintf(stderr, "%s: unknown protocol name (%s) in: -i ", Pn, n.proto); safestrprt(na, stderr, 1); goto nwad_exit; } /* * Convert protocol name to lower case. */ for (p = n.proto; *p; p++) { if (*p >= 'A' && *p <= 'Z') *p = *p - 'A' + 'a'; } } } /* * Process an IPv4 address (1.2.3.4), IPv6 address ([1:2:3:4:5:6:7:8]), * or host name, preceded by a '@' and optionally followed by a colon * and a service name or port number. */ if (*wa == '@') { wa++; if (!*wa || *wa == ':') { #if defined(HASIPv6) unacc_address: #endif /* defined(HASIPv6) */ (void) fprintf(stderr, "%s: unacceptable Internet address in: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; } if ((p = isIPv4addr(wa, n.a, sizeof(n.a)))) { /* * Process IPv4 address. */ if (ft == 6) { (void) fprintf(stderr, "%s: IPv4 addresses are prohibited: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; } wa = p; n.af = AF_INET; } else if (*wa == '[') { #if defined(HASIPv6) /* * Make sure IPv6 addresses are permitted. If they are, assemble * one. */ if (ft == 4) { (void) fprintf(stderr, "%s: IPv6 addresses are prohibited: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; } if (!(cp = strrchr(++wa, ']'))) goto unacc_address; *cp = '\0'; i = inet_pton(AF_INET6, wa, (void *)&n.a); *cp = ']'; if (i != 1) goto unacc_address; for (ae = i = 0; i < MAX_AF_ADDR; i++) { if ((ae |= n.a[i])) break; } if (!ae) goto unacc_address; if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)&n.a[0])) { if (ft == 6) { (void) fprintf(stderr, "%s: IPv4 addresses are prohibited: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; } for (i = 0; i < 4; i++) { n.a[i] = n.a[i+12]; } n.af = AF_INET; } else n.af = AF_INET6; wa = cp + 1; #else /* !defined(HASIPv6) */ (void) fprintf(stderr, "%s: unsupported IPv6 address in: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; #endif /* defined(HASIPv6) */ } else { /* * Assemble host name. */ for (p = wa; *p && *p != ':'; p++) ; if ((l = p - wa)) { if (!(hn = mkstrcat(wa, l, (char *)NULL, -1, (char *)NULL, -1, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for host name: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; } #if defined(HASIPv6) /* * If no IP version has been specified, look up an IPv6 host * name first. If that fails, look up an IPv4 host name. * * If the IPv6 version has been specified, look up the host * name only under its IP version specification. */ if (!ft) n.af = AF_INET6; if (!(he = lkup_hostnm(hn, &n)) && !ft) { n.af = AF_INET; he = lkup_hostnm(hn, &n); } #else /* !defined(HASIPv6) */ if (!ft) n.af = AF_INET; he = lkup_hostnm(hn, &n); #endif /* defined(HASIPv6) */ if (!he) { fprintf(stderr, "%s: unknown host name (%s) in: -i ", Pn, hn); safestrprt(na, stderr, 1); goto nwad_exit; } } wa = p; } } /* * If there is no port number, enter the address. */ if (!*wa) goto nwad_enter; /* * Process a service name or port number list, preceded by a colon. * * Entries of the list are separated with commas; elements of a numeric range * are specified with a separating minus sign (`-'); all service names must * belong to the same protocol; embedded spaces are not allowed. An embedded * minus sign in a name is taken to be part of the name, the starting entry * of a range can't be a service name. */ if (*wa != ':' || *(wa + 1) == '\0') { unacc_port: (void) fprintf(stderr, "%s: unacceptable port specification in: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; } for (++wa; wa && *wa; wa++) { for (ep = pr = sp = 0; *wa; wa++) { if (*wa < '0' || *wa > '9') { /* * Convert service name to port number, using already-specified * protocol name. A '-' is taken to be part of the name; hence * the starting entry of a range can't be a service name. */ for (p = wa; *wa && *wa != ','; wa++) ; if (!(l = wa - p)) { (void) fprintf(stderr, "%s: invalid service name: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; } if (sn) { if (l > snl) { sn = (char *)realloc((MALLOC_P *)sn, l + 1); snl = l; } } else { sn = (char *)malloc(l + 1); snl = l; } if (!sn) { (void) fprintf(stderr, "%s: no space for service name: -i ", Pn); safestrprt(na, stderr, 1); goto nwad_exit; } (void) strncpy(sn, p, l); *(sn + l) = '\0'; if (n.proto) { /* * If the protocol has been specified, look up the port * number for the service name for the specified protocol. */ if (!(se = getservbyname(sn, n.proto))) { (void) fprintf(stderr, "%s: unknown service %s for %s in: -i ", Pn, sn, n.proto); safestrprt(na, stderr, 1); goto nwad_exit; } pt = (int)ntohs(se->s_port); } else { /* * If no protocol has been specified, look up the port * numbers for the service name for both TCP and UDP. */ if((se = getservbyname(sn, "tcp"))) pt = (int)ntohs(se->s_port); if ((se1 = getservbyname(sn, "udp"))) pu = (int)ntohs(se1->s_port); if (!se && !se1) { (void) fprintf(stderr, "%s: unknown service %s in: -i ", Pn, sn); safestrprt(na, stderr, 1); goto nwad_exit; } if (se && se1 && pt != pu) { (void) fprintf(stderr, "%s: TCP=%d and UDP=%d %s ports conflict;\n", Pn, pt, pu, sn); (void) fprintf(stderr, " specify \"tcp:%s\" or \"udp:%s\": -i ", sn, sn); safestrprt(na, stderr, 1); goto nwad_exit; } if (!se && se1) pt = pu; } if (pr) ep = pt; else { sp = pt; if (*wa == '-') pr++; } } else { /* * Assemble port number. */ for (; *wa && *wa != ','; wa++) { if (*wa == '-') { if (pr) goto unacc_port; pr++; break; } if (*wa < '0' || *wa > '9') goto unacc_port; if (pr) ep = (ep * 10) + *wa - '0'; else sp = (sp * 10) + *wa - '0'; } } if (!*wa || *wa == ',') break; if (pr) continue; goto unacc_port; } if (!pr) ep = sp; if (ep < sp) goto unacc_port; /* * Enter completed port or port range specification. */ nwad_enter: for (i = 1; i;) { if (enter_nwad(&n, sp, ep, na, he)) goto nwad_exit; #if defined(HASIPv6) /* * If IPv6 is enabled, a host name was specified, and the * associated * address is for the AF_INET6 address family, * try to get and address for the AF_INET family, too, unless * IPv4 is prohibited. */ if (hn && (n.af == AF_INET6) && (ft != 6)) { n.af = AF_INET; if ((he = lkup_hostnm(hn, &n))) continue; } #endif /* defined(HASIPv6) */ i = 0; } if (!*wa) break; } if (sn) (void) free((FREE_P *)sn); return(0); } /* * enter_nwad() - enter nwad structure */ static int enter_nwad(n, sp, ep, s, he) struct nwad *n; /* pointer to partially completed * nwad (less port) */ int sp; /* starting port number */ int ep; /* ending port number */ char *s; /* string that states the address */ struct hostent *he; /* pointer to hostent struct from which * network address came */ { int ac; unsigned char *ap; static int na = 0; struct nwad nc; struct nwad *np; /* * Allocate space for the argument specification. */ if (strlen(s)) { if (!(n->arg = mkstrcpy(s, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for Internet argument: -i ", Pn); safestrprt(s, stderr, 1); Exit(1); } } else n->arg = (char *)NULL; /* * Loop through all hostent addresses. */ for (ac = 1, nc = *n;;) { /* * Test address specification -- it must contain at least one of: * protocol, Internet address or port. If correct, link into search * list. */ if (!nc.proto && !nc.a[0] && !nc.a[1] && !nc.a[2] && !nc.a[3] #if defined(HASIPv6) && (nc.af != AF_INET6 || (!nc.a[4] && !nc.a[5] && !nc.a[6] && !nc.a[7] && !nc.a[8] && !nc.a[9] && !nc.a[10] && !nc.a[11] && !nc.a[12] && !nc.a[13] && !nc.a[14] && !nc.a[15])) #endif /* defined(HASIPv6) */ && sp == -1) { (void) fprintf(stderr, "%s: incomplete Internet address specification: -i ", Pn); safestrprt(s, stderr, 1); return(1); } /* * Limit the network address chain length to MAXNWAD for reasons of * search efficiency. */ if (na >= MAXNWAD) { (void) fprintf(stderr, "%s: network address limit (%d) exceeded: -i ", Pn, MAXNWAD); safestrprt(s, stderr, 1); return(1); } /* * Allocate space for the address specification. */ if ((np = (struct nwad *)malloc(sizeof(struct nwad))) == NULL) { (void) fprintf(stderr, "%s: no space for network address from: -i ", Pn); safestrprt(s, stderr, 1); return(1); } /* * Construct and link the address specification. */ *np = nc; np->sport = sp; np->eport = ep; np->f = 0; np->next = Nwad; Nwad = np; na++; /* * If the network address came from gethostbyname(), advance to * the next address; otherwise quit. */ if (!he) break; if (!(ap = (unsigned char *)he->h_addr_list[ac++])) break; #if defined(HASIPv6) { int i; for (i = 0; (i < (he->h_length - 1)) && (i < (MAX_AF_ADDR - 1)); i++) { nc.a[i] = *ap++; } nc.a[i] = *ap; } #else /* !defined(HASIPv6) */ nc.a[0] = *ap++; nc.a[1] = *ap++; nc.a[2] = *ap++; nc.a[3] = *ap; #endif /* defined(HASIPv6) */ } return(0); } #if defined(HASTCPUDPSTATE) /* * enter_state_spec() -- enter TCP and UDP state specifications */ int enter_state_spec(ss) char *ss; /* state specification string */ { char *cp, *ne, *ns, *pr; int err, d, f, i, tx, x; size_t len; static char *ssc = (char *)NULL; char *ty; /* * Check the protocol specification. */ if (!strncasecmp(ss, "tcp:", 4)) { pr = "TCP"; tx = 0; } #if !defined(USE_LIB_PRINT_TCPTPI) else if (!strncasecmp(ss, "UDP:", 4)) { pr = "UDP"; tx = 1; } #endif /* !defined(USE_LIB_PRINT_TCPTPI) */ else { (void) fprintf(stderr, "%s: unknown -s protocol: \"%s\"\n", Pn, ss); return(1); } cp = ss + 4; if (!*cp) { (void) fprintf(stderr, "%s: no %s state names in: %s\n", Pn, pr, ss); return(1); } (void) build_IPstates(); if (!(tx ? UdpSt : TcpSt)) { (void) fprintf(stderr, "%s: no %s state names available: %s\n", Pn, pr, ss); return(1); } /* * Allocate the inclusion and exclusion tables for the protocol. */ if (tx) { if (UdpNstates) { if (!UdpStI) { if (!(UdpStI = (unsigned char *)calloc((MALLOC_S)UdpNstates, sizeof(unsigned char)))) { ty = "UDP state inclusion"; no_IorX_space: (void) fprintf(stderr, "%s: no %s table space\n", Pn, ty); Exit(1); } } if (!UdpStX) { if (!(UdpStX = (unsigned char *)calloc((MALLOC_S)UdpNstates, sizeof(unsigned char)))) { ty = "UDP state exclusion"; goto no_IorX_space; } } } } else { if (TcpNstates) { if (!TcpStI) { if (!(TcpStI = (unsigned char *)calloc((MALLOC_S)TcpNstates, sizeof(unsigned char)))) { ty = "TCP state inclusion"; goto no_IorX_space; } } if (!TcpStX) { if (!(TcpStX = (unsigned char *)calloc((MALLOC_S)TcpNstates, sizeof(unsigned char)))) { ty = "TCP state exclusion"; goto no_IorX_space; } } } } /* * Convert the state names in the rest of the string to state indexes and * record them in the appropriate inclusion or exclusion table. */ if (ssc) (void) free((MALLOC_P *)ssc); if (!(ssc = mkstrcpy(cp, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no temporary state argument space for: %s\n", Pn, ss); Exit(1); } cp = ssc; err = 0; while (*cp) { /* * Determine inclusion or exclusion for this state name. */ if (*cp == '^') { x = 1; cp++; } else x = 0; /* * Find the end of the state name. Make sure it is non-null in length * and terminated with '\0'. */ ns = cp; while (*cp && (*cp != ',')) { cp++; } ne = cp; if (*cp) { *cp = '\0'; cp++; } if (!(len = (size_t)(ne - ns))) { (void) fprintf(stderr, "%s: NULL %s state name in: %s\n", Pn, pr, ss); err = 1; continue; } /* * Find the state name in the appropriate table. */ f = 0; if (tx) { if (UdpSt) { for (i = 0; i < UdpNstates; i++) { if (!strcasecmp(ns, UdpSt[i])) { f = 1; break; } } } } else { if (TcpSt) { for (i = 0; i < TcpNstates; i++) { if (!strcasecmp(ns, TcpSt[i])) { f = 1; break; } } } } if (!f) { (void) fprintf(stderr, "%s: unknown %s state name: %s\n", Pn, pr, ns); err = 1; continue; } /* * Set the inclusion or exclusion status in the appropriate table. */ d = 0; if (x) { if (tx) { if (!UdpStX[i]) { UdpStX[i] = 1; UdpStXn++; } else d = 1; } else { if (!TcpStX[i]) { TcpStX[i] = 1; TcpStXn++; } else d = 1; } } else { if (tx) { if (!UdpStI[i]) { UdpStI[i] = 1; UdpStIn++; } else d = 1; } else { if (!TcpStI[i]) { TcpStI[i] = 1; TcpStIn++; } else d = 1; } } if (d) { /* * Report a duplicate. */ (void) fprintf(stderr, "%s: duplicate %s %sclusion: %s\n", Pn, pr, x ? "ex" : "in", ns); err = 1; } } /* * Release any temporary space and return. */ if (ssc) { (void) free((MALLOC_P *)ssc); ssc = (char *)NULL; } return(err); } #endif /* defined(HASTCPUDPSTATE) */ /* * enter_str_lst() - enter a string on a list */ int enter_str_lst(opt, s, lp, incl, excl) char *opt; /* option name */ char *s; /* string to enter */ struct str_lst **lp; /* string's list */ int *incl; /* included count */ int *excl; /* excluded count */ { char *cp; short i, x; MALLOC_S len; struct str_lst *lpt; if (!s || *s == '-' || *s == '+') { (void) fprintf(stderr, "%s: missing %s option value\n", Pn, opt); return(1); } if (*s == '^') { i = 0; x = 1; s++; } else { i = 1; x = 0; } if (!(cp = mkstrcpy(s, &len))) { (void) fprintf(stderr, "%s: no string copy space: ", Pn); safestrprt(s, stderr, 1); return(1); } if ((lpt = (struct str_lst *)malloc(sizeof(struct str_lst))) == NULL) { (void) fprintf(stderr, "%s: no list space: ", Pn); safestrprt(s, stderr, 1); (void) free((FREE_P *)cp); return(1); } lpt->f = 0; lpt->str = cp; lpt->len = (int)len; lpt->x = x; if (i) *incl += 1; if (x) *excl += 1; lpt->next = *lp; *lp = lpt; return(0); } /* * enter_uid() - enter User Identifier for searching */ int enter_uid(us) char *us; /* User IDentifier string pointer */ { int err, i, j, lnml, nn; unsigned char excl; MALLOC_S len; char lnm[LOGINML+1], *lp; struct passwd *pw; char *s, *st; uid_t uid; if (!us) { (void) fprintf(stderr, "%s: no UIDs specified\n", Pn); return(1); } for (err = 0, s = us; *s;) { /* * Assemble next User IDentifier. */ for (excl = i = j = lnml = nn = uid = 0, st = s; *s && *s != ','; i++, s++) { if (lnml >= LOGINML) { while (*s && *s != ',') { s++; lnml++; } (void) fprintf(stderr, "%s: -u login name > %d characters: ", Pn, (int)LOGINML); safestrprtn(st, lnml, stderr, 1); err = j = 1; break; } if (i == 0 && *s == '^') { excl = 1; continue; } lnm[lnml++] = *s; if (nn) continue; #if defined(__STDC__) if (isdigit((unsigned char)*s)) #else /* !defined(__STDC__) */ if (isascii(*s) && isdigit((unsigned char)*s)) #endif /* defined(__STDC__) */ uid = (uid * 10) + *s - '0'; else nn++; } if (*s) s++; if (j) continue; if (nn) { lnm[lnml++] = '\0'; if ((pw = getpwnam(lnm)) == NULL) { (void) fprintf(stderr, "%s: can't get UID for ", Pn); safestrprt(lnm, stderr, 1); err = 1; continue; } else uid = pw->pw_uid; } #if defined(HASSECURITY) && !defined(HASNOSOCKSECURITY) /* * If the security mode is enabled, only the root user may list files * belonging to user IDs other than the real user ID of this lsof * process. If HASNOSOCKSECURITY is also defined, then anyone may * list anyone else's socket files. */ if (Myuid && uid != Myuid) { (void) fprintf(stderr, "%s: ID %d request rejected because of security mode.\n", Pn, uid); err = 1; continue; } #endif /* defined(HASSECURITY) && !defined(HASNOSOCKSECURITY) */ /* * Avoid entering duplicates. */ for (i = j = 0; i < Nuid; i++) { if (uid != Suid[i].uid) continue; if (Suid[i].excl == excl) { j = 1; continue; } (void) fprintf(stderr, "%s: UID %d has been included and excluded.\n", Pn, (int)uid); err = j = 1; break; } if (j) continue; /* * Allocate space for User IDentifier. */ if (Nuid >= Mxuid) { Mxuid += UIDINCR; len = (MALLOC_S)(Mxuid * sizeof(struct seluid)); if (!Suid) Suid = (struct seluid *)malloc(len); else Suid = (struct seluid *)realloc((MALLOC_P *)Suid, len); if (!Suid) { (void) fprintf(stderr, "%s: no space for UIDs", Pn); Exit(1); } } if (nn) { if (!(lp = mkstrcpy(lnm, (MALLOC_S *)NULL))) { (void) fprintf(stderr, "%s: no space for login: ", Pn); safestrprt(lnm, stderr, 1); Exit(1); } Suid[Nuid].lnm = lp; } else Suid[Nuid].lnm = (char *)NULL; Suid[Nuid].uid = uid; Suid[Nuid++].excl = excl; if (excl) Nuidexcl++; else Nuidincl++; } return(err); } /* * isIPv4addr() - is host name an IPv4 address */ static char * isIPv4addr(hn, a, al) char *hn; /* host name */ unsigned char *a; /* address receptor */ int al; /* address receptor length */ { int dc = 0; /* dot count */ int i; /* temorary index */ int ov[MIN_AF_ADDR]; /* octet values */ int ovx = 0; /* ov[] index */ /* * The host name must begin with a number and the return octet value * arguments must be acceptable. */ if ((*hn < '0') || (*hn > '9')) return((char *)NULL); if (!a || (al < MIN_AF_ADDR)) return((char *)NULL); /* * Start the first octet assembly, then parse tge remainder of the host * name for four octets, separated by dots. */ ov[0] = (int)(*hn++ - '0'); while (*hn && (*hn != ':')) { if (*hn == '.') { /* * Count a dot. Make sure a preceding octet value has been * assembled. Don't assemble more than MIN_AF_ADDR octets. */ dc++; if ((ov[ovx] < 0) || (ov[ovx] > 255)) return((char *)NULL); if (++ovx > (MIN_AF_ADDR - 1)) return((char *)NULL); ov[ovx] = -1; } else if ((*hn >= '0') && (*hn <= '9')) { /* * Assemble an octet. */ if (ov[ovx] < 0) ov[ovx] = (int)(*hn - '0'); else ov[ovx] = (ov[ovx] * 10) + (int)(*hn - '0'); } else { /* * A non-address character has been detected. */ return((char *)NULL); } hn++; } /* * Make sure there were three dots and four non-null octets. */ if ((dc != 3) || (ovx != (MIN_AF_ADDR - 1)) || (ov[ovx] < 0) || (ov[ovx] > 255)) return((char *)NULL); /* * Copy the octets as unsigned characters and return the ending host name * character position. */ for (i = 0; i < MIN_AF_ADDR; i++) { a[i] = (unsigned char)ov[i]; } return(hn); } /* * lkup_hostnm() - look up host name */ static struct hostent * lkup_hostnm(hn, n) char *hn; /* host name */ struct nwad *n; /* network address destination */ { unsigned char *ap; struct hostent *he; int ln; /* * Get hostname structure pointer. Return NULL if there is none. */ #if defined(HASIPv6) he = gethostbyname2(hn, n->af); #else /* !defined(HASIPv6) */ he = gethostbyname(hn); #endif /* defined(HASIPv6) */ if (!he) return(he); /* * Copy first hostname structure address to destination structure. */ #if defined(HASIPv6) if (n->af != he->h_addrtype) return((struct hostent *)NULL); if (n->af == AF_INET6) { /* * Copy an AF_INET6 address. */ if (he->h_length > MAX_AF_ADDR) return((struct hostent *)NULL); (void) memcpy((void *)&n->a[0], (void *)he->h_addr, he->h_length); if ((ln = MAX_AF_ADDR - he->h_length) > 0) zeromem((char *)&n->a[he->h_length], ln); return(he); } #endif /* defined(HASIPv6) */ /* * Copy an AF_INET address. */ if (he->h_length != 4) return((struct hostent *)NULL); ap = (unsigned char *)he->h_addr; n->a[0] = *ap++; n->a[1] = *ap++; n->a[2] = *ap++; n->a[3] = *ap; if ((ln = MAX_AF_ADDR - 4) > 0) zeromem((char *)&n->a[4], ln); return(he); }