/* $NetBSD: pcnfsd_misc.c,v 1.16 2018/01/23 21:06:25 sevan Exp $ */ /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_misc.c 1.5 92/01/24 19:59:13 SMI */ /* **===================================================================== ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc. ** @(#)pcnfsd_misc.c 1.5 1/24/92 **===================================================================== */ /* **===================================================================== ** I N C L U D E F I L E S E C T I O N * ** * ** If your port requires different include files, add a suitable * ** #define in the customization section, and make the inclusion or * ** exclusion of the files conditional on this. * **===================================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SUPPORT_UTMPX #include #endif #ifdef ISC_2_0 #include #endif #ifdef SHADOW_SUPPORT #include #endif #ifdef WTMP int wtmp_enabled = 1; #endif #include "common.h" #include "pcnfsd.h" #include "extern.h" /* **--------------------------------------------------------------------- ** Other #define's **--------------------------------------------------------------------- */ #define zchar 0x5b char tempstr[256]; char *mapfont(char, char, char); void myhandler(int); void start_watchdog(int); void stop_watchdog(void); /* **===================================================================== ** C O D E S E C T I O N * **===================================================================== */ /* **--------------------------------------------------------------------- ** Support procedures **--------------------------------------------------------------------- */ void scramble(char *s1, char *s2) { while (*s1) { *s2++ = (*s1 ^ zchar) & 0x7f; s1++; } *s2 = 0; } struct passwd * get_password(char *usrnam) { struct passwd *p; static struct passwd localp; __aconst char *pswd, *ushell; #ifdef SHADOW_SUPPORT struct spwd *sp; int shadowfile; #endif #ifdef SHADOW_SUPPORT /* **-------------------------------------------------------------- ** Check the existence of SHADOW. If it is there, then we are ** running a two-password-file system. **-------------------------------------------------------------- */ if (access(SHADOW, 0)) shadowfile = 0; /* SHADOW is not there */ else shadowfile = 1; setpwent(); if (shadowfile) (void) setspent(); /* Setting the shadow password file */ if ((p = getpwnam(usrnam)) == NULL || (shadowfile && (sp = getspnam(usrnam)) == NULL)) return (NULL); if (shadowfile) { pswd = sp->sp_pwdp; (void) endspent(); } else pswd = p->pw_passwd; #else p = getpwnam(usrnam); if (p == NULL) return (NULL); pswd = p->pw_passwd; #endif #ifdef ISC_2_0 /* *----------------------------------------------------------- * We * may have an 'x' in which case look in /etc/shadow .. * *----------------------------------------------------------- */ if (((strlen(pswd)) == 1) && pswd[0] == 'x') { struct spwd *shadow = getspnam(usrnam); if (!shadow) return (NULL); pswd = shadow->sp_pwdp; } #endif localp = *p; localp.pw_passwd = pswd; #ifdef USE_GETUSERSHELL setusershell(); while (ushell = getusershell()) { if (!strcmp(ushell, localp.pw_shell)) { ok = 1; break; } } endusershell(); if (!ok) return (NULL); #else /* * the best we can do is to ensure that the shell ends in "sh" */ ushell = localp.pw_shell; if (strlen(ushell) < 2) return (NULL); ushell += strlen(ushell) - 2; if (strcmp(ushell, "sh")) return (NULL); #endif return (&localp); } /* **--------------------------------------------------------------------- ** Print support procedures **--------------------------------------------------------------------- */ char * mapfont(char f, char i, char b) { static char fontname[64]; fontname[0] = 0; /* clear it out */ switch (f) { case 'c': (void) strlcpy(fontname, "Courier", sizeof(fontname)); break; case 'h': (void) strlcpy(fontname, "Helvetica", sizeof(fontname)); break; case 't': (void) strlcpy(fontname, "Times", sizeof(fontname)); break; default: (void) strlcpy(fontname, "Times-Roman", sizeof(fontname)); goto finis; } if (i != 'o' && b != 'b') { /* no bold or oblique */ if (f == 't') /* special case Times */ (void) strlcat(fontname, "-Roman", sizeof(fontname)); goto finis; } (void) strlcat(fontname, "-", sizeof(fontname)); if (b == 'b') (void) strlcat(fontname, "Bold", sizeof(fontname)); if (i == 'o') /* o-blique */ (void) strlcat(fontname, f == 't' ? "Italic" : "Oblique", sizeof(fontname)); finis: return (&fontname[0]); } /* * run_ps630 performs the Diablo 630 emulation filtering process. ps630 * was broken in certain Sun releases: it would not accept point size or * font changes. If your version is fixed, undefine the symbol * PS630_IS_BROKEN and rebuild pc-nfsd. */ /* #define PS630_IS_BROKEN 1 */ void run_ps630(char *f, char *opts) { char temp_file[256]; char commbuf[256]; int i; (void) strlcpy(temp_file, f, sizeof(temp_file)); (void) strlcat(temp_file, "X", sizeof(temp_file)); /* intermediate file name */ #ifndef PS630_IS_BROKEN (void) snprintf(commbuf, sizeof(commbuf), "ps630 -s %c%c -p %s -f ", opts[2], opts[3], temp_file); (void) strlcat(commbuf, mapfont(opts[4], opts[5], opts[6]), sizeof(commbuf)); (void) strlcat(commbuf, " -F ", sizeof(commbuf)); (void) strlcat(commbuf, mapfont(opts[7], opts[8], opts[9]), sizeof(commbuf)); (void) strlcat(commbuf, " ", sizeof(commbuf)); (void) strlcat(commbuf, f, sizeof(commbuf)); #else /* PS630_IS_BROKEN */ /* * The pitch and font features of ps630 appear to be broken at * this time. */ (void) snprintf(commbuf, sizeof(commbuf), "ps630 -p %s %s", temp_file, f); #endif /* PS630_IS_BROKEN */ if ((i = system(commbuf)) != 0) { /* * Under (un)certain conditions, ps630 may return -1 even * if it worked. Hence the commenting out of this error * report. */ /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ; /* exit(1); */ } if (rename(temp_file, f)) { perror("run_ps630: rename"); exit(1); } return; } /* **--------------------------------------------------------------------- ** WTMP update support **--------------------------------------------------------------------- */ #ifdef WTMP void wlogin(char *name, struct svc_req *req) { struct sockaddr_in *who; struct hostent *hp; char *host; if (!wtmp_enabled) return; /* Get network address of client. */ who = &req->rq_xprt->xp_raddr; /* Get name of connected client */ hp = gethostbyaddr((char *) &who->sin_addr, sizeof(struct in_addr), who->sin_family); if (hp) { host = hp->h_name; } else { host = inet_ntoa(who->sin_addr); } #ifdef SUPPORT_UTMP logwtmp("PC-NFS", name, host); #endif #ifdef SUPPORT_UTMPX logwtmpx("PC-NFS", name, host, 0, USER_PROCESS); #endif } #endif /* WTMP */ /* **--------------------------------------------------------------------- ** Run-process-as-user procedures **--------------------------------------------------------------------- */ #define READER_FD 0 #define WRITER_FD 1 static int child_pid; static char cached_user[64] = ""; static uid_t cached_uid; static gid_t cached_gid; static struct sigaction old_action; static struct sigaction new_action; static struct itimerval timer; int interrupted = 0; static FILE *pipe_handle; void myhandler(int dummy) { interrupted = 1; fclose(pipe_handle); kill(child_pid, SIGKILL); msg_out("rpc.pcnfsd: su_popen timeout - killed child process"); } void start_watchdog(int n) { /* * Setup SIGALRM handler, force interrupt of ongoing syscall */ new_action.sa_handler = myhandler; sigemptyset(&(new_action.sa_mask)); new_action.sa_flags = 0; #ifdef SA_INTERRUPT new_action.sa_flags |= SA_INTERRUPT; #endif sigaction(SIGALRM, &new_action, &old_action); /* * Set interval timer for n seconds */ timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = n; timer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &timer, NULL); interrupted = 0; } void stop_watchdog() { /* * Cancel timer */ timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = 0; timer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &timer, NULL); /* * restore old signal handling */ sigaction(SIGALRM, &old_action, NULL); } FILE * su_popen(char *user, char *cmd, int maxtime) { int p[2]; int parent_fd, child_fd, pid; struct passwd *pw; if (strcmp(cached_user, user)) { pw = getpwnam(user); if (!pw) pw = getpwnam("nobody"); if (pw) { cached_uid = pw->pw_uid; cached_gid = pw->pw_gid; strlcpy(cached_user, user, sizeof(cached_user)); } else { cached_uid = (uid_t) (-2); cached_gid = (gid_t) (-2); cached_user[0] = '\0'; } } if (pipe(p) < 0) { msg_out("rpc.pcnfsd: unable to create pipe in su_popen"); return (NULL); } parent_fd = p[READER_FD]; child_fd = p[WRITER_FD]; if ((pid = fork()) == 0) { int i; for (i = 0; i < 10; i++) if (i != child_fd) (void) close(i); if (child_fd != 1) { (void) dup2(child_fd, 1); (void) close(child_fd); } dup2(1, 2); /* let's get stderr as well */ (void) setgid(cached_gid); (void) setuid(cached_uid); (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); _exit(255); } if (pid == -1) { msg_out("rpc.pcnfsd: fork failed"); close(parent_fd); close(child_fd); return (NULL); } child_pid = pid; close(child_fd); start_watchdog(maxtime); pipe_handle = fdopen(parent_fd, "r"); return (pipe_handle); } int su_pclose(FILE *ptr) { int pid, status; stop_watchdog(); fclose(ptr); if (child_pid == -1) return (-1); while ((pid = wait(&status)) != child_pid && pid != -1); return (pid == -1 ? -1 : status); } /* ** The following routine reads a file "/etc/pcnfsd.conf" if present, ** and uses it to replace certain builtin elements, like the ** name of the print spool directory. The configuration file ** Is the usual kind: Comments begin with '#', blank lines are ignored, ** and valid lines are of the form ** ** ** ** The following keywords are recognized: ** ** spooldir ** printer name alias-for command ** wtmp yes|no */ static void config_from_file(void) { FILE *fd; char buff[1024]; char *cp; char *kw; char *val; char *arg1; char *arg2; if ((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL) return; while (fgets(buff, 1024, fd)) { cp = strchr(buff, '\n'); *cp = '\0'; cp = strchr(buff, '#'); if (cp) *cp = '\0'; kw = strtok(buff, " \t"); if (kw == NULL) continue; val = strtok(NULL, " \t"); if (val == NULL) continue; if (!strcasecmp(kw, "spooldir")) { strlcpy(sp_name, val, sizeof(sp_name)); continue; } #ifdef WTMP if (!strcasecmp(kw, "wtmp")) { /* assume default is YES, just look for negatives */ if (!strcasecmp(val, "no") || !strcasecmp(val, "off") || !strcasecmp(val, "disable") || !strcmp(val, "0")) wtmp_enabled = 0; continue; } #endif if (!strcasecmp(kw, "printer")) { arg1 = strtok(NULL, " \t"); arg2 = strtok(NULL, ""); (void) add_printer_alias(val, arg1, arg2); continue; } /* ** Add new cases here */ } fclose(fd); } /* ** hack for main() - call config_from_file() then the real main ** in the rpcgen output, which is hacked by CPPFLAGS to be "mymain" */ #undef main int mymain(int argc, char *argv[]); int main(int argc, char *argv[]) { config_from_file(); return mymain(argc, argv); } /* ** strembedded - returns true if s1 is embedded (in any case) in s2 */ int strembedded(const char *s1, const char *s2) { while (*s2) { if (!strcasecmp(s1, s2)) return 1; s2++; } return 0; }