File mod_nss-bnc863518-reopen_dev_tty.diff of Package apache2-mod_nss

diff -rNU 50 ../mod_nss-1.0.8-o/nss_engine_pphrase.c ./nss_engine_pphrase.c
--- ../mod_nss-1.0.8-o/nss_engine_pphrase.c	2014-07-24 12:23:30.000000000 +0200
+++ ./nss_engine_pphrase.c	2014-07-24 13:54:23.000000000 +0200
@@ -181,199 +181,218 @@
  * that may be done.
  */ 
 static PRBool nss_check_password(unsigned char *cp)
 {
     int len;
     unsigned char *end, ch;
 
     len = strlen((char *)cp);
     if (len < 8) {
             return PR_TRUE;
     }
     end = cp + len;
     while (cp < end) {
         ch = *cp++;
         if (!((ch >= 'A') && (ch <= 'Z')) &&
             !((ch >= 'a') && (ch <= 'z'))) {
             /* pass phrase has at least one non alphabetic in it */
             return PR_TRUE;
         }
     }
     return PR_TRUE;
 }
 
 /*
  * Password callback so the user is not prompted to enter the password
  * after the server starts.
  */
 static char * nss_no_password(PK11SlotInfo *slot, PRBool retry, void *arg)
 {
    return NULL;
 }
 
 /*
  * Password callback to prompt the user for a password. This requires
  * twiddling with the tty. Alternatively, if the file password.conf
  * exists then it may be used to store the token password(s).
  */
 static char *nss_get_password(FILE *input, FILE *output,
                                        PK11SlotInfo *slot,
                                        PRBool (*ok)(unsigned char *),
                                        pphrase_arg_t *parg)
 {
     char *pwdstr = NULL;
     char *token_name = NULL;
     int tmp;
     FILE *pwd_fileptr;
     char *ptr;
     char line[1024];
     unsigned char phrase[200];
     int infd = fileno(input);
+    int tmpfd;
     int isTTY = isatty(infd);
 
     token_name = PK11_GetTokenName(slot);
 
     if (parg->mc->pphrase_dialog_type == SSL_PPTYPE_FILE ||
         parg->mc->pphrase_dialog_type == SSL_PPTYPE_DEFER) {
         /* Try to get the passwords from the password file if it exists.
          * THIS IS UNSAFE and is provided for convenience only. Without this
          * capability the server would have to be started in foreground mode.
          */
         if ((*parg->mc->pphrase_dialog_path != '\0') &&
            ((pwd_fileptr = fopen(parg->mc->pphrase_dialog_path, "r")) != NULL)) {
             while(fgets(line, 1024, pwd_fileptr)) {
                 if (PL_strstr(line, token_name) == line) {
                     tmp = PL_strlen(line) - 1;
                     while((line[tmp] == ' ') || (line[tmp] == '\n'))
                         tmp--;
                     line[tmp+1] = '\0';
                     ptr = PL_strchr(line, ':');
                     if (ptr == NULL) {
                         ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                            "Malformed password entry for token %s. Format should be token:password", token_name);
                         continue;
                     }
                     for(tmp=1; ptr[tmp] == ' '; tmp++) {}
                     pwdstr = strdup(&(ptr[tmp]));
                 }
             }
             fclose(pwd_fileptr);
         } else {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                  "Unable to open password file %s", parg->mc->pphrase_dialog_path);
             nss_die();
         }
     }
 
     /* For SSL_PPTYPE_DEFER we only want to authenticate passwords found
      * in the password file.
      */
     if ((parg->mc->pphrase_dialog_type == SSL_PPTYPE_DEFER) &&
         (pwdstr == NULL)) {
         return NULL;
     }
 
     /* This purposely comes after the file check because that is more
      * authoritative.
      */
     if (parg->mc->nInitCount > 1) {
         char buf[1024];
         apr_status_t rv;
         apr_size_t nBytes = 1024;
         struct sembuf sb;
 
         /* lock the pipe */
         sb.sem_num = 0;
         sb.sem_op = -1;
         sb.sem_flg = SEM_UNDO;
         if (semop(parg->mc->semid, &sb, 1) == -1) {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                 "Unable to reserve semaphore resource");
         }
 
         snprintf(buf, 1024, "RETR\t%s", token_name);
         rv = apr_file_write_full(parg->mc->proc.in, buf, strlen(buf), NULL);
         if (rv != APR_SUCCESS) {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                 "Unable to write to pin store for slot: %s APR err: %d",  PK11_GetTokenName(slot), rv);
             nss_die();
         }
 
         /* The helper just returns a token pw or "", so we don't have much
          * to check for.
          */
         memset(buf, 0, sizeof(buf));
         rv = apr_file_read(parg->mc->proc.out, buf, &nBytes);
         sb.sem_op = 1;
         if (semop(parg->mc->semid, &sb, 1) == -1) {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                 "Unable to free semaphore resource");
             /* perror("semop free resource id"); */
         }
 
         if (rv != APR_SUCCESS) {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                 "Unable to read from pin store for slot: %s APR err: %d",  PK11_GetTokenName(slot), rv);
             nss_die();
         }
 
         /* Just return what we got. If we got this far and we don't have a 
          * PIN then I/O is already shut down, so we can't do anything really
          * clever.
          */
         pwdstr = strdup(buf);
     }
 
     /* If we got a password we're done */ 
     if (pwdstr)
         return pwdstr;
-    
+
+    /* It happens that stdin is not opened with O_RDONLY. Better make sure
+     * it is and re-open /dev/tty.
+     */
+    close(infd); /* is 0 normally. open(2) will return first available. */
+    tmpfd = open("/dev/tty", O_RDONLY);
+    if( tmpfd == -1) {
+	fprintf(output, "Cannot open /dev/tty for reading the passphrase.\n");
+	nss_die();
+    }
+    if(tmpfd != infd) {
+	if( dup2(tmpfd, infd) != infd) {
+	    fprintf(output, "Problem duplicating /dev/tty file descriptor.\n");
+	    close(tmpfd);
+	    nss_die();
+	}
+	close(tmpfd);
+    }
+
     for (;;) {
         /* Prompt for password */
         if (isTTY) {
             if (parg->retryCount > 0) {
                 fprintf(output, "Password incorrect. Please try again.\n");
             }
             fprintf(output, "%s", prompt);
             echoOff(infd);
         }
         fgets((char*) phrase, sizeof(phrase), input);
         if (isTTY) {
             fprintf(output, "\n");
             echoOn(infd);
         }
         /* stomp on newline */ 
         phrase[strlen((char*)phrase)-1] = 0;
 
         /* Validate password */
         if (!(*ok)(phrase)) {
             /* Not weird enough */
             if (!isTTY) return 0;
             fprintf(output, "Password must be at least 8 characters long with one or more\n");
             fprintf(output, "non-alphabetic characters\n");
             continue; 
         }
         if (PK11_IsFIPS() && strlen(phrase) == 0) {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                 "The FIPS security policy requires that a password be set.");
             nss_die();
         } else
             return (char*) PORT_Strdup((char*)phrase);
     }
 }
 
 /*
  * Turn the echoing off on a tty.
  */
 static void echoOff(int fd)
 {
     if (isatty(fd)) {
         struct termios tio;
         tcgetattr(fd, &tio);
         tio.c_lflag &= ~ECHO;
         tcsetattr(fd, TCSAFLUSH, &tio);
     }
 }
 
 /*
  * Turn the echoing on on a tty.
  */
openSUSE Build Service is sponsored by