1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * nlsadmin.c -- control program for the network listener service 32 * 33 * This program replaces a previous version of nlsadmin. 34 * 35 * This version of nlsadmin works with the service access facility to 36 * control the network listener. The functionality of the SVR3.2 nlsadmin 37 * command is supported through calls to the more general sacadm and pmadm 38 * commands available through SAF. Users should migrate away from nlsadmin 39 * to sacadm and pmadm for these functions. 40 * 41 * The -m option of the SVR3.2 nlsadmin command is now ignored. 42 * 43 * The -t option associates an address with service code 1 (same as in SVR3.2). 44 * The -l option associates an address with service code 0. 45 * 46 * nlsadmin also contains new functionality -- the ability to format a 47 * "listener-specific" string to put in the _pmtab database. This 48 * functionality is required by SAF. 49 */ 50 51 #include <sys/types.h> 52 #include <sys/stat.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <ctype.h> 56 #include <errno.h> 57 #include <string.h> 58 #include <sac.h> 59 #include "nlsadmin.h" 60 61 #define OPTIONS "a:c:d:e:ikl:mo:p:qr:st:vw:xy:z:A:N:VDR:" 62 #ifndef FALSE 63 #define TRUE 1 64 #define FALSE 0 65 #endif 66 /* 67 * defines for -q exit codes: QZERO is used for conditions that the 68 * man page documents as returning 0, QONE for those that return 1 69 */ 70 #define QZERO 0 71 #define QONE 1 72 73 /* 74 * defines for simulated standard error format code 75 */ 76 #define MM_NOSEV 0 77 #define MM_HALT 1 78 #define MM_ERROR 2 79 #define MM_WARNING 3 80 #define MM_INFO 4 81 82 char *Nlsname; /* set to argv[0] */ 83 char Label[25]; /* label component for fmtmsg */ 84 int Quietflag = FALSE; /* set to TRUE when -q used */ 85 86 extern int errno; 87 void nlsmesg(); 88 uid_t geteuid(); 89 char *nexttok(); 90 char *pflags(); 91 char *gencmdstr(); 92 93 struct svcfields { 94 char *pmtag; 95 char *pmtype; 96 char *svc_code; 97 char *flags; 98 char *id; 99 char *res1; 100 char *res2; 101 char *res3; 102 char *addr; 103 char *rpc; 104 char *lflags; 105 char *modules; 106 char *command; 107 char *comment; 108 }; 109 110 void no_permission(void) __NORETURN; 111 void usage(int flag); 112 113 int 114 main(int argc, char **argv) 115 { 116 extern char *optarg; 117 extern int optind; 118 int c; /* used for return from getopt */ 119 char *addrptr = NULL; /* set when -A address is used */ 120 char *rpcptr = NULL; /* set when -R rpcinfo is used */ 121 char *cmdptr = NULL; /* set with -c command */ 122 char *comptr = NULL; /* set with -y comment (old) */ 123 char *idptr = NULL; /* set with -w id (old) */ 124 char *lptr = NULL; /* set with -l addr (old) */ 125 char *moduleptr = NULL; /* set with -m modules */ 126 char *pipeptr = NULL; /* set with -o pipe */ 127 char *svcptr = NULL; /* set when service code used (old) */ 128 char *tptr = NULL; /* set when -t addr used (old) */ 129 char *netspec = NULL; /* set to the network specification */ 130 int flag = 0; /* bit flag of type of command */ 131 int exitcode = 0; /* exit status of this command */ 132 int lflags = 0; /* listener flags */ 133 char buf[BUFSIZ]; /* temp buffer #1 */ 134 char mesg[BUFSIZ]; /* temp buffer #2 */ 135 FILE *fp; /* used for checking netspec */ 136 char *ptr; /* temp pointer */ 137 char *ptr2; /* temp pointer */ 138 int sawsep = 0; /* flag for RPC separator */ 139 140 Nlsname = argv[0]; 141 sprintf(Label, "UX:%.14s", argv[0]); /* for standard message fmt */ 142 143 while ((c = getopt(argc, argv, OPTIONS)) != -1) { 144 switch (c) { 145 case 'a': 146 if ( (flag && (flag != CMDFLAG)) || svcptr || Quietflag 147 || addrptr || rpcptr || lflags) 148 usage(INCONSISTENT); 149 svcptr = optarg; 150 break; 151 case 'c': 152 if ( (flag && (flag != CMDFLAG)) || cmdptr || Quietflag ) 153 usage(INCONSISTENT); 154 cmdptr = optarg; 155 flag |= CMDFLAG; 156 break; 157 case 'd': 158 if ( flag || svcptr || Quietflag || comptr || addrptr 159 || rpcptr || cmdptr || idptr || lflags ) 160 usage(INCONSISTENT); 161 svcptr = optarg; 162 flag |= DISFLAG; 163 break; 164 case 'e': 165 if ( flag || svcptr || Quietflag || comptr || addrptr 166 || rpcptr || cmdptr || idptr || lflags ) 167 usage(INCONSISTENT); 168 svcptr = optarg; 169 flag |= ENAFLAG; 170 break; 171 case 'i': 172 if ( flag || svcptr || Quietflag || comptr || addrptr 173 || rpcptr || cmdptr || idptr || lflags ) 174 usage(INCONSISTENT); 175 flag |= INIFLAG; 176 break; 177 case 'k': 178 if ( flag || svcptr || Quietflag || comptr || addrptr 179 || rpcptr || cmdptr || idptr || lflags ) 180 usage(INCONSISTENT); 181 flag |= KILFLAG; 182 break; 183 case 'l': 184 if ( ( flag && (flag != ADRFLAG)) || svcptr || lptr 185 || Quietflag || comptr || addrptr || rpcptr 186 || cmdptr || idptr || lflags ) 187 usage(INCONSISTENT); 188 lptr = optarg; 189 flag |= ADRFLAG; 190 break; 191 case 'm': 192 if ( (flag && (flag != CMDFLAG)) || Quietflag || rpcptr || lflags ) 193 usage(INCONSISTENT); 194 flag |= CMDFLAG; 195 break; 196 case 'o': 197 if ( flag || svcptr || Quietflag || comptr || idptr || netspec ) 198 usage(INCONSISTENT); 199 pipeptr = optarg; 200 flag |= PIPFLAG; 201 break; 202 case 'p': 203 if ( (flag && (flag != CMDFLAG) && (flag != PIPFLAG)) || Quietflag ) 204 usage(INCONSISTENT); 205 moduleptr = optarg; 206 break; 207 case 'q': 208 if ( (flag && (flag != ZZZFLAG)) || Quietflag || comptr 209 || rpcptr || lflags || idptr ) 210 usage(INCONSISTENT); 211 Quietflag = TRUE; 212 break; 213 case 'r': 214 if ( flag || svcptr || Quietflag || comptr || addrptr 215 || rpcptr || cmdptr || idptr || lflags ) 216 usage(INCONSISTENT); 217 flag |= REMFLAG; 218 svcptr = optarg; 219 break; 220 case 's': 221 if ( flag || svcptr || Quietflag || comptr || addrptr 222 || rpcptr || cmdptr || idptr || lflags ) 223 usage(INCONSISTENT); 224 flag |= STAFLAG; 225 break; 226 case 't': 227 if ( (flag && (flag != ADRFLAG)) || svcptr || tptr 228 || Quietflag || comptr || addrptr || rpcptr 229 || cmdptr || idptr || lflags ) 230 usage(INCONSISTENT); 231 tptr = optarg; 232 flag |= ADRFLAG; 233 break; 234 case 'v': 235 if ( flag || svcptr || Quietflag || comptr || rpcptr 236 || addrptr || idptr || lflags ) 237 usage(INCONSISTENT); 238 flag |= VBSFLAG; 239 break; 240 case 'w': 241 if ( (flag && (flag != CMDFLAG)) || Quietflag || idptr 242 || rpcptr || addrptr || lflags ) 243 usage(INCONSISTENT); 244 idptr = optarg; 245 break; 246 case 'x': 247 if ( flag || svcptr || Quietflag || netspec || comptr 248 || rpcptr || addrptr || lflags || idptr ) 249 usage(INCONSISTENT); 250 flag |= NETFLAG; 251 break; 252 case 'y': 253 if ( (flag && (flag != CMDFLAG)) || Quietflag || comptr 254 || rpcptr || addrptr || lflags ) 255 usage(INCONSISTENT); 256 comptr = optarg; 257 break; 258 case 'z': 259 if ( flag || svcptr || comptr || addrptr || rpcptr 260 || idptr || lflags ) 261 usage(INCONSISTENT); 262 flag |= ZZZFLAG; 263 svcptr = optarg; 264 break; 265 case 'A': 266 if ( (flag && (flag != CMDFLAG) && (flag != PIPFLAG)) 267 || netspec || svcptr || idptr || comptr ) 268 usage(INCONSISTENT); 269 addrptr = optarg; 270 break; 271 case 'D': 272 if ( (flag && (flag != CMDFLAG) && (flag != PIPFLAG)) 273 || netspec || svcptr || idptr || comptr || addrptr 274 || lflags ) 275 usage(INCONSISTENT); 276 lflags |= DFLAG; 277 break; 278 case 'N': 279 if ( netspec ) 280 usage(INCONSISTENT); 281 netspec = optarg; 282 break; 283 case 'R': 284 if ( (flag && (flag != CMDFLAG) && (flag != PIPFLAG)) 285 || netspec || svcptr || idptr || comptr ) 286 usage(INCONSISTENT); 287 for (ptr = optarg; *ptr; ++ptr) { 288 if ((*ptr == ':') && !sawsep) { 289 /* 290 * skip separator - note that if 291 * separator has been seen, it's not 292 * a digit so it will generate a usage 293 * message below like we want 294 */ 295 sawsep++; 296 continue; 297 } 298 if (!isdigit(*ptr)) 299 usage(USAGE); 300 } 301 ptr = strchr(optarg, ':'); 302 if (ptr) 303 /* change the ':' to a ',' */ 304 *ptr = ','; 305 else 306 usage(USAGE); 307 rpcptr = optarg; 308 break; 309 case 'V': 310 if ( flag || svcptr || Quietflag || comptr || netspec 311 || rpcptr || addrptr || idptr || lflags ) 312 usage(INCONSISTENT); 313 flag |= VERFLAG; 314 break; 315 case '?': 316 usage(USAGE); 317 } 318 /* NOTREACHED */ 319 } 320 321 if ((optind < argc) && ! netspec) 322 netspec = argv[optind++]; 323 if (optind < argc) 324 usage(USAGE); 325 326 327 /* determine if this command requires a netspec */ 328 if (flag != CMDFLAG) { 329 /* if flag is CMDFLAG, more complicated checking of netspec 330 * is done below in switch 331 */ 332 if ((flag == PIPFLAG || flag == VERFLAG || flag == NETFLAG)) { 333 if (netspec) 334 usage(USAGE); 335 } 336 else if (!netspec) 337 usage(USAGE); 338 } 339 340 if (netspec && (flag != INIFLAG)) { 341 sprintf(buf, SAC_LSPM, netspec); 342 343 if ((fp = popen(buf, "r")) == NULL) { 344 nlsmesg(MM_ERROR, "System error"); 345 exit(NLS_SYSERR); 346 } 347 348 if (fgets(buf, BUFSIZ, fp) == NULL) { 349 nlsmesg(MM_ERROR, "Invalid network specification"); 350 exit(NLS_BADPM); 351 } 352 else { 353 ptr = strchr(buf, ':'); 354 ptr++; 355 ptr2 = strchr(ptr, ':'); 356 *ptr2 = '\0'; 357 if (strcmp(ptr, LISTENTYPE) != 0) { 358 sprintf(mesg, "Network specification \"%s\" is not of type %s", netspec, LISTENTYPE); 359 nlsmesg(MM_ERROR, mesg); 360 exit(NLS_BADPM); 361 } 362 } 363 364 pclose(fp); 365 } 366 367 if (svcptr) { 368 /* check to see if service code is "correct" -- right range 369 * and format. The -m flag is ignored, so no check for 370 * "administrative" service codes (0-100) is done. 371 */ 372 c = strlen(svcptr); 373 if ((c == 0) || (c >= SVC_CODE_SZ)) { 374 sprintf(mesg, "Service code contains more than %d characters", SVC_CODE_SZ); 375 nlsmesg(MM_ERROR, mesg); 376 exit(NLS_SERV); 377 } 378 } 379 380 switch (flag) { 381 default: 382 usage(USAGE); 383 break; 384 case NONE: 385 if ( svcptr || comptr || rpcptr || lflags || idptr ) 386 usage(INCONSISTENT); 387 exitcode = prt_nets(netspec); 388 break; 389 case INIFLAG: 390 if (geteuid() != ROOT) 391 no_permission(); 392 exitcode = add_pm(netspec); 393 break; 394 case CMDFLAG: 395 if ( svcptr || comptr || idptr || netspec ) { 396 if (geteuid() != ROOT) 397 no_permission(); 398 if ((exitcode = old_addsvc(svcptr, "", cmdptr, comptr, moduleptr, idptr, NULL, netspec)) != NLS_OK) 399 switch (exitcode) { 400 case NLS_SERV: 401 nlsmesg(MM_ERROR, "Service code already exists"); 402 break; 403 default: 404 nlsmesg(MM_ERROR, "Could not add service"); 405 break; 406 } 407 } 408 else { 409 if (netspec) 410 usage(INCONSISTENT); 411 exitcode = prt_cmd(cmdptr, CFLAG | lflags, moduleptr, addrptr, rpcptr); 412 } 413 break; 414 case PIPFLAG: 415 if (geteuid() != ROOT) 416 no_permission(); 417 exitcode = prt_cmd(pipeptr, PFLAG | lflags, moduleptr, addrptr, rpcptr); 418 break; 419 case VERFLAG: 420 printf("%d\n", VERSION); 421 exit(NLS_OK); 422 break; 423 case DISFLAG: 424 if (geteuid() != ROOT) 425 no_permission(); 426 exitcode = disable_svc(svcptr, netspec); 427 break; 428 case ENAFLAG: 429 if (geteuid() != ROOT) 430 no_permission(); 431 exitcode = enable_svc(svcptr, netspec); 432 break; 433 case KILFLAG: 434 if (geteuid() != ROOT) 435 no_permission(); 436 exitcode = kill_listener(netspec); 437 break; 438 case ADRFLAG: 439 /* check for root permissions in setup_addr */ 440 exitcode = setup_addr(lptr, tptr, netspec); 441 break; 442 case REMFLAG: 443 if (geteuid() != ROOT) 444 no_permission(); 445 exitcode = remove_svc(svcptr, netspec, TRUE); 446 break; 447 case STAFLAG: 448 if (geteuid() != ROOT) 449 no_permission(); 450 exitcode = start_listener(netspec); 451 break; 452 case VBSFLAG: 453 exitcode = prt_svcs(NULL, netspec); 454 break; 455 case NETFLAG: 456 exitcode = prt_nets(NULL); 457 break; 458 case ZZZFLAG: 459 exitcode = prt_svcs(svcptr, netspec); 460 break; 461 } 462 if (exitcode == NLS_SYSERR) 463 nlsmesg(MM_ERROR, "System error in SAC command"); 464 return (exitcode); 465 } 466 467 468 static char umsg[] = "usage: %s -x\n\ 469 %s [ options ] netspec\n\ 470 %s [ options ] -N port_monitor_tag\n\ 471 %s -V\n\ 472 %s -c cmd | -o pipename [ -p modules ] [ -A addr | -D ] \\\n\ 473 [ -R prognum:versnum ]\n\ 474 \n\ 475 [ options ] are:\n\ 476 [ -a svc_code -c \"cmd\" -y \"cmt\" [-p modules] [-w id] ]\n\ 477 [-q] | [-v] | [-s] | [-k] | [-i] |\n\ 478 [-e svc_code] | [-d svc_code] | [-r svc_code] | [[-q] -z svc_code]\n\ 479 [[-l addr | -] [-t addr | -]] |\n\ 480 "; 481 482 void 483 usage(int flag) 484 { 485 switch (flag) { 486 case INCONSISTENT: 487 nlsmesg(MM_ERROR, "Inconsistent options"); 488 break; 489 case MISSINGARG: 490 nlsmesg(MM_ERROR, "Missing argument"); 491 break; 492 case USAGE: 493 break; 494 } 495 fprintf(stderr, umsg, Nlsname, Nlsname, Nlsname, Nlsname, Nlsname); 496 exit(NLS_CMD); 497 } 498 499 500 /* 501 * no_permission: print out error message and exit when the user needs to 502 * needs to be root and isn't. 503 */ 504 505 void 506 no_permission(void) 507 { 508 nlsmesg(MM_ERROR, "Must be super user"); 509 exit(NLS_PERM); 510 } 511 512 /* 513 * nlsmesg: print out either an error or a warning message. severity must 514 * be either MM_ERROR or MM_WARNING. this routine will be converted 515 * to use the standard message format later. 516 */ 517 518 void 519 nlsmesg(int severity, char *text) 520 { 521 int class; 522 523 if (severity == MM_ERROR) 524 fprintf(stderr, "%s: error: %s\n", Nlsname, text); 525 else 526 fprintf(stderr, "%s: warning: %s\n", Nlsname, text); 527 return; 528 } 529 530 /* 531 * prt_cmd: print out the listener-dependent string for sacadm. 532 */ 533 534 int 535 prt_cmd(char *path, long flags, char *modules, char *addr, char *rpcp) 536 /* path: full path of command or pipe */ 537 /* flags: listener flags */ 538 /* PFLAG for pipe */ 539 /* CFLAG for command */ 540 /* DFLAG for dynamic addr */ 541 /* modules: STREAMS modules to push */ 542 /* addr: private address */ 543 /* rpcp: RPC prog and ver # */ 544 { 545 struct stat sbuf; 546 char mesgbuf[BUFSIZ]; 547 char *tmp; 548 549 if (*path != '/') { 550 nlsmesg(MM_ERROR, "Must specify full path name"); 551 return(NLS_CMD); 552 } 553 554 if ((tmp = strchr(path, ' ')) != NULL) 555 *tmp = '\0'; 556 557 if (stat(path, &sbuf) < 0) { 558 if (errno != EFAULT) { 559 sprintf(mesgbuf, "%s does not exist", path); 560 nlsmesg(MM_WARNING, mesgbuf); 561 } 562 else 563 return(NLS_SYSERR); 564 } 565 566 if (tmp) 567 *tmp = ' '; 568 569 printf("%s:%s:%s:%s:%s\n", (addr ? addr : ""), (rpcp ? rpcp : ""), 570 pflags(flags), (modules ? modules : ""), path); 571 return(NLS_OK); 572 } 573 574 /* 575 * old_addsvc: use pmadm to add a service code to the listener. this will 576 * not allow specification of a private address -- use pmadm! 577 */ 578 579 int 580 old_addsvc(char *svc, char *addr, char *cmd, char *com, char *module, 581 char *id, char *flags, char *netspec) 582 { 583 char buf[BUFSIZ]; 584 char mesgbuf[BUFSIZ]; 585 int rtn; 586 struct stat sbuf; 587 char *tmp; 588 589 if (!svc || !cmd || !com || !netspec) 590 usage(MISSINGARG); 591 592 /* create "port-monitor specific" info in the same way as prt_cmd */ 593 594 if (*cmd != '/') { 595 nlsmesg(MM_ERROR, "Must specify full path name"); 596 return(NLS_CMD); 597 } 598 599 if ((tmp = strchr(cmd, ' ')) != NULL) 600 *tmp = '\0'; 601 602 if (stat(cmd, &sbuf) < 0) { 603 if (errno != EFAULT) { 604 sprintf(mesgbuf, "%s does not exist", cmd); 605 nlsmesg(MM_WARNING, mesgbuf); 606 } 607 else 608 return(NLS_SYSERR); 609 } 610 611 if (tmp) 612 *tmp = ' '; 613 614 if (addr) 615 sprintf(mesgbuf, "'%s::c:%s:%s'", addr, module ? module : "" , cmd); 616 else 617 sprintf(mesgbuf, "'::c:%s:%s'", module ? module : "" , cmd); 618 619 if (flags && *flags) 620 sprintf(buf, PM_ADDSVCF, netspec, svc, (id)?id:DEFAULTID, flags, mesgbuf, VERSION, com ? com : ""); 621 else 622 sprintf(buf, PM_ADDSVC, netspec, svc, (id)?id:DEFAULTID, mesgbuf, VERSION, com ? com : ""); 623 624 if ((rtn = system(buf)) < 0) { 625 return(NLS_SYSERR); 626 } 627 rtn = (rtn>>8) & 0xff; /* get child return value out of exit word */ 628 629 switch (rtn) { 630 case 0: 631 return(NLS_OK); 632 break; 633 case E_BADARGS: 634 case E_SAFERR: 635 case E_SYSERR: 636 case E_NOEXIST: 637 case E_PMRUN: 638 case E_PMNOTRUN: 639 case E_RECOVER: 640 case E_SACNOTRUN: 641 default: 642 return(NLS_SYSERR); 643 break; 644 case E_DUP: 645 return(NLS_SERV); 646 break; 647 case E_NOPRIV: 648 no_permission(); 649 break; 650 } 651 /* NOTREACHED */ 652 } 653 654 /* 655 * prt_nets: print the status of one network, or all nets if netspec 656 * is NULL 657 */ 658 int 659 prt_nets(char *netspec) 660 { 661 char buf[BUFSIZ]; 662 FILE *fp; 663 char *name; 664 char *state; 665 char *type; 666 int found = FALSE; 667 int rtn = NLS_OK; 668 669 if (netspec == NULL) 670 sprintf(buf, SAC_LSTY, LISTENTYPE); 671 else 672 sprintf(buf, SAC_LSPM, netspec); 673 674 if ((fp = popen(buf, "r")) == NULL) 675 return(NLS_SYSERR); 676 677 while (fgets(buf, BUFSIZ, fp) != NULL) { 678 if ((name = nexttok(buf, ":")) == NULL) 679 return(NLS_SYSERR); 680 if ((type = nexttok(NULL, ":")) == NULL) 681 return(NLS_SYSERR); 682 683 if (strcmp(type, LISTENTYPE) != 0) 684 continue; /* ignore other types of port monitors */ 685 686 found = TRUE; 687 if (nexttok(NULL, ":") == NULL) 688 return(NLS_SYSERR); 689 if (nexttok(NULL, ":") == NULL) 690 return(NLS_SYSERR); 691 if ((state = nexttok(NULL, ":")) == NULL) 692 return(NLS_SYSERR); 693 if (strcmp(state, "ENABLED") == 0 || 694 strcmp(state, "STARTING") == 0) { 695 rtn = QZERO; 696 if (!Quietflag) 697 printf("%s\t%s\n", name, "ACTIVE"); 698 } 699 else { 700 rtn = QONE; 701 if (!Quietflag) 702 printf("%s\t%s\n", name, "INACTIVE"); 703 } 704 } 705 pclose(fp); 706 707 if (netspec && !found) { 708 nlsmesg(MM_ERROR, "Invalid network specification"); 709 return(NLS_BADPM); 710 } 711 712 if (netspec) 713 return(rtn); 714 else 715 return(NLS_OK); 716 717 } 718 719 720 /* 721 * print info about service on netspec, or all services on netspec 722 * if svc is NULL 723 */ 724 725 int 726 prt_svcs(char *svc, char *netspec) 727 { 728 char buf[BUFSIZ]; 729 char mesg[BUFSIZ]; 730 FILE *fp; 731 struct svcfields entry; 732 int rtn; 733 int found = FALSE; 734 char *p; 735 736 if (svc == NULL) 737 sprintf(buf, PM_LSALL, netspec); 738 else 739 sprintf(buf, PM_LSONE, netspec, svc); 740 741 if ((fp = popen(buf, "r")) == NULL) 742 return(NLS_SYSERR); 743 744 while (fgets(buf, BUFSIZ, fp) != NULL) { 745 if ((rtn = svc_format(buf, &entry)) != 0) { 746 switch (rtn) { 747 case NOTLISTEN: 748 continue; 749 break; 750 case BADPMFMT: 751 return(NLS_SYSERR); 752 break; 753 case BADLISFMT: 754 sprintf(mesg, "Entry for code \"%s\" has incorrect format", entry.svc_code); 755 nlsmesg(MM_WARNING, mesg); 756 continue; 757 break; 758 } 759 } 760 found = TRUE; 761 762 if (!Quietflag) { 763 printf("%s\t", entry.svc_code); 764 if (*entry.addr) 765 printf("%s\t", entry.addr); 766 else if (strchr(entry.lflags, 'd')) 767 printf("DYNAMIC\t"); 768 else 769 printf("NOADDR\t"); 770 771 if (strchr(entry.flags, 'x') == NULL) 772 printf("ENABLED \t"); 773 else 774 printf("DISABLED\t"); 775 776 777 printf("%s\t%s\t%s\t%s\t# %s", 778 (*entry.rpc)?entry.rpc:"NORPC", entry.id, 779 (*entry.modules)?entry.modules:"NOMODULES", 780 entry.command, (*entry.comment)?entry.comment:""); 781 } 782 else { 783 if (strchr(entry.flags, 'x') == NULL) 784 return(QZERO); 785 else 786 return(QONE); 787 } 788 } 789 790 pclose(fp); 791 792 if (rtn == NOTLISTEN) { /* check last return to see if error */ 793 sprintf(mesg, "Network specification \"%s\" is not of type %s", netspec, LISTENTYPE); 794 nlsmesg(MM_ERROR, mesg); 795 return(NLS_BADPM); 796 } 797 if (svc && !found) { 798 if (!Quietflag) { 799 sprintf(mesg, "Service \"%s\" unknown", svc); 800 nlsmesg(MM_ERROR, mesg); 801 } 802 return(NLS_SERV); 803 } 804 805 return(NLS_OK); 806 } 807 808 /* 809 * disable_svc: use pmadm to disable a service 810 */ 811 812 int 813 disable_svc(char *svc, char *netspec) 814 { 815 char buf[BUFSIZ]; 816 int rtn; 817 818 sprintf(buf, PM_DISABLE, netspec, svc); 819 820 if ((rtn = system(buf)) < 0) { 821 return(NLS_SYSERR); 822 } 823 rtn = (rtn>>8) & 0xff; /* get child return value out of exit word */ 824 825 switch (rtn) { 826 case 0: 827 return(NLS_OK); 828 break; 829 case E_BADARGS: 830 case E_SAFERR: 831 case E_SYSERR: 832 case E_PMRUN: 833 case E_PMNOTRUN: 834 case E_RECOVER: 835 case E_SACNOTRUN: 836 default: 837 return(NLS_SYSERR); 838 break; 839 case E_NOEXIST: 840 case E_DUP: 841 nlsmesg(MM_ERROR, "Non-existent service."); 842 return(NLS_SERV); 843 break; 844 case E_NOPRIV: 845 no_permission(); 846 break; 847 } 848 /* NOTREACHED */ 849 } 850 851 852 int 853 enable_svc(char *svc, char *netspec) 854 { 855 char buf[BUFSIZ]; 856 int rtn; 857 858 sprintf(buf, PM_ENABLE, netspec, svc); 859 860 if ((rtn = system(buf)) < 0) { 861 return(NLS_SYSERR); 862 } 863 rtn = (rtn>>8) & 0xff; /* get child return value out of exit word */ 864 865 switch (rtn) { 866 case 0: 867 return(NLS_OK); 868 break; 869 case E_BADARGS: 870 case E_SAFERR: 871 case E_SYSERR: 872 case E_PMRUN: 873 case E_PMNOTRUN: 874 case E_RECOVER: 875 case E_SACNOTRUN: 876 default: 877 return(NLS_SYSERR); 878 break; 879 case E_NOEXIST: 880 case E_DUP: 881 nlsmesg(MM_ERROR, "Non-existent service."); 882 return(NLS_SERV); 883 break; 884 case E_NOPRIV: 885 no_permission(); 886 break; 887 } 888 /* NOTREACHED */ 889 } 890 891 892 int 893 remove_svc(char *svc, char *netspec, int printerrors) 894 { 895 char buf[BUFSIZ]; 896 int rtn; 897 898 sprintf(buf, PM_REMSVC, netspec, svc); 899 900 if ((rtn = system(buf)) < 0) { 901 return(NLS_SYSERR); 902 } 903 rtn = (rtn>>8) & 0xff; /* get child return value out of exit word */ 904 905 switch (rtn) { 906 case 0: 907 return(NLS_OK); 908 break; 909 case E_BADARGS: 910 case E_SAFERR: 911 case E_SYSERR: 912 case E_PMRUN: 913 case E_PMNOTRUN: 914 case E_RECOVER: 915 case E_SACNOTRUN: 916 default: 917 return(NLS_SYSERR); 918 break; 919 case E_NOEXIST: 920 case E_DUP: 921 if (printerrors) 922 nlsmesg(MM_ERROR, "Non-existent service."); 923 return(NLS_SERV); 924 break; 925 case E_NOPRIV: 926 no_permission(); 927 break; 928 } 929 /* NOTREACHED */ 930 } 931 932 933 int 934 kill_listener(char *netspec) 935 { 936 char buf[BUFSIZ]; 937 char mesg[BUFSIZ]; 938 int rtn; 939 940 sprintf(buf, SAC_KILLPM, netspec); 941 942 if ((rtn = system(buf)) < 0) { 943 return(NLS_SYSERR); 944 } 945 rtn = (rtn>>8) & 0xff; /* get child return value out of exit word */ 946 947 switch (rtn) { 948 case 0: 949 return(NLS_OK); 950 break; 951 case E_BADARGS: 952 case E_DUP: 953 case E_SAFERR: 954 case E_SYSERR: 955 case E_PMRUN: 956 case E_RECOVER: 957 case E_SACNOTRUN: 958 default: 959 return(NLS_SYSERR); 960 break; 961 case E_PMNOTRUN: 962 sprintf(mesg, "No listener active on network \"%s\"", netspec); 963 nlsmesg(MM_ERROR, mesg); 964 return(NLS_FAILED); 965 case E_NOEXIST: 966 nlsmesg(MM_ERROR, "Non-existent port monitor."); 967 return(NLS_SERV); 968 break; 969 case E_NOPRIV: 970 no_permission(); 971 break; 972 } 973 /* NOTREACHED */ 974 } 975 976 977 /* 978 * add_pm: add a port monitor (initialize directories) using sacadm 979 */ 980 981 int 982 add_pm(char *netspec) 983 { 984 char buf[BUFSIZ]; 985 char mesg[BUFSIZ]; 986 int rtn; 987 988 sprintf(buf, SAC_ADDPM, netspec, LISTENTYPE, gencmdstr(netspec), VERSION); 989 990 if ((rtn = system(buf)) < 0) { 991 return(NLS_SYSERR); 992 } 993 rtn = (rtn>>8) & 0xff; /* get child return value out of exit word */ 994 995 switch (rtn) { 996 case 0: 997 old_addsvc(NLPSSVCCODE, NULL, NLPSSRV, "NLPS server", "", "root", NULL, netspec); 998 return(NLS_OK); 999 break; 1000 case E_BADARGS: 1001 case E_SAFERR: 1002 case E_SYSERR: 1003 case E_RECOVER: 1004 case E_NOEXIST: 1005 case E_PMNOTRUN: 1006 case E_SACNOTRUN: 1007 default: 1008 return(NLS_SYSERR); 1009 break; 1010 case E_DUP: 1011 case E_PMRUN: 1012 nlsmesg(MM_ERROR, "Listener already initialized"); 1013 return(NLS_FAILED); 1014 break; 1015 case E_NOPRIV: 1016 no_permission(); 1017 break; 1018 } 1019 /* NOTREACHED */ 1020 } 1021 1022 1023 /* 1024 * gencmdstr: generate the correct string to invoke the listener (starlan 1025 * requires special handling) 1026 */ 1027 1028 char * 1029 gencmdstr(char *netspec) 1030 { 1031 static char buf[BUFSIZ]; 1032 1033 (void) strcpy(buf, LISTENCMD); 1034 if (!strcmp(netspec, "starlan")) 1035 (void) strcat(buf, " -m slan"); 1036 (void) strcat(buf, " "); 1037 (void) strcat(buf, netspec); 1038 return(buf); 1039 } 1040 1041 1042 /* 1043 * start_listener: start the listener 1044 */ 1045 1046 int 1047 start_listener(char *netspec) 1048 { 1049 char buf[BUFSIZ]; 1050 char scratch[BUFSIZ]; 1051 int rtn; 1052 1053 sprintf(buf, SAC_STARTPM, netspec); 1054 1055 if ((rtn = system(buf)) < 0) 1056 return(NLS_SYSERR); 1057 rtn = (rtn>>8) & 0xff; 1058 switch (rtn) { 1059 case 0: 1060 break; 1061 case E_BADARGS: 1062 case E_SAFERR: 1063 case E_SYSERR: 1064 case E_RECOVER: 1065 case E_PMNOTRUN: 1066 case E_SACNOTRUN: 1067 default: 1068 return(NLS_SYSERR); 1069 break; 1070 case E_NOEXIST: 1071 case E_DUP: 1072 nlsmesg(MM_ERROR, "Non-existent port monitor."); 1073 return(NLS_BADPM); 1074 break; 1075 case E_PMRUN: 1076 nlsmesg(MM_ERROR, "Listener already running"); 1077 return(NLS_FAILED); 1078 case E_NOPRIV: 1079 no_permission(); 1080 break; 1081 } 1082 1083 sprintf(buf, SAC_ENABLPM, netspec); 1084 1085 if ((rtn = system(buf)) < 0) { 1086 return(NLS_SYSERR); 1087 } 1088 rtn = (rtn>>8) & 0xff; 1089 switch (rtn) { 1090 case 0: 1091 return(NLS_OK); 1092 break; 1093 case E_BADARGS: 1094 case E_SAFERR: 1095 case E_SYSERR: 1096 case E_RECOVER: 1097 case E_SACNOTRUN: 1098 default: 1099 return(NLS_SYSERR); 1100 break; 1101 case E_NOEXIST: 1102 case E_DUP: 1103 nlsmesg(MM_ERROR, "Non-existent port monitor."); 1104 return(NLS_BADPM); 1105 break; 1106 case E_PMRUN: 1107 nlsmesg(MM_ERROR, "Listener already running"); 1108 return(NLS_FAILED); 1109 case E_PMNOTRUN: 1110 nlsmesg(MM_ERROR, "Listener start failed"); 1111 return(NLS_FAILED); 1112 case E_NOPRIV: 1113 no_permission(); 1114 break; 1115 } 1116 /* NOTREACHED */ 1117 } 1118 1119 1120 /* 1121 * setup_addr: setup the -l and -t addresses. 1122 */ 1123 1124 int 1125 setup_addr(char *laddr, char *taddr, char *netspec) 1126 { 1127 char buf[BUFSIZ]; 1128 char mesg[BUFSIZ]; 1129 char *p; 1130 int rtn; 1131 int qlisten = FALSE; 1132 int qtty = FALSE; 1133 FILE *fp; 1134 struct svcfields entry; 1135 1136 if (laddr && *laddr == '-') 1137 qlisten = TRUE; 1138 1139 if (taddr && *taddr == '-') 1140 qtty = TRUE; 1141 1142 if (laddr) { 1143 sprintf(buf, PM_LSONE, netspec, NLPSSVCCODE); 1144 1145 if ((fp = popen(buf, "r")) == NULL) { 1146 return(NLS_SYSERR); 1147 } 1148 1149 if (fgets(buf, BUFSIZ, fp) != NULL) { 1150 if ((rtn = svc_format(buf, &entry)) != 0) { 1151 switch (rtn) { 1152 case NOTLISTEN: 1153 nlsmesg(MM_ERROR, "Incorrect port monitor type. Must be of type listen"); 1154 return(NLS_FAILED); 1155 break; 1156 case BADPMFMT: 1157 return(NLS_SYSERR); 1158 break; 1159 case BADLISFMT: 1160 sprintf(mesg, "Entry for code \"%s\" has incorrect format", entry.svc_code); 1161 nlsmesg(MM_WARNING, mesg); 1162 break; 1163 } 1164 } 1165 else { 1166 if (qlisten) 1167 printf("%s\n", entry.addr); 1168 else { 1169 if (geteuid() != ROOT) 1170 no_permission(); 1171 /* add address */ 1172 remove_svc(NLPSSVCCODE, netspec, FALSE); 1173 p = strchr(entry.comment, '\n'); 1174 if (p) 1175 *p = '\0'; 1176 old_addsvc(NLPSSVCCODE, laddr, entry.command, entry.comment, entry.modules, entry.id, entry.flags, netspec); 1177 } 1178 } 1179 pclose(fp); 1180 } 1181 else if (!qlisten) 1182 nlsmesg(MM_WARNING, "NLPS service not defined"); 1183 } 1184 if (taddr) { 1185 sprintf(buf, PM_LSONE, netspec, TTYSVCCODE); 1186 1187 if ((fp = popen(buf, "r")) == NULL) { 1188 return(NLS_SYSERR); 1189 } 1190 1191 if (fgets(buf, BUFSIZ, fp) != NULL) { 1192 if ((rtn = svc_format(buf, &entry)) != 0) { 1193 switch (rtn) { 1194 case NOTLISTEN: 1195 nlsmesg(MM_ERROR, "Incorrect port monitor type. Must be of type listen"); 1196 return(NLS_FAILED); 1197 break; 1198 case BADPMFMT: 1199 return(NLS_SYSERR); 1200 break; 1201 case BADLISFMT: 1202 sprintf(mesg, "Entry for code \"%s\" has incorrect format", entry.svc_code); 1203 nlsmesg(MM_WARNING, mesg); 1204 break; 1205 } 1206 } 1207 else { 1208 if (qtty) 1209 printf("%s\n", entry.addr); 1210 else { 1211 if (geteuid() != ROOT) 1212 no_permission(); 1213 /* add address */ 1214 remove_svc(TTYSVCCODE, netspec, FALSE); 1215 p = strchr(entry.comment, '\n'); 1216 if (p) 1217 *p = '\0'; 1218 old_addsvc(TTYSVCCODE, taddr, entry.command, entry.comment, entry.modules, entry.id, entry.flags, netspec); 1219 } 1220 } 1221 pclose(fp); 1222 } 1223 else if (!qtty) 1224 nlsmesg(MM_WARNING, "remote login service not defined"); 1225 } 1226 return(NLS_OK); 1227 } 1228 1229 1230 /* 1231 * svc_format: scan a line of output from pmadm to separate it into fields. 1232 * returns BADPMFMT for missing fields or incorrect syntax. 1233 * NOTLISTEN is the port monitor type is not listen. 1234 * BADLISFMT if the listener-specific data is incorrect. 1235 * NLS_OK if everything checked out and data is broken 1236 * into the structure. 1237 */ 1238 1239 int 1240 svc_format(char *buf, struct svcfields *entry) 1241 { 1242 char *ptr; /* temporary pointer into buffer */ 1243 char *tmp; /* temporary pointer into buffer */ 1244 1245 entry->pmtag = buf; 1246 if ((ptr = strchr(buf, ':')) == NULL) 1247 return(BADPMFMT); 1248 *ptr++ = '\0'; 1249 entry->pmtype = ptr; 1250 if ((ptr = strchr(entry->pmtype, ':')) == NULL) 1251 return(BADPMFMT); 1252 *ptr++ = '\0'; 1253 entry->svc_code = ptr; 1254 1255 if (strcmp(entry->pmtype, LISTENTYPE) != 0) 1256 return(NOTLISTEN); 1257 1258 if ((ptr = strchr(entry->svc_code, ':')) == NULL) 1259 return(BADPMFMT); 1260 *ptr++ = '\0'; 1261 entry->flags = ptr; 1262 if ((ptr = strchr(entry->flags, ':')) == NULL) 1263 return(BADPMFMT); 1264 *ptr++ = '\0'; 1265 entry->id = ptr; 1266 if ((ptr = strchr(entry->id, ':')) == NULL) 1267 return(BADPMFMT); 1268 *ptr++ = '\0'; 1269 entry->res1 = ptr; 1270 if ((ptr = strchr(entry->res1, ':')) == NULL) 1271 return(BADPMFMT); 1272 *ptr++ = '\0'; 1273 entry->res2 = ptr; 1274 if ((ptr = strchr(entry->res2, ':')) == NULL) 1275 return(BADPMFMT); 1276 *ptr++ = '\0'; 1277 entry->res3 = ptr; 1278 if ((ptr = strchr(entry->res3, ':')) == NULL) 1279 return(BADPMFMT); 1280 *ptr++ = '\0'; 1281 entry->addr = ptr; 1282 if ((ptr = strchr(entry->addr, ':')) == NULL) 1283 return(BADLISFMT); 1284 *ptr++ = '\0'; 1285 entry->rpc = ptr; 1286 if ((ptr = strchr(entry->rpc, ':')) == NULL) 1287 return(BADLISFMT); 1288 *ptr++ = '\0'; 1289 if (*entry->rpc) { 1290 if ((tmp = strchr(entry->rpc, ',')) == NULL) 1291 return(BADLISFMT); 1292 *tmp = ':'; 1293 } 1294 entry->lflags = ptr; 1295 if ((ptr = strchr(entry->lflags, ':')) == NULL) 1296 return(BADLISFMT); 1297 *ptr++ = '\0'; 1298 entry->modules = ptr; 1299 if ((ptr = strchr(entry->modules, ':')) == NULL) 1300 return(BADLISFMT); 1301 *ptr++ = '\0'; 1302 entry->command = ptr; 1303 if ((ptr = strchr(entry->command, '#')) == NULL) 1304 return(BADLISFMT); 1305 *ptr++ = '\0'; 1306 entry->comment = ptr; 1307 return(NLS_OK); 1308 } 1309 1310 1311 /* 1312 * nexttok - return next token, essentially a strtok, but it can 1313 * deal with null fields and strtok can not 1314 * 1315 * args: str - the string to be examined, NULL if we should 1316 * examine the remembered string 1317 * delim - the list of valid delimiters 1318 */ 1319 1320 1321 char * 1322 nexttok(char *str, char *delim) 1323 { 1324 static char *savep; /* the remembered string */ 1325 register char *p; /* pointer to start of token */ 1326 register char *ep; /* pointer to end of token */ 1327 1328 p = (str == NULL) ? savep : str ; 1329 if (p == NULL) 1330 return(NULL); 1331 ep = strpbrk(p, delim); 1332 if (ep == NULL) { 1333 savep = NULL; 1334 return(p); 1335 } 1336 savep = ep + 1; 1337 *ep = '\0'; 1338 return(p); 1339 } 1340 1341 1342 /* 1343 * pflags - put flags into intelligible form for output 1344 * 1345 * args: flags - binary representation of flags 1346 */ 1347 1348 char * 1349 pflags(long flags) 1350 { 1351 register int i; /* scratch counter */ 1352 static char buf[BUFSIZ]; /* formatted flags */ 1353 1354 if (flags == 0) 1355 return(""); 1356 i = 0; 1357 if (flags & CFLAG) { 1358 buf[i++] = 'c'; 1359 flags &= ~CFLAG; 1360 } 1361 if (flags & DFLAG) { 1362 buf[i++] = 'd'; 1363 flags &= ~DFLAG; 1364 } 1365 if (flags & PFLAG) { 1366 buf[i++] = 'p'; 1367 flags &= ~PFLAG; 1368 } 1369 if (flags) { 1370 nlsmesg(MM_ERROR, "Internal error in pflags"); 1371 exit(NLS_FAILED); 1372 } 1373 buf[i] = '\0'; 1374 return(buf); 1375 } 1376