diff --git a/cyrus-sasl-2.1.27-Add-basic-test-plain-auth.patch b/cyrus-sasl-2.1.27-Add-basic-test-plain-auth.patch new file mode 100644 index 0000000..35903d0 --- /dev/null +++ b/cyrus-sasl-2.1.27-Add-basic-test-plain-auth.patch @@ -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 + #include + ++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 ++/* Copyright (C) Simo Sorce , ++ * Dmitry Belyavskiy + * See COPYING file for License */ + + #include "t_common.h" +@@ -15,6 +16,10 @@ + #include + #include + ++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); diff --git a/cyrus-sasl-2.1.27-Migration-from-BerkeleyDB.patch b/cyrus-sasl-2.1.27-Migration-from-BerkeleyDB.patch new file mode 100644 index 0000000..c026abd --- /dev/null +++ b/cyrus-sasl-2.1.27-Migration-from-BerkeleyDB.patch @@ -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 ++#include ], ++ [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 ++.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 ++ ++#include ++#include ++ ++#include ++#include ++#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 ++ ++#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;lupc_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@ + diff --git a/cyrus-sasl.spec b/cyrus-sasl.spec index 4e97c83..fd3a48e 100644 --- a/cyrus-sasl.spec +++ b/cyrus-sasl.spec @@ -4,11 +4,12 @@ %global _plugindir2 %{_libdir}/sasl2 %global bootstrap_cyrus_sasl 0 +%global gdbm_db_file /etc/sasl2/sasldb2 Summary: The Cyrus SASL library Name: cyrus-sasl Version: 2.1.27 -Release: 10%{?dist} +Release: 11%{?dist} License: BSD with advertising URL: https://www.cyrusimap.org/sasl/ @@ -40,18 +41,23 @@ Patch103: cyrus-sasl-2.1.27-Add-support-for-setting-max-ssf-0-to-GSS-SPNEGO.patc Patch104: cyrus-sasl-2.1.27-Emit-debug-log-only-in-case-of-errors.patch #https://github.com/simo5/cyrus-sasl/commit/ebd2387f06c84c7f9aac3167ec041bb01e5c6e48 Patch105: cyrus-sasl-2.1.27-nostrncpy.patch +#Migration tool should be removed from RHEL10 +Patch106: cyrus-sasl-2.1.27-Migration-from-BerkeleyDB.patch +# Upstream PR: https://github.com/cyrusimap/cyrus-sasl/pull/635 +Patch107: cyrus-sasl-2.1.27-Add-basic-test-plain-auth.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 %{?systemd_requires} Requires(pre): /usr/sbin/useradd /usr/sbin/groupadd Requires(postun): /usr/sbin/userdel /usr/sbin/groupdel @@ -169,6 +175,8 @@ the GS2 authentication scheme. %patch103 -p1 -b .maxssf0 %patch104 -p1 -b .nolog %patch105 -p1 -b .nostrncpy +%patch106 -p1 -b .frombdb +%patch107 -p1 -b .plaintests %patch500 -p1 -b .coverity %build @@ -229,8 +237,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 \ @@ -272,6 +280,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 @@ -339,6 +349,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* @@ -378,6 +389,12 @@ getent passwd %{username} >/dev/null || useradd -r -g %{username} -d %{homedir} %{_sbindir}/sasl2-shared-mechlist %changelog +* Wed Apr 28 2021 Dmitry Belyavskiy - 2.1.27-11 +- Set default sasldb database to GDBM instead of BerkeleyDB +- Add the migration tool from BerkeleyDB +- Add some PLAIN auth tests +- Resolves rhbz#1947971 + * Thu Apr 15 2021 Mohan Boddu - 2.1.27-10 - Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937