xref: /netbsd-src/usr.sbin/rpc.pcnfsd/pcnfsd_misc.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: pcnfsd_misc.c,v 1.15 2012/11/04 22:26:04 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 #ifdef SUPPORT_UTMPX
41 #include <utmpx.h>
42 #endif
43 
44 #ifdef ISC_2_0
45 #include <sys/fcntl.h>
46 #endif
47 
48 #ifdef SHADOW_SUPPORT
49 #include <shadow.h>
50 #endif
51 
52 #ifdef WTMP
53 int     wtmp_enabled = 1;
54 #endif
55 
56 #include "common.h"
57 #include "pcnfsd.h"
58 #include "extern.h"
59 
60 /*
61 **---------------------------------------------------------------------
62 ** Other #define's
63 **---------------------------------------------------------------------
64 */
65 
66 #define	zchar		0x5b
67 
68 char    tempstr[256];
69 
70 char   *mapfont __P((char, char, char));
71 void	myhandler __P((int));
72 void	start_watchdog __P((int));
73 void	stop_watchdog __P((void));
74 
75 /*
76 **=====================================================================
77 **                      C O D E   S E C T I O N                       *
78 **=====================================================================
79 */
80 /*
81 **---------------------------------------------------------------------
82 **                          Support procedures
83 **---------------------------------------------------------------------
84 */
85 
86 
87 void
88 scramble(s1, s2)
89 	char   *s1;
90 	char   *s2;
91 {
92 	while (*s1) {
93 		*s2++ = (*s1 ^ zchar) & 0x7f;
94 		s1++;
95 	}
96 	*s2 = 0;
97 }
98 
99 
100 
101 struct passwd *
102 get_password(usrnam)
103 	char   *usrnam;
104 {
105 	struct passwd *p;
106 	static struct passwd localp;
107 	__aconst char *pswd, *ushell;
108 
109 
110 #ifdef SHADOW_SUPPORT
111 	struct spwd *sp;
112 	int     shadowfile;
113 #endif
114 
115 #ifdef SHADOW_SUPPORT
116 /*
117 **--------------------------------------------------------------
118 ** Check the existence of SHADOW.  If it is there, then we are
119 ** running a two-password-file system.
120 **--------------------------------------------------------------
121 */
122 	if (access(SHADOW, 0))
123 		shadowfile = 0;	/* SHADOW is not there */
124 	else
125 		shadowfile = 1;
126 
127 	setpwent();
128 	if (shadowfile)
129 		(void) setspent();	/* Setting the shadow password file */
130 	if ((p = getpwnam(usrnam)) == NULL ||
131 	    (shadowfile && (sp = getspnam(usrnam)) == NULL))
132 		return (NULL);
133 
134 	if (shadowfile) {
135 		pswd = sp->sp_pwdp;
136 		(void) endspent();
137 	} else
138 		pswd = p->pw_passwd;
139 
140 #else
141 	p = getpwnam(usrnam);
142 	if (p == NULL)
143 		return (NULL);
144 	pswd = p->pw_passwd;
145 #endif
146 
147 #ifdef ISC_2_0
148 /* *----------------------------------------------------------- * We
149  * may have an 'x' in which case look in /etc/shadow ..
150  * *----------------------------------------------------------- */
151 	if (((strlen(pswd)) == 1) && pswd[0] == 'x') {
152 		struct spwd *shadow = getspnam(usrnam);
153 
154 		if (!shadow)
155 			return (NULL);
156 		pswd = shadow->sp_pwdp;
157 	}
158 #endif
159 	localp = *p;
160 	localp.pw_passwd = pswd;
161 #ifdef USE_GETUSERSHELL
162 
163 	setusershell();
164 	while (ushell = getusershell()) {
165 		if (!strcmp(ushell, localp.pw_shell)) {
166 			ok = 1;
167 			break;
168 		}
169 	}
170 	endusershell();
171 	if (!ok)
172 		return (NULL);
173 #else
174 /*
175 * the best we can do is to ensure that the shell ends in "sh"
176 */
177 	ushell = localp.pw_shell;
178 	if (strlen(ushell) < 2)
179 		return (NULL);
180 	ushell += strlen(ushell) - 2;
181 	if (strcmp(ushell, "sh"))
182 		return (NULL);
183 
184 #endif
185 	return (&localp);
186 }
187 
188 
189 
190 /*
191 **---------------------------------------------------------------------
192 **                      Print support procedures
193 **---------------------------------------------------------------------
194 */
195 
196 
197 char   *
198 mapfont(char f, char i, 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) strlcpy(fontname, "Courier", sizeof(fontname));
207 		break;
208 	case 'h':
209 		(void) strlcpy(fontname, "Helvetica", sizeof(fontname));
210 		break;
211 	case 't':
212 		(void) strlcpy(fontname, "Times", sizeof(fontname));
213 		break;
214 	default:
215 		(void) strlcpy(fontname, "Times-Roman", sizeof(fontname));
216 		goto finis;
217 	}
218 	if (i != 'o' && b != 'b') {	/* no bold or oblique */
219 		if (f == 't')	/* special case Times */
220 			(void) strlcat(fontname, "-Roman", sizeof(fontname));
221 		goto finis;
222 	}
223 	(void) strlcat(fontname, "-", sizeof(fontname));
224 	if (b == 'b')
225 		(void) strlcat(fontname, "Bold", sizeof(fontname));
226 	if (i == 'o')		/* o-blique */
227 		(void) strlcat(fontname, f == 't' ? "Italic" : "Oblique",
228 		    sizeof(fontname));
229 
230 finis:	return (&fontname[0]);
231 }
232 /*
233 * run_ps630 performs the Diablo 630 emulation filtering process. ps630
234 * was broken in certain Sun releases: it would not accept point size or
235 * font changes. If your version is fixed, undefine the symbol
236 * PS630_IS_BROKEN and rebuild pc-nfsd.
237 */
238 /* #define PS630_IS_BROKEN 1 */
239 
240 void
241 run_ps630(f, opts)
242 	char   *f;
243 	char   *opts;
244 {
245 	char    temp_file[256];
246 	char    commbuf[256];
247 	int     i;
248 
249 	(void) strlcpy(temp_file, f, sizeof(temp_file));
250 	(void) strlcat(temp_file, "X", sizeof(temp_file)); /* intermediate file name */
251 
252 #ifndef PS630_IS_BROKEN
253 	(void) snprintf(commbuf, sizeof(commbuf), "ps630 -s %c%c -p %s -f ",
254 	    opts[2], opts[3], temp_file);
255 	(void) strlcat(commbuf, mapfont(opts[4], opts[5], opts[6]),
256 	    sizeof(commbuf));
257 	(void) strlcat(commbuf, " -F ", sizeof(commbuf));
258 	(void) strlcat(commbuf, mapfont(opts[7], opts[8], opts[9]),
259 	    sizeof(commbuf));
260 	(void) strlcat(commbuf, "  ", sizeof(commbuf));
261 	(void) strlcat(commbuf, f, sizeof(commbuf));
262 #else				/* PS630_IS_BROKEN */
263 /*
264  * The pitch and font features of ps630 appear to be broken at
265  * this time.
266  */
267 	(void) snprintf(commbuf, sizeof(commbuf), "ps630 -p %s %s",
268 	    temp_file, f);
269 #endif				/* PS630_IS_BROKEN */
270 
271 
272 	if ((i = system(commbuf)) != 0) {
273 		/*
274 		 * Under (un)certain conditions, ps630 may return -1 even
275 		 * if it worked. Hence the commenting out of this error
276 		 * report.
277 		 */
278 		 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
279 		/* exit(1); */
280 	}
281 	if (rename(temp_file, f)) {
282 		perror("run_ps630: rename");
283 		exit(1);
284 	}
285 	return;
286 }
287 
288 
289 
290 
291 
292 /*
293 **---------------------------------------------------------------------
294 **                      WTMP update support
295 **---------------------------------------------------------------------
296 */
297 
298 
299 #ifdef WTMP
300 void
301 wlogin(name, req)
302 	char   *name;
303 	struct svc_req *req;
304 {
305 	struct sockaddr_in *who;
306 	struct hostent *hp;
307 	char *host;
308 
309 	if (!wtmp_enabled)
310 		return;
311 
312 /* Get network address of client. */
313 	who = &req->rq_xprt->xp_raddr;
314 
315 /* Get name of connected client */
316 	hp = gethostbyaddr((char *) &who->sin_addr,
317 	    sizeof(struct in_addr),
318 	    who->sin_family);
319 
320 	if (hp) {
321 		host = hp->h_name;
322 	} else {
323 		host = inet_ntoa(who->sin_addr);
324 	}
325 
326 #ifdef SUPPORT_UTMP
327 	logwtmp("PC-NFS", name, host);
328 #endif
329 #ifdef SUPPORT_UTMPX
330 	logwtmpx("PC-NFS", name, host, 0, USER_PROCESS);
331 #endif
332 }
333 #endif				/* WTMP */
334 
335 
336 /*
337 **---------------------------------------------------------------------
338 **                      Run-process-as-user procedures
339 **---------------------------------------------------------------------
340 */
341 
342 
343 #define	READER_FD	0
344 #define	WRITER_FD	1
345 
346 static int child_pid;
347 
348 static char cached_user[64] = "";
349 static uid_t cached_uid;
350 static gid_t cached_gid;
351 
352 static struct sigaction old_action;
353 static struct sigaction new_action;
354 static struct itimerval timer;
355 
356 int     interrupted = 0;
357 static FILE *pipe_handle;
358 
359 void
360 myhandler(dummy)
361 	int     dummy;
362 {
363 	interrupted = 1;
364 	fclose(pipe_handle);
365 	kill(child_pid, SIGKILL);
366 	msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
367 }
368 
369 void
370 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
398 stop_watchdog()
399 {
400 /*
401  * Cancel timer
402  */
403 
404 	timer.it_interval.tv_sec = 0;
405 	timer.it_interval.tv_usec = 0;
406 	timer.it_value.tv_sec = 0;
407 	timer.it_value.tv_usec = 0;
408 	setitimer(ITIMER_REAL, &timer, NULL);
409 
410 /*
411  * restore old signal handling
412  */
413 	sigaction(SIGALRM, &old_action, NULL);
414 }
415 
416 FILE   *
417 su_popen(user, cmd, maxtime)
418 	char   *user;
419 	char   *cmd;
420 	int     maxtime;
421 {
422 	int     p[2];
423 	int     parent_fd, child_fd, pid;
424 	struct passwd *pw;
425 
426 	if (strcmp(cached_user, user)) {
427 		pw = getpwnam(user);
428 		if (!pw)
429 			pw = getpwnam("nobody");
430 		if (pw) {
431 			cached_uid = pw->pw_uid;
432 			cached_gid = pw->pw_gid;
433 			strlcpy(cached_user, user, sizeof(cached_user));
434 		} else {
435 			cached_uid = (uid_t) (-2);
436 			cached_gid = (gid_t) (-2);
437 			cached_user[0] = '\0';
438 		}
439 	}
440 	if (pipe(p) < 0) {
441 		msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
442 		return (NULL);
443 	}
444 	parent_fd = p[READER_FD];
445 	child_fd = p[WRITER_FD];
446 	if ((pid = fork()) == 0) {
447 		int     i;
448 
449 		for (i = 0; i < 10; i++)
450 			if (i != child_fd)
451 				(void) close(i);
452 		if (child_fd != 1) {
453 			(void) dup2(child_fd, 1);
454 			(void) close(child_fd);
455 		}
456 		dup2(1, 2);	/* let's get stderr as well */
457 
458 		(void) setgid(cached_gid);
459 		(void) setuid(cached_uid);
460 
461 		(void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
462 		_exit(255);
463 	}
464 	if (pid == -1) {
465 		msg_out("rpc.pcnfsd: fork failed");
466 		close(parent_fd);
467 		close(child_fd);
468 		return (NULL);
469 	}
470 	child_pid = pid;
471 	close(child_fd);
472 	start_watchdog(maxtime);
473 	pipe_handle = fdopen(parent_fd, "r");
474 	return (pipe_handle);
475 }
476 
477 int
478 su_pclose(ptr)
479 	FILE   *ptr;
480 {
481 	int     pid, status;
482 
483 	stop_watchdog();
484 
485 	fclose(ptr);
486 	if (child_pid == -1)
487 		return (-1);
488 	while ((pid = wait(&status)) != child_pid && pid != -1);
489 	return (pid == -1 ? -1 : status);
490 }
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 static void
510 config_from_file(void)
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 (!strcasecmp(kw, "spooldir")) {
535 			strlcpy(sp_name, val, sizeof(sp_name));
536 			continue;
537 		}
538 #ifdef WTMP
539 		if (!strcasecmp(kw, "wtmp")) {
540 			/* assume default is YES, just look for negatives */
541 			if (!strcasecmp(val, "no") ||
542 			    !strcasecmp(val, "off") ||
543 			    !strcasecmp(val, "disable") ||
544 			    !strcmp(val, "0"))
545 				wtmp_enabled = 0;
546 			continue;
547 		}
548 #endif
549 		if (!strcasecmp(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 ** hack for main() - call config_from_file() then the real main
564 ** in the rpcgen output, which is hacked by CPPFLAGS to be "mymain"
565 */
566 #undef main
567 
568 int mymain(int argc, char *argv[]);
569 
570 int
571 main(int argc, char *argv[])
572 {
573 	config_from_file();
574 	return mymain(argc, argv);
575 }
576 
577 /*
578 ** strembedded - returns true if s1 is embedded (in any case) in s2
579 */
580 
581 int
582 strembedded(s1, s2)
583 	const char   *s1;
584 	const char   *s2;
585 {
586 	while (*s2) {
587 		if (!strcasecmp(s1, s2))
588 			return 1;
589 		s2++;
590 	}
591 	return 0;
592 }
593