1/* 2 * arg.c - common argument processing support functions for lsof 3 */ 4 5 6/* 7 * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana 8 * 47907. All rights reserved. 9 * 10 * Written by Victor A. Abell 11 * 12 * This software is not subject to any license of the American Telephone 13 * and Telegraph Company or the Regents of the University of California. 14 * 15 * Permission is granted to anyone to use this software for any purpose on 16 * any computer system, and to alter it and redistribute it freely, subject 17 * to the following restrictions: 18 * 19 * 1. Neither the authors nor Purdue University are responsible for any 20 * consequences of the use of this software. 21 * 22 * 2. The origin of this software must not be misrepresented, either by 23 * explicit claim or by omission. Credit to the authors and Purdue 24 * University must appear in documentation and sources. 25 * 26 * 3. Altered versions must be plainly marked as such, and must not be 27 * misrepresented as being the original software. 28 * 29 * 4. This notice may not be removed or altered. 30 */ 31 32#ifndef lint 33static char copyright[] = 34"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; 35static char *rcsid = "$Id: arg.c,v 1.51 2012/04/10 16:30:06 abe Exp $"; 36#endif 37 38 39#include "lsof.h" 40 41 42/* 43 * Local definitions 44 */ 45 46#define CMDRXINCR 32 /* CmdRx[] allocation increment */ 47 48 49/* 50 * Local static variables 51 */ 52 53static int NCmdRxA = 0; /* space allocated to CmdRx[] */ 54 55 56/* 57 * Local function prototypes 58 */ 59 60_PROTOTYPE(static int ckfd_range,(char *first, char *dash, char *last, int *lo, int *hi)); 61_PROTOTYPE(static int enter_fd_lst,(char *nm, int lo, int hi, int excl)); 62_PROTOTYPE(static int enter_nwad,(struct nwad *n, int sp, int ep, char *s, struct hostent *he)); 63_PROTOTYPE(static struct hostent *lkup_hostnm,(char *hn, struct nwad *n)); 64_PROTOTYPE(static char *isIPv4addr,(char *hn, unsigned char *a, int al)); 65 66 67/* 68 * ckfd_range() - check fd range 69 */ 70 71static int 72ckfd_range(first, dash, last, lo, hi) 73 char *first; /* starting character */ 74 char *dash; /* '-' location */ 75 char *last; /* '\0' location */ 76 int *lo; /* returned low value */ 77 int *hi; /* returned high value */ 78{ 79 char *cp; 80/* 81 * See if the range character pointers make sense. 82 */ 83 if (first >= dash || dash >= last) { 84 (void) fprintf(stderr, "%s: illegal FD range for -d: ", Pn); 85 safestrprt(first, stderr, 1); 86 return(1); 87 } 88/* 89 * Assemble and check the high and low values. 90 */ 91 for (cp = first, *lo = 0; *cp && cp < dash; cp++) { 92 if (!isdigit((unsigned char)*cp)) { 93 94FD_range_nondigit: 95 96 (void) fprintf(stderr, "%s: non-digit in -d FD range: ", Pn); 97 safestrprt(first, stderr, 1); 98 return(1); 99 } 100 *lo = (*lo * 10) + (int)(*cp - '0'); 101 } 102 for (cp = dash+1, *hi = 0; *cp && cp < last; cp++) { 103 if (!isdigit((unsigned char)*cp)) 104 goto FD_range_nondigit; 105 *hi = (*hi * 10) + (int)(*cp - '0'); 106 } 107 if (*lo >= *hi) { 108 (void) fprintf(stderr, "%s: -d FD range's low >= its high: ", Pn); 109 safestrprt(first, stderr, 1); 110 return(1); 111 } 112 return(0); 113} 114 115 116/* 117 * ck_file_arg() - check file arguments 118 */ 119 120int 121ck_file_arg(i, ac, av, fv, rs, sbp) 122 int i; /* first file argument index */ 123 int ac; /* argument count */ 124 char *av[]; /* argument vector */ 125 int fv; /* Ffilesys value (real or temporary) */ 126 int rs; /* Readlink() status if argument count == 1: 127 * 0 = undone; 1 = done */ 128 struct stat *sbp; /* if non-NULL, pointer to stat(2) buffer 129 * when argument count == 1 */ 130{ 131 char *ap, *fnm, *fsnm, *path; 132 short err = 0; 133 int fsm, ftype, j, k; 134 MALLOC_S l; 135 struct mounts *mp; 136 static struct mounts **mmp = (struct mounts **)NULL; 137 int mx, nm; 138 static int nma = 0; 139 struct stat sb; 140 struct sfile *sfp; 141 short ss = 0; 142 143#if defined(CKFA_EXPDEV) 144 dev_t dev, rdev; 145#endif /* defined(CKFA_EXPDEV) */ 146 147#if defined(HASPROCFS) 148 unsigned char ad, an; 149 int pfsnl = -1; 150 pid_t pid; 151 struct procfsid *pfi; 152#endif /* defined(HASPROCFS) */ 153 154/* 155 * Loop through arguments. 156 */ 157 for (; i < ac; i++) { 158 if (rs && (ac == 1) && (i == 0)) 159 path = av[i]; 160 else { 161 if (!(path = Readlink(av[i]))) { 162 ErrStat = 1; 163 continue; 164 } 165 } 166 /* 167 * Remove terminating `/' characters from paths longer than one. 168 */ 169 j = k = strlen(path); 170 while ((k > 1) && (path[k-1] == '/')) { 171 k--; 172 } 173 if (k < j) { 174 if (path != av[i]) 175 path[k] = '\0'; 176 else { 177 if (!(ap = (char *)malloc((MALLOC_S)(k + 1)))) { 178 (void) fprintf(stderr, "%s: no space for copy of %s\n", 179 Pn, path); 180 Exit(1); 181 } 182 (void) strncpy(ap, path, k); 183 ap[k] = '\0'; 184 path = ap; 185 } 186 } 187 /* 188 * Check for file system argument. 189 */ 190 for (ftype = 1, mp = readmnt(), nm = 0; 191 (fv != 1) && mp; 192 mp = mp->next) 193 { 194 fsm = 0; 195 if (strcmp(mp->dir, path) == 0) 196 fsm++; 197 else if (fv == 2 || (mp->fs_mode & S_IFMT) == S_IFBLK) { 198 if (mp->fsnmres && strcmp(mp->fsnmres, path) == 0) 199 fsm++; 200 } 201 if (!fsm) 202 continue; 203 ftype = 0; 204 /* 205 * Skip duplicates. 206 */ 207 for (mx = 0; mx < nm; mx++) { 208 if (strcmp(mp->dir, mmp[mx]->dir) == 0 209 && mp->dev == mmp[mx]->dev 210 && mp->rdev == mmp[mx]->rdev 211 && mp->inode == mmp[mx]->inode) 212 break; 213 } 214 if (mx < nm) 215 continue; 216 /* 217 * Allocate space for and save another mount point match and 218 * the type of match -- directory name (mounted) or file system 219 * name (mounted-on). 220 */ 221 if (nm >= nma) { 222 nma += 5; 223 l = (MALLOC_S)(nma * sizeof(struct mounts *)); 224 if (mmp) 225 mmp = (struct mounts **)realloc((MALLOC_P *)mmp, l); 226 else 227 mmp = (struct mounts **)malloc(l); 228 if (!mmp) { 229 (void) fprintf(stderr, 230 "%s: no space for mount pointers\n", Pn); 231 Exit(1); 232 } 233 } 234 mmp[nm++] = mp; 235 } 236 if (fv == 2 && nm == 0) { 237 (void) fprintf(stderr, "%s: not a file system: ", Pn); 238 safestrprt(av[i], stderr, 1); 239 ErrStat = 1; 240 continue; 241 } 242 /* 243 * Loop through the file system matches. If there were none, make one 244 * pass through the loop, using simply the path name. 245 */ 246 mx = 0; 247 do { 248 249 /* 250 * Allocate an sfile structure and fill in the type and link. 251 */ 252 if (!(sfp = (struct sfile *)malloc(sizeof(struct sfile)))) { 253 (void) fprintf(stderr, "%s: no space for files\n", Pn); 254 Exit(1); 255 } 256 sfp->next = Sfile; 257 Sfile = sfp; 258 sfp->f = 0; 259 if ((sfp->type = ftype)) { 260 261 /* 262 * For a non-file system path, use the path as the file name 263 * and set a NULL file system name. 264 */ 265 fnm = path; 266 fsnm = (char *)NULL; 267 /* 268 * Stat the path to obtain its characteristics. 269 */ 270 if (sbp && (ac == 1)) 271 sb = *sbp; 272 else { 273 if (statsafely(fnm, &sb) != 0) { 274 int en = errno; 275 276 (void) fprintf(stderr, "%s: status error on ", Pn); 277 safestrprt(fnm, stderr, 0); 278 (void) fprintf(stderr, ": %s\n", strerror(en)); 279 Sfile = sfp->next; 280 (void) free((FREE_P *)sfp); 281 ErrStat = 1; 282 continue; 283 } 284 285#if defined(HASSPECDEVD) 286 (void) HASSPECDEVD(fnm, &sb); 287#endif /* defined(HASSPECDEVD) */ 288 289 } 290 sfp->i = (INODETYPE)sb.st_ino; 291 sfp->mode = sb.st_mode & S_IFMT; 292 293#if defined(CKFA_EXPDEV) 294 /* 295 * Expand device numbers before saving, so that they match the 296 * already-expanded local mount info table device numbers. 297 * (This is an EP/IX 2.1.1 and above artifact.) 298 */ 299 sfp->dev = expdev(sb.st_dev); 300 sfp->rdev = expdev(sb.st_rdev); 301#else /* !defined(CKFA_EXPDEV) */ 302 sfp->dev = sb.st_dev; 303 sfp->rdev = sb.st_rdev; 304#endif /* defined(CKFA_EXPDEV) */ 305 306#if defined(CKFA_MPXCHAN) 307 /* 308 * Save a (possible) multiplexed channel number. (This is an 309 * AIX artifact.) 310 */ 311 sfp->ch = getchan(path); 312#endif /* defined(CKFA_MPXCHAN) */ 313 314 } else { 315 316#if defined(SAVE_MP_IN_SFILE) 317 sfp->mp = mp = mmp[mx++]; 318#else /* !defined(SAVE_MP_IN_SFILE) */ 319 mp = mmp[mx++]; 320#endif /* defined(SAVE_MP_IN_SFILE) */ 321 322 ss++; 323 324#if defined(HASPROCFS) 325 /* 326 * If this is a /proc file system, set the search flag and 327 * abandon the sfile entry. 328 */ 329 if (mp == Mtprocfs) { 330 Sfile = sfp->next; 331 (void) free((FREE_P *)sfp); 332 Procsrch = 1; 333 continue; 334 } 335#endif /* defined(HASPROCFS) */ 336 337 /* 338 * Derive file name and file system name for a mount point. 339 * 340 * Save the device numbers, inode number, and modes. 341 */ 342 fnm = mp->dir; 343 fsnm = mp->fsname; 344 sfp->dev = mp->dev; 345 sfp->rdev = mp->rdev; 346 sfp->i = mp->inode; 347 sfp->mode = mp->mode & S_IFMT; 348 } 349 ss = 1; /* indicate a "safe" stat() */ 350 /* 351 * Store the file name and file system name pointers in the sfile 352 * structure, allocating space as necessary. 353 */ 354 if (!fnm || fnm == path) { 355 sfp->name = fnm; 356 357#if defined(HASPROCFS) 358 an = 0; 359#endif /* defined(HASPROCFS) */ 360 361 } else { 362 if (!(sfp->name = mkstrcpy(fnm, (MALLOC_S *)NULL))) { 363 (void) fprintf(stderr, 364 "%s: no space for file name: ", Pn); 365 safestrprt(fnm, stderr, 1); 366 Exit(1); 367 } 368 369#if defined(HASPROCFS) 370 an = 1; 371#endif /* defined(HASPROCFS) */ 372 373 } 374 if (!fsnm || fsnm == path) { 375 sfp->devnm = fsnm; 376 377#if defined(HASPROCFS) 378 ad = 0; 379#endif /* defined(HASPROCFS) */ 380 381 } else { 382 if (!(sfp->devnm = mkstrcpy(fsnm, (MALLOC_S *)NULL))) { 383 (void) fprintf(stderr, 384 "%s: no space for file system name: ", Pn); 385 safestrprt(fsnm, stderr, 1); 386 Exit(1); 387 } 388 389#if defined(HASPROCFS) 390 ad = 1; 391#endif /* defined(HASPROCFS) */ 392 393 } 394 if (!(sfp->aname = mkstrcpy(av[i], (MALLOC_S *)NULL))) { 395 (void) fprintf(stderr, 396 "%s: no space for argument file name: ", Pn); 397 safestrprt(av[i], stderr, 1); 398 Exit(1); 399 } 400 401#if defined(HASPROCFS) 402 /* 403 * See if this is an individual member of a proc file system. 404 */ 405 if (!Mtprocfs || Procsrch) 406 continue; 407 408# if defined(HASFSTYPE) && HASFSTYPE==1 409 if (strcmp(sb.st_fstype, HASPROCFS) != 0) 410 continue; 411# endif /* defined(HASFSTYPE) && HASFSTYPE==1 */ 412 413 if (pfsnl == -1) 414 pfsnl = strlen(Mtprocfs->dir); 415 if (!pfsnl) 416 continue; 417 if (strncmp(Mtprocfs->dir, path, pfsnl) != 0) 418 continue; 419 if (path[pfsnl] != '/') 420 421# if defined(HASPINODEN) 422 pid = 0; 423# else /* !defined(HASPINODEN) */ 424 continue; 425# endif /* defined(HASPINODEN) */ 426 427 else { 428 for (j = pfsnl+1; path[j]; j++) { 429 if (!isdigit((unsigned char)path[j])) 430 break; 431 } 432 if (path[j] || (j - pfsnl - 1) < 1 433 || (sfp->mode & S_IFMT) != S_IFREG) 434 435# if defined(HASPINODEN) 436 pid = 0; 437# else /* !defined(HASPINODEN) */ 438 continue; 439# endif /* defined(HASPINODEN) */ 440 441 else 442 pid = atoi(&path[pfsnl+1]); 443 } 444 if (!(pfi = (struct procfsid *)malloc((MALLOC_S) 445 sizeof(struct procfsid)))) 446 { 447 (void) fprintf(stderr, "%s: no space for %s ID: ", 448 Pn, Mtprocfs->dir); 449 safestrprt(path, stderr, 1); 450 Exit(1); 451 } 452 pfi->pid = pid; 453 pfi->f = 0; 454 pfi->nm = sfp->aname; 455 pfi->next = Procfsid; 456 Procfsid = pfi; 457 458# if defined(HASPINODEN) 459 pfi->inode = (INODETYPE)sfp->i; 460# endif /* defined(HASPINODEN) */ 461 462 /* 463 * Abandon the Sfile entry, lest it be used in is_file_named(). 464 */ 465 Sfile = sfp->next; 466 if (ad) 467 (void) free((FREE_P *)sfp->devnm); 468 if (an) 469 (void) free((FREE_P *)sfp->name); 470 (void) free((FREE_P *)sfp); 471#endif /* defined(HASPROCFS) */ 472 473 } while (mx < nm); 474 } 475 if (!ss) 476 err = 1; 477 return((int)err); 478} 479 480 481#if defined(HASDCACHE) 482/* 483 * ctrl_dcache() - enter device cache control 484 */ 485 486int 487ctrl_dcache(c) 488 char *c; /* control string */ 489{ 490 int rc = 0; 491 492 if (!c) { 493 (void) fprintf(stderr, 494 "%s: no device cache option control string\n", Pn); 495 return(1); 496 } 497/* 498 * Decode argument function character. 499 */ 500 switch (*c) { 501 case '?': 502 if (*(c+1) != '\0') { 503 (void) fprintf(stderr, "%s: nothing should follow -D?\n", Pn); 504 return(1); 505 } 506 DChelp = 1; 507 return(0); 508 case 'b': 509 case 'B': 510 if (Setuidroot 511 512#if !defined(WILLDROPGID) 513 || Myuid 514#endif /* !defined(WILLDROPGID) */ 515 516 ) 517 rc = 1; 518 else 519 DCstate = 1; 520 break; 521 case 'r': 522 case 'R': 523 if (Setuidroot && *(c+1)) 524 rc = 1; 525 else 526 DCstate = 2; 527 break; 528 case 'u': 529 case 'U': 530 if (Setuidroot 531 532#if !defined(WILLDROPGID) 533 || Myuid 534#endif /* !defined(WILLDROPGID) */ 535 536 ) 537 rc = 1; 538 else 539 DCstate = 3; 540 break; 541 case 'i': 542 case 'I': 543 if (*(c+1) == '\0') { 544 DCstate = 0; 545 return(0); 546 } 547 /* fall through */ 548 default: 549 (void) fprintf(stderr, "%s: unknown -D option: ", Pn); 550 safestrprt(c, stderr, 1); 551 return(1); 552 } 553 if (rc) { 554 (void) fprintf(stderr, "%s: -D option restricted to root: ", Pn); 555 safestrprt(c, stderr, 1); 556 return(1); 557 } 558/* 559 * Skip to optional path name and save it. 560 */ 561 for (c++; *c && (*c == ' ' || *c == '\t'); c++) 562 ; 563 if (strlen(c)) { 564 if (!(DCpathArg = mkstrcpy(c, (MALLOC_S *)NULL))) { 565 (void) fprintf(stderr, "%s: no space for -D path: ", Pn); 566 safestrprt(c, stderr, 1); 567 Exit(1); 568 } 569 } 570 return(0); 571} 572#endif /* defined(HASDCACHE) */ 573 574 575/* 576 * enter_cmd_rx() - enter command regular expression 577 */ 578 579int 580enter_cmd_rx(x) 581 char *x; /* regular expression */ 582{ 583 int bmod = 0; 584 int bxmod = 0; 585 int i, re; 586 int imod = 0; 587 int xmod = 0; 588 int co = REG_NOSUB|REG_EXTENDED; 589 char reb[256], *xb, *xe, *xm; 590 MALLOC_S xl; 591 char *xp = (char *)NULL; 592/* 593 * Make sure the supplied string starts a regular expression. 594 */ 595 if (!*x || (*x != '/')) { 596 (void) fprintf(stderr, "%s: regexp doesn't begin with '/': ", Pn); 597 if (x) 598 safestrprt(x, stderr, 1); 599 return(1); 600 } 601/* 602 * Skip to the end ('/') of the regular expression. 603 */ 604 xb = x + 1; 605 for (xe = xb; *xe; xe++) { 606 if (*xe == '/') 607 break; 608 } 609 if (*xe != '/') { 610 (void) fprintf(stderr, "%s: regexp doesn't end with '/': ", Pn); 611 safestrprt(x, stderr, 1); 612 return(1); 613 } 614/* 615 * Decode any regular expression modifiers. 616 */ 617 for (i = 0, xm = xe + 1; *xm; xm++) { 618 switch(*xm) { 619 case 'b': /* This is a basic expression. */ 620 if (++bmod > 1) { 621 if (bmod == 2) { 622 (void) fprintf(stderr, 623 "%s: b regexp modifier already used: ", Pn); 624 safestrprt(x, stderr, 1); 625 } 626 i = 1; 627 } else if (xmod) { 628 if (++bxmod == 1) { 629 (void) fprintf(stderr, 630 "%s: b and x regexp modifiers conflict: ", Pn); 631 safestrprt(x, stderr, 1); 632 } 633 i = 1; 634 } else 635 co &= ~REG_EXTENDED; 636 break; 637 case 'i': /* Ignore case. */ 638 if (++imod > 1) { 639 if (imod == 2) { 640 (void) fprintf(stderr, 641 "%s: i regexp modifier already used: ", Pn); 642 safestrprt(x, stderr, 1); 643 } 644 i = 1; 645 } else 646 co |= REG_ICASE; 647 break; 648 case 'x': /* This is an extended expression. */ 649 if (++xmod > 1) { 650 if (xmod == 2) { 651 (void) fprintf(stderr, 652 "%s: x regexp modifier already used: ", Pn); 653 safestrprt(x, stderr, 1); 654 } 655 i = 1; 656 } else if (bmod) { 657 if (++bxmod == 1) { 658 (void) fprintf(stderr, 659 "%s: b and x regexp modifiers conflict: ", Pn); 660 safestrprt(x, stderr, 1); 661 } 662 i = 1; 663 } else 664 co |= REG_EXTENDED; 665 break; 666 default: 667 (void) fprintf(stderr, "%s: invalid regexp modifier: %c\n", 668 Pn, (int)*xm); 669 i = 1; 670 } 671 } 672 if (i) 673 return(1); 674/* 675 * Allocate space to hold expression and copy it there. 676 */ 677 xl = (MALLOC_S)(xe - xb); 678 if (!(xp = (char *)malloc(xl + 1))) { 679 (void) fprintf(stderr, "%s: no regexp space for: ", Pn); 680 safestrprt(x, stderr, 1); 681 Exit(1); 682 } 683 (void) strncpy(xp, xb, xl); 684 xp[(int)xl] = '\0'; 685/* 686 * Assign a new CmdRx[] slot for this expression. 687 */ 688 if (NCmdRxA >= NCmdRxU) { 689 690 /* 691 * More CmdRx[] space must be assigned. 692 */ 693 NCmdRxA += CMDRXINCR; 694 xl = (MALLOC_S)(NCmdRxA * sizeof(lsof_rx_t)); 695 if (CmdRx) 696 CmdRx = (lsof_rx_t *)realloc((MALLOC_P *)CmdRx, xl); 697 else 698 CmdRx = (lsof_rx_t *)malloc(xl); 699 if (!CmdRx) { 700 (void) fprintf(stderr, "%s: no space for regexp: ", Pn); 701 safestrprt(x, stderr, 1); 702 Exit(1); 703 } 704 } 705 i = NCmdRxU; 706 CmdRx[i].exp = xp; 707/* 708 * Compile the expression. 709 */ 710 if ((re = regcomp(&CmdRx[i].cx, xp, co))) { 711 (void) fprintf(stderr, "%s: regexp error: ", Pn); 712 safestrprt(x, stderr, 0); 713 (void) regerror(re, &CmdRx[i].cx, &reb[0], sizeof(reb)); 714 (void) fprintf(stderr, ": %s\n", reb); 715 if (xp) { 716 (void) free((FREE_P *)xp); 717 xp = (char *)NULL; 718 } 719 return(1); 720 } 721/* 722 * Complete the CmdRx[] table entry. 723 */ 724 CmdRx[i].mc = 0; 725 CmdRx[i].exp = xp; 726 NCmdRxU++; 727 return(0); 728} 729 730 731#if defined(HASEOPT) 732/* 733 * enter_efsys() -- enter path of file system whose kernel blocks are to be 734 * eliminated 735 */ 736 737int 738enter_efsys(e, rdlnk) 739 char *e; /* file system path */ 740 int rdlnk; /* avoid readlink(2) if non-zero */ 741{ 742 char *ec; /* pointer to copy of path */ 743 efsys_list_t *ep; /* file system path list pointer */ 744 int i; /* temporary index */ 745 char *path; /* Readlink() of file system path */ 746 747 if (!e || (*e != '/')) { 748 if (!Fwarn) 749 (void) fprintf(stderr, 750 "%s: -e not followed by a file system path: \"%s\"\n", 751 Pn, e); 752 return(1); 753 } 754 if (!(ec = mkstrcpy(e, (MALLOC_S *)NULL))) { 755 (void) fprintf(stderr, "%s: no space for -e string: ", Pn); 756 safestrprt(e, stderr, 1); 757 Exit(1); 758 } 759 if (rdlnk) 760 path = ec; 761 else { 762 if (!(path = Readlink(ec))) 763 return(1); 764 } 765/* 766 * Remove terminating `/' characters from paths longer than one. 767 */ 768 for (i = (int)strlen(path); (i > 1) && (path[i - 1] == '/'); i--) { 769 path[i - 1] = '\0'; 770 } 771/* 772 * Enter file system path on list, avoiding duplicates. 773 */ 774 for (ep = Efsysl; ep; ep = ep->next) { 775 if (!strcmp(ep->path, path)) 776 return(0); 777 } 778 if (!(ep = (efsys_list_t *)malloc((MALLOC_S)(sizeof(efsys_list_t))))) { 779 (void) fprintf(stderr, "%s: no space for \"-e %s\" entry\n", 780 Pn, e); 781 Exit(1); 782 } 783 ep->path = path; 784 ep->pathl = i; 785 ep->rdlnk = rdlnk; 786 ep->mp = (struct mounts *)NULL; 787 ep->next = Efsysl; 788 Efsysl = ep; 789 return(0); 790} 791#endif /* defined(HASEOPT) */ 792 793 794/* 795 * enter_fd() - enter file descriptor list for searching 796 */ 797 798int 799enter_fd(f) 800 char *f; /* file descriptor list pointer */ 801{ 802 char c, *cp1, *cp2, *dash; 803 int err, excl, hi, lo; 804 char *fc; 805/* 806 * Check for non-empty list and make a copy. 807 */ 808 if (!f || (strlen(f) + 1) < 2) { 809 (void) fprintf(stderr, "%s: no file descriptor specified\n", Pn); 810 return(1); 811 } 812 if (!(fc = mkstrcpy(f, (MALLOC_S *)NULL))) { 813 (void) fprintf(stderr, "%s: no space for fd string: ", Pn); 814 safestrprt(f, stderr, 1); 815 Exit(1); 816 } 817/* 818 * Isolate each file descriptor in the comma-separated list, then enter it 819 * in the file descriptor string list. If a descriptor has the form: 820 * 821 * [0-9]+-[0-9]+ 822 * 823 * treat it as an ascending range of file descriptor numbers. 824 * 825 * Accept a leading '^' as an excusion on match. 826 */ 827 for (cp1 = fc, err = 0; *cp1;) { 828 if (*cp1 == '^') { 829 excl = 1; 830 cp1++; 831 } else 832 excl = 0; 833 for (cp2 = cp1, dash = (char *)NULL; *cp2 && *cp2 != ','; cp2++) { 834 if (*cp2 == '-') 835 dash = cp2; 836 } 837 if ((c = *cp2) != '\0') 838 *cp2 = '\0'; 839 if (cp2 > cp1) { 840 if (dash) { 841 if (ckfd_range(cp1, dash, cp2, &lo, &hi)) 842 err = 1; 843 else { 844 if (enter_fd_lst((char *)NULL, lo, hi, excl)) 845 err = 1; 846 } 847 } else { 848 if (enter_fd_lst(cp1, 0, 0, excl)) 849 err = 1; 850 } 851 } 852 if (c == '\0') 853 break; 854 cp1 = cp2 + 1; 855 } 856 (void) free((FREE_P *)fc); 857 return(err); 858} 859 860 861/* 862 * enter_fd_lst() - make an entry in the FD list, Fdl 863 */ 864 865static int 866enter_fd_lst(nm, lo, hi, excl) 867 char *nm; /* FD name (none if NULL) */ 868 int lo; /* FD low boundary (if nm NULL) */ 869 int hi; /* FD high boundary (if nm NULL) */ 870 int excl; /* exclusion on match */ 871{ 872 char buf[256], *cp; 873 int n; 874 struct fd_lst *f, *ft; 875/* 876 * Don't allow a mixture of exclusions and inclusions. 877 */ 878 if (FdlTy >= 0) { 879 if (FdlTy != excl) { 880 if (!Fwarn) { 881 882 /* 883 * If warnings are enabled, report a mixture. 884 */ 885 if (nm) { 886 (void) snpf(buf, sizeof(buf) - 1, "%s%s", 887 excl ? "^" : "", nm); 888 } else { 889 if (lo != hi) { 890 (void) snpf(buf, sizeof(buf) - 1, "%s%d-%d", 891 excl ? "^" : "", lo, hi); 892 } else { 893 (void) snpf(buf, sizeof(buf) - 1, "%s%d", 894 excl ? "^" : "", lo); 895 } 896 } 897 buf[sizeof(buf) - 1] = '\0'; 898 (void) fprintf(stderr, 899 "%s: %s in an %s -d list: %s\n", Pn, 900 excl ? "exclude" : "include", 901 FdlTy ? "exclude" : "include", 902 buf); 903 } 904 return(1); 905 } 906 } 907/* 908 * Allocate an fd_lst entry. 909 */ 910 if (!(f = (struct fd_lst *)malloc((MALLOC_S)sizeof(struct fd_lst)))) { 911 (void) fprintf(stderr, "%s: no space for FD list entry\n", Pn); 912 Exit(1); 913 } 914 if (nm) { 915 916 /* 917 * Process an FD name. First see if it contains only digits; if it 918 * does, convert them to an integer and set the low and high 919 * boundaries to the result. 920 * 921 * If the name has a non-digit, store it as a string, and set the 922 * boundaries to impossible values (i.e., low > high). 923 */ 924 for (cp = nm, n = 0; *cp; cp++) { 925 if (!isdigit((unsigned char)*cp)) 926 break; 927 n = (n * 10) + (int)(*cp - '0'); 928 } 929 if (*cp) { 930 if (!(f->nm = mkstrcpy(nm, (MALLOC_S *)NULL))) { 931 (void) fprintf(stderr, 932 "%s: no space for copy of: %s\n", Pn, nm); 933 Exit(1); 934 } 935 lo = 1; 936 hi = 0; 937 } else { 938 f->nm = (char *)NULL; 939 lo = hi = n; 940 } 941 } else 942 f->nm = (char *)NULL; 943/* 944 * Skip duplicates. 945 */ 946 for (ft = Fdl; ft; ft = ft->next) { 947 if (f->nm) { 948 if (!ft->nm || strcmp(f->nm, ft->nm)) 949 continue; 950 } else if ((lo != ft->lo) || (hi != ft->hi)) 951 continue; 952 (void) free((FREE_P *)f); 953 return(0); 954 } 955/* 956 * Complete the fd_lst entry and link it to the head of the chain. 957 */ 958 f->hi = hi; 959 f->lo = lo; 960 f->next = Fdl; 961 Fdl = f; 962 FdlTy = excl; 963 return(0); 964} 965 966 967/* 968 * enter_dir() - enter the files of a directory for searching 969 */ 970 971#define EDDEFFNL 128 /* default file name length */ 972 973int 974enter_dir(d, descend) 975 char *d; /* directory path name pointer */ 976 int descend; /* subdirectory descend flag: 977 * 0 = don't descend 978 * 1 = descend */ 979{ 980 char *av[2]; 981 dev_t ddev; 982 DIR *dfp; 983 char *dn = (char *)NULL; 984 MALLOC_S dnl, dnamlen; 985 struct DIRTYPE *dp; 986 int en, sl; 987 int fct = 0; 988 char *fp = (char *)NULL; 989 MALLOC_S fpl = (MALLOC_S)0; 990 MALLOC_S fpli = (MALLOC_S)0; 991 struct stat sb; 992/* 993 * Check the directory path; reduce symbolic links; stat(2) it; make sure it's 994 * really a directory. 995 */ 996 if (!d || !*d || *d == '+' || *d == '-') { 997 if (!Fwarn) 998 (void) fprintf(stderr, 999 "%s: +d not followed by a directory path\n", Pn); 1000 return(1); 1001 } 1002 if (!(dn = Readlink(d))) 1003 return(1); 1004 if (statsafely(dn, &sb)) { 1005 if (!Fwarn) { 1006 en = errno; 1007 (void) fprintf(stderr, "%s: WARNING: can't stat(", Pn); 1008 safestrprt(dn, stderr, 0); 1009 (void) fprintf(stderr, "): %s\n", strerror(en)); 1010 } 1011 if (dn && dn != d) { 1012 (void) free((FREE_P *)dn); 1013 dn = (char *)NULL; 1014 } 1015 return(1); 1016 } 1017 if ((sb.st_mode & S_IFMT) != S_IFDIR) { 1018 if (!Fwarn) { 1019 (void) fprintf(stderr, "%s: WARNING: not a directory: ", Pn); 1020 safestrprt(dn, stderr, 1); 1021 } 1022 if (dn && dn != d) { 1023 (void) free((FREE_P *)dn); 1024 dn = (char *)NULL; 1025 } 1026 return(1); 1027 } 1028 1029#if defined(HASSPECDEVD) 1030 (void) HASSPECDEVD(dn, &sb); 1031#endif /* defined(HASSPECDEVD) */ 1032 1033 ddev = sb.st_dev; 1034/* 1035 * Stack the directory and record it in Sfile for searching. 1036 */ 1037 Dstkn = Dstkx = 0; 1038 Dstk = (char **)NULL; 1039 (void) stkdir(dn); 1040 av[0] = (dn == d) ? mkstrcpy(dn, (MALLOC_S *)NULL) : dn; 1041 av[1] = (char *)NULL; 1042 dn = (char *)NULL; 1043 if (!ck_file_arg(0, 1, av, 1, 1, &sb)) { 1044 av[0] = (char *)NULL; 1045 fct++; 1046 } 1047/* 1048 * Unstack the next directory and examine it. 1049 */ 1050 while (--Dstkx >= 0) { 1051 if (!(dn = Dstk[Dstkx])) 1052 continue; 1053 Dstk[Dstkx] = (char *)NULL; 1054 /* 1055 * Open the directory path and prepare its name for use with the 1056 * files in the directory. 1057 */ 1058 if (!(dfp = OpenDir(dn))) { 1059 if (!Fwarn) { 1060 if ((en = errno) != ENOENT) { 1061 (void) fprintf(stderr, 1062 "%s: WARNING: can't opendir(", Pn); 1063 safestrprt(dn, stderr, 0); 1064 (void) fprintf(stderr, "): %s\n", strerror(en)); 1065 } 1066 } 1067 (void) free((FREE_P *)dn); 1068 dn = (char *)NULL; 1069 continue; 1070 } 1071 dnl = strlen(dn); 1072 sl = ((dnl > 0) && (*(dn + dnl - 1) == '/')) ? 0 : 1; 1073 /* 1074 * Define space for possible addition to the directory path. 1075 */ 1076 fpli = (MALLOC_S)(dnl + sl + EDDEFFNL + 1); 1077 if ((int)fpli > (int)fpl) { 1078 fpl = fpli; 1079 if (!fp) 1080 fp = (char *)malloc(fpl); 1081 else 1082 fp = (char *)realloc(fp, fpl); 1083 if (!fp) { 1084 (void) fprintf(stderr, 1085 "%s: no space for path to entries in directory: %s\n", 1086 Pn, dn); 1087 Exit(1); 1088 } 1089 } 1090 (void) snpf(fp, (size_t)fpl, "%s%s", dn, sl ? "/" : ""); 1091 (void) free((FREE_P *)dn); 1092 dn = (char *)NULL; 1093 /* 1094 * Read the contents of the directory. 1095 */ 1096 for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) { 1097 1098 /* 1099 * Skip: entries with no inode number; 1100 * entries with a zero length name; 1101 * "."; 1102 * and "..". 1103 */ 1104 if (!dp->d_ino) 1105 continue; 1106 1107#if defined(HASDNAMLEN) 1108 dnamlen = (MALLOC_S)dp->d_namlen; 1109#else /* !defined(HASDNAMLEN) */ 1110 dnamlen = (MALLOC_S)strlen(dp->d_name); 1111#endif /* defined(HASDNAMLEN) */ 1112 1113 if (!dnamlen) 1114 continue; 1115 if (dnamlen <= 2 && dp->d_name[0] == '.') { 1116 if (dnamlen == 1) 1117 continue; 1118 if (dp->d_name[1] == '.') 1119 continue; 1120 } 1121 /* 1122 * Form the entry's path name. 1123 */ 1124 fpli = (MALLOC_S)(dnamlen - (fpl - dnl - sl - 1)); 1125 if ((int)fpli > 0) { 1126 fpl += fpli; 1127 if (!(fp = (char *)realloc(fp, fpl))) { 1128 (void) fprintf(stderr, "%s: no space for: ", Pn); 1129 safestrprt(dn, stderr, 0); 1130 putc('/', stderr); 1131 safestrprtn(dp->d_name, dnamlen, stderr, 1); 1132 Exit(1); 1133 } 1134 } 1135 (void) strncpy(fp + dnl + sl, dp->d_name, dnamlen); 1136 fp[dnl + sl + dnamlen] = '\0'; 1137 /* 1138 * Lstatsafely() the entry; complain if that fails. 1139 * 1140 * Stack entries that represent subdirectories. 1141 */ 1142 if (lstatsafely(fp, &sb)) { 1143 if ((en = errno) != ENOENT) { 1144 if (!Fwarn) { 1145 (void) fprintf(stderr, 1146 "%s: WARNING: can't lstat(", Pn); 1147 safestrprt(fp, stderr, 0); 1148 (void) fprintf(stderr, "): %s\n", strerror(en)); 1149 } 1150 } 1151 continue; 1152 } 1153 1154#if defined(HASSPECDEVD) 1155 (void) HASSPECDEVD(fp, &sb); 1156#endif /* defined(HASSPECDEVD) */ 1157 1158 if (!(Fxover & XO_FILESYS)) { 1159 1160 /* 1161 * Unless "-x" or "-x f" was specified, don't cross over file 1162 * system mount points. 1163 */ 1164 if (sb.st_dev != ddev) 1165 continue; 1166 } 1167 if ((sb.st_mode & S_IFMT) == S_IFLNK) { 1168 1169 /* 1170 * If this is a symbolic link and "-x_ or "-x l" was specified, 1171 * Statsafely() the entry and process it. 1172 * 1173 * Otherwise skip symbolic links. 1174 */ 1175 if (Fxover & XO_SYMLINK) { 1176 if (statsafely(fp, &sb)) { 1177 if ((en = errno) != ENOENT) { 1178 if (!Fwarn) { 1179 (void) fprintf(stderr, 1180 "%s: WARNING: can't stat(", Pn); 1181 safestrprt(fp, stderr, 0); 1182 (void) fprintf(stderr, 1183 ") symbolc link: %s\n", strerror(en)); 1184 } 1185 } 1186 continue; 1187 } 1188 } else 1189 continue; 1190 } 1191 if (av[0]) { 1192 (void) free((FREE_P *)av[0]); 1193 av[0] = (char *)NULL; 1194 } 1195 av[0] = mkstrcpy(fp, (MALLOC_S *)NULL); 1196 if ((sb.st_mode & S_IFMT) == S_IFDIR && descend) 1197 1198 /* 1199 * Stack a subdirectory according to the descend argument. 1200 */ 1201 stkdir(av[0]); 1202 /* 1203 * Use ck_file_arg() to record the entry for searching. Force it 1204 * to consider the entry a file, not a file system. 1205 */ 1206 if (!ck_file_arg(0, 1, av, 1, 1, &sb)) { 1207 av[0] = (char *)NULL; 1208 fct++; 1209 } 1210 } 1211 (void) CloseDir(dfp); 1212 if (dn && dn != d) { 1213 (void) free((FREE_P *)dn); 1214 dn = (char *)NULL; 1215 } 1216 } 1217/* 1218 * Free malloc()'d space. 1219 */ 1220 if (dn && dn != d) { 1221 (void) free((FREE_P *)dn); 1222 dn = (char *)NULL; 1223 } 1224 if (av[0] && av[0] != fp) { 1225 (void) free((FREE_P *)av[0]); 1226 av[0] = (char *)NULL; 1227 } 1228 if (fp) { 1229 (void) free((FREE_P *)fp); 1230 fp = (char *)NULL; 1231 } 1232 if (Dstk) { 1233 (void) free((FREE_P *)Dstk); 1234 Dstk = (char **)NULL; 1235 } 1236 if (!fct) { 1237 1238 /* 1239 * Warn if no files were recorded for searching. 1240 */ 1241 if (!Fwarn) { 1242 (void) fprintf(stderr, 1243 "%s: WARNING: no files found in directory: ", Pn); 1244 safestrprt(d, stderr, 1); 1245 } 1246 return(1); 1247 } 1248 return(0); 1249} 1250 1251 1252/* 1253 * enter_id() - enter PGID or PID for searching 1254 */ 1255 1256int 1257enter_id(ty, p) 1258 enum IDType ty; /* type: PGID or PID */ 1259 char *p; /* process group ID string pointer */ 1260{ 1261 char *cp; 1262 int err, i, id, j, mx, n, ni, nx, x; 1263 struct int_lst *s; 1264 1265 if (!p) { 1266 (void) fprintf(stderr, "%s: no process%s ID specified\n", 1267 Pn, (ty == PGID) ? " group" : ""); 1268 return(1); 1269 } 1270/* 1271 * Set up variables for the type of ID. 1272 */ 1273 switch (ty) { 1274 case PGID: 1275 mx = Mxpgid; 1276 n = Npgid; 1277 ni = Npgidi; 1278 nx = Npgidx; 1279 s = Spgid; 1280 break; 1281 case PID: 1282 mx = Mxpid; 1283 n = Npid; 1284 ni = Npidi; 1285 nx = Npidx; 1286 s = Spid; 1287 break; 1288 default: 1289 (void) fprintf(stderr, "%s: enter_id \"", Pn); 1290 safestrprt(p, stderr, 0); 1291 (void) fprintf(stderr, "\", invalid type: %d\n", ty); 1292 Exit(1); 1293 } 1294/* 1295 * Convert and store the ID. 1296 */ 1297 for (cp = p, err = 0; *cp;) { 1298 1299 /* 1300 * Assemble ID. 1301 */ 1302 for (i = id = x = 0; *cp && *cp != ','; cp++) { 1303 if (!i) { 1304 i = 1; 1305 if (*cp == '^') { 1306 x = 1; 1307 continue; 1308 } 1309 } 1310 1311#if defined(__STDC__) 1312 if (!isdigit((unsigned char)*cp)) 1313#else /* !defined(__STDC__) */ 1314 if (!isascii(*cp) || ! isdigit((unsigned char)*cp)) 1315#endif /* __STDC__ */ 1316 1317 { 1318 (void) fprintf(stderr, "%s: illegal process%s ID: ", 1319 Pn, (ty == PGID) ? " group" : ""); 1320 safestrprt(p, stderr, 1); 1321 return(1); 1322 } 1323 id = (id * 10) + *cp - '0'; 1324 } 1325 if (*cp) 1326 cp++; 1327 /* 1328 * Avoid entering duplicates and conflicts. 1329 */ 1330 for (i = j = 0; i < n; i++) { 1331 if (id == s[i].i) { 1332 if (x == s[i].x) { 1333 j = 1; 1334 continue; 1335 } 1336 (void) fprintf(stderr, 1337 "%s: P%sID %d has been included and excluded.\n", 1338 Pn, 1339 (ty == PGID) ? "G" : "", 1340 id); 1341 err = j = 1; 1342 break; 1343 } 1344 } 1345 if (j) 1346 continue; 1347 /* 1348 * Allocate table table space. 1349 */ 1350 if (n >= mx) { 1351 mx += IDINCR; 1352 if (!s) 1353 s = (struct int_lst *)malloc( 1354 (MALLOC_S)(sizeof(struct int_lst) * mx)); 1355 else 1356 s = (struct int_lst *)realloc((MALLOC_P *)s, 1357 (MALLOC_S)(sizeof(struct int_lst) * mx)); 1358 if (!s) { 1359 (void) fprintf(stderr, "%s: no space for %d process%s IDs", 1360 Pn, mx, (ty == PGID) ? " group" : ""); 1361 Exit(1); 1362 } 1363 } 1364 s[n].f = 0; 1365 s[n].i = id; 1366 s[n++].x = x; 1367 if (x) 1368 nx++; 1369 else 1370 ni++; 1371 } 1372/* 1373 * Save variables for the type of ID. 1374 */ 1375 if (ty == PGID) { 1376 Mxpgid = mx; 1377 Npgid = n; 1378 Npgidi = ni; 1379 Npgidx = nx; 1380 Spgid = s; 1381 } else { 1382 Mxpid = mx; 1383 Npid = Npuns = n; 1384 Npidi = ni; 1385 Npidx = nx; 1386 Spid = s; 1387 } 1388 return(err); 1389} 1390 1391 1392/* 1393 * enter_network_address() - enter Internet address for searching 1394 */ 1395 1396int 1397enter_network_address(na) 1398 char *na; /* Internet address string pointer */ 1399{ 1400 int ae, i, pr; 1401 int ep = -1; 1402 int ft = 0; 1403 struct hostent *he = (struct hostent *)NULL; 1404 char *hn = (char *)NULL; 1405 MALLOC_S l; 1406 struct nwad n; 1407 char *p, *wa; 1408 int pt = 0; 1409 int pu = 0; 1410 struct servent *se, *se1; 1411 char *sn = (char *)NULL; 1412 int sp = -1; 1413 MALLOC_S snl = 0; 1414 1415#if defined(HASIPv6) 1416 char *cp; 1417#endif /* defined(HASIPv6) */ 1418 1419 if (!na) { 1420 (void) fprintf(stderr, "%s: no network address specified\n", Pn); 1421 return(1); 1422 } 1423 zeromem((char *)&n, sizeof(n)); 1424 wa = na; 1425/* 1426 * Process an IP version type specification, IPv4 or IPv6, optionally followed 1427 * by a '@' and a host name or Internet address, or a ':' and a service name or 1428 * port number. 1429 */ 1430 if ((*wa == '4') || (*wa == '6')) { 1431 if (*wa == '4') 1432 ft = 4; 1433 else if (*wa == '6') { 1434 1435#if defined(HASIPv6) 1436 ft = 6; 1437#else /* !defined(HASIPv6) */ 1438 (void) fprintf(stderr, "%s: IPv6 not supported: -i ", Pn); 1439 safestrprt(na, stderr, 1); 1440 goto nwad_exit; 1441#endif /* defined(HASIPv6) */ 1442 1443 } 1444 wa++; 1445 if (!*wa) { 1446 1447 /* 1448 * If nothing follows 4 or 6, then all network files of the 1449 * specified IP version are selected. Sequential -i, -i4, and 1450 * -i6 specifications interact logically -- e.g., -i[46] followed 1451 * by -i[64] is the same as -i. 1452 */ 1453 if (!Fnet) { 1454 Fnet = 1; 1455 FnetTy = ft; 1456 } else { 1457 if (FnetTy) { 1458 if (FnetTy != ft) 1459 FnetTy = 0; 1460 } else 1461 FnetTy = ft; 1462 } 1463 return(0); 1464 } 1465 } else if (Fnet) 1466 ft = FnetTy; 1467/* 1468 * If an IP version has been specified, use it to set the address family. 1469 */ 1470 switch (ft) { 1471 case 4: 1472 n.af = AF_INET; 1473 break; 1474 1475#if defined(HASIPv6) 1476 case 6: 1477 n.af = AF_INET6; 1478 break; 1479#endif /* defined(HASIPv6) */ 1480 1481 } 1482/* 1483 * Process protocol name, optionally followed by a '@' and a host name or 1484 * Internet address, or a ':' and a service name or port number. 1485 */ 1486 if (*wa && *wa != '@' && *wa != ':') { 1487 for (p = wa; *wa && *wa != '@' && *wa != ':'; wa++) 1488 ; 1489 if ((l = wa - p)) { 1490 if (!(n.proto = mkstrcat(p, l, (char *)NULL, -1, (char *)NULL, 1491 -1, (MALLOC_S *)NULL))) 1492 { 1493 (void) fprintf(stderr, 1494 "%s: no space for protocol name from: -i ", Pn); 1495 safestrprt(na, stderr, 1); 1496nwad_exit: 1497 if (n.proto) 1498 (void) free((FREE_P *)n.proto); 1499 if (hn) 1500 (void) free((FREE_P *)hn); 1501 if (sn) 1502 (void) free((FREE_P *)sn); 1503 return(1); 1504 } 1505 /* 1506 * The protocol name should be "tcp", "udp" or "udplite". 1507 */ 1508 if ((strcasecmp(n.proto, "tcp") != 0) 1509 && (strcasecmp(n.proto, "udp") != 0) 1510 && (strcasecmp(n.proto, "udplite") != 0)) 1511 { 1512 (void) fprintf(stderr, 1513 "%s: unknown protocol name (%s) in: -i ", Pn, n.proto); 1514 safestrprt(na, stderr, 1); 1515 goto nwad_exit; 1516 } 1517 /* 1518 * Convert protocol name to lower case. 1519 */ 1520 for (p = n.proto; *p; p++) { 1521 if (*p >= 'A' && *p <= 'Z') 1522 *p = *p - 'A' + 'a'; 1523 } 1524 } 1525 } 1526/* 1527 * Process an IPv4 address (1.2.3.4), IPv6 address ([1:2:3:4:5:6:7:8]), 1528 * or host name, preceded by a '@' and optionally followed by a colon 1529 * and a service name or port number. 1530 */ 1531 if (*wa == '@') { 1532 wa++; 1533 if (!*wa || *wa == ':') { 1534 1535#if defined(HASIPv6) 1536unacc_address: 1537#endif /* defined(HASIPv6) */ 1538 1539 (void) fprintf(stderr, 1540 "%s: unacceptable Internet address in: -i ", Pn); 1541 safestrprt(na, stderr, 1); 1542 goto nwad_exit; 1543 } 1544 1545 if ((p = isIPv4addr(wa, n.a, sizeof(n.a)))) { 1546 1547 /* 1548 * Process IPv4 address. 1549 */ 1550 if (ft == 6) { 1551 (void) fprintf(stderr, 1552 "%s: IPv4 addresses are prohibited: -i ", Pn); 1553 safestrprt(na, stderr, 1); 1554 goto nwad_exit; 1555 } 1556 wa = p; 1557 n.af = AF_INET; 1558 } else if (*wa == '[') { 1559 1560#if defined(HASIPv6) 1561 /* 1562 * Make sure IPv6 addresses are permitted. If they are, assemble 1563 * one. 1564 */ 1565 if (ft == 4) { 1566 (void) fprintf(stderr, 1567 "%s: IPv6 addresses are prohibited: -i ", Pn); 1568 safestrprt(na, stderr, 1); 1569 goto nwad_exit; 1570 } 1571 if (!(cp = strrchr(++wa, ']'))) 1572 goto unacc_address; 1573 *cp = '\0'; 1574 i = inet_pton(AF_INET6, wa, (void *)&n.a); 1575 *cp = ']'; 1576 if (i != 1) 1577 goto unacc_address; 1578 for (ae = i = 0; i < MAX_AF_ADDR; i++) { 1579 if ((ae |= n.a[i])) 1580 break; 1581 } 1582 if (!ae) 1583 goto unacc_address; 1584 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)&n.a[0])) { 1585 if (ft == 6) { 1586 (void) fprintf(stderr, 1587 "%s: IPv4 addresses are prohibited: -i ", Pn); 1588 safestrprt(na, stderr, 1); 1589 goto nwad_exit; 1590 } 1591 for (i = 0; i < 4; i++) { 1592 n.a[i] = n.a[i+12]; 1593 } 1594 n.af = AF_INET; 1595 } else 1596 n.af = AF_INET6; 1597 wa = cp + 1; 1598#else /* !defined(HASIPv6) */ 1599 (void) fprintf(stderr, 1600 "%s: unsupported IPv6 address in: -i ", Pn); 1601 safestrprt(na, stderr, 1); 1602 goto nwad_exit; 1603#endif /* defined(HASIPv6) */ 1604 1605 } else { 1606 1607 /* 1608 * Assemble host name. 1609 */ 1610 for (p = wa; *p && *p != ':'; p++) 1611 ; 1612 if ((l = p - wa)) { 1613 if (!(hn = mkstrcat(wa, l, (char *)NULL, -1, (char *)NULL, 1614 -1, (MALLOC_S *)NULL))) 1615 { 1616 (void) fprintf(stderr, 1617 "%s: no space for host name: -i ", Pn); 1618 safestrprt(na, stderr, 1); 1619 goto nwad_exit; 1620 } 1621 1622#if defined(HASIPv6) 1623 1624 /* 1625 * If no IP version has been specified, look up an IPv6 host 1626 * name first. If that fails, look up an IPv4 host name. 1627 * 1628 * If the IPv6 version has been specified, look up the host 1629 * name only under its IP version specification. 1630 */ 1631 if (!ft) 1632 n.af = AF_INET6; 1633 if (!(he = lkup_hostnm(hn, &n)) && !ft) { 1634 n.af = AF_INET; 1635 he = lkup_hostnm(hn, &n); 1636 } 1637#else /* !defined(HASIPv6) */ 1638 if (!ft) 1639 n.af = AF_INET; 1640 he = lkup_hostnm(hn, &n); 1641#endif /* defined(HASIPv6) */ 1642 1643 if (!he) { 1644 fprintf(stderr, "%s: unknown host name (%s) in: -i ", 1645 Pn, hn); 1646 safestrprt(na, stderr, 1); 1647 goto nwad_exit; 1648 } 1649 } 1650 wa = p; 1651 } 1652 } 1653/* 1654 * If there is no port number, enter the address. 1655 */ 1656 if (!*wa) 1657 goto nwad_enter; 1658/* 1659 * Process a service name or port number list, preceded by a colon. 1660 * 1661 * Entries of the list are separated with commas; elements of a numeric range 1662 * are specified with a separating minus sign (`-'); all service names must 1663 * belong to the same protocol; embedded spaces are not allowed. An embedded 1664 * minus sign in a name is taken to be part of the name, the starting entry 1665 * of a range can't be a service name. 1666 */ 1667 if (*wa != ':' || *(wa + 1) == '\0') { 1668 1669unacc_port: 1670 (void) fprintf(stderr, 1671 "%s: unacceptable port specification in: -i ", Pn); 1672 safestrprt(na, stderr, 1); 1673 goto nwad_exit; 1674 } 1675 for (++wa; wa && *wa; wa++) { 1676 for (ep = pr = sp = 0; *wa; wa++) { 1677 if (*wa < '0' || *wa > '9') { 1678 1679 /* 1680 * Convert service name to port number, using already-specified 1681 * protocol name. A '-' is taken to be part of the name; hence 1682 * the starting entry of a range can't be a service name. 1683 */ 1684 for (p = wa; *wa && *wa != ','; wa++) 1685 ; 1686 if (!(l = wa - p)) { 1687 (void) fprintf(stderr, 1688 "%s: invalid service name: -i ", Pn); 1689 safestrprt(na, stderr, 1); 1690 goto nwad_exit; 1691 } 1692 if (sn) { 1693 if (l > snl) { 1694 sn = (char *)realloc((MALLOC_P *)sn, l + 1); 1695 snl = l; 1696 } 1697 } else { 1698 sn = (char *)malloc(l + 1); 1699 snl = l; 1700 } 1701 if (!sn) { 1702 (void) fprintf(stderr, 1703 "%s: no space for service name: -i ", Pn); 1704 safestrprt(na, stderr, 1); 1705 goto nwad_exit; 1706 } 1707 (void) strncpy(sn, p, l); 1708 *(sn + l) = '\0'; 1709 if (n.proto) { 1710 1711 /* 1712 * If the protocol has been specified, look up the port 1713 * number for the service name for the specified protocol. 1714 */ 1715 if (!(se = getservbyname(sn, n.proto))) { 1716 (void) fprintf(stderr, 1717 "%s: unknown service %s for %s in: -i ", 1718 Pn, sn, n.proto); 1719 safestrprt(na, stderr, 1); 1720 goto nwad_exit; 1721 } 1722 pt = (int)ntohs(se->s_port); 1723 } else { 1724 1725 /* 1726 * If no protocol has been specified, look up the port 1727 * numbers for the service name for both TCP and UDP. 1728 */ 1729 if((se = getservbyname(sn, "tcp"))) 1730 pt = (int)ntohs(se->s_port); 1731 if ((se1 = getservbyname(sn, "udp"))) 1732 pu = (int)ntohs(se1->s_port); 1733 if (!se && !se1) { 1734 (void) fprintf(stderr, 1735 "%s: unknown service %s in: -i ", Pn, sn); 1736 safestrprt(na, stderr, 1); 1737 goto nwad_exit; 1738 } 1739 if (se && se1 && pt != pu) { 1740 (void) fprintf(stderr, 1741 "%s: TCP=%d and UDP=%d %s ports conflict;\n", 1742 Pn, pt, pu, sn); 1743 (void) fprintf(stderr, 1744 " specify \"tcp:%s\" or \"udp:%s\": -i ", 1745 sn, sn); 1746 safestrprt(na, stderr, 1); 1747 goto nwad_exit; 1748 } 1749 if (!se && se1) 1750 pt = pu; 1751 } 1752 if (pr) 1753 ep = pt; 1754 else { 1755 sp = pt; 1756 if (*wa == '-') 1757 pr++; 1758 } 1759 } else { 1760 1761 /* 1762 * Assemble port number. 1763 */ 1764 for (; *wa && *wa != ','; wa++) { 1765 if (*wa == '-') { 1766 if (pr) 1767 goto unacc_port; 1768 pr++; 1769 break; 1770 } 1771 if (*wa < '0' || *wa > '9') 1772 goto unacc_port; 1773 if (pr) 1774 ep = (ep * 10) + *wa - '0'; 1775 else 1776 sp = (sp * 10) + *wa - '0'; 1777 } 1778 } 1779 if (!*wa || *wa == ',') 1780 break; 1781 if (pr) 1782 continue; 1783 goto unacc_port; 1784 } 1785 if (!pr) 1786 ep = sp; 1787 if (ep < sp) 1788 goto unacc_port; 1789 /* 1790 * Enter completed port or port range specification. 1791 */ 1792 1793nwad_enter: 1794 1795 for (i = 1; i;) { 1796 if (enter_nwad(&n, sp, ep, na, he)) 1797 goto nwad_exit; 1798 1799#if defined(HASIPv6) 1800 /* 1801 * If IPv6 is enabled, a host name was specified, and the 1802 * associated * address is for the AF_INET6 address family, 1803 * try to get and address for the AF_INET family, too, unless 1804 * IPv4 is prohibited. 1805 */ 1806 if (hn && (n.af == AF_INET6) && (ft != 6)) { 1807 n.af = AF_INET; 1808 if ((he = lkup_hostnm(hn, &n))) 1809 continue; 1810 } 1811#endif /* defined(HASIPv6) */ 1812 1813 i = 0; 1814 } 1815 if (!*wa) 1816 break; 1817 } 1818 if (sn) 1819 (void) free((FREE_P *)sn); 1820 return(0); 1821} 1822 1823/* 1824 * enter_nwad() - enter nwad structure 1825 */ 1826 1827static int 1828enter_nwad(n, sp, ep, s, he) 1829 struct nwad *n; /* pointer to partially completed 1830 * nwad (less port) */ 1831 int sp; /* starting port number */ 1832 int ep; /* ending port number */ 1833 char *s; /* string that states the address */ 1834 struct hostent *he; /* pointer to hostent struct from which 1835 * network address came */ 1836{ 1837 int ac; 1838 unsigned char *ap; 1839 static int na = 0; 1840 struct nwad nc; 1841 struct nwad *np; 1842/* 1843 * Allocate space for the argument specification. 1844 */ 1845 if (strlen(s)) { 1846 if (!(n->arg = mkstrcpy(s, (MALLOC_S *)NULL))) { 1847 (void) fprintf(stderr, 1848 "%s: no space for Internet argument: -i ", Pn); 1849 safestrprt(s, stderr, 1); 1850 Exit(1); 1851 } 1852 } else 1853 n->arg = (char *)NULL; 1854/* 1855 * Loop through all hostent addresses. 1856 */ 1857 for (ac = 1, nc = *n;;) { 1858 1859 /* 1860 * Test address specification -- it must contain at least one of: 1861 * protocol, Internet address or port. If correct, link into search 1862 * list. 1863 */ 1864 if (!nc.proto 1865 && !nc.a[0] && !nc.a[1] && !nc.a[2] && !nc.a[3] 1866 1867#if defined(HASIPv6) 1868 && (nc.af != AF_INET6 1869 || (!nc.a[4] && !nc.a[5] && !nc.a[6] && !nc.a[7] 1870 && !nc.a[8] && !nc.a[9] && !nc.a[10] && !nc.a[11] 1871 && !nc.a[12] && !nc.a[13] && !nc.a[14] && !nc.a[15])) 1872#endif /* defined(HASIPv6) */ 1873 1874 && sp == -1) { 1875 (void) fprintf(stderr, 1876 "%s: incomplete Internet address specification: -i ", Pn); 1877 safestrprt(s, stderr, 1); 1878 return(1); 1879 } 1880 /* 1881 * Limit the network address chain length to MAXNWAD for reasons of 1882 * search efficiency. 1883 */ 1884 if (na >= MAXNWAD) { 1885 (void) fprintf(stderr, 1886 "%s: network address limit (%d) exceeded: -i ", 1887 Pn, MAXNWAD); 1888 safestrprt(s, stderr, 1); 1889 return(1); 1890 } 1891 /* 1892 * Allocate space for the address specification. 1893 */ 1894 if ((np = (struct nwad *)malloc(sizeof(struct nwad))) == NULL) { 1895 (void) fprintf(stderr, 1896 "%s: no space for network address from: -i ", Pn); 1897 safestrprt(s, stderr, 1); 1898 return(1); 1899 } 1900 /* 1901 * Construct and link the address specification. 1902 */ 1903 *np = nc; 1904 np->sport = sp; 1905 np->eport = ep; 1906 np->f = 0; 1907 np->next = Nwad; 1908 Nwad = np; 1909 na++; 1910 /* 1911 * If the network address came from gethostbyname(), advance to 1912 * the next address; otherwise quit. 1913 */ 1914 if (!he) 1915 break; 1916 if (!(ap = (unsigned char *)he->h_addr_list[ac++])) 1917 break; 1918 1919#if defined(HASIPv6) 1920 { 1921 int i; 1922 1923 for (i = 0; 1924 (i < (he->h_length - 1)) && (i < (MAX_AF_ADDR - 1)); 1925 i++) 1926 { 1927 nc.a[i] = *ap++; 1928 } 1929 nc.a[i] = *ap; 1930 } 1931#else /* !defined(HASIPv6) */ 1932 nc.a[0] = *ap++; 1933 nc.a[1] = *ap++; 1934 nc.a[2] = *ap++; 1935 nc.a[3] = *ap; 1936#endif /* defined(HASIPv6) */ 1937 1938 } 1939 return(0); 1940} 1941 1942 1943#if defined(HASTCPUDPSTATE) 1944/* 1945 * enter_state_spec() -- enter TCP and UDP state specifications 1946 */ 1947 1948int 1949enter_state_spec(ss) 1950 char *ss; /* state specification string */ 1951{ 1952 char *cp, *ne, *ns, *pr; 1953 int err, d, f, i, tx, x; 1954 size_t len; 1955 static char *ssc = (char *)NULL; 1956 char *ty; 1957/* 1958 * Check the protocol specification. 1959 */ 1960 if (!strncasecmp(ss, "tcp:", 4)) { 1961 pr = "TCP"; 1962 tx = 0; 1963 } 1964 1965#if !defined(USE_LIB_PRINT_TCPTPI) 1966 else if (!strncasecmp(ss, "UDP:", 4)) { 1967 pr = "UDP"; 1968 tx = 1; 1969 } 1970 1971#endif /* !defined(USE_LIB_PRINT_TCPTPI) */ 1972 1973 else { 1974 (void) fprintf(stderr, "%s: unknown -s protocol: \"%s\"\n", 1975 Pn, ss); 1976 return(1); 1977 } 1978 cp = ss + 4; 1979 if (!*cp) { 1980 (void) fprintf(stderr, "%s: no %s state names in: %s\n", 1981 Pn, pr, ss); 1982 return(1); 1983 } 1984 (void) build_IPstates(); 1985 if (!(tx ? UdpSt : TcpSt)) { 1986 (void) fprintf(stderr, "%s: no %s state names available: %s\n", 1987 Pn, pr, ss); 1988 return(1); 1989 } 1990/* 1991 * Allocate the inclusion and exclusion tables for the protocol. 1992 */ 1993 if (tx) { 1994 if (UdpNstates) { 1995 if (!UdpStI) { 1996 if (!(UdpStI = (unsigned char *)calloc((MALLOC_S)UdpNstates, 1997 sizeof(unsigned char)))) 1998 { 1999 ty = "UDP state inclusion"; 2000 2001no_IorX_space: 2002 2003 (void) fprintf(stderr, "%s: no %s table space\n", 2004 Pn, ty); 2005 Exit(1); 2006 } 2007 } 2008 if (!UdpStX) { 2009 if (!(UdpStX = (unsigned char *)calloc((MALLOC_S)UdpNstates, 2010 sizeof(unsigned char)))) 2011 { 2012 ty = "UDP state exclusion"; 2013 goto no_IorX_space; 2014 } 2015 } 2016 } 2017 } else { 2018 if (TcpNstates) { 2019 if (!TcpStI) { 2020 if (!(TcpStI = (unsigned char *)calloc((MALLOC_S)TcpNstates, 2021 sizeof(unsigned char)))) 2022 { 2023 ty = "TCP state inclusion"; 2024 goto no_IorX_space; 2025 } 2026 } 2027 if (!TcpStX) { 2028 if (!(TcpStX = (unsigned char *)calloc((MALLOC_S)TcpNstates, 2029 sizeof(unsigned char)))) 2030 { 2031 ty = "TCP state exclusion"; 2032 goto no_IorX_space; 2033 } 2034 } 2035 } 2036 } 2037/* 2038 * Convert the state names in the rest of the string to state indexes and 2039 * record them in the appropriate inclusion or exclusion table. 2040 */ 2041 if (ssc) 2042 (void) free((MALLOC_P *)ssc); 2043 if (!(ssc = mkstrcpy(cp, (MALLOC_S *)NULL))) { 2044 (void) fprintf(stderr, 2045 "%s: no temporary state argument space for: %s\n", Pn, ss); 2046 Exit(1); 2047 } 2048 cp = ssc; 2049 err = 0; 2050 while (*cp) { 2051 2052 /* 2053 * Determine inclusion or exclusion for this state name. 2054 */ 2055 if (*cp == '^') { 2056 x = 1; 2057 cp++; 2058 } else 2059 x = 0; 2060 /* 2061 * Find the end of the state name. Make sure it is non-null in length 2062 * and terminated with '\0'. 2063 */ 2064 ns = cp; 2065 while (*cp && (*cp != ',')) { 2066 cp++; 2067 } 2068 ne = cp; 2069 if (*cp) { 2070 *cp = '\0'; 2071 cp++; 2072 } 2073 if (!(len = (size_t)(ne - ns))) { 2074 (void) fprintf(stderr, "%s: NULL %s state name in: %s\n", 2075 Pn, pr, ss); 2076 err = 1; 2077 continue; 2078 } 2079 /* 2080 * Find the state name in the appropriate table. 2081 */ 2082 f = 0; 2083 if (tx) { 2084 if (UdpSt) { 2085 for (i = 0; i < UdpNstates; i++) { 2086 if (!strcasecmp(ns, UdpSt[i])) { 2087 f = 1; 2088 break; 2089 } 2090 } 2091 } 2092 } else { 2093 if (TcpSt) { 2094 for (i = 0; i < TcpNstates; i++) { 2095 if (!strcasecmp(ns, TcpSt[i])) { 2096 f = 1; 2097 break; 2098 } 2099 } 2100 } 2101 } 2102 if (!f) { 2103 (void) fprintf(stderr, "%s: unknown %s state name: %s\n", 2104 Pn, pr, ns); 2105 err = 1; 2106 continue; 2107 } 2108 /* 2109 * Set the inclusion or exclusion status in the appropriate table. 2110 */ 2111 d = 0; 2112 if (x) { 2113 if (tx) { 2114 if (!UdpStX[i]) { 2115 UdpStX[i] = 1; 2116 UdpStXn++; 2117 } else 2118 d = 1; 2119 } else { 2120 if (!TcpStX[i]) { 2121 TcpStX[i] = 1; 2122 TcpStXn++; 2123 } else 2124 d = 1; 2125 } 2126 } else { 2127 if (tx) { 2128 if (!UdpStI[i]) { 2129 UdpStI[i] = 1; 2130 UdpStIn++; 2131 } else 2132 d = 1; 2133 } else { 2134 if (!TcpStI[i]) { 2135 TcpStI[i] = 1; 2136 TcpStIn++; 2137 } else 2138 d = 1; 2139 } 2140 } 2141 if (d) { 2142 2143 /* 2144 * Report a duplicate. 2145 */ 2146 (void) fprintf(stderr, "%s: duplicate %s %sclusion: %s\n", 2147 Pn, pr, 2148 x ? "ex" : "in", 2149 ns); 2150 err = 1; 2151 } 2152 } 2153/* 2154 * Release any temporary space and return. 2155 */ 2156 if (ssc) { 2157 (void) free((MALLOC_P *)ssc); 2158 ssc = (char *)NULL; 2159 } 2160 return(err); 2161} 2162#endif /* defined(HASTCPUDPSTATE) */ 2163 2164 2165/* 2166 * enter_str_lst() - enter a string on a list 2167 */ 2168 2169int 2170enter_str_lst(opt, s, lp, incl, excl) 2171 char *opt; /* option name */ 2172 char *s; /* string to enter */ 2173 struct str_lst **lp; /* string's list */ 2174 int *incl; /* included count */ 2175 int *excl; /* excluded count */ 2176{ 2177 char *cp; 2178 short i, x; 2179 MALLOC_S len; 2180 struct str_lst *lpt; 2181 2182 if (!s || *s == '-' || *s == '+') { 2183 (void) fprintf(stderr, "%s: missing %s option value\n", 2184 Pn, opt); 2185 return(1); 2186 } 2187 if (*s == '^') { 2188 i = 0; 2189 x = 1; 2190 s++; 2191 } else { 2192 i = 1; 2193 x = 0; 2194 } 2195 if (!(cp = mkstrcpy(s, &len))) { 2196 (void) fprintf(stderr, "%s: no string copy space: ", Pn); 2197 safestrprt(s, stderr, 1); 2198 return(1); 2199 } 2200 if ((lpt = (struct str_lst *)malloc(sizeof(struct str_lst))) == NULL) { 2201 (void) fprintf(stderr, "%s: no list space: ", Pn); 2202 safestrprt(s, stderr, 1); 2203 (void) free((FREE_P *)cp); 2204 return(1); 2205 } 2206 lpt->f = 0; 2207 lpt->str = cp; 2208 lpt->len = (int)len; 2209 lpt->x = x; 2210 if (i) 2211 *incl += 1; 2212 if (x) 2213 *excl += 1; 2214 lpt->next = *lp; 2215 *lp = lpt; 2216 return(0); 2217} 2218 2219 2220/* 2221 * enter_uid() - enter User Identifier for searching 2222 */ 2223 2224int 2225enter_uid(us) 2226 char *us; /* User IDentifier string pointer */ 2227{ 2228 int err, i, j, lnml, nn; 2229 unsigned char excl; 2230 MALLOC_S len; 2231 char lnm[LOGINML+1], *lp; 2232 struct passwd *pw; 2233 char *s, *st; 2234 uid_t uid; 2235 2236 if (!us) { 2237 (void) fprintf(stderr, "%s: no UIDs specified\n", Pn); 2238 return(1); 2239 } 2240 for (err = 0, s = us; *s;) { 2241 2242 /* 2243 * Assemble next User IDentifier. 2244 */ 2245 for (excl = i = j = lnml = nn = uid = 0, st = s; 2246 *s && *s != ','; 2247 i++, s++) 2248 { 2249 if (lnml >= LOGINML) { 2250 while (*s && *s != ',') { 2251 s++; 2252 lnml++; 2253 } 2254 (void) fprintf(stderr, 2255 "%s: -u login name > %d characters: ", Pn, 2256 (int)LOGINML); 2257 safestrprtn(st, lnml, stderr, 1); 2258 err = j = 1; 2259 break; 2260 } 2261 if (i == 0 && *s == '^') { 2262 excl = 1; 2263 continue; 2264 } 2265 lnm[lnml++] = *s; 2266 if (nn) 2267 continue; 2268 2269#if defined(__STDC__) 2270 if (isdigit((unsigned char)*s)) 2271#else /* !defined(__STDC__) */ 2272 if (isascii(*s) && isdigit((unsigned char)*s)) 2273#endif /* defined(__STDC__) */ 2274 2275 uid = (uid * 10) + *s - '0'; 2276 else 2277 nn++; 2278 } 2279 if (*s) 2280 s++; 2281 if (j) 2282 continue; 2283 if (nn) { 2284 lnm[lnml++] = '\0'; 2285 if ((pw = getpwnam(lnm)) == NULL) { 2286 (void) fprintf(stderr, "%s: can't get UID for ", Pn); 2287 safestrprt(lnm, stderr, 1); 2288 err = 1; 2289 continue; 2290 } else 2291 uid = pw->pw_uid; 2292 } 2293 2294#if defined(HASSECURITY) && !defined(HASNOSOCKSECURITY) 2295 /* 2296 * If the security mode is enabled, only the root user may list files 2297 * belonging to user IDs other than the real user ID of this lsof 2298 * process. If HASNOSOCKSECURITY is also defined, then anyone may 2299 * list anyone else's socket files. 2300 */ 2301 if (Myuid && uid != Myuid) { 2302 (void) fprintf(stderr, 2303 "%s: ID %d request rejected because of security mode.\n", 2304 Pn, uid); 2305 err = 1; 2306 continue; 2307 } 2308#endif /* defined(HASSECURITY) && !defined(HASNOSOCKSECURITY) */ 2309 2310 /* 2311 * Avoid entering duplicates. 2312 */ 2313 for (i = j = 0; i < Nuid; i++) { 2314 if (uid != Suid[i].uid) 2315 continue; 2316 if (Suid[i].excl == excl) { 2317 j = 1; 2318 continue; 2319 } 2320 (void) fprintf(stderr, 2321 "%s: UID %d has been included and excluded.\n", 2322 Pn, (int)uid); 2323 err = j = 1; 2324 break; 2325 } 2326 if (j) 2327 continue; 2328 /* 2329 * Allocate space for User IDentifier. 2330 */ 2331 if (Nuid >= Mxuid) { 2332 Mxuid += UIDINCR; 2333 len = (MALLOC_S)(Mxuid * sizeof(struct seluid)); 2334 if (!Suid) 2335 Suid = (struct seluid *)malloc(len); 2336 else 2337 Suid = (struct seluid *)realloc((MALLOC_P *)Suid, len); 2338 if (!Suid) { 2339 (void) fprintf(stderr, "%s: no space for UIDs", Pn); 2340 Exit(1); 2341 } 2342 } 2343 if (nn) { 2344 if (!(lp = mkstrcpy(lnm, (MALLOC_S *)NULL))) { 2345 (void) fprintf(stderr, "%s: no space for login: ", Pn); 2346 safestrprt(lnm, stderr, 1); 2347 Exit(1); 2348 } 2349 Suid[Nuid].lnm = lp; 2350 } else 2351 Suid[Nuid].lnm = (char *)NULL; 2352 Suid[Nuid].uid = uid; 2353 Suid[Nuid++].excl = excl; 2354 if (excl) 2355 Nuidexcl++; 2356 else 2357 Nuidincl++; 2358 } 2359 return(err); 2360} 2361 2362 2363/* 2364 * isIPv4addr() - is host name an IPv4 address 2365 */ 2366 2367static char * 2368isIPv4addr(hn, a, al) 2369 char *hn; /* host name */ 2370 unsigned char *a; /* address receptor */ 2371 int al; /* address receptor length */ 2372{ 2373 int dc = 0; /* dot count */ 2374 int i; /* temorary index */ 2375 int ov[MIN_AF_ADDR]; /* octet values */ 2376 int ovx = 0; /* ov[] index */ 2377/* 2378 * The host name must begin with a number and the return octet value 2379 * arguments must be acceptable. 2380 */ 2381 if ((*hn < '0') || (*hn > '9')) 2382 return((char *)NULL); 2383 if (!a || (al < MIN_AF_ADDR)) 2384 return((char *)NULL); 2385/* 2386 * Start the first octet assembly, then parse tge remainder of the host 2387 * name for four octets, separated by dots. 2388 */ 2389 ov[0] = (int)(*hn++ - '0'); 2390 while (*hn && (*hn != ':')) { 2391 if (*hn == '.') { 2392 2393 /* 2394 * Count a dot. Make sure a preceding octet value has been 2395 * assembled. Don't assemble more than MIN_AF_ADDR octets. 2396 */ 2397 dc++; 2398 if ((ov[ovx] < 0) || (ov[ovx] > 255)) 2399 return((char *)NULL); 2400 if (++ovx > (MIN_AF_ADDR - 1)) 2401 return((char *)NULL); 2402 ov[ovx] = -1; 2403 } else if ((*hn >= '0') && (*hn <= '9')) { 2404 2405 /* 2406 * Assemble an octet. 2407 */ 2408 if (ov[ovx] < 0) 2409 ov[ovx] = (int)(*hn - '0'); 2410 else 2411 ov[ovx] = (ov[ovx] * 10) + (int)(*hn - '0'); 2412 } else { 2413 2414 /* 2415 * A non-address character has been detected. 2416 */ 2417 return((char *)NULL); 2418 } 2419 hn++; 2420 } 2421/* 2422 * Make sure there were three dots and four non-null octets. 2423 */ 2424 if ((dc != 3) 2425 || (ovx != (MIN_AF_ADDR - 1)) 2426 || (ov[ovx] < 0) || (ov[ovx] > 255)) 2427 return((char *)NULL); 2428/* 2429 * Copy the octets as unsigned characters and return the ending host name 2430 * character position. 2431 */ 2432 for (i = 0; i < MIN_AF_ADDR; i++) { 2433 a[i] = (unsigned char)ov[i]; 2434 } 2435 return(hn); 2436} 2437 2438 2439/* 2440 * lkup_hostnm() - look up host name 2441 */ 2442 2443static struct hostent * 2444lkup_hostnm(hn, n) 2445 char *hn; /* host name */ 2446 struct nwad *n; /* network address destination */ 2447{ 2448 unsigned char *ap; 2449 struct hostent *he; 2450 int ln; 2451/* 2452 * Get hostname structure pointer. Return NULL if there is none. 2453 */ 2454 2455#if defined(HASIPv6) 2456 he = gethostbyname2(hn, n->af); 2457#else /* !defined(HASIPv6) */ 2458 he = gethostbyname(hn); 2459#endif /* defined(HASIPv6) */ 2460 2461 if (!he) 2462 return(he); 2463/* 2464 * Copy first hostname structure address to destination structure. 2465 */ 2466 2467#if defined(HASIPv6) 2468 if (n->af != he->h_addrtype) 2469 return((struct hostent *)NULL); 2470 if (n->af == AF_INET6) { 2471 2472 /* 2473 * Copy an AF_INET6 address. 2474 */ 2475 if (he->h_length > MAX_AF_ADDR) 2476 return((struct hostent *)NULL); 2477 (void) memcpy((void *)&n->a[0], (void *)he->h_addr, he->h_length); 2478 if ((ln = MAX_AF_ADDR - he->h_length) > 0) 2479 zeromem((char *)&n->a[he->h_length], ln); 2480 return(he); 2481 } 2482#endif /* defined(HASIPv6) */ 2483 2484/* 2485 * Copy an AF_INET address. 2486 */ 2487 if (he->h_length != 4) 2488 return((struct hostent *)NULL); 2489 ap = (unsigned char *)he->h_addr; 2490 n->a[0] = *ap++; 2491 n->a[1] = *ap++; 2492 n->a[2] = *ap++; 2493 n->a[3] = *ap; 2494 if ((ln = MAX_AF_ADDR - 4) > 0) 2495 zeromem((char *)&n->a[4], ln); 2496 return(he); 2497} 2498