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
main(int argc,char ** argv)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
usage(int flag)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
no_permission(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
nlsmesg(int severity,char * text)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
prt_cmd(char * path,long flags,char * modules,char * addr,char * rpcp)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
old_addsvc(char * svc,char * addr,char * cmd,char * com,char * module,char * id,char * flags,char * netspec)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
prt_nets(char * netspec)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
prt_svcs(char * svc,char * netspec)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
disable_svc(char * svc,char * netspec)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
enable_svc(char * svc,char * netspec)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
remove_svc(char * svc,char * netspec,int printerrors)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
kill_listener(char * netspec)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
add_pm(char * netspec)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 *
gencmdstr(char * netspec)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
start_listener(char * netspec)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
setup_addr(char * laddr,char * taddr,char * netspec)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
svc_format(char * buf,struct svcfields * entry)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 *
nexttok(char * str,char * delim)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 *
pflags(long flags)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