xref: /illumos-gate/usr/src/cmd/listen/nlps_serv.c (revision 3ce5372277f4657ad0e52d36c979527c4ca22de2)
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 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /* system include files	*/
34 
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <sys/utsname.h>
42 #include <sys/tiuser.h>
43 #include <sys/param.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/mkdev.h>
47 #include <values.h>
48 #include <ctype.h>
49 #include <pwd.h>
50 #include <grp.h>
51 #include <sys/poll.h>
52 #include <sys/stropts.h>
53 #include <utmpx.h>
54 #include <sac.h>
55 
56 
57 /* listener include files */
58 
59 #include "lsparam.h"		/* listener parameters		*/
60 #include "lsfiles.h"		/* listener files info		*/
61 #include "lserror.h"		/* listener error codes		*/
62 #include "lsnlsmsg.h"		/* NLPS listener protocol	*/
63 #include "lssmbmsg.h"		/* MS_NET identifier		*/
64 #include "lsdbf.h"		/* data base file stuff		*/
65 #include "listen.h"
66 
67 /* global variables */
68 
69 FILE *Logfp;		/* file pointer for nlps_server's log file	*/
70 #ifdef DEBUGMODE
71 FILE *Debugfp;		/* debugging output				*/
72 #endif
73 
74 int Dbf_entries;	/* number of private addresses in dbf file */
75 dbf_t	*Dbfhead;
76 dbf_t	*Newdbf;
77 char	*New_cmd_lines;
78 char	*Server_cmd_lines;
79 
80 extern int t_errno;
81 
82 /*
83  * These global symbols are used for logging.
84  * Pid, NLPS_proc, and Lastmsg are significant here; the others aren't used.
85  */
86 int	NLPS_proc = 1;
87 pid_t	Pid;
88 char	Lastmsg[BUFSIZ];
89 char	*Netspec = NULL;
90 int	Splflag = 0;
91 int	Logmax = 0;
92 char	*Mytag = NULL;
93 
94 char	msgbuf[BUFSIZ];
95 char	Altbasedir[BUFSIZ];
96 char	Basedir[BUFSIZ];
97 extern	char *getenv();
98 
99 static void nls_reply(int code, char *text);
100 static void nullfix(void);
101 
102 int
103 main(int argc, char **argv)
104 {
105 	extern int read_dbf();
106 	char *provider;
107 
108 	provider = getenv("PMTAG");
109 	sprintf(Altbasedir, "%s/%s/", ALTDIR, provider);
110 	sprintf(Basedir, "%s/%s/", BASEDIR, provider);
111 	sprintf(msgbuf, "%s/%s", Altbasedir, LOGNAME);
112 	if (!(Logfp = fopen(msgbuf, "a+")))  {
113 		(void)exit(1);
114 	}
115 
116 #ifdef DEBUGMODE
117 	sprintf(msgbuf, "%s/%s", Altbasedir, PDEBUGNAME);
118 	if (!(Debugfp = fopen(msgbuf, "a")))  {
119 		logmessage("NLPS: Unable to open DEBUG file");
120 		(void)exit(1);
121 	}
122 #endif
123 
124 	/*
125 	 * re-sync TLI structures after we were exec'ed from listener
126 	 */
127 
128 	if (t_sync(0) == -1) {
129 		DEBUG((9,"t_sync failed, t_errno %d", t_errno));
130 		logmessage("NLPS: Resynchronization of TLI failed");
131 		(void)exit(1);
132 	}
133 
134 	nlps_server();
135 	return(0);
136 }
137 
138 /*
139  *  nlps_server:
140  */
141 
142 int
143 nlps_server()
144 {
145 	int size;
146 	char buf[RCVBUFSZ];
147 	char **argv;
148 	char *bp = buf;
149 	dbf_t *dbp;
150 	dbf_t *getdbfentry();
151 	extern char **mkdbfargv();
152 
153 	Pid = getpid();
154 	DEBUG((9,"in nlps_server (NLPS/SMB message), pid %ld", Pid));
155 
156 	if ((size = getrequest(bp)) <= 0)  {
157 		logmessage("NLPS: No/bad service request received");
158 		return(-1);
159 	}
160 
161 	if (size < 0)  {
162 		DEBUG((7,"nlps_server(): Error returned from getrequest()" ));
163 		logmessage("NLPS: Error returned from getrequest()");
164 		return(-1);
165 	}
166 
167 	/*
168 	 * if message is NLPS protocol...
169 	 */
170 
171 	if ((!strncmp(bp,NLPSIDSTR,NLPSIDSZ))  && 	/* NLPS request	*/
172 	    (*(bp + NLPSIDSZ) == NLPSSEPCHAR)) {
173 		nls_service(bp, size);
174 		(void)sleep(10);	/* if returned to here, then
175 				 * must sleep for a short period of time to
176 				 * insure that the client received any possible
177 				 * exit response message from the listener.
178 					 */
179 
180 	/*
181 	 * else if message is for the MS-NET file server...
182 	 */
183 
184 	} else if ( (*bp == (char)0xff) && (!strncmp(bp+1,SMBIDSTR,SMBIDSZ)) )  {
185 		if (dbp = getdbfentry(DBF_SMB_CODE))
186 		    if (dbp->dbf_flags & DBF_OFF)
187 			logmessage("NLPS: SMB message, server disabled in data base");
188 		    else    {
189 			argv = mkdbfargv(dbp);
190 			smbservice(bp, size, argv);
191 		    }
192 		else
193 			logmessage("NLPS: SMB message, no data base entry");
194 
195 	/*
196 	 * else, message type is unknown...
197 	 */
198 
199 	} else  {
200 		logmessage("NLPS: Unknown service request (ignored)");
201 		DEBUG((7,"msg size: %d; 1st four chars (hex) %x %x %x %x",
202 			*bp, *(bp+1), *(bp+2), *(bp+3)));
203 	}
204 
205 	/*
206 	 * the routines that start servers return only if there was an error
207 	 * and will have logged their own errors.
208 	 */
209 
210 	return(-1);
211 }
212 
213 
214 /*
215  * getrequest:	read in a full message.  Timeout, in case the client died.
216  *		returns: -1 = timeout or other error.
217  *			 positive number = message size.
218  */
219 
220 int
221 getrequest(bp)
222 char *bp;
223 {
224 	int size;
225 	char *tmp = bp;
226 	int flags;
227 	extern void timeout();
228 	short cnt;
229 	void (*oldhanp)();
230 
231 	DEBUG((9,"in getrequest"));
232 
233 	oldhanp = signal(SIGALRM, timeout);
234 	(void)alarm(ALARMTIME);
235 
236 	/* read in MINMSGSZ to determine type of msg */
237 	if ((size = l_rcv(bp, MINMSGSZ, &flags)) != MINMSGSZ) {
238 		DEBUG((9, "getrequest: l_rcv returned %d", size));
239 		tli_error(E_RCV_MSG, CONTINUE);
240 		return(-1);
241 	}
242 	tmp += size;
243 
244 	/*
245 	 * if message is NLPS protocol...
246 	 */
247 
248 	if ((!strncmp(bp,NLPSIDSTR,NLPSIDSZ))  && 	/* NLPS request	*/
249 	    (*(bp + NLPSIDSZ) == NLPSSEPCHAR)) {
250 
251 		do {
252 			if (++size > RCVBUFSZ) {
253 				logmessage("NLPS: recieve buffer not large enough");
254 				return(-1);
255 			}
256 
257 			if (t_rcv(0, tmp, sizeof(char), &flags) != sizeof(char)) {
258 				tli_error(E_RCV_MSG, CONTINUE);
259 				return(-1);
260 			}
261 
262 		} while (*tmp++ != '\0');
263 
264 
265 
266 	/*
267 	 * else if message is for the MS-NET file server...
268 	 */
269 
270 	} else if ( (*bp == (char)0xff) && (!strncmp(bp+1,SMBIDSTR,SMBIDSZ)) )  {
271 
272 		/* read in 28 more bytes to get count of paramter words */
273 		if (l_rcv(tmp, 28, &flags) != 28) {
274 			tli_error(E_RCV_MSG, CONTINUE);
275 			return(-1);
276 		}
277 		tmp += 28;
278 		size += 28;
279 
280 		/*
281 		 * read amount of paramater words plus word for
282                  * the number of data bytes to follow (2 bytes/word)
283                  */
284 		cnt = (int)*(tmp - 1) * 2 + 2;
285 
286 		if ((size += cnt) > RCVBUFSZ) {
287 			logmessage("NLPS: recieve buffer not large enough");
288 			return(-1);
289 		}
290 
291 		if (l_rcv(tmp, cnt, &flags) != cnt) {
292 			tli_error(E_RCV_MSG, CONTINUE);
293 			return(-1);
294 		}
295 		tmp += cnt;
296 
297 		getword(tmp - 2, &cnt);
298 
299 		if ((size += cnt) > RCVBUFSZ) {
300 			logmessage("NLPS: recieve buffer not large enough");
301 			return(-1);
302 		}
303 
304 		if (l_rcv(tmp, cnt, &flags) != cnt) {
305 			tli_error(E_RCV_MSG, CONTINUE);
306 			return(-1);
307 		}
308 
309 		nullfix();
310 
311 	/*
312 	 * else, message type is unknown...
313 	 */
314 
315 	} else  {
316 		logmessage("NLPS: Unknown service request (ignored)");
317 		DEBUG((7,"msg size: %d; 1st four chars (hex) %x %x %x %x",
318 			*bp, *(bp+1), *(bp+2), *(bp+3)));
319 		return(-1);
320 	}
321 
322 	(void)alarm(0);
323 	signal(SIGALRM, oldhanp);
324 
325 	DEBUG((7,"t_rcv returned %d, flags: %x",size,flags));
326 
327 	return(size);
328 }
329 
330 
331 /*
332  * The following code is for patching a 6300 side bug.  The original
333  * message that comes over may contain 2 null bytes which aren't
334  * part of the message, and if left on the stream, will poison the
335  * server.  Peek into the stream and snarf up those bytes if they
336  * are there.  If anything goes wrong with the I_PEEK, just continue,
337  * if the nulls weren't there, it'll work, and if they were, all that
338  * will happen is that the server will fail.  Just note what happened
339  * in the log file.
340  */
341 
342 static void
343 nullfix(void)
344 {
345 	struct strpeek peek;
346 	register struct strpeek *peekp;
347 	char scratch[BUFSIZ];
348 	char junk[2];
349 	int flags;
350 	int ret;
351 
352 	peekp = &peek;
353 	peekp->flags = 0;
354 	/* need to ask for ctl info to avoid bug in I_PEEK code */
355 	peekp->ctlbuf.maxlen = 1;
356 	peekp->ctlbuf.buf = junk;
357 	peekp->databuf.maxlen = 2;
358 	peekp->databuf.buf = junk;
359 	ret = ioctl(0, I_PEEK, &peek);
360 	if (ret == -1) {
361 		sprintf(scratch, "NLPS: nullfix(): unable to PEEK, errno is %d", errno);
362 		DEBUG((9, "nullfix(): I_PEEK failed, errno is %d", errno));
363 		logmessage(scratch);
364 	}
365 	else if (ret == 0) {
366 		DEBUG((9, "nullfix(): no messages on stream to PEEK"));
367 	}
368 	else {
369 		if (peekp->databuf.len == 2) {
370 			/* Note: junk contains "peeked" data */
371 			DEBUG((9, "peeked <%x> <%x>", junk[0], junk[1]));
372 			if ((junk[0] == 0) && (junk[1] == 0)) {
373 				/* pitch the nulls */
374 				DEBUG((9, "pitching 2 nulls from first peek"));
375 				l_rcv(junk, 2, &flags);
376 			}
377 		}
378 
379 		/*
380 		 * this represents a somewhat pathological case where
381 		 * the "2 nulls" are broken across message boundaries.
382 		 * Pitch the first and hope the next one is there
383 		 */
384 
385 		else if (peekp->databuf.len == 1) {
386 			DEBUG((9, "peeked <%x>", junk[0]));
387 			if (junk[0] == 0) {
388 				/* pitch the first */
389 				DEBUG((9, "split nulls, pitching first"));
390 				l_rcv(junk, 1, &flags);
391 				peekp->databuf.maxlen = 1;
392 				ret = ioctl(0, I_PEEK, &peek);
393 				if (ret == -1) {
394 					sprintf(scratch, "NLPS: nullfix(): unable to PEEK second time, errno is %d", errno);
395 					DEBUG((9, "second peek failed, errno %d", errno));
396 					logmessage(scratch);
397 				}
398 				else if (ret == 0) {
399 					DEBUG((9, "no messages for 2nd peek"));
400 				}
401 				else {
402 					if (peekp->databuf.len == 1) {
403 						DEBUG((9, "2nd peek <%x>", junk[0]));
404 						if (junk[0] == 0) {
405 							/* pitch the second */
406 							DEBUG((9, "pitching 2nd single null"));
407 							l_rcv(junk, 1, &flags);
408 						}
409 						else {
410 							/* uh oh, server will most likely fail */
411 							DEBUG((9, "2nd null not found"));
412 							logmessage("NLPS: nullfix(): threw away a valid null byte");
413 						}
414 					}
415 				}
416 			}
417 		}
418 	}
419 }
420 
421 
422 /*
423  * timeout:	SIGALRM signal handler.  Invoked if t_rcv timed out.
424  *		See comments about 'exit' in nlps_server().
425  */
426 
427 
428 void
429 timeout()
430 {
431 	DEBUG((9, "TIMEOUT"));
432 	error(E_RCV_TMO, EXIT | NOCORE);
433 }
434 
435 
436 
437 /*
438  * nls_service:	Validate and start a server requested via the NLPS protocol
439  *
440  *		version 0:1 -- expect "NLPS:000:001:service_code".
441  *
442  *	returns only if there was an error (either msg format, or couldn't exec)
443  */
444 
445 static char *badversion =
446 	"NLPS: Unknown version of an NLPS service request: %d:%d";
447 static char *disabledmsg =
448 	"NLPS: Request for service code <%s> denied, service is disabled";
449 static char *nlsunknown =
450 	"NLPS: Request for service code <%s> denied, unknown service code";
451 
452 
453 /*
454  * Nlsversion can be used as a NLPS flag (< 0 == not nls service)
455  * and when >= 0, indicates the version of the NLPS protocol used
456  */
457 
458 static int Nlsversion = -1;	/* protocol version	*/
459 
460 int
461 nls_service(bp, size)
462 int  size;
463 char *bp;
464 {
465 	int low, high;
466 	char svc_buf[64];
467 	register char *svc_code_p = svc_buf;
468 	char scratch[256];
469 	register dbf_t *dbp;
470 	dbf_t *getdbfentry();
471 	extern char **mkdbfargv();
472 	int passfd;
473 	int i;
474 
475 	if (nls_chkmsg(bp, size, &low, &high, svc_code_p))  {
476 		if ((low == 0) || (low == 2))
477 			Nlsversion = low;
478 		else  {
479 			sprintf(scratch, badversion, low, high);
480 			logmessage(scratch);
481 			error(E_BAD_VERSION, CONTINUE);
482 			return(-1);
483 		}
484 
485 		DEBUG((9,"nls_service: protocol version %d", Nlsversion));
486 
487 		/*
488 		 * common code for protocol version 0 or 2
489 		 * version 0 allows no answerback message
490 		 * version 2 allows exactly 1 answerback message
491 		 */
492 
493 		if (dbp = getdbfentry(svc_code_p)) {
494 			if (dbp->dbf_flags & DBF_OFF)  {
495 				sprintf(scratch, disabledmsg, svc_code_p);
496 				logmessage(scratch);
497 				nls_reply(NLSDISABLED, scratch);
498 			}
499 			else {
500 				if (dbp->dbf_sflags & CFLAG) {
501 					exec_cmd(dbp, (char **)0);
502 					/* return is an error	*/
503 				}
504 				else {
505 					sprintf(msgbuf,"NLPS (%s) passfd: %s",
506 						dbp->dbf_svc_code,
507 						dbp->dbf_cmd_line);
508 					nls_reply(NLSSTART, msgbuf);
509 					logmessage(msgbuf);
510 					/* open pipe to pass fd through */
511 					if ((passfd = open(dbp->dbf_cmd_line,
512 							O_WRONLY)) < 0) {
513 						sprintf(scratch,"NLPS open failed: %s", dbp->dbf_cmd_line);
514 						logmessage(scratch);
515 					}
516 					DEBUG((9, "pushmod string: %s", dbp->dbf_modules));
517 					if (pushmod(0, dbp->dbf_modules)) {
518 						logmessage("NLPS: Can't push server's modules: exit");
519 						(void)exit(2); /* server, don't log */
520 					}
521 
522 					DEBUG((9, "Running doconfig on %s", dbp->dbf_svc_code));
523 
524 					sprintf(msgbuf,"%s/%s",Basedir,dbp->dbf_svc_code);
525 
526 					if ((i = doconfig(0, msgbuf, NOASSIGN)) != 0) {
527 						DEBUG((9, "doconfig exited with code %d", i));
528 						sprintf(scratch, "doconfig failed on line %d of script %s",
529 								i, msgbuf);
530 						logmessage(scratch);
531 						(void)exit(2);
532 					}
533 					if (ioctl(passfd, I_SENDFD, 0) < 0) {
534 						sprintf(scratch,"NLPS passfd failed: %s", dbp->dbf_cmd_line);
535 						logmessage(scratch);
536 					}
537 				}
538 			}
539 		}
540 		else  {
541 			sprintf(scratch, nlsunknown, svc_code_p);
542 			logmessage(scratch);
543 			nls_reply(NLSUNKNOWN, scratch);
544 		}
545 		exit(2);
546 
547 	}  else
548 		error(E_BAD_FORMAT, CONTINUE);
549 
550 	/* if we're still here, server didn't get exec'ed	*/
551 
552 	return(-1);
553 }
554 
555 
556 
557 /*
558  * nls_chkmsg:	validate message and return fields to caller.
559  *		returns: TRUE == good format
560  *			 FALSE== bad format
561  */
562 
563 int
564 nls_chkmsg(bp, size, lowp, highp, svc_code_p)
565 char *bp, *svc_code_p;
566 int size, *lowp, *highp;
567 {
568 
569 	/* first, make sure bp is null terminated */
570 
571 	if ((*(bp + size - 1)) != (char)0)
572 		return(0);
573 
574 	/* scanf returns number of "matched and assigned items"	*/
575 
576 	return(sscanf(bp, "%*4c:%3d:%3d:%s", lowp, highp, svc_code_p) == 3);
577 
578 }
579 
580 
581 /*
582  * nls_reply:	send the "service request response message"
583  *		when appropriate.  (Valid if running version 2 or greater).
584  *		Must use write(2) since unknown modules may be pushed.
585  *
586  *		Message format:
587  *		protocol_verion_# : message_code_# : message_text
588  */
589 
590 static char *srrpprot = "%d:%d:%s";
591 
592 static void
593 nls_reply(int code, char *text)
594 {
595 	char scratch[256];
596 
597 	/* Nlsversion = -1 for login service */
598 
599 	if (Nlsversion >= 2)  {
600 		DEBUG((7, "nls_reply: sending response message"));
601 		sprintf(scratch, srrpprot, Nlsversion, code, text);
602 		t_snd(0, scratch, strlen(scratch)+1, 0);
603 	}
604 }
605 
606 
607 /*
608  * common code to  start a server process (for any service)
609  * if optional argv is given, info comes from o_argv, else pointer
610  * to dbf struct is used.  In either case, first argument in argv is
611  * full pathname of server. Before exec-ing the server, the caller's
612  * logical address, opt and udata are added to the environment.
613  */
614 
615 static char homeenv[BUFSIZ];
616 #define NETFD	0
617 
618 
619 int
620 exec_cmd(dbf_t *dbp, char **o_argv)
621 {
622 	char *path;
623 	char **argvp;
624 	extern char **environ;
625 	dbf_t *getdbfentry();
626 	extern char **mkdbfargv();
627 	struct passwd *pwdp;
628 	struct group *grpp;
629 	dbf_t *wdbp = dbp;
630 	int	i;
631 
632 	/*
633 	 * o_argv is set during SMB service setup only, in
634 	 * which case dbp is NULL.
635 	 */
636 
637 	if (o_argv) {
638 		argvp = o_argv;
639 		if ((wdbp = getdbfentry(DBF_SMB_CODE)) == NULL) {
640 			/* this shouldn't happen because at this point we've
641 			   already found it once */
642 			logmessage("NLPS: SMB message, missing data base entry");
643 			(void)exit(2); /* server, don't log */
644 		}
645 	}
646 	else
647 		argvp = mkdbfargv(dbp);
648 	path = *argvp;
649 
650 	sprintf(msgbuf,"NLPS (%s) exec: %s",
651 			(dbp)?dbp->dbf_svc_code:DBF_SMB_CODE, path);
652 	nls_reply(NLSSTART, msgbuf);
653 	logmessage(msgbuf);
654 
655 	if (wdbp->dbf_flags & DBF_UTMP) {
656 		pid_t	tmp;
657 		struct	stat	sbuf;
658 		char	*prefix;
659 		char	device[20];
660 		struct	utmpx utline;
661 
662 		/*
663 		 * create a utmpx entry.  extra fork makes parent init,
664 		 * which will clean up the entry.
665 		 */
666 
667 		DEBUG((9, "Creating a utmpx entry for this service "));
668 		if ((tmp = fork()) < 0) {
669 			logmessage("NLPS: Can't fork to create utmpx entry");
670 			exit(2);
671 		}
672 		if (tmp)
673 			exit(0);	/* kill parent */
674 
675 		/*
676 		 * child continues processing, creating utmpx and exec'ing
677 		 * the service
678 		 */
679 
680 		setpgrp();
681 		if (fstat(0, &sbuf) < 0) {
682 			logmessage("NLPS: Stat failed on fd 0: no line "
683 			    "field available for utmpx entry");
684 			*device = '\0';
685 		}
686 		else {
687 			/*
688 			 * MPREFIX is added to the environment by the parent
689 			 * listener process.
690 			 */
691 			prefix = getenv("MPREFIX");
692 			if (minor(sbuf.st_rdev) < 100)
693 				sprintf(device, "%.9s%02.02d", prefix, minor(sbuf.st_rdev));
694 			else
695 				sprintf(device, "%.8s%03.03d", prefix, minor(sbuf.st_rdev));
696 			DEBUG((9, "Device: %s", device));
697 		}
698 		strncpy(utline.ut_user, wdbp->dbf_id,
699 		    sizeof (utline.ut_user) - 1);
700 		sprintf(utline.ut_id, "ps%c%c", SC_WILDC, SC_WILDC);
701 		strncpy(utline.ut_line, device, sizeof (utline.ut_line) - 1);
702 		utline.ut_pid = getpid();
703                 utline.ut_type = USER_PROCESS;
704 		utline.ut_exit.e_termination = 0;
705 		utline.ut_exit.e_exit = 0;
706 		utline.ut_xtime = (time_t) time((time_t *)0);
707 		makeutx(&utline);
708 	}
709 
710 	/* after pushmod, tli calls are questionable?		*/
711 
712 	DEBUG((9, "pushmod string: %s", wdbp->dbf_modules));
713 	if (dbp && pushmod(NETFD, dbp->dbf_modules)) {
714 		logmessage("NLPS: Can't push server's modules: exit");
715 		exit(2); /* server, don't log */
716 	}
717 
718 	DEBUG((9, "Running doconfig on %s", wdbp->dbf_svc_code));
719 	if ((i = doconfig(NETFD, wdbp->dbf_svc_code, 0)) != 0) {
720 		DEBUG((9, "doconfig exited with code %d", i));
721 		sprintf(msgbuf, "doconfig failed on line %d of script %s",
722 				i, wdbp->dbf_svc_code);
723 		logmessage(msgbuf);
724 	}
725 
726 	if (wdbp == NULL) {
727 		logmessage("NLPS: No database entry");
728 		exit(2); /* server, don't log */
729 	}
730 
731 	if ((pwdp = getpwnam(wdbp->dbf_id)) == NULL)  {
732 		sprintf(msgbuf, "NLPS: Missing or bad passwd entry for <%s>",wdbp->dbf_id);
733 		logmessage(msgbuf);
734 		exit(2); /* server, don't log */
735 	}
736 
737 
738 	if (setgid(pwdp->pw_gid)) {
739 		if ((grpp = getgrgid(pwdp->pw_gid)) == NULL) {
740 			sprintf(msgbuf, "NLPS: No group entry for %ld", pwdp->pw_gid);
741 			logmessage(msgbuf);
742 			exit(2); /* server, don't log */
743 		}
744 		sprintf(msgbuf, "NLPS: Cannot set group id to %s", grpp->gr_name);
745 		logmessage(msgbuf);
746 		(void)exit(2); /* server, don't log */
747 	}
748 
749 	if (setuid(pwdp->pw_uid)) {
750 		sprintf(msgbuf, "NLPS: Cannot set user id to %s", wdbp->dbf_id);
751 		logmessage(msgbuf);
752 		(void)exit(2); /* server, don't log */
753 	}
754 
755 	if (chdir(pwdp->pw_dir)) {
756 		sprintf(msgbuf, "NLPS: Cannot chdir to %s", pwdp->pw_dir);
757 		logmessage(msgbuf);
758 		(void)exit(2); /* server, don't log */
759 	}
760 
761 	DEBUG((9, "New uid %ld New gid %ld", getuid(), getgid()));
762 
763 	sprintf(homeenv, "HOME=%s", pwdp->pw_dir);
764 	DEBUG((9,"HOME=%s", pwdp->pw_dir));
765 	putenv(homeenv);
766 	endpwent();
767 
768 	fclose(Logfp);
769 #ifdef DEBUGMODE
770 	fclose(Debugfp);
771 #endif
772 	execve(path, argvp, environ);
773 
774 	/* exec returns only on failure!		*/
775 
776 	logmessage("NLPS server: could not exec service");
777 	sys_error(E_SYS_ERROR, CONTINUE);
778 	return(-1);
779 }
780 
781 
782 
783 
784 
785 /*
786  * isdigits:	string version of isdigit.  (See ctype(3))
787  */
788 
789 /* This routine is public here and used in lsdbf.c as an external */
790 int
791 isdigits(p)
792 register char *p;
793 {
794 	register int flag = 1;
795 
796 	if (!strlen(p))
797 		return(0);
798 
799 	while (*p)
800 		if (!isdigit(*p++))
801 			flag = 0;
802 	return(flag);
803 }
804 
805 
806 int
807 l_rcv(bufp, bytes, flagp)
808 char *bufp;
809 int bytes;
810 int *flagp;
811 {
812 	register int n;
813 	register int count = bytes;
814 	register char *bp = bufp;
815 
816 	DEBUG((9, "in l_rcv"));
817 
818 	do {
819 		*flagp = 0;
820 		n = t_rcv(0, bp, count, flagp);
821 		DEBUG((9, "l_rcv, after t_rcv call, n =  %d",n));
822 
823 		if (n < 0) {
824 			DEBUG((9, "l_rcv, t_errno is %d", t_errno));
825 #ifdef DEBUGMODE
826 			if (t_errno == TLOOK) {
827 				DEBUG((9, "l_rcv, t_look returns %d", t_look(0)));
828 			}
829 #endif
830 			return(n);
831 		}
832 		count -= n;
833 		bp += n;
834 	} while (count > 0);
835 
836 	return(bp - bufp);
837 }
838 
839 
840 /*
841  * getdbfentry:	Given a service code, return a pointer to the dbf_t
842  *		entry.  Return NULL if the entry doesn't exist.
843  *		Reads the data base, one line at a time, into
844  *		Dbf_line_buf.
845  */
846 
847 static	char	Dbf_line_buf[DBFLINESZ];
848 static	dbf_t	Dbf_entry;
849 
850 dbf_t *
851 getdbfentry(svc_code_p)
852 register char *svc_code_p;
853 {
854 	FILE	*dbfp;
855 	char	dbfname[BUFSIZ];
856 
857 	sprintf(dbfname, "%s/%s", Basedir, DBFNAME);
858 	if ((dbfp = fopen(dbfname, "r")) == NULL) {
859 		DEBUG((9, "open of database file %s failed", DBFNAME));
860 		logmessage("NLPS: Unable to open database file");
861 		return((dbf_t *)NULL);
862 	}
863 
864 	DEBUG((9, "database file opened, looking for %s", svc_code_p));
865 	while (rd_dbf_line(dbfp, Dbf_line_buf, &Dbf_entry.dbf_svc_code,
866 		&Dbf_entry.dbf_flags, &Dbf_entry.dbf_id, &Dbf_entry.dbf_res1,
867 		&Dbf_entry.dbf_res2, &Dbf_entry.dbf_res3,&Dbf_entry.dbf_prv_adr,
868 		&Dbf_entry.dbf_prognum, &Dbf_entry.dbf_version,
869 		&Dbf_entry.dbf_modules, &Dbf_entry.dbf_sflags,
870 		&Dbf_entry.dbf_cmd_line) > 0) {
871 
872 		/* see if this line is the one we want (svc_code match) */
873 		if (!strcmp(Dbf_entry.dbf_svc_code, svc_code_p)) {
874 			fclose(dbfp);
875 			return(&Dbf_entry);
876 		}
877 	}
878 
879 	DEBUG((9, "No svc code match"));
880 	fclose(dbfp);
881 	return((dbf_t *)0);	/* svc code not in database	*/
882 }
883