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