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