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