xref: /netbsd/usr.sbin/rpc.pcnfsd/pcnfsd_misc.c (revision d6aaec91)
1 /*	$NetBSD: pcnfsd_misc.c,v 1.16 2018/01/23 21:06:25 sevan 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(char, char, char);
71 void	myhandler(int);
72 void	start_watchdog(int);
73 void	stop_watchdog(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(char *s1, char *s2)
89 {
90 	while (*s1) {
91 		*s2++ = (*s1 ^ zchar) & 0x7f;
92 		s1++;
93 	}
94 	*s2 = 0;
95 }
96 
97 
98 
99 struct passwd *
100 get_password(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)) == NULL ||
128 	    (shadowfile && (sp = getspnam(usrnam)) == NULL))
129 		return (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 == NULL)
140 		return (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 (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 (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 (NULL);
177 	ushell += strlen(ushell) - 2;
178 	if (strcmp(ushell, "sh"))
179 		return (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(char f, char i, char b)
196 {
197 	static char fontname[64];
198 
199 	fontname[0] = 0;	/* clear it out */
200 
201 	switch (f) {
202 	case 'c':
203 		(void) strlcpy(fontname, "Courier", sizeof(fontname));
204 		break;
205 	case 'h':
206 		(void) strlcpy(fontname, "Helvetica", sizeof(fontname));
207 		break;
208 	case 't':
209 		(void) strlcpy(fontname, "Times", sizeof(fontname));
210 		break;
211 	default:
212 		(void) strlcpy(fontname, "Times-Roman", sizeof(fontname));
213 		goto finis;
214 	}
215 	if (i != 'o' && b != 'b') {	/* no bold or oblique */
216 		if (f == 't')	/* special case Times */
217 			(void) strlcat(fontname, "-Roman", sizeof(fontname));
218 		goto finis;
219 	}
220 	(void) strlcat(fontname, "-", sizeof(fontname));
221 	if (b == 'b')
222 		(void) strlcat(fontname, "Bold", sizeof(fontname));
223 	if (i == 'o')		/* o-blique */
224 		(void) strlcat(fontname, f == 't' ? "Italic" : "Oblique",
225 		    sizeof(fontname));
226 
227 finis:	return (&fontname[0]);
228 }
229 /*
230 * run_ps630 performs the Diablo 630 emulation filtering process. ps630
231 * was broken in certain Sun releases: it would not accept point size or
232 * font changes. If your version is fixed, undefine the symbol
233 * PS630_IS_BROKEN and rebuild pc-nfsd.
234 */
235 /* #define PS630_IS_BROKEN 1 */
236 
237 void
238 run_ps630(char *f, char *opts)
239 {
240 	char    temp_file[256];
241 	char    commbuf[256];
242 	int     i;
243 
244 	(void) strlcpy(temp_file, f, sizeof(temp_file));
245 	(void) strlcat(temp_file, "X", sizeof(temp_file)); /* intermediate file name */
246 
247 #ifndef PS630_IS_BROKEN
248 	(void) snprintf(commbuf, sizeof(commbuf), "ps630 -s %c%c -p %s -f ",
249 	    opts[2], opts[3], temp_file);
250 	(void) strlcat(commbuf, mapfont(opts[4], opts[5], opts[6]),
251 	    sizeof(commbuf));
252 	(void) strlcat(commbuf, " -F ", sizeof(commbuf));
253 	(void) strlcat(commbuf, mapfont(opts[7], opts[8], opts[9]),
254 	    sizeof(commbuf));
255 	(void) strlcat(commbuf, "  ", sizeof(commbuf));
256 	(void) strlcat(commbuf, f, sizeof(commbuf));
257 #else				/* PS630_IS_BROKEN */
258 /*
259  * The pitch and font features of ps630 appear to be broken at
260  * this time.
261  */
262 	(void) snprintf(commbuf, sizeof(commbuf), "ps630 -p %s %s",
263 	    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 void
296 wlogin(char *name, struct svc_req *req)
297 {
298 	struct sockaddr_in *who;
299 	struct hostent *hp;
300 	char *host;
301 
302 	if (!wtmp_enabled)
303 		return;
304 
305 /* Get network address of client. */
306 	who = &req->rq_xprt->xp_raddr;
307 
308 /* Get name of connected client */
309 	hp = gethostbyaddr((char *) &who->sin_addr,
310 	    sizeof(struct in_addr),
311 	    who->sin_family);
312 
313 	if (hp) {
314 		host = hp->h_name;
315 	} else {
316 		host = inet_ntoa(who->sin_addr);
317 	}
318 
319 #ifdef SUPPORT_UTMP
320 	logwtmp("PC-NFS", name, host);
321 #endif
322 #ifdef SUPPORT_UTMPX
323 	logwtmpx("PC-NFS", name, host, 0, USER_PROCESS);
324 #endif
325 }
326 #endif				/* WTMP */
327 
328 
329 /*
330 **---------------------------------------------------------------------
331 **                      Run-process-as-user procedures
332 **---------------------------------------------------------------------
333 */
334 
335 
336 #define	READER_FD	0
337 #define	WRITER_FD	1
338 
339 static int child_pid;
340 
341 static char cached_user[64] = "";
342 static uid_t cached_uid;
343 static gid_t cached_gid;
344 
345 static struct sigaction old_action;
346 static struct sigaction new_action;
347 static struct itimerval timer;
348 
349 int     interrupted = 0;
350 static FILE *pipe_handle;
351 
352 void
353 myhandler(int dummy)
354 {
355 	interrupted = 1;
356 	fclose(pipe_handle);
357 	kill(child_pid, SIGKILL);
358 	msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
359 }
360 
361 void
362 start_watchdog(int n)
363 {
364 /*
365  * Setup SIGALRM handler, force interrupt of ongoing syscall
366  */
367 
368 	new_action.sa_handler = myhandler;
369 	sigemptyset(&(new_action.sa_mask));
370 	new_action.sa_flags = 0;
371 #ifdef SA_INTERRUPT
372 	new_action.sa_flags |= SA_INTERRUPT;
373 #endif
374 	sigaction(SIGALRM, &new_action, &old_action);
375 
376 /*
377  * Set interval timer for n seconds
378  */
379 	timer.it_interval.tv_sec = 0;
380 	timer.it_interval.tv_usec = 0;
381 	timer.it_value.tv_sec = n;
382 	timer.it_value.tv_usec = 0;
383 	setitimer(ITIMER_REAL, &timer, NULL);
384 	interrupted = 0;
385 
386 }
387 
388 void
389 stop_watchdog()
390 {
391 /*
392  * Cancel timer
393  */
394 
395 	timer.it_interval.tv_sec = 0;
396 	timer.it_interval.tv_usec = 0;
397 	timer.it_value.tv_sec = 0;
398 	timer.it_value.tv_usec = 0;
399 	setitimer(ITIMER_REAL, &timer, NULL);
400 
401 /*
402  * restore old signal handling
403  */
404 	sigaction(SIGALRM, &old_action, NULL);
405 }
406 
407 FILE   *
408 su_popen(char *user, char *cmd, int maxtime)
409 {
410 	int     p[2];
411 	int     parent_fd, child_fd, pid;
412 	struct passwd *pw;
413 
414 	if (strcmp(cached_user, user)) {
415 		pw = getpwnam(user);
416 		if (!pw)
417 			pw = getpwnam("nobody");
418 		if (pw) {
419 			cached_uid = pw->pw_uid;
420 			cached_gid = pw->pw_gid;
421 			strlcpy(cached_user, user, sizeof(cached_user));
422 		} else {
423 			cached_uid = (uid_t) (-2);
424 			cached_gid = (gid_t) (-2);
425 			cached_user[0] = '\0';
426 		}
427 	}
428 	if (pipe(p) < 0) {
429 		msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
430 		return (NULL);
431 	}
432 	parent_fd = p[READER_FD];
433 	child_fd = p[WRITER_FD];
434 	if ((pid = fork()) == 0) {
435 		int     i;
436 
437 		for (i = 0; i < 10; i++)
438 			if (i != child_fd)
439 				(void) close(i);
440 		if (child_fd != 1) {
441 			(void) dup2(child_fd, 1);
442 			(void) close(child_fd);
443 		}
444 		dup2(1, 2);	/* let's get stderr as well */
445 
446 		(void) setgid(cached_gid);
447 		(void) setuid(cached_uid);
448 
449 		(void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
450 		_exit(255);
451 	}
452 	if (pid == -1) {
453 		msg_out("rpc.pcnfsd: fork failed");
454 		close(parent_fd);
455 		close(child_fd);
456 		return (NULL);
457 	}
458 	child_pid = pid;
459 	close(child_fd);
460 	start_watchdog(maxtime);
461 	pipe_handle = fdopen(parent_fd, "r");
462 	return (pipe_handle);
463 }
464 
465 int
466 su_pclose(FILE *ptr)
467 {
468 	int     pid, status;
469 
470 	stop_watchdog();
471 
472 	fclose(ptr);
473 	if (child_pid == -1)
474 		return (-1);
475 	while ((pid = wait(&status)) != child_pid && pid != -1);
476 	return (pid == -1 ? -1 : status);
477 }
478 
479 
480 
481 /*
482 ** The following routine reads a file "/etc/pcnfsd.conf" if present,
483 ** and uses it to replace certain builtin elements, like the
484 ** name of the print spool directory. The configuration file
485 ** Is the usual kind: Comments begin with '#', blank lines are ignored,
486 ** and valid lines are of the form
487 **
488 **	<keyword><whitespace><value>
489 **
490 ** The following keywords are recognized:
491 **
492 **	spooldir
493 **	printer name alias-for command
494 **	wtmp yes|no
495 */
496 static void
497 config_from_file(void)
498 {
499 	FILE   *fd;
500 	char    buff[1024];
501 	char   *cp;
502 	char   *kw;
503 	char   *val;
504 	char   *arg1;
505 	char   *arg2;
506 
507 	if ((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
508 		return;
509 	while (fgets(buff, 1024, fd)) {
510 		cp = strchr(buff, '\n');
511 		*cp = '\0';
512 		cp = strchr(buff, '#');
513 		if (cp)
514 			*cp = '\0';
515 		kw = strtok(buff, " \t");
516 		if (kw == NULL)
517 			continue;
518 		val = strtok(NULL, " \t");
519 		if (val == NULL)
520 			continue;
521 		if (!strcasecmp(kw, "spooldir")) {
522 			strlcpy(sp_name, val, sizeof(sp_name));
523 			continue;
524 		}
525 #ifdef WTMP
526 		if (!strcasecmp(kw, "wtmp")) {
527 			/* assume default is YES, just look for negatives */
528 			if (!strcasecmp(val, "no") ||
529 			    !strcasecmp(val, "off") ||
530 			    !strcasecmp(val, "disable") ||
531 			    !strcmp(val, "0"))
532 				wtmp_enabled = 0;
533 			continue;
534 		}
535 #endif
536 		if (!strcasecmp(kw, "printer")) {
537 			arg1 = strtok(NULL, " \t");
538 			arg2 = strtok(NULL, "");
539 			(void) add_printer_alias(val, arg1, arg2);
540 			continue;
541 		}
542 /*
543 ** Add new cases here
544 */
545 	}
546 	fclose(fd);
547 }
548 
549 /*
550 ** hack for main() - call config_from_file() then the real main
551 ** in the rpcgen output, which is hacked by CPPFLAGS to be "mymain"
552 */
553 #undef main
554 
555 int mymain(int argc, char *argv[]);
556 
557 int
558 main(int argc, char *argv[])
559 {
560 	config_from_file();
561 	return mymain(argc, argv);
562 }
563 
564 /*
565 ** strembedded - returns true if s1 is embedded (in any case) in s2
566 */
567 
568 int
569 strembedded(const char *s1, const char *s2)
570 {
571 	while (*s2) {
572 		if (!strcasecmp(s1, s2))
573 			return 1;
574 		s2++;
575 	}
576 	return 0;
577 }
578