Tools for migration of cyrus-sasl from BerkeleyDB to GDBM

This commit is contained in:
Dmitry Belyavskiy 2021-05-03 16:37:22 +02:00
parent cfd0a1d04b
commit c91728d8af
3 changed files with 994 additions and 4 deletions

View File

@ -0,0 +1,411 @@
diff -Nru cyrus-sasl-2.1.27/tests/runtests.py cyrus-sasl-2.1.27-beldmit/tests/runtests.py
--- cyrus-sasl-2.1.27/tests/runtests.py 2020-12-23 14:31:35.564537485 +0100
+++ cyrus-sasl-2.1.27-beldmit/tests/runtests.py 2020-12-23 14:30:46.933219377 +0100
@@ -313,6 +313,99 @@
return err
+def setup_plain(testdir):
+ """ Create sasldb file """
+ sasldbfile = os.path.join(testdir, 'testsasldb.db')
+
+ sasldbenv = {'SASL_PATH': os.path.join(testdir, '../../plugins/.libs'),
+ 'LD_LIBRARY_PATH' : os.path.join(testdir, '../../lib/.libs')}
+
+ passwdprog = os.path.join(testdir, '../../utils/saslpasswd2')
+
+ echo = subprocess.Popen(('echo', '1234567'), stdout=subprocess.PIPE)
+ subprocess.check_call([
+ passwdprog, "-f", sasldbfile, "-c", "test",
+ "-u", "host.realm.test", "-p"
+ ], stdin=echo.stdout, env=sasldbenv, timeout=5)
+
+ return (sasldbfile, sasldbenv)
+
+def plain_test(sasldbfile, sasldbenv):
+ try:
+ srv = subprocess.Popen(["../tests/t_gssapi_srv", "-P", sasldbfile],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, env=sasldbenv)
+ srv.stdout.readline() # Wait for srv to say it is ready
+ cli = subprocess.Popen(["../tests/t_gssapi_cli", "-P", "1234567"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, env=sasldbenv)
+ try:
+ cli.wait(timeout=5)
+ srv.wait(timeout=5)
+ except Exception as e:
+ print("Failed on {}".format(e));
+ cli.kill()
+ srv.kill()
+ if cli.returncode != 0 or srv.returncode != 0:
+ raise Exception("CLI ({}): {} --> SRV ({}): {}".format(
+ cli.returncode, cli.stderr.read().decode('utf-8'),
+ srv.returncode, srv.stderr.read().decode('utf-8')))
+ except Exception as e:
+ print("FAIL: {}".format(e))
+ return 1
+
+ print("PASS: PLAIN CLI({}) SRV({})".format(
+ cli.stdout.read().decode('utf-8').strip(),
+ srv.stdout.read().decode('utf-8').strip()))
+ return 0
+
+def plain_mismatch_test(sasldbfile, sasldbenv):
+ result = "FAIL"
+ try:
+ srv = subprocess.Popen(["../tests/t_gssapi_srv", "-P", sasldbfile],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, env=sasldbenv)
+ srv.stdout.readline() # Wait for srv to say it is ready
+ bindings = base64.b64encode("CLI CBS".encode('utf-8'))
+ cli = subprocess.Popen(["../tests/t_gssapi_cli", "-P", "12345678"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, env=sasldbenv)
+ try:
+ cli.wait(timeout=5)
+ srv.wait(timeout=5)
+ except Exception as e:
+ print("Failed on {}".format(e));
+ cli.kill()
+ srv.kill()
+ if cli.returncode != 0 or srv.returncode != 0:
+ cli_err = cli.stderr.read().decode('utf-8').strip()
+ srv_err = srv.stderr.read().decode('utf-8').strip()
+ if "authentication failure" in srv_err:
+ result = "PASS"
+ raise Exception("CLI ({}): {} --> SRV ({}): {}".format(
+ cli.returncode, cli_err, srv.returncode, srv_err))
+ except Exception as e:
+ print("{}: {}".format(result, e))
+ return 0
+
+ print("FAIL: This test should fail [CLI({}) SRV({})]".format(
+ cli.stdout.read().decode('utf-8').strip(),
+ srv.stdout.read().decode('utf-8').strip()))
+ return 1
+
+def plain_tests(testdir):
+ err = 0
+ sasldbfile, sasldbenv = setup_plain(testdir)
+ #print("DB file: {}, ENV: {}".format(sasldbfile, sasldbenv))
+ print('SASLDB PLAIN:')
+ print(' ', end='')
+ err += plain_test(sasldbfile, sasldbenv)
+
+ print('SASLDB PLAIN PASSWORD MISMATCH:')
+ print(' ', end='')
+ err += plain_mismatch_test(sasldbfile, sasldbenv)
+
+ return err
if __name__ == "__main__":
@@ -329,5 +422,9 @@
err = gssapi_tests(T)
if err != 0:
- print('{} test(s) FAILED'.format(err))
+ print('{} GSSAPI test(s) FAILED'.format(err))
+
+ err = plain_tests(T)
+ if err != 0:
+ print('{} PLAIN test(s) FAILED'.format(err))
sys.exit(-1)
diff -Nru cyrus-sasl-2.1.27/tests/t_gssapi_cli.c cyrus-sasl-2.1.27-beldmit/tests/t_gssapi_cli.c
--- cyrus-sasl-2.1.27/tests/t_gssapi_cli.c 2020-12-23 14:31:35.564537485 +0100
+++ cyrus-sasl-2.1.27-beldmit/tests/t_gssapi_cli.c 2021-01-06 11:26:15.460662537 +0100
@@ -16,6 +16,8 @@
#include <saslplug.h>
#include <saslutil.h>
+const char *testpass = NULL;
+
static int setup_socket(void)
{
struct sockaddr_in addr;
@@ -34,9 +36,60 @@
return sock;
}
+static int get_user(void *context __attribute__((unused)),
+ int id,
+ const char **result,
+ unsigned *len)
+{
+ const char *testuser = "test@host.realm.test";
+
+ if (! result)
+ return SASL_BADPARAM;
+
+ switch (id) {
+ case SASL_CB_USER:
+ case SASL_CB_AUTHNAME:
+ *result = testuser;
+ break;
+ default:
+ return SASL_BADPARAM;
+ }
+
+ if (len) *len = strlen(*result);
+
+ return SASL_OK;
+}
+
+static int get_pass(sasl_conn_t *conn __attribute__((unused)),
+ void *context __attribute__((unused)),
+ int id,
+ sasl_secret_t **psecret)
+{
+ size_t len;
+ static sasl_secret_t *x;
+
+ /* paranoia check */
+ if (! conn || ! psecret || id != SASL_CB_PASS)
+ return SASL_BADPARAM;
+
+ len = strlen(testpass);
+
+ x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
+
+ if (!x) {
+ return SASL_NOMEM;
+ }
+
+ x->len = len;
+ strcpy((char *)x->data, testpass);
+
+ *psecret = x;
+ return SASL_OK;
+}
+
int main(int argc, char *argv[])
{
- sasl_callback_t callbacks[2] = {};
+ sasl_callback_t callbacks[4] = {};
char buf[8192];
const char *chosenmech;
sasl_conn_t *conn;
@@ -49,8 +102,9 @@
const char *sasl_mech = "GSSAPI";
bool spnego = false;
bool zeromaxssf = false;
+ bool plain = false;
- while ((c = getopt(argc, argv, "c:zN")) != EOF) {
+ while ((c = getopt(argc, argv, "c:zNP:")) != EOF) {
switch (c) {
case 'c':
parse_cb(&cb, cb_buf, 256, optarg);
@@ -61,6 +115,10 @@
case 'N':
spnego = true;
break;
+ case 'P':
+ plain = true;
+ testpass = optarg;
+ break;
default:
break;
}
@@ -73,6 +131,12 @@
callbacks[1].id = SASL_CB_LIST_END;
callbacks[1].proc = NULL;
callbacks[1].context = NULL;
+ callbacks[2].id = SASL_CB_LIST_END;
+ callbacks[2].proc = NULL;
+ callbacks[2].context = NULL;
+ callbacks[3].id = SASL_CB_LIST_END;
+ callbacks[3].proc = NULL;
+ callbacks[3].context = NULL;
r = sasl_client_init(callbacks);
if (r != SASL_OK) exit(-1);
@@ -91,6 +155,16 @@
sasl_mech = "GSS-SPNEGO";
}
+ if (plain) {
+ sasl_mech = "PLAIN";
+
+ callbacks[1].id = SASL_CB_AUTHNAME;
+ callbacks[1].proc = (sasl_callback_ft)&get_user;
+
+ callbacks[2].id = SASL_CB_PASS;
+ callbacks[2].proc = (sasl_callback_ft)&get_pass;
+ }
+
if (zeromaxssf) {
/* set all security properties to 0 including maxssf */
sasl_security_properties_t secprops = { 0 };
@@ -99,9 +173,9 @@
r = sasl_client_start(conn, sasl_mech, NULL, &data, &len, &chosenmech);
if (r != SASL_OK && r != SASL_CONTINUE) {
- saslerr(r, "starting SASL negotiation");
- printf("\n%s\n", sasl_errdetail(conn));
- exit(-1);
+ saslerr(r, "starting SASL negotiation");
+ printf("\n%s\n", sasl_errdetail(conn));
+ exit(-1);
}
sd = setup_socket();
@@ -111,11 +185,11 @@
len = 8192;
recv_string(sd, buf, &len, false);
- r = sasl_client_step(conn, buf, len, NULL, &data, &len);
- if (r != SASL_OK && r != SASL_CONTINUE) {
- saslerr(r, "performing SASL negotiation");
- printf("\n%s\n", sasl_errdetail(conn));
- exit(-1);
+ r = sasl_client_step(conn, buf, len, NULL, &data, &len);
+ if (r != SASL_OK && r != SASL_CONTINUE) {
+ saslerr(r, "performing SASL negotiation");
+ printf("\n%s\n", sasl_errdetail(conn));
+ exit(-1);
}
}
diff -Nru cyrus-sasl-2.1.27/tests/t_gssapi_srv.c cyrus-sasl-2.1.27-beldmit/tests/t_gssapi_srv.c
--- cyrus-sasl-2.1.27/tests/t_gssapi_srv.c 2020-12-23 14:31:35.565537492 +0100
+++ cyrus-sasl-2.1.27-beldmit/tests/t_gssapi_srv.c 2021-01-06 11:27:48.373257373 +0100
@@ -1,4 +1,5 @@
-/* Copyright (C) Simo Sorce <simo@redhat.com>
+/* Copyright (C) Simo Sorce <simo@redhat.com>,
+ * Dmitry Belyavskiy <dbelyavs@redhat.com>
* See COPYING file for License */
#include "t_common.h"
@@ -15,6 +16,10 @@
#include <arpa/inet.h>
#include <saslplug.h>
+const char *sasldb_path = NULL,
+ *auxprop_plugin = "sasldb",
+ *pwcheck_method = "auxprop-hashed";
+
static int setup_socket(void)
{
struct sockaddr_in addr;
@@ -45,9 +50,38 @@
return sd;
}
+static int test_getopt(void *context __attribute__((unused)),
+ const char *plugin_name __attribute__((unused)),
+ const char *option,
+ const char **result,
+ unsigned *len)
+{
+ if (sasldb_path && !strcmp(option, "sasldb_path")) {
+ *result = sasldb_path;
+ if (len)
+ *len = (unsigned) strlen(sasldb_path);
+ return SASL_OK;
+ }
+
+ if (sasldb_path && !strcmp(option, "auxprop_plugin")) {
+ *result = auxprop_plugin;
+ if (len)
+ *len = (unsigned) strlen(auxprop_plugin);
+ return SASL_OK;
+ }
+
+ if (sasldb_path && !strcmp(option, "pwcheck_method")) {
+ *result = pwcheck_method;
+ if (len)
+ *len = (unsigned) strlen(pwcheck_method);
+ return SASL_OK;
+ }
+ return SASL_FAIL;
+}
+
int main(int argc, char *argv[])
{
- sasl_callback_t callbacks[2] = {};
+ sasl_callback_t callbacks[3] = {};
char buf[8192];
sasl_conn_t *conn;
const char *data;
@@ -59,8 +93,9 @@
const char *sasl_mech = "GSSAPI";
bool spnego = false;
bool zeromaxssf = false;
+ bool plain = false;
- while ((c = getopt(argc, argv, "c:zN")) != EOF) {
+ while ((c = getopt(argc, argv, "c:zNP:")) != EOF) {
switch (c) {
case 'c':
parse_cb(&cb, cb_buf, 256, optarg);
@@ -71,6 +106,10 @@
case 'N':
spnego = true;
break;
+ case 'P':
+ plain = true;
+ sasldb_path = optarg;
+ break;
default:
break;
}
@@ -81,9 +120,12 @@
callbacks[0].id = SASL_CB_GETPATH;
callbacks[0].proc = (sasl_callback_ft)&getpath;
callbacks[0].context = NULL;
- callbacks[1].id = SASL_CB_LIST_END;
- callbacks[1].proc = NULL;
+ callbacks[1].id = SASL_CB_GETOPT;
+ callbacks[1].proc = (sasl_callback_ft)&test_getopt;
callbacks[1].context = NULL;
+ callbacks[2].id = SASL_CB_LIST_END;
+ callbacks[2].proc = NULL;
+ callbacks[2].context = NULL;
r = sasl_server_init(callbacks, "t_gssapi_srv");
if (r != SASL_OK) exit(-1);
@@ -103,6 +145,10 @@
sasl_mech = "GSS-SPNEGO";
}
+ if (plain) {
+ sasl_mech = "PLAIN";
+ }
+
if (zeromaxssf) {
/* set all security properties to 0 including maxssf */
sasl_security_properties_t secprops = { 0 };
@@ -116,9 +162,9 @@
r = sasl_server_start(conn, sasl_mech, buf, len, &data, &len);
if (r != SASL_OK && r != SASL_CONTINUE) {
- saslerr(r, "starting SASL negotiation");
- printf("\n%s\n", sasl_errdetail(conn));
- exit(-1);
+ saslerr(r, "starting SASL negotiation");
+ printf("\n%s\n", sasl_errdetail(conn));
+ exit(-1);
}
while (r == SASL_CONTINUE) {
@@ -126,12 +172,12 @@
len = 8192;
recv_string(sd, buf, &len, true);
- r = sasl_server_step(conn, buf, len, &data, &len);
- if (r != SASL_OK && r != SASL_CONTINUE) {
- saslerr(r, "performing SASL negotiation");
- printf("\n%s\n", sasl_errdetail(conn));
- exit(-1);
- }
+ r = sasl_server_step(conn, buf, len, &data, &len);
+ if (r != SASL_OK && r != SASL_CONTINUE) {
+ saslerr(r, "performing SASL negotiation");
+ printf("\n%s\n", sasl_errdetail(conn));
+ exit(-1);
+ }
}
if (r != SASL_OK) exit(-1);

View File

@ -0,0 +1,564 @@
diff -up cyrus-sasl-2.1.27/configure.ac.frombdb cyrus-sasl-2.1.27/configure.ac
--- cyrus-sasl-2.1.27/configure.ac.frombdb 2021-04-28 15:36:37.313675329 +0200
+++ cyrus-sasl-2.1.27/configure.ac 2021-04-28 15:36:37.320675385 +0200
@@ -1091,6 +1091,9 @@ AC_SUBST(SASL_STATIC_SRCS)
AC_SUBST(SASL_STATIC_OBJS)
AC_SUBST(SASL_STATIC_LIBS)
+CYRUS_BERKELEY_DB_STATIC_LIB()
+AC_SUBST(BDB_STATIC_LIBADD)
+
AC_ARG_WITH(plugindir, [ --with-plugindir=DIR set the directory where plugins will
be found [[LIBDIR/sasl2]] ],
plugindir=$withval,
diff -up cyrus-sasl-2.1.27/m4/berkdb.m4.frombdb cyrus-sasl-2.1.27/m4/berkdb.m4
--- cyrus-sasl-2.1.27/m4/berkdb.m4.frombdb 2016-01-29 18:35:35.000000000 +0100
+++ cyrus-sasl-2.1.27/m4/berkdb.m4 2021-04-28 15:36:37.320675385 +0200
@@ -286,3 +286,25 @@ AC_DEFUN([CYRUS_BERKELEY_DB_CHK],
CPPFLAGS=$cmu_save_CPPFLAGS
])
+
+AC_DEFUN([CYRUS_BERKELEY_DB_STATIC_LIB],
+[
+ BDB_SAVE_LDFLAGS=$LDFLAGS
+
+ saved_LIBS=$LIBS
+ for dbname in /usr/lib/libdb-5.3.a \
+ /usr/lib64/libdb-5.3.a
+ do
+ LIBS="$saved_LIBS $dbname -lpthread"
+ AC_TRY_LINK([#include <stdio.h>
+#include <db.h>],
+ [db_create(NULL, NULL, 0);],
+ BDB_STATIC_LIBADD="$dbname -lpthread"; dblib="berkeley";
+ dblib="no")
+ if test "$dblib" = "berkeley"; then break; fi
+ done
+ LIBS=$saved_LIBS
+
+ LDFLAGS=$BDB_SAVE_LDFLAGS
+ BDB_STATIC_LIBADD="$dbname -lpthread"
+])
diff -up cyrus-sasl-2.1.27/m4/sasldb.m4.frombdb cyrus-sasl-2.1.27/m4/sasldb.m4
--- cyrus-sasl-2.1.27/m4/sasldb.m4.frombdb 2017-07-13 20:45:19.000000000 +0200
+++ cyrus-sasl-2.1.27/m4/sasldb.m4 2021-04-28 15:36:37.321675394 +0200
@@ -111,7 +111,7 @@ AC_MSG_RESULT($dblib)
SASL_DB_BACKEND="db_${dblib}.lo"
SASL_DB_BACKEND_STATIC="db_${dblib}.o allockey.o"
SASL_DB_BACKEND_STATIC_SRCS="\$(top_srcdir)/sasldb/db_${dblib}.c \$(top_srcdir)/sasldb/allockey.c"
-SASL_DB_UTILS="saslpasswd2 sasldblistusers2"
+SASL_DB_UTILS="cyrusbdb2current saslpasswd2 sasldblistusers2"
SASL_DB_MANS="saslpasswd2.8 sasldblistusers2.8"
case "$dblib" in
diff -up cyrus-sasl-2.1.27/sasldb/db_gdbm.c.frombdb cyrus-sasl-2.1.27/sasldb/db_gdbm.c
--- cyrus-sasl-2.1.27/sasldb/db_gdbm.c.frombdb 2021-04-28 15:49:23.729883976 +0200
+++ cyrus-sasl-2.1.27/sasldb/db_gdbm.c 2021-04-28 15:51:52.107086685 +0200
@@ -99,6 +99,9 @@ int _sasldb_getdata(const sasl_utils_t *
}
db = gdbm_open((char *)path, 0, GDBM_READER, S_IRUSR | S_IWUSR, NULL);
if (! db) {
+ utils->log(conn, SASL_LOG_ERR,
+ "SASL error opening password file. "
+ "Have you performed the migration from db2 using cyrusbdb2current?\n");
utils->seterror(cntxt, 0, "Could not open %s: gdbm_errno=%d",
path, gdbm_errno);
result = SASL_FAIL;
@@ -186,7 +189,8 @@ int _sasldb_putdata(const sasl_utils_t *
if (! db) {
utils->log(conn, SASL_LOG_ERR,
"SASL error opening password file. "
- "Do you have write permissions?\n");
+ "Do you have write permissions?\n"
+ "Have you performed the migration from db2 using cyrusbdb2current?\n");
utils->seterror(conn, 0, "Could not open %s for write: gdbm_errno=%d",
path, gdbm_errno);
result = SASL_FAIL;
@@ -298,6 +302,9 @@ sasldb_handle _sasldb_getkeyhandle(const
db = gdbm_open((char *)path, 0, GDBM_READER, S_IRUSR | S_IWUSR, NULL);
if(!db) {
+ utils->log(conn, SASL_LOG_ERR,
+ "SASL error opening password file. "
+ "Have you performed the migration from db2 using cyrusbdb2current?\n");
utils->seterror(conn, 0, "Could not open %s: gdbm_errno=%d",
path, gdbm_errno);
return NULL;
diff -up cyrus-sasl-2.1.27/utils/cyrusbdb2current.8.frombdb cyrus-sasl-2.1.27/utils/cyrusbdb2current.8
--- cyrus-sasl-2.1.27/utils/cyrusbdb2current.8.frombdb 2021-04-28 15:36:37.321675394 +0200
+++ cyrus-sasl-2.1.27/utils/cyrusbdb2current.8 2021-04-28 15:36:37.321675394 +0200
@@ -0,0 +1,159 @@
+.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. \*(C+ will
+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "CYRUSBDB2CURRENT 1"
+.TH CYRUSBDB2CURRENT 1 "2021-04-28" "perl v5.30.3" "User Contributed Perl Documentation"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+cyrusbdb2current \- command\-line utility converting the SASLDB database from
+BerkeleyDB to the database format currently used bys sasldb.
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+cyrusbdb2current <sasldb_old_path> <sasldb_new_path>
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBcyrusbdb2current\fR converts the current sasldb database from BerkeleyDB format to the
+currently used database format. It is \fB\s-1STRONGLY RECOMMENDED\s0\fR to make a backup
+of the current database before the conversion.
+.PP
+We expect that the old path is \fB/etc/sasldb2\fR and the new one is
+\&\fB/etc/sasl2/sasldb2\fR
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fBsaslpasswd2\fR\|(8)
+.PP
+rfc4422 \- Simple Authentication and Security Layer (\s-1SASL\s0)
diff -up cyrus-sasl-2.1.27/utils/cyrusbdb2current.c.frombdb cyrus-sasl-2.1.27/utils/cyrusbdb2current.c
--- cyrus-sasl-2.1.27/utils/cyrusbdb2current.c.frombdb 2021-04-28 15:36:37.321675394 +0200
+++ cyrus-sasl-2.1.27/utils/cyrusbdb2current.c 2021-04-28 15:36:37.321675394 +0200
@@ -0,0 +1,282 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include "../sasldb/sasldb.h"
+
+/* Cheating to make the utils work out right */
+extern const sasl_utils_t *sasl_global_utils;
+sasl_conn_t *globalconn;
+
+typedef void *listcb_t(const char *, const char *, const char *,
+ const char *, unsigned);
+
+void listusers_cb(const char *authid, const char *realm,
+ const char *propName, const char *secret,
+ unsigned seclen)
+{
+ if (!authid || !propName || !realm) {
+ fprintf(stderr,"userlist callback has bad param");
+ return;
+ }
+
+ /* the entries that just say the mechanism exists */
+ if (strlen(authid)==0) return;
+
+ printf("Converting: %s@%s (%s)...",authid,realm,propName);
+
+ _sasldb_putdata(sasl_global_utils, globalconn,
+ authid, realm, propName,
+ secret, seclen);
+
+ printf("ok\n");
+}
+
+/*
+ * List all users in database
+ */
+
+#include <db.h>
+
+#define DB_VERSION_FULL ((DB_VERSION_MAJOR << 24) | (DB_VERSION_MINOR << 16) | DB_VERSION_PATCH)
+/*
+ * Open the database
+ *
+ */
+static int berkeleydb_open(const char *path,DB **mbdb)
+{
+ int ret;
+
+#if DB_VERSION_FULL < 0x03000000
+ ret = db_open(path, DB_HASH, DB_CREATE, 0664, NULL, NULL, mbdb);
+#else /* DB_VERSION_FULL < 0x03000000 */
+ ret = db_create(mbdb, NULL, 0);
+ if (ret == 0 && *mbdb != NULL)
+ {
+#if DB_VERSION_FULL >= 0x04010000
+ ret = (*mbdb)->open(*mbdb, NULL, path, NULL, DB_HASH, DB_CREATE, 0664);
+#else
+ ret = (*mbdb)->open(*mbdb, path, NULL, DB_HASH, DB_CREATE, 0664);
+#endif
+ if (ret != 0)
+ {
+ (void) (*mbdb)->close(*mbdb, 0);
+ *mbdb = NULL;
+ }
+ }
+#endif /* DB_VERSION_FULL < 0x03000000 */
+
+ if (ret != 0) {
+ fprintf(stderr,"Error opening password file %s\n", path);
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+}
+
+/*
+ * Close the database
+ *
+ */
+
+static void berkeleydb_close(DB *mbdb)
+{
+ int ret;
+
+ ret = mbdb->close(mbdb, 0);
+ if (ret!=0) {
+ fprintf(stderr,"error closing sasldb: %s",
+ db_strerror(ret));
+ }
+}
+
+int listusers(const char *path, listcb_t *cb)
+{
+ int result;
+ DB *mbdb = NULL;
+ DBC *cursor;
+ DBT key, data;
+
+ /* open the db */
+ result=berkeleydb_open(path, &mbdb);
+ if (result!=SASL_OK) goto cleanup;
+
+ /* make cursor */
+#if DB_VERSION_FULL < 0x03060000
+ result = mbdb->cursor(mbdb, NULL,&cursor);
+#else
+ result = mbdb->cursor(mbdb, NULL,&cursor, 0);
+#endif /* DB_VERSION_FULL < 0x03060000 */
+
+ if (result!=0) {
+ fprintf(stderr,"Making cursor failure: %s\n",db_strerror(result));
+ result = SASL_FAIL;
+ goto cleanup;
+ }
+
+ memset(&key,0, sizeof(key));
+ memset(&data,0,sizeof(data));
+
+ /* loop thru */
+ result = cursor->c_get(cursor, &key, &data,
+ DB_FIRST);
+
+ while (result != DB_NOTFOUND)
+ {
+ char *authid;
+ char *realm;
+ char *tmp;
+ unsigned int len;
+ char prop[1024];
+ int numnulls = 0;
+ unsigned int lup;
+
+ /* make sure there are exactly 2 null's */
+ for (lup=0;lup<key.size;lup++)
+ if (((char *)key.data)[lup]=='\0')
+ numnulls++;
+
+ if (numnulls != 2) {
+ fprintf(stderr,"warning: probable database corruption\n");
+ result = cursor->c_get(cursor, &key, &data, DB_NEXT);
+ continue;
+ }
+
+ authid = key.data;
+ realm = authid + strlen(authid)+1;
+ tmp = realm + strlen(realm)+1;
+ len = key.size - (tmp - authid);
+
+ /* make sure we have enough space of prop */
+ if (len >=sizeof(prop)) {
+ fprintf(stderr,"warning: absurdly long prop name\n");
+ result = cursor->c_get(cursor, &key, &data, DB_NEXT);
+ continue;
+ }
+
+ memcpy(prop, tmp, key.size - (tmp - ((char *)key.data)));
+ prop[key.size - (tmp - ((char *)key.data))] = '\0';
+
+ if (*authid) {
+ /* don't check return values */
+ cb(authid,realm,prop,data.data,data.size);
+ }
+
+ result = cursor->c_get(cursor, &key, &data, DB_NEXT);
+ }
+
+ if (result != DB_NOTFOUND) {
+ fprintf(stderr,"failure: %s\n",db_strerror(result));
+ result = SASL_FAIL;
+ goto cleanup;
+ }
+
+ result = cursor->c_close(cursor);
+ if (result != 0) {
+ result = SASL_FAIL;
+ goto cleanup;
+ }
+
+ result = SASL_OK;
+
+ cleanup:
+
+ if (mbdb != NULL) berkeleydb_close(mbdb);
+ return result;
+}
+
+
+char *db = NULL, *db_new=NULL;
+
+int good_getopt(void *context __attribute__((unused)),
+ const char *plugin_name __attribute__((unused)),
+ const char *option,
+ const char **result,
+ unsigned *len)
+{
+ if (db_new && !strcmp(option, "sasldb_path")) {
+ *result = db_new;
+ if (len)
+ *len = strlen(db_new);
+ return SASL_OK;
+ }
+
+ return SASL_FAIL;
+}
+
+static struct sasl_callback goodsasl_cb[] = {
+ { SASL_CB_GETOPT, (int (*)(void))&good_getopt, NULL },
+ { SASL_CB_LIST_END, NULL, NULL }
+};
+
+int main(int argc, char **argv)
+{
+ int result;
+ FILE *f;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: cyrusbdb2current old_sasldb new_sasldb\n");
+ fprintf(stderr, "old_sasldb is presumably /etc/sasldb2\n");
+ fprintf(stderr, "new_sasldb is presumably /etc/sasl2/sasldb2\n");
+ return 1;
+ }
+
+ db = argv[1];
+ db_new = argv[2];
+
+ if (strcmp(db, db_new) == 0) {
+ fprintf(stderr, "Old and new files should be different\n");
+ return 1;
+ }
+
+
+ f = fopen(db_new, "rb");
+ if (f != NULL) {
+ fprintf(stderr, "The specified target file %s already exists\n", db_new);
+ fclose(f);
+ return 1;
+ }
+
+ result = sasl_server_init(goodsasl_cb, "dbconverter");
+ if (result != SASL_OK) {
+ fprintf(stderr, "couldn't init saslv2\n");
+ return 1;
+ }
+
+ result = sasl_server_new("sasldb",
+ "localhost",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ &globalconn);
+ if (result != SASL_OK) {
+ fprintf(stderr, "couldn't create globalconn\n");
+ return 1;
+ }
+
+ if(_sasl_check_db(sasl_global_utils,globalconn) != SASL_OK) {
+ fprintf(stderr, "target DB %s is not OK\n", db_new);
+ return 1;
+ }
+
+ printf("\nThis program will take the sasldb file specified on the\n"
+ "command line and convert it to a new sasldb specified\n"
+ "on the command line. It is STRONGLY RECOMMENDED that you\n"
+ "backup sasldb before allowing this program to run\n\n"
+ "We are going to convert %s and our output will be in %s\n\n"
+ "Press return to continue\n", db, db_new);
+
+ getchar();
+
+ listusers(db, (listcb_t *) &listusers_cb);
+
+ sasl_dispose(&globalconn);
+ sasl_done();
+
+ exit(0);
+}
diff -up cyrus-sasl-2.1.27/utils/Makefile.am.frombdb cyrus-sasl-2.1.27/utils/Makefile.am
--- cyrus-sasl-2.1.27/utils/Makefile.am.frombdb 2018-10-05 16:40:16.000000000 +0200
+++ cyrus-sasl-2.1.27/utils/Makefile.am 2021-04-28 15:36:37.321675394 +0200
@@ -46,14 +46,14 @@ all_sasl_libs = ../lib/libsasl2.la $(SAS
all_sasl_static_libs = ../lib/.libs/libsasl2.a $(SASL_DB_LIB) $(LIB_SOCKET) $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(SASL_KRB_LIB) $(LIB_DES) $(PLAIN_LIBS) $(SRP_LIBS) $(LIB_MYSQL) $(LIB_PGSQL) $(LIB_SQLITE)
sbin_PROGRAMS = @SASL_DB_UTILS@ @SMTPTEST_PROGRAM@ pluginviewer
-EXTRA_PROGRAMS = saslpasswd2 sasldblistusers2 testsuite testsuitestatic smtptest pluginviewer
+EXTRA_PROGRAMS = saslpasswd2 sasldblistusers2 testsuite testsuitestatic smtptest pluginviewer cyrusbdb2current
noinst_PROGRAMS = dbconverter-2
if NO_SASL_DB_MANS
man_MANS =
else
-man_MANS = saslpasswd2.8 sasldblistusers2.8 pluginviewer.8
+man_MANS = saslpasswd2.8 sasldblistusers2.8 pluginviewer.8 cyrusbdb2current.8
endif
saslpasswd2_LDADD = ../sasldb/libsasldb.la $(all_sasl_libs)
@@ -63,6 +63,7 @@ sasldblistusers2_SOURCES = sasldblistuse
dbconverter_2_LDADD = ../sasldb/libsasldb.la $(all_sasl_libs)
pluginviewer_LDADD = $(all_sasl_libs)
pluginviewer_SOURCES = pluginviewer.c
+cyrusbdb2current_LDADD = ../sasldb/libsasldb.la @BDB_STATIC_LIBADD@ $(all_sasl_libs)
testsuite_LDADD = $(all_sasl_libs) @DMALLOC_LIBS@

View File

@ -4,6 +4,7 @@
%global _plugindir2 %{_libdir}/sasl2
%global bootstrap_cyrus_sasl 0
%global gdbm_db_file /etc/sasl2/sasldb2
Summary: The Cyrus SASL library
Name: cyrus-sasl
@ -41,15 +42,21 @@ Patch104: cyrus-sasl-2.1.27-Emit-debug-log-only-in-case-of-errors.patch
Patch105: cyrus-sasl-2.1.27-fix-for-autoconf270.patch
#https://github.com/simo5/cyrus-sasl/commit/ebd2387f06c84c7f9aac3167ec041bb01e5c6e48
Patch106: cyrus-sasl-2.1.27-nostrncpy.patch
# Upstream PR: https://github.com/cyrusimap/cyrus-sasl/pull/635
Patch107: cyrus-sasl-2.1.27-Add-basic-test-plain-auth.patch
#Migration tool should be removed from Fedora 36
Patch108: cyrus-sasl-2.1.27-Migration-from-BerkeleyDB.patch
Patch500: cyrus-sasl-2.1.27-coverity.patch
BuildRequires: autoconf, automake, libtool, gdbm-devel, groff
BuildRequires: krb5-devel >= 1.2.2, openssl-devel, pam-devel, pkgconfig
BuildRequires: mariadb-connector-c-devel, libpq-devel, zlib-devel
BuildRequires: libdb-devel
%if ! %{bootstrap_cyrus_sasl}
BuildRequires: openldap-devel
%endif
#build reqs for migration from BerkeleyDB
#should be removed from RHEL10
BuildRequires: libdb-devel-static
#build reqs for make check
BuildRequires: python3 nss_wrapper socket_wrapper krb5-server
BuildRequires: make
@ -171,6 +178,8 @@ the GS2 authentication scheme.
%patch104 -p1 -b .nolog
%patch105 -p1 -b .autoconf270
%patch106 -p1 -b .nostrncpy
%patch107 -p1 -b .plaintests
%patch108 -p1 -b .frombdb
%patch500 -p1 -b .coverity
@ -232,8 +241,8 @@ echo "$LDFLAGS"
--enable-gssapi${krb5_prefix:+=${krb5_prefix}} \
--with-gss_impl=mit \
--with-rc4 \
--with-dblib=berkeley \
--with-bdb=db \
--with-dblib=gdbm \
--with-dbpath=%{gdbm_db_file} \
--with-saslauthd=/run/saslauthd --without-pwcheck \
%if ! %{bootstrap_cyrus_sasl}
--with-ldap \
@ -275,6 +284,8 @@ install -m755 -d $RPM_BUILD_ROOT%{_bindir}
install -m755 sample/client $RPM_BUILD_ROOT%{_bindir}/sasl2-sample-client
./libtool --mode=install \
install -m755 sample/server $RPM_BUILD_ROOT%{_bindir}/sasl2-sample-server
#Migration tool should be removed from RHEL10
mv $RPM_BUILD_ROOT%{_sbindir}/cyrusbdb2current $RPM_BUILD_ROOT%{_bindir}/cyrusbdb2current
./libtool --mode=install \
install -m755 saslauthd/testsaslauthd $RPM_BUILD_ROOT%{_sbindir}/testsaslauthd
@ -342,6 +353,7 @@ getent passwd %{username} >/dev/null || useradd -r -g %{username} -d %{homedir}
%{_plugindir2}/*sasldb*.so*
%{_sbindir}/saslpasswd2
%{_sbindir}/sasldblistusers2
%{_bindir}/cyrusbdb2current
%files plain
%{_plugindir2}/*plain*.so*
@ -382,7 +394,10 @@ getent passwd %{username} >/dev/null || useradd -r -g %{username} -d %{homedir}
%changelog
* Mon May 03 2021 Dmitry Belyavskiy <dbelyavs@redhat.com> - 2.1.27-11
- rebuilt
- Fix some coverity issues
- Set default sasldb database to GDBM instead of BerkeleyDB
- Add the migration tool from BerkeleyDB
- Add some PLAIN auth tests
* Tue Apr 06 2021 Simo Sorce <simo@redhat.com> - 2.1.27-10
- Fix issues with autoconf 2.70+