Home | History | Annotate | Line # | Download | only in rpc.pcnfsd
      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
     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 *
     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   *
    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
    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
    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
    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
    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
    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   *
    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
    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
    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
    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
    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