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