/* * set_env - copy command line arguments into the environment */ void set_env(int argc, char * const *argv) { int noname = 1; char variable[1024]; char *cp; for ( ; argc > 0; argc--, argv++) { if (strlen(*argv) >= sizeof variable) continue; /* ignore long entries */ if (! (cp = strchr (*argv, '='))) { snprintf(variable, sizeof variable, "L%d", noname++); addenv(variable, *argv); } else { const char **p; for (p = forbid; *p; p++) if (strncmp(*argv, *p, strlen(*p)) == 0) break; if (*p) { strncpy(variable, *argv, cp - *argv); variable[cp - *argv] = '\0'; printf(_("You may not change $%s\n"), variable); continue; } addenv(*argv, NULL); } } }
/* * change to the user's home directory * set the HOME, SHELL, MAIL, PATH, and LOGNAME or USER environmental * variables. */ void setup_env(struct passwd *info) { char *cp; /* * Change the current working directory to be the home directory * of the user. It is a fatal error for this process to be unable * to change to that directory. There is no "default" home * directory. * * We no longer do it as root - should work better on NFS-mounted * home directories. */ if (chdir(info->pw_dir) == -1) { static char temp_pw_dir[] = "/"; if (!getdef_bool("DEFAULT_HOME") || chdir("/") == -1) { fprintf(stderr, _("Unable to cd to \"%s\"\n"), info->pw_dir); syslog(LOG_WARNING, "unable to cd to `%s' for user `%s'\n", info->pw_dir, info->pw_name); closelog(); exit (1); } puts(_("No directory, logging in with HOME=/")); info->pw_dir = temp_pw_dir; } /* * Create the HOME environmental variable and export it. */ addenv("HOME", info->pw_dir); /* * Create the SHELL environmental variable and export it. */ if (info->pw_shell == (char *) 0 || ! *info->pw_shell) { static char temp_pw_shell[] = "/bin/sh"; info->pw_shell = temp_pw_shell; } addenv("SHELL", info->pw_shell); /* * Create the PATH environmental variable and export it. */ cp = getdef_str("ENV_PATH"); addenv(cp ? cp : "PATH=/bin:/usr/bin", NULL); /* * Export the user name. For BSD derived systems, it's "USER", for * all others it's "LOGNAME". We set both of them. */ addenv("USER", info->pw_name); addenv("LOGNAME", info->pw_name); }
void semicolon_arrfixenv(char *s, char **t) { char **ep, *u; int len_s; Param pm; MUSTUSEHEAP("semicolon_arrfixenv"); if (t == path) cmdnamtab->emptytable(cmdnamtab); u = zjoin(t, ';'); len_s = strlen(s); pm = (Param) paramtab->getnode(paramtab, s); for (ep = environ; *ep; ep++) if (!strncmp(*ep, s, len_s) && (*ep)[len_s] == '=') { pm->env = replenv(*ep, u); // (void)SetEnvironmentVariable(*ep,u); return; } if (isset(ALLEXPORT)) pm->flags |= PM_EXPORTED; if (pm->flags & PM_EXPORTED) { pm->env = addenv(s, u); (void)SetEnvironmentVariable(s,u); } }
void updenvlocal(Var *v) { if(v){ updenvlocal(v->next); addenv(v); } }
static void init_env (void) { #ifndef USE_PAM char *cp; #endif char *tmp; tmp = getenv ("LANG"); if (NULL != tmp) { addenv ("LANG", tmp); } /* * Add the timezone environmental variable so that time functions * work correctly. */ tmp = getenv ("TZ"); if (NULL != tmp) { addenv ("TZ", tmp); } #ifndef USE_PAM else { cp = getdef_str ("ENV_TZ"); if (NULL != cp) { addenv (('/' == *cp) ? tz (cp) : cp, NULL); } } #endif /* !USE_PAM */ /* * Add the clock frequency so that profiling commands work * correctly. */ tmp = getenv ("HZ"); if (NULL != tmp) { addenv ("HZ", tmp); } #ifndef USE_PAM else { cp = getdef_str ("ENV_HZ"); if (NULL != cp) { addenv (cp, NULL); } } #endif /* !USE_PAM */ }
void Updenv(void) { var *v, **h; for(h = gvar;h!=&gvar[NVAR];h++) for(v=*h;v;v = v->next) addenv(v); if(runq) updenvlocal(runq->local); }
/* * set_env - copy command line arguments into the environment */ void set_env (int argc, char *const *argv) { int noname = 1; char variable[1024]; char *cp; for (; argc > 0; argc--, argv++) { if (strlen (*argv) >= sizeof variable) { continue; /* ignore long entries */ } cp = strchr (*argv, '='); if (NULL == cp) { int wlen; wlen = snprintf (variable, sizeof variable, "L%d", noname); assert (wlen < (int) sizeof(variable)); noname++; addenv (variable, *argv); } else { const char **p; for (p = forbid; NULL != *p; p++) { if (strncmp (*argv, *p, strlen (*p)) == 0) { break; } } if (NULL != *p) { strncpy (variable, *argv, (size_t)(cp - *argv)); variable[cp - *argv] = '\0'; printf (_("You may not change $%s\n"), variable); continue; } addenv (*argv, NULL); } } }
/* * ttytype - set ttytype from port to terminal type mapping database */ void ttytype (const char *line) { FILE *fp; char buf[BUFSIZ]; char *typefile; char *cp; char type[BUFSIZ]; char port[BUFSIZ]; if (getenv ("TERM")) return; if ((typefile = getdef_str ("TTYTYPE_FILE")) == NULL) return; if (access (typefile, F_OK)) return; if (!(fp = fopen (typefile, "r"))) { perror (typefile); return; } while (fgets (buf, sizeof buf, fp)) { if (buf[0] == '#') continue; if ((cp = strchr (buf, '\n'))) *cp = '\0'; if (sscanf (buf, "%s %s", type, port) == 2 && strcmp (line, port) == 0) break; } if (!feof (fp) && !ferror (fp)) addenv ("TERM", type); fclose (fp); }
int main(int argc, char **argv) { const char *filename = NULL; for (int i = 1; i < argc; i++) { if (strstr(argv[i], "-mcpu=") == argv[i]) { setenv("SI_FORCE_FAMILY", argv[i] + 6, 1); } else if (filename == NULL) { filename = argv[i]; } else { if (strcmp(argv[i], "--help") != 0 && strcmp(argv[i], "-h") != 0) fprintf(stderr, "Unknown option: %s\n\n", argv[i]); fprintf(stderr, "Usage: amdgcn_glslc -mcpu=[chip name] [glsl filename]\n"); return 1; } } if (filename == NULL) { fprintf(stderr, "No filename specified.\n"); return 1; } addenv("R600_DEBUG", "precompile,vs,tcs,tes,gs,ps,cs,noir,notgsi"); create_gl_core_context(); /* Read the source. */ char *input = read_file(filename); /* Comment out lines beginning with ; (FileCheck prefix). */ if (input[0] == ';') memcpy(input, "//", 2); char *s = input; while (s = strstr(s, "\n;")) memcpy(s + 1, "//", 2); s = input; while (s && (s = strstr(s, "#shader "))) { char type_str[16], name[128]; GLenum type; /* If #shader is not at the beginning of the line. */ if (s != input && s[-1] != '\n' && s[-1] != 0) { s = strstr(s, "\n"); continue; } /* Parse the #shader directive. */ if (sscanf(s + 8, "%s %s", type_str, name) != 2) { fprintf(stderr, "Cannot parse #shader directive.\n"); continue; } if (!strcmp(type_str, "vs")) type = GL_VERTEX_SHADER; else if (!strcmp(type_str, "tcs")) type = GL_TESS_CONTROL_SHADER; else if (!strcmp(type_str, "tes")) type = GL_TESS_EVALUATION_SHADER; else if (!strcmp(type_str, "gs")) type = GL_GEOMETRY_SHADER; else if (!strcmp(type_str, "fs")) type = GL_FRAGMENT_SHADER; else if (!strcmp(type_str, "cs")) type = GL_COMPUTE_SHADER; /* Go the next line. */ s = strstr(s, "\n"); if (!s) break; s++; const char *source = s; /* Cut the shader source at the end. */ s = strstr(s, "#shader"); if (s && s[-1] == '\n') s[-1] = 0; /* Compile the shader. */ printf("@%s:\n", name); /* Redirect stderr to stdout for the compiler. */ FILE *stderr_original = stderr; stderr = stdout; GLuint prog = glCreateShaderProgramv(type, 1, &source); stderr = stderr_original; GLint linked; glGetProgramiv(prog, GL_LINK_STATUS, &linked); if (!linked) { char log[4096]; GLsizei length; glGetProgramInfoLog(prog, sizeof(log), &length, log); fprintf(stderr, "ERROR: Compile failure:\n\n%s\n%s\n", source, log); return 1; } glDeleteProgram(prog); } return 0; }
/* * TODO: CLEANUP * * This function is DEPRECATED and should be removed with the next * major release. * * This function can't be used in multi threaded environments because it * might cause a deadlock in the executing qmaster thread. * Use sge_peopen_r() instead. */ pid_t sge_peopen(const char *shell, int login_shell, const char *command, const char *user, char **env, FILE **fp_in, FILE **fp_out, FILE **fp_err, bool null_stderr) { pid_t pid; int pipefds[3][2]; const char *could_not = MSG_SYSTEM_EXECBINSHFAILED; const char *not_root = MSG_SYSTEM_NOROOTRIGHTSTOSWITCHUSER; int i; char arg0[256]; char err_str[256]; #if !(defined(WIN32) || defined(INTERIX)) /* var not needed */ int res; #endif /* WIN32 */ uid_t myuid; DENTER(TOP_LAYER, "sge_peopen"); /* open pipes - close on failure */ for (i=0; i<3; i++) { if (pipe(pipefds[i]) != 0) { while (--i >= 0) { close(pipefds[i][0]); close(pipefds[i][1]); } ERROR((SGE_EVENT, MSG_SYSTEM_FAILOPENPIPES_SS, command, strerror(errno))); DEXIT; return -1; } } #if defined(SOLARIS) pid = sge_smf_contract_fork(err_str, 256); #else pid = fork(); #endif if (pid == 0) { /* child */ int keep_open[6]; keep_open[0] = 0; keep_open[1] = 1; keep_open[2] = 2; keep_open[3] = pipefds[0][0]; keep_open[4] = pipefds[1][1]; keep_open[5] = pipefds[2][1]; sge_close_all_fds(keep_open, 6); /* shall we redirect stderr to /dev/null? */ if (null_stderr) { /* open /dev/null */ int fd = open("/dev/null", O_WRONLY); if (fd == -1) { sprintf(err_str, MSG_ERROROPENINGFILEFORWRITING_SS, "/dev/null", strerror(errno)); sprintf(err_str, "\n"); write(2, err_str, strlen(err_str)); SGE_EXIT(NULL, 1); } /* set stderr to /dev/null */ close(2); dup(fd); /* we don't need the stderr the pipe - close it */ close(pipefds[2][1]); } else { /* redirect stderr to the pipe */ close(2); dup(pipefds[2][1]); } /* redirect stdin and stdout to the pipes */ close(0); close(1); dup(pipefds[0][0]); dup(pipefds[1][1]); if (user) { struct passwd *pw; struct passwd pw_struct; char *buffer; int size; size = get_pw_buffer_size(); buffer = sge_malloc(size); if (!(pw=sge_getpwnam_r(user, &pw_struct, buffer, size))) { sprintf(err_str, MSG_SYSTEM_NOUSERFOUND_SS , user, strerror(errno)); sprintf(err_str, "\n"); write(2, err_str, strlen(err_str)); FREE(buffer); SGE_EXIT(NULL, 1); } myuid = geteuid(); if (myuid != pw->pw_uid) { /* Only change user if we differ from the wanted user */ if(myuid != SGE_SUPERUSER_UID) { write(2, not_root, sizeof(not_root)); FREE(buffer); SGE_EXIT(NULL, 1); } sprintf(err_str, "%s %d\n", pw->pw_name, (int)pw->pw_gid); write(2, err_str, strlen(err_str)); #if !(defined(WIN32) || defined(INTERIX)) /* initgroups not called */ res = initgroups(pw->pw_name,pw->pw_gid); # if defined(SVR3) || defined(sun) if (res < 0) # else if (res) # endif { sprintf(err_str, MSG_SYSTEM_INITGROUPSFORUSERFAILED_ISS , res, user, strerror(errno)); sprintf(err_str, "\n"); write(2, err_str, strlen(err_str)); FREE(buffer); SGE_EXIT(NULL, 1); } #endif /* WIN32 */ if (setuid(pw->pw_uid)) { sprintf(err_str, MSG_SYSTEM_SWITCHTOUSERFAILED_SS , user, strerror(errno)); sprintf(err_str, "\n"); write(2, err_str, strlen(err_str)); FREE(buffer); SGE_EXIT(NULL, 1); } } addenv("HOME", pw->pw_dir); addenv("SHELL", pw->pw_shell); addenv("USER", pw->pw_name); addenv("LOGNAME", pw->pw_name); addenv("PATH", SGE_DEFAULT_PATH); FREE(buffer); } if (login_shell) strcpy(arg0, "-"); else strcpy(arg0, ""); strcat(arg0, shell); if (env) for(; *env; env++) putenv(*env); execlp(shell, arg0, "-c", command, NULL); write(2, could_not, sizeof(could_not)); SGE_EXIT(NULL, 1); } if (pid < 0) { for (i=0; i<3; i++) { close(pipefds[i][0]); close(pipefds[i][1]); } #if defined(SOLARIS) if (pid < -1 && err_str) { ERROR((SGE_EVENT, MSG_SMF_FORK_FAILED_SS, "sge_peopen()", err_str)); } #endif /* fork could have failed, report it */ ERROR((SGE_EVENT, MSG_SMF_FORK_FAILED_SS, "sge_peopen()", strerror(errno))); DEXIT; return -1; } /* close the childs ends of the pipes */ close(pipefds[0][0]); close(pipefds[1][1]); close(pipefds[2][1]); /* return filehandles for stdin and stdout */ *fp_in = fdopen(pipefds[0][1], "a"); *fp_out = fdopen(pipefds[1][0], "r"); /* is stderr redirected to /dev/null? */ if (null_stderr) { /* close the pipe and return NULL as filehandle */ close(pipefds[2][0]); *fp_err = NULL; } else { /* return filehandle for stderr */ *fp_err = fdopen(pipefds[2][0], "r"); } DEXIT; return pid; }
/****** uti/stdio/sge_peopen() ************************************************ * NAME * sge_peopen_r() -- Advanced popen() * * SYNOPSIS * pid_t sge_peopen_r(const char *shell, int login_shell, * const char *command, const char *user, * char **env, FILE **fp_in, FILE **fp_out, * FILE **fp_err) * * FUNCTION * Advanced popen() with additional parameters: * - free shell usage * - login shell if wanted * - user under which to start (for root only) * - stdin and stderr file pointers * - wait for exactly the process we started * File descriptors have to be closed with sge_peclose(). * * This function is reentrant as long as env is not provided to * this function. This means that the function can be used in * multi thread processed as long as env is not used. * * INPUTS * const char *shell - which shell to use * int login_shell - make it a login shell? * const char *command - name of the program * const char *user - user under which to start (for root only) * char **env - env variables to add to child * FILE **fp_in - file input stream * FILE **fp_out - file output stream * FILE **fp_err - file error stream * * RESULT * pid_t - process id * * NOTES * MT-NOTE: sge_peopen() is MT safe * * DO NOT ADD ASYNC SIGNAL UNSAFE FUNCTIONS BETWEEN FORK AND EXEC * DUE TO THE FACT THAT THIS FUNCTION WILL BE USED IN QMASTER * (MULTITHREADED ENVIRONMENT) THIS MIGHT CAUSE A DEADLOCK * IN A MASTER THREAD. * * SEE ALSO * uti/stdio/sge_peclose() ******************************************************************************/ pid_t sge_peopen_r(const char *shell, int login_shell, const char *command, const char *user, char **env, FILE **fp_in, FILE **fp_out, FILE **fp_err, bool null_stderr) { pid_t pid; int pipefds[3][2]; int i; char arg0[256]; #if defined(SOLARIS) char err_str[256]; #endif struct passwd *pw = NULL; uid_t myuid; uid_t tuid; DENTER(TOP_LAYER, "sge_peopen_r"); if (sge_has_admin_user()) { sge_switch2start_user(); } myuid = geteuid(); tuid = myuid; /* * open pipes - close on failure */ for (i = 0; i < 3; i++) { if (pipe(pipefds[i]) != 0) { while (--i >= 0) { close(pipefds[i][0]); close(pipefds[i][1]); } ERROR((SGE_EVENT, MSG_SYSTEM_FAILOPENPIPES_SS, command, strerror(errno))); if (sge_has_admin_user()) { sge_switch2admin_user(); } DRETURN(-1); } } /* * set arg0 for exec call correctly to that * either a normal shell or a login shell will be started */ if (login_shell) { strcpy(arg0, "-"); } else { strcpy(arg0, ""); } strcat(arg0, shell); DPRINTF(("arg0 = %s\n", arg0)); DPRINTF(("arg1 = -c\n")); DPRINTF(("arg2 = %s\n", command)); /* * prepare the change of the user which might be done after fork() * if a user name is provided. * * this has to be done before the fork() afterwards it might cause * a deadlock of the child because getpwnam() is not async-thread safe. */ if (user) { struct passwd pw_struct; int size = get_pw_buffer_size(); char *buffer = sge_malloc(size); /* * get information about the target user */ if (buffer != NULL) { pw = sge_getpwnam_r(user, &pw_struct, buffer, size); if (pw == NULL) { ERROR((SGE_EVENT, MSG_SYSTEM_NOUSERFOUND_SS, user, strerror(errno))); FREE(buffer); if (sge_has_admin_user()) { sge_switch2admin_user(); } DRETURN(-1); } } else { ERROR((SGE_EVENT, MSG_UTI_MEMPWNAM)); FREE(buffer); if (sge_has_admin_user()) { sge_switch2admin_user(); } DRETURN(-1); } DPRINTF(("was able to resolve user\n")); /* * only prepare change of user if target user is different from current one */ if (myuid != pw->pw_uid) { #if !(defined(WIN32) || defined(INTERIX)) /* var not needed */ int res; #endif if (myuid != SGE_SUPERUSER_UID) { DPRINTF(("only root is allowed to switch to a different user\n")); ERROR((SGE_EVENT, MSG_SYSTEM_NOROOTRIGHTSTOSWITCHUSER)); FREE(buffer); DRETURN(-2); } DPRINTF(("Before initgroups\n")); #if !(defined(WIN32) || defined(INTERIX)) /* initgroups not called */ res = initgroups(pw->pw_name, pw->pw_gid); # if defined(SVR3) || defined(sun) if (res < 0) # else if (res) # endif { ERROR((SGE_EVENT, MSG_SYSTEM_INITGROUPSFORUSERFAILED_ISS, res, user, strerror(errno))); FREE(buffer); SGE_EXIT(NULL, 1); } DPRINTF(("Initgroups was successful\n")); #endif /* WIN32 */ } DPRINTF(("user = %s\n", user)); DPRINTF(("myuid = %d\n", (int)myuid)); if (pw != NULL) { tuid = pw->pw_uid; DPRINTF(("target uid = %d\n", (int)tuid)); } FREE(buffer); } DPRINTF(("Now process will fork\n")); #if defined(SOLARIS) pid = sge_smf_contract_fork(err_str, 256); #else pid = fork(); #endif /* * in the child pid is 0 */ if (pid == 0) { /* * close all fd's except that ones mentioned in keep_open */ int keep_open[6]; keep_open[0] = 0; keep_open[1] = 1; keep_open[2] = 2; keep_open[3] = pipefds[0][0]; keep_open[4] = pipefds[1][1]; keep_open[5] = pipefds[2][1]; sge_close_all_fds(keep_open, 6); /* * shall we redirect stderr to /dev/null? Then * - open "/dev/null" * - set stderr to "dev/null" * - close the stderr-pipe * otherwise * - redirect stderr to the pipe */ if (null_stderr) { int fd = open("/dev/null", O_WRONLY); if (fd != -1) { close(2); dup(fd); close(pipefds[2][1]); } else { SGE_EXIT(NULL, 1); } } else { close(2); dup(pipefds[2][1]); } /* * redirect stdin and stdout to the pipes */ close(0); close(1); dup(pipefds[0][0]); dup(pipefds[1][1]); if (pw != NULL) { int lret = setuid(tuid); if (lret) { SGE_EXIT(NULL, 1); } } /* * set the environment if we got one as argument */ if (env != NULL) { if (pw != NULL) { addenv("HOME", pw->pw_dir); addenv("SHELL", pw->pw_shell); addenv("USER", pw->pw_name); addenv("LOGNAME", pw->pw_name); } addenv("PATH", SGE_DEFAULT_PATH); for(; *env; env++) { putenv(*env); } } execlp(shell, arg0, "-c", command, NULL); } if (pid < 0) { for (i=0; i<3; i++) { close(pipefds[i][0]); close(pipefds[i][1]); } #if defined(SOLARIS) if (pid < -1 && err_str) { ERROR((SGE_EVENT, MSG_SMF_FORK_FAILED_SS, "sge_peopen()", err_str)); } #endif if (sge_has_admin_user()) { sge_switch2admin_user(); } DRETURN(-1); } /* close the childs ends of the pipes */ close(pipefds[0][0]); close(pipefds[1][1]); close(pipefds[2][1]); /* return filehandles for stdin and stdout */ *fp_in = fdopen(pipefds[0][1], "a"); *fp_out = fdopen(pipefds[1][0], "r"); /* is stderr redirected to /dev/null? */ if (null_stderr) { /* close the pipe and return NULL as filehandle */ close(pipefds[2][0]); *fp_err = NULL; } else { /* return filehandle for stderr */ *fp_err = fdopen(pipefds[2][0], "r"); } if (sge_has_admin_user()) { sge_switch2admin_user(); } DRETURN(pid); }
/*ARGSUSED*/ int main (int argc, char **argv) { #ifndef USE_PAM const char *env; #endif /* !USE_PAM */ char **envp = environ; TERMIO termio; int err = 0; #ifdef USE_TERMIO ioctl (0, TCGETA, &termio); termio.c_iflag |= (ICRNL | IXON); termio.c_oflag |= (OPOST | ONLCR); termio.c_cflag |= (CREAD); termio.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK); ioctl (0, TCSETAF, &termio); #endif #ifdef USE_TERMIOS tcgetattr (0, &termio); termio.c_iflag |= (ICRNL | IXON); termio.c_oflag |= (CREAD); termio.c_lflag |= (ECHO | ECHOE | ECHOK | ICANON | ISIG); tcsetattr (0, TCSANOW, &termio); #endif Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); #ifdef USE_SYSLOG OPENLOG ("sulogin"); #endif initenv (); if (argc > 1) { close (0); close (1); close (2); if (open (argv[1], O_RDWR) >= 0) { dup (0); dup (0); } else { #ifdef USE_SYSLOG SYSLOG (LOG_WARN, "cannot open %s\n", argv[1]); closelog (); #endif exit (1); } } if (access (PASSWD_FILE, F_OK) == -1) { /* must be a password file! */ (void) puts (_("No password file")); #ifdef USE_SYSLOG SYSLOG (LOG_WARN, "No password file\n"); closelog (); #endif exit (1); } #if !defined(DEBUG) && defined(SULOGIN_ONLY_INIT) if (getppid () != 1) { /* parent must be INIT */ #ifdef USE_SYSLOG SYSLOG (LOG_WARN, "Pid == %d, not 1\n", getppid ()); closelog (); #endif exit (1); } #endif if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) { #ifdef USE_SYSLOG closelog (); #endif exit (1); /* must be a terminal */ } /* If we were init, we need to start a new session */ if (getppid() == 1) { setsid(); if (ioctl(0, TIOCSCTTY, 1) != 0) { (void) fputs (_("TIOCSCTTY failed"), stderr); } } while (NULL != *envp) { /* add inherited environment, */ addenv (*envp, NULL); /* some variables change later */ envp++; } #ifndef USE_PAM env = getdef_str ("ENV_TZ"); if (NULL != env) { addenv (('/' == *env) ? tz (env) : env, NULL); } env = getdef_str ("ENV_HZ"); if (NULL != env) { addenv (env, NULL); /* set the default $HZ, if one */ } #endif /* !USE_PAM */ (void) strcpy (name, "root"); /* KLUDGE!!! */ (void) signal (SIGALRM, catch_signals); /* exit if the timer expires */ (void) alarm (ALARM); /* only wait so long ... */ while (true) { /* repeatedly get login/password pairs */ char *cp; pw_entry (name, &pwent); /* get entry from password file */ if (pwent.pw_name == (char *) 0) { /* * Fail secure */ (void) puts (_("No password entry for 'root'")); #ifdef USE_SYSLOG SYSLOG (LOG_WARN, "No password entry for 'root'\n"); closelog (); #endif exit (1); } /* * Here we prompt for the root password, or if no password * is given we just exit. */ /* get a password for root */ cp = getpass (_( "\n" "Type control-d to proceed with normal startup,\n" "(or give root password for system maintenance):")); /* * XXX - can't enter single user mode if root password is * empty. I think this doesn't happen very often :-). But * it will work with standard getpass() (no NULL on EOF). * --marekm */ if ((NULL == cp) || ('\0' == *cp)) { #ifdef USE_SYSLOG SYSLOG (LOG_INFO, "Normal startup\n"); closelog (); #endif (void) puts (""); #ifdef TELINIT execl (PATH_TELINIT, "telinit", RUNLEVEL, (char *) 0); #endif exit (0); } else { STRFCPY (pass, cp); strzero (cp); } if (valid (pass, &pwent)) { /* check encrypted passwords ... */ break; /* ... encrypted passwords matched */ } #ifdef USE_SYSLOG SYSLOG (LOG_WARN, "Incorrect root password\n"); #endif sleep (2); (void) puts (_("Login incorrect")); } strzero (pass); (void) alarm (0); (void) signal (SIGALRM, SIG_DFL); environ = newenvp; /* make new environment active */ (void) puts (_("Entering System Maintenance Mode")); #ifdef USE_SYSLOG SYSLOG (LOG_INFO, "System Maintenance Mode\n"); #endif #ifdef USE_SYSLOG closelog (); #endif /* exec the shell finally. */ err = shell (pwent.pw_shell, (char *) 0, environ); return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); }
/* * login - create a new login session for a user * * login is typically called by getty as the second step of a * new user session. getty is responsible for setting the line * characteristics to a reasonable set of values and getting * the name of the user to be logged in. login may also be * called to create a new user session on a pty for a variety * of reasons, such as X servers or network logins. * * the flags which login supports are * * -p - preserve the environment * -r - perform autologin protocol for rlogin * -f - do not perform authentication, user is preauthenticated * -h - the name of the remote host */ int main (int argc, char **argv) { const char *tmptty; char tty[BUFSIZ]; #ifdef RLOGIN char term[128] = ""; #endif /* RLOGIN */ #if defined(HAVE_STRFTIME) && !defined(USE_PAM) char ptime[80]; #endif unsigned int delay; unsigned int retries; bool failed; bool subroot = false; #ifndef USE_PAM bool is_console; #endif int err; const char *cp; char *tmp; char fromhost[512]; struct passwd *pwd = NULL; char **envp = environ; const char *failent_user; /*@null@*/struct utmp *utent; #ifdef USE_PAM int retcode; pid_t child; char *pam_user = NULL; #else struct spwd *spwd = NULL; #endif /* * Some quick initialization. */ sanitize_env (); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); initenv (); amroot = (getuid () == 0); Prog = Basename (argv[0]); if (geteuid() != 0) { fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog); exit (1); } process_flags (argc, argv); if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) { exit (1); /* must be a terminal */ } utent = get_current_utmp (); /* * Be picky if run by normal users (possible if installed setuid * root), but not if run by root. This way it still allows logins * even if your getty is broken, or if something corrupts utmp, * but users must "exec login" which will use the existing utmp * entry (will not overwrite remote hostname). --marekm */ if (!amroot && (NULL == utent)) { (void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\"")); exit (1); } /* NOTE: utent might be NULL afterwards */ tmptty = ttyname (0); if (NULL == tmptty) { tmptty = "UNKNOWN"; } STRFCPY (tty, tmptty); #ifndef USE_PAM is_console = console (tty); #endif if (rflg || hflg) { /* * Add remote hostname to the environment. I think * (not sure) I saw it once on Irix. --marekm */ addenv ("REMOTEHOST", hostname); } if (fflg) { preauth_flag = true; } if (hflg) { reason = PW_RLOGIN; } #ifdef RLOGIN if (rflg) { assert (NULL == username); username = xmalloc (USER_NAME_MAX_LENGTH + 1); username[USER_NAME_MAX_LENGTH] = '\0'; if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) { preauth_flag = true; } else { free (username); username = NULL; } } #endif /* RLOGIN */ OPENLOG ("login"); setup_tty (); #ifndef USE_PAM (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); { /* * Use the ULIMIT in the login.defs file, and if * there isn't one, use the default value. The * user may have one for themselves, but otherwise, * just take what you get. */ long limit = getdef_long ("ULIMIT", -1L); if (limit != -1) { set_filesize_limit (limit); } } #endif /* * The entire environment will be preserved if the -p flag * is used. */ if (pflg) { while (NULL != *envp) { /* add inherited environment, */ addenv (*envp, NULL); /* some variables change later */ envp++; } } #ifdef RLOGIN if (term[0] != '\0') { addenv ("TERM", term); } else #endif /* RLOGIN */ { /* preserve TERM from getty */ if (!pflg) { tmp = getenv ("TERM"); if (NULL != tmp) { addenv ("TERM", tmp); } } } init_env (); if (optind < argc) { /* now set command line variables */ set_env (argc - optind, &argv[optind]); } if (rflg || hflg) { cp = hostname; #ifdef HAVE_STRUCT_UTMP_UT_HOST } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) { cp = utent->ut_host; #endif /* HAVE_STRUCT_UTMP_UT_HOST */ } else { cp = ""; } if ('\0' != *cp) { snprintf (fromhost, sizeof fromhost, " on '%.100s' from '%.200s'", tty, cp); } else { snprintf (fromhost, sizeof fromhost, " on '%.100s'", tty); } top: /* only allow ALARM sec. for login */ (void) signal (SIGALRM, alarm_handler); timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM); if (timeout > 0) { (void) alarm (timeout); } environ = newenvp; /* make new environment active */ delay = getdef_unum ("FAIL_DELAY", 1); retries = getdef_unum ("LOGIN_RETRIES", RETRIES); #ifdef USE_PAM retcode = pam_start ("login", username, &conv, &pamh); if (retcode != PAM_SUCCESS) { fprintf (stderr, _("login: PAM Failure, aborting: %s\n"), pam_strerror (pamh, retcode)); SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s", pam_strerror (pamh, retcode))); exit (99); } /* * hostname & tty are either set to NULL or their correct values, * depending on how much we know. We also set PAM's fail delay to * ours. * * PAM_RHOST and PAM_TTY are used for authentication, only use * information coming from login or from the caller (e.g. no utmp) */ retcode = pam_set_item (pamh, PAM_RHOST, hostname); PAM_FAIL_CHECK; retcode = pam_set_item (pamh, PAM_TTY, tty); PAM_FAIL_CHECK; #ifdef HAS_PAM_FAIL_DELAY retcode = pam_fail_delay (pamh, 1000000 * delay); PAM_FAIL_CHECK; #endif /* if fflg, then the user has already been authenticated */ if (!fflg) { unsigned int failcount = 0; char hostn[256]; char loginprompt[256]; /* That's one hell of a prompt :) */ /* Make the login prompt look like we want it */ if (gethostname (hostn, sizeof (hostn)) == 0) { snprintf (loginprompt, sizeof (loginprompt), _("%s login: "******"login: "******"TOO MANY LOGIN TRIES (%u)%s FOR '%s'", failcount, fromhost, failent_user)); fprintf(stderr, _("Maximum number of tries exceeded (%u)\n"), failcount); PAM_END; exit(0); } else if (retcode == PAM_ABORT) { /* Serious problems, quit now */ (void) fputs (_("login: abort requested by PAM\n"), stderr); SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()")); PAM_END; exit(99); } else if (retcode != PAM_SUCCESS) { SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s", failcount, fromhost, failent_user, pam_strerror (pamh, retcode))); failed = true; } if (!failed) { break; } #ifdef WITH_AUDIT audit_fd = audit_open (); audit_log_acct_message (audit_fd, AUDIT_USER_LOGIN, NULL, /* Prog. name */ "login", failent_user, AUDIT_NO_ID, hostname, NULL, /* addr */ tty, 0); /* result */ close (audit_fd); #endif /* WITH_AUDIT */ (void) puts (""); (void) puts (_("Login incorrect")); if (failcount >= retries) { SYSLOG ((LOG_NOTICE, "TOO MANY LOGIN TRIES (%u)%s FOR '%s'", failcount, fromhost, failent_user)); fprintf(stderr, _("Maximum number of tries exceeded (%u)\n"), failcount); PAM_END; exit(0); } /* * Let's give it another go around. * Even if a username was given on the command * line, prompt again for the username. */ retcode = pam_set_item (pamh, PAM_USER, NULL); PAM_FAIL_CHECK; } /* We don't get here unless they were authenticated above */ (void) alarm (0); } /* Check the account validity */ retcode = pam_acct_mgmt (pamh, 0); if (retcode == PAM_NEW_AUTHTOK_REQD) { retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } PAM_FAIL_CHECK; /* Open the PAM session */ get_pam_user (&pam_user); retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0); PAM_FAIL_CHECK; /* Grab the user information out of the password file for future usage * First get the username that we are actually using, though. * * From now on, we will discard changes of the user (PAM_USER) by * PAM APIs. */ get_pam_user (&pam_user); if (NULL != username) { free (username); } username = pam_user; failent_user = get_failent_user (username); pwd = xgetpwnam (username); if (NULL == pwd) { SYSLOG ((LOG_ERR, "cannot find user %s", failent_user)); exit (1); } /* This set up the process credential (group) and initialize the * supplementary group access list. * This has to be done before pam_setcred */ if (setup_groups (pwd) != 0) { exit (1); } retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED); PAM_FAIL_CHECK; /* NOTE: If pam_setcred changes PAM_USER, this will not be taken * into account. */ #else /* ! USE_PAM */ while (true) { /* repeatedly get login/password pairs */ /* user_passwd is always a pointer to this constant string * or a passwd or shadow password that will be memzero by * pw_free / spw_free. * Do not free() user_passwd. */ const char *user_passwd = "!"; /* Do some cleanup to avoid keeping entries we do not need * anymore. */ if (NULL != pwd) { pw_free (pwd); pwd = NULL; } if (NULL != spwd) { spw_free (spwd); spwd = NULL; } failed = false; /* haven't failed authentication yet */ if (NULL == username) { /* need to get a login id */ if (subroot) { closelog (); exit (1); } preauth_flag = false; username = xmalloc (USER_NAME_MAX_LENGTH + 1); username[USER_NAME_MAX_LENGTH] = '\0'; login_prompt (_("\n%s login: "******"!", * the account is locked and the user cannot * login, even if they have been * "pre-authenticated." */ if ( ('!' == user_passwd[0]) || ('*' == user_passwd[0])) { failed = true; } } if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) { spwd = xgetspnam (username); if (NULL != spwd) { user_passwd = spwd->sp_pwdp; } else { /* The user exists in passwd, but not in * shadow. SHADOW_PASSWD_STRING indicates * that the password shall be in shadow. */ SYSLOG ((LOG_WARN, "no shadow password for '%s'%s", username, fromhost)); } } /* * The -r and -f flags provide a name which has already * been authenticated by some server. */ if (preauth_flag) { goto auth_ok; } if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) { goto auth_ok; } SYSLOG ((LOG_WARN, "invalid password for '%s' %s", failent_user, fromhost)); failed = true; auth_ok: /* * This is the point where all authenticated users wind up. * If you reach this far, your password has been * authenticated and so on. */ if ( !failed && (NULL != pwd) && (0 == pwd->pw_uid) && !is_console) { SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost)); failed = true; } if ( !failed && !login_access (username, ('\0' != *hostname) ? hostname : tty)) { SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s", username, fromhost)); failed = true; } if ( (NULL != pwd) && getdef_bool ("FAILLOG_ENAB") && !failcheck (pwd->pw_uid, &faillog, failed)) { SYSLOG ((LOG_CRIT, "exceeded failure limit for '%s' %s", username, fromhost)); failed = true; } if (!failed) { break; } /* don't log non-existent users */ if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) { failure (pwd->pw_uid, tty, &faillog); } if (getdef_str ("FTMP_FILE") != NULL) { #ifdef USE_UTMPX struct utmpx *failent = prepare_utmpx (failent_user, tty, /* FIXME: or fromhost? */hostname, utent); #else /* !USE_UTMPX */ struct utmp *failent = prepare_utmp (failent_user, tty, hostname, utent); #endif /* !USE_UTMPX */ failtmp (failent_user, failent); free (failent); } retries--; if (retries <= 0) { SYSLOG ((LOG_CRIT, "REPEATED login failures%s", fromhost)); } /* * If this was a passwordless account and we get here, login * was denied (securetty, faillog, etc.). There was no * password prompt, so do it now (will always fail - the bad * guys won't see that the passwordless account exists at * all). --marekm */ if (user_passwd[0] == '\0') { pw_auth ("!", username, reason, (char *) 0); } /* * Authentication of this user failed. * The username must be confirmed in the next try. */ free (username); username = NULL; /* * Wait a while (a la SVR4 /usr/bin/login) before attempting * to login the user again. If the earlier alarm occurs * before the sleep() below completes, login will exit. */ if (delay > 0) { (void) sleep (delay); } (void) puts (_("Login incorrect")); /* allow only one attempt with -r or -f */ if (rflg || fflg || (retries <= 0)) { closelog (); exit (1); } } /* while (true) */ #endif /* ! USE_PAM */ assert (NULL != username); assert (NULL != pwd); (void) alarm (0); /* turn off alarm clock */ #ifndef USE_PAM /* PAM does this */ /* * porttime checks moved here, after the user has been * authenticated. now prints a message, as suggested * by Ivan Nejgebauer <*****@*****.**>. --marekm */ if ( getdef_bool ("PORTTIME_CHECKS_ENAB") && !isttytime (username, tty, time ((time_t *) 0))) { SYSLOG ((LOG_WARN, "invalid login time for '%s'%s", username, fromhost)); closelog (); bad_time_notify (); exit (1); } check_nologin (pwd->pw_uid == 0); #endif if (getenv ("IFS")) { /* don't export user IFS ... */ addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */ } if (pwd->pw_shell[0] == '*') { /* subsystem root */ pwd->pw_shell++; /* skip the '*' */ subsystem (pwd); /* figure out what to execute */ subroot = true; /* say I was here again */ endpwent (); /* close all of the file which were */ endgrent (); /* open in the original rooted file */ endspent (); /* system. they will be re-opened */ #ifdef SHADOWGRP endsgent (); /* in the new rooted file system */ #endif goto top; /* go do all this all over again */ } #ifdef WITH_AUDIT audit_fd = audit_open (); audit_log_acct_message (audit_fd, AUDIT_USER_LOGIN, NULL, /* Prog. name */ "login", username, AUDIT_NO_ID, hostname, NULL, /* addr */ tty, 1); /* result */ close (audit_fd); #endif /* WITH_AUDIT */ #ifndef USE_PAM /* pam_lastlog handles this */ if (getdef_bool ("LASTLOG_ENAB")) { /* give last login and log this one */ dolastlog (&ll, pwd, tty, hostname); } #endif #ifndef USE_PAM /* PAM handles this as well */ /* * Have to do this while we still have root privileges, otherwise we * don't have access to /etc/shadow. */ if (NULL != spwd) { /* check for age of password */ if (expire (pwd, spwd)) { /* The user updated her password, get the new * entries. * Use the x variants because we need to keep the * entry for a long time, and there might be other * getxxyy in between. */ pw_free (pwd); pwd = xgetpwnam (username); if (NULL == pwd) { SYSLOG ((LOG_ERR, "cannot find user %s after update of expired password", username)); exit (1); } spw_free (spwd); spwd = xgetspnam (username); } } setup_limits (pwd); /* nice, ulimit etc. */ #endif /* ! USE_PAM */ chown_tty (pwd); #ifdef USE_PAM /* * We must fork before setuid() because we need to call * pam_close_session() as root. */ (void) signal (SIGINT, SIG_IGN); child = fork (); if (child < 0) { /* error in fork() */ fprintf (stderr, _("%s: failure forking: %s"), Prog, strerror (errno)); PAM_END; exit (0); } else if (child != 0) { /* * parent - wait for child to finish, then cleanup * session */ wait (NULL); PAM_END; exit (0); } /* child */ #endif /* If we were init, we need to start a new session */ if (getppid() == 1) { setsid(); if (ioctl(0, TIOCSCTTY, 1) != 0) { fprintf (stderr, _("TIOCSCTTY failed on %s"), tty); } } /* * The utmp entry needs to be updated to indicate the new status * of the session, the new PID and SID. */ update_utmp (username, tty, hostname, utent); /* The pwd and spwd entries for the user have been copied. * * Close all the files so that unauthorized access won't occur. */ endpwent (); /* stop access to password file */ endgrent (); /* stop access to group file */ endspent (); /* stop access to shadow passwd file */ #ifdef SHADOWGRP endsgent (); /* stop access to shadow group file */ #endif /* Drop root privileges */ #ifndef USE_PAM if (setup_uid_gid (pwd, is_console)) #else /* The group privileges were already dropped. * See setup_groups() above. */ if (change_uid (pwd)) #endif { exit (1); } setup_env (pwd); /* set env vars, cd to the home dir */ #ifdef USE_PAM { const char *const *env; env = (const char *const *) pam_getenvlist (pamh); while ((NULL != env) && (NULL != *env)) { addenv (*env, NULL); env++; } } #endif (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); if (!hushed (username)) { addenv ("HUSHLOGIN=FALSE", NULL); /* * pam_unix, pam_mail and pam_lastlog should take care of * this */ #ifndef USE_PAM motd (); /* print the message of the day */ if ( getdef_bool ("FAILLOG_ENAB") && (0 != faillog.fail_cnt)) { failprint (&faillog); /* Reset the lockout times if logged in */ if ( (0 != faillog.fail_max) && (faillog.fail_cnt >= faillog.fail_max)) { (void) puts (_("Warning: login re-enabled after temporary lockout.")); SYSLOG ((LOG_WARN, "login '%s' re-enabled after temporary lockout (%d failures)", username, (int) faillog.fail_cnt)); } } if ( getdef_bool ("LASTLOG_ENAB") && (ll.ll_time != 0)) { time_t ll_time = ll.ll_time; #ifdef HAVE_STRFTIME (void) strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", localtime (&ll_time)); printf (_("Last login: %s on %s"), ptime, ll.ll_line); #else printf (_("Last login: %.19s on %s"), ctime (&ll_time), ll.ll_line); #endif #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */ if ('\0' != ll.ll_host[0]) { printf (_(" from %.*s"), (int) sizeof ll.ll_host, ll.ll_host); } #endif printf (".\n"); } agecheck (spwd); mailcheck (); /* report on the status of mail */ #endif /* !USE_PAM */ } else { addenv ("HUSHLOGIN=TRUE", NULL); } ttytype (tty); (void) signal (SIGQUIT, SIG_DFL); /* default quit signal */ (void) signal (SIGTERM, SIG_DFL); /* default terminate signal */ (void) signal (SIGALRM, SIG_DFL); /* default alarm signal */ (void) signal (SIGHUP, SIG_DFL); /* added this. --marekm */ (void) signal (SIGINT, SIG_DFL); /* default interrupt signal */ if (0 == pwd->pw_uid) { SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost)); } else if (getdef_bool ("LOG_OK_LOGINS")) { SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost)); } closelog (); tmp = getdef_str ("FAKE_SHELL"); if (NULL != tmp) { err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */ } else { /* exec the shell finally */ err = shell (pwd->pw_shell, (char *) 0, newenvp); } return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); }
static void prepare_environment(const struct conn *c, const char *prog, struct env_block *blk) { const struct headers *h = &c->ch; const char *s; size_t len; blk->len = blk->nvars = 0; /* Prepare the environment block */ addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1"); addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1"); addenv(blk, "%s", "REDIRECT_STATUS=200"); /* PHP */ addenv(blk, "SERVER_PORT=%d", c->loc_port); addenv(blk, "SERVER_NAME=%s", c->ctx->auth_realm); addenv(blk, "SERVER_ROOT=%s", c->ctx->document_root); addenv(blk, "DOCUMENT_ROOT=%s", c->ctx->document_root); addenv(blk, "REQUEST_METHOD=%s", known_http_methods[c->method].ptr); addenv(blk, "REMOTE_ADDR=%s", inet_ntoa(c->sa.u.sin.sin_addr)); addenv(blk, "REMOTE_PORT=%hu", ntohs(c->sa.u.sin.sin_port)); addenv(blk, "REQUEST_URI=%s", c->uri); addenv(blk, "SCRIPT_NAME=%s", prog + strlen(c->ctx->document_root)); addenv(blk, "SCRIPT_FILENAME=%s", prog); /* PHP */ addenv(blk, "PATH_TRANSLATED=%s", prog); if (h->ct.v_vec.len > 0) addenv(blk, "CONTENT_TYPE=%.*s", h->ct.v_vec.len, h->ct.v_vec.ptr); if (c->query != NULL) addenv(blk, "QUERY_STRING=%s", c->query); if (c->path_info != NULL) addenv(blk, "PATH_INFO=/%s", c->path_info); if (h->cl.v_big_int > 0) addenv(blk, "CONTENT_LENGTH=%lu", h->cl.v_big_int); if ((s = getenv("PATH")) != NULL) addenv(blk, "PATH=%s", s); #ifdef _WIN32 if ((s = getenv("COMSPEC")) != NULL) addenv(blk, "COMSPEC=%s", s); if ((s = getenv("SYSTEMROOT")) != NULL) addenv(blk, "SYSTEMROOT=%s", s); #else if ((s = getenv("LD_LIBRARY_PATH")) != NULL) addenv(blk, "LD_LIBRARY_PATH=%s", s); #endif /* _WIN32 */ if ((s = getenv("PERLLIB")) != NULL) addenv(blk, "PERLLIB=%s", s); if (h->user.v_vec.len > 0) { addenv(blk, "REMOTE_USER=%.*s", h->user.v_vec.len, h->user.v_vec.ptr); addenv(blk, "%s", "AUTH_TYPE=Digest"); } /* Add user-specified variables */ s = c->ctx->cgi_vars; FOR_EACH_WORD_IN_LIST(s, len) addenv(blk, "%.*s", len, s); /* Add all headers as HTTP_* variables */ add_http_headers_to_env(blk, c->headers, c->rem.headers_len - (c->headers - c->request)); blk->vars[blk->nvars++] = NULL; blk->buf[blk->len++] = '\0'; assert(blk->nvars < CGI_ENV_VARS); assert(blk->len > 0); assert(blk->len < (int) sizeof(blk->buf)); /* Debug stuff to view passed environment */ DBG(("%s: %d vars, %d env size", prog, blk->nvars, blk->len)); { int i; for (i = 0 ; i < blk->nvars; i++) DBG(("[%s]", blk->vars[i] ? blk->vars[i] : "null")); } }
/*VARARGS1*/ int exec(int type, ...) { va_list args; int i; int procuid; int procgid; int ret; int fr_flg; char *cp; char *infile; char *outfile; char *errfile; char *sep; char **listp; char **file_list; char *printerName; char *printerNameToShow; static char nameBuf[100]; char *clean_title; PSTATUS *printer; RSTATUS *request; FSTATUS *form; EXEC *ep; PWSTATUS *pwheel; time_t now; struct passwd *pwp; #ifdef LP_USE_PAPI_ATTR struct stat tmpBuf; char tmpName[BUFSIZ]; char *path = NULL; #endif char *av[ARG_MAX]; char **envp = NULL; int ac = 0; char *mail_zonename = NULL; char *slabel = NULL; syslog(LOG_DEBUG, "exec(%s)", _exec_name(type)); memset(av, 0, sizeof (*av)); va_start (args, type); switch (type) { case EX_INTERF: printer = va_arg(args, PSTATUS *); request = printer->request; ep = printer->exec; break; case EX_FAULT_MESSAGE: printer = va_arg(args, PSTATUS *); request = va_arg(args, RSTATUS *); if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) { return(0); } ep = printer->fault_exec; printerName = (printer->printer && printer->printer->name ? printer->printer->name : "??"); snprintf(nameBuf, sizeof (nameBuf), "%s (on %s)\n", printerName, Local_System); printerNameToShow = nameBuf; (void) time(&now); (void) strftime(time_buf, sizeof (time_buf), NULL, localtime(&now)); break; case EX_SLOWF: request = va_arg(args, RSTATUS *); ep = request->exec; break; case EX_NOTIFY: request = va_arg(args, RSTATUS *); if (request->request->actions & ACT_NOTIFY) { errno = EINVAL; return (-1); } ep = request->exec; break; case EX_ALERT: printer = va_arg(args, PSTATUS *); if (!(printer->printer->fault_alert.shcmd)) { errno = EINVAL; return(-1); } ep = printer->alert->exec; break; case EX_PALERT: pwheel = va_arg(args, PWSTATUS *); ep = pwheel->alert->exec; break; case EX_FORM_MESSAGE: (void) time(&now); (void) strftime(time_buf, sizeof (time_buf), NULL, localtime(&now)); /*FALLTHRU*/ case EX_FALERT: form = va_arg(args, FSTATUS *); ep = form->alert->exec; break; default: errno = EINVAL; return(-1); } va_end (args); if (!ep || (ep->pid > 0)) { errno = EBUSY; return(-1); } ep->flags = 0; key = ep->key = getkey(); switch ((ep->pid = Fork1(ep))) { case -1: relock (); return(-1); case 0: /* * We want to be able to tell our parent how we died. */ lp_alloc_fail_handler = child_mallocfail; break; default: switch(type) { case EX_INTERF: request->request->outcome |= RS_PRINTING; break; case EX_NOTIFY: request->request->outcome |= RS_NOTIFYING; break; case EX_SLOWF: request->request->outcome |= RS_FILTERING; request->request->outcome &= ~RS_REFILTER; break; } return(0); } for (i = 0; i < NSIG; i++) (void)signal (i, SIG_DFL); (void)signal (SIGALRM, SIG_IGN); (void)signal (SIGTERM, sigtrap); closelog(); for (i = 0; i < OpenMax; i++) if (i != ChildMd->writefd) Close (i); openlog("lpsched", LOG_PID|LOG_NDELAY|LOG_NOWAIT, LOG_LPR); setpgrp(); /* Set a default path */ addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin"); /* copy locale related variables */ addenv (&envp, "TZ", getenv("TZ")); addenv (&envp, "LANG", getenv("LANG")); addenv (&envp, "LC_ALL", getenv("LC_ALL")); addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE")); addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE")); addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES")); addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY")); addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC")); addenv (&envp, "LC_TIME", getenv("LC_TIME")); sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key); addenv (&envp, "SPOOLER_KEY", cp); #if defined(DEBUG) addenv (&envp, "LPDEBUG", (debug? "1" : "0")); #endif /* * Open the standard input, standard output, and standard error. */ switch (type) { case EX_SLOWF: case EX_INTERF: /* * stdin: /dev/null * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF) * stderr: req# */ infile = 0; outfile = 0; errfile = makereqerr(request); break; case EX_NOTIFY: /* * stdin: req# * stdout: /dev/null * stderr: /dev/null */ infile = makereqerr(request); outfile = 0; errfile = 0; break; case EX_ALERT: case EX_FALERT: case EX_PALERT: case EX_FAULT_MESSAGE: case EX_FORM_MESSAGE: /* * stdin: /dev/null * stdout: /dev/null * stderr: /dev/null */ infile = 0; outfile = 0; errfile = 0; break; } if (infile) { if (Open(infile, O_RDONLY) == -1) Done (EXEC_EXIT_NOPEN, errno); } else { if (Open("/dev/null", O_RDONLY) == -1) Done (EXEC_EXIT_NOPEN, errno); } if (outfile) { if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1) Done (EXEC_EXIT_NOPEN, errno); } else { /* * If EX_INTERF, this is still needed to cause the * standard error channel to be #2. */ if (Open("/dev/null", O_WRONLY) == -1) Done (EXEC_EXIT_NOPEN, errno); } if (errfile) { if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1) Done (EXEC_EXIT_NOPEN, errno); } else { if (Open("/dev/null", O_WRONLY) == -1) Done (EXEC_EXIT_NOPEN, errno); } switch (type) { case EX_INTERF: /* * Opening a ``port'' can be dangerous to our health: * * - Hangups can occur if the line is dropped. * - The printer may send an interrupt. * - A FIFO may be closed, generating SIGPIPE. * * We catch these so we can complain nicely. */ trap_fault_signals (); (void)Close (1); if (strchr (request->request->user, '@')) { procuid = Lp_Uid; procgid = Lp_Gid; } else { procuid = request->secure->uid; procgid = request->secure->gid; } if (printer->printer->dial_info) { ret = open_dialup(request->printer_type, printer->printer); if (ret == 0) do_undial = 1; } else { ret = open_direct(request->printer_type, printer->printer); do_undial = 0; /* this is a URI */ if (is_printer_uri(printer->printer->device) == 0) addenv(&envp, "DEVICE_URI", printer->printer->device); } addenv(&envp, "DEVICE_URI", printer->printer->device); if (ret != 0) Done (ret, errno); if (!(request->request->outcome & RS_FILTERED)) file_list = request->request->file_list; else { register int count = 0; register char * num = BIGGEST_REQID_S; register char * prefix; prefix = makestr( Lp_Temp, "/F", getreqno(request->secure->req_id), "-", (char *)0 ); file_list = (char **)Malloc( (lenlist(request->request->file_list) + 1) * sizeof(char *) ); for ( listp = request->request->file_list; *listp; listp++ ) { sprintf (num, "%d", count + 1); file_list[count] = makestr( prefix, num, (char *)0 ); count++; } file_list[count] = 0; } #ifdef LP_USE_PAPI_ATTR /* * Check if the PAPI job attribute file exists, if it does * pass the file's pathname to the printer interface script * in an environment variable. This file is created when * print jobs are submitted via the PAPI interface. */ snprintf(tmpName, sizeof (tmpName), "%s-%s", getreqno(request->secure->req_id), LP_PAPIATTRNAME); path = makepath(Lp_Temp, tmpName, (char *)0); if ((path != NULL) && (stat(path, &tmpBuf) == 0)) { /* * IPP job attribute file exists for this job so * set the environment variable */ addenv(&envp, "ATTRPATH", path); } Free(path); /* * now set environment variable for the printer's PostScript * Printer Description (PPD) file, this is used by the filter * when forming the print data for this printer. */ if ((request->printer != NULL) && (request->printer->printer != NULL) && (request->printer->printer->name != NULL)) { snprintf(tmpName, sizeof (tmpName), "%s.ppd", request->printer->printer->name); path = makepath(ETCDIR, "ppd", tmpName, (char *)0); if ((path != NULL) && (stat(path, &tmpBuf) == 0)) { addenv(&envp, "PPD", path); } Free(path); } #endif if (request->printer_type) addenv(&envp, "TERM", request->printer_type); if (!(printer->printer->daisy)) { register char * chset = 0; register char * csp; if ( request->form && request->form->form->chset && request->form->form->mandatory && !STREQU(NAME_ANY, request->form->form->chset) ) chset = request->form->form->chset; else if ( request->request->charset && !STREQU(NAME_ANY, request->request->charset) ) chset = request->request->charset; if (chset) { csp = search_cslist( chset, printer->printer->char_sets ); /* * The "strtok()" below wrecks the string * for future use, but this is a child * process where it won't be needed again. */ addenv (&envp, "CHARSET", (csp? strtok(csp, "=") : chset) ); } } if (request->fast) addenv(&envp, "FILTER", request->fast); /* * Add the sensitivity label to the environment for * banner page and header/footer processing */ if (is_system_labeled() && request->secure->slabel != NULL) addenv(&envp, "SLABEL", request->secure->slabel); /* * Add the system name to the user name (ala system!user) * unless it is already there. RFS users may have trouble * here, sorry! */ cp = strchr(request->secure->user, '@'); allTraysWithForm(printer, request->form); /* * Fix for 4137389 * Remove double quotes from title string. */ fr_flg = 1; clean_title = strdup(NB(request->request->title)); if (clean_title == NULL) { /* * strdup failed. We're probably hosed * but try setting clean_title * to original title and continuing. */ clean_title = NB(request->request->title); fr_flg = 0; } else if (strcmp(clean_title, "") != 0) { char *ct_p; for (ct_p = clean_title; *ct_p != NULL; ct_p++) { if (*ct_p == '"') *ct_p = ' '; } } av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces, printer->printer->name); av[ac++] = arg_string(TRUSTED, "%s", request->secure->req_id); av[ac++] = arg_string(UNTRUSTED, "%s", request->request->user); av[ac++] = arg_string(TRUSTED, "%s", clean_title); av[ac++] = arg_string(TRUSTED, "%d", request->copies); if (fr_flg) free (clean_title); sep = ""; /* * Do the administrator defined key=value pair options */ argbuf[0] = '\0'; if (printer->printer->options) { char **tmp = printer->printer->options; while(*tmp != NULL) { STRLCAT(argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT(argbuf, *tmp++, sizeof (argbuf)); } } /* * Do the administrator defined ``stty'' stuff before * the user's -o options, to allow the user to override. */ if (printer->printer->stty) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "stty='", sizeof (argbuf)); STRLCAT (argbuf, printer->printer->stty, sizeof (argbuf)); STRLCAT (argbuf, "'", sizeof (argbuf)); } /* * Do all of the user's options except the cpi/lpi/etc. * stuff, which is done separately. */ if (request->request->options) { listp = dashos(request->request->options); while (*listp) { if ( !STRNEQU(*listp, "cpi=", 4) && !STRNEQU(*listp, "lpi=", 4) && !STRNEQU(*listp, "width=", 6) && !STRNEQU(*listp, "length=", 7) ) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, *listp, sizeof (argbuf)); } listp++; } } /* * The "pickfilter()" routine (from "validate()") * stored the cpi/lpi/etc. stuff that should be * used for this request. It chose form over user, * and user over printer. */ if (request->cpi) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "cpi=", sizeof (argbuf)); STRLCAT (argbuf, request->cpi, sizeof (argbuf)); } if (request->lpi) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "lpi=", sizeof (argbuf)); STRLCAT (argbuf, request->lpi, sizeof (argbuf)); } if (request->pwid) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "width=", sizeof (argbuf)); STRLCAT (argbuf, request->pwid, sizeof (argbuf)); } if (request->plen) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "length=", sizeof (argbuf)); STRLCAT (argbuf, request->plen, sizeof (argbuf)); } /* * Do the ``raw'' bit last, to ensure it gets * done. If the user doesn't want this, then he or * she can do the correct thing using -o stty= * and leaving out the -r option. */ if (request->request->actions & ACT_RAW) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "stty=-opost", sizeof (argbuf)); } /* the "options" */ av[ac++] = arg_string(UNTRUSTED, "%s", argbuf); for (listp = file_list; *listp; listp++) av[ac++] = arg_string(TRUSTED, "%s", *listp); (void)chfiles (file_list, procuid, procgid); break; case EX_SLOWF: if (request->slow) addenv(&envp, "FILTER", request->slow); if (strchr (request->request->user, '@')) { procuid = Lp_Uid; procgid = Lp_Gid; } else { procuid = request->secure->uid; procgid = request->secure->gid; } cp = _alloc_files( lenlist(request->request->file_list), getreqno(request->secure->req_id), procuid, procgid); av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter); av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_Temp, cp); for (listp = request->request->file_list; *listp; listp++) av[ac++] = arg_string(TRUSTED, "%s", *listp); (void)chfiles (request->request->file_list, procuid, procgid); #ifdef LP_USE_PAPI_ATTR /* * Check if the PAPI job attribute file exists, if it does * pass the file's pathname to the slow-filters in an * environment variable. Note: this file is created when * print jobs are submitted via the PAPI interface. */ snprintf(tmpName, sizeof (tmpName), "%s-%s", getreqno(request->secure->req_id), LP_PAPIATTRNAME); path = makepath(Lp_Temp, tmpName, (char *)0); if ((path != NULL) && (stat(path, &tmpBuf) == 0)) { /* * IPP job attribute file exists for this job so * set the environment variable */ addenv(&envp, "ATTRPATH", path); } Free(path); /* * now set environment variable for the printer's PostScript * Printer Description (PPD) file, this is used by the filter * when forming the print data for this printer. */ if ((request->printer != NULL) && (request->printer->printer != NULL) && (request->printer->printer->name != NULL)) { snprintf(tmpName, sizeof (tmpName), "%s.ppd", request->printer->printer->name); path = makepath(ETCDIR, "ppd", tmpName, (char *)0); if ((path != NULL) && (stat(path, &tmpBuf) == 0)) { addenv(&envp, "PPD", path); } Free(path); } #endif break; case EX_ALERT: procuid = Lp_Uid; procgid = Lp_Gid; (void)Chown (printer->alert->msgfile, procuid, procgid); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers, printer->printer->name, ALERTSHFILE); av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); break; case EX_PALERT: procuid = Lp_Uid; procgid = Lp_Gid; (void)Chown (pwheel->alert->msgfile, procuid, procgid); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels, pwheel->pwheel->name, ALERTSHFILE); av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); break; case EX_FALERT: procuid = Lp_Uid; procgid = Lp_Gid; (void)Chown (form->alert->msgfile, procuid, procgid); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms, form->form->name, ALERTSHFILE); av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); break; case EX_FORM_MESSAGE: procuid = Lp_Uid; procgid = Lp_Gid; av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults); av[ac++] = arg_string(TRUSTED, "%s", form->form->name); av[ac++] = arg_string(TRUSTED, "%s", time_buf); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms, form->form->name, FORMMESSAGEFILE); break; case EX_FAULT_MESSAGE: procuid = Lp_Uid; procgid = Lp_Gid; av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults); av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow); av[ac++] = arg_string(TRUSTED, "%s", time_buf); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers, printerName, FAULTMESSAGEFILE); break; case EX_NOTIFY: if (request->request->alert) { if (strchr(request->request->user, '@')) { procuid = Lp_Uid; procgid = Lp_Gid; } else { procuid = request->secure->uid; procgid = request->secure->gid; } av[ac++] = arg_string(TRUSTED, "%s", request->request->alert); } else { char *user = strdup(request->request->user); clean_string(user); slabel = request->secure->slabel; if (request->request->actions & ACT_WRITE) { av[ac++] = arg_string(TRUSTED, "%s", BINWRITE); snprintf(argbuf, sizeof (argbuf), "%s %s || %s %s", BINWRITE, user, BINMAIL, user ); av[ac++] = arg_string(TRUSTED, "/bin/sh"); av[ac++] = arg_string(TRUSTED, "-c"); av[ac++] = arg_string(TRUSTED, "%s", argbuf); } else if ((getzoneid() == GLOBAL_ZONEID) && is_system_labeled() && (slabel != NULL)) { /* * If in the global zone and the system is * labeled, mail is handled via a local * labeled zone that is the same label as * the request. */ if ((mail_zonename = get_labeled_zonename(slabel)) == (char *)-1) { /* * Cannot find labeled zone, just * return 0. */ return(0); } } if (mail_zonename == NULL) { procuid = Lp_Uid; procgid = Lp_Gid; av[ac++] = arg_string(TRUSTED, "%s", BINMAIL); av[ac++] = arg_string(UNTRUSTED, "%s", user); } else { procuid = getuid(); procgid = getgid(); av[ac++] = arg_string(TRUSTED, "%s", "/usr/sbin/zlogin"); av[ac++] = arg_string(TRUSTED, "%s", mail_zonename); av[ac++] = arg_string(TRUSTED, "%s", BINMAIL); av[ac++] = arg_string(UNTRUSTED, "%s", user); Free(mail_zonename); } free(user); } break; } av[ac++] = NULL; Fork2 (); /* only the child returns */ /* * Correctly set up the supplemental group list * for proper file access (before execl the interface program) */ pwp = getpwuid(procuid); if (pwp == NULL) { note("getpwuid(%d) call failed\n", procuid); } else if (initgroups(pwp->pw_name, procgid) < 0) { note("initgroups() call failed %d\n", errno); } setgid (procgid); setuid (procuid); /* * The shell doesn't allow the "trap" builtin to set a trap * for a signal ignored when the shell is started. Thus, don't * turn off signals in the last child! */ #ifdef DEBUG for (i = 0; av[i] != NULL; i++) note("exec(%s): av[%d] = %s", _exec_name(type), i, av[i]); for (i = 0; envp[i] != NULL; i++) note("exec(%s): envp[%d] = %s", _exec_name(type), i, envp[i]); #endif execvpe(av[0], av, envp); Done (EXEC_EXIT_NEXEC, errno); /*NOTREACHED*/ return (0); }