xref: /illumos-gate/usr/src/cmd/ttymon/tmpmtab.c (revision f20211217f12ce291fd518e61065cd273f23e4ea)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 
33 #include	<unistd.h>
34 #include	<stdlib.h>
35 #include	<sys/types.h>
36 #include	<ctype.h>
37 #include	<string.h>
38 #include 	<pwd.h>
39 #include 	<grp.h>
40 #include	<signal.h>
41 #include	"ttymon.h"
42 #include	"tmstruct.h"
43 #include	"tmextern.h"
44 
45 extern	char	*strsave();
46 extern	void	set_softcar();
47 extern	int	vml();
48 void	purge();
49 static	int	get_flags();
50 static	int	get_ttyflags();
51 static	int	same_entry();
52 static	int	check_pmtab();
53 static	void	insert_pmtab();
54 static	void	free_pmtab();
55 static	char	*expand();
56 
57 int	check_identity();
58 
59 int	strcheck();
60 
61 /*
62  * read_pmtab()
63  *	- read and parse pmtab
64  *	- store table in linked list pointed by global variable "PMtab"
65  *	- exit if file does not exist or error detected.
66  */
67 void
68 read_pmtab()
69 {
70 	register struct pmtab *gptr;
71 	register char *ptr, *wptr;
72 	FILE 	 *fp;
73 	int 	 input, state, size, rawc, field, linenum;
74 	char 	 oldc;
75 	char 	 line[BUFSIZ];
76 	char 	 wbuf[BUFSIZ];
77 	static 	 char *states[] = {
78 	      "","tag","flags","identity","reserved1","reserved2","reserved3",
79 	      "device","ttyflags","count","service", "timeout","ttylabel",
80 	      "modules","prompt","disable msg","terminal type","soft-carrier"
81 	};
82 
83 # ifdef DEBUG
84 	debug("in read_pmtab");
85 # endif
86 
87 	if ((fp = fopen(PMTABFILE,"r")) == NULL) {
88 		fatal("open pmtab (%s) failed", PMTABFILE);
89 	}
90 
91 	Nentries = 0;
92 	if (check_version(PMTAB_VERS, PMTABFILE) != 0)
93 		fatal("check pmtab version failed");
94 
95 	for (gptr = PMtab; gptr; gptr = gptr->p_next) {
96 		if ((gptr->p_status == SESSION) ||
97 		    (gptr->p_status == LOCKED) ||
98 		    (gptr->p_status == UNACCESS)) {
99 			if (gptr->p_fd > 0) {
100 				(void)close(gptr->p_fd);
101 				gptr->p_fd = 0;
102 			}
103 			gptr->p_inservice = gptr->p_status;
104 		}
105 		gptr->p_status = NOTVALID;
106 	}
107 
108 	wptr = wbuf;
109 	input = ACTIVE;
110 	linenum = 0;
111 	do {
112 		linenum++;
113 		line[0] = '\0';
114 		for (ptr= line,oldc = '\0'; ptr < &line[sizeof(line)-1] &&
115 		 (rawc=getc(fp))!= '\n' && rawc != EOF; ptr++,oldc=(char)rawc){
116 			if ((rawc == '#') && (oldc != '\\'))
117 				break;
118 			*ptr = (char)rawc;
119 		}
120 		*ptr = '\0';
121 
122 		/* skip rest of the line */
123 		if (rawc != EOF && rawc != '\n') {
124 			if (rawc != '#')
125 				log("Entry too long.\n");
126 			while ((rawc = getc(fp)) != EOF && rawc != '\n')
127 				;
128 		}
129 
130 		if (rawc == EOF) {
131 			if (ptr == line) break;
132 			else input = FINISHED;
133 		}
134 
135 		/* if empty line, skip */
136 		for (ptr=line; *ptr != '\0' && isspace(*ptr); ptr++)
137 			;
138 		if (*ptr == '\0') continue;
139 
140 #ifdef DEBUG
141 		debug("**** Next Entry ****\n%s", line);
142 #endif
143 		log("Processing pmtab line #%d", linenum);
144 
145 		/* Now we have the complete line */
146 
147 		if ((gptr = ALLOC_PMTAB) == PNULL)
148 			fatal("memory allocation failed");
149 
150 		/* set hangup flag, this is the default */
151 		gptr->p_ttyflags |= H_FLAG;
152 
153 		/*
154 		 * For compatibility reasons, we cannot rely on these
155 		 * having values assigned from pmtab.
156 		 */
157 		gptr->p_termtype = "";
158 		gptr->p_softcar = "";
159 
160 		for (state=P_TAG,ptr=line;state !=FAILURE && state !=SUCCESS;) {
161 			switch(state) {
162 			case P_TAG:
163 				gptr->p_tag = strsave(getword(ptr,&size,0));
164 				break;
165 			case P_FLAGS:
166 				(void)strcpy(wptr, getword(ptr,&size,0));
167 				if ((get_flags(wptr, &gptr->p_flags)) != 0) {
168 					field = state;
169 					state = FAILURE;
170 				}
171 				break;
172 			case P_IDENTITY:
173 				gptr->p_identity=strsave(getword(ptr,&size,0));
174 				break;
175 			case P_RES1:
176 				gptr->p_res1=strsave(getword(ptr,&size,0));
177 				break;
178 			case P_RES2:
179 				gptr->p_res2=strsave(getword(ptr,&size,0));
180 				break;
181 			case P_RES3:
182 				gptr->p_res3=strsave(getword(ptr,&size,0));
183 				break;
184 			case P_DEVICE:
185 				gptr->p_device = strsave(getword(ptr,&size,0));
186 				break;
187 			case P_TTYFLAGS:
188 				(void)strcpy(wptr, getword(ptr,&size,0));
189 				if ((get_ttyflags(wptr,&gptr->p_ttyflags))!=0) {
190 					field = state;
191 					state = FAILURE;
192 				}
193 				break;
194 			case P_COUNT:
195 				(void)strcpy(wptr, getword(ptr,&size,0));
196 				if (strcheck(wptr, NUM) != 0) {
197 					log("wait_read count must be a positive number");
198 					field = state;
199 					state = FAILURE;
200 				}
201 				else
202 				    gptr->p_count = atoi(wptr);
203 				break;
204 			case P_SERVER:
205 				gptr->p_server =
206 				strsave(expand(getword(ptr,&size,1),
207 					gptr->p_device));
208 				break;
209 			case P_TIMEOUT:
210 				(void)strcpy(wptr, getword(ptr,&size,0));
211 				if (strcheck(wptr, NUM) != 0) {
212 					log("timeout value must be a positive number");
213 					field = state;
214 					state = FAILURE;
215 				}
216 				else
217 				    gptr->p_timeout = atoi(wptr);
218 				break;
219 			case P_TTYLABEL:
220 				gptr->p_ttylabel=strsave(getword(ptr,&size,0));
221 				break;
222 			case P_MODULES:
223 				gptr->p_modules = strsave(getword(ptr,&size,0));
224 				if (vml(gptr->p_modules) != 0) {
225 					field = state;
226 					state = FAILURE;
227 				}
228 				break;
229 			case P_PROMPT:
230 				gptr->p_prompt = strsave(getword(ptr,&size,TRUE));
231 				break;
232 			case P_DMSG:
233 				gptr->p_dmsg = strsave(getword(ptr,&size,TRUE));
234 				break;
235 
236 			case P_TERMTYPE:
237 				gptr->p_termtype = strsave(getword(ptr,&size,TRUE));
238 				break;
239 
240 			case P_SOFTCAR:
241 				gptr->p_softcar = strsave(getword(ptr,&size,TRUE));
242 				break;
243 
244 			} /* end switch */
245 			ptr += size;
246 			if (state == FAILURE)
247 				break;
248 			if (*ptr == ':') {
249 				ptr++;	/* Skip the ':' */
250 				state++ ;
251 			} else if (*ptr != '\0') {
252 				field = state;
253 				state = FAILURE;
254 			}
255 			if (*ptr == '\0') {
256 				/*
257 				 * Maintain compatibility with older ttymon
258 				 * pmtab files.  If Sun-added fields are
259 				 * missing, this should not be an error.
260 				 */
261 				if (state > P_DMSG) {
262 					state = SUCCESS;
263 				} else {
264 					field = state;
265 					state = FAILURE;
266 				}
267 			}
268 		} /* end for loop */
269 
270 		if (state == SUCCESS) {
271 			if (check_pmtab(gptr) == 0) {
272 				if (Nentries < Maxfds)
273 					insert_pmtab(gptr);
274 				else {
275 					log("can't add more entries to "
276 					    "pmtab, Maxfds = %d", Maxfds);
277 					free_pmtab(gptr);
278 					(void)fclose(fp);
279 					return;
280 				}
281 			}
282 			else {
283 				log("Parsing failure for entry: \n%s", line);
284 			log("-------------------------------------------");
285 				free_pmtab(gptr);
286 			}
287 		} else {
288 			*++ptr = '\0';
289 			log("Parsing failure in the \"%s\" field,\n%s"
290 			    "<--error detected here", states[field], line);
291 			log("-------------------------------------------");
292 			free_pmtab(gptr);
293 		}
294 	} while (input == ACTIVE);
295 
296 	(void)fclose(fp);
297 	return;
298 }
299 
300 /*
301  * get_flags	- scan flags field to set U_FLAG and X_FLAG
302  */
303 static	int
304 get_flags(wptr, flags)
305 char	*wptr;		/* pointer to the input string	*/
306 long *flags;		/* pointer to the flag to set	*/
307 {
308 	register char	*p;
309 	for (p = wptr; *p; p++) {
310 		switch (*p) {
311 		case 'x':
312 			*flags |= X_FLAG;
313 			break;
314 		case 'u':
315 			*flags |= U_FLAG;
316 			break;
317 		default:
318 			log("Invalid flag -- %c", *p);
319 			return(-1);
320 		}
321 	}
322 	return(0);
323 }
324 
325 /*
326  * get_ttyflags	- scan ttyflags field to set corresponding flags
327  */
328 static	int
329 get_ttyflags(wptr, ttyflags)
330 char	*wptr;		/* pointer to the input string	*/
331 long 	*ttyflags;	/* pointer to the flag to be set*/
332 {
333 	register char	*p;
334 	for (p = wptr; *p; p++) {
335 		switch (*p) {
336 		case 'c':
337 			*ttyflags |= C_FLAG;
338 			break;
339 		case 'h': /* h means don't hangup */
340 			*ttyflags &= ~H_FLAG;
341 			break;
342 		case 'b':
343 			*ttyflags |= B_FLAG;
344 			break;
345 		case 'r':
346 			*ttyflags |= R_FLAG;
347 			break;
348 		case 'I':
349 			*ttyflags |= I_FLAG;
350 			break;
351 		default:
352 			log("Invalid ttyflag -- %c", *p);
353 			return(-1);
354 		}
355 	}
356 	return(0);
357 }
358 
359 # ifdef DEBUG
360 /*
361  * pflags - put service flags into intelligible form for output
362  */
363 
364 char *
365 pflags(flags)
366 long flags;	/* binary representation of the flags */
367 {
368 	register int i;			/* scratch counter */
369 	static char buf[BUFSIZ];	/* formatted flags */
370 
371 	if (flags == 0)
372 		return("-");
373 	i = 0;
374 	if (flags & U_FLAG) {
375 		buf[i++] = 'u';
376 		flags &= ~U_FLAG;
377 	}
378 	if (flags & X_FLAG) {
379 		buf[i++] = 'x';
380 		flags &= ~X_FLAG;
381 	}
382 	if (flags)
383 		log("Internal error in pflags");
384 	buf[i] = '\0';
385 	return(buf);
386 }
387 
388 /*
389  * pttyflags - put ttyflags into intelligible form for output
390  */
391 
392 char *
393 pttyflags(flags)
394 long flags;	/* binary representation of ttyflags */
395 {
396 	register int i;			/* scratch counter */
397 	static char buf[BUFSIZ];	/* formatted flags */
398 
399 	if (flags == 0)
400 		return("h");
401 	i = 0;
402 	if (flags & C_FLAG) {
403 		buf[i++] = 'c';
404 		flags &= ~C_FLAG;
405 	}
406 	if (flags & H_FLAG)
407 		flags &= ~H_FLAG;
408 	else
409 		buf[i++] = 'h';
410 	if (flags & B_FLAG) {
411 		buf[i++] = 'b';
412 		flags &= ~B_FLAG;
413 	}
414 	if (flags & R_FLAG) {
415 		buf[i++] = 'r';
416 		flags &= ~B_FLAG;
417 	}
418 	if (flags & I_FLAG) {
419 		buf[i++] = 'I';
420 		flags &= ~I_FLAG;
421 	}
422 	if (flags)
423 		log("Internal error in p_ttyflags");
424 	buf[i] = '\0';
425 	return(buf);
426 }
427 
428 void
429 dump_pmtab()
430 {
431 	struct	pmtab *gptr;
432 
433 	debug("in dump_pmtab");
434 	log("********** dumping pmtab **********");
435 	log(" ");
436 	for (gptr=PMtab; gptr; gptr = gptr->p_next) {
437 		log("-------------------------------------------");
438 		log("tag:\t\t%s", gptr->p_tag);
439 		log("flags:\t\t%s",pflags(gptr->p_flags));
440 		log("identity:\t%s", gptr->p_identity);
441 		log("reserved1:\t%s", gptr->p_res1);
442 		log("reserved2:\t%s", gptr->p_res2);
443 		log("reserved3:\t%s", gptr->p_res3);
444 		log("device:\t%s", gptr->p_device);
445 		log("ttyflags:\t%s",pttyflags(gptr->p_ttyflags));
446 		log("count:\t\t%d", gptr->p_count);
447 		log("server:\t%s", gptr->p_server);
448 		log("timeout:\t%d", gptr->p_timeout);
449 		log("ttylabel:\t%s", gptr->p_ttylabel);
450 		log("modules:\t%s", gptr->p_modules);
451 		log("prompt:\t%s", gptr->p_prompt);
452 		log("disable msg:\t%s", gptr->p_dmsg);
453 		log("terminal type:\t%s", gptr->p_termtype);
454 		log("soft-carrier:\t%s", gptr->p_softcar);
455 		log("status:\t\t%d", gptr->p_status);
456 		log("inservice:\t%d", gptr->p_inservice);
457 		log("fd:\t\t%d", gptr->p_fd);
458 		log("pid:\t\t%ld", gptr->p_pid);
459 		log("uid:\t\t%ld", gptr->p_uid);
460 		log("gid:\t\t%ld", gptr->p_gid);
461 		log("dir:\t%s", gptr->p_dir);
462 		log(" ");
463 	}
464 	log("********** end dumping pmtab **********");
465 }
466 # endif
467 
468 /*
469  * same_entry(e1,e2) -    compare 2 entries of pmtab
470  *			if the fields are different, copy e2 to e1
471  * 			return 1 if same, return 0 if different
472  */
473 static	int
474 same_entry(e1,e2)
475 struct	pmtab	*e1,*e2;
476 {
477 
478 	if (strcmp(e1->p_identity, e2->p_identity) != 0)
479 		return(0);
480 	if (strcmp(e1->p_res1, e2->p_res1) != 0)
481 		return(0);
482 	if (strcmp(e1->p_res2, e2->p_res2) != 0)
483 		return(0);
484 	if (strcmp(e1->p_res3, e2->p_res3) != 0)
485 		return(0);
486 	if (strcmp(e1->p_device, e2->p_device) != 0)
487 		return(0);
488 	if (strcmp(e1->p_server, e2->p_server) != 0)
489 		return(0);
490 	if (strcmp(e1->p_ttylabel, e2->p_ttylabel) != 0)
491 		return(0);
492 	if (strcmp(e1->p_modules, e2->p_modules) != 0)
493 		return(0);
494 	if (strcmp(e1->p_prompt, e2->p_prompt) != 0)
495 		return(0);
496 	if (strcmp(e1->p_dmsg, e2->p_dmsg) != 0)
497 		return(0);
498 	if (strcmp(e1->p_termtype, e2->p_termtype) != 0)
499 		return(0);
500 	if (strcmp(e1->p_softcar, e2->p_softcar) != 0)
501 		return(0);
502 	if (e1->p_flags != e2->p_flags)
503 		return(0);
504 	/*
505 	 * compare lowest 4 bits only,
506 	 * because A_FLAG is not part of original ttyflags
507 	 */
508 	if ((e1->p_ttyflags & ~A_FLAG) != (e2->p_ttyflags & ~A_FLAG))
509 		return(0);
510 	if (e1->p_count != e2->p_count)
511 		return(0);
512 	if (e1->p_timeout != e2->p_timeout)
513 		return(0);
514 	if (e1->p_uid != e2->p_uid)
515 		return(0);
516 	if (e1->p_gid != e2->p_gid)
517 		return(0);
518 	if (strcmp(e1->p_dir, e2->p_dir) != 0)
519 		return(0);
520 	return(1);
521 }
522 
523 
524 /*
525  * insert_pmtab - insert a pmtab entry into the linked list
526  */
527 
528 static	void
529 insert_pmtab(sp)
530 register struct pmtab *sp;	/* ptr to entry to be inserted */
531 {
532 	register struct pmtab *tsp, *savtsp;	/* scratch pointers */
533 	int ret;				/* strcmp return value */
534 
535 # ifdef DEBUG
536 	debug("in insert_pmtab");
537 # endif
538 	savtsp = tsp = PMtab;
539 
540 /*
541  * find the correct place to insert this element
542  */
543 
544 	while (tsp) {
545 		ret = strcmp(sp->p_tag, tsp->p_tag);
546 		if (ret > 0) {
547 			/* keep on looking */
548 			savtsp = tsp;
549 			tsp = tsp->p_next;
550 			continue;
551 		}
552 		else if (ret == 0) {
553 			if (tsp->p_status) {
554 				/* this is a duplicate entry, ignore it */
555 				log("Ignoring duplicate entry for <%s>",
556 				    tsp->p_tag);
557 			}
558 			else {
559 				if (same_entry(tsp,sp)) {  /* same entry */
560 					tsp->p_status = VALID;
561 				}
562 				else {	/* entry changed */
563 					if ((sp->p_flags & X_FLAG) &&
564 						((sp->p_dmsg == NULL) ||
565 						(*(sp->p_dmsg) == '\0'))) {
566 						/* disabled entry */
567 						tsp->p_status = NOTVALID;
568 					}
569 					else {
570 # ifdef DEBUG
571 					debug("replacing <%s>", sp->p_tag);
572 # endif
573 						/* replace old entry */
574 						sp->p_next = tsp->p_next;
575 						if (tsp == PMtab) {
576 						   PMtab = sp;
577 						}
578 						else {
579 						   savtsp->p_next = sp;
580 						}
581 						sp->p_status = CHANGED;
582 						sp->p_fd = tsp->p_fd;
583 						sp->p_pid = tsp->p_pid;
584 					        sp->p_inservice =
585 							tsp->p_inservice;
586 						sp = tsp;
587 					}
588 				}
589 				Nentries++;
590 			}
591 			free_pmtab(sp);
592 			return;
593 		}
594 		else {
595 			if ((sp->p_flags & X_FLAG) &&
596 				((sp->p_dmsg == NULL) ||
597 				(*(sp->p_dmsg) == '\0'))) { /* disabled entry */
598 				free_pmtab(sp);
599 				return;
600 			}
601 			/*
602 			 * Set the state of soft-carrier.
603 			 * Since this is a one-time only operation,
604 			 * we do it when this service is added to
605 			 * the enabled list.
606 			 */
607 			if (*sp->p_softcar != '\0')
608 				set_softcar(sp);
609 
610 			/* insert it here */
611 			if (tsp == PMtab) {
612 				sp->p_next = PMtab;
613 				PMtab = sp;
614 			}
615 			else {
616 				sp->p_next = savtsp->p_next;
617 				savtsp->p_next = sp;
618 			}
619 # ifdef DEBUG
620 			debug("adding <%s>", sp->p_tag);
621 # endif
622 			Nentries++;
623 			/* this entry is "current" */
624 			sp->p_status = VALID;
625 			return;
626 		}
627 	}
628 
629 /*
630  * either an empty list or should put element at end of list
631  */
632 
633 	if ((sp->p_flags & X_FLAG) &&
634 		((sp->p_dmsg == NULL) ||
635 		(*(sp->p_dmsg) == '\0'))) { /* disabled entry */
636 		free_pmtab(sp);		 /* do not poll this entry */
637 		return;
638 	}
639 	/*
640 	 * Set the state of soft-carrier.
641 	 * Since this is a one-time only operation,
642 	 * we do it when this service is added to
643 	 * the enabled list.
644 	 */
645 	if (*sp->p_softcar != '\0')
646 		set_softcar(sp);
647 	sp->p_next = NULL;
648 	if (PMtab == NULL)
649 		PMtab = sp;
650 	else
651 		savtsp->p_next = sp;
652 # ifdef DEBUG
653 	debug("adding <%s>", sp->p_tag);
654 # endif
655 	++Nentries;
656 	/* this entry is "current" */
657 	sp->p_status = VALID;
658 }
659 
660 
661 /*
662  * purge - purge linked list of "old" entries
663  */
664 
665 
666 void
667 purge()
668 {
669 	register struct pmtab *sp;		/* working pointer */
670 	register struct pmtab *savesp, *tsp;	/* scratch pointers */
671 
672 # ifdef DEBUG
673 	debug("in purge");
674 # endif
675 	sp = savesp = PMtab;
676 	while (sp) {
677 		if (sp->p_status) {
678 # ifdef DEBUG
679 			debug("p_status not 0");
680 # endif
681 			savesp = sp;
682 			sp = sp->p_next;
683 		}
684 		else {
685 			tsp = sp;
686 			if (tsp == PMtab) {
687 				PMtab = sp->p_next;
688 				savesp = PMtab;
689 			}
690 			else
691 				savesp->p_next = sp->p_next;
692 # ifdef DEBUG
693 			debug("purging <%s>", sp->p_tag);
694 # endif
695 			sp = sp->p_next;
696 			free_pmtab(tsp);
697 		}
698 	}
699 }
700 
701 /*
702  *	free_pmtab	- free one pmtab entry
703  */
704 static	void
705 free_pmtab(p)
706 struct	pmtab	*p;
707 {
708 #ifdef	DEBUG
709 	debug("in free_pmtab");
710 #endif
711 	free(p->p_tag);
712 	free(p->p_identity);
713 	free(p->p_res1);
714 	free(p->p_res2);
715 	free(p->p_res3);
716 	free(p->p_device);
717 	free(p->p_server);
718 	free(p->p_ttylabel);
719 	free(p->p_modules);
720 	free(p->p_prompt);
721 	free(p->p_dmsg);
722 	free(p->p_termtype);
723 	free(p->p_softcar);
724 	if (p->p_dir)
725 		free(p->p_dir);
726 	free(p);
727 }
728 
729 /*
730  *	check_pmtab - check the fields to make sure things are correct
731  *		    - return 0 if everything is ok
732  *		    - return -1 if something is wrong
733  */
734 
735 static	int
736 check_pmtab(p)
737 struct	pmtab	*p;
738 {
739 	if (p == NULL) {
740 		log("pmtab ptr is NULL");
741 		return(-1);
742 	}
743 
744 	/* check service tag */
745 	if ((p->p_tag == NULL) || (*(p->p_tag) == '\0')) {
746 		log("port/service tag is missing");
747 		return(-1);
748 	}
749 	if (strlen(p->p_tag) > (size_t)(MAXID - 1)) {
750 		log("port/service tag <%s> is longer than %d", p->p_tag,
751 		    MAXID-1);
752 		return(-1);
753 	}
754 	if (strcheck(p->p_tag, ALNUM) != 0) {
755 		log("port/service tag <%s> is not alphanumeric", p->p_tag);
756 		return(-1);
757 	}
758 	if (check_identity(p) != 0) {
759 		return(-1);
760 	}
761 
762 	if (check_device(p->p_device) != 0)
763 		return(-1);
764 
765 	if (check_cmd(p->p_server) != 0)
766 		return(-1);
767 	return(0);
768 }
769 
770 extern  struct 	passwd *getpwnam();
771 extern  void 	endpwent();
772 extern  struct 	group *getgrgid();
773 extern  void 	endgrent();
774 
775 /*
776  *	check_identity - check to see if the identity is a valid user
777  *		       - log name in the passwd file,
778  *		       - and if its group id is a valid one
779  *		  	- return 0 if everything is ok. Otherwise, return -1
780  */
781 
782 int
783 check_identity(p)
784 struct	pmtab	*p;
785 {
786 	register struct passwd *pwdp;
787 
788 	if ((p->p_identity == NULL) || (*(p->p_identity) == '\0')) {
789 		log("identity field is missing");
790 		return(-1);
791 	}
792 	if ((pwdp = getpwnam(p->p_identity)) == NULL) {
793 		log("missing or bad passwd entry for <%s>", p->p_identity);
794 		endpwent();
795 		return(-1);
796 	}
797 	if (getgrgid(pwdp->pw_gid) == NULL) {
798 		log("no group entry for %ld", pwdp->pw_gid);
799 		endgrent();
800 		endpwent();
801 		return(-1);
802 	}
803 	p->p_uid = pwdp->pw_uid;
804 	p->p_gid = pwdp->pw_gid;
805 	p->p_dir = strsave(pwdp->pw_dir);
806 	endgrent();
807 	endpwent();
808 	return(0);
809 }
810 
811 /*
812  * expand(cmdp, devp)	- expand %d to device name and %% to %,
813  *				- any other characters are untouched.
814  *				- return the expanded string
815  */
816 static char	*
817 expand(cmdp,devp)
818 char	*cmdp;		/* ptr to cmd string	*/
819 char	*devp;		/* ptr to device name	*/
820 {
821 	register char	*cp, *dp, *np;
822 	static char	buf[BUFSIZ];
823 	cp = cmdp;
824 	np = buf;
825 	dp = devp;
826 	while (*cp) {
827 		if (*cp != '%') {
828 			*np++ = *cp++;
829 			continue;
830 		}
831 		switch (*++cp) {
832 		case 'd':
833 			while (*dp) {
834 				*np++ = *dp++;
835 			}
836 			cp++;
837 			break;
838 		case '%':
839 			*np++ = *cp++;
840 			break;
841 		default:
842 			*np++ = *cp++;
843 			break;
844 		}
845 	}
846 	*np = '\0';
847 	return(buf);
848 }
849 
850