nss_secutil.c (5445B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* With the exception of GetPasswordString, this file was 6 copied from NSS's cmd/lib/secutil.c hg revision 8f011395145e */ 7 8 #include "nss_secutil.h" 9 10 #include "prprf.h" 11 #ifdef XP_WIN 12 # include <io.h> 13 #else 14 # include <unistd.h> 15 #endif 16 17 #if defined(_WINDOWS) 18 char* quiet_fgets(char* buf, int length, FILE* input) { 19 int c; 20 char* end = buf; 21 22 /* fflush (input); */ 23 memset(buf, 0, length); 24 25 if (!isatty(fileno(input))) { 26 return fgets(buf, length, input); 27 } 28 29 while (1) { 30 # if defined(_WIN32_WCE) 31 c = getchar(); /* gets a character from stdin */ 32 # else 33 c = getch(); /* getch gets a character from the console */ 34 # endif 35 if (c == '\b') { 36 if (end > buf) end--; 37 } 38 39 else if (--length > 0) 40 *end++ = c; 41 42 if (!c || c == '\n' || c == '\r') break; 43 } 44 45 return buf; 46 } 47 #endif 48 49 char* GetPasswordString(void* arg, char* prompt) { 50 FILE* input = stdin; 51 char phrase[200] = {'\0'}; 52 int isInputTerminal = isatty(fileno(stdin)); 53 54 #ifndef _WINDOWS 55 if (isInputTerminal) { 56 static char consoleName[] = { 57 # ifdef XP_UNIX 58 "/dev/tty" 59 # else 60 "CON:" 61 # endif 62 }; 63 64 input = fopen(consoleName, "r"); 65 if (input == NULL) { 66 fprintf(stderr, "Error opening input terminal for read\n"); 67 return NULL; 68 } 69 } 70 #endif 71 72 if (isInputTerminal) { 73 fprintf(stdout, "Please enter your password:\n"); 74 fflush(stdout); 75 } 76 77 if (!QUIET_FGETS(phrase, sizeof(phrase), input)) { 78 fprintf(stderr, "QUIET_FGETS failed\n"); 79 #ifndef _WINDOWS 80 if (isInputTerminal) { 81 fclose(input); 82 } 83 #endif 84 return NULL; 85 } 86 87 if (isInputTerminal) { 88 fprintf(stdout, "\n"); 89 } 90 91 #ifndef _WINDOWS 92 if (isInputTerminal) { 93 fclose(input); 94 } 95 #endif 96 97 /* Strip off the newlines if present */ 98 if (phrase[PORT_Strlen(phrase) - 1] == '\n' || 99 phrase[PORT_Strlen(phrase) - 1] == '\r') { 100 phrase[PORT_Strlen(phrase) - 1] = 0; 101 } 102 return (char*)PORT_Strdup(phrase); 103 } 104 105 char* SECU_FilePasswd(PK11SlotInfo* slot, PRBool retry, void* arg) { 106 char *phrases, *phrase; 107 PRFileDesc* fd; 108 int32_t nb; 109 char* pwFile = arg; 110 int i; 111 const long maxPwdFileSize = 4096; 112 char* tokenName = NULL; 113 int tokenLen = 0; 114 115 if (!pwFile) return 0; 116 117 if (retry) { 118 return 0; /* no good retrying - the files contents will be the same */ 119 } 120 121 phrases = PORT_ZAlloc(maxPwdFileSize); 122 123 if (!phrases) { 124 return 0; /* out of memory */ 125 } 126 127 fd = PR_Open(pwFile, PR_RDONLY, 0); 128 if (!fd) { 129 fprintf(stderr, "No password file \"%s\" exists.\n", pwFile); 130 PORT_Free(phrases); 131 return NULL; 132 } 133 134 nb = PR_Read(fd, phrases, maxPwdFileSize); 135 136 PR_Close(fd); 137 138 if (nb == 0) { 139 fprintf(stderr, "password file contains no data\n"); 140 PORT_Free(phrases); 141 return NULL; 142 } 143 144 if (slot) { 145 tokenName = PK11_GetTokenName(slot); 146 if (tokenName) { 147 tokenLen = PORT_Strlen(tokenName); 148 } 149 } 150 i = 0; 151 do { 152 int startphrase = i; 153 int phraseLen; 154 155 /* handle the Windows EOL case */ 156 while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++; 157 /* terminate passphrase */ 158 if (i < nb) { 159 phrases[i++] = '\0'; 160 } 161 /* clean up any EOL before the start of the next passphrase */ 162 while ((i < nb) && (phrases[i] == '\r' || phrases[i] == '\n')) { 163 phrases[i++] = '\0'; 164 } 165 /* now analyze the current passphrase */ 166 phrase = &phrases[startphrase]; 167 if (!tokenName) break; 168 if (PORT_Strncmp(phrase, tokenName, tokenLen)) continue; 169 phraseLen = PORT_Strlen(phrase); 170 if (phraseLen < (tokenLen + 1)) continue; 171 if (phrase[tokenLen] != ':') continue; 172 phrase = &phrase[tokenLen + 1]; 173 break; 174 175 } while (i < nb); 176 177 phrase = PORT_Strdup((char*)phrase); 178 PORT_Free(phrases); 179 return phrase; 180 } 181 182 char* SECU_GetModulePassword(PK11SlotInfo* slot, PRBool retry, void* arg) { 183 char prompt[255]; 184 secuPWData* pwdata = (secuPWData*)arg; 185 secuPWData pwnull = {PW_NONE, 0}; 186 secuPWData pwxtrn = {PW_EXTERNAL, "external"}; 187 char* pw; 188 189 if (pwdata == NULL) pwdata = &pwnull; 190 191 if (PK11_ProtectedAuthenticationPath(slot)) { 192 pwdata = &pwxtrn; 193 } 194 if (retry && pwdata->source != PW_NONE) { 195 PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n"); 196 return NULL; 197 } 198 199 switch (pwdata->source) { 200 case PW_NONE: 201 sprintf(prompt, 202 "Enter Password or Pin for \"%s\":", PK11_GetTokenName(slot)); 203 return GetPasswordString(NULL, prompt); 204 case PW_FROMFILE: 205 /* Instead of opening and closing the file every time, get the pw 206 * once, then keep it in memory (duh). 207 */ 208 pw = SECU_FilePasswd(slot, retry, pwdata->data); 209 pwdata->source = PW_PLAINTEXT; 210 pwdata->data = strdup(pw); 211 /* it's already been dup'ed */ 212 return pw; 213 case PW_EXTERNAL: 214 sprintf(prompt, 215 "Press Enter, then enter PIN for \"%s\" on external device.\n", 216 PK11_GetTokenName(slot)); 217 pw = GetPasswordString(NULL, prompt); 218 if (pw) { 219 memset(pw, 0, PORT_Strlen(pw)); 220 PORT_Free(pw); 221 } 222 /* Fall Through */ 223 case PW_PLAINTEXT: 224 return strdup(pwdata->data); 225 default: 226 break; 227 } 228 229 PR_fprintf(PR_STDERR, "Password check failed: No password found.\n"); 230 return NULL; 231 }