srp.c revision 325335
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
85static 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
107extern int EF_PROTECT_FREE;
108extern int EF_PROTECT_BELOW;
109extern int EF_ALIGNMENT;
110# endif
111
112static CONF *conf = NULL;
113static char *section = NULL;
114
115# define VERBOSE if (verbose)
116# define VVERBOSE if (verbose>1)
117
118int MAIN(int, char **);
119
120static 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
144static 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
156static 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
161static 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
175static 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    irow[DB_NUMBER] = NULL;
189
190    if (!TXT_DB_insert(db->db, irow)) {
191        BIO_printf(bio, "failed to update srpvfile\n");
192        BIO_printf(bio, "TXT_DB error number %ld\n", db->db->error);
193        OPENSSL_free(irow);
194        return 0;
195    }
196    return 1;
197}
198
199static void lookup_fail(const char *name, char *tag)
200{
201    BIO_printf(bio_err, "variable lookup failed for %s::%s\n", name, tag);
202}
203
204static char *srp_verify_user(const char *user, const char *srp_verifier,
205                             char *srp_usersalt, const char *g, const char *N,
206                             const char *passin, BIO *bio, int verbose)
207{
208    char password[1024];
209    PW_CB_DATA cb_tmp;
210    char *verifier = NULL;
211    char *gNid = NULL;
212
213    cb_tmp.prompt_info = user;
214    cb_tmp.password = passin;
215
216    if (password_callback(password, 1024, 0, &cb_tmp) > 0) {
217        VERBOSE BIO_printf(bio,
218                           "Validating\n   user=\"%s\"\n srp_verifier=\"%s\"\n srp_usersalt=\"%s\"\n g=\"%s\"\n N=\"%s\"\n",
219                           user, srp_verifier, srp_usersalt, g, N);
220        BIO_printf(bio, "Pass %s\n", password);
221
222        if (!
223            (gNid =
224             SRP_create_verifier(user, password, &srp_usersalt, &verifier, N,
225                                 g))) {
226            BIO_printf(bio, "Internal error validating SRP verifier\n");
227        } else {
228            if (strcmp(verifier, srp_verifier))
229                gNid = NULL;
230            OPENSSL_free(verifier);
231        }
232    }
233    return gNid;
234}
235
236static char *srp_create_user(char *user, char **srp_verifier,
237                             char **srp_usersalt, char *g, char *N,
238                             char *passout, BIO *bio, int verbose)
239{
240    char password[1024];
241    PW_CB_DATA cb_tmp;
242    char *gNid = NULL;
243    char *salt = NULL;
244    cb_tmp.prompt_info = user;
245    cb_tmp.password = passout;
246
247    if (password_callback(password, 1024, 1, &cb_tmp) > 0) {
248        VERBOSE BIO_printf(bio,
249                           "Creating\n user=\"%s\"\n g=\"%s\"\n N=\"%s\"\n",
250                           user, g, N);
251        if (!
252            (gNid =
253             SRP_create_verifier(user, password, &salt, srp_verifier, N,
254                                 g))) {
255            BIO_printf(bio, "Internal error creating SRP verifier\n");
256        } else
257            *srp_usersalt = salt;
258        VVERBOSE BIO_printf(bio, "gNid=%s salt =\"%s\"\n verifier =\"%s\"\n",
259                            gNid, salt, *srp_verifier);
260
261    }
262    return gNid;
263}
264
265int MAIN(int argc, char **argv)
266{
267    int add_user = 0;
268    int list_user = 0;
269    int delete_user = 0;
270    int modify_user = 0;
271    char *user = NULL;
272
273    char *passargin = NULL, *passargout = NULL;
274    char *passin = NULL, *passout = NULL;
275    char *gN = NULL;
276    int gNindex = -1;
277    char **gNrow = NULL;
278    int maxgN = -1;
279
280    char *userinfo = NULL;
281
282    int badops = 0;
283    int ret = 1;
284    int errors = 0;
285    int verbose = 0;
286    int doupdatedb = 0;
287    char *configfile = NULL;
288    char *dbfile = NULL;
289    CA_DB *db = NULL;
290    char **pp;
291    int i;
292    long errorline = -1;
293    char *randfile = NULL;
294    ENGINE *e = NULL;
295    char *engine = NULL;
296    char *tofree = NULL;
297    DB_ATTR db_attr;
298
299# ifdef EFENCE
300    EF_PROTECT_FREE = 1;
301    EF_PROTECT_BELOW = 1;
302    EF_ALIGNMENT = 0;
303# endif
304
305    apps_startup();
306
307    conf = NULL;
308    section = NULL;
309
310    if (bio_err == NULL)
311        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
312            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
313
314    argc--;
315    argv++;
316    while (argc >= 1 && badops == 0) {
317        if (strcmp(*argv, "-verbose") == 0)
318            verbose++;
319        else if (strcmp(*argv, "-config") == 0) {
320            if (--argc < 1)
321                goto bad;
322            configfile = *(++argv);
323        } else if (strcmp(*argv, "-name") == 0) {
324            if (--argc < 1)
325                goto bad;
326            section = *(++argv);
327        } else if (strcmp(*argv, "-srpvfile") == 0) {
328            if (--argc < 1)
329                goto bad;
330            dbfile = *(++argv);
331        } else if (strcmp(*argv, "-add") == 0)
332            add_user = 1;
333        else if (strcmp(*argv, "-delete") == 0)
334            delete_user = 1;
335        else if (strcmp(*argv, "-modify") == 0)
336            modify_user = 1;
337        else if (strcmp(*argv, "-list") == 0)
338            list_user = 1;
339        else if (strcmp(*argv, "-gn") == 0) {
340            if (--argc < 1)
341                goto bad;
342            gN = *(++argv);
343        } else if (strcmp(*argv, "-userinfo") == 0) {
344            if (--argc < 1)
345                goto bad;
346            userinfo = *(++argv);
347        } else if (strcmp(*argv, "-passin") == 0) {
348            if (--argc < 1)
349                goto bad;
350            passargin = *(++argv);
351        } else if (strcmp(*argv, "-passout") == 0) {
352            if (--argc < 1)
353                goto bad;
354            passargout = *(++argv);
355        }
356# ifndef OPENSSL_NO_ENGINE
357        else if (strcmp(*argv, "-engine") == 0) {
358            if (--argc < 1)
359                goto bad;
360            engine = *(++argv);
361        }
362# endif
363
364        else if (**argv == '-') {
365 bad:
366            BIO_printf(bio_err, "unknown option %s\n", *argv);
367            badops = 1;
368            break;
369        } else
370            break;
371
372        argc--;
373        argv++;
374    }
375
376    if (dbfile && configfile) {
377        BIO_printf(bio_err,
378                   "-dbfile and -configfile cannot be specified together.\n");
379        badops = 1;
380    }
381    if (add_user + delete_user + modify_user + list_user != 1) {
382        BIO_printf(bio_err,
383                   "Exactly one of the options -add, -delete, -modify -list must be specified.\n");
384        badops = 1;
385    }
386    if (delete_user + modify_user + delete_user == 1 && argc <= 0) {
387        BIO_printf(bio_err,
388                   "Need at least one user for options -add, -delete, -modify. \n");
389        badops = 1;
390    }
391    if ((passin || passout) && argc != 1) {
392        BIO_printf(bio_err,
393                   "-passin, -passout arguments only valid with one user.\n");
394        badops = 1;
395    }
396
397    if (badops) {
398        for (pp = srp_usage; (*pp != NULL); pp++)
399            BIO_printf(bio_err, "%s", *pp);
400
401        BIO_printf(bio_err, " -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR,
402                   LIST_SEPARATOR_CHAR);
403        BIO_printf(bio_err,
404                   "                 load the file (or the files in the directory) into\n");
405        BIO_printf(bio_err, "                 the random number generator\n");
406        goto err;
407    }
408
409    ERR_load_crypto_strings();
410
411    e = setup_engine(bio_err, engine, 0);
412
413    if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) {
414        BIO_printf(bio_err, "Error getting passwords\n");
415        goto err;
416    }
417
418    if (!dbfile) {
419
420        /*****************************************************************/
421        tofree = NULL;
422        if (configfile == NULL)
423            configfile = getenv("OPENSSL_CONF");
424        if (configfile == NULL)
425            configfile = getenv("SSLEAY_CONF");
426        if (configfile == NULL) {
427            const char *s = X509_get_default_cert_area();
428            size_t len;
429
430# ifdef OPENSSL_SYS_VMS
431            len = strlen(s) + sizeof(CONFIG_FILE);
432            tofree = OPENSSL_malloc(len);
433            if (!tofree) {
434                BIO_printf(bio_err, "Out of memory\n");
435                goto err;
436            }
437            strcpy(tofree, s);
438# else
439            len = strlen(s) + sizeof(CONFIG_FILE) + 1;
440            tofree = OPENSSL_malloc(len);
441            if (!tofree) {
442                BIO_printf(bio_err, "Out of memory\n");
443                goto err;
444            }
445            BUF_strlcpy(tofree, s, len);
446            BUF_strlcat(tofree, "/", len);
447# endif
448            BUF_strlcat(tofree, CONFIG_FILE, len);
449            configfile = tofree;
450        }
451
452        VERBOSE BIO_printf(bio_err, "Using configuration from %s\n",
453                           configfile);
454        conf = NCONF_new(NULL);
455        if (NCONF_load(conf, configfile, &errorline) <= 0) {
456            if (errorline <= 0)
457                BIO_printf(bio_err, "error loading the config file '%s'\n",
458                           configfile);
459            else
460                BIO_printf(bio_err, "error on line %ld of config file '%s'\n",
461                           errorline, configfile);
462            goto err;
463        }
464        if (tofree) {
465            OPENSSL_free(tofree);
466            tofree = NULL;
467        }
468
469        if (!load_config(bio_err, conf))
470            goto err;
471
472        /* Lets get the config section we are using */
473        if (section == NULL) {
474            VERBOSE BIO_printf(bio_err,
475                               "trying to read " ENV_DEFAULT_SRP
476                               " in \" BASE_SECTION \"\n");
477
478            section = NCONF_get_string(conf, BASE_SECTION, ENV_DEFAULT_SRP);
479            if (section == NULL) {
480                lookup_fail(BASE_SECTION, ENV_DEFAULT_SRP);
481                goto err;
482            }
483        }
484
485        if (randfile == NULL && conf)
486            randfile = NCONF_get_string(conf, BASE_SECTION, "RANDFILE");
487
488        VERBOSE BIO_printf(bio_err,
489                           "trying to read " ENV_DATABASE
490                           " in section \"%s\"\n", section);
491
492        if ((dbfile = NCONF_get_string(conf, section, ENV_DATABASE)) == NULL) {
493            lookup_fail(section, ENV_DATABASE);
494            goto err;
495        }
496
497    }
498    if (randfile == NULL)
499        ERR_clear_error();
500    else
501        app_RAND_load_file(randfile, bio_err, 0);
502
503    VERBOSE BIO_printf(bio_err, "Trying to read SRP verifier file \"%s\"\n",
504                       dbfile);
505
506    db = load_index(dbfile, &db_attr);
507    if (db == NULL)
508        goto err;
509
510    /* Lets check some fields */
511    for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
512        pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
513
514        if (pp[DB_srptype][0] == DB_SRP_INDEX) {
515            maxgN = i;
516            if (gNindex < 0 && gN != NULL && !strcmp(gN, pp[DB_srpid]))
517                gNindex = i;
518
519            print_index(db, bio_err, i, verbose > 1);
520        }
521    }
522
523    VERBOSE BIO_printf(bio_err, "Database initialised\n");
524
525    if (gNindex >= 0) {
526        gNrow = sk_OPENSSL_PSTRING_value(db->db->data, gNindex);
527        print_entry(db, bio_err, gNindex, verbose > 1, "Default g and N");
528    } else if (maxgN > 0 && !SRP_get_default_gN(gN)) {
529        BIO_printf(bio_err, "No g and N value for index \"%s\"\n", gN);
530        goto err;
531    } else {
532        VERBOSE BIO_printf(bio_err, "Database has no g N information.\n");
533        gNrow = NULL;
534    }
535
536    VVERBOSE BIO_printf(bio_err, "Starting user processing\n");
537
538    if (argc > 0)
539        user = *(argv++);
540
541    while (list_user || user) {
542        int userindex = -1;
543        if (user)
544            VVERBOSE BIO_printf(bio_err, "Processing user \"%s\"\n", user);
545        if ((userindex = get_index(db, user, 'U')) >= 0) {
546            print_user(db, bio_err, userindex, (verbose > 0) || list_user);
547        }
548
549        if (list_user) {
550            if (user == NULL) {
551                BIO_printf(bio_err, "List all users\n");
552
553                for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
554                    print_user(db, bio_err, i, 1);
555                }
556                list_user = 0;
557            } else if (userindex < 0) {
558                BIO_printf(bio_err,
559                           "user \"%s\" does not exist, ignored. t\n", user);
560                errors++;
561            }
562        } else if (add_user) {
563            if (userindex >= 0) {
564                /* reactivation of a new user */
565                char **row =
566                    sk_OPENSSL_PSTRING_value(db->db->data, userindex);
567                BIO_printf(bio_err, "user \"%s\" reactivated.\n", user);
568                row[DB_srptype][0] = 'V';
569
570                doupdatedb = 1;
571            } else {
572                char *row[DB_NUMBER];
573                char *gNid;
574                row[DB_srpverifier] = NULL;
575                row[DB_srpsalt] = NULL;
576                row[DB_srpinfo] = NULL;
577                if (!
578                    (gNid =
579                     srp_create_user(user, &(row[DB_srpverifier]),
580                                     &(row[DB_srpsalt]),
581                                     gNrow ? gNrow[DB_srpsalt] : gN,
582                                     gNrow ? gNrow[DB_srpverifier] : NULL,
583                                     passout, bio_err, verbose))) {
584                    BIO_printf(bio_err,
585                               "Cannot create srp verifier for user \"%s\", operation abandoned .\n",
586                               user);
587                    errors++;
588                    goto err;
589                }
590                row[DB_srpid] = BUF_strdup(user);
591                row[DB_srptype] = BUF_strdup("v");
592                row[DB_srpgN] = BUF_strdup(gNid);
593
594                if (!row[DB_srpid] || !row[DB_srpgN] || !row[DB_srptype]
595                    || !row[DB_srpverifier] || !row[DB_srpsalt] || (userinfo
596                                                                    &&
597                                                                    (!(row
598                                                                       [DB_srpinfo]
599                                                                       =
600                                                                       BUF_strdup
601                                                                       (userinfo))))
602                    || !update_index(db, bio_err, row)) {
603                    if (row[DB_srpid])
604                        OPENSSL_free(row[DB_srpid]);
605                    if (row[DB_srpgN])
606                        OPENSSL_free(row[DB_srpgN]);
607                    if (row[DB_srpinfo])
608                        OPENSSL_free(row[DB_srpinfo]);
609                    if (row[DB_srptype])
610                        OPENSSL_free(row[DB_srptype]);
611                    if (row[DB_srpverifier])
612                        OPENSSL_free(row[DB_srpverifier]);
613                    if (row[DB_srpsalt])
614                        OPENSSL_free(row[DB_srpsalt]);
615                    goto err;
616                }
617                doupdatedb = 1;
618            }
619        } else if (modify_user) {
620            if (userindex < 0) {
621                BIO_printf(bio_err,
622                           "user \"%s\" does not exist, operation ignored.\n",
623                           user);
624                errors++;
625            } else {
626
627                char **row =
628                    sk_OPENSSL_PSTRING_value(db->db->data, userindex);
629                char type = row[DB_srptype][0];
630                if (type == 'v') {
631                    BIO_printf(bio_err,
632                               "user \"%s\" already updated, operation ignored.\n",
633                               user);
634                    errors++;
635                } else {
636                    char *gNid;
637
638                    if (row[DB_srptype][0] == 'V') {
639                        int user_gN;
640                        char **irow = NULL;
641                        VERBOSE BIO_printf(bio_err,
642                                           "Verifying password for user \"%s\"\n",
643                                           user);
644                        if ((user_gN =
645                             get_index(db, row[DB_srpgN], DB_SRP_INDEX)) >= 0)
646                            irow =
647                                (char **)sk_OPENSSL_PSTRING_value(db->
648                                                                  db->data,
649                                                                  userindex);
650
651                        if (!srp_verify_user
652                            (user, row[DB_srpverifier], row[DB_srpsalt],
653                             irow ? irow[DB_srpsalt] : row[DB_srpgN],
654                             irow ? irow[DB_srpverifier] : NULL, passin,
655                             bio_err, verbose)) {
656                            BIO_printf(bio_err,
657                                       "Invalid password for user \"%s\", operation abandoned.\n",
658                                       user);
659                            errors++;
660                            goto err;
661                        }
662                    }
663                    VERBOSE BIO_printf(bio_err,
664                                       "Password for user \"%s\" ok.\n",
665                                       user);
666
667                    if (!
668                        (gNid =
669                         srp_create_user(user, &(row[DB_srpverifier]),
670                                         &(row[DB_srpsalt]),
671                                         gNrow ? gNrow[DB_srpsalt] : NULL,
672                                         gNrow ? gNrow[DB_srpverifier] : NULL,
673                                         passout, bio_err, verbose))) {
674                        BIO_printf(bio_err,
675                                   "Cannot create srp verifier for user \"%s\", operation abandoned.\n",
676                                   user);
677                        errors++;
678                        goto err;
679                    }
680
681                    row[DB_srptype][0] = 'v';
682                    row[DB_srpgN] = BUF_strdup(gNid);
683
684                    if (!row[DB_srpid] || !row[DB_srpgN] || !row[DB_srptype]
685                        || !row[DB_srpverifier] || !row[DB_srpsalt]
686                        || (userinfo
687                            && (!(row[DB_srpinfo] = BUF_strdup(userinfo)))))
688                        goto err;
689
690                    doupdatedb = 1;
691                }
692            }
693        } else if (delete_user) {
694            if (userindex < 0) {
695                BIO_printf(bio_err,
696                           "user \"%s\" does not exist, operation ignored. t\n",
697                           user);
698                errors++;
699            } else {
700                char **xpp =
701                    sk_OPENSSL_PSTRING_value(db->db->data, userindex);
702                BIO_printf(bio_err, "user \"%s\" revoked. t\n", user);
703
704                xpp[DB_srptype][0] = 'R';
705
706                doupdatedb = 1;
707            }
708        }
709        if (--argc > 0)
710            user = *(argv++);
711        else {
712            user = NULL;
713            list_user = 0;
714        }
715    }
716
717    VERBOSE BIO_printf(bio_err, "User procession done.\n");
718
719    if (doupdatedb) {
720        /* Lets check some fields */
721        for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
722            pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
723
724            if (pp[DB_srptype][0] == 'v') {
725                pp[DB_srptype][0] = 'V';
726                print_user(db, bio_err, i, verbose);
727            }
728        }
729
730        VERBOSE BIO_printf(bio_err, "Trying to update srpvfile.\n");
731        if (!save_index(dbfile, "new", db))
732            goto err;
733
734        VERBOSE BIO_printf(bio_err, "Temporary srpvfile created.\n");
735        if (!rotate_index(dbfile, "new", "old"))
736            goto err;
737
738        VERBOSE BIO_printf(bio_err, "srpvfile updated.\n");
739    }
740
741    ret = (errors != 0);
742 err:
743    if (errors != 0)
744        VERBOSE BIO_printf(bio_err, "User errors %d.\n", errors);
745
746    VERBOSE BIO_printf(bio_err, "SRP terminating with code %d.\n", ret);
747    if (tofree)
748        OPENSSL_free(tofree);
749    if (ret)
750        ERR_print_errors(bio_err);
751    if (randfile)
752        app_RAND_write_file(randfile, bio_err);
753    if (conf)
754        NCONF_free(conf);
755    if (db)
756        free_index(db);
757
758    release_engine(e);
759    OBJ_cleanup();
760    apps_shutdown();
761    OPENSSL_EXIT(ret);
762}
763
764#else
765static void *dummy = &dummy;
766#endif
767