bacd6701855bc529cc19a94a5ba8da961cde1496
[openssl.git] / apps / srp.c
1 /*
2  * Written by Peter Sylvester (peter.sylvester@edelweb.fr) for the EdelKey
3  * project and contributed to the OpenSSL project 2004.
4  */
5 /* ====================================================================
6  * Copyright (c) 2004 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 #include <openssl/opensslconf.h>
59
60 #ifndef OPENSSL_NO_SRP
61 # include <stdio.h>
62 # include <stdlib.h>
63 # include <string.h>
64 # include <openssl/conf.h>
65 # include <openssl/bio.h>
66 # include <openssl/err.h>
67 # include <openssl/txt_db.h>
68 # include <openssl/buffer.h>
69 # include <openssl/srp.h>
70
71 # include "apps.h"
72
73 # define BASE_SECTION    "srp"
74 # define CONFIG_FILE "openssl.cnf"
75
76 # define ENV_RANDFILE            "RANDFILE"
77
78 # define ENV_DATABASE            "srpvfile"
79 # define ENV_DEFAULT_SRP         "default_srp"
80
81 # ifdef EFENCE
82 extern int EF_PROTECT_FREE;
83 extern int EF_PROTECT_BELOW;
84 extern int EF_ALIGNMENT;
85 # endif
86
87 static int get_index(CA_DB *db, char *id, char type)
88 {
89     char **pp;
90     int i;
91     if (id == NULL)
92         return -1;
93     if (type == DB_SRP_INDEX)
94         for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
95             pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
96             if (pp[DB_srptype][0] == DB_SRP_INDEX
97                 && !strcmp(id, pp[DB_srpid]))
98                 return i;
99     } else
100         for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
101             pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
102
103             if (pp[DB_srptype][0] != DB_SRP_INDEX
104                 && !strcmp(id, pp[DB_srpid]))
105                 return i;
106         }
107
108     return -1;
109 }
110
111 static void print_entry(CA_DB *db, BIO *bio, int indx, int verbose, char *s)
112 {
113     if (indx >= 0 && verbose) {
114         int j;
115         char **pp = sk_OPENSSL_PSTRING_value(db->db->data, indx);
116         BIO_printf(bio, "%s \"%s\"\n", s, pp[DB_srpid]);
117         for (j = 0; j < DB_NUMBER; j++) {
118             BIO_printf(bio_err, "  %d = \"%s\"\n", j, pp[j]);
119         }
120     }
121 }
122
123 static void print_index(CA_DB *db, BIO *bio, int indexindex, int verbose)
124 {
125     print_entry(db, bio, indexindex, verbose, "g N entry");
126 }
127
128 static void print_user(CA_DB *db, BIO *bio, int userindex, int verbose)
129 {
130     if (verbose > 0) {
131         char **pp = sk_OPENSSL_PSTRING_value(db->db->data, userindex);
132
133         if (pp[DB_srptype][0] != 'I') {
134             print_entry(db, bio, userindex, verbose, "User entry");
135             print_entry(db, bio, get_index(db, pp[DB_srpgN], 'I'), verbose,
136                         "g N entry");
137         }
138
139     }
140 }
141
142 static int update_index(CA_DB *db, BIO *bio, char **row)
143 {
144     char **irow;
145     int i;
146
147     if ((irow =
148          (char **)OPENSSL_malloc(sizeof(char *) * (DB_NUMBER + 1))) == NULL) {
149         BIO_printf(bio_err, "Memory allocation failure\n");
150         return 0;
151     }
152
153     for (i = 0; i < DB_NUMBER; i++) {
154         irow[i] = row[i];
155         row[i] = NULL;
156     }
157     irow[DB_NUMBER] = NULL;
158
159     if (!TXT_DB_insert(db->db, irow)) {
160         BIO_printf(bio, "failed to update srpvfile\n");
161         BIO_printf(bio, "TXT_DB error number %ld\n", db->db->error);
162         OPENSSL_free(irow);
163         return 0;
164     }
165     return 1;
166 }
167
168 static void lookup_fail(const char *name, const char *tag)
169 {
170     BIO_printf(bio_err, "variable lookup failed for %s::%s\n", name, tag);
171 }
172
173 static char *srp_verify_user(const char *user, const char *srp_verifier,
174                              char *srp_usersalt, const char *g, const char *N,
175                              const char *passin, BIO *bio, int verbose)
176 {
177     char password[1024];
178     PW_CB_DATA cb_tmp;
179     char *verifier = NULL;
180     char *gNid = NULL;
181
182     cb_tmp.prompt_info = user;
183     cb_tmp.password = passin;
184
185     if (password_callback(password, 1024, 0, &cb_tmp) > 0) {
186         if (verbose)
187             BIO_printf(bio,
188                        "Validating\n   user=\"%s\"\n srp_verifier=\"%s\"\n srp_usersalt=\"%s\"\n g=\"%s\"\n N=\"%s\"\n",
189                        user, srp_verifier, srp_usersalt, g, N);
190         BIO_printf(bio, "Pass %s\n", password);
191
192         OPENSSL_assert(srp_usersalt != NULL);
193         if (!
194             (gNid =
195              SRP_create_verifier(user, password, &srp_usersalt, &verifier, N,
196                                  g))) {
197             BIO_printf(bio, "Internal error validating SRP verifier\n");
198         } else {
199             if (strcmp(verifier, srp_verifier))
200                 gNid = NULL;
201             OPENSSL_free(verifier);
202         }
203     }
204     return gNid;
205 }
206
207 static char *srp_create_user(char *user, char **srp_verifier,
208                              char **srp_usersalt, char *g, char *N,
209                              char *passout, BIO *bio, int verbose)
210 {
211     char password[1024];
212     PW_CB_DATA cb_tmp;
213     char *gNid = NULL;
214     char *salt = NULL;
215     cb_tmp.prompt_info = user;
216     cb_tmp.password = passout;
217
218     if (password_callback(password, 1024, 1, &cb_tmp) > 0) {
219         if (verbose)
220             BIO_printf(bio, "Creating\n user=\"%s\"\n g=\"%s\"\n N=\"%s\"\n",
221                        user, g, N);
222         if (!
223             (gNid =
224              SRP_create_verifier(user, password, &salt, srp_verifier, N,
225                                  g))) {
226             BIO_printf(bio, "Internal error creating SRP verifier\n");
227         } else
228             *srp_usersalt = salt;
229         if (verbose > 1)
230             BIO_printf(bio, "gNid=%s salt =\"%s\"\n verifier =\"%s\"\n", gNid,
231                        salt, *srp_verifier);
232
233     }
234     return gNid;
235 }
236
237 typedef enum OPTION_choice {
238     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
239     OPT_VERBOSE, OPT_CONFIG, OPT_NAME, OPT_SRPVFILE, OPT_ADD,
240     OPT_DELETE, OPT_MODIFY, OPT_LIST, OPT_GN, OPT_USERINFO,
241     OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE
242 } OPTION_CHOICE;
243
244 OPTIONS srp_options[] = {
245     {"help", OPT_HELP, '-', "Display this summary"},
246     {"verbose", OPT_VERBOSE, '-', "Talk a lot while doing things"},
247     {"config", OPT_CONFIG, '<', "A config file"},
248     {"name", OPT_NAME, 's', "The particular srp definition to use"},
249     {"srpvfile", OPT_SRPVFILE, '<', "The srp verifier file name"},
250     {"add", OPT_ADD, '-', "Add a user and srp verifier"},
251     {"modify", OPT_MODIFY, '-',
252      "Modify the srp verifier of an existing user"},
253     {"delete", OPT_DELETE, '-', "Delete user from verifier file"},
254     {"list", OPT_LIST, '-', "List users"},
255     {"gn", OPT_GN, 's', "Set g and N values to be used for new verifier"},
256     {"userinfo", OPT_USERINFO, 's', "Additional info to be set for user"},
257     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
258     {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
259 # ifndef OPENSSL_NO_ENGINE
260     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
261 # endif
262     {NULL}
263 };
264
265 int srp_main(int argc, char **argv)
266 {
267     CA_DB *db = NULL;
268     DB_ATTR db_attr;
269     CONF *conf = NULL;
270     int gNindex = -1, maxgN = -1, ret = 1, errors = 0, verbose =
271         0, i, doupdatedb = 0;
272     int mode = OPT_ERR;
273     char *user = NULL, *passinarg = NULL, *passoutarg = NULL;
274     char *passin = NULL, *passout = NULL, *gN = NULL, *userinfo = NULL;
275     char *randfile = NULL, *engine = NULL, *tofree = NULL, *section = NULL;
276     char **gNrow = NULL, *configfile = NULL, *dbfile = NULL, **pp, *prog;
277     long errorline = -1;
278     OPTION_CHOICE o;
279
280 # ifdef EFENCE
281     EF_PROTECT_FREE = 1;
282     EF_PROTECT_BELOW = 1;
283     EF_ALIGNMENT = 0;
284 # endif
285
286     prog = opt_init(argc, argv, srp_options);
287     while ((o = opt_next()) != OPT_EOF) {
288         switch (o) {
289         case OPT_EOF:
290         case OPT_ERR:
291  opthelp:
292             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
293             goto end;
294         case OPT_HELP:
295             opt_help(srp_options);
296             ret = 0;
297             goto end;
298         case OPT_VERBOSE:
299             verbose++;
300             break;
301         case OPT_CONFIG:
302             configfile = opt_arg();
303             break;
304         case OPT_NAME:
305             section = opt_arg();
306             break;
307         case OPT_SRPVFILE:
308             dbfile = opt_arg();
309             break;
310         case OPT_ADD:
311         case OPT_DELETE:
312         case OPT_MODIFY:
313         case OPT_LIST:
314             if (mode != OPT_ERR) {
315                 BIO_printf(bio_err,
316                            "%s: Only one of -add/delete-modify/-list\n",
317                            prog);
318                 goto opthelp;
319             }
320             mode = o;
321             break;
322         case OPT_GN:
323             gN = opt_arg();
324             break;
325         case OPT_USERINFO:
326             userinfo = opt_arg();
327             break;
328         case OPT_PASSIN:
329             passinarg = opt_arg();
330             break;
331         case OPT_PASSOUT:
332             passoutarg = opt_arg();
333             break;
334         case OPT_ENGINE:
335             engine = opt_arg();
336             break;
337         }
338     }
339     argc = opt_num_rest();
340     argv = opt_rest();
341
342     if (dbfile && configfile) {
343         BIO_printf(bio_err,
344                    "-dbfile and -configfile cannot be specified together.\n");
345         goto end;
346     }
347     if (mode == OPT_ERR) {
348         BIO_printf(bio_err,
349                    "Exactly one of the options -add, -delete, -modify -list must be specified.\n");
350         goto opthelp;
351     }
352     if ((mode == OPT_DELETE || mode == OPT_MODIFY || OPT_ADD) && argc < 1) {
353         BIO_printf(bio_err,
354                    "Need at least one user for options -add, -delete, -modify. \n");
355         goto opthelp;
356     }
357     if ((passin || passout) && argc != 1) {
358         BIO_printf(bio_err,
359                    "-passin, -passout arguments only valid with one user.\n");
360         goto opthelp;
361     }
362 # ifndef OPENSSL_NO_ENGINE
363     setup_engine(engine, 0);
364 # endif
365
366     if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
367         BIO_printf(bio_err, "Error getting passwords\n");
368         goto end;
369     }
370
371     if (!dbfile) {
372
373         /*****************************************************************/
374         tofree = NULL;
375         if (configfile == NULL)
376             configfile = getenv("OPENSSL_CONF");
377         if (configfile == NULL)
378             configfile = getenv("SSLEAY_CONF");
379         if (configfile == NULL) {
380             const char *s = X509_get_default_cert_area();
381             size_t len;
382
383 # ifdef OPENSSL_SYS_VMS
384             len = strlen(s) + sizeof(CONFIG_FILE);
385             tofree = OPENSSL_malloc(len);
386             if (!tofree) {
387                 BIO_printf(bio_err, "Out of memory\n");
388                 goto end;
389             }
390             strcpy(tofree, s);
391 # else
392             len = strlen(s) + sizeof(CONFIG_FILE) + 1;
393             tofree = OPENSSL_malloc(len);
394             if (!tofree) {
395                 BIO_printf(bio_err, "Out of memory\n");
396                 goto end;
397             }
398             BUF_strlcpy(tofree, s, len);
399             BUF_strlcat(tofree, "/", len);
400 # endif
401             BUF_strlcat(tofree, CONFIG_FILE, len);
402             configfile = tofree;
403         }
404
405         if (verbose)
406             BIO_printf(bio_err, "Using configuration from %s\n", configfile);
407         conf = NCONF_new(NULL);
408         if (NCONF_load(conf, configfile, &errorline) <= 0) {
409             if (errorline <= 0)
410                 BIO_printf(bio_err, "error loading the config file '%s'\n",
411                            configfile);
412             else
413                 BIO_printf(bio_err, "error on line %ld of config file '%s'\n",
414                            errorline, configfile);
415             goto end;
416         }
417         if (tofree) {
418             OPENSSL_free(tofree);
419             tofree = NULL;
420         }
421
422         /* Lets get the config section we are using */
423         if (section == NULL) {
424             if (verbose)
425                 BIO_printf(bio_err,
426                            "trying to read " ENV_DEFAULT_SRP
427                            " in \" BASE_SECTION \"\n");
428
429             section = NCONF_get_string(conf, BASE_SECTION, ENV_DEFAULT_SRP);
430             if (section == NULL) {
431                 lookup_fail(BASE_SECTION, ENV_DEFAULT_SRP);
432                 goto end;
433             }
434         }
435
436         if (randfile == NULL && conf)
437             randfile = NCONF_get_string(conf, BASE_SECTION, "RANDFILE");
438
439         if (verbose)
440             BIO_printf(bio_err,
441                        "trying to read " ENV_DATABASE " in section \"%s\"\n",
442                        section);
443
444         if ((dbfile = NCONF_get_string(conf, section, ENV_DATABASE)) == NULL) {
445             lookup_fail(section, ENV_DATABASE);
446             goto end;
447         }
448
449     }
450     if (randfile == NULL)
451         ERR_clear_error();
452     else
453         app_RAND_load_file(randfile, 0);
454
455     if (verbose)
456         BIO_printf(bio_err, "Trying to read SRP verifier file \"%s\"\n",
457                    dbfile);
458
459     db = load_index(dbfile, &db_attr);
460     if (db == NULL)
461         goto end;
462
463     /* Lets check some fields */
464     for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
465         pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
466
467         if (pp[DB_srptype][0] == DB_SRP_INDEX) {
468             maxgN = i;
469             if (gNindex < 0 && gN != NULL && !strcmp(gN, pp[DB_srpid]))
470                 gNindex = i;
471
472             print_index(db, bio_err, i, verbose > 1);
473         }
474     }
475
476     if (verbose)
477         BIO_printf(bio_err, "Database initialised\n");
478
479     if (gNindex >= 0) {
480         gNrow = sk_OPENSSL_PSTRING_value(db->db->data, gNindex);
481         print_entry(db, bio_err, gNindex, verbose > 1, "Default g and N");
482     } else if (maxgN > 0 && !SRP_get_default_gN(gN)) {
483         BIO_printf(bio_err, "No g and N value for index \"%s\"\n", gN);
484         goto end;
485     } else {
486         if (verbose)
487             BIO_printf(bio_err, "Database has no g N information.\n");
488         gNrow = NULL;
489     }
490
491     if (verbose > 1)
492         BIO_printf(bio_err, "Starting user processing\n");
493
494     if (argc > 0)
495         user = *(argv++);
496
497     while (mode == OPT_LIST || user) {
498         int userindex = -1;
499         if (user)
500             if (verbose > 1)
501                 BIO_printf(bio_err, "Processing user \"%s\"\n", user);
502         if ((userindex = get_index(db, user, 'U')) >= 0) {
503             print_user(db, bio_err, userindex, (verbose > 0)
504                        || mode == OPT_LIST);
505         }
506
507         if (mode == OPT_LIST) {
508             if (user == NULL) {
509                 BIO_printf(bio_err, "List all users\n");
510
511                 for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
512                     print_user(db, bio_err, i, 1);
513                 }
514             } else if (userindex < 0) {
515                 BIO_printf(bio_err,
516                            "user \"%s\" does not exist, ignored. t\n", user);
517                 errors++;
518             }
519         } else if (mode == OPT_ADD) {
520             if (userindex >= 0) {
521                 /* reactivation of a new user */
522                 char **row =
523                     sk_OPENSSL_PSTRING_value(db->db->data, userindex);
524                 BIO_printf(bio_err, "user \"%s\" reactivated.\n", user);
525                 row[DB_srptype][0] = 'V';
526
527                 doupdatedb = 1;
528             } else {
529                 char *row[DB_NUMBER];
530                 char *gNid;
531                 row[DB_srpverifier] = NULL;
532                 row[DB_srpsalt] = NULL;
533                 row[DB_srpinfo] = NULL;
534                 if (!
535                     (gNid =
536                      srp_create_user(user, &(row[DB_srpverifier]),
537                                      &(row[DB_srpsalt]),
538                                      gNrow ? gNrow[DB_srpsalt] : gN,
539                                      gNrow ? gNrow[DB_srpverifier] : NULL,
540                                      passout, bio_err, verbose))) {
541                     BIO_printf(bio_err,
542                                "Cannot create srp verifier for user \"%s\", operation abandoned .\n",
543                                user);
544                     errors++;
545                     goto end;
546                 }
547                 row[DB_srpid] = BUF_strdup(user);
548                 row[DB_srptype] = BUF_strdup("v");
549                 row[DB_srpgN] = BUF_strdup(gNid);
550
551                 if (!row[DB_srpid] || !row[DB_srpgN] || !row[DB_srptype]
552                     || !row[DB_srpverifier] || !row[DB_srpsalt] || (userinfo
553                                                                     &&
554                                                                     (!(row
555                                                                        [DB_srpinfo]
556                                                                        =
557                                                                        BUF_strdup
558                                                                        (userinfo))))
559                     || !update_index(db, bio_err, row)) {
560                     if (row[DB_srpid])
561                         OPENSSL_free(row[DB_srpid]);
562                     if (row[DB_srpgN])
563                         OPENSSL_free(row[DB_srpgN]);
564                     if (row[DB_srpinfo])
565                         OPENSSL_free(row[DB_srpinfo]);
566                     if (row[DB_srptype])
567                         OPENSSL_free(row[DB_srptype]);
568                     if (row[DB_srpverifier])
569                         OPENSSL_free(row[DB_srpverifier]);
570                     if (row[DB_srpsalt])
571                         OPENSSL_free(row[DB_srpsalt]);
572                     goto end;
573                 }
574                 doupdatedb = 1;
575             }
576         } else if (mode == OPT_MODIFY) {
577             if (userindex < 0) {
578                 BIO_printf(bio_err,
579                            "user \"%s\" does not exist, operation ignored.\n",
580                            user);
581                 errors++;
582             } else {
583
584                 char **row =
585                     sk_OPENSSL_PSTRING_value(db->db->data, userindex);
586                 char type = row[DB_srptype][0];
587                 if (type == 'v') {
588                     BIO_printf(bio_err,
589                                "user \"%s\" already updated, operation ignored.\n",
590                                user);
591                     errors++;
592                 } else {
593                     char *gNid;
594
595                     if (row[DB_srptype][0] == 'V') {
596                         int user_gN;
597                         char **irow = NULL;
598                         if (verbose)
599                             BIO_printf(bio_err,
600                                        "Verifying password for user \"%s\"\n",
601                                        user);
602                         if ((user_gN =
603                              get_index(db, row[DB_srpgN], DB_SRP_INDEX)) >= 0)
604                             irow =
605                                 sk_OPENSSL_PSTRING_value(db->db->data,
606                                                          userindex);
607
608                         if (!srp_verify_user
609                             (user, row[DB_srpverifier], row[DB_srpsalt],
610                              irow ? irow[DB_srpsalt] : row[DB_srpgN],
611                              irow ? irow[DB_srpverifier] : NULL, passin,
612                              bio_err, verbose)) {
613                             BIO_printf(bio_err,
614                                        "Invalid password for user \"%s\", operation abandoned.\n",
615                                        user);
616                             errors++;
617                             goto end;
618                         }
619                     }
620                     if (verbose)
621                         BIO_printf(bio_err, "Password for user \"%s\" ok.\n",
622                                    user);
623
624                     if (!
625                         (gNid =
626                          srp_create_user(user, &(row[DB_srpverifier]),
627                                          &(row[DB_srpsalt]),
628                                          gNrow ? gNrow[DB_srpsalt] : NULL,
629                                          gNrow ? gNrow[DB_srpverifier] : NULL,
630                                          passout, bio_err, verbose))) {
631                         BIO_printf(bio_err,
632                                    "Cannot create srp verifier for user \"%s\", operation abandoned.\n",
633                                    user);
634                         errors++;
635                         goto end;
636                     }
637
638                     row[DB_srptype][0] = 'v';
639                     row[DB_srpgN] = BUF_strdup(gNid);
640
641                     if (!row[DB_srpid] || !row[DB_srpgN] || !row[DB_srptype]
642                         || !row[DB_srpverifier] || !row[DB_srpsalt]
643                         || (userinfo
644                             && (!(row[DB_srpinfo] = BUF_strdup(userinfo)))))
645                         goto end;
646
647                     doupdatedb = 1;
648                 }
649             }
650         } else if (mode == OPT_DELETE) {
651             if (userindex < 0) {
652                 BIO_printf(bio_err,
653                            "user \"%s\" does not exist, operation ignored. t\n",
654                            user);
655                 errors++;
656             } else {
657                 char **xpp =
658                     sk_OPENSSL_PSTRING_value(db->db->data, userindex);
659                 BIO_printf(bio_err, "user \"%s\" revoked. t\n", user);
660
661                 xpp[DB_srptype][0] = 'R';
662
663                 doupdatedb = 1;
664             }
665         }
666         if (--argc > 0)
667             user = *(argv++);
668         else {
669             user = NULL;
670         }
671     }
672
673     if (verbose)
674         BIO_printf(bio_err, "User procession done.\n");
675
676     if (doupdatedb) {
677         /* Lets check some fields */
678         for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
679             pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
680
681             if (pp[DB_srptype][0] == 'v') {
682                 pp[DB_srptype][0] = 'V';
683                 print_user(db, bio_err, i, verbose);
684             }
685         }
686
687         if (verbose)
688             BIO_printf(bio_err, "Trying to update srpvfile.\n");
689         if (!save_index(dbfile, "new", db))
690             goto end;
691
692         if (verbose)
693             BIO_printf(bio_err, "Temporary srpvfile created.\n");
694         if (!rotate_index(dbfile, "new", "old"))
695             goto end;
696
697         if (verbose)
698             BIO_printf(bio_err, "srpvfile updated.\n");
699     }
700
701     ret = (errors != 0);
702  end:
703     if (errors != 0)
704         if (verbose)
705             BIO_printf(bio_err, "User errors %d.\n", errors);
706
707     if (verbose)
708         BIO_printf(bio_err, "SRP terminating with code %d.\n", ret);
709     if (tofree)
710         OPENSSL_free(tofree);
711     if (ret)
712         ERR_print_errors(bio_err);
713     if (randfile)
714         app_RAND_write_file(randfile);
715     if (conf)
716         NCONF_free(conf);
717     if (db)
718         free_index(db);
719
720     OBJ_cleanup();
721     return (ret);
722 }
723
724 #endif