--- mod_auth_any-1.2.2/src/mod_auth_any.c.fork 2002-07-02 15:40:25.000000000 -0400 +++ mod_auth_any-1.2.2/src/mod_auth_any.c 2003-03-19 12:47:44.000000000 -0500 @@ -170,127 +170,98 @@ module MODULE_VAR_EXPORT auth_any_module; -/* Escape special characters in the input string so that the bash - shell will not interpolate them when the input string is withing - single quotes. - - IN: null-terminated character array containing string to be interpolated - OUT: newly allocate (using malloc) null-terminated character array - containing the input string with the special characters properly - escaped */ -char* bash_single_quote_escape_string(const char *s) { - /* used to count the length of the string and the number of single quotes */ - int str_len, sq_count; - int s_pos, buf_pos; /* copy chars loop counter */ - /* used to hold the final result string */ - char *buf; - - /* Count the single quotes. - LOOP INVARIANT: str_len < (number of chars in string 's') - POSTCONDITION: sq_count == (number of single quotes in string 's') */ - for (str_len = 0, sq_count = 0; s[str_len] != '\0'; str_len++) - if (s[str_len] == '\'') - sq_count++; - - /* Allocate the memory for the final string. - Each ' (one char) will become '\'' (4 chars), so multiply by 4 - and don't forget to add 1 for terminating null. */ - buf = (char*) malloc(sizeof(char) * (str_len + 1 + sq_count * 4)); - - /* Copy the chars of 's' into 'buf', turning each ' into '\'' */ - for (s_pos = 0, buf_pos = 0; s_pos < str_len; s_pos++) { - /* If we see a single quote, then put '\'' into 'buf' and advance - buf_pos 4 positions, else put the next char from 's' into 'buf' - and advance buf_pos 1 position. */ - if(s[s_pos] == '\'') { - buf[buf_pos++] = '\''; - buf[buf_pos++] = '\\'; - buf[buf_pos++] = '\''; - buf[buf_pos++] = '\''; - } else { - buf[buf_pos++] = s[s_pos]; - } - } - /* don't forget the null terminator */ - buf[buf_pos] = '\0'; - - return buf; -} - /* - nb: - - The popen() call to the external validator program is made here. -*/ + * Call the external program auth_pwfile with user and password as its + * arguments. These should have been passed in over a pipe, but it's too + * late to change that now. The called program should print the name of the + * valid user to stdout, or print "Authentication Error" on failure. + */ static char *get_pw(request_rec *r, char *user, const char* password, char *auth_pwfile) { - configfile_t *f; - char* execstr; - char* l; - const char *rpw, *w; - FILE* ext_authprog; - FILE* fp; - char *escaped_password; + char result[256]; + int fd[2], i, length = 0; + pid_t pid; #ifdef __sun static char m_envstr[256]; /* sun's putenv() call is a bunch of bull malarkey */ #endif - - l = (char*) malloc (MAX_STRING_LEN * sizeof(char)); - execstr = (char*) malloc (MAX_STRING_LEN * sizeof(char)); -#ifdef __sun - snprintf (m_envstr, 256, "%s=%s\0", "REMOTE_ADDR", r -> connection -> remote_ip); - putenv (m_envstr); -#else - setenv ("REMOTE_ADDR", r -> connection -> remote_ip, 1); -#endif - - /* escape the password */ - escaped_password = bash_single_quote_escape_string(password); - - /* open the program stream */ - snprintf (execstr, MAX_STRING_LEN, "%s %s \'%s\'", auth_pwfile, user, escaped_password); - - /* free the escaped password before we forget */ - free(escaped_password); + memset (result, '\0', sizeof(result)); - if (!(ext_authprog = popen (execstr, "r"))) { + /* sanity check the auth_pwfile */ + if ((auth_pwfile == NULL) || (auth_pwfile[0] != '/')) { + ap_log_rerror (APLOG_MARK, APLOG_ERR, r, "Invalid program: %s", + auth_pwfile); + return NULL; + } - ap_log_rerror (APLOG_MARK, APLOG_ERR, r, "Could not popen() on program: %s: %s", - auth_pwfile, strerror(errno)); - return NULL; + /* set up our communication pipe */ + if (pipe (fd) == -1) { + /* couldn't create pipe for some reason */ + ap_log_rerror (APLOG_MARK, APLOG_ERR, r, "Error creating pipe: %s", + strerror(errno)); + return NULL; } - /* whew, the popen() has seemingly succeeded, let's write the username passwd stuff*/ - if (feof(ext_authprog) == 0) - fgets (l, MAX_STRING_LEN, ext_authprog); - pclose (ext_authprog); - - if (strncmp(l, "Authentication Error", 19) == 0) /* no authorized */ - return NULL; - /* otherwise, we got a winner :), return user's real name */ - return l; - /* ignore the rest */ - /* - if (!(f = ap_pcfg_openfile(r->pool, auth_pwfile))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, r, - "Could not open password file: %s", auth_pwfile); + /* start our child */ + pid = fork (); + switch (pid) { + case -1: + /* fork failed -- clean up and return */ + close (fd[0]); + close (fd[1]); + ap_log_rerror (APLOG_MARK, APLOG_ERR, r, "Error fork()ing: %s", + strerror (errno)); return NULL; + break; + case 0: +#ifdef __sun + snprintf (m_envstr, sizeof(m_envstr), "%s=%s", "REMOTE_ADDR", + r -> connection -> remote_ip); + putenv (m_envstr); +#else + setenv ("REMOTE_ADDR", r -> connection -> remote_ip, 1); +#endif + /* close open fds */ + i = sysconf (_SC_OPEN_MAX); + while (i >= 0) { + if (i != fd[1]) { + fcntl (i, F_SETFD, FD_CLOEXEC); + } + i--; + } + /* make the write end of the pipe our stdout */ + if (fd[1] != STDOUT_FILENO) { + close (STDOUT_FILENO); + dup2 (fd[1], STDOUT_FILENO); + fcntl (STDOUT_FILENO, F_SETFD, 0); + fcntl (fd[1], F_SETFD, FD_CLOEXEC); + } + execl (auth_pwfile, auth_pwfile, user, password, NULL); + _exit (1); + break; + default: + /* parent: read what the child has to say, if anything */ + close (fd[1]); + do { + i = read (fd[0], result + length, sizeof(result) - length - 1); + if (i != -1) { + length += i; + } + } while ((i != -1) && (i != 0) && (length < (sizeof(result) - 1))); + close (fd[0]); + break; } - - while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { - if ((l[0] == '#') || (!l[0])) - continue; - rpw = l; - w = ap_getword(r->pool, &rpw, ':'); - if (!strcmp(user, w)) { - ap_cfg_closefile(f); - return ap_getword(r->pool, &rpw, ':'); - } + while ((length > 0) && + ((result[length - 1] == '\r') || (result[length - 1] == '\n'))) { + result[--length] = '\0'; } - ap_cfg_closefile(f); - return NULL; - */ + + if ((strlen(result) == 0) || + (strncmp(result, "Authentication Error", 19) == 0)) /* not authorized */ + return NULL; + + /* otherwise, we got a winner :), return user's real name */ + return strdup(result); } static table *groups_for_user(pool *p, char *user, char *grpfile) @@ -351,9 +322,7 @@ conn_rec *c = r->connection; const char *sent_pw; char *real_pw; - char *invalid_pw; int res; - FILE* fp; if ((res = ap_get_basic_auth_pw(r, &sent_pw))) return res; @@ -423,8 +392,6 @@ table *grpstatus; const array_header *reqs_arr = ap_requires(r); require_line *reqs; - FILE* fp; - /* BUG FIX: tadc, 11-Nov-1995. If there is no "requires" directive, * then any user will do.