Home | History | Annotate | Line # | Download | only in rpc.pcnfsd
pcnfsd_misc.c revision 1.10
      1 /*	$NetBSD: pcnfsd_misc.c,v 1.10 2003/07/16 08:22:01 itojun 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)) == (struct passwd *) NULL ||
    128 	    (shadowfile && (sp = getspnam(usrnam)) == (struct spwd *) NULL))
    129 		return ((struct passwd *) 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 == (struct passwd *) NULL)
    140 		return ((struct passwd *) 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 ((struct passwd *) 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 ((struct passwd *) 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 ((struct passwd *) NULL);
    177 	ushell += strlen(ushell) - 2;
    178 	if (strcmp(ushell, "sh"))
    179 		return ((struct passwd *) 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(f, i, b)
    196 	char    f;
    197 	char    i;
    198 	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 #if XXX_unused
    495 /*
    496 ** The following routine reads a file "/etc/pcnfsd.conf" if present,
    497 ** and uses it to replace certain builtin elements, like the
    498 ** name of the print spool directory. The configuration file
    499 ** Is the usual kind: Comments begin with '#', blank lines are ignored,
    500 ** and valid lines are of the form
    501 **
    502 **	<keyword><whitespace><value>
    503 **
    504 ** The following keywords are recognized:
    505 **
    506 **	spooldir
    507 **	printer name alias-for command
    508 **	wtmp yes|no
    509 */
    510 void
    511 config_from_file()
    512 {
    513 	FILE   *fd;
    514 	char    buff[1024];
    515 	char   *cp;
    516 	char   *kw;
    517 	char   *val;
    518 	char   *arg1;
    519 	char   *arg2;
    520 
    521 	if ((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
    522 		return;
    523 	while (fgets(buff, 1024, fd)) {
    524 		cp = strchr(buff, '\n');
    525 		*cp = '\0';
    526 		cp = strchr(buff, '#');
    527 		if (cp)
    528 			*cp = '\0';
    529 		kw = strtok(buff, " \t");
    530 		if (kw == NULL)
    531 			continue;
    532 		val = strtok(NULL, " \t");
    533 		if (val == NULL)
    534 			continue;
    535 		if (!strcasecmp(kw, "spooldir")) {
    536 			strlcpy(sp_name, val, sizeof(sp_name));
    537 			continue;
    538 		}
    539 #ifdef WTMP
    540 		if (!strcasecmp(kw, "wtmp")) {
    541 			/* assume default is YES, just look for negatives */
    542 			if (!strcasecmp(val, "no") ||
    543 			    !strcasecmp(val, "off") ||
    544 			    !strcasecmp(val, "disable") ||
    545 			    !strcmp(val, "0"))
    546 				wtmp_enabled = 0;
    547 			continue;
    548 		}
    549 #endif
    550 		if (!strcasecmp(kw, "printer")) {
    551 			arg1 = strtok(NULL, " \t");
    552 			arg2 = strtok(NULL, "");
    553 			(void) add_printer_alias(val, arg1, arg2);
    554 			continue;
    555 		}
    556 /*
    557 ** Add new cases here
    558 */
    559 	}
    560 	fclose(fd);
    561 }
    562 #endif	/* XXX_unused */
    563 
    564 
    565 /*
    566 ** strembedded - returns true if s1 is embedded (in any case) in s2
    567 */
    568 
    569 int
    570 strembedded(s1, s2)
    571 	const char   *s1;
    572 	const char   *s2;
    573 {
    574 	while (*s2) {
    575 		if (!strcasecmp(s1, s2))
    576 			return 1;
    577 		s2++;
    578 	}
    579 	return 0;
    580 }
    581