Home | History | Annotate | Line # | Download | only in rpc.pcnfsd
pcnfsd_misc.c revision 1.3
      1 /*	$NetBSD: pcnfsd_misc.c,v 1.3 1997/10/25 13:45:57 lukem 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 
     40 #ifdef ISC_2_0
     41 #include <sys/fcntl.h>
     42 #endif
     43 
     44 #ifdef SHADOW_SUPPORT
     45 #include <shadow.h>
     46 #endif
     47 
     48 #ifdef WTMP
     49 int     wtmp_enabled = 1;
     50 #endif
     51 
     52 #include "common.h"
     53 #include "pcnfsd.h"
     54 #include "extern.h"
     55 
     56 /*
     57 **---------------------------------------------------------------------
     58 ** Other #define's
     59 **---------------------------------------------------------------------
     60 */
     61 
     62 #define	zchar		0x5b
     63 
     64 char    tempstr[256];
     65 
     66 char   *mapfont __P((char, char, char));
     67 void	myhandler __P((int));
     68 void	start_watchdog __P((int));
     69 void	stop_watchdog __P((void));
     70 
     71 /*
     72 **=====================================================================
     73 **                      C O D E   S E C T I O N                       *
     74 **=====================================================================
     75 */
     76 /*
     77 **---------------------------------------------------------------------
     78 **                          Support procedures
     79 **---------------------------------------------------------------------
     80 */
     81 
     82 
     83 void
     84 scramble(s1, s2)
     85 	char   *s1;
     86 	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(usrnam)
     99 	char   *usrnam;
    100 {
    101 	struct passwd *p;
    102 	static struct passwd localp;
    103 	char   *pswd;
    104 	char   *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) strcpy(fontname, "Courier");
    207 		break;
    208 	case 'h':
    209 		(void) strcpy(fontname, "Helvetica");
    210 		break;
    211 	case 't':
    212 		(void) strcpy(fontname, "Times");
    213 		break;
    214 	default:
    215 		(void) strcpy(fontname, "Times-Roman");
    216 		goto finis;
    217 	}
    218 	if (i != 'o' && b != 'b') {	/* no bold or oblique */
    219 		if (f == 't')	/* special case Times */
    220 			(void) strcat(fontname, "-Roman");
    221 		goto finis;
    222 	}
    223 	(void) strcat(fontname, "-");
    224 	if (b == 'b')
    225 		(void) strcat(fontname, "Bold");
    226 	if (i == 'o')		/* o-blique */
    227 		(void) strcat(fontname, f == 't' ? "Italic" : "Oblique");
    228 
    229 finis:	return (&fontname[0]);
    230 }
    231 /*
    232 * run_ps630 performs the Diablo 630 emulation filtering process. ps630
    233 * was broken in certain Sun releases: it would not accept point size or
    234 * font changes. If your version is fixed, undefine the symbol
    235 * PS630_IS_BROKEN and rebuild pc-nfsd.
    236 */
    237 /* #define PS630_IS_BROKEN 1 */
    238 
    239 void
    240 run_ps630(f, opts)
    241 	char   *f;
    242 	char   *opts;
    243 {
    244 	char    temp_file[256];
    245 	char    commbuf[256];
    246 	int     i;
    247 
    248 	(void) strcpy(temp_file, f);
    249 	(void) strcat(temp_file, "X");	/* intermediate file name */
    250 
    251 #ifndef PS630_IS_BROKEN
    252 	(void) sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
    253 	    opts[2], opts[3], temp_file);
    254 	(void) strcat(commbuf, mapfont(opts[4], opts[5], opts[6]));
    255 	(void) strcat(commbuf, " -F ");
    256 	(void) strcat(commbuf, mapfont(opts[7], opts[8], opts[9]));
    257 	(void) strcat(commbuf, "  ");
    258 	(void) strcat(commbuf, f);
    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) sprintf(commbuf, "ps630 -p %s %s", temp_file, f);
    265 #endif				/* PS630_IS_BROKEN */
    266 
    267 
    268 	if ((i = system(commbuf)) != 0) {
    269 		/*
    270 		 * Under (un)certain conditions, ps630 may return -1 even
    271 		 * if it worked. Hence the commenting out of this error
    272 		 * report.
    273 		 */
    274 		 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
    275 		/* exit(1); */
    276 	}
    277 	if (rename(temp_file, f)) {
    278 		perror("run_ps630: rename");
    279 		exit(1);
    280 	}
    281 	return;
    282 }
    283 
    284 
    285 
    286 
    287 
    288 /*
    289 **---------------------------------------------------------------------
    290 **                      WTMP update support
    291 **---------------------------------------------------------------------
    292 */
    293 
    294 
    295 #ifdef WTMP
    296 
    297 #include <utmp.h>
    298 
    299 #ifndef	_PATH_WTMP
    300 #define _PATH_WTMP "/usr/adm/wtmp"
    301 #endif
    302 
    303 void
    304 wlogin(name, req)
    305 	char   *name;
    306 	struct svc_req *req;
    307 {
    308 	struct sockaddr_in *who;
    309 	struct hostent *hp;
    310 	char   *host;
    311 	struct utmp ut;
    312 	int     fd;
    313 
    314 	if (!wtmp_enabled)
    315 		return;
    316 
    317 /* Get network address of client. */
    318 	who = &req->rq_xprt->xp_raddr;
    319 
    320 /* Get name of connected client */
    321 	hp = gethostbyaddr((char *) &who->sin_addr,
    322 	    sizeof(struct in_addr),
    323 	    who->sin_family);
    324 
    325 	if (hp && (strlen(hp->h_name) <= sizeof(ut.ut_host))) {
    326 		host = hp->h_name;
    327 	} else {
    328 		host = inet_ntoa(who->sin_addr);
    329 	}
    330 
    331 	(void) strcpy(ut.ut_line, "PC-NFS");
    332 	(void) strncpy(ut.ut_name, name, sizeof ut.ut_name);
    333 	(void) strncpy(ut.ut_host, host, sizeof ut.ut_host);
    334 	ut.ut_time = time((time_t *) 0);
    335 
    336 	if ((fd = open(_PATH_WTMP, O_WRONLY | O_APPEND, 0)) >= 0) {
    337 		(void) write(fd, (char *) &ut, sizeof(struct utmp));
    338 		(void) close(fd);
    339 	}
    340 }
    341 #endif				/* WTMP */
    342 
    343 
    344 /*
    345 **---------------------------------------------------------------------
    346 **                      Run-process-as-user procedures
    347 **---------------------------------------------------------------------
    348 */
    349 
    350 
    351 #define	READER_FD	0
    352 #define	WRITER_FD	1
    353 
    354 static int child_pid;
    355 
    356 static char cached_user[64] = "";
    357 static uid_t cached_uid;
    358 static gid_t cached_gid;
    359 
    360 static struct sigaction old_action;
    361 static struct sigaction new_action;
    362 static struct itimerval timer;
    363 
    364 int     interrupted = 0;
    365 static FILE *pipe_handle;
    366 
    367 void
    368 myhandler(dummy)
    369 	int     dummy;
    370 {
    371 	interrupted = 1;
    372 	fclose(pipe_handle);
    373 	kill(child_pid, SIGKILL);
    374 	msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
    375 }
    376 
    377 void
    378 start_watchdog(n)
    379 	int     n;
    380 {
    381 /*
    382  * Setup SIGALRM handler, force interrupt of ongoing syscall
    383  */
    384 
    385 	new_action.sa_handler = myhandler;
    386 	sigemptyset(&(new_action.sa_mask));
    387 	new_action.sa_flags = 0;
    388 #ifdef SA_INTERRUPT
    389 	new_action.sa_flags |= SA_INTERRUPT;
    390 #endif
    391 	sigaction(SIGALRM, &new_action, &old_action);
    392 
    393 /*
    394  * Set interval timer for n seconds
    395  */
    396 	timer.it_interval.tv_sec = 0;
    397 	timer.it_interval.tv_usec = 0;
    398 	timer.it_value.tv_sec = n;
    399 	timer.it_value.tv_usec = 0;
    400 	setitimer(ITIMER_REAL, &timer, NULL);
    401 	interrupted = 0;
    402 
    403 }
    404 
    405 void
    406 stop_watchdog()
    407 {
    408 /*
    409  * Cancel timer
    410  */
    411 
    412 	timer.it_interval.tv_sec = 0;
    413 	timer.it_interval.tv_usec = 0;
    414 	timer.it_value.tv_sec = 0;
    415 	timer.it_value.tv_usec = 0;
    416 	setitimer(ITIMER_REAL, &timer, NULL);
    417 
    418 /*
    419  * restore old signal handling
    420  */
    421 	sigaction(SIGALRM, &old_action, NULL);
    422 }
    423 
    424 FILE   *
    425 su_popen(user, cmd, maxtime)
    426 	char   *user;
    427 	char   *cmd;
    428 	int     maxtime;
    429 {
    430 	int     p[2];
    431 	int     parent_fd, child_fd, pid;
    432 	struct passwd *pw;
    433 
    434 	if (strcmp(cached_user, user)) {
    435 		pw = getpwnam(user);
    436 		if (!pw)
    437 			pw = getpwnam("nobody");
    438 		if (pw) {
    439 			cached_uid = pw->pw_uid;
    440 			cached_gid = pw->pw_gid;
    441 			strcpy(cached_user, user);
    442 		} else {
    443 			cached_uid = (uid_t) (-2);
    444 			cached_gid = (gid_t) (-2);
    445 			cached_user[0] = '\0';
    446 		}
    447 	}
    448 	if (pipe(p) < 0) {
    449 		msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
    450 		return (NULL);
    451 	}
    452 	parent_fd = p[READER_FD];
    453 	child_fd = p[WRITER_FD];
    454 	if ((pid = fork()) == 0) {
    455 		int     i;
    456 
    457 		for (i = 0; i < 10; i++)
    458 			if (i != child_fd)
    459 				(void) close(i);
    460 		if (child_fd != 1) {
    461 			(void) dup2(child_fd, 1);
    462 			(void) close(child_fd);
    463 		}
    464 		dup2(1, 2);	/* let's get stderr as well */
    465 
    466 		(void) setgid(cached_gid);
    467 		(void) setuid(cached_uid);
    468 
    469 		(void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
    470 		_exit(255);
    471 	}
    472 	if (pid == -1) {
    473 		msg_out("rpc.pcnfsd: fork failed");
    474 		close(parent_fd);
    475 		close(child_fd);
    476 		return (NULL);
    477 	}
    478 	child_pid = pid;
    479 	close(child_fd);
    480 	start_watchdog(maxtime);
    481 	pipe_handle = fdopen(parent_fd, "r");
    482 	return (pipe_handle);
    483 }
    484 
    485 int
    486 su_pclose(ptr)
    487 	FILE   *ptr;
    488 {
    489 	int     pid, status;
    490 
    491 	stop_watchdog();
    492 
    493 	fclose(ptr);
    494 	if (child_pid == -1)
    495 		return (-1);
    496 	while ((pid = wait(&status)) != child_pid && pid != -1);
    497 	return (pid == -1 ? -1 : status);
    498 }
    499 
    500 
    501 
    502 #if XXX_unused
    503 /*
    504 ** The following routine reads a file "/etc/pcnfsd.conf" if present,
    505 ** and uses it to replace certain builtin elements, like the
    506 ** name of the print spool directory. The configuration file
    507 ** Is the usual kind: Comments begin with '#', blank lines are ignored,
    508 ** and valid lines are of the form
    509 **
    510 **	<keyword><whitespace><value>
    511 **
    512 ** The following keywords are recognized:
    513 **
    514 **	spooldir
    515 **	printer name alias-for command
    516 **	wtmp yes|no
    517 */
    518 void
    519 config_from_file()
    520 {
    521 	FILE   *fd;
    522 	char    buff[1024];
    523 	char   *cp;
    524 	char   *kw;
    525 	char   *val;
    526 	char   *arg1;
    527 	char   *arg2;
    528 
    529 	if ((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
    530 		return;
    531 	while (fgets(buff, 1024, fd)) {
    532 		cp = strchr(buff, '\n');
    533 		*cp = '\0';
    534 		cp = strchr(buff, '#');
    535 		if (cp)
    536 			*cp = '\0';
    537 		kw = strtok(buff, " \t");
    538 		if (kw == NULL)
    539 			continue;
    540 		val = strtok(NULL, " \t");
    541 		if (val == NULL)
    542 			continue;
    543 		if (!strcasecmp(kw, "spooldir")) {
    544 			strcpy(sp_name, val);
    545 			continue;
    546 		}
    547 #ifdef WTMP
    548 		if (!strcasecmp(kw, "wtmp")) {
    549 			/* assume default is YES, just look for negatives */
    550 			if (!strcasecmp(val, "no") ||
    551 			    !strcasecmp(val, "off") ||
    552 			    !strcasecmp(val, "disable") ||
    553 			    !strcmp(val, "0"))
    554 				wtmp_enabled = 0;;
    555 			continue;
    556 		}
    557 #endif
    558 		if (!strcasecmp(kw, "printer")) {
    559 			arg1 = strtok(NULL, " \t");
    560 			arg2 = strtok(NULL, "");
    561 			(void) add_printer_alias(val, arg1, arg2);
    562 			continue;
    563 		}
    564 /*
    565 ** Add new cases here
    566 */
    567 	}
    568 	fclose(fd);
    569 }
    570 #endif	/* XXX_unused */
    571 
    572 
    573 /*
    574 ** strembedded - returns true if s1 is embedded (in any case) in s2
    575 */
    576 
    577 int
    578 strembedded(s1, s2)
    579 	const char   *s1;
    580 	const char   *s2;
    581 {
    582 	while (*s2) {
    583 		if (!strcasecmp(s1, s2))
    584 			return 1;
    585 		s2++;
    586 	}
    587 	return 0;
    588 }
    589