Home | History | Annotate | Line # | Download | only in rpc.pcnfsd
pcnfsd_misc.c revision 1.1
      1 /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_misc.c 1.5 92/01/24 19:59:13 SMI */
      2 /*
      3 **=====================================================================
      4 ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
      5 **	@(#)pcnfsd_misc.c	1.5	1/24/92
      6 **=====================================================================
      7 */
      8 #include "common.h"
      9 /*
     10 **=====================================================================
     11 **             I N C L U D E   F I L E   S E C T I O N                *
     12 **                                                                    *
     13 ** If your port requires different include files, add a suitable      *
     14 ** #define in the customization section, and make the inclusion or    *
     15 ** exclusion of the files conditional on this.                        *
     16 **=====================================================================
     17 */
     18 #include "pcnfsd.h"
     19 
     20 #include <stdio.h>
     21 #include <pwd.h>
     22 #include <sys/file.h>
     23 #include <signal.h>
     24 #include <sys/time.h>
     25 #include <sys/stat.h>
     26 #include <sys/ioctl.h>
     27 #include <netdb.h>
     28 #include <errno.h>
     29 #include <string.h>
     30 #include <ctype.h>
     31 
     32 #ifdef ISC_2_0
     33 #include <sys/fcntl.h>
     34 #endif
     35 
     36 #ifdef SHADOW_SUPPORT
     37 #include <shadow.h>
     38 #endif
     39 
     40 #ifdef WTMP
     41 int wtmp_enabled = 1;
     42 #endif
     43 
     44 #ifdef USE_GETUSERSHELL
     45 extern char *getusershell();
     46 #endif
     47 
     48 /*
     49 **---------------------------------------------------------------------
     50 ** Other #define's
     51 **---------------------------------------------------------------------
     52 */
     53 
     54 #define	zchar		0x5b
     55 
     56 char            tempstr[256];
     57 extern char	sp_name[1024]; /* in pcnfsd_print.c */
     58 
     59 /*
     60 **=====================================================================
     61 **                      C O D E   S E C T I O N                       *                    **=====================================================================
     62 */
     63 /*
     64 **---------------------------------------------------------------------
     65 **                          Support procedures
     66 **---------------------------------------------------------------------
     67 */
     68 
     69 
     70 void
     71 scramble(s1, s2)
     72 char           *s1;
     73 char           *s2;
     74 {
     75 	while (*s1)
     76 	      {
     77 	      *s2++ = (*s1 ^ zchar) & 0x7f;
     78 	      s1++;
     79 	      }
     80 	*s2 = 0;
     81 }
     82 
     83 
     84 
     85 struct passwd  *
     86 get_password(usrnam)
     87 char           *usrnam;
     88 {
     89 struct passwd  *p;
     90 static struct passwd localp;
     91 char           *pswd;
     92 char           *ushell;
     93 int		ok = 0;
     94 
     95 
     96 #ifdef SHADOW_SUPPORT
     97 struct spwd    *sp;
     98 int             shadowfile;
     99 #endif
    100 
    101 #ifdef SHADOW_SUPPORT
    102 	/*
    103         **--------------------------------------------------------------
    104 	** Check the existence of SHADOW.  If it is there, then we are
    105 	** running a two-password-file system.
    106         **--------------------------------------------------------------
    107 	*/
    108 	if (access(SHADOW, 0))
    109 	   shadowfile = 0;	/* SHADOW is not there */
    110 	else
    111 	   shadowfile = 1;
    112 
    113 	setpwent();
    114 	if (shadowfile)
    115 	   (void) setspent();	/* Setting the shadow password
    116 					 * file */
    117 	if ((p = getpwnam(usrnam)) == (struct passwd *)NULL ||
    118 	   (shadowfile && (sp = getspnam(usrnam)) == (struct spwd *)NULL))
    119 	return ((struct passwd *)NULL);
    120 
    121 	if (shadowfile)
    122            {
    123 	   pswd = sp->sp_pwdp;
    124 	   (void) endspent();
    125 	   }
    126         else
    127 	   pswd = p->pw_passwd;
    128 
    129 #else
    130 	p = getpwnam(usrnam);
    131 	if (p == (struct passwd *)NULL)
    132 		return ((struct passwd *)NULL);
    133 	pswd = p->pw_passwd;
    134 #endif
    135 
    136 #ifdef ISC_2_0
    137 	/*
    138         **-----------------------------------------------------------
    139 	** We may have an 'x' in which case look in /etc/shadow ..
    140         **-----------------------------------------------------------
    141         */
    142 	if (((strlen(pswd)) == 1) && pswd[0] == 'x')
    143 	   {
    144 	   struct spwd    *shadow = getspnam(usrnam);
    145 
    146 	   if (!shadow)
    147 	      return ((struct passwd *)NULL);
    148 	   pswd = shadow->sp_pwdp;
    149 	   }
    150 #endif
    151 	localp = *p;
    152 	localp.pw_passwd = pswd;
    153 #ifdef USE_GETUSERSHELL
    154 
    155 	setusershell();
    156 	while(ushell = getusershell()){
    157 		if(!strcmp(ushell, localp.pw_shell)) {
    158 			ok = 1;
    159 			break;
    160 		}
    161 	}
    162 	endusershell();
    163 	if(!ok)
    164 		return ((struct passwd *)NULL);
    165 #else
    166 /*
    167  * the best we can do is to ensure that the shell ends in "sh"
    168  */
    169 	ushell = localp.pw_shell;
    170 	if(strlen(ushell) < 2)
    171 		return ((struct passwd *)NULL);
    172 	ushell += strlen(ushell) - 2;
    173 	if(strcmp(ushell, "sh"))
    174 		return ((struct passwd *)NULL);
    175 
    176 #endif
    177 	return (&localp);
    178 }
    179 
    180 
    181 /*
    183 **---------------------------------------------------------------------
    184 **                      Print support procedures
    185 **---------------------------------------------------------------------
    186 */
    187 
    188 char           *
    189 mapfont(f, i, b)
    190 	char            f;
    191 	char            i;
    192 	char            b;
    193 {
    194 	static char     fontname[64];
    195 
    196 	fontname[0] = 0;	/* clear it out */
    197 
    198 	switch (f) {
    199 	case 'c':
    200 		(void)strcpy(fontname, "Courier");
    201 		break;
    202 	case 'h':
    203 		(void)strcpy(fontname, "Helvetica");
    204 		break;
    205 	case 't':
    206 		(void)strcpy(fontname, "Times");
    207 		break;
    208 	default:
    209 		(void)strcpy(fontname, "Times-Roman");
    210 		goto finis ;
    211 	}
    212 	if (i != 'o' && b != 'b') {	/* no bold or oblique */
    213 		if (f == 't')	/* special case Times */
    214 			(void)strcat(fontname, "-Roman");
    215 		goto finis;
    216 	}
    217 	(void)strcat(fontname, "-");
    218 	if (b == 'b')
    219 		(void)strcat(fontname, "Bold");
    220 	if (i == 'o')		/* o-blique */
    221 		(void)strcat(fontname, f == 't' ? "Italic" : "Oblique");
    222 
    223 finis:	return (&fontname[0]);
    224 }
    225 
    226 /*
    227  * run_ps630 performs the Diablo 630 emulation filtering process. ps630
    228  * was broken in certain Sun releases: it would not accept point size or
    229  * font changes. If your version is fixed, undefine the symbol
    230  * PS630_IS_BROKEN and rebuild pc-nfsd.
    231  */
    232 /* #define PS630_IS_BROKEN 1 */
    233 
    234 void
    235 run_ps630(f, opts)
    236 	char           *f;
    237 	char           *opts;
    238 {
    239 	char            temp_file[256];
    240 	char            commbuf[256];
    241 	int             i;
    242 
    243 	(void)strcpy(temp_file, f);
    244 	(void)strcat(temp_file, "X");	/* intermediate file name */
    245 
    246 #ifndef PS630_IS_BROKEN
    247 	(void)sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
    248 		opts[2], opts[3], temp_file);
    249 	(void)strcat(commbuf, mapfont(opts[4], opts[5], opts[6]));
    250 	(void)strcat(commbuf, " -F ");
    251 	(void)strcat(commbuf, mapfont(opts[7], opts[8], opts[9]));
    252 	(void)strcat(commbuf, "  ");
    253 	(void)strcat(commbuf, f);
    254 #else	/* PS630_IS_BROKEN */
    255 	/*
    256 	 * The pitch and font features of ps630 appear to be broken at
    257 	 * this time.
    258 	 */
    259 	(void)sprintf(commbuf, "ps630 -p %s %s", temp_file, f);
    260 #endif	/* PS630_IS_BROKEN */
    261 
    262 
    263 	if (i = system(commbuf)) {
    264 		/*
    265 		 * Under (un)certain conditions, ps630 may return -1 even
    266 		 * if it worked. Hence the commenting out of this error
    267 		 * report.
    268 		 */
    269 		 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
    270 		/* exit(1); */
    271 	}
    272 	if (rename(temp_file, f)) {
    273 		perror("run_ps630: rename");
    274 		exit(1);
    275 	}
    276 	return;
    277 }
    278 
    279 
    280 
    281 
    282 /*
    284 **---------------------------------------------------------------------
    285 **                      WTMP update support
    286 **---------------------------------------------------------------------
    287 */
    288 
    289 
    290 #ifdef WTMP
    291 
    292 #include <utmp.h>
    293 
    294 #ifndef	_PATH_WTMP
    295 #define _PATH_WTMP "/usr/adm/wtmp"
    296 #endif
    297 
    298 void
    299 wlogin(name, req)
    300 	char *name;
    301 	struct svc_req *req;
    302 {
    303 	extern char *inet_ntoa();
    304 	struct sockaddr_in *who;
    305 	struct hostent *hp;
    306 	char *host;
    307 	struct utmp ut;
    308 	int fd;
    309 
    310 	if(!wtmp_enabled)
    311 		return;
    312 
    313 	/* Get network address of client. */
    314 	who = &req->rq_xprt->xp_raddr;
    315 
    316 	/* Get name of connected client */
    317 	hp = gethostbyaddr((char *)&who->sin_addr,
    318 			   sizeof (struct in_addr),
    319 			   who->sin_family);
    320 
    321 	if (hp && (strlen(hp->h_name) <= sizeof(ut.ut_host))) {
    322 		host = hp->h_name;
    323 	} else {
    324 		host = inet_ntoa(who->sin_addr);
    325 	}
    326 
    327 	(void) strcpy(ut.ut_line, "PC-NFS");
    328 	(void) strncpy(ut.ut_name,name,sizeof ut.ut_name);
    329 	(void) strncpy(ut.ut_host, host, sizeof ut.ut_host);
    330 	ut.ut_time = time( (time_t *) 0);
    331 
    332 	if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
    333 		(void)write(fd, (char *)&ut, sizeof(struct utmp));
    334 		(void)close(fd);
    335 	}
    336 }
    337 #endif WTMP
    338 
    339 /*
    341 **---------------------------------------------------------------------
    342 **                      Run-process-as-user procedures
    343 **---------------------------------------------------------------------
    344 */
    345 
    346 
    347 #define	READER_FD	0
    348 #define	WRITER_FD	1
    349 
    350 static int      child_pid;
    351 
    352 static char     cached_user[64] = "";
    353 static uid_t    cached_uid;
    354 static gid_t    cached_gid;
    355 
    356 static	struct sigaction old_action;
    357 static	struct sigaction new_action;
    358 static	struct itimerval timer;
    359 
    360 int interrupted = 0;
    361 static	FILE *pipe_handle;
    362 
    363 static	void myhandler()
    364 {
    365  interrupted = 1;
    366  fclose(pipe_handle);
    367  kill(child_pid, SIGKILL);
    368  msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
    369 }
    370 
    371 void start_watchdog(n)
    372 int n;
    373 {
    374 	/*
    375 	 * Setup SIGALRM handler, force interrupt of ongoing syscall
    376 	 */
    377 
    378 	new_action.sa_handler = myhandler;
    379 	sigemptyset(&(new_action.sa_mask));
    380 	new_action.sa_flags = 0;
    381 #ifdef SA_INTERRUPT
    382 	new_action.sa_flags |= SA_INTERRUPT;
    383 #endif
    384 	sigaction(SIGALRM, &new_action, &old_action);
    385 
    386 	/*
    387 	 * Set interval timer for n seconds
    388 	 */
    389 	timer.it_interval.tv_sec = 0;
    390 	timer.it_interval.tv_usec = 0;
    391 	timer.it_value.tv_sec = n;
    392 	timer.it_value.tv_usec = 0;
    393 	setitimer(ITIMER_REAL, &timer, NULL);
    394 	interrupted = 0;
    395 
    396 }
    397 
    398 void 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 
    417 
    418 FILE           *
    419 su_popen(user, cmd, maxtime)
    420 	char           *user;
    421 	char           *cmd;
    422 	int		maxtime;
    423 {
    424 	int             p[2];
    425 	int             parent_fd, child_fd, pid;
    426 	struct passwd *pw;
    427 
    428 	if (strcmp(cached_user, user)) {
    429 		pw = getpwnam(user);
    430 		if (!pw)
    431 			pw = getpwnam("nobody");
    432 		if (pw) {
    433 			cached_uid = pw->pw_uid;
    434 			cached_gid = pw->pw_gid;
    435 			strcpy(cached_user, user);
    436 		} else {
    437 			cached_uid = (uid_t) (-2);
    438 			cached_gid = (gid_t) (-2);
    439 			cached_user[0] = '\0';
    440 		}
    441 	}
    442 	if (pipe(p) < 0) {
    443 		msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
    444 		return (NULL);
    445 	}
    446 	parent_fd = p[READER_FD];
    447 	child_fd = p[WRITER_FD];
    448 	if ((pid = fork()) == 0) {
    449 		int             i;
    450 
    451 		for (i = 0; i < 10; i++)
    452 			if (i != child_fd)
    453 				(void) close(i);
    454 		if (child_fd != 1) {
    455 			(void) dup2(child_fd, 1);
    456 			(void) close(child_fd);
    457 		}
    458 		dup2(1, 2);	/* let's get stderr as well */
    459 
    460 		(void) setgid(cached_gid);
    461 		(void) setuid(cached_uid);
    462 
    463 		(void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
    464 		_exit(255);
    465 	}
    466 	if (pid == -1) {
    467 		msg_out("rpc.pcnfsd: fork failed");
    468 		close(parent_fd);
    469 		close(child_fd);
    470 		return (NULL);
    471 	}
    472 	child_pid = pid;
    473 	close(child_fd);
    474 	start_watchdog(maxtime);
    475 	pipe_handle = fdopen(parent_fd, "r");
    476 	return (pipe_handle);
    477 }
    478 
    479 int
    480 su_pclose(ptr)
    481 	FILE           *ptr;
    482 {
    483 	int             pid, status;
    484 
    485 	stop_watchdog();
    486 
    487 	fclose(ptr);
    488 	if (child_pid == -1)
    489 		return (-1);
    490 	while ((pid = wait(&status)) != child_pid && pid != -1);
    491 	return (pid == -1 ? -1 : status);
    492 }
    493 
    494 
    495 /*
    497 ** The following routine reads a file "/etc/pcnfsd.conf" if present,
    498 ** and uses it to replace certain builtin elements, like the
    499 ** name of the print spool directory. The configuration file
    500 ** Is the usual kind: Comments begin with '#', blank lines are ignored,
    501 ** and valid lines are of the form
    502 **
    503 **	<keyword><whitespace><value>
    504 **
    505 ** The following keywords are recognized:
    506 **
    507 **	spooldir
    508 **	printer name alias-for command
    509 **	wtmp yes|no
    510 */
    511 void
    512 config_from_file()
    513 {
    514 FILE *fd;
    515 char buff[1024];
    516 char *cp;
    517 char *kw;
    518 char *val;
    519 char *arg1;
    520 char *arg2;
    521 
    522 	if((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
    523 		return;
    524 	while(fgets(buff, 1024, fd)) {
    525 		cp = strchr(buff, '\n');
    526 		*cp = '\0';
    527 		cp = strchr(buff, '#');
    528 		if(cp)
    529 			*cp = '\0';
    530 		kw = strtok(buff, " \t");
    531 		if(kw == NULL)
    532 			continue;
    533 		val = strtok(NULL, " \t");
    534 		if(val == NULL)
    535 			continue;
    536 		if(!mystrcasecmp(kw, "spooldir")) {
    537 			strcpy(sp_name, val);
    538 			continue;
    539 		}
    540 #ifdef WTMP
    541 		if(!mystrcasecmp(kw, "wtmp")) {
    542 			/* assume default is YES, just look for negatives */
    543 			if(!mystrcasecmp(val, "no") ||
    544 			   !mystrcasecmp(val, "off") ||
    545 			   !mystrcasecmp(val, "disable") ||
    546 			   !strcmp(val, "0"))
    547 				wtmp_enabled = 0;;
    548 			continue;
    549 		}
    550 #endif
    551 		if(!mystrcasecmp(kw, "printer")) {
    552 			arg1 = strtok(NULL, " \t");
    553 			arg2 = strtok(NULL, "");
    554 			(void)add_printer_alias(val, arg1, arg2);
    555 			continue;
    556 		}
    557 /*
    558 ** Add new cases here
    559 */
    560 	}
    561 	fclose(fd);
    562 }
    563 
    564 
    565 /*
    566 ** The following are replacements for the SunOS library
    567 ** routines strcasecmp and strncasecmp, which SVR4 doesn't
    568 ** include.
    569 */
    570 
    571 mystrcasecmp(s1, s2)
    572 	char *s1, *s2;
    573 {
    574 
    575 	while (toupper(*s1) == toupper(*s2++))
    576 		if (*s1++ == '\0')
    577 			return(0);
    578 	return(toupper(*s1) - toupper(*--s2));
    579 }
    580 
    581 mystrncasecmp(s1, s2, n)
    582 	char *s1, *s2;
    583 	int n;
    584 {
    585 
    586 	while (--n >= 0 && toupper(*s1) == toupper(*s2++))
    587 		if (*s1++ == '\0')
    588 			return(0);
    589 	return(n < 0 ? 0 : toupper(*s1) - toupper(*--s2));
    590 }
    591 
    592 
    593 /*
    594 ** strembedded - returns true if s1 is embedded (in any case) in s2
    595 */
    596 
    597 int strembedded(s1, s2)
    598 char *s1;
    599 char *s2;
    600 {
    601 	while(*s2) {
    602 		if(!mystrcasecmp(s1, s2))
    603 			return 1;
    604 		s2++;
    605 	}
    606 	return 0;
    607 }
    608