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 /* 182 **--------------------------------------------------------------------- 183 ** Print support procedures 184 **--------------------------------------------------------------------- 185 */ 186 187 char * 188 mapfont(f, i, b) 189 char f; 190 char i; 191 char b; 192 { 193 static char fontname[64]; 194 195 fontname[0] = 0; /* clear it out */ 196 197 switch (f) { 198 case 'c': 199 (void)strcpy(fontname, "Courier"); 200 break; 201 case 'h': 202 (void)strcpy(fontname, "Helvetica"); 203 break; 204 case 't': 205 (void)strcpy(fontname, "Times"); 206 break; 207 default: 208 (void)strcpy(fontname, "Times-Roman"); 209 goto finis ; 210 } 211 if (i != 'o' && b != 'b') { /* no bold or oblique */ 212 if (f == 't') /* special case Times */ 213 (void)strcat(fontname, "-Roman"); 214 goto finis; 215 } 216 (void)strcat(fontname, "-"); 217 if (b == 'b') 218 (void)strcat(fontname, "Bold"); 219 if (i == 'o') /* o-blique */ 220 (void)strcat(fontname, f == 't' ? "Italic" : "Oblique"); 221 222 finis: return (&fontname[0]); 223 } 224 225 /* 226 * run_ps630 performs the Diablo 630 emulation filtering process. ps630 227 * was broken in certain Sun releases: it would not accept point size or 228 * font changes. If your version is fixed, undefine the symbol 229 * PS630_IS_BROKEN and rebuild pc-nfsd. 230 */ 231 /* #define PS630_IS_BROKEN 1 */ 232 233 void 234 run_ps630(f, opts) 235 char *f; 236 char *opts; 237 { 238 char temp_file[256]; 239 char commbuf[256]; 240 int i; 241 242 (void)strcpy(temp_file, f); 243 (void)strcat(temp_file, "X"); /* intermediate file name */ 244 245 #ifndef PS630_IS_BROKEN 246 (void)sprintf(commbuf, "ps630 -s %c%c -p %s -f ", 247 opts[2], opts[3], temp_file); 248 (void)strcat(commbuf, mapfont(opts[4], opts[5], opts[6])); 249 (void)strcat(commbuf, " -F "); 250 (void)strcat(commbuf, mapfont(opts[7], opts[8], opts[9])); 251 (void)strcat(commbuf, " "); 252 (void)strcat(commbuf, f); 253 #else /* PS630_IS_BROKEN */ 254 /* 255 * The pitch and font features of ps630 appear to be broken at 256 * this time. 257 */ 258 (void)sprintf(commbuf, "ps630 -p %s %s", temp_file, f); 259 #endif /* PS630_IS_BROKEN */ 260 261 262 if (i = system(commbuf)) { 263 /* 264 * Under (un)certain conditions, ps630 may return -1 even 265 * if it worked. Hence the commenting out of this error 266 * report. 267 */ 268 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ; 269 /* exit(1); */ 270 } 271 if (rename(temp_file, f)) { 272 perror("run_ps630: rename"); 273 exit(1); 274 } 275 return; 276 } 277 278 279 280 281 /* 282 **--------------------------------------------------------------------- 283 ** WTMP update support 284 **--------------------------------------------------------------------- 285 */ 286 287 288 #ifdef WTMP 289 290 #include <utmp.h> 291 292 #ifndef _PATH_WTMP 293 #define _PATH_WTMP "/usr/adm/wtmp" 294 #endif 295 296 void 297 wlogin(name, req) 298 char *name; 299 struct svc_req *req; 300 { 301 extern char *inet_ntoa(); 302 struct sockaddr_in *who; 303 struct hostent *hp; 304 char *host; 305 struct utmp ut; 306 int fd; 307 308 if(!wtmp_enabled) 309 return; 310 311 /* Get network address of client. */ 312 who = &req->rq_xprt->xp_raddr; 313 314 /* Get name of connected client */ 315 hp = gethostbyaddr((char *)&who->sin_addr, 316 sizeof (struct in_addr), 317 who->sin_family); 318 319 if (hp && (strlen(hp->h_name) <= sizeof(ut.ut_host))) { 320 host = hp->h_name; 321 } else { 322 host = inet_ntoa(who->sin_addr); 323 } 324 325 (void) strcpy(ut.ut_line, "PC-NFS"); 326 (void) strncpy(ut.ut_name,name,sizeof ut.ut_name); 327 (void) strncpy(ut.ut_host, host, sizeof ut.ut_host); 328 ut.ut_time = time( (time_t *) 0); 329 330 if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) { 331 (void)write(fd, (char *)&ut, sizeof(struct utmp)); 332 (void)close(fd); 333 } 334 } 335 #endif WTMP 336 337 /* 338 **--------------------------------------------------------------------- 339 ** Run-process-as-user procedures 340 **--------------------------------------------------------------------- 341 */ 342 343 344 #define READER_FD 0 345 #define WRITER_FD 1 346 347 static int child_pid; 348 349 static char cached_user[64] = ""; 350 static uid_t cached_uid; 351 static gid_t cached_gid; 352 353 static struct sigaction old_action; 354 static struct sigaction new_action; 355 static struct itimerval timer; 356 357 int interrupted = 0; 358 static FILE *pipe_handle; 359 360 static void myhandler() 361 { 362 interrupted = 1; 363 fclose(pipe_handle); 364 kill(child_pid, SIGKILL); 365 msg_out("rpc.pcnfsd: su_popen timeout - killed child process"); 366 } 367 368 void start_watchdog(n) 369 int n; 370 { 371 /* 372 * Setup SIGALRM handler, force interrupt of ongoing syscall 373 */ 374 375 new_action.sa_handler = myhandler; 376 sigemptyset(&(new_action.sa_mask)); 377 new_action.sa_flags = 0; 378 #ifdef SA_INTERRUPT 379 new_action.sa_flags |= SA_INTERRUPT; 380 #endif 381 sigaction(SIGALRM, &new_action, &old_action); 382 383 /* 384 * Set interval timer for n seconds 385 */ 386 timer.it_interval.tv_sec = 0; 387 timer.it_interval.tv_usec = 0; 388 timer.it_value.tv_sec = n; 389 timer.it_value.tv_usec = 0; 390 setitimer(ITIMER_REAL, &timer, NULL); 391 interrupted = 0; 392 393 } 394 395 void 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 414 415 FILE * 416 su_popen(user, cmd, maxtime) 417 char *user; 418 char *cmd; 419 int maxtime; 420 { 421 int p[2]; 422 int parent_fd, child_fd, pid; 423 struct passwd *pw; 424 425 if (strcmp(cached_user, user)) { 426 pw = getpwnam(user); 427 if (!pw) 428 pw = getpwnam("nobody"); 429 if (pw) { 430 cached_uid = pw->pw_uid; 431 cached_gid = pw->pw_gid; 432 strcpy(cached_user, user); 433 } else { 434 cached_uid = (uid_t) (-2); 435 cached_gid = (gid_t) (-2); 436 cached_user[0] = '\0'; 437 } 438 } 439 if (pipe(p) < 0) { 440 msg_out("rpc.pcnfsd: unable to create pipe in su_popen"); 441 return (NULL); 442 } 443 parent_fd = p[READER_FD]; 444 child_fd = p[WRITER_FD]; 445 if ((pid = fork()) == 0) { 446 int i; 447 448 for (i = 0; i < 10; i++) 449 if (i != child_fd) 450 (void) close(i); 451 if (child_fd != 1) { 452 (void) dup2(child_fd, 1); 453 (void) close(child_fd); 454 } 455 dup2(1, 2); /* let's get stderr as well */ 456 457 (void) setgid(cached_gid); 458 (void) setuid(cached_uid); 459 460 (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); 461 _exit(255); 462 } 463 if (pid == -1) { 464 msg_out("rpc.pcnfsd: fork failed"); 465 close(parent_fd); 466 close(child_fd); 467 return (NULL); 468 } 469 child_pid = pid; 470 close(child_fd); 471 start_watchdog(maxtime); 472 pipe_handle = fdopen(parent_fd, "r"); 473 return (pipe_handle); 474 } 475 476 int 477 su_pclose(ptr) 478 FILE *ptr; 479 { 480 int pid, status; 481 482 stop_watchdog(); 483 484 fclose(ptr); 485 if (child_pid == -1) 486 return (-1); 487 while ((pid = wait(&status)) != child_pid && pid != -1); 488 return (pid == -1 ? -1 : status); 489 } 490 491 492 /* 493 ** The following routine reads a file "/etc/pcnfsd.conf" if present, 494 ** and uses it to replace certain builtin elements, like the 495 ** name of the print spool directory. The configuration file 496 ** Is the usual kind: Comments begin with '#', blank lines are ignored, 497 ** and valid lines are of the form 498 ** 499 ** <keyword><whitespace><value> 500 ** 501 ** The following keywords are recognized: 502 ** 503 ** spooldir 504 ** printer name alias-for command 505 ** wtmp yes|no 506 */ 507 void 508 config_from_file() 509 { 510 FILE *fd; 511 char buff[1024]; 512 char *cp; 513 char *kw; 514 char *val; 515 char *arg1; 516 char *arg2; 517 518 if((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL) 519 return; 520 while(fgets(buff, 1024, fd)) { 521 cp = strchr(buff, '\n'); 522 *cp = '\0'; 523 cp = strchr(buff, '#'); 524 if(cp) 525 *cp = '\0'; 526 kw = strtok(buff, " \t"); 527 if(kw == NULL) 528 continue; 529 val = strtok(NULL, " \t"); 530 if(val == NULL) 531 continue; 532 if(!mystrcasecmp(kw, "spooldir")) { 533 strcpy(sp_name, val); 534 continue; 535 } 536 #ifdef WTMP 537 if(!mystrcasecmp(kw, "wtmp")) { 538 /* assume default is YES, just look for negatives */ 539 if(!mystrcasecmp(val, "no") || 540 !mystrcasecmp(val, "off") || 541 !mystrcasecmp(val, "disable") || 542 !strcmp(val, "0")) 543 wtmp_enabled = 0;; 544 continue; 545 } 546 #endif 547 if(!mystrcasecmp(kw, "printer")) { 548 arg1 = strtok(NULL, " \t"); 549 arg2 = strtok(NULL, ""); 550 (void)add_printer_alias(val, arg1, arg2); 551 continue; 552 } 553 /* 554 ** Add new cases here 555 */ 556 } 557 fclose(fd); 558 } 559 560 561 /* 562 ** The following are replacements for the SunOS library 563 ** routines strcasecmp and strncasecmp, which SVR4 doesn't 564 ** include. 565 */ 566 567 mystrcasecmp(s1, s2) 568 char *s1, *s2; 569 { 570 571 while (toupper(*s1) == toupper(*s2++)) 572 if (*s1++ == '\0') 573 return(0); 574 return(toupper(*s1) - toupper(*--s2)); 575 } 576 577 mystrncasecmp(s1, s2, n) 578 char *s1, *s2; 579 int n; 580 { 581 582 while (--n >= 0 && toupper(*s1) == toupper(*s2++)) 583 if (*s1++ == '\0') 584 return(0); 585 return(n < 0 ? 0 : toupper(*s1) - toupper(*--s2)); 586 } 587 588 589 /* 590 ** strembedded - returns true if s1 is embedded (in any case) in s2 591 */ 592 593 int strembedded(s1, s2) 594 char *s1; 595 char *s2; 596 { 597 while(*s2) { 598 if(!mystrcasecmp(s1, s2)) 599 return 1; 600 s2++; 601 } 602 return 0; 603 } 604