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