From 829998b19b30e5f71c4438598d92afc93a9f0162 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 21 Feb 2018 15:32:07 +0100 Subject: [PATCH] Apply sane LDAP settings to C code Common LDAP code from ipa-getkeytab and ipa-join are moved to libutil.a. The common ipa_ldap_init() and ipa_tls_ssl_init() set the same options as ldap_initialize() Signed-off-by: Christian Heimes Reviewed-By: Florence Blanc-Renaud --- client/Makefile.am | 1 + client/ipa-getkeytab.c | 70 +----------------------- client/ipa-join.c | 37 ++++--------- ipatests/util.py | 3 +- util/Makefile.am | 2 + util/ipa_ldap.c | 118 +++++++++++++++++++++++++++++++++++++++++ util/ipa_ldap.h | 39 ++++++++++++++ 7 files changed, 174 insertions(+), 96 deletions(-) create mode 100644 util/ipa_ldap.c create mode 100644 util/ipa_ldap.h diff --git a/client/Makefile.am b/client/Makefile.am index e354cb41a..e83106123 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -80,6 +80,7 @@ ipa_join_SOURCES = \ $(NULL) ipa_join_LDADD = \ + $(top_builddir)/util/libutil.la \ $(KRB5_LIBS) \ $(LDAP_LIBS) \ $(SASL_LIBS) \ diff --git a/client/ipa-getkeytab.c b/client/ipa-getkeytab.c index 478b500b5..8a7ddd5ab 100644 --- a/client/ipa-getkeytab.c +++ b/client/ipa-getkeytab.c @@ -43,14 +43,8 @@ #include "ipa_krb5.h" #include "ipa_asn1.h" #include "ipa-client-common.h" +#include "ipa_ldap.h" -#define DEFAULT_CA_CERT_FILE "/etc/ipa/ca.crt" - -#define LDAP_SASL_EXTERNAL "EXTERNAL" -#define LDAP_SASL_GSSAPI "GSSAPI" - -#define SCHEMA_LDAP "ldap://" -#define SCHEMA_LDAPS "ldaps://" static int check_sasl_mech(const char *mech) { @@ -178,42 +172,6 @@ static int ipa_server_to_uri(const char *servername, const char *mech, return 0; } -static int ipa_ldap_init(LDAP **ld, const char *ldap_uri) -{ - int rc = 0; - rc = ldap_initialize(ld, ldap_uri); - - return rc; -} - -static int ipa_tls_ssl_init(LDAP *ld, const char *ldap_uri) -{ - int ret = LDAP_SUCCESS; - int tls_hard = LDAP_OPT_X_TLS_HARD; - int tls_demand = LDAP_OPT_X_TLS_DEMAND; - - if (strncmp(ldap_uri, SCHEMA_LDAP, sizeof(SCHEMA_LDAP) - 1) == 0) { - ret = ldap_set_option(ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &tls_demand); - if (ret != LDAP_OPT_SUCCESS) { - fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS_REQUIRE_CERT\n")); - return ret; - } - ret = ldap_start_tls_s(ld, NULL, NULL); - if (ret != LDAP_SUCCESS) { - fprintf(stderr, _("Unable to initialize STARTTLS session\n")); - return ret; - } - } else if (strncmp(ldap_uri, SCHEMA_LDAPS, sizeof(SCHEMA_LDAPS) - 1) == 0) { - ret = ldap_set_option(ld, LDAP_OPT_X_TLS, &tls_hard); - if (ret != LDAP_OPT_SUCCESS) { - fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS\n")); - return ret; - } - } - return ret; - -} - static int ipa_ldap_bind(const char *ldap_uri, krb5_principal bind_princ, const char *bind_dn, const char *bind_pw, const char *mech, const char *ca_cert_file, @@ -221,20 +179,12 @@ static int ipa_ldap_bind(const char *ldap_uri, krb5_principal bind_princ, { char *msg = NULL; struct berval bv; - int version; LDAP *ld; int ret; /* TODO: support referrals ? */ - ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ca_cert_file); - if (ret != LDAP_OPT_SUCCESS) { - fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS_CERTIFICATE\n")); - return ret; - } - ret = ipa_ldap_init(&ld, ldap_uri); if (ret != LDAP_SUCCESS) { - fprintf(stderr, _("Unable to init connection to %s\n"), ldap_uri); return ret; } @@ -243,23 +193,7 @@ static int ipa_ldap_bind(const char *ldap_uri, krb5_principal bind_princ, return LDAP_OPERATIONS_ERROR; } -#ifdef LDAP_OPT_X_SASL_NOCANON - /* Don't do DNS canonicalization */ - ret = ldap_set_option(ld, LDAP_OPT_X_SASL_NOCANON, LDAP_OPT_ON); - if (ret != LDAP_SUCCESS) { - fprintf(stderr, _("Unable to set LDAP_OPT_X_SASL_NOCANON\n")); - goto done; - } -#endif - - version = LDAP_VERSION3; - ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); - if (ret != LDAP_SUCCESS) { - fprintf(stderr, _("Unable to set LDAP_OPT_PROTOCOL_VERSION\n")); - goto done; - } - - ret = ipa_tls_ssl_init(ld, ldap_uri); + ret = ipa_tls_ssl_init(ld, ldap_uri, ca_cert_file); if (ret != LDAP_OPT_SUCCESS) { goto done; } diff --git a/client/ipa-join.c b/client/ipa-join.c index 837e7ce39..7f406b440 100644 --- a/client/ipa-join.c +++ b/client/ipa-join.c @@ -39,13 +39,12 @@ #include "xmlrpc-c/client.h" #include "ipa-client-common.h" +#include "ipa_ldap.h" #define NAME "ipa-join" #define JOIN_OID "2.16.840.1.113730.3.8.10.3" -#define CAFILE "/etc/ipa/ca.crt" - #define IPA_CONFIG "/etc/ipa/default.conf" char * read_config_file(const char *filename); @@ -200,8 +199,6 @@ callRPC(char * user_agent, static LDAP * connect_ldap(const char *hostname, const char *binddn, const char *bindpw) { LDAP *ld = NULL; - int ssl = LDAP_OPT_X_TLS_HARD; - int version = LDAP_VERSION3; int ret; int ldapdebug = 0; char *uri; @@ -215,40 +212,23 @@ connect_ldap(const char *hostname, const char *binddn, const char *bindpw) { } } - if (ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, CAFILE) != LDAP_OPT_SUCCESS) - goto fail; - ret = asprintf(&uri, "ldaps://%s:636", hostname); if (ret == -1) { fprintf(stderr, _("Out of memory!")); goto fail; } - ret = ldap_initialize(&ld, uri); - free(uri); - if(ret != LDAP_SUCCESS) { - fprintf(stderr, _("Unable to initialize connection to ldap server: %s"), - ldap_err2string(ret)); + ret = ipa_ldap_init(&ld, uri); + if (ret != LDAP_SUCCESS) { goto fail; } - - if (ldap_set_option(ld, LDAP_OPT_X_TLS, &ssl) != LDAP_OPT_SUCCESS) { + ret = ipa_tls_ssl_init(ld, uri, DEFAULT_CA_CERT_FILE); + if (ret != LDAP_SUCCESS) { fprintf(stderr, _("Unable to enable SSL in LDAP\n")); goto fail; } - - /* Don't do DNS canonicalization */ - ret = ldap_set_option(ld, LDAP_OPT_X_SASL_NOCANON, LDAP_OPT_ON); - if (ret != LDAP_SUCCESS) { - fprintf(stderr, _("Unable to set LDAP_OPT_X_SASL_NOCANON\n")); - goto fail; - } - - ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); - if (ret != LDAP_SUCCESS) { - fprintf(stderr, _("Unable to set LDAP version\n")); - goto fail; - } + free(uri); + uri = NULL; if (bindpw) { bindpw_bv.bv_val = discard_const(bindpw); @@ -276,6 +256,9 @@ fail: if (ld != NULL) { ldap_unbind_ext(ld, NULL, NULL); } + if (uri != NULL) { + free(uri); + } return NULL; } diff --git a/ipatests/util.py b/ipatests/util.py index eb66fca39..1cbc7c45f 100644 --- a/ipatests/util.py +++ b/ipatests/util.py @@ -859,7 +859,8 @@ def get_entity_keytab(principal, options=None): yield keytab_filename finally: - os.remove(keytab_filename) + if os.path.isfile(keytab_filename): + os.remove(keytab_filename) @contextmanager diff --git a/util/Makefile.am b/util/Makefile.am index 7869bc92b..be40e8699 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -7,6 +7,8 @@ noinst_LTLIBRARIES = libutil.la libutil_la_SOURCES = ipa_krb5.c \ ipa_krb5.h \ ipa_mspac.h \ + ipa_ldap.c \ + ipa_ldap.h \ ipa_pwd.c \ ipa_pwd.h \ ipa_pwd_ntlm.c diff --git a/util/ipa_ldap.c b/util/ipa_ldap.c new file mode 100644 index 000000000..789ea0d8c --- /dev/null +++ b/util/ipa_ldap.c @@ -0,0 +1,118 @@ +/* Authors: Christian Heimes + * Simo Sorce + * + * Copyright (C) 2018 Red Hat + * see file 'COPYING' for use and warranty information + * + * This program is free software you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define _GNU_SOURCE + +#include + +#include "ipa_ldap.h" + +/** Initialize LDAP context + * + * Initializes an LDAP context for a given LDAP URI. LDAP protocol version + * and SASL canonization are disabled. + * + */ +int ipa_ldap_init(LDAP **ld, const char *ldap_uri) +{ + int ret = 0; + int version = LDAP_VERSION3; + ret = ldap_initialize(ld, ldap_uri); + + if (ret != LDAP_SUCCESS) { + fprintf( + stderr, + _("Unable to initialize connection to ldap server %1$s: %1$s\n"), + ldap_uri, + ldap_err2string(ret) + ); + return ret; + } + + /* StartTLS and other features need LDAP protocol version 3 */ + ret = ldap_set_option(*ld, LDAP_OPT_PROTOCOL_VERSION, &version); + if (ret != LDAP_SUCCESS) { + fprintf(stderr, _("Unable to set LDAP_OPT_PROTOCOL_VERSION\n")); + return ret; + } + +#ifdef LDAP_OPT_X_SASL_NOCANON + /* Don't do DNS canonization */ + ret = ldap_set_option(*ld, LDAP_OPT_X_SASL_NOCANON, LDAP_OPT_ON); + if (ret != LDAP_SUCCESS) { + fprintf(stderr, _("Unable to set LDAP_OPT_X_SASL_NOCANON\n")); + return ret; + } +#endif + + return ret; +} + +/** Configure TLS/SSL and perform StartTLS for ldap:// + * + * The LDAP connection is configured for secure TLS. + * + */ +int ipa_tls_ssl_init(LDAP *ld, const char *ldap_uri, + const char *ca_cert_file) +{ + int ret = LDAP_SUCCESS; + int tls_demand = LDAP_OPT_X_TLS_DEMAND; + int tlsv1_0 = LDAP_OPT_X_TLS_PROTOCOL_TLS1_0; + int newctx = 0; /* client context */ + + if (strncmp(ldap_uri, SCHEMA_LDAPI, sizeof(SCHEMA_LDAPI) - 1) == 0) { + /* Nothing to do for LDAPI */ + return ret; + } + + ret = ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, ca_cert_file); + if (ret != LDAP_OPT_SUCCESS) { + fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS_CACERTFILE\n")); + return ret; + } + /* Require a valid certificate */ + ret = ldap_set_option(ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &tls_demand); + if (ret != LDAP_OPT_SUCCESS) { + fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS_REQUIRE_CERT\n")); + return ret; + } + /* Disable SSLv2 and SSLv3 */ + ret = ldap_set_option(ld, LDAP_OPT_X_TLS_PROTOCOL_MIN, &tlsv1_0); + if (ret != LDAP_OPT_SUCCESS) { + fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS_PROTOCOL_MIN\n")); + return ret; + } + /* Apply TLS settings and create new client context */ + ret = ldap_set_option(ld, LDAP_OPT_X_TLS_NEWCTX, &newctx); + if (ret != LDAP_OPT_SUCCESS) { + fprintf(stderr, _("Unable to set LDAP_OPT_X_TLS_NEWCTX\n")); + return ret; + } + + if (strncmp(ldap_uri, SCHEMA_LDAP, sizeof(SCHEMA_LDAP) - 1) == 0) { + ret = ldap_start_tls_s(ld, NULL, NULL); + if (ret != LDAP_SUCCESS) { + fprintf(stderr, _("Unable to initialize STARTTLS session\n")); + return ret; + } + } + return ret; +} diff --git a/util/ipa_ldap.h b/util/ipa_ldap.h new file mode 100644 index 000000000..2525a7ae2 --- /dev/null +++ b/util/ipa_ldap.h @@ -0,0 +1,39 @@ +/* Authors: Christian Heimes + * Simo Sorce + * + * Copyright (C) 2018 Red Hat + * see file 'COPYING' for use and warranty information + * + * This program is free software you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#define DEFAULT_CA_CERT_FILE "/etc/ipa/ca.crt" + +#define LDAP_SASL_EXTERNAL "EXTERNAL" +#define LDAP_SASL_GSSAPI "GSSAPI" + +#define SCHEMA_LDAPI "ldapi://" +#define SCHEMA_LDAP "ldap://" +#define SCHEMA_LDAPS "ldaps://" + +#ifndef _ +#include +#define _(STRING) gettext(STRING) +#endif + +int ipa_ldap_init(LDAP **ld, const char *ldap_uri); +int ipa_tls_ssl_init(LDAP *ld, const char *ldap_uri, + const char *ca_cert_file);