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