--- /dev/null
+--- 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.