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