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