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 /*
6 ** dbtest.c
7 **
8 ** QA test for cert and key databases, especially to open
9 ** database readonly (NSS_INIT_READONLY) and force initializations
10 ** even if the databases cannot be opened (NSS_INIT_FORCEOPEN)
11 **
12 */
13 #include <stdio.h>
14 #include <string.h>
15
16 #if defined(WIN32)
17 #include "fcntl.h"
18 #include "io.h"
19 #endif
20
21 #include "secutil.h"
22 #include "pk11pub.h"
23
24 #if defined(XP_UNIX)
25 #include <unistd.h>
26 #endif
27
28 #include <nspr.h>
29 #include "prtypes.h"
30 #include "certdb.h"
31 #include "nss.h"
32 #include "../modutil/modutil.h"
33
34 #include "plgetopt.h"
35
36 static char *progName;
37
38 char *dbDir = NULL;
39
40 static char *dbName[] = { "secmod.db", "cert8.db", "key3.db" };
41 static char *dbprefix = "";
42 static char *secmodName = "secmod.db";
43 static char *userPassword = "";
44 PRBool verbose;
45
46 static char *
getPassword(PK11SlotInfo * slot,PRBool retry,void * arg)47 getPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
48 {
49 int *success = (int *)arg;
50
51 if (retry) {
52 *success = 0;
53 return NULL;
54 }
55
56 *success = 1;
57 return PORT_Strdup(userPassword);
58 }
59
60 static void
Usage()61 Usage()
62 {
63 printf("Usage: %s [-r] [-f] [-i] [-d dbdir ] \n",
64 progName);
65 printf("%-20s open database readonly (NSS_INIT_READONLY)\n", "-r");
66 printf("%-20s Continue to force initializations even if the\n", "-f");
67 printf("%-20s databases cannot be opened (NSS_INIT_FORCEOPEN)\n", " ");
68 printf("%-20s Try to initialize the database\n", "-i");
69 printf("%-20s Supply a password with which to initialize the db\n", "-p");
70 printf("%-20s Directory with cert database (default is .\n",
71 "-d certdir");
72 exit(1);
73 }
74
75 int
main(int argc,char ** argv)76 main(int argc, char **argv)
77 {
78 PLOptState *optstate;
79 PLOptStatus optstatus;
80
81 PRUint32 flags = 0;
82 Error ret;
83 SECStatus rv;
84 char *dbString = NULL;
85 PRBool doInitTest = PR_FALSE;
86 int i;
87
88 progName = strrchr(argv[0], '/');
89 if (!progName)
90 progName = strrchr(argv[0], '\\');
91 progName = progName ? progName + 1 : argv[0];
92
93 optstate = PL_CreateOptState(argc, argv, "rfip:d:h");
94
95 while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
96 switch (optstate->option) {
97 case 'h':
98 default:
99 Usage();
100 break;
101
102 case 'r':
103 flags |= NSS_INIT_READONLY;
104 break;
105
106 case 'f':
107 flags |= NSS_INIT_FORCEOPEN;
108 break;
109
110 case 'i':
111 doInitTest = PR_TRUE;
112 break;
113
114 case 'p':
115 userPassword = PORT_Strdup(optstate->value);
116 break;
117
118 case 'd':
119 dbDir = PORT_Strdup(optstate->value);
120 break;
121 }
122 }
123 PL_DestroyOptState(optstate);
124 if (optstatus == PL_OPT_BAD)
125 Usage();
126
127 if (dbDir) {
128 char *tmp = dbDir;
129 dbDir = SECU_ConfigDirectory(tmp);
130 PORT_Free(tmp);
131 } else {
132 /* Look in $SSL_DIR */
133 dbDir = SECU_ConfigDirectory(SECU_DefaultSSLDir());
134 }
135 PR_fprintf(PR_STDERR, "dbdir selected is %s\n\n", dbDir);
136
137 if (dbDir[0] == '\0') {
138 PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dbDir);
139 ret = DIR_DOESNT_EXIST_ERR;
140 goto loser;
141 }
142
143 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
144
145 /* get the status of the directory and databases and output message */
146 if (PR_Access(dbDir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
147 PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dbDir);
148 } else if (PR_Access(dbDir, PR_ACCESS_READ_OK) != PR_SUCCESS) {
149 PR_fprintf(PR_STDERR, errStrings[DIR_NOT_READABLE_ERR], dbDir);
150 } else {
151 if (!(flags & NSS_INIT_READONLY) &&
152 PR_Access(dbDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
153 PR_fprintf(PR_STDERR, errStrings[DIR_NOT_WRITEABLE_ERR], dbDir);
154 }
155 if (!doInitTest) {
156 for (i = 0; i < 3; i++) {
157 dbString = PR_smprintf("%s/%s", dbDir, dbName[i]);
158 PR_fprintf(PR_STDOUT, "database checked is %s\n", dbString);
159 if (PR_Access(dbString, PR_ACCESS_EXISTS) != PR_SUCCESS) {
160 PR_fprintf(PR_STDERR, errStrings[FILE_DOESNT_EXIST_ERR],
161 dbString);
162 } else if (PR_Access(dbString, PR_ACCESS_READ_OK) != PR_SUCCESS) {
163 PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR],
164 dbString);
165 } else if (!(flags & NSS_INIT_READONLY) &&
166 PR_Access(dbString, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
167 PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR],
168 dbString);
169 }
170 PR_smprintf_free(dbString);
171 }
172 }
173 }
174
175 rv = NSS_Initialize(SECU_ConfigDirectory(dbDir), dbprefix, dbprefix,
176 secmodName, flags);
177 if (rv != SECSuccess) {
178 SECU_PrintPRandOSError(progName);
179 ret = NSS_INITIALIZE_FAILED_ERR;
180 } else {
181 ret = SUCCESS;
182 if (doInitTest) {
183 PK11SlotInfo *slot = PK11_GetInternalKeySlot();
184 int passwordSuccess = 0;
185 int type = CKM_DES3_CBC;
186 SECItem keyid = { 0, NULL, 0 };
187 unsigned char keyIdData[] = { 0xff, 0xfe };
188 PK11SymKey *key = NULL;
189
190 keyid.data = keyIdData;
191 keyid.len = sizeof(keyIdData);
192
193 PK11_SetPasswordFunc(getPassword);
194 rv = PK11_InitPin(slot, (char *)NULL, userPassword);
195 if (rv != SECSuccess) {
196 PR_fprintf(PR_STDERR, "Failed to Init DB: %s\n",
197 SECU_Strerror(PORT_GetError()));
198 ret = CHANGEPW_FAILED_ERR;
199 }
200 if (*userPassword && !PK11_IsLoggedIn(slot, &passwordSuccess)) {
201 PR_fprintf(PR_STDERR, "New DB did not log in after init\n");
202 ret = AUTHENTICATION_FAILED_ERR;
203 }
204 /* generate a symetric key */
205 key = PK11_TokenKeyGen(slot, type, NULL, 0, &keyid,
206 PR_TRUE, &passwordSuccess);
207
208 if (!key) {
209 PR_fprintf(PR_STDERR, "Could not generated symetric key: %s\n",
210 SECU_Strerror(PORT_GetError()));
211 exit(UNSPECIFIED_ERR);
212 }
213 PK11_FreeSymKey(key);
214 PK11_Logout(slot);
215
216 PK11_Authenticate(slot, PR_TRUE, &passwordSuccess);
217
218 if (*userPassword && !passwordSuccess) {
219 PR_fprintf(PR_STDERR, "New DB Did not initalize\n");
220 ret = AUTHENTICATION_FAILED_ERR;
221 }
222 key = PK11_FindFixedKey(slot, type, &keyid, &passwordSuccess);
223
224 if (!key) {
225 PR_fprintf(PR_STDERR, "Could not find generated key: %s\n",
226 SECU_Strerror(PORT_GetError()));
227 ret = UNSPECIFIED_ERR;
228 } else {
229 PK11_FreeSymKey(key);
230 }
231 PK11_FreeSlot(slot);
232 }
233
234 if (NSS_Shutdown() != SECSuccess) {
235 PR_fprintf(PR_STDERR, "Could not find generated key: %s\n",
236 SECU_Strerror(PORT_GetError()));
237 exit(1);
238 }
239 }
240
241 loser:
242 return ret;
243 }
244