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