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