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