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