Home | History | Annotate | Line # | Download | only in rpc.pcnfsd
pcnfsd_misc.c revision 1.14
      1 /*	$NetBSD: pcnfsd_misc.c,v 1.14 2011/09/01 07:18:51 plunky 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)) == 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(f, opts)
    239 	char   *f;
    240 	char   *opts;
    241 {
    242 	char    temp_file[256];
    243 	char    commbuf[256];
    244 	int     i;
    245 
    246 	(void) strlcpy(temp_file, f, sizeof(temp_file));
    247 	(void) strlcat(temp_file, "X", sizeof(temp_file)); /* intermediate file name */
    248 
    249 #ifndef PS630_IS_BROKEN
    250 	(void) snprintf(commbuf, sizeof(commbuf), "ps630 -s %c%c -p %s -f ",
    251 	    opts[2], opts[3], temp_file);
    252 	(void) strlcat(commbuf, mapfont(opts[4], opts[5], opts[6]),
    253 	    sizeof(commbuf));
    254 	(void) strlcat(commbuf, " -F ", sizeof(commbuf));
    255 	(void) strlcat(commbuf, mapfont(opts[7], opts[8], opts[9]),
    256 	    sizeof(commbuf));
    257 	(void) strlcat(commbuf, "  ", sizeof(commbuf));
    258 	(void) strlcat(commbuf, f, sizeof(commbuf));
    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) snprintf(commbuf, sizeof(commbuf), "ps630 -p %s %s",
    265 	    temp_file, f);
    266 #endif				/* PS630_IS_BROKEN */
    267 
    268 
    269 	if ((i = system(commbuf)) != 0) {
    270 		/*
    271 		 * Under (un)certain conditions, ps630 may return -1 even
    272 		 * if it worked. Hence the commenting out of this error
    273 		 * report.
    274 		 */
    275 		 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
    276 		/* exit(1); */
    277 	}
    278 	if (rename(temp_file, f)) {
    279 		perror("run_ps630: rename");
    280 		exit(1);
    281 	}
    282 	return;
    283 }
    284 
    285 
    286 
    287 
    288 
    289 /*
    290 **---------------------------------------------------------------------
    291 **                      WTMP update support
    292 **---------------------------------------------------------------------
    293 */
    294 
    295 
    296 #ifdef WTMP
    297 void
    298 wlogin(name, req)
    299 	char   *name;
    300 	struct svc_req *req;
    301 {
    302 	struct sockaddr_in *who;
    303 	struct hostent *hp;
    304 	char *host;
    305 
    306 	if (!wtmp_enabled)
    307 		return;
    308 
    309 /* Get network address of client. */
    310 	who = &req->rq_xprt->xp_raddr;
    311 
    312 /* Get name of connected client */
    313 	hp = gethostbyaddr((char *) &who->sin_addr,
    314 	    sizeof(struct in_addr),
    315 	    who->sin_family);
    316 
    317 	if (hp) {
    318 		host = hp->h_name;
    319 	} else {
    320 		host = inet_ntoa(who->sin_addr);
    321 	}
    322 
    323 #ifdef SUPPORT_UTMP
    324 	logwtmp("PC-NFS", name, host);
    325 #endif
    326 #ifdef SUPPORT_UTMPX
    327 	logwtmpx("PC-NFS", name, host, 0, USER_PROCESS);
    328 #endif
    329 }
    330 #endif				/* WTMP */
    331 
    332 
    333 /*
    334 **---------------------------------------------------------------------
    335 **                      Run-process-as-user procedures
    336 **---------------------------------------------------------------------
    337 */
    338 
    339 
    340 #define	READER_FD	0
    341 #define	WRITER_FD	1
    342 
    343 static int child_pid;
    344 
    345 static char cached_user[64] = "";
    346 static uid_t cached_uid;
    347 static gid_t cached_gid;
    348 
    349 static struct sigaction old_action;
    350 static struct sigaction new_action;
    351 static struct itimerval timer;
    352 
    353 int     interrupted = 0;
    354 static FILE *pipe_handle;
    355 
    356 void
    357 myhandler(dummy)
    358 	int     dummy;
    359 {
    360 	interrupted = 1;
    361 	fclose(pipe_handle);
    362 	kill(child_pid, SIGKILL);
    363 	msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
    364 }
    365 
    366 void
    367 start_watchdog(n)
    368 	int     n;
    369 {
    370 /*
    371  * Setup SIGALRM handler, force interrupt of ongoing syscall
    372  */
    373 
    374 	new_action.sa_handler = myhandler;
    375 	sigemptyset(&(new_action.sa_mask));
    376 	new_action.sa_flags = 0;
    377 #ifdef SA_INTERRUPT
    378 	new_action.sa_flags |= SA_INTERRUPT;
    379 #endif
    380 	sigaction(SIGALRM, &new_action, &old_action);
    381 
    382 /*
    383  * Set interval timer for n seconds
    384  */
    385 	timer.it_interval.tv_sec = 0;
    386 	timer.it_interval.tv_usec = 0;
    387 	timer.it_value.tv_sec = n;
    388 	timer.it_value.tv_usec = 0;
    389 	setitimer(ITIMER_REAL, &timer, NULL);
    390 	interrupted = 0;
    391 
    392 }
    393 
    394 void
    395 stop_watchdog()
    396 {
    397 /*
    398  * Cancel timer
    399  */
    400 
    401 	timer.it_interval.tv_sec = 0;
    402 	timer.it_interval.tv_usec = 0;
    403 	timer.it_value.tv_sec = 0;
    404 	timer.it_value.tv_usec = 0;
    405 	setitimer(ITIMER_REAL, &timer, NULL);
    406 
    407 /*
    408  * restore old signal handling
    409  */
    410 	sigaction(SIGALRM, &old_action, NULL);
    411 }
    412 
    413 FILE   *
    414 su_popen(user, cmd, maxtime)
    415 	char   *user;
    416 	char   *cmd;
    417 	int     maxtime;
    418 {
    419 	int     p[2];
    420 	int     parent_fd, child_fd, pid;
    421 	struct passwd *pw;
    422 
    423 	if (strcmp(cached_user, user)) {
    424 		pw = getpwnam(user);
    425 		if (!pw)
    426 			pw = getpwnam("nobody");
    427 		if (pw) {
    428 			cached_uid = pw->pw_uid;
    429 			cached_gid = pw->pw_gid;
    430 			strlcpy(cached_user, user, sizeof(cached_user));
    431 		} else {
    432 			cached_uid = (uid_t) (-2);
    433 			cached_gid = (gid_t) (-2);
    434 			cached_user[0] = '\0';
    435 		}
    436 	}
    437 	if (pipe(p) < 0) {
    438 		msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
    439 		return (NULL);
    440 	}
    441 	parent_fd = p[READER_FD];
    442 	child_fd = p[WRITER_FD];
    443 	if ((pid = fork()) == 0) {
    444 		int     i;
    445 
    446 		for (i = 0; i < 10; i++)
    447 			if (i != child_fd)
    448 				(void) close(i);
    449 		if (child_fd != 1) {
    450 			(void) dup2(child_fd, 1);
    451 			(void) close(child_fd);
    452 		}
    453 		dup2(1, 2);	/* let's get stderr as well */
    454 
    455 		(void) setgid(cached_gid);
    456 		(void) setuid(cached_uid);
    457 
    458 		(void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
    459 		_exit(255);
    460 	}
    461 	if (pid == -1) {
    462 		msg_out("rpc.pcnfsd: fork failed");
    463 		close(parent_fd);
    464 		close(child_fd);
    465 		return (NULL);
    466 	}
    467 	child_pid = pid;
    468 	close(child_fd);
    469 	start_watchdog(maxtime);
    470 	pipe_handle = fdopen(parent_fd, "r");
    471 	return (pipe_handle);
    472 }
    473 
    474 int
    475 su_pclose(ptr)
    476 	FILE   *ptr;
    477 {
    478 	int     pid, status;
    479 
    480 	stop_watchdog();
    481 
    482 	fclose(ptr);
    483 	if (child_pid == -1)
    484 		return (-1);
    485 	while ((pid = wait(&status)) != child_pid && pid != -1);
    486 	return (pid == -1 ? -1 : status);
    487 }
    488 
    489 
    490 
    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 static void
    507 config_from_file(void)
    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 			strlcpy(sp_name, val, sizeof(sp_name));
    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 
    559 /*
    560 ** hack for main() - call config_from_file() then the real main
    561 ** in the rpcgen output, which is hacked by CPPFLAGS to be "mymain"
    562 */
    563 #undef main
    564 
    565 int mymain(int argc, char *argv[]);
    566 
    567 int
    568 main(int argc, char *argv[])
    569 {
    570 	config_from_file();
    571 	return mymain(argc, argv);
    572 }
    573 
    574 /*
    575 ** strembedded - returns true if s1 is embedded (in any case) in s2
    576 */
    577 
    578 int
    579 strembedded(s1, s2)
    580 	const char   *s1;
    581 	const char   *s2;
    582 {
    583 	while (*s2) {
    584 		if (!strcasecmp(s1, s2))
    585 			return 1;
    586 		s2++;
    587 	}
    588 	return 0;
    589 }
    590