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