xref: /netbsd/usr.sbin/rpc.pcnfsd/pcnfsd_misc.c (revision 457d5a17)
1 /*	$NetBSD: pcnfsd_misc.c,v 1.2 1995/07/25 22:20:42 gwr Exp $	*/
2 
3 /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_misc.c 1.5 92/01/24 19:59:13 SMI */
4 /*
5 **=====================================================================
6 ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
7 **	@(#)pcnfsd_misc.c	1.5	1/24/92
8 **=====================================================================
9 */
10 #include "common.h"
11 /*
12 **=====================================================================
13 **             I N C L U D E   F I L E   S E C T I O N                *
14 **                                                                    *
15 ** If your port requires different include files, add a suitable      *
16 ** #define in the customization section, and make the inclusion or    *
17 ** exclusion of the files conditional on this.                        *
18 **=====================================================================
19 */
20 #include "pcnfsd.h"
21 
22 #include <stdio.h>
23 #include <pwd.h>
24 #include <sys/file.h>
25 #include <signal.h>
26 #include <sys/time.h>
27 #include <sys/stat.h>
28 #include <sys/ioctl.h>
29 #include <netdb.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <ctype.h>
33 
34 #ifdef ISC_2_0
35 #include <sys/fcntl.h>
36 #endif
37 
38 #ifdef SHADOW_SUPPORT
39 #include <shadow.h>
40 #endif
41 
42 #ifdef WTMP
43 int wtmp_enabled = 1;
44 #endif
45 
46 #ifdef USE_GETUSERSHELL
47 extern char *getusershell();
48 #endif
49 
50 /*
51 **---------------------------------------------------------------------
52 ** Other #define's
53 **---------------------------------------------------------------------
54 */
55 
56 #define	zchar		0x5b
57 
58 char            tempstr[256];
59 extern char	sp_name[1024]; /* in pcnfsd_print.c */
60 
61 /*
62 **=====================================================================
63 **                      C O D E   S E C T I O N                       *                    **=====================================================================
64 */
65 /*
66 **---------------------------------------------------------------------
67 **                          Support procedures
68 **---------------------------------------------------------------------
69 */
70 
71 
72 void
73 scramble(s1, s2)
74 char           *s1;
75 char           *s2;
76 {
77 	while (*s1)
78 	      {
79 	      *s2++ = (*s1 ^ zchar) & 0x7f;
80 	      s1++;
81 	      }
82 	*s2 = 0;
83 }
84 
85 
86 
87 struct passwd  *
88 get_password(usrnam)
89 char           *usrnam;
90 {
91 struct passwd  *p;
92 static struct passwd localp;
93 char           *pswd;
94 char           *ushell;
95 int		ok = 0;
96 
97 
98 #ifdef SHADOW_SUPPORT
99 struct spwd    *sp;
100 int             shadowfile;
101 #endif
102 
103 #ifdef SHADOW_SUPPORT
104 	/*
105         **--------------------------------------------------------------
106 	** Check the existence of SHADOW.  If it is there, then we are
107 	** running a two-password-file system.
108         **--------------------------------------------------------------
109 	*/
110 	if (access(SHADOW, 0))
111 	   shadowfile = 0;	/* SHADOW is not there */
112 	else
113 	   shadowfile = 1;
114 
115 	setpwent();
116 	if (shadowfile)
117 	   (void) setspent();	/* Setting the shadow password
118 					 * file */
119 	if ((p = getpwnam(usrnam)) == (struct passwd *)NULL ||
120 	   (shadowfile && (sp = getspnam(usrnam)) == (struct spwd *)NULL))
121 	return ((struct passwd *)NULL);
122 
123 	if (shadowfile)
124            {
125 	   pswd = sp->sp_pwdp;
126 	   (void) endspent();
127 	   }
128         else
129 	   pswd = p->pw_passwd;
130 
131 #else
132 	p = getpwnam(usrnam);
133 	if (p == (struct passwd *)NULL)
134 		return ((struct passwd *)NULL);
135 	pswd = p->pw_passwd;
136 #endif
137 
138 #ifdef ISC_2_0
139 	/*
140         **-----------------------------------------------------------
141 	** We may have an 'x' in which case look in /etc/shadow ..
142         **-----------------------------------------------------------
143         */
144 	if (((strlen(pswd)) == 1) && pswd[0] == 'x')
145 	   {
146 	   struct spwd    *shadow = getspnam(usrnam);
147 
148 	   if (!shadow)
149 	      return ((struct passwd *)NULL);
150 	   pswd = shadow->sp_pwdp;
151 	   }
152 #endif
153 	localp = *p;
154 	localp.pw_passwd = pswd;
155 #ifdef USE_GETUSERSHELL
156 
157 	setusershell();
158 	while(ushell = getusershell()){
159 		if(!strcmp(ushell, localp.pw_shell)) {
160 			ok = 1;
161 			break;
162 		}
163 	}
164 	endusershell();
165 	if(!ok)
166 		return ((struct passwd *)NULL);
167 #else
168 /*
169  * the best we can do is to ensure that the shell ends in "sh"
170  */
171 	ushell = localp.pw_shell;
172 	if(strlen(ushell) < 2)
173 		return ((struct passwd *)NULL);
174 	ushell += strlen(ushell) - 2;
175 	if(strcmp(ushell, "sh"))
176 		return ((struct passwd *)NULL);
177 
178 #endif
179 	return (&localp);
180 }
181 
182 
183 /*
184 **---------------------------------------------------------------------
185 **                      Print support procedures
186 **---------------------------------------------------------------------
187 */
188 
189 char           *
190 mapfont(f, i, b)
191 	char            f;
192 	char            i;
193 	char            b;
194 {
195 	static char     fontname[64];
196 
197 	fontname[0] = 0;	/* clear it out */
198 
199 	switch (f) {
200 	case 'c':
201 		(void)strcpy(fontname, "Courier");
202 		break;
203 	case 'h':
204 		(void)strcpy(fontname, "Helvetica");
205 		break;
206 	case 't':
207 		(void)strcpy(fontname, "Times");
208 		break;
209 	default:
210 		(void)strcpy(fontname, "Times-Roman");
211 		goto finis ;
212 	}
213 	if (i != 'o' && b != 'b') {	/* no bold or oblique */
214 		if (f == 't')	/* special case Times */
215 			(void)strcat(fontname, "-Roman");
216 		goto finis;
217 	}
218 	(void)strcat(fontname, "-");
219 	if (b == 'b')
220 		(void)strcat(fontname, "Bold");
221 	if (i == 'o')		/* o-blique */
222 		(void)strcat(fontname, f == 't' ? "Italic" : "Oblique");
223 
224 finis:	return (&fontname[0]);
225 }
226 
227 /*
228  * run_ps630 performs the Diablo 630 emulation filtering process. ps630
229  * was broken in certain Sun releases: it would not accept point size or
230  * font changes. If your version is fixed, undefine the symbol
231  * PS630_IS_BROKEN and rebuild pc-nfsd.
232  */
233 /* #define PS630_IS_BROKEN 1 */
234 
235 void
236 run_ps630(f, opts)
237 	char           *f;
238 	char           *opts;
239 {
240 	char            temp_file[256];
241 	char            commbuf[256];
242 	int             i;
243 
244 	(void)strcpy(temp_file, f);
245 	(void)strcat(temp_file, "X");	/* intermediate file name */
246 
247 #ifndef PS630_IS_BROKEN
248 	(void)sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
249 		opts[2], opts[3], temp_file);
250 	(void)strcat(commbuf, mapfont(opts[4], opts[5], opts[6]));
251 	(void)strcat(commbuf, " -F ");
252 	(void)strcat(commbuf, mapfont(opts[7], opts[8], opts[9]));
253 	(void)strcat(commbuf, "  ");
254 	(void)strcat(commbuf, f);
255 #else	/* PS630_IS_BROKEN */
256 	/*
257 	 * The pitch and font features of ps630 appear to be broken at
258 	 * this time.
259 	 */
260 	(void)sprintf(commbuf, "ps630 -p %s %s", temp_file, f);
261 #endif	/* PS630_IS_BROKEN */
262 
263 
264 	if (i = system(commbuf)) {
265 		/*
266 		 * Under (un)certain conditions, ps630 may return -1 even
267 		 * if it worked. Hence the commenting out of this error
268 		 * report.
269 		 */
270 		 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
271 		/* exit(1); */
272 	}
273 	if (rename(temp_file, f)) {
274 		perror("run_ps630: rename");
275 		exit(1);
276 	}
277 	return;
278 }
279 
280 
281 
282 
283 /*
284 **---------------------------------------------------------------------
285 **                      WTMP update support
286 **---------------------------------------------------------------------
287 */
288 
289 
290 #ifdef WTMP
291 
292 #include <utmp.h>
293 
294 #ifndef	_PATH_WTMP
295 #define _PATH_WTMP "/usr/adm/wtmp"
296 #endif
297 
298 void
299 wlogin(name, req)
300 	char *name;
301 	struct svc_req *req;
302 {
303 	extern char *inet_ntoa();
304 	struct sockaddr_in *who;
305 	struct hostent *hp;
306 	char *host;
307 	struct utmp ut;
308 	int fd;
309 
310 	if(!wtmp_enabled)
311 		return;
312 
313 	/* Get network address of client. */
314 	who = &req->rq_xprt->xp_raddr;
315 
316 	/* Get name of connected client */
317 	hp = gethostbyaddr((char *)&who->sin_addr,
318 			   sizeof (struct in_addr),
319 			   who->sin_family);
320 
321 	if (hp && (strlen(hp->h_name) <= sizeof(ut.ut_host))) {
322 		host = hp->h_name;
323 	} else {
324 		host = inet_ntoa(who->sin_addr);
325 	}
326 
327 	(void) strcpy(ut.ut_line, "PC-NFS");
328 	(void) strncpy(ut.ut_name,name,sizeof ut.ut_name);
329 	(void) strncpy(ut.ut_host, host, sizeof ut.ut_host);
330 	ut.ut_time = time( (time_t *) 0);
331 
332 	if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
333 		(void)write(fd, (char *)&ut, sizeof(struct utmp));
334 		(void)close(fd);
335 	}
336 }
337 #endif WTMP
338 
339 /*
340 **---------------------------------------------------------------------
341 **                      Run-process-as-user procedures
342 **---------------------------------------------------------------------
343 */
344 
345 
346 #define	READER_FD	0
347 #define	WRITER_FD	1
348 
349 static int      child_pid;
350 
351 static char     cached_user[64] = "";
352 static uid_t    cached_uid;
353 static gid_t    cached_gid;
354 
355 static	struct sigaction old_action;
356 static	struct sigaction new_action;
357 static	struct itimerval timer;
358 
359 int interrupted = 0;
360 static	FILE *pipe_handle;
361 
362 static	void myhandler()
363 {
364  interrupted = 1;
365  fclose(pipe_handle);
366  kill(child_pid, SIGKILL);
367  msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
368 }
369 
370 void start_watchdog(n)
371 int n;
372 {
373 	/*
374 	 * Setup SIGALRM handler, force interrupt of ongoing syscall
375 	 */
376 
377 	new_action.sa_handler = myhandler;
378 	sigemptyset(&(new_action.sa_mask));
379 	new_action.sa_flags = 0;
380 #ifdef SA_INTERRUPT
381 	new_action.sa_flags |= SA_INTERRUPT;
382 #endif
383 	sigaction(SIGALRM, &new_action, &old_action);
384 
385 	/*
386 	 * Set interval timer for n seconds
387 	 */
388 	timer.it_interval.tv_sec = 0;
389 	timer.it_interval.tv_usec = 0;
390 	timer.it_value.tv_sec = n;
391 	timer.it_value.tv_usec = 0;
392 	setitimer(ITIMER_REAL, &timer, NULL);
393 	interrupted = 0;
394 
395 }
396 
397 void stop_watchdog()
398 {
399 	/*
400 	 * Cancel timer
401 	 */
402 
403 	timer.it_interval.tv_sec = 0;
404 	timer.it_interval.tv_usec = 0;
405 	timer.it_value.tv_sec = 0;
406 	timer.it_value.tv_usec = 0;
407 	setitimer(ITIMER_REAL, &timer, NULL);
408 
409 	/*
410  	 * restore old signal handling
411 	 */
412 	sigaction(SIGALRM, &old_action, NULL);
413 }
414 
415 
416 
417 FILE           *
418 su_popen(user, cmd, maxtime)
419 	char           *user;
420 	char           *cmd;
421 	int		maxtime;
422 {
423 	int             p[2];
424 	int             parent_fd, child_fd, pid;
425 	struct passwd *pw;
426 
427 	if (strcmp(cached_user, user)) {
428 		pw = getpwnam(user);
429 		if (!pw)
430 			pw = getpwnam("nobody");
431 		if (pw) {
432 			cached_uid = pw->pw_uid;
433 			cached_gid = pw->pw_gid;
434 			strcpy(cached_user, user);
435 		} else {
436 			cached_uid = (uid_t) (-2);
437 			cached_gid = (gid_t) (-2);
438 			cached_user[0] = '\0';
439 		}
440 	}
441 	if (pipe(p) < 0) {
442 		msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
443 		return (NULL);
444 	}
445 	parent_fd = p[READER_FD];
446 	child_fd = p[WRITER_FD];
447 	if ((pid = fork()) == 0) {
448 		int             i;
449 
450 		for (i = 0; i < 10; i++)
451 			if (i != child_fd)
452 				(void) close(i);
453 		if (child_fd != 1) {
454 			(void) dup2(child_fd, 1);
455 			(void) close(child_fd);
456 		}
457 		dup2(1, 2);	/* let's get stderr as well */
458 
459 		(void) setgid(cached_gid);
460 		(void) setuid(cached_uid);
461 
462 		(void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
463 		_exit(255);
464 	}
465 	if (pid == -1) {
466 		msg_out("rpc.pcnfsd: fork failed");
467 		close(parent_fd);
468 		close(child_fd);
469 		return (NULL);
470 	}
471 	child_pid = pid;
472 	close(child_fd);
473 	start_watchdog(maxtime);
474 	pipe_handle = fdopen(parent_fd, "r");
475 	return (pipe_handle);
476 }
477 
478 int
479 su_pclose(ptr)
480 	FILE           *ptr;
481 {
482 	int             pid, status;
483 
484 	stop_watchdog();
485 
486 	fclose(ptr);
487 	if (child_pid == -1)
488 		return (-1);
489 	while ((pid = wait(&status)) != child_pid && pid != -1);
490 	return (pid == -1 ? -1 : status);
491 }
492 
493 
494 /*
495 ** The following routine reads a file "/etc/pcnfsd.conf" if present,
496 ** and uses it to replace certain builtin elements, like the
497 ** name of the print spool directory. The configuration file
498 ** Is the usual kind: Comments begin with '#', blank lines are ignored,
499 ** and valid lines are of the form
500 **
501 **	<keyword><whitespace><value>
502 **
503 ** The following keywords are recognized:
504 **
505 **	spooldir
506 **	printer name alias-for command
507 **	wtmp yes|no
508 */
509 void
510 config_from_file()
511 {
512 FILE *fd;
513 char buff[1024];
514 char *cp;
515 char *kw;
516 char *val;
517 char *arg1;
518 char *arg2;
519 
520 	if((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
521 		return;
522 	while(fgets(buff, 1024, fd)) {
523 		cp = strchr(buff, '\n');
524 		*cp = '\0';
525 		cp = strchr(buff, '#');
526 		if(cp)
527 			*cp = '\0';
528 		kw = strtok(buff, " \t");
529 		if(kw == NULL)
530 			continue;
531 		val = strtok(NULL, " \t");
532 		if(val == NULL)
533 			continue;
534 		if(!mystrcasecmp(kw, "spooldir")) {
535 			strcpy(sp_name, val);
536 			continue;
537 		}
538 #ifdef WTMP
539 		if(!mystrcasecmp(kw, "wtmp")) {
540 			/* assume default is YES, just look for negatives */
541 			if(!mystrcasecmp(val, "no") ||
542 			   !mystrcasecmp(val, "off") ||
543 			   !mystrcasecmp(val, "disable") ||
544 			   !strcmp(val, "0"))
545 				wtmp_enabled = 0;;
546 			continue;
547 		}
548 #endif
549 		if(!mystrcasecmp(kw, "printer")) {
550 			arg1 = strtok(NULL, " \t");
551 			arg2 = strtok(NULL, "");
552 			(void)add_printer_alias(val, arg1, arg2);
553 			continue;
554 		}
555 /*
556 ** Add new cases here
557 */
558 	}
559 	fclose(fd);
560 }
561 
562 
563 /*
564 ** The following are replacements for the SunOS library
565 ** routines strcasecmp and strncasecmp, which SVR4 doesn't
566 ** include.
567 */
568 
569 mystrcasecmp(s1, s2)
570 	char *s1, *s2;
571 {
572 
573 	while (toupper(*s1) == toupper(*s2++))
574 		if (*s1++ == '\0')
575 			return(0);
576 	return(toupper(*s1) - toupper(*--s2));
577 }
578 
579 mystrncasecmp(s1, s2, n)
580 	char *s1, *s2;
581 	int n;
582 {
583 
584 	while (--n >= 0 && toupper(*s1) == toupper(*s2++))
585 		if (*s1++ == '\0')
586 			return(0);
587 	return(n < 0 ? 0 : toupper(*s1) - toupper(*--s2));
588 }
589 
590 
591 /*
592 ** strembedded - returns true if s1 is embedded (in any case) in s2
593 */
594 
595 int strembedded(s1, s2)
596 char *s1;
597 char *s2;
598 {
599 	while(*s2) {
600 		if(!mystrcasecmp(s1, s2))
601 			return 1;
602 		s2++;
603 	}
604 	return 0;
605 }
606