1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2004-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci * Copyright (c) 2004, EdelKey Project. All Rights Reserved.
4e1051a39Sopenharmony_ci *
5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
6e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
9e1051a39Sopenharmony_ci *
10e1051a39Sopenharmony_ci * Originally written by Christophe Renou and Peter Sylvester,
11e1051a39Sopenharmony_ci * for the EdelKey project.
12e1051a39Sopenharmony_ci */
13e1051a39Sopenharmony_ci
14e1051a39Sopenharmony_ci/* SRP is deprecated, so we're going to have to use some deprecated APIs */
15e1051a39Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED
16e1051a39Sopenharmony_ci
17e1051a39Sopenharmony_ci#include <openssl/opensslconf.h>
18e1051a39Sopenharmony_ci
19e1051a39Sopenharmony_ci#include <stdio.h>
20e1051a39Sopenharmony_ci#include <stdlib.h>
21e1051a39Sopenharmony_ci#include <string.h>
22e1051a39Sopenharmony_ci#include <openssl/conf.h>
23e1051a39Sopenharmony_ci#include <openssl/bio.h>
24e1051a39Sopenharmony_ci#include <openssl/err.h>
25e1051a39Sopenharmony_ci#include <openssl/txt_db.h>
26e1051a39Sopenharmony_ci#include <openssl/buffer.h>
27e1051a39Sopenharmony_ci#include <openssl/srp.h>
28e1051a39Sopenharmony_ci#include "apps.h"
29e1051a39Sopenharmony_ci#include "progs.h"
30e1051a39Sopenharmony_ci
31e1051a39Sopenharmony_ci#define BASE_SECTION    "srp"
32e1051a39Sopenharmony_ci#define CONFIG_FILE "openssl.cnf"
33e1051a39Sopenharmony_ci
34e1051a39Sopenharmony_ci
35e1051a39Sopenharmony_ci#define ENV_DATABASE            "srpvfile"
36e1051a39Sopenharmony_ci#define ENV_DEFAULT_SRP         "default_srp"
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_cistatic int get_index(CA_DB *db, char *id, char type)
39e1051a39Sopenharmony_ci{
40e1051a39Sopenharmony_ci    char **pp;
41e1051a39Sopenharmony_ci    int i;
42e1051a39Sopenharmony_ci    if (id == NULL)
43e1051a39Sopenharmony_ci        return -1;
44e1051a39Sopenharmony_ci    if (type == DB_SRP_INDEX) {
45e1051a39Sopenharmony_ci        for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
46e1051a39Sopenharmony_ci            pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
47e1051a39Sopenharmony_ci            if (pp[DB_srptype][0] == DB_SRP_INDEX
48e1051a39Sopenharmony_ci                && strcmp(id, pp[DB_srpid]) == 0)
49e1051a39Sopenharmony_ci                return i;
50e1051a39Sopenharmony_ci        }
51e1051a39Sopenharmony_ci    } else {
52e1051a39Sopenharmony_ci        for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
53e1051a39Sopenharmony_ci            pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
54e1051a39Sopenharmony_ci
55e1051a39Sopenharmony_ci            if (pp[DB_srptype][0] != DB_SRP_INDEX
56e1051a39Sopenharmony_ci                && strcmp(id, pp[DB_srpid]) == 0)
57e1051a39Sopenharmony_ci                return i;
58e1051a39Sopenharmony_ci        }
59e1051a39Sopenharmony_ci    }
60e1051a39Sopenharmony_ci
61e1051a39Sopenharmony_ci    return -1;
62e1051a39Sopenharmony_ci}
63e1051a39Sopenharmony_ci
64e1051a39Sopenharmony_cistatic void print_entry(CA_DB *db, int indx, int verbose, char *s)
65e1051a39Sopenharmony_ci{
66e1051a39Sopenharmony_ci    if (indx >= 0 && verbose) {
67e1051a39Sopenharmony_ci        int j;
68e1051a39Sopenharmony_ci        char **pp = sk_OPENSSL_PSTRING_value(db->db->data, indx);
69e1051a39Sopenharmony_ci        BIO_printf(bio_err, "%s \"%s\"\n", s, pp[DB_srpid]);
70e1051a39Sopenharmony_ci        for (j = 0; j < DB_NUMBER; j++) {
71e1051a39Sopenharmony_ci            BIO_printf(bio_err, "  %d = \"%s\"\n", j, pp[j]);
72e1051a39Sopenharmony_ci        }
73e1051a39Sopenharmony_ci    }
74e1051a39Sopenharmony_ci}
75e1051a39Sopenharmony_ci
76e1051a39Sopenharmony_cistatic void print_index(CA_DB *db, int indexindex, int verbose)
77e1051a39Sopenharmony_ci{
78e1051a39Sopenharmony_ci    print_entry(db, indexindex, verbose, "g N entry");
79e1051a39Sopenharmony_ci}
80e1051a39Sopenharmony_ci
81e1051a39Sopenharmony_cistatic void print_user(CA_DB *db, int userindex, int verbose)
82e1051a39Sopenharmony_ci{
83e1051a39Sopenharmony_ci    if (verbose > 0) {
84e1051a39Sopenharmony_ci        char **pp = sk_OPENSSL_PSTRING_value(db->db->data, userindex);
85e1051a39Sopenharmony_ci
86e1051a39Sopenharmony_ci        if (pp[DB_srptype][0] != 'I') {
87e1051a39Sopenharmony_ci            print_entry(db, userindex, verbose, "User entry");
88e1051a39Sopenharmony_ci            print_entry(db, get_index(db, pp[DB_srpgN], 'I'), verbose,
89e1051a39Sopenharmony_ci                        "g N entry");
90e1051a39Sopenharmony_ci        }
91e1051a39Sopenharmony_ci
92e1051a39Sopenharmony_ci    }
93e1051a39Sopenharmony_ci}
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_cistatic int update_index(CA_DB *db, char **row)
96e1051a39Sopenharmony_ci{
97e1051a39Sopenharmony_ci    char **irow;
98e1051a39Sopenharmony_ci    int i;
99e1051a39Sopenharmony_ci
100e1051a39Sopenharmony_ci    irow = app_malloc(sizeof(*irow) * (DB_NUMBER + 1), "row pointers");
101e1051a39Sopenharmony_ci    for (i = 0; i < DB_NUMBER; i++)
102e1051a39Sopenharmony_ci        irow[i] = row[i];
103e1051a39Sopenharmony_ci    irow[DB_NUMBER] = NULL;
104e1051a39Sopenharmony_ci
105e1051a39Sopenharmony_ci    if (!TXT_DB_insert(db->db, irow)) {
106e1051a39Sopenharmony_ci        BIO_printf(bio_err, "failed to update srpvfile\n");
107e1051a39Sopenharmony_ci        BIO_printf(bio_err, "TXT_DB error number %ld\n", db->db->error);
108e1051a39Sopenharmony_ci        OPENSSL_free(irow);
109e1051a39Sopenharmony_ci        return 0;
110e1051a39Sopenharmony_ci    }
111e1051a39Sopenharmony_ci    return 1;
112e1051a39Sopenharmony_ci}
113e1051a39Sopenharmony_ci
114e1051a39Sopenharmony_cistatic char *lookup_conf(const CONF *conf, const char *section, const char *tag)
115e1051a39Sopenharmony_ci{
116e1051a39Sopenharmony_ci    char *entry = NCONF_get_string(conf, section, tag);
117e1051a39Sopenharmony_ci    if (entry == NULL)
118e1051a39Sopenharmony_ci        BIO_printf(bio_err, "variable lookup failed for %s::%s\n", section, tag);
119e1051a39Sopenharmony_ci    return entry;
120e1051a39Sopenharmony_ci}
121e1051a39Sopenharmony_ci
122e1051a39Sopenharmony_cistatic char *srp_verify_user(const char *user, const char *srp_verifier,
123e1051a39Sopenharmony_ci                             char *srp_usersalt, const char *g, const char *N,
124e1051a39Sopenharmony_ci                             const char *passin, int verbose)
125e1051a39Sopenharmony_ci{
126e1051a39Sopenharmony_ci    char password[1025];
127e1051a39Sopenharmony_ci    PW_CB_DATA cb_tmp;
128e1051a39Sopenharmony_ci    char *verifier = NULL;
129e1051a39Sopenharmony_ci    char *gNid = NULL;
130e1051a39Sopenharmony_ci    int len;
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ci    cb_tmp.prompt_info = user;
133e1051a39Sopenharmony_ci    cb_tmp.password = passin;
134e1051a39Sopenharmony_ci
135e1051a39Sopenharmony_ci    len = password_callback(password, sizeof(password)-1, 0, &cb_tmp);
136e1051a39Sopenharmony_ci    if (len > 0) {
137e1051a39Sopenharmony_ci        password[len] = 0;
138e1051a39Sopenharmony_ci        if (verbose)
139e1051a39Sopenharmony_ci            BIO_printf(bio_err,
140e1051a39Sopenharmony_ci                       "Validating\n   user=\"%s\"\n srp_verifier=\"%s\"\n srp_usersalt=\"%s\"\n g=\"%s\"\n N=\"%s\"\n",
141e1051a39Sopenharmony_ci                       user, srp_verifier, srp_usersalt, g, N);
142e1051a39Sopenharmony_ci        if (verbose > 1)
143e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Pass %s\n", password);
144e1051a39Sopenharmony_ci
145e1051a39Sopenharmony_ci        OPENSSL_assert(srp_usersalt != NULL);
146e1051a39Sopenharmony_ci        if ((gNid = SRP_create_verifier(user, password, &srp_usersalt,
147e1051a39Sopenharmony_ci                                        &verifier, N, g)) == NULL) {
148e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Internal error validating SRP verifier\n");
149e1051a39Sopenharmony_ci        } else {
150e1051a39Sopenharmony_ci            if (strcmp(verifier, srp_verifier))
151e1051a39Sopenharmony_ci                gNid = NULL;
152e1051a39Sopenharmony_ci            OPENSSL_free(verifier);
153e1051a39Sopenharmony_ci        }
154e1051a39Sopenharmony_ci        OPENSSL_cleanse(password, len);
155e1051a39Sopenharmony_ci    }
156e1051a39Sopenharmony_ci    return gNid;
157e1051a39Sopenharmony_ci}
158e1051a39Sopenharmony_ci
159e1051a39Sopenharmony_cistatic char *srp_create_user(char *user, char **srp_verifier,
160e1051a39Sopenharmony_ci                             char **srp_usersalt, char *g, char *N,
161e1051a39Sopenharmony_ci                             char *passout, int verbose)
162e1051a39Sopenharmony_ci{
163e1051a39Sopenharmony_ci    char password[1025];
164e1051a39Sopenharmony_ci    PW_CB_DATA cb_tmp;
165e1051a39Sopenharmony_ci    char *gNid = NULL;
166e1051a39Sopenharmony_ci    char *salt = NULL;
167e1051a39Sopenharmony_ci    int len;
168e1051a39Sopenharmony_ci    cb_tmp.prompt_info = user;
169e1051a39Sopenharmony_ci    cb_tmp.password = passout;
170e1051a39Sopenharmony_ci
171e1051a39Sopenharmony_ci    len = password_callback(password, sizeof(password)-1, 1, &cb_tmp);
172e1051a39Sopenharmony_ci    if (len > 0) {
173e1051a39Sopenharmony_ci        password[len] = 0;
174e1051a39Sopenharmony_ci        if (verbose)
175e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Creating\n user=\"%s\"\n g=\"%s\"\n N=\"%s\"\n",
176e1051a39Sopenharmony_ci                       user, g, N);
177e1051a39Sopenharmony_ci        if ((gNid = SRP_create_verifier(user, password, &salt,
178e1051a39Sopenharmony_ci                                        srp_verifier, N, g)) == NULL) {
179e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Internal error creating SRP verifier\n");
180e1051a39Sopenharmony_ci        } else {
181e1051a39Sopenharmony_ci            *srp_usersalt = salt;
182e1051a39Sopenharmony_ci        }
183e1051a39Sopenharmony_ci        OPENSSL_cleanse(password, len);
184e1051a39Sopenharmony_ci        if (verbose > 1)
185e1051a39Sopenharmony_ci            BIO_printf(bio_err, "gNid=%s salt =\"%s\"\n verifier =\"%s\"\n",
186e1051a39Sopenharmony_ci                       gNid, salt, *srp_verifier);
187e1051a39Sopenharmony_ci
188e1051a39Sopenharmony_ci    }
189e1051a39Sopenharmony_ci    return gNid;
190e1051a39Sopenharmony_ci}
191e1051a39Sopenharmony_ci
192e1051a39Sopenharmony_citypedef enum OPTION_choice {
193e1051a39Sopenharmony_ci    OPT_COMMON,
194e1051a39Sopenharmony_ci    OPT_VERBOSE, OPT_CONFIG, OPT_NAME, OPT_SRPVFILE, OPT_ADD,
195e1051a39Sopenharmony_ci    OPT_DELETE, OPT_MODIFY, OPT_LIST, OPT_GN, OPT_USERINFO,
196e1051a39Sopenharmony_ci    OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE, OPT_R_ENUM, OPT_PROV_ENUM
197e1051a39Sopenharmony_ci} OPTION_CHOICE;
198e1051a39Sopenharmony_ci
199e1051a39Sopenharmony_ciconst OPTIONS srp_options[] = {
200e1051a39Sopenharmony_ci    {OPT_HELP_STR, 1, '-', "Usage: %s [options] [user...]\n"},
201e1051a39Sopenharmony_ci
202e1051a39Sopenharmony_ci    OPT_SECTION("General"),
203e1051a39Sopenharmony_ci    {"help", OPT_HELP, '-', "Display this summary"},
204e1051a39Sopenharmony_ci    {"verbose", OPT_VERBOSE, '-', "Talk a lot while doing things"},
205e1051a39Sopenharmony_ci    {"config", OPT_CONFIG, '<', "A config file"},
206e1051a39Sopenharmony_ci    {"name", OPT_NAME, 's', "The particular srp definition to use"},
207e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_ENGINE
208e1051a39Sopenharmony_ci    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
209e1051a39Sopenharmony_ci#endif
210e1051a39Sopenharmony_ci
211e1051a39Sopenharmony_ci    OPT_SECTION("Action"),
212e1051a39Sopenharmony_ci    {"add", OPT_ADD, '-', "Add a user and SRP verifier"},
213e1051a39Sopenharmony_ci    {"modify", OPT_MODIFY, '-', "Modify the SRP verifier of an existing user"},
214e1051a39Sopenharmony_ci    {"delete", OPT_DELETE, '-', "Delete user from verifier file"},
215e1051a39Sopenharmony_ci    {"list", OPT_LIST, '-', "List users"},
216e1051a39Sopenharmony_ci
217e1051a39Sopenharmony_ci    OPT_SECTION("Configuration"),
218e1051a39Sopenharmony_ci    {"srpvfile", OPT_SRPVFILE, '<', "The srp verifier file name"},
219e1051a39Sopenharmony_ci    {"gn", OPT_GN, 's', "Set g and N values to be used for new verifier"},
220e1051a39Sopenharmony_ci    {"userinfo", OPT_USERINFO, 's', "Additional info to be set for user"},
221e1051a39Sopenharmony_ci    {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
222e1051a39Sopenharmony_ci    {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
223e1051a39Sopenharmony_ci
224e1051a39Sopenharmony_ci    OPT_R_OPTIONS,
225e1051a39Sopenharmony_ci    OPT_PROV_OPTIONS,
226e1051a39Sopenharmony_ci
227e1051a39Sopenharmony_ci    OPT_PARAMETERS(),
228e1051a39Sopenharmony_ci    {"user", 0, 0, "Username(s) to process (optional)"},
229e1051a39Sopenharmony_ci    {NULL}
230e1051a39Sopenharmony_ci};
231e1051a39Sopenharmony_ci
232e1051a39Sopenharmony_ciint srp_main(int argc, char **argv)
233e1051a39Sopenharmony_ci{
234e1051a39Sopenharmony_ci    ENGINE *e = NULL;
235e1051a39Sopenharmony_ci    CA_DB *db = NULL;
236e1051a39Sopenharmony_ci    CONF *conf = NULL;
237e1051a39Sopenharmony_ci    int gNindex = -1, maxgN = -1, ret = 1, errors = 0, verbose = 0, i;
238e1051a39Sopenharmony_ci    int doupdatedb = 0, mode = OPT_ERR;
239e1051a39Sopenharmony_ci    char *user = NULL, *passinarg = NULL, *passoutarg = NULL;
240e1051a39Sopenharmony_ci    char *passin = NULL, *passout = NULL, *gN = NULL, *userinfo = NULL;
241e1051a39Sopenharmony_ci    char *section = NULL;
242e1051a39Sopenharmony_ci    char **gNrow = NULL, *configfile = NULL;
243e1051a39Sopenharmony_ci    char *srpvfile = NULL, **pp, *prog;
244e1051a39Sopenharmony_ci    OPTION_CHOICE o;
245e1051a39Sopenharmony_ci
246e1051a39Sopenharmony_ci    prog = opt_init(argc, argv, srp_options);
247e1051a39Sopenharmony_ci    while ((o = opt_next()) != OPT_EOF) {
248e1051a39Sopenharmony_ci        switch (o) {
249e1051a39Sopenharmony_ci        case OPT_EOF:
250e1051a39Sopenharmony_ci        case OPT_ERR:
251e1051a39Sopenharmony_ci opthelp:
252e1051a39Sopenharmony_ci            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
253e1051a39Sopenharmony_ci            goto end;
254e1051a39Sopenharmony_ci        case OPT_HELP:
255e1051a39Sopenharmony_ci            opt_help(srp_options);
256e1051a39Sopenharmony_ci            ret = 0;
257e1051a39Sopenharmony_ci            goto end;
258e1051a39Sopenharmony_ci        case OPT_VERBOSE:
259e1051a39Sopenharmony_ci            verbose++;
260e1051a39Sopenharmony_ci            break;
261e1051a39Sopenharmony_ci        case OPT_CONFIG:
262e1051a39Sopenharmony_ci            configfile = opt_arg();
263e1051a39Sopenharmony_ci            break;
264e1051a39Sopenharmony_ci        case OPT_NAME:
265e1051a39Sopenharmony_ci            section = opt_arg();
266e1051a39Sopenharmony_ci            break;
267e1051a39Sopenharmony_ci        case OPT_SRPVFILE:
268e1051a39Sopenharmony_ci            srpvfile = opt_arg();
269e1051a39Sopenharmony_ci            break;
270e1051a39Sopenharmony_ci        case OPT_ADD:
271e1051a39Sopenharmony_ci        case OPT_DELETE:
272e1051a39Sopenharmony_ci        case OPT_MODIFY:
273e1051a39Sopenharmony_ci        case OPT_LIST:
274e1051a39Sopenharmony_ci            if (mode != OPT_ERR) {
275e1051a39Sopenharmony_ci                BIO_printf(bio_err,
276e1051a39Sopenharmony_ci                           "%s: Only one of -add/-delete/-modify/-list\n",
277e1051a39Sopenharmony_ci                           prog);
278e1051a39Sopenharmony_ci                goto opthelp;
279e1051a39Sopenharmony_ci            }
280e1051a39Sopenharmony_ci            mode = o;
281e1051a39Sopenharmony_ci            break;
282e1051a39Sopenharmony_ci        case OPT_GN:
283e1051a39Sopenharmony_ci            gN = opt_arg();
284e1051a39Sopenharmony_ci            break;
285e1051a39Sopenharmony_ci        case OPT_USERINFO:
286e1051a39Sopenharmony_ci            userinfo = opt_arg();
287e1051a39Sopenharmony_ci            break;
288e1051a39Sopenharmony_ci        case OPT_PASSIN:
289e1051a39Sopenharmony_ci            passinarg = opt_arg();
290e1051a39Sopenharmony_ci            break;
291e1051a39Sopenharmony_ci        case OPT_PASSOUT:
292e1051a39Sopenharmony_ci            passoutarg = opt_arg();
293e1051a39Sopenharmony_ci            break;
294e1051a39Sopenharmony_ci        case OPT_ENGINE:
295e1051a39Sopenharmony_ci            e = setup_engine(opt_arg(), 0);
296e1051a39Sopenharmony_ci            break;
297e1051a39Sopenharmony_ci        case OPT_R_CASES:
298e1051a39Sopenharmony_ci            if (!opt_rand(o))
299e1051a39Sopenharmony_ci                goto end;
300e1051a39Sopenharmony_ci            break;
301e1051a39Sopenharmony_ci        case OPT_PROV_CASES:
302e1051a39Sopenharmony_ci            if (!opt_provider(o))
303e1051a39Sopenharmony_ci                goto end;
304e1051a39Sopenharmony_ci            break;
305e1051a39Sopenharmony_ci        }
306e1051a39Sopenharmony_ci    }
307e1051a39Sopenharmony_ci
308e1051a39Sopenharmony_ci    /* Optional parameters are usernames. */
309e1051a39Sopenharmony_ci    argc = opt_num_rest();
310e1051a39Sopenharmony_ci    argv = opt_rest();
311e1051a39Sopenharmony_ci
312e1051a39Sopenharmony_ci    if (!app_RAND_load())
313e1051a39Sopenharmony_ci        goto end;
314e1051a39Sopenharmony_ci
315e1051a39Sopenharmony_ci    if (srpvfile != NULL && configfile != NULL) {
316e1051a39Sopenharmony_ci        BIO_printf(bio_err,
317e1051a39Sopenharmony_ci                   "-srpvfile and -configfile cannot be specified together.\n");
318e1051a39Sopenharmony_ci        goto end;
319e1051a39Sopenharmony_ci    }
320e1051a39Sopenharmony_ci    if (mode == OPT_ERR) {
321e1051a39Sopenharmony_ci        BIO_printf(bio_err,
322e1051a39Sopenharmony_ci                   "Exactly one of the options -add, -delete, -modify -list must be specified.\n");
323e1051a39Sopenharmony_ci        goto opthelp;
324e1051a39Sopenharmony_ci    }
325e1051a39Sopenharmony_ci    if (mode == OPT_DELETE || mode == OPT_MODIFY || mode == OPT_ADD) {
326e1051a39Sopenharmony_ci        if (argc == 0) {
327e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Need at least one user.\n");
328e1051a39Sopenharmony_ci            goto opthelp;
329e1051a39Sopenharmony_ci        }
330e1051a39Sopenharmony_ci        user = *argv++;
331e1051a39Sopenharmony_ci    }
332e1051a39Sopenharmony_ci    if ((passinarg != NULL || passoutarg != NULL) && argc != 1) {
333e1051a39Sopenharmony_ci        BIO_printf(bio_err,
334e1051a39Sopenharmony_ci                   "-passin, -passout arguments only valid with one user.\n");
335e1051a39Sopenharmony_ci        goto opthelp;
336e1051a39Sopenharmony_ci    }
337e1051a39Sopenharmony_ci
338e1051a39Sopenharmony_ci    if (!app_passwd(passinarg, passoutarg, &passin, &passout)) {
339e1051a39Sopenharmony_ci        BIO_printf(bio_err, "Error getting passwords\n");
340e1051a39Sopenharmony_ci        goto end;
341e1051a39Sopenharmony_ci    }
342e1051a39Sopenharmony_ci
343e1051a39Sopenharmony_ci    if (srpvfile == NULL) {
344e1051a39Sopenharmony_ci        if (configfile == NULL)
345e1051a39Sopenharmony_ci            configfile = default_config_file;
346e1051a39Sopenharmony_ci
347e1051a39Sopenharmony_ci        conf = app_load_config_verbose(configfile, verbose);
348e1051a39Sopenharmony_ci        if (conf == NULL)
349e1051a39Sopenharmony_ci            goto end;
350e1051a39Sopenharmony_ci        if (configfile != default_config_file && !app_load_modules(conf))
351e1051a39Sopenharmony_ci            goto end;
352e1051a39Sopenharmony_ci
353e1051a39Sopenharmony_ci        /* Lets get the config section we are using */
354e1051a39Sopenharmony_ci        if (section == NULL) {
355e1051a39Sopenharmony_ci            if (verbose)
356e1051a39Sopenharmony_ci                BIO_printf(bio_err,
357e1051a39Sopenharmony_ci                           "trying to read " ENV_DEFAULT_SRP
358e1051a39Sopenharmony_ci                           " in " BASE_SECTION "\n");
359e1051a39Sopenharmony_ci
360e1051a39Sopenharmony_ci            section = lookup_conf(conf, BASE_SECTION, ENV_DEFAULT_SRP);
361e1051a39Sopenharmony_ci            if (section == NULL)
362e1051a39Sopenharmony_ci                goto end;
363e1051a39Sopenharmony_ci        }
364e1051a39Sopenharmony_ci
365e1051a39Sopenharmony_ci        app_RAND_load_conf(conf, BASE_SECTION);
366e1051a39Sopenharmony_ci
367e1051a39Sopenharmony_ci        if (verbose)
368e1051a39Sopenharmony_ci            BIO_printf(bio_err,
369e1051a39Sopenharmony_ci                       "trying to read " ENV_DATABASE " in section \"%s\"\n",
370e1051a39Sopenharmony_ci                       section);
371e1051a39Sopenharmony_ci
372e1051a39Sopenharmony_ci        srpvfile = lookup_conf(conf, section, ENV_DATABASE);
373e1051a39Sopenharmony_ci        if (srpvfile == NULL)
374e1051a39Sopenharmony_ci            goto end;
375e1051a39Sopenharmony_ci    }
376e1051a39Sopenharmony_ci
377e1051a39Sopenharmony_ci    if (verbose)
378e1051a39Sopenharmony_ci        BIO_printf(bio_err, "Trying to read SRP verifier file \"%s\"\n",
379e1051a39Sopenharmony_ci                   srpvfile);
380e1051a39Sopenharmony_ci
381e1051a39Sopenharmony_ci    db = load_index(srpvfile, NULL);
382e1051a39Sopenharmony_ci    if (db == NULL) {
383e1051a39Sopenharmony_ci        BIO_printf(bio_err, "Problem with index file: %s (could not load/parse file)\n", srpvfile);
384e1051a39Sopenharmony_ci        goto end;
385e1051a39Sopenharmony_ci    }
386e1051a39Sopenharmony_ci
387e1051a39Sopenharmony_ci    /* Lets check some fields */
388e1051a39Sopenharmony_ci    for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
389e1051a39Sopenharmony_ci        pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
390e1051a39Sopenharmony_ci
391e1051a39Sopenharmony_ci        if (pp[DB_srptype][0] == DB_SRP_INDEX) {
392e1051a39Sopenharmony_ci            maxgN = i;
393e1051a39Sopenharmony_ci            if ((gNindex < 0) && (gN != NULL) && strcmp(gN, pp[DB_srpid]) == 0)
394e1051a39Sopenharmony_ci                gNindex = i;
395e1051a39Sopenharmony_ci
396e1051a39Sopenharmony_ci            print_index(db, i, verbose > 1);
397e1051a39Sopenharmony_ci        }
398e1051a39Sopenharmony_ci    }
399e1051a39Sopenharmony_ci
400e1051a39Sopenharmony_ci    if (verbose)
401e1051a39Sopenharmony_ci        BIO_printf(bio_err, "Database initialised\n");
402e1051a39Sopenharmony_ci
403e1051a39Sopenharmony_ci    if (gNindex >= 0) {
404e1051a39Sopenharmony_ci        gNrow = sk_OPENSSL_PSTRING_value(db->db->data, gNindex);
405e1051a39Sopenharmony_ci        print_entry(db, gNindex, verbose > 1, "Default g and N");
406e1051a39Sopenharmony_ci    } else if (maxgN > 0 && !SRP_get_default_gN(gN)) {
407e1051a39Sopenharmony_ci        BIO_printf(bio_err, "No g and N value for index \"%s\"\n", gN);
408e1051a39Sopenharmony_ci        goto end;
409e1051a39Sopenharmony_ci    } else {
410e1051a39Sopenharmony_ci        if (verbose)
411e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Database has no g N information.\n");
412e1051a39Sopenharmony_ci        gNrow = NULL;
413e1051a39Sopenharmony_ci    }
414e1051a39Sopenharmony_ci
415e1051a39Sopenharmony_ci    if (verbose > 1)
416e1051a39Sopenharmony_ci        BIO_printf(bio_err, "Starting user processing\n");
417e1051a39Sopenharmony_ci
418e1051a39Sopenharmony_ci    while (mode == OPT_LIST || user != NULL) {
419e1051a39Sopenharmony_ci        int userindex = -1;
420e1051a39Sopenharmony_ci
421e1051a39Sopenharmony_ci        if (user != NULL && verbose > 1)
422e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Processing user \"%s\"\n", user);
423e1051a39Sopenharmony_ci        if ((userindex = get_index(db, user, 'U')) >= 0)
424e1051a39Sopenharmony_ci            print_user(db, userindex, (verbose > 0) || mode == OPT_LIST);
425e1051a39Sopenharmony_ci
426e1051a39Sopenharmony_ci        if (mode == OPT_LIST) {
427e1051a39Sopenharmony_ci            if (user == NULL) {
428e1051a39Sopenharmony_ci                BIO_printf(bio_err, "List all users\n");
429e1051a39Sopenharmony_ci
430e1051a39Sopenharmony_ci                for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++)
431e1051a39Sopenharmony_ci                    print_user(db, i, 1);
432e1051a39Sopenharmony_ci            } else if (userindex < 0) {
433e1051a39Sopenharmony_ci                BIO_printf(bio_err,
434e1051a39Sopenharmony_ci                           "user \"%s\" does not exist, ignored. t\n", user);
435e1051a39Sopenharmony_ci                errors++;
436e1051a39Sopenharmony_ci            }
437e1051a39Sopenharmony_ci        } else if (mode == OPT_ADD) {
438e1051a39Sopenharmony_ci            if (userindex >= 0) {
439e1051a39Sopenharmony_ci                /* reactivation of a new user */
440e1051a39Sopenharmony_ci                char **row =
441e1051a39Sopenharmony_ci                    sk_OPENSSL_PSTRING_value(db->db->data, userindex);
442e1051a39Sopenharmony_ci                BIO_printf(bio_err, "user \"%s\" reactivated.\n", user);
443e1051a39Sopenharmony_ci                row[DB_srptype][0] = 'V';
444e1051a39Sopenharmony_ci
445e1051a39Sopenharmony_ci                doupdatedb = 1;
446e1051a39Sopenharmony_ci            } else {
447e1051a39Sopenharmony_ci                char *row[DB_NUMBER];
448e1051a39Sopenharmony_ci                char *gNid;
449e1051a39Sopenharmony_ci                row[DB_srpverifier] = NULL;
450e1051a39Sopenharmony_ci                row[DB_srpsalt] = NULL;
451e1051a39Sopenharmony_ci                row[DB_srpinfo] = NULL;
452e1051a39Sopenharmony_ci                if (!
453e1051a39Sopenharmony_ci                    (gNid =
454e1051a39Sopenharmony_ci                     srp_create_user(user, &(row[DB_srpverifier]),
455e1051a39Sopenharmony_ci                                     &(row[DB_srpsalt]),
456e1051a39Sopenharmony_ci                                     gNrow ? gNrow[DB_srpsalt] : gN,
457e1051a39Sopenharmony_ci                                     gNrow ? gNrow[DB_srpverifier] : NULL,
458e1051a39Sopenharmony_ci                                     passout, verbose))) {
459e1051a39Sopenharmony_ci                    BIO_printf(bio_err,
460e1051a39Sopenharmony_ci                               "Cannot create srp verifier for user \"%s\", operation abandoned .\n",
461e1051a39Sopenharmony_ci                               user);
462e1051a39Sopenharmony_ci                    errors++;
463e1051a39Sopenharmony_ci                    goto end;
464e1051a39Sopenharmony_ci                }
465e1051a39Sopenharmony_ci                row[DB_srpid] = OPENSSL_strdup(user);
466e1051a39Sopenharmony_ci                row[DB_srptype] = OPENSSL_strdup("v");
467e1051a39Sopenharmony_ci                row[DB_srpgN] = OPENSSL_strdup(gNid);
468e1051a39Sopenharmony_ci
469e1051a39Sopenharmony_ci                if ((row[DB_srpid] == NULL)
470e1051a39Sopenharmony_ci                    || (row[DB_srpgN] == NULL)
471e1051a39Sopenharmony_ci                    || (row[DB_srptype] == NULL)
472e1051a39Sopenharmony_ci                    || (row[DB_srpverifier] == NULL)
473e1051a39Sopenharmony_ci                    || (row[DB_srpsalt] == NULL)
474e1051a39Sopenharmony_ci                    || (userinfo
475e1051a39Sopenharmony_ci                        && ((row[DB_srpinfo] = OPENSSL_strdup(userinfo)) == NULL))
476e1051a39Sopenharmony_ci                    || !update_index(db, row)) {
477e1051a39Sopenharmony_ci                    OPENSSL_free(row[DB_srpid]);
478e1051a39Sopenharmony_ci                    OPENSSL_free(row[DB_srpgN]);
479e1051a39Sopenharmony_ci                    OPENSSL_free(row[DB_srpinfo]);
480e1051a39Sopenharmony_ci                    OPENSSL_free(row[DB_srptype]);
481e1051a39Sopenharmony_ci                    OPENSSL_free(row[DB_srpverifier]);
482e1051a39Sopenharmony_ci                    OPENSSL_free(row[DB_srpsalt]);
483e1051a39Sopenharmony_ci                    goto end;
484e1051a39Sopenharmony_ci                }
485e1051a39Sopenharmony_ci                doupdatedb = 1;
486e1051a39Sopenharmony_ci            }
487e1051a39Sopenharmony_ci        } else if (mode == OPT_MODIFY) {
488e1051a39Sopenharmony_ci            if (userindex < 0) {
489e1051a39Sopenharmony_ci                BIO_printf(bio_err,
490e1051a39Sopenharmony_ci                           "user \"%s\" does not exist, operation ignored.\n",
491e1051a39Sopenharmony_ci                           user);
492e1051a39Sopenharmony_ci                errors++;
493e1051a39Sopenharmony_ci            } else {
494e1051a39Sopenharmony_ci
495e1051a39Sopenharmony_ci                char **row =
496e1051a39Sopenharmony_ci                    sk_OPENSSL_PSTRING_value(db->db->data, userindex);
497e1051a39Sopenharmony_ci                char type = row[DB_srptype][0];
498e1051a39Sopenharmony_ci                if (type == 'v') {
499e1051a39Sopenharmony_ci                    BIO_printf(bio_err,
500e1051a39Sopenharmony_ci                               "user \"%s\" already updated, operation ignored.\n",
501e1051a39Sopenharmony_ci                               user);
502e1051a39Sopenharmony_ci                    errors++;
503e1051a39Sopenharmony_ci                } else {
504e1051a39Sopenharmony_ci                    char *gNid;
505e1051a39Sopenharmony_ci
506e1051a39Sopenharmony_ci                    if (row[DB_srptype][0] == 'V') {
507e1051a39Sopenharmony_ci                        int user_gN;
508e1051a39Sopenharmony_ci                        char **irow = NULL;
509e1051a39Sopenharmony_ci                        if (verbose)
510e1051a39Sopenharmony_ci                            BIO_printf(bio_err,
511e1051a39Sopenharmony_ci                                       "Verifying password for user \"%s\"\n",
512e1051a39Sopenharmony_ci                                       user);
513e1051a39Sopenharmony_ci                        if ((user_gN =
514e1051a39Sopenharmony_ci                             get_index(db, row[DB_srpgN], DB_SRP_INDEX)) >= 0)
515e1051a39Sopenharmony_ci                            irow =
516e1051a39Sopenharmony_ci                                sk_OPENSSL_PSTRING_value(db->db->data,
517e1051a39Sopenharmony_ci                                                         userindex);
518e1051a39Sopenharmony_ci
519e1051a39Sopenharmony_ci                        if (!srp_verify_user
520e1051a39Sopenharmony_ci                            (user, row[DB_srpverifier], row[DB_srpsalt],
521e1051a39Sopenharmony_ci                             irow ? irow[DB_srpsalt] : row[DB_srpgN],
522e1051a39Sopenharmony_ci                             irow ? irow[DB_srpverifier] : NULL, passin,
523e1051a39Sopenharmony_ci                             verbose)) {
524e1051a39Sopenharmony_ci                            BIO_printf(bio_err,
525e1051a39Sopenharmony_ci                                       "Invalid password for user \"%s\", operation abandoned.\n",
526e1051a39Sopenharmony_ci                                       user);
527e1051a39Sopenharmony_ci                            errors++;
528e1051a39Sopenharmony_ci                            goto end;
529e1051a39Sopenharmony_ci                        }
530e1051a39Sopenharmony_ci                    }
531e1051a39Sopenharmony_ci                    if (verbose)
532e1051a39Sopenharmony_ci                        BIO_printf(bio_err, "Password for user \"%s\" ok.\n",
533e1051a39Sopenharmony_ci                                   user);
534e1051a39Sopenharmony_ci
535e1051a39Sopenharmony_ci                    if (!
536e1051a39Sopenharmony_ci                        (gNid =
537e1051a39Sopenharmony_ci                         srp_create_user(user, &(row[DB_srpverifier]),
538e1051a39Sopenharmony_ci                                         &(row[DB_srpsalt]),
539e1051a39Sopenharmony_ci                                         gNrow ? gNrow[DB_srpsalt] : NULL,
540e1051a39Sopenharmony_ci                                         gNrow ? gNrow[DB_srpverifier] : NULL,
541e1051a39Sopenharmony_ci                                         passout, verbose))) {
542e1051a39Sopenharmony_ci                        BIO_printf(bio_err,
543e1051a39Sopenharmony_ci                                   "Cannot create srp verifier for user \"%s\", operation abandoned.\n",
544e1051a39Sopenharmony_ci                                   user);
545e1051a39Sopenharmony_ci                        errors++;
546e1051a39Sopenharmony_ci                        goto end;
547e1051a39Sopenharmony_ci                    }
548e1051a39Sopenharmony_ci
549e1051a39Sopenharmony_ci                    row[DB_srptype][0] = 'v';
550e1051a39Sopenharmony_ci                    row[DB_srpgN] = OPENSSL_strdup(gNid);
551e1051a39Sopenharmony_ci
552e1051a39Sopenharmony_ci                    if (row[DB_srpid] == NULL
553e1051a39Sopenharmony_ci                        || row[DB_srpgN] == NULL
554e1051a39Sopenharmony_ci                        || row[DB_srptype] == NULL
555e1051a39Sopenharmony_ci                        || row[DB_srpverifier] == NULL
556e1051a39Sopenharmony_ci                        || row[DB_srpsalt] == NULL
557e1051a39Sopenharmony_ci                        || (userinfo
558e1051a39Sopenharmony_ci                            && ((row[DB_srpinfo] = OPENSSL_strdup(userinfo))
559e1051a39Sopenharmony_ci                                == NULL)))
560e1051a39Sopenharmony_ci                        goto end;
561e1051a39Sopenharmony_ci
562e1051a39Sopenharmony_ci                    doupdatedb = 1;
563e1051a39Sopenharmony_ci                }
564e1051a39Sopenharmony_ci            }
565e1051a39Sopenharmony_ci        } else if (mode == OPT_DELETE) {
566e1051a39Sopenharmony_ci            if (userindex < 0) {
567e1051a39Sopenharmony_ci                BIO_printf(bio_err,
568e1051a39Sopenharmony_ci                           "user \"%s\" does not exist, operation ignored. t\n",
569e1051a39Sopenharmony_ci                           user);
570e1051a39Sopenharmony_ci                errors++;
571e1051a39Sopenharmony_ci            } else {
572e1051a39Sopenharmony_ci                char **xpp = sk_OPENSSL_PSTRING_value(db->db->data, userindex);
573e1051a39Sopenharmony_ci
574e1051a39Sopenharmony_ci                BIO_printf(bio_err, "user \"%s\" revoked. t\n", user);
575e1051a39Sopenharmony_ci                xpp[DB_srptype][0] = 'R';
576e1051a39Sopenharmony_ci                doupdatedb = 1;
577e1051a39Sopenharmony_ci            }
578e1051a39Sopenharmony_ci        }
579e1051a39Sopenharmony_ci        user = *argv++;
580e1051a39Sopenharmony_ci        if (user == NULL) {
581e1051a39Sopenharmony_ci            /* no more processing in any mode if no users left */
582e1051a39Sopenharmony_ci            break;
583e1051a39Sopenharmony_ci        }
584e1051a39Sopenharmony_ci    }
585e1051a39Sopenharmony_ci
586e1051a39Sopenharmony_ci    if (verbose)
587e1051a39Sopenharmony_ci        BIO_printf(bio_err, "User procession done.\n");
588e1051a39Sopenharmony_ci
589e1051a39Sopenharmony_ci    if (doupdatedb) {
590e1051a39Sopenharmony_ci        /* Lets check some fields */
591e1051a39Sopenharmony_ci        for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
592e1051a39Sopenharmony_ci            pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
593e1051a39Sopenharmony_ci
594e1051a39Sopenharmony_ci            if (pp[DB_srptype][0] == 'v') {
595e1051a39Sopenharmony_ci                pp[DB_srptype][0] = 'V';
596e1051a39Sopenharmony_ci                print_user(db, i, verbose);
597e1051a39Sopenharmony_ci            }
598e1051a39Sopenharmony_ci        }
599e1051a39Sopenharmony_ci
600e1051a39Sopenharmony_ci        if (verbose)
601e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Trying to update srpvfile.\n");
602e1051a39Sopenharmony_ci        if (!save_index(srpvfile, "new", db))
603e1051a39Sopenharmony_ci            goto end;
604e1051a39Sopenharmony_ci
605e1051a39Sopenharmony_ci        if (verbose)
606e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Temporary srpvfile created.\n");
607e1051a39Sopenharmony_ci        if (!rotate_index(srpvfile, "new", "old"))
608e1051a39Sopenharmony_ci            goto end;
609e1051a39Sopenharmony_ci
610e1051a39Sopenharmony_ci        if (verbose)
611e1051a39Sopenharmony_ci            BIO_printf(bio_err, "srpvfile updated.\n");
612e1051a39Sopenharmony_ci    }
613e1051a39Sopenharmony_ci
614e1051a39Sopenharmony_ci    ret = (errors != 0);
615e1051a39Sopenharmony_ci end:
616e1051a39Sopenharmony_ci    if (errors != 0)
617e1051a39Sopenharmony_ci        if (verbose)
618e1051a39Sopenharmony_ci            BIO_printf(bio_err, "User errors %d.\n", errors);
619e1051a39Sopenharmony_ci
620e1051a39Sopenharmony_ci    if (verbose)
621e1051a39Sopenharmony_ci        BIO_printf(bio_err, "SRP terminating with code %d.\n", ret);
622e1051a39Sopenharmony_ci
623e1051a39Sopenharmony_ci    OPENSSL_free(passin);
624e1051a39Sopenharmony_ci    OPENSSL_free(passout);
625e1051a39Sopenharmony_ci    if (ret)
626e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
627e1051a39Sopenharmony_ci    NCONF_free(conf);
628e1051a39Sopenharmony_ci    free_index(db);
629e1051a39Sopenharmony_ci    release_engine(e);
630e1051a39Sopenharmony_ci    return ret;
631e1051a39Sopenharmony_ci}
632