diff --git a/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch b/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch new file mode 100644 index 0000000..c7e698e --- /dev/null +++ b/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch @@ -0,0 +1,43 @@ +From 3c93c96eb6ea2abd3869921ee4c89e1a4d9e4c44 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 14 Aug 2018 13:08:52 +0200 +Subject: [PATCH] Fix for issues found by Coverity + +--- + library/adenroll.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 02bd9e3..de2242a 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -1575,7 +1575,7 @@ load_host_keytab (adcli_enroll *enroll) + } + + krb5_free_context (k5); +- return ADCLI_SUCCESS; ++ return res; + } + + typedef struct { +@@ -1756,12 +1756,12 @@ add_principal_to_keytab (adcli_enroll *enroll, + enroll->kvno, &password, enctypes, &salts[*which_salt]); + + free_principal_salts (k5, salts); ++ } + +- if (code != 0) { +- _adcli_err ("Couldn't add keytab entries: %s: %s", +- enroll->keytab_name, krb5_get_error_message (k5, code)); +- return ADCLI_ERR_FAIL; +- } ++ if (code != 0) { ++ _adcli_err ("Couldn't add keytab entries: %s: %s", ++ enroll->keytab_name, krb5_get_error_message (k5, code)); ++ return ADCLI_ERR_FAIL; + } + + +-- +2.21.0 + diff --git a/SOURCES/0001-Implement-adcli-testjoin.patch b/SOURCES/0001-Implement-adcli-testjoin.patch new file mode 100644 index 0000000..d75cbf2 --- /dev/null +++ b/SOURCES/0001-Implement-adcli-testjoin.patch @@ -0,0 +1,181 @@ +From 6fd99ff6c5dd6ef0be8d942989b1c6dcee3102d9 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 22 Mar 2019 12:37:39 +0100 +Subject: [PATCH] Implement 'adcli testjoin' + +By calling adcli testjoin it will be checked if the host credentials +stored in the keytab are still valid. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1622583 +--- + doc/adcli.xml | 34 +++++++++++++++++++++++ + tools/computer.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ + tools/tools.c | 1 + + tools/tools.h | 4 +++ + 4 files changed, 111 insertions(+) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index af73433..9605b4a 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -43,6 +43,9 @@ + + adcli update + ++ ++ adcli testjoin ++ + + adcli create-user + --domain=domain.example.com +@@ -474,6 +477,37 @@ $ adcli update --login-ccache=/tmp/krbcc_123 + + + ++ ++ Testing if the machine account password is valid ++ ++ adcli testjoin uses the current credentials in ++ the keytab and tries to authenticate with the machine account to the AD ++ domain. If this works the machine account password and the join are ++ still valid. If it fails the machine account password or the whole ++ machine account have to be refreshed with ++ adcli join or adcli update. ++ ++ ++ ++$ adcli testjoin ++ ++ ++ Only the global options not related to authentication are ++ available, additionally you can specify the following options to ++ control how this operation is done. ++ ++ ++ ++ ++ Specify the path to the host keytab where ++ current host credentials are stored and the new ones ++ will be written to. If not specified, the default ++ location will be used, usually ++ /etc/krb5.keytab. ++ ++ ++ ++ + + Creating a User + +diff --git a/tools/computer.c b/tools/computer.c +index 112340e..610ed2b 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -566,6 +566,78 @@ adcli_tool_computer_update (adcli_conn *conn, + return 0; + } + ++int ++adcli_tool_computer_testjoin (adcli_conn *conn, ++ int argc, ++ char *argv[]) ++{ ++ adcli_enroll *enroll; ++ adcli_result res; ++ const char *ktname; ++ int opt; ++ ++ struct option options[] = { ++ { "domain", required_argument, NULL, opt_domain }, ++ { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "host-keytab", required_argument, 0, opt_host_keytab }, ++ { "verbose", no_argument, NULL, opt_verbose }, ++ { "help", no_argument, NULL, 'h' }, ++ { 0 }, ++ }; ++ ++ static adcli_tool_desc usages[] = { ++ { 0, "usage: adcli testjoin" }, ++ { 0 }, ++ }; ++ ++ enroll = adcli_enroll_new (conn); ++ if (enroll == NULL) ++ errx (-1, "unexpected memory problems"); ++ ++ while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { ++ switch (opt) { ++ case 'h': ++ case '?': ++ case ':': ++ adcli_tool_usage (options, usages); ++ adcli_tool_usage (options, common_usages); ++ adcli_enroll_unref (enroll); ++ return opt == 'h' ? 0 : 2; ++ default: ++ parse_option ((Option)opt, optarg, conn, enroll); ++ break; ++ } ++ } ++ ++ /* Force use of a keytab to test the join/machine account password */ ++ adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT); ++ ktname = adcli_enroll_get_keytab_name (enroll); ++ adcli_conn_set_login_keytab_name (conn, ktname ? ktname : ""); ++ ++ res = adcli_enroll_load (enroll); ++ if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); ++ errx (-res, "couldn't lookup domain info from keytab: %s", ++ adcli_get_last_error ()); ++ } ++ ++ res = adcli_conn_connect (conn); ++ if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); ++ errx (-res, "couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ } ++ ++ printf ("Sucessfully validated join to domain %s\n", ++ adcli_conn_get_domain_name (conn)); ++ ++ adcli_enroll_unref (enroll); ++ ++ return 0; ++} + + int + adcli_tool_computer_preset (adcli_conn *conn, +diff --git a/tools/tools.c b/tools/tools.c +index 915130e..c4e2851 100644 +--- a/tools/tools.c ++++ b/tools/tools.c +@@ -55,6 +55,7 @@ struct { + { "info", adcli_tool_info, "Print information about a domain", CONNECTION_LESS }, + { "join", adcli_tool_computer_join, "Join this machine to a domain", }, + { "update", adcli_tool_computer_update, "Update machine membership in a domain", }, ++ { "testjoin", adcli_tool_computer_testjoin, "Test if machine account password is valid", }, + { "preset-computer", adcli_tool_computer_preset, "Pre setup computers accounts", }, + { "reset-computer", adcli_tool_computer_reset, "Reset a computer account", }, + { "delete-computer", adcli_tool_computer_delete, "Delete a computer account", }, +diff --git a/tools/tools.h b/tools/tools.h +index 6c97ccf..8cebbf9 100644 +--- a/tools/tools.h ++++ b/tools/tools.h +@@ -70,6 +70,10 @@ int adcli_tool_computer_update (adcli_conn *conn, + int argc, + char *argv[]); + ++int adcli_tool_computer_testjoin (adcli_conn *conn, ++ int argc, ++ char *argv[]); ++ + int adcli_tool_computer_delete (adcli_conn *conn, + int argc, + char *argv[]); +-- +2.20.1 + diff --git a/SOURCES/0001-Increment-kvno-after-password-change-with-user-creds.patch b/SOURCES/0001-Increment-kvno-after-password-change-with-user-creds.patch new file mode 100644 index 0000000..aeef509 --- /dev/null +++ b/SOURCES/0001-Increment-kvno-after-password-change-with-user-creds.patch @@ -0,0 +1,32 @@ +From 5cf1723c308e21cdbe9b98ed2aaa42cb997456fb Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 15 Mar 2019 14:31:12 +0100 +Subject: [PATCH] Increment kvno after password change with user creds + +Originally only the host credential part was fixed in the context of +https://bugs.freedesktop.org/show_bug.cgi?id=91185. This patch adds the +fix to the case when user credentials are used. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1642546 +--- + library/adenroll.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/library/adenroll.c b/library/adenroll.c +index e02f403..58362c2 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -1057,6 +1057,10 @@ set_password_with_user_creds (adcli_enroll *enroll) + #endif + } else { + _adcli_info ("Set computer password"); ++ if (enroll->kvno > 0) { ++ enroll->kvno++; ++ _adcli_info ("kvno incremented to %d", enroll->kvno); ++ } + res = ADCLI_SUCCESS; + } + +-- +2.20.1 + diff --git a/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch b/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch new file mode 100644 index 0000000..ad69b70 --- /dev/null +++ b/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch @@ -0,0 +1,80 @@ +From 341974aae7d0755fc32a0b7e2b34d8e1ef60d195 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 20 Dec 2018 21:05:35 +0100 +Subject: [PATCH 1/4] adenroll: make sure only allowed enctypes are used in + FIPS mode + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1717355 +--- + library/adenroll.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 52aa8a8..f617f28 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -41,11 +41,19 @@ + #include + #include + #include ++#include ++#include + + #ifndef SAMBA_DATA_TOOL + #define SAMBA_DATA_TOOL "/usr/bin/net" + #endif + ++static krb5_enctype v60_later_enctypes_fips[] = { ++ ENCTYPE_AES256_CTS_HMAC_SHA1_96, ++ ENCTYPE_AES128_CTS_HMAC_SHA1_96, ++ 0 ++}; ++ + static krb5_enctype v60_later_enctypes[] = { + ENCTYPE_AES256_CTS_HMAC_SHA1_96, + ENCTYPE_AES128_CTS_HMAC_SHA1_96, +@@ -2594,6 +2602,28 @@ adcli_enroll_set_keytab_name (adcli_enroll *enroll, + enroll->keytab_name_is_krb5 = 0; + } + ++#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled" ++ ++static bool adcli_fips_enabled (void) ++{ ++ int fd; ++ ssize_t len; ++ char buf[8]; ++ ++ fd = open (PROC_SYS_FIPS, O_RDONLY); ++ if (fd != -1) { ++ len = read (fd, buf, sizeof (buf)); ++ close (fd); ++ /* Assume FIPS in enabled if PROC_SYS_FIPS contains a ++ * non-0 value. */ ++ if ( ! (len == 2 && buf[0] == '0' && buf[1] == '\n')) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ + krb5_enctype * + adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll) + { +@@ -2602,7 +2632,11 @@ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll) + return enroll->keytab_enctypes; + + if (adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID)) +- return v60_later_enctypes; ++ if (adcli_fips_enabled ()) { ++ return v60_later_enctypes_fips; ++ } else { ++ return v60_later_enctypes; ++ } + else + return v51_earlier_enctypes; + } +-- +2.21.0 + diff --git a/SOURCES/0001-adutil-add-_adcli_strv_add_unique.patch b/SOURCES/0001-adutil-add-_adcli_strv_add_unique.patch new file mode 100644 index 0000000..f49f5f8 --- /dev/null +++ b/SOURCES/0001-adutil-add-_adcli_strv_add_unique.patch @@ -0,0 +1,134 @@ +From 85d127fd52a8469f9f3ce0d1130fe17e756fdd75 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 16 Nov 2018 13:32:33 +0100 +Subject: [PATCH 1/2] adutil: add _adcli_strv_add_unique + +_adcli_strv_add_unique checks is the new value already exists in the +strv before adding it. Check can be done case-sensitive or not. + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/16 +--- + library/adprivate.h | 5 ++++ + library/adutil.c | 65 ++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 61 insertions(+), 9 deletions(-) + +diff --git a/library/adprivate.h b/library/adprivate.h +index bc9df6d..0806430 100644 +--- a/library/adprivate.h ++++ b/library/adprivate.h +@@ -111,6 +111,11 @@ char ** _adcli_strv_add (char **strv, + char *string, + int *length) GNUC_WARN_UNUSED; + ++char ** _adcli_strv_add_unique (char **strv, ++ char *string, ++ int *length, ++ bool case_sensitive) GNUC_WARN_UNUSED; ++ + void _adcli_strv_remove_unsorted (char **strv, + const char *string, + int *length); +diff --git a/library/adutil.c b/library/adutil.c +index 17d2caa..76ea158 100644 +--- a/library/adutil.c ++++ b/library/adutil.c +@@ -221,6 +221,34 @@ _adcli_strv_add (char **strv, + return seq_push (strv, length, string); + } + ++static int ++_adcli_strv_has_ex (char **strv, ++ const char *str, ++ int (* compare) (const char *match, const char*value)) ++{ ++ int i; ++ ++ for (i = 0; strv && strv[i] != NULL; i++) { ++ if (compare (strv[i], str) == 0) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++char ** ++_adcli_strv_add_unique (char **strv, ++ char *string, ++ int *length, ++ bool case_sensitive) ++{ ++ if (_adcli_strv_has_ex (strv, string, case_sensitive ? strcmp : strcasecmp) == 1) { ++ return strv; ++ } ++ ++ return _adcli_strv_add (strv, string, length); ++} ++ + #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) + + void +@@ -241,19 +269,11 @@ _adcli_strv_remove_unsorted (char **strv, + (seq_compar)strcasecmp, free); + } + +- + int + _adcli_strv_has (char **strv, + const char *str) + { +- int i; +- +- for (i = 0; strv && strv[i] != NULL; i++) { +- if (strcmp (strv[i], str) == 0) +- return 1; +- } +- +- return 0; ++ return _adcli_strv_has_ex (strv, str, strcmp); + } + + void +@@ -704,6 +724,32 @@ test_strv_add_free (void) + _adcli_strv_free (strv); + } + ++static void ++test_strv_add_unique_free (void) ++{ ++ char **strv = NULL; ++ ++ strv = _adcli_strv_add_unique (strv, strdup ("one"), NULL, false); ++ strv = _adcli_strv_add_unique (strv, strdup ("one"), NULL, false); ++ strv = _adcli_strv_add_unique (strv, strdup ("two"), NULL, false); ++ strv = _adcli_strv_add_unique (strv, strdup ("two"), NULL, false); ++ strv = _adcli_strv_add_unique (strv, strdup ("tWo"), NULL, false); ++ strv = _adcli_strv_add_unique (strv, strdup ("three"), NULL, false); ++ strv = _adcli_strv_add_unique (strv, strdup ("three"), NULL, false); ++ strv = _adcli_strv_add_unique (strv, strdup ("TWO"), NULL, true); ++ ++ assert_num_eq (_adcli_strv_len (strv), 4); ++ ++ assert_str_eq (strv[0], "one"); ++ assert_str_eq (strv[1], "two"); ++ assert_str_eq (strv[2], "three"); ++ assert_str_eq (strv[3], "TWO"); ++ assert (strv[4] == NULL); ++ ++ _adcli_strv_free (strv); ++} ++ ++ + static void + test_strv_dup (void) + { +@@ -856,6 +902,7 @@ main (int argc, + char *argv[]) + { + test_func (test_strv_add_free, "/util/strv_add_free"); ++ test_func (test_strv_add_unique_free, "/util/strv_add_unique_free"); + test_func (test_strv_dup, "/util/strv_dup"); + test_func (test_strv_count, "/util/strv_count"); + test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime"); +-- +2.20.1 + diff --git a/SOURCES/0001-create-user-add-nis-domain-option.patch b/SOURCES/0001-create-user-add-nis-domain-option.patch new file mode 100644 index 0000000..32b0ca9 --- /dev/null +++ b/SOURCES/0001-create-user-add-nis-domain-option.patch @@ -0,0 +1,71 @@ +From 1457b4a7623a8ae58fb8d6a652d1cc44904b8863 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 18 Mar 2019 11:02:57 +0100 +Subject: [PATCH 1/2] create-user: add nis-domain option + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/2 +--- + doc/adcli.xml | 8 ++++++++ + tools/entry.c | 6 ++++++ + 2 files changed, 14 insertions(+) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 4722c3a..18620c0 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -531,6 +531,14 @@ $ adcli create-user Fry --domain=domain.example.com \ + the new created user account, which should be the user's + numeric primary user id. + ++ ++ ++ Set the msSFU30NisDomain attribute of ++ the new created user account, which should be the user's ++ NIS domain is the NIS/YP service of Active Directory's Services for Unix (SFU) ++ are used. This is needed to let the 'UNIX attributes' tab of older Active ++ Directoy versions show the set UNIX specific attributes. ++ + + + +diff --git a/tools/entry.c b/tools/entry.c +index 7b6a200..69ce62c 100644 +--- a/tools/entry.c ++++ b/tools/entry.c +@@ -52,6 +52,7 @@ typedef enum { + opt_unix_uid, + opt_unix_gid, + opt_unix_shell, ++ opt_nis_domain, + } Option; + + static adcli_tool_desc common_usages[] = { +@@ -62,6 +63,7 @@ static adcli_tool_desc common_usages[] = { + { opt_unix_uid, "unix uid number" }, + { opt_unix_gid, "unix gid number" }, + { opt_unix_shell, "unix shell" }, ++ { opt_nis_domain, "NIS domain" }, + { opt_domain, "active directory domain name" }, + { opt_domain_realm, "kerberos realm for the domain" }, + { opt_domain_controller, "domain directory server to connect to" }, +@@ -159,6 +161,7 @@ adcli_tool_user_create (adcli_conn *conn, + { "unix-uid", required_argument, NULL, opt_unix_uid }, + { "unix-gid", required_argument, NULL, opt_unix_gid }, + { "unix-shell", required_argument, NULL, opt_unix_shell }, ++ { "nis-domain", required_argument, NULL, opt_nis_domain }, + { "domain-ou", required_argument, NULL, opt_domain_ou }, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, +@@ -200,6 +203,9 @@ adcli_tool_user_create (adcli_conn *conn, + case opt_unix_shell: + adcli_attrs_add (attrs, "loginShell", optarg, NULL); + break; ++ case opt_nis_domain: ++ adcli_attrs_add (attrs, "msSFU30NisDomain", optarg, NULL); ++ break; + case opt_domain_ou: + ou = optarg; + break; +-- +2.20.1 + diff --git a/SOURCES/0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch b/SOURCES/0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch new file mode 100644 index 0000000..dfdf745 --- /dev/null +++ b/SOURCES/0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch @@ -0,0 +1,72 @@ +From 3a84c2469c31967bc22c0490456f07723ef5fc86 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 20 Mar 2019 11:01:50 +0100 +Subject: [PATCH 1/4] ensure_keytab_principals: do not leak memory when called + twice + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187 +--- + library/adenroll.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index d1f746c..48cb4cf 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -413,6 +413,25 @@ ensure_service_principals (adcli_result res, + return res; + } + ++static void enroll_clear_keytab_principals (adcli_enroll *enroll) ++{ ++ krb5_context k5; ++ size_t c; ++ ++ if (enroll->keytab_principals) { ++ k5 = adcli_conn_get_krb5_context (enroll->conn); ++ return_if_fail (k5 != NULL); ++ ++ for (c = 0; enroll->keytab_principals[c] != NULL; c++) ++ krb5_free_principal (k5, enroll->keytab_principals[c]); ++ ++ free (enroll->keytab_principals); ++ enroll->keytab_principals = NULL; ++ } ++ ++ return; ++} ++ + static adcli_result + ensure_keytab_principals (adcli_result res, + adcli_enroll *enroll) +@@ -430,6 +449,7 @@ ensure_keytab_principals (adcli_result res, + k5 = adcli_conn_get_krb5_context (enroll->conn); + return_unexpected_if_fail (k5 != NULL); + ++ enroll_clear_keytab_principals (enroll); + enroll->keytab_principals = calloc (count + 3, sizeof (krb5_principal)); + return_unexpected_if_fail (enroll->keytab_principals != NULL); + at = 0; +@@ -1860,18 +1880,8 @@ static void + enroll_clear_state (adcli_enroll *enroll) + { + krb5_context k5; +- int i; +- +- if (enroll->keytab_principals) { +- k5 = adcli_conn_get_krb5_context (enroll->conn); +- return_if_fail (k5 != NULL); +- +- for (i = 0; enroll->keytab_principals[i] != NULL; i++) +- krb5_free_principal (k5, enroll->keytab_principals[i]); + +- free (enroll->keytab_principals); +- enroll->keytab_principals = NULL; +- } ++ enroll_clear_keytab_principals (enroll); + + if (enroll->keytab) { + k5 = adcli_conn_get_krb5_context (enroll->conn); +-- +2.20.1 + diff --git a/SOURCES/0001-join-always-add-service-principals.patch b/SOURCES/0001-join-always-add-service-principals.patch new file mode 100644 index 0000000..0281dc6 --- /dev/null +++ b/SOURCES/0001-join-always-add-service-principals.patch @@ -0,0 +1,86 @@ +From cd296bf24e7cc56fb8d00bad7e9a56c539894309 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 19 Mar 2019 20:44:36 +0100 +Subject: [PATCH 1/2] join: always add service principals + +If currently --service-name is given during the join only the service +names given by this option are added as service principal names. As a +result the default 'host' service principal name might be missing which +might cause issues e.g. with SSSD and sshd. + +The patch makes sure the default service principals 'host' and +'RestrictedKrbHost' are always added during join. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1644311 +--- + library/adenroll.c | 36 ++++++++++++++++++++++++++++++------ + 1 file changed, 30 insertions(+), 6 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 58362c2..d1f746c 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -288,16 +288,23 @@ ensure_computer_password (adcli_result res, + } + + static adcli_result +-ensure_service_names (adcli_result res, +- adcli_enroll *enroll) ++ensure_default_service_names (adcli_enroll *enroll) + { + int length = 0; + +- if (res != ADCLI_SUCCESS) +- return res; ++ if (enroll->service_names != NULL) { ++ length = seq_count (enroll->service_names); + +- if (enroll->service_names || enroll->service_principals) +- return ADCLI_SUCCESS; ++ /* Make sure there is no entry with an unexpected case. AD ++ * would not care but since the client side is case-sensitive ++ * we should make sure we use the expected spelling. */ ++ seq_remove_unsorted (enroll->service_names, ++ &length, "host", ++ (seq_compar)strcasecmp, free); ++ seq_remove_unsorted (enroll->service_names, ++ &length, "RestrictedKrbHost", ++ (seq_compar)strcasecmp, free); ++ } + + /* The default ones specified by MS */ + enroll->service_names = _adcli_strv_add (enroll->service_names, +@@ -307,6 +314,19 @@ ensure_service_names (adcli_result res, + return ADCLI_SUCCESS; + } + ++static adcli_result ++ensure_service_names (adcli_result res, ++ adcli_enroll *enroll) ++{ ++ if (res != ADCLI_SUCCESS) ++ return res; ++ ++ if (enroll->service_names || enroll->service_principals) ++ return ADCLI_SUCCESS; ++ ++ return ensure_default_service_names (enroll); ++} ++ + static adcli_result + add_service_names_to_service_principals (adcli_enroll *enroll) + { +@@ -2039,6 +2059,10 @@ adcli_enroll_join (adcli_enroll *enroll, + if (res != ADCLI_SUCCESS) + return res; + ++ res = ensure_default_service_names (enroll); ++ if (res != ADCLI_SUCCESS) ++ return res; ++ + res = adcli_enroll_prepare (enroll, flags); + if (res != ADCLI_SUCCESS) + return res; +-- +2.20.1 + diff --git a/SOURCES/0001-library-add-missing-strdup.patch b/SOURCES/0001-library-add-missing-strdup.patch new file mode 100644 index 0000000..378bb3c --- /dev/null +++ b/SOURCES/0001-library-add-missing-strdup.patch @@ -0,0 +1,34 @@ +From a64cce9830c2e9c26e120f671b247ee71b45c888 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 12 Apr 2019 17:31:41 +0200 +Subject: [PATCH] library: add missing strdup + +In add_server_side_service_principals _adcli_strv_add_unique is called +which only adds a string to a list without copying to. Since the +original list will be freed later the value must be copied. + +This issue was introduce with 972f1a2f35829ed89f5353bd204683aa9ad6a2d2 +and hence + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187 +--- + library/adenroll.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 1cce86a..52aa8a8 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -1987,7 +1987,8 @@ add_server_side_service_principals (adcli_enroll *enroll) + _adcli_info ("Checking %s", spn_list[c]); + if (!_adcli_strv_has_ex (enroll->service_principals_to_remove, spn_list[c], strcasecmp)) { + enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, +- spn_list[c], &length, false); ++ strdup (spn_list[c]), ++ &length, false); + assert (enroll->service_principals != NULL); + _adcli_info (" Added %s", spn_list[c]); + } +-- +2.20.1 + diff --git a/SOURCES/0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch b/SOURCES/0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch new file mode 100644 index 0000000..c682c5a --- /dev/null +++ b/SOURCES/0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch @@ -0,0 +1,92 @@ +From 85b835f8258a57e3b23de47a255dddd822d5bfb3 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 15 Mar 2019 17:33:44 +0100 +Subject: [PATCH] library: use getaddrinfo with AI_CANONNAME to find a FQDN + +Currently adcli creates service principals only with a short name if the +hostname of the client is a short name. This would fail is +Kerberos/GSSAPI clients will use the fully-qualified domain name (FQDN) +to access the host. + +With this patch adcli tries to expand the short name by calling +getaddrinfo with the AI_CANONNAME hint. + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/1 +--- + doc/adcli.xml | 6 +++++- + library/adconn.c | 30 +++++++++++++++++++++++++++++- + 2 files changed, 34 insertions(+), 2 deletions(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 97dec08..4722c3a 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -228,7 +228,11 @@ Password for Administrator: + + Override the local machine's fully qualified + domain name. If not specified, the local machine's hostname +- will be retrieved via gethostname(). ++ will be retrieved via gethostname(). ++ If gethostname() only returns a short name ++ getaddrinfo() with the AI_CANONNAME hint ++ is called to expand the name to a fully qualified domain ++ name. + + + +diff --git a/library/adconn.c b/library/adconn.c +index e2250e3..f6c23d3 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -86,11 +86,36 @@ struct _adcli_conn_ctx { + krb5_keytab keytab; + }; + ++static char *try_to_get_fqdn (const char *host_name) ++{ ++ int ret; ++ char *fqdn = NULL; ++ struct addrinfo *res; ++ struct addrinfo hints; ++ ++ memset (&hints, 0, sizeof (struct addrinfo)); ++ hints.ai_socktype = SOCK_DGRAM; ++ hints.ai_flags = AI_CANONNAME; ++ ++ ret = getaddrinfo (host_name, NULL, &hints, &res); ++ if (ret != 0) { ++ _adcli_err ("Failed to find FQDN: %s", gai_strerror (ret)); ++ return NULL; ++ } ++ ++ fqdn = strdup (res->ai_canonname); ++ ++ freeaddrinfo (res); ++ ++ return fqdn; ++} ++ + static adcli_result + ensure_host_fqdn (adcli_result res, + adcli_conn *conn) + { + char hostname[HOST_NAME_MAX + 1]; ++ char *fqdn = NULL; + int ret; + + if (res != ADCLI_SUCCESS) +@@ -107,7 +132,10 @@ ensure_host_fqdn (adcli_result res, + return ADCLI_ERR_UNEXPECTED; + } + +- conn->host_fqdn = strdup (hostname); ++ if (strchr (hostname, '.') == NULL) { ++ fqdn = try_to_get_fqdn (hostname); ++ } ++ conn->host_fqdn = fqdn != NULL ? fqdn : strdup (hostname); + return_unexpected_if_fail (conn->host_fqdn != NULL); + return ADCLI_SUCCESS; + } +-- +2.20.1 + diff --git a/SOURCES/0001-tools-remove-errx-from-computer-commands.patch b/SOURCES/0001-tools-remove-errx-from-computer-commands.patch new file mode 100644 index 0000000..71db611 --- /dev/null +++ b/SOURCES/0001-tools-remove-errx-from-computer-commands.patch @@ -0,0 +1,328 @@ +From fa7926c7a9d92bc7c42c610ba6f1706c635aa901 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 15 Apr 2019 17:54:27 +0200 +Subject: [PATCH 1/7] tools: remove errx from computer commands + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596 +--- + tools/computer.c | 166 ++++++++++++++++++++++++++++++----------------- + 1 file changed, 107 insertions(+), 59 deletions(-) + +diff --git a/tools/computer.c b/tools/computer.c +index bee695c..9cbbb28 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -379,8 +379,10 @@ adcli_tool_computer_join (adcli_conn *conn, + }; + + enroll = adcli_enroll_new (conn); +- if (enroll == NULL) +- errx (-1, "unexpected memory problems"); ++ if (enroll == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { + switch (opt) { +@@ -415,21 +417,28 @@ adcli_tool_computer_join (adcli_conn *conn, + + if (argc == 1) + adcli_conn_set_domain_name (conn, argv[0]); +- else if (argc > 1) +- errx (2, "extra arguments specified"); ++ else if (argc > 1) { ++ warnx ("extra arguments specified"); ++ adcli_enroll_unref (enroll); ++ return 2; ++ } + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + res = adcli_enroll_join (enroll, flags); + if (res != ADCLI_SUCCESS) { +- errx (-res, "joining domain %s failed: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("joining domain %s failed: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + if (details) +@@ -486,8 +495,10 @@ adcli_tool_computer_update (adcli_conn *conn, + }; + + enroll = adcli_enroll_new (conn); +- if (enroll == NULL) +- errx (-1, "unexpected memory problems"); ++ if (enroll == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { + switch (opt) { +@@ -525,22 +536,28 @@ adcli_tool_computer_update (adcli_conn *conn, + + res = adcli_enroll_load (enroll); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't lookup domain info from keytab: %s", +- adcli_get_last_error ()); ++ warnx ("couldn't lookup domain info from keytab: %s", ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + res = adcli_enroll_update (enroll, flags); + if (res != ADCLI_SUCCESS) { +- errx (-res, "updating membership with domain %s failed: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("updating membership with domain %s failed: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + if (details) +@@ -578,8 +595,10 @@ adcli_tool_computer_testjoin (adcli_conn *conn, + }; + + enroll = adcli_enroll_new (conn); +- if (enroll == NULL) +- errx (-1, "unexpected memory problems"); ++ if (enroll == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { + switch (opt) { +@@ -604,18 +623,18 @@ adcli_tool_computer_testjoin (adcli_conn *conn, + res = adcli_enroll_load (enroll); + if (res != ADCLI_SUCCESS) { + adcli_enroll_unref (enroll); +- adcli_conn_unref (conn); +- errx (-res, "couldn't lookup domain info from keytab: %s", +- adcli_get_last_error ()); ++ warnx ("couldn't lookup domain info from keytab: %s", ++ adcli_get_last_error ()); ++ return -res; + } + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { + adcli_enroll_unref (enroll); +- adcli_conn_unref (conn); +- errx (-res, "couldn't connect to %s domain: %s", ++ warnx ("couldn't connect to %s domain: %s", + adcli_conn_get_domain_name (conn), + adcli_get_last_error ()); ++ return -res; + } + + printf ("Sucessfully validated join to domain %s\n", +@@ -665,8 +684,10 @@ adcli_tool_computer_preset (adcli_conn *conn, + }; + + enroll = adcli_enroll_new (conn); +- if (enroll == NULL) +- errx (-1, "unexpected memory problems"); ++ if (enroll == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + flags = ADCLI_ENROLL_NO_KEYTAB; + + while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { +@@ -694,17 +715,22 @@ adcli_tool_computer_preset (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc < 1) +- errx (EUSAGE, "specify one or more host names of computer accounts to preset"); ++ if (argc < 1) { ++ warnx ("specify one or more host names of computer accounts to preset"); ++ adcli_enroll_unref (enroll); ++ return EUSAGE; ++ } + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + reset_password = (adcli_enroll_get_computer_password (enroll) == NULL); + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + for (i = 0; i < argc; i++) { +@@ -715,9 +741,11 @@ adcli_tool_computer_preset (adcli_conn *conn, + + res = adcli_enroll_join (enroll, flags); + if (res != ADCLI_SUCCESS) { +- errx (-res, "presetting %s in %s domain failed: %s", argv[i], +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("presetting %s in %s domain failed: %s", argv[i], ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + printf ("computer-name: %s\n", adcli_enroll_get_computer_name (enroll)); +@@ -758,8 +786,10 @@ adcli_tool_computer_reset (adcli_conn *conn, + }; + + enroll = adcli_enroll_new (conn); +- if (enroll == NULL) +- errx (-1, "unexpected memory problems"); ++ if (enroll == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { + switch (opt) { +@@ -779,14 +809,19 @@ adcli_tool_computer_reset (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc != 1) +- errx (EUSAGE, "specify one host name of computer account to reset"); ++ if (argc != 1) { ++ warnx ("specify one host name of computer account to reset"); ++ adcli_enroll_unref (enroll); ++ return EUSAGE; ++ } + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + parse_fqdn_or_name (enroll, argv[0]); +@@ -794,9 +829,11 @@ adcli_tool_computer_reset (adcli_conn *conn, + + res = adcli_enroll_password (enroll, 0); + if (res != ADCLI_SUCCESS) { +- errx (-res, "resetting %s in %s domain failed: %s", argv[0], +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("resetting %s in %s domain failed: %s", argv[0], ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + adcli_enroll_unref (enroll); +@@ -832,8 +869,10 @@ adcli_tool_computer_delete (adcli_conn *conn, + }; + + enroll = adcli_enroll_new (conn); +- if (enroll == NULL) +- errx (-1, "unexpected memory problems"); ++ if (enroll == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { + switch (opt) { +@@ -853,22 +892,29 @@ adcli_tool_computer_delete (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc > 1) +- errx (EUSAGE, "specify one host name of computer account to delete"); ++ if (argc > 1) { ++ warnx ("specify one host name of computer account to delete"); ++ adcli_enroll_unref (enroll); ++ return EUSAGE; ++ } + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + res = adcli_enroll_load (enroll); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't lookup domain info from keytab: %s", +- adcli_get_last_error ()); ++ warnx ("couldn't lookup domain info from keytab: %s", ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + if (argc == 1) +@@ -876,9 +922,11 @@ adcli_tool_computer_delete (adcli_conn *conn, + + res = adcli_enroll_delete (enroll, 0); + if (res != ADCLI_SUCCESS) { +- errx (-res, "deleting %s in %s domain failed: %s", argv[0], +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("deleting %s in %s domain failed: %s", argv[0], ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_enroll_unref (enroll); ++ return -res; + } + + adcli_enroll_unref (enroll); +-- +2.20.1 + diff --git a/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch b/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch new file mode 100644 index 0000000..769a022 --- /dev/null +++ b/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch @@ -0,0 +1,52 @@ +From 2fc259a88be618871cea8ff8b8a13bd3e040aea4 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 13 Jun 2019 17:23:47 +0200 +Subject: [PATCH 2/4] adconn: add adcli_conn_set_krb5_context + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3 +--- + library/adconn.c | 13 +++++++++++++ + library/adconn.h | 3 +++ + 2 files changed, 16 insertions(+) + +diff --git a/library/adconn.c b/library/adconn.c +index f6c23d3..bcaced8 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -1406,6 +1406,19 @@ adcli_conn_get_krb5_context (adcli_conn *conn) + return conn->k5; + } + ++void ++adcli_conn_set_krb5_context (adcli_conn *conn, ++ krb5_context k5) ++{ ++ return_if_fail (conn != NULL); ++ ++ if (conn->k5 != NULL) { ++ krb5_free_context (conn->k5); ++ } ++ ++ conn->k5 = k5; ++} ++ + const char * + adcli_conn_get_login_user (adcli_conn *conn) + { +diff --git a/library/adconn.h b/library/adconn.h +index 13cfd32..1ad5715 100644 +--- a/library/adconn.h ++++ b/library/adconn.h +@@ -97,6 +97,9 @@ LDAP * adcli_conn_get_ldap_connection (adcli_conn *conn); + + krb5_context adcli_conn_get_krb5_context (adcli_conn *conn); + ++void adcli_conn_set_krb5_context (adcli_conn *conn, ++ krb5_context k5); ++ + const char * adcli_conn_get_computer_name (adcli_conn *conn); + + void adcli_conn_set_computer_name (adcli_conn *conn, +-- +2.21.0 + diff --git a/SOURCES/0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch b/SOURCES/0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch new file mode 100644 index 0000000..e4a6bc5 --- /dev/null +++ b/SOURCES/0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch @@ -0,0 +1,83 @@ +From 0c027538f398b3823bedbfbf5f388ad97784a0ec Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 16 Nov 2018 13:32:59 +0100 +Subject: [PATCH 2/2] adenroll: use _adcli_strv_add_unique for service + principals + +Check if service principals is already in the list before adding it. + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/16 +--- + library/adenroll.c | 31 ++++++++----------------------- + 1 file changed, 8 insertions(+), 23 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index de2242a..e02f403 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -313,7 +313,6 @@ add_service_names_to_service_principals (adcli_enroll *enroll) + char *name; + int length = 0; + int i; +- size_t c; + + if (enroll->service_principals != NULL) { + length = seq_count (enroll->service_principals); +@@ -322,28 +321,14 @@ add_service_names_to_service_principals (adcli_enroll *enroll) + for (i = 0; enroll->service_names[i] != NULL; i++) { + if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0) + return_unexpected_if_reached (); +- for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) { +- if (strcmp (name, enroll->service_principals[c]) == 0) { +- break; +- } +- } +- if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) { +- enroll->service_principals = _adcli_strv_add (enroll->service_principals, +- name, &length); +- } ++ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, ++ name, &length, false); + + if (enroll->host_fqdn) { + if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0) + return_unexpected_if_reached (); +- for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) { +- if (strcmp (name, enroll->service_principals[c]) == 0) { +- break; +- } +- } +- if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) { +- enroll->service_principals = _adcli_strv_add (enroll->service_principals, +- name, &length); +- } ++ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, ++ name, &length, false); + } + } + +@@ -364,9 +349,9 @@ add_and_remove_service_principals (adcli_enroll *enroll) + list = adcli_enroll_get_service_principals_to_add (enroll); + if (list != NULL) { + for (c = 0; list[c] != NULL; c++) { +- enroll->service_principals = _adcli_strv_add (enroll->service_principals, +- strdup (list[c]), +- &length); ++ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, ++ strdup (list[c]), ++ &length, false); + if (enroll->service_principals == NULL) { + return ADCLI_ERR_UNEXPECTED; + } +@@ -1525,7 +1510,7 @@ load_keytab_entry (krb5_context k5, + value = strdup (name); + return_val_if_fail (value != NULL, FALSE); + _adcli_info ("Found service principal in keytab: %s", value); +- enroll->service_principals = _adcli_strv_add (enroll->service_principals, value, NULL); ++ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, value, NULL, false); + } + } + +-- +2.20.1 + diff --git a/SOURCES/0002-create-user-try-to-find-NIS-domain-if-needed.patch b/SOURCES/0002-create-user-try-to-find-NIS-domain-if-needed.patch new file mode 100644 index 0000000..0ecdc90 --- /dev/null +++ b/SOURCES/0002-create-user-try-to-find-NIS-domain-if-needed.patch @@ -0,0 +1,147 @@ +From 408880a11879b1a57a450e25c77ef2e310bdffd5 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 18 Mar 2019 16:45:54 +0100 +Subject: [PATCH 2/2] create-user: try to find NIS domain if needed + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/2 +--- + doc/adcli.xml | 4 +++- + library/adentry.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ + library/adentry.h | 2 ++ + tools/entry.c | 16 ++++++++++++++++ + 4 files changed, 65 insertions(+), 1 deletion(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 18620c0..af73433 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -537,7 +537,9 @@ $ adcli create-user Fry --domain=domain.example.com \ + the new created user account, which should be the user's + NIS domain is the NIS/YP service of Active Directory's Services for Unix (SFU) + are used. This is needed to let the 'UNIX attributes' tab of older Active +- Directoy versions show the set UNIX specific attributes. ++ Directoy versions show the set UNIX specific attributes. If not specified ++ adcli will try to determine the NIS domain automatically if needed. ++ + + + +diff --git a/library/adentry.c b/library/adentry.c +index 9b9e1c6..1cc0518 100644 +--- a/library/adentry.c ++++ b/library/adentry.c +@@ -484,3 +484,47 @@ adcli_entry_new_group (adcli_conn *conn, + return_val_if_fail (sam_name != NULL, NULL); + return entry_new (conn, "group", group_entry_builder, sam_name); + } ++ ++adcli_result ++adcli_get_nis_domain (adcli_entry *entry, ++ adcli_attrs *attrs) ++{ ++ LDAP *ldap; ++ const char *ldap_attrs[] = { "cn", NULL }; ++ LDAPMessage *results; ++ LDAPMessage *ldap_entry; ++ char *base; ++ const char *filter = "objectClass=msSFU30DomainInfo"; ++ char *cn; ++ int ret; ++ ++ ldap = adcli_conn_get_ldap_connection (entry->conn); ++ return_unexpected_if_fail (ldap != NULL); ++ ++ if (asprintf (&base, "CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System,%s", ++ adcli_conn_get_default_naming_context (entry->conn)) < 0) { ++ return_unexpected_if_reached (); ++ } ++ ++ ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_SUB, filter, (char **)ldap_attrs, ++ 0, NULL, NULL, NULL, -1, &results); ++ ++ free (base); ++ ++ if (ret != LDAP_SUCCESS) { ++ /* No NIS domain available */ ++ ldap_msgfree (results); ++ return ADCLI_SUCCESS; ++ } ++ ++ ldap_entry = ldap_first_entry (ldap, results); ++ if (ldap_entry != NULL) { ++ cn = _adcli_ldap_parse_value (ldap, ldap_entry, "cn"); ++ return_unexpected_if_fail (cn != NULL); ++ ++ adcli_attrs_add (attrs, "msSFU30NisDomain", cn, NULL); ++ } ++ ldap_msgfree (results); ++ ++ return ADCLI_SUCCESS; ++} +diff --git a/library/adentry.h b/library/adentry.h +index eb8bc00..ae90689 100644 +--- a/library/adentry.h ++++ b/library/adentry.h +@@ -58,4 +58,6 @@ const char * adcli_entry_get_sam_name (adcli_entry *entry); + + const char * adcli_entry_get_dn (adcli_entry *entry); + ++adcli_result adcli_get_nis_domain (adcli_entry *entry, ++ adcli_attrs *attrs); + #endif /* ADENTRY_H_ */ +diff --git a/tools/entry.c b/tools/entry.c +index 69ce62c..de56586 100644 +--- a/tools/entry.c ++++ b/tools/entry.c +@@ -153,6 +153,8 @@ adcli_tool_user_create (adcli_conn *conn, + adcli_attrs *attrs; + const char *ou = NULL; + int opt; ++ bool has_unix_attr = false; ++ bool has_nis_domain = false; + + struct option options[] = { + { "display-name", required_argument, NULL, opt_display_name }, +@@ -193,18 +195,23 @@ adcli_tool_user_create (adcli_conn *conn, + break; + case opt_unix_home: + adcli_attrs_add (attrs, "unixHomeDirectory", optarg, NULL); ++ has_unix_attr = true; + break; + case opt_unix_uid: + adcli_attrs_add (attrs, "uidNumber", optarg, NULL); ++ has_unix_attr = true; + break; + case opt_unix_gid: + adcli_attrs_add (attrs, "gidNumber", optarg, NULL); ++ has_unix_attr = true; + break; + case opt_unix_shell: + adcli_attrs_add (attrs, "loginShell", optarg, NULL); ++ has_unix_attr = true; + break; + case opt_nis_domain: + adcli_attrs_add (attrs, "msSFU30NisDomain", optarg, NULL); ++ has_nis_domain = true; + break; + case opt_domain_ou: + ou = optarg; +@@ -242,6 +249,15 @@ adcli_tool_user_create (adcli_conn *conn, + adcli_get_last_error ()); + } + ++ if (has_unix_attr && !has_nis_domain) { ++ res = adcli_get_nis_domain (entry, attrs); ++ if (res != ADCLI_SUCCESS) { ++ adcli_entry_unref (entry); ++ adcli_attrs_free (attrs); ++ errx (-res, "couldn't get NIS domain"); ++ } ++ } ++ + res = adcli_entry_create (entry, attrs); + if (res != ADCLI_SUCCESS) { + errx (-res, "creating user %s in domain %s failed: %s", +-- +2.20.1 + diff --git a/SOURCES/0002-library-make-_adcli_strv_has_ex-public.patch b/SOURCES/0002-library-make-_adcli_strv_has_ex-public.patch new file mode 100644 index 0000000..db18951 --- /dev/null +++ b/SOURCES/0002-library-make-_adcli_strv_has_ex-public.patch @@ -0,0 +1,42 @@ +From e1b45e66bc185f5db4c252e1f3fb1b4400b4538e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 22 Mar 2019 10:36:38 +0100 +Subject: [PATCH 2/4] library: make _adcli_strv_has_ex public + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187 +--- + library/adprivate.h | 4 ++++ + library/adutil.c | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/library/adprivate.h b/library/adprivate.h +index 0806430..55e6234 100644 +--- a/library/adprivate.h ++++ b/library/adprivate.h +@@ -125,6 +125,10 @@ void _adcli_strv_free (char **strv); + int _adcli_strv_has (char **strv, + const char *str); + ++int _adcli_strv_has_ex (char **strv, ++ const char *str, ++ int (* compare) (const char *match, const char*value)); ++ + char ** _adcli_strv_dup (char **strv) GNUC_WARN_UNUSED; + + char * _adcli_strv_join (char **strv, +diff --git a/library/adutil.c b/library/adutil.c +index 76ea158..9b0c47f 100644 +--- a/library/adutil.c ++++ b/library/adutil.c +@@ -221,7 +221,7 @@ _adcli_strv_add (char **strv, + return seq_push (strv, length, string); + } + +-static int ++int + _adcli_strv_has_ex (char **strv, + const char *str, + int (* compare) (const char *match, const char*value)) +-- +2.20.1 + diff --git a/SOURCES/0002-library-return-error-if-no-matching-key-was-found.patch b/SOURCES/0002-library-return-error-if-no-matching-key-was-found.patch new file mode 100644 index 0000000..f9c68d6 --- /dev/null +++ b/SOURCES/0002-library-return-error-if-no-matching-key-was-found.patch @@ -0,0 +1,35 @@ +From 4987a21f4839ab7ea50e932c72df05075efb89b3 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 21 Mar 2019 15:05:33 +0100 +Subject: [PATCH 2/2] library: return error if no matching key was found + +To avoid a misleading debug message indicating success a proper erro +code should be returned the no matching key was found when trying to +copy an keytab entry for a new principal. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1644311 +--- + library/adkrb5.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/library/adkrb5.c b/library/adkrb5.c +index 033c181..7f77373 100644 +--- a/library/adkrb5.c ++++ b/library/adkrb5.c +@@ -298,11 +298,10 @@ _adcli_krb5_keytab_copy_entries (krb5_context k5, + + code = _adcli_krb5_get_keyblock (k5, keytab, &entry.key, + match_enctype_and_kvno, &closure); +- if (code != 0) { +- return code; ++ if (code != 0 || closure.matched == 0) { ++ return code != 0 ? code : ENOKEY; + } + +- + entry.principal = principal; + entry.vno = kvno; + +-- +2.20.1 + diff --git a/SOURCES/0002-tools-remove-errx-from-user-and-group-commands.patch b/SOURCES/0002-tools-remove-errx-from-user-and-group-commands.patch new file mode 100644 index 0000000..36e5567 --- /dev/null +++ b/SOURCES/0002-tools-remove-errx-from-user-and-group-commands.patch @@ -0,0 +1,398 @@ +From cac0fa9df8888245399f2db187e05e31f93d1471 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 15 Apr 2019 17:56:37 +0200 +Subject: [PATCH 2/7] tools: remove errx from user and group commands + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596 +--- + tools/entry.c | 232 +++++++++++++++++++++++++++++++++----------------- + 1 file changed, 154 insertions(+), 78 deletions(-) + +diff --git a/tools/entry.c b/tools/entry.c +index de56586..97ec6e7 100644 +--- a/tools/entry.c ++++ b/tools/entry.c +@@ -232,21 +232,30 @@ adcli_tool_user_create (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc != 1) +- errx (2, "specify one user name to create"); ++ if (argc != 1) { ++ warnx ("specify one user name to create"); ++ adcli_attrs_free (attrs); ++ return 2; ++ } + + entry = adcli_entry_new_user (conn, argv[0]); +- if (entry == NULL) +- errx (-1, "unexpected memory problems"); ++ if (entry == NULL) { ++ warnx ("unexpected memory problems"); ++ adcli_attrs_free (attrs); ++ return -1; ++ } + adcli_entry_set_domain_ou (entry, ou); + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ adcli_attrs_free (attrs); ++ return -res; + } + + if (has_unix_attr && !has_nis_domain) { +@@ -254,16 +263,20 @@ adcli_tool_user_create (adcli_conn *conn, + if (res != ADCLI_SUCCESS) { + adcli_entry_unref (entry); + adcli_attrs_free (attrs); +- errx (-res, "couldn't get NIS domain"); ++ warnx ("couldn't get NIS domain"); ++ return -res; + } + } + + res = adcli_entry_create (entry, attrs); + if (res != ADCLI_SUCCESS) { +- errx (-res, "creating user %s in domain %s failed: %s", +- adcli_entry_get_sam_name (entry), +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("creating user %s in domain %s failed: %s", ++ adcli_entry_get_sam_name (entry), ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ adcli_attrs_free (attrs); ++ return -res; + } + + adcli_entry_unref (entry); +@@ -317,28 +330,36 @@ adcli_tool_user_delete (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc != 1) +- errx (2, "specify one user name to delete"); ++ if (argc != 1) { ++ warnx ("specify one user name to delete"); ++ return 2; ++ } + + entry = adcli_entry_new_user (conn, argv[0]); +- if (entry == NULL) +- errx (-1, "unexpected memory problems"); ++ if (entry == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; + } + + res = adcli_entry_delete (entry); + if (res != ADCLI_SUCCESS) { +- errx (-res, "deleting user %s in domain %s failed: %s", +- adcli_entry_get_sam_name (entry), +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("deleting user %s in domain %s failed: %s", ++ adcli_entry_get_sam_name (entry), ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; + } + + adcli_entry_unref (entry); +@@ -404,29 +425,41 @@ adcli_tool_group_create (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc != 1) +- errx (2, "specify one group to create"); ++ if (argc != 1) { ++ warnx ("specify one group to create"); ++ adcli_attrs_free (attrs); ++ return 2; ++ } + + entry = adcli_entry_new_group (conn, argv[0]); +- if (entry == NULL) +- errx (-1, "unexpected memory problems"); ++ if (entry == NULL) { ++ warnx ("unexpected memory problems"); ++ adcli_attrs_free (attrs); ++ return -1; ++ } + adcli_entry_set_domain_ou (entry, ou); + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to domain %s: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to domain %s: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ adcli_attrs_free (attrs); ++ return -res; + } + + res = adcli_entry_create (entry, attrs); + if (res != ADCLI_SUCCESS) { +- errx (-res, "creating group %s in domain %s failed: %s", +- adcli_entry_get_sam_name (entry), +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("creating group %s in domain %s failed: %s", ++ adcli_entry_get_sam_name (entry), ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ adcli_attrs_free (attrs); ++ return -res; + } + + adcli_entry_unref (entry); +@@ -480,28 +513,36 @@ adcli_tool_group_delete (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc != 1) +- errx (2, "specify one group name to delete"); ++ if (argc != 1) { ++ warnx ("specify one group name to delete"); ++ return 2; ++ } + + entry = adcli_entry_new_group (conn, argv[0]); +- if (entry == NULL) +- errx (-1, "unexpected memory problems"); ++ if (entry == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; + } + + res = adcli_entry_delete (entry); + if (res != ADCLI_SUCCESS) { +- errx (-res, "deleting group %s in domain %s failed: %s", +- adcli_entry_get_sam_name (entry), +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("deleting group %s in domain %s failed: %s", ++ adcli_entry_get_sam_name (entry), ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; + } + + adcli_entry_unref (entry); +@@ -509,7 +550,7 @@ adcli_tool_group_delete (adcli_conn *conn, + return 0; + } + +-static void ++static int + expand_user_dn_as_member (adcli_conn *conn, + adcli_attrs *attrs, + const char *user, +@@ -523,16 +564,19 @@ expand_user_dn_as_member (adcli_conn *conn, + + res = adcli_entry_load (entry); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't lookup user %s in domain %s: %s", +- user, adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't lookup user %s in domain %s: %s", ++ user, adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; + } + + dn = adcli_entry_get_dn (entry); + if (dn == NULL) { +- errx (-ADCLI_ERR_CONFIG, +- "couldn't found user %s in domain %s", +- user, adcli_conn_get_domain_name (conn)); ++ warnx ("couldn't found user %s in domain %s", ++ user, adcli_conn_get_domain_name (conn)); ++ adcli_entry_unref (entry); ++ return -ADCLI_ERR_CONFIG; + } + + if (adding) +@@ -541,6 +585,8 @@ expand_user_dn_as_member (adcli_conn *conn, + adcli_attrs_delete1 (attrs, "member", dn); + + adcli_entry_unref (entry); ++ ++ return ADCLI_SUCCESS; + } + + int +@@ -590,33 +636,48 @@ adcli_tool_member_add (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc < 2) +- errx (2, "specify a group name and a user to add"); ++ if (argc < 2) { ++ warnx ("specify a group name and a user to add"); ++ return 2; ++ } + + entry = adcli_entry_new_group (conn, argv[0]); +- if (entry == NULL) +- errx (-1, "unexpected memory problems"); ++ if (entry == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; + } + + attrs = adcli_attrs_new (); + +- for (i = 1; i < argc; i++) +- expand_user_dn_as_member (conn, attrs, argv[i], 1); ++ for (i = 1; i < argc; i++) { ++ res = expand_user_dn_as_member (conn, attrs, argv[i], 1); ++ if (res != ADCLI_SUCCESS) { ++ adcli_attrs_free (attrs); ++ adcli_entry_unref (entry); ++ return res; ++ } ++ } + + res = adcli_entry_modify (entry, attrs); + if (res != ADCLI_SUCCESS) { +- errx (-res, "adding member(s) to group %s in domain %s failed: %s", +- adcli_entry_get_sam_name (entry), +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("adding member(s) to group %s in domain %s failed: %s", ++ adcli_entry_get_sam_name (entry), ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_attrs_free (attrs); ++ adcli_entry_unref (entry); ++ return -res; + } + + adcli_attrs_free (attrs); +@@ -672,33 +733,48 @@ adcli_tool_member_remove (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc < 2) +- errx (2, "specify a group name and a user to remove"); ++ if (argc < 2) { ++ warnx ("specify a group name and a user to remove"); ++ return 2; ++ } + + entry = adcli_entry_new_group (conn, argv[0]); +- if (entry == NULL) +- errx (-1, "unexpected memory problems"); ++ if (entry == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + res = adcli_conn_connect (conn); + if (res != ADCLI_SUCCESS) { +- errx (-res, "couldn't connect to %s domain: %s", +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; + } + + attrs = adcli_attrs_new (); + +- for (i = 1; i < argc; i++) +- expand_user_dn_as_member (conn, attrs, argv[i], 0); ++ for (i = 1; i < argc; i++) { ++ res = expand_user_dn_as_member (conn, attrs, argv[i], 0); ++ if (res != ADCLI_SUCCESS) { ++ adcli_attrs_free (attrs); ++ adcli_entry_unref (entry); ++ return res; ++ } ++ } + + res = adcli_entry_modify (entry, attrs); + if (res != ADCLI_SUCCESS) { +- errx (-res, "adding member(s) to group %s in domain %s failed: %s", +- adcli_entry_get_sam_name (entry), +- adcli_conn_get_domain_name (conn), +- adcli_get_last_error ()); ++ warnx ("adding member(s) to group %s in domain %s failed: %s", ++ adcli_entry_get_sam_name (entry), ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_attrs_free (attrs); ++ adcli_entry_unref (entry); ++ return -res; + } + + adcli_attrs_free (attrs); +-- +2.20.1 + diff --git a/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch b/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch new file mode 100644 index 0000000..f810c13 --- /dev/null +++ b/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch @@ -0,0 +1,196 @@ +From 0c09070e8beec734e3f0c70e14b0a04788077b73 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 13 Jun 2019 17:25:52 +0200 +Subject: [PATCH 3/4] adenroll: add adcli_enroll_get_permitted_keytab_enctypes + with tests + +The new call does not only return the current encryption types set in AD +or a default list but filters them with the list of permitted encryption +types on the client. This makes sure the client can create and use the +keys. + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3 +--- + library/Makefile.am | 5 ++ + library/adenroll.c | 124 ++++++++++++++++++++++++++++++++++++++++++++ + library/adenroll.h | 2 + + 3 files changed, 131 insertions(+) + +diff --git a/library/Makefile.am b/library/Makefile.am +index 39e8fd1..4829555 100644 +--- a/library/Makefile.am ++++ b/library/Makefile.am +@@ -40,6 +40,7 @@ check_PROGRAMS = \ + test-util \ + test-ldap \ + test-attrs \ ++ test-adenroll \ + $(NULL) + + test_seq_SOURCES = seq.c test.c test.h +@@ -56,6 +57,10 @@ test_attrs_SOURCES = adattrs.c $(test_ldap_SOURCES) + test_attrs_CFLAGS = -DATTRS_TESTS + test_attrs_LDADD = $(test_ldap_LDADD) + ++test_adenroll_SOURCES = adenroll.c $(test_ldap_SOURCES) ++test_adenroll_CFLAGS = -DADENROLL_TESTS ++test_adenroll_LDADD = $(KRB5_LIBS) ++ + TESTS = $(check_PROGRAMS) + + MEMCHECK_ENV = $(TEST_RUNNER) valgrind --error-exitcode=80 --quiet --trace-children=yes +diff --git a/library/adenroll.c b/library/adenroll.c +index f617f28..95c07cd 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -2641,6 +2641,50 @@ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll) + return v51_earlier_enctypes; + } + ++krb5_enctype * ++adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll) ++{ ++ krb5_enctype *cur_enctypes; ++ krb5_enctype *permitted_enctypes; ++ krb5_enctype *new_enctypes; ++ krb5_error_code code; ++ krb5_context k5; ++ size_t c; ++ size_t p; ++ size_t n; ++ ++ return_val_if_fail (enroll != NULL, NULL); ++ cur_enctypes = adcli_enroll_get_keytab_enctypes (enroll); ++ ++ k5 = adcli_conn_get_krb5_context (enroll->conn); ++ return_val_if_fail (k5 != NULL, NULL); ++ ++ code = krb5_get_permitted_enctypes (k5, &permitted_enctypes); ++ return_val_if_fail (code == 0, NULL); ++ ++ for (c = 0; cur_enctypes[c] != 0; c++); ++ ++ new_enctypes = calloc (c + 1, sizeof (krb5_enctype)); ++ return_val_if_fail (new_enctypes != NULL, NULL); ++ ++ n = 0; ++ for (c = 0; cur_enctypes[c] != 0; c++) { ++ for (p = 0; permitted_enctypes[p] != 0; p++) { ++ if (cur_enctypes[c] == permitted_enctypes[p]) { ++ new_enctypes[n++] = cur_enctypes[c]; ++ break; ++ } ++ } ++ if (permitted_enctypes[p] == 0) { ++ _adcli_info ("Encryption type [%d] not permitted.", cur_enctypes[c]); ++ } ++ } ++ ++ krb5_free_enctypes (k5, permitted_enctypes); ++ ++ return new_enctypes; ++} ++ + void + adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll, + krb5_enctype *value) +@@ -2833,3 +2877,83 @@ adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll, + strdup (value), NULL); + return_if_fail (enroll->service_principals_to_remove != NULL); + } ++ ++#ifdef ADENROLL_TESTS ++ ++#include "test.h" ++ ++static void ++test_adcli_enroll_get_permitted_keytab_enctypes (void) ++{ ++ krb5_enctype *enctypes; ++ krb5_error_code code; ++ krb5_enctype *permitted_enctypes; ++ krb5_enctype check_enctypes[3] = { 0 }; ++ adcli_conn *conn; ++ adcli_enroll *enroll; ++ adcli_result res; ++ krb5_context k5; ++ size_t c; ++ ++ conn = adcli_conn_new ("test.dom"); ++ assert_ptr_not_null (conn); ++ ++ enroll = adcli_enroll_new (conn); ++ assert_ptr_not_null (enroll); ++ ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (NULL); ++ assert_ptr_eq (enctypes, NULL); ++ ++ /* krb5 context missing */ ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ assert_ptr_eq (enctypes, NULL); ++ ++ /* check that all permitted enctypes can pass */ ++ res = _adcli_krb5_init_context (&k5); ++ assert_num_eq (res, ADCLI_SUCCESS); ++ ++ adcli_conn_set_krb5_context (conn, k5); ++ ++ code = krb5_get_permitted_enctypes (k5, &permitted_enctypes); ++ assert_num_eq (code, 0); ++ assert_ptr_not_null (permitted_enctypes); ++ assert_num_cmp (permitted_enctypes[0], !=, 0); ++ ++ adcli_enroll_set_keytab_enctypes (enroll, permitted_enctypes); ++ ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ assert_ptr_not_null (enctypes); ++ for (c = 0; permitted_enctypes[c] != 0; c++) { ++ assert_num_eq (enctypes[c], permitted_enctypes[c]); ++ } ++ assert_num_eq (enctypes[c], 0); ++ krb5_free_enctypes (k5, enctypes); ++ ++ /* check that ENCTYPE_UNKNOWN is filtered out */ ++ check_enctypes[0] = permitted_enctypes[0]; ++ check_enctypes[1] = ENCTYPE_UNKNOWN; ++ check_enctypes[2] = 0; ++ adcli_enroll_set_keytab_enctypes (enroll, check_enctypes); ++ ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ assert_ptr_not_null (enctypes); ++ assert_num_eq (enctypes[0], permitted_enctypes[0]); ++ assert_num_eq (enctypes[1], 0); ++ krb5_free_enctypes (k5, enctypes); ++ ++ krb5_free_enctypes (k5, permitted_enctypes); ++ ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); ++} ++ ++int ++main (int argc, ++ char *argv[]) ++{ ++ test_func (test_adcli_enroll_get_permitted_keytab_enctypes, ++ "/attrs/adcli_enroll_get_permitted_keytab_enctypes"); ++ return test_run (argc, argv); ++} ++ ++#endif /* ADENROLL_TESTS */ +diff --git a/library/adenroll.h b/library/adenroll.h +index abbbfd4..1d5d00d 100644 +--- a/library/adenroll.h ++++ b/library/adenroll.h +@@ -138,6 +138,8 @@ krb5_enctype * adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll); + void adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll, + krb5_enctype *enctypes); + ++krb5_enctype * adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll); ++ + const char * adcli_enroll_get_os_name (adcli_enroll *enroll); + + void adcli_enroll_set_os_name (adcli_enroll *enroll, +-- +2.21.0 + diff --git a/SOURCES/0003-library-_adcli_krb5_build_principal-allow-principals.patch b/SOURCES/0003-library-_adcli_krb5_build_principal-allow-principals.patch new file mode 100644 index 0000000..217636c --- /dev/null +++ b/SOURCES/0003-library-_adcli_krb5_build_principal-allow-principals.patch @@ -0,0 +1,42 @@ +From 10a4dbb5978b6f05cf75f820d97da908e735ace8 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 22 Mar 2019 10:37:11 +0100 +Subject: [PATCH 3/4] library: _adcli_krb5_build_principal allow principals as + names + +Make _adcli_krb5_build_principal a bit more robust by checking if the +given name already contains a realm suffix. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187 +--- + library/adkrb5.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/library/adkrb5.c b/library/adkrb5.c +index 7f77373..da835d7 100644 +--- a/library/adkrb5.c ++++ b/library/adkrb5.c +@@ -41,12 +41,16 @@ _adcli_krb5_build_principal (krb5_context k5, + krb5_principal *principal) + { + krb5_error_code code; +- char *name; ++ char *name = NULL; + +- if (asprintf (&name, "%s@%s", user, realm) < 0) +- return_val_if_reached (ENOMEM); ++ /* Use user if user contains a @-character and add @realm otherwise */ ++ if (strchr (user, '@') == NULL) { ++ if (asprintf (&name, "%s@%s", user, realm) < 0) { ++ return_val_if_reached (ENOMEM); ++ } ++ } + +- code = krb5_parse_name (k5, name, principal); ++ code = krb5_parse_name (k5, name != NULL ? name : user, principal); + return_val_if_fail (code == 0, code); + + free (name); +-- +2.20.1 + diff --git a/SOURCES/0003-tools-remove-errx-from-info-commands.patch b/SOURCES/0003-tools-remove-errx-from-info-commands.patch new file mode 100644 index 0000000..c53cf50 --- /dev/null +++ b/SOURCES/0003-tools-remove-errx-from-info-commands.patch @@ -0,0 +1,53 @@ +From 4794812cc98c8783921f534d20dae8b44f3826d2 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 15 Apr 2019 17:57:37 +0200 +Subject: [PATCH 3/7] tools: remove errx from info commands + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596 +--- + tools/info.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/tools/info.c b/tools/info.c +index e7e20ad..c63e0ff 100644 +--- a/tools/info.c ++++ b/tools/info.c +@@ -162,21 +162,28 @@ adcli_tool_info (adcli_conn *unused, + + if (argc == 1) + domain = argv[0]; +- else if (argc != 0) +- errx (2, "specify one user name to create"); ++ else if (argc != 0) { ++ warnx ("specify one user name to create"); ++ return 2; ++ } + + if (server) { + adcli_disco_host (server, &disco); +- if (disco == NULL) +- errx (1, "couldn't discover domain controller: %s", server); ++ if (disco == NULL) { ++ warnx ("couldn't discover domain controller: %s", server); ++ return 1; ++ } + for_host = 1; + } else if (domain) { + adcli_disco_domain (domain, &disco); +- if (disco == NULL) +- errx (1, "couldn't discover domain: %s", domain); ++ if (disco == NULL) { ++ warnx ("couldn't discover domain: %s", domain); ++ return 1; ++ } + for_host = 0; + } else { +- errx (2, "specify a domain to discover"); ++ warnx ("specify a domain to discover"); ++ return 2; + } + + print_info (disco, for_host); +-- +2.20.1 + diff --git a/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch b/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch new file mode 100644 index 0000000..a496e32 --- /dev/null +++ b/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch @@ -0,0 +1,103 @@ +From cc3ef52884a48863a81acbfc741735fe09cd85f7 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 13 Jun 2019 18:27:49 +0200 +Subject: [PATCH 4/4] adenroll: use only enctypes permitted by Kerberos config + +Realted to https://gitlab.freedesktop.org/realmd/adcli/issues/3 +--- + doc/adcli.xml | 10 ++++++++++ + library/adenroll.c | 22 +++++++++++++++++++--- + 2 files changed, 29 insertions(+), 3 deletions(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 9605b4a..094f577 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -342,6 +342,11 @@ Password for Administrator: + + + ++ If supported on the AD side the ++ attribute will be set as ++ well. Either the current value or the default list of AD's supported ++ encryption types filtered by the permitted encryption types of the ++ client's Kerberos configuration are written. + + + +@@ -475,6 +480,11 @@ $ adcli update --login-ccache=/tmp/krbcc_123 + + + ++ If supported on the AD side the ++ attribute will be set as ++ well. Either the current value or the default list of AD's supported ++ encryption types filtered by the permitted encryption types of the ++ client's Kerberos configuration are written. + + + +diff --git a/library/adenroll.c b/library/adenroll.c +index 95c07cd..53cd812 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -639,6 +639,7 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype) + { + char *value = NULL; + krb5_enctype *read_enctypes; ++ krb5_enctype *new_enctypes; + char *new_value = NULL; + int is_2008_or_later; + LDAP *ldap; +@@ -685,7 +686,14 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype) + value = _adcli_krb5_format_enctypes (v51_earlier_enctypes); + } + +- new_value = _adcli_krb5_format_enctypes (adcli_enroll_get_keytab_enctypes (enroll)); ++ new_enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ if (new_enctypes == NULL) { ++ _adcli_warn ("No permitted encryption type found."); ++ return ADCLI_ERR_UNEXPECTED; ++ } ++ ++ new_value = _adcli_krb5_format_enctypes (new_enctypes); ++ krb5_free_enctypes (adcli_conn_get_krb5_context (enroll->conn), new_enctypes); + if (new_value == NULL) { + free (value); + _adcli_warn ("The encryption types desired are not available in active directory"); +@@ -1758,7 +1766,11 @@ add_principal_to_keytab (adcli_enroll *enroll, + enroll->keytab_name); + } + +- enctypes = adcli_enroll_get_keytab_enctypes (enroll); ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ if (enctypes == NULL) { ++ _adcli_warn ("No permitted encryption type found."); ++ return ADCLI_ERR_UNEXPECTED; ++ } + + if (flags & ADCLI_ENROLL_PASSWORD_VALID) { + code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal, +@@ -1774,7 +1786,10 @@ add_principal_to_keytab (adcli_enroll *enroll, + */ + + salts = build_principal_salts (enroll, k5, principal); +- return_unexpected_if_fail (salts != NULL); ++ if (salts == NULL) { ++ krb5_free_enctypes (k5, enctypes); ++ return ADCLI_ERR_UNEXPECTED; ++ } + + if (*which_salt < 0) { + code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password, +@@ -1794,6 +1809,7 @@ add_principal_to_keytab (adcli_enroll *enroll, + + free_principal_salts (k5, salts); + } ++ krb5_free_enctypes (k5, enctypes); + + if (code != 0) { + _adcli_err ("Couldn't add keytab entries: %s: %s", +-- +2.21.0 + diff --git a/SOURCES/0004-library-make-sure-server-side-SPNs-are-preserved.patch b/SOURCES/0004-library-make-sure-server-side-SPNs-are-preserved.patch new file mode 100644 index 0000000..07cc8fb --- /dev/null +++ b/SOURCES/0004-library-make-sure-server-side-SPNs-are-preserved.patch @@ -0,0 +1,82 @@ +From 972f1a2f35829ed89f5353bd204683aa9ad6a2d2 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 22 Mar 2019 10:37:57 +0100 +Subject: [PATCH 4/4] library: make sure server side SPNs are preserved + +adcli should not delete service principal names (SPNs) unexpectedly. If +a SPN was added on the server while presetting a host or updating an +existing entry and upcoming adcli join or update should preserver this +change. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187 +--- + library/adenroll.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 48cb4cf..1cce86a 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -1961,6 +1961,47 @@ adcli_enroll_prepare (adcli_enroll *enroll, + return res; + } + ++static adcli_result ++add_server_side_service_principals (adcli_enroll *enroll) ++{ ++ char **spn_list; ++ LDAP *ldap; ++ size_t c; ++ int length = 0; ++ adcli_result res; ++ ++ ldap = adcli_conn_get_ldap_connection (enroll->conn); ++ assert (ldap != NULL); ++ ++ spn_list = _adcli_ldap_parse_values (ldap, enroll->computer_attributes, ++ "servicePrincipalName"); ++ if (spn_list == NULL) { ++ return ADCLI_SUCCESS; ++ } ++ ++ if (enroll->service_principals != NULL) { ++ length = seq_count (enroll->service_principals); ++ } ++ ++ for (c = 0; spn_list[c] != NULL; c++) { ++ _adcli_info ("Checking %s", spn_list[c]); ++ if (!_adcli_strv_has_ex (enroll->service_principals_to_remove, spn_list[c], strcasecmp)) { ++ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, ++ spn_list[c], &length, false); ++ assert (enroll->service_principals != NULL); ++ _adcli_info (" Added %s", spn_list[c]); ++ } ++ } ++ _adcli_strv_free (spn_list); ++ ++ res = ensure_keytab_principals (ADCLI_SUCCESS, enroll); ++ if (res != ADCLI_SUCCESS) { ++ return res; ++ } ++ ++ return ADCLI_SUCCESS; ++} ++ + static adcli_result + enroll_join_or_update_tasks (adcli_enroll *enroll, + adcli_enroll_flags flags) +@@ -2019,6 +2060,11 @@ enroll_join_or_update_tasks (adcli_enroll *enroll, + update_and_calculate_enctypes (enroll); + update_computer_account (enroll); + ++ res = add_server_side_service_principals (enroll); ++ if (res != ADCLI_SUCCESS) { ++ return res; ++ } ++ + /* service_names is only set from input on the command line, so no + * additional check for explicit is needed here */ + if (enroll->service_names != NULL) { +-- +2.20.1 + diff --git a/SOURCES/0004-tools-remove-errx-from-adcli_read_password_func.patch b/SOURCES/0004-tools-remove-errx-from-adcli_read_password_func.patch new file mode 100644 index 0000000..1b53d7d --- /dev/null +++ b/SOURCES/0004-tools-remove-errx-from-adcli_read_password_func.patch @@ -0,0 +1,42 @@ +From 251d7d0c71226afb8e51f7bc5794a7a3164f5a20 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 15 Apr 2019 17:59:17 +0200 +Subject: [PATCH 4/7] tools: remove errx from adcli_read_password_func + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596 +--- + tools/tools.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/tools/tools.c b/tools/tools.c +index c4e2851..bdf6d38 100644 +--- a/tools/tools.c ++++ b/tools/tools.c +@@ -247,7 +247,9 @@ adcli_read_password_func (adcli_login_type login_type, + if (res < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; +- err (EFAIL, "couldn't read password from stdin"); ++ warn ("couldn't read password from stdin"); ++ free (buffer); ++ return NULL; + + } else if (res == 0) { + buffer[offset] = '\0'; +@@ -261,8 +263,11 @@ adcli_read_password_func (adcli_login_type login_type, + return buffer; + + } else { +- if (memchr (buffer + offset, 0, res)) +- errx (EUSAGE, "unsupported null character present in password"); ++ if (memchr (buffer + offset, 0, res)) { ++ warnx ("unsupported null character present in password"); ++ free (buffer); ++ return NULL; ++ } + offset += res; + } + } +-- +2.20.1 + diff --git a/SOURCES/0005-tools-remove-errx-from-setup_krb5_conf_directory.patch b/SOURCES/0005-tools-remove-errx-from-setup_krb5_conf_directory.patch new file mode 100644 index 0000000..8fd9197 --- /dev/null +++ b/SOURCES/0005-tools-remove-errx-from-setup_krb5_conf_directory.patch @@ -0,0 +1,63 @@ +From b8f5d995d30c17eb8bec3ac5e0777ea94f5b76c3 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 15 Apr 2019 18:00:52 +0200 +Subject: [PATCH 5/7] tools: remove errx from setup_krb5_conf_directory + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596 +--- + tools/tools.c | 38 ++++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 14 deletions(-) + +diff --git a/tools/tools.c b/tools/tools.c +index bdf6d38..fc9fa9a 100644 +--- a/tools/tools.c ++++ b/tools/tools.c +@@ -327,21 +327,31 @@ setup_krb5_conf_directory (adcli_conn *conn) + } + + if (asprintf (&directory, "%s%sadcli-krb5-XXXXXX", parent, +- (parent[0] && parent[strlen(parent) - 1] == '/') ? "" : "/") < 0) +- errx (1, "unexpected: out of memory"); +- +- if (mkdtemp (directory) == NULL) { +- errn = errno; ++ (parent[0] && parent[strlen(parent) - 1] == '/') ? "" : "/") < 0) { ++ warnx ("unexpected: out of memory"); ++ directory = NULL; /* content is undefined */ + failed = 1; +- warnx ("couldn't create temporary directory in: %s: %s", +- parent, strerror (errn)); +- } else { +- if (asprintf (&filename, "%s/krb5.conf", directory) < 0 || +- asprintf (&snippets, "%s/krb5.d", directory) < 0 || +- asprintf (&contents, "includedir %s\n%s%s\n", snippets, +- krb5_conf ? "include " : "", +- krb5_conf ? krb5_conf : "") < 0) +- errx (1, "unexpected: out of memory"); ++ } ++ ++ if (!failed) { ++ if (mkdtemp (directory) == NULL) { ++ errn = errno; ++ failed = 1; ++ warnx ("couldn't create temporary directory in: %s: %s", ++ parent, strerror (errn)); ++ } else { ++ if (asprintf (&filename, "%s/krb5.conf", directory) < 0 || ++ asprintf (&snippets, "%s/krb5.d", directory) < 0 || ++ asprintf (&contents, "includedir %s\n%s%s\n", snippets, ++ krb5_conf ? "include " : "", ++ krb5_conf ? krb5_conf : "") < 0) { ++ warnx ("unexpected: out of memory"); ++ filename = NULL; /* content is undefined */ ++ snippets = NULL; /* content is undefined */ ++ contents = NULL; /* content is undefined */ ++ failed = 1; ++ } ++ } + } + + if (!failed) { +-- +2.20.1 + diff --git a/SOURCES/0006-tools-entry-remove-errx-from-parse_option.patch b/SOURCES/0006-tools-entry-remove-errx-from-parse_option.patch new file mode 100644 index 0000000..17bb9c4 --- /dev/null +++ b/SOURCES/0006-tools-entry-remove-errx-from-parse_option.patch @@ -0,0 +1,175 @@ +From d9912e19e48ec482351b9c384140ad71922ec5c0 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 8 Apr 2019 17:22:00 +0200 +Subject: [PATCH 6/7] tools: entry - remove errx from parse_option + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596 +--- + tools/entry.c | 70 ++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 47 insertions(+), 23 deletions(-) + +diff --git a/tools/entry.c b/tools/entry.c +index 97ec6e7..f361845 100644 +--- a/tools/entry.c ++++ b/tools/entry.c +@@ -81,7 +81,7 @@ static adcli_tool_desc common_usages[] = { + { 0 }, + }; + +-static void ++static int + parse_option (Option opt, + const char *optarg, + adcli_conn *conn) +@@ -93,54 +93,58 @@ parse_option (Option opt, + switch (opt) { + case opt_login_ccache: + adcli_conn_set_login_ccache_name (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_login_user: + adcli_conn_set_login_user (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_domain: + adcli_conn_set_domain_name (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_domain_realm: + adcli_conn_set_domain_realm (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_domain_controller: + adcli_conn_set_domain_controller (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_no_password: + if (stdin_password || prompt_password) { +- errx (EUSAGE, "cannot use --no-password argument with %s", +- stdin_password ? "--stdin-password" : "--prompt-password"); ++ warnx ("cannot use --no-password argument with %s", ++ stdin_password ? "--stdin-password" : "--prompt-password"); ++ return EUSAGE; + } else { + adcli_conn_set_password_func (conn, NULL, NULL, NULL); + no_password = 1; + } +- return; ++ return ADCLI_SUCCESS; + case opt_prompt_password: + if (stdin_password || no_password) { +- errx (EUSAGE, "cannot use --prompt-password argument with %s", +- stdin_password ? "--stdin-password" : "--no-password"); ++ warnx ("cannot use --prompt-password argument with %s", ++ stdin_password ? "--stdin-password" : "--no-password"); ++ return EUSAGE; + } else { + adcli_conn_set_password_func (conn, adcli_prompt_password_func, NULL, NULL); + prompt_password = 1; + } +- return; ++ return ADCLI_SUCCESS; + case opt_stdin_password: + if (prompt_password || no_password) { +- errx (EUSAGE, "cannot use --stdin-password argument with %s", +- prompt_password ? "--prompt-password" : "--no-password"); ++ warnx ("cannot use --stdin-password argument with %s", ++ prompt_password ? "--prompt-password" : "--no-password"); ++ return EUSAGE; + } else { + adcli_conn_set_password_func (conn, adcli_read_password_func, NULL, NULL); + stdin_password = 1; + } +- return; ++ return ADCLI_SUCCESS; + case opt_verbose: +- return; ++ return ADCLI_SUCCESS; + default: + assert (0 && "not reached"); + break; + } + +- errx (EUSAGE, "failure to parse option '%c'", opt); ++ warnx ("failure to parse option '%c'", opt); ++ return EUSAGE; + } + + int +@@ -224,7 +228,11 @@ adcli_tool_user_create (adcli_conn *conn, + adcli_attrs_free (attrs); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn); ++ res = parse_option ((Option)opt, optarg, conn); ++ if (res != ADCLI_SUCCESS) { ++ adcli_attrs_free (attrs); ++ return res; ++ } + break; + } + } +@@ -322,7 +330,10 @@ adcli_tool_user_delete (adcli_conn *conn, + adcli_tool_usage (options, common_usages); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn); ++ res = parse_option ((Option)opt, optarg, conn); ++ if (res != ADCLI_SUCCESS) { ++ return res; ++ } + break; + } + } +@@ -417,7 +428,11 @@ adcli_tool_group_create (adcli_conn *conn, + adcli_attrs_free (attrs); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn); ++ res = parse_option ((Option)opt, optarg, conn); ++ if (res != ADCLI_SUCCESS) { ++ adcli_attrs_free (attrs); ++ return res; ++ } + break; + } + } +@@ -505,7 +520,10 @@ adcli_tool_group_delete (adcli_conn *conn, + adcli_tool_usage (options, common_usages); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn); ++ res = parse_option ((Option)opt, optarg, conn); ++ if (res != ADCLI_SUCCESS) { ++ return res; ++ } + break; + } + } +@@ -628,7 +646,10 @@ adcli_tool_member_add (adcli_conn *conn, + adcli_tool_usage (options, common_usages); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn); ++ res = parse_option ((Option)opt, optarg, conn); ++ if (res != ADCLI_SUCCESS) { ++ return res; ++ } + break; + } + } +@@ -725,7 +746,10 @@ adcli_tool_member_remove (adcli_conn *conn, + adcli_tool_usage (options, common_usages); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn); ++ res = parse_option ((Option)opt, optarg, conn); ++ if (res != ADCLI_SUCCESS) { ++ return res; ++ } + break; + } + } +-- +2.20.1 + diff --git a/SOURCES/0007-tools-computer-remove-errx-from-parse_option.patch b/SOURCES/0007-tools-computer-remove-errx-from-parse_option.patch new file mode 100644 index 0000000..065fc9f --- /dev/null +++ b/SOURCES/0007-tools-computer-remove-errx-from-parse_option.patch @@ -0,0 +1,294 @@ +From f127ddef23a532cd9763190527bf79b4e47fa2ab Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 8 Apr 2019 17:33:17 +0200 +Subject: [PATCH 7/7] tools: computer - remove errx from parse_option + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596 +--- + tools/computer.c | 128 +++++++++++++++++++++++++++++------------------ + 1 file changed, 80 insertions(+), 48 deletions(-) + +diff --git a/tools/computer.c b/tools/computer.c +index 9cbbb28..ac8a203 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -159,7 +159,7 @@ static adcli_tool_desc common_usages[] = { + { 0 }, + }; + +-static void ++static int + parse_option (Option opt, + const char *optarg, + adcli_conn *conn, +@@ -175,132 +175,139 @@ parse_option (Option opt, + switch (opt) { + case opt_login_ccache: + adcli_conn_set_login_ccache_name (conn, optarg ? optarg : ""); +- return; ++ return ADCLI_SUCCESS; + case opt_login_user: + if (adcli_conn_get_allowed_login_types (conn) & ADCLI_LOGIN_USER_ACCOUNT) { + adcli_conn_set_login_user (conn, optarg); + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + } else { +- errx (EUSAGE, "cannot set --user if --login-type not set to 'user'"); ++ warnx ("cannot set --user if --login-type not set to 'user'"); ++ return EUSAGE; + } +- return; ++ return ADCLI_SUCCESS; + case opt_login_type: + if (optarg && strcmp (optarg, "computer") == 0) { +- if (adcli_conn_get_login_user (conn) != NULL) +- errx (EUSAGE, "cannot set --login-type to 'computer' if --user is set"); +- else ++ if (adcli_conn_get_login_user (conn) != NULL) { ++ warnx ("cannot set --login-type to 'computer' if --user is set"); ++ return EUSAGE; ++ } else + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT); + } else if (optarg && strcmp (optarg, "user") == 0) { + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + } else { +- errx (EUSAGE, "unknown login type '%s'", optarg); ++ warnx ("unknown login type '%s'", optarg); ++ return EUSAGE; + } +- return; ++ return ADCLI_SUCCESS; + case opt_host_fqdn: + adcli_conn_set_host_fqdn (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_host_keytab: + adcli_enroll_set_keytab_name (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_computer_name: + adcli_conn_set_computer_name (conn, optarg); + adcli_enroll_set_computer_name (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_domain: + adcli_conn_set_domain_name (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_domain_realm: + adcli_conn_set_domain_realm (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_domain_controller: + adcli_conn_set_domain_controller (conn, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_domain_ou: + adcli_enroll_set_domain_ou (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_service_name: + adcli_enroll_add_service_name (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_no_password: + if (stdin_password || prompt_password) { +- errx (EUSAGE, "cannot use --no-password argument with %s", +- stdin_password ? "--stdin-password" : "--prompt-password"); ++ warnx ("cannot use --no-password argument with %s", ++ stdin_password ? "--stdin-password" : "--prompt-password"); ++ return EUSAGE; + } else { + adcli_conn_set_password_func (conn, NULL, NULL, NULL); + no_password = 1; + } +- return; ++ return ADCLI_SUCCESS; + case opt_prompt_password: + if (stdin_password || no_password) { +- errx (EUSAGE, "cannot use --prompt-password argument with %s", +- stdin_password ? "--stdin-password" : "--no-password"); ++ warnx ("cannot use --prompt-password argument with %s", ++ stdin_password ? "--stdin-password" : "--no-password"); ++ return EUSAGE; + } else { + adcli_conn_set_password_func (conn, adcli_prompt_password_func, NULL, NULL); + prompt_password = 1; + } +- return; ++ return ADCLI_SUCCESS; + case opt_stdin_password: + if (prompt_password || no_password) { +- errx (EUSAGE, "cannot use --stdin-password argument with %s", +- prompt_password ? "--prompt-password" : "--no-password"); ++ warnx ("cannot use --stdin-password argument with %s", ++ prompt_password ? "--prompt-password" : "--no-password"); ++ return EUSAGE; + } else { + adcli_conn_set_password_func (conn, adcli_read_password_func, NULL, NULL); + stdin_password = 1; + } +- return; ++ return ADCLI_SUCCESS; + case opt_os_name: + adcli_enroll_set_os_name (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_os_version: + adcli_enroll_set_os_version (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_os_service_pack: + adcli_enroll_set_os_service_pack (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_user_principal: + if (optarg && optarg[0]) + adcli_enroll_set_user_principal (enroll, optarg); + else + adcli_enroll_auto_user_principal (enroll); +- return; ++ return ADCLI_SUCCESS; + case opt_computer_password_lifetime: + errno = 0; + lifetime = strtoul (optarg, &endptr, 10); + if (errno != 0 || *endptr != '\0' || endptr == optarg) { +- errx (EUSAGE, +- "failure to parse value '%s' of option 'computer-password-lifetime'; " +- "expecting non-negative integer indicating the lifetime in days", +- optarg); ++ warnx ("failure to parse value '%s' of option 'computer-password-lifetime'; " ++ "expecting non-negative integer indicating the lifetime in days", ++ optarg); ++ return EUSAGE; + } + + adcli_enroll_set_computer_password_lifetime (enroll, lifetime); +- return; ++ return ADCLI_SUCCESS; + case opt_samba_data_tool: + errno = 0; + ret = access (optarg, X_OK); + if (ret != 0) { + ret = errno; +- errx (EUSAGE, "Failed to access tool to add Samba data: %s", strerror (ret)); ++ warnx ("Failed to access tool to add Samba data: %s", strerror (ret)); ++ return EUSAGE; + } else { + adcli_enroll_set_samba_data_tool (enroll, optarg); + } +- return; ++ return ADCLI_SUCCESS; + case opt_trusted_for_delegation: + if (strcasecmp (optarg, "true") == 0 || strcasecmp (optarg, "yes") == 0) { + adcli_enroll_set_trusted_for_delegation (enroll, true); + } else { + adcli_enroll_set_trusted_for_delegation (enroll, false); + } +- return; ++ return ADCLI_SUCCESS; + case opt_add_service_principal: + adcli_enroll_add_service_principal_to_add (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_remove_service_principal: + adcli_enroll_add_service_principal_to_remove (enroll, optarg); +- return; ++ return ADCLI_SUCCESS; + case opt_verbose: +- return; ++ return ADCLI_SUCCESS; + + /* Should be handled by caller */ + case opt_show_details: +@@ -311,7 +318,8 @@ parse_option (Option opt, + break; + } + +- errx (EUSAGE, "failure to parse option '%c'", opt); ++ warnx ("failure to parse option '%c'", opt); ++ return EUSAGE; + } + + static void +@@ -407,7 +415,11 @@ adcli_tool_computer_join (adcli_conn *conn, + adcli_enroll_unref (enroll); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn, enroll); ++ res = parse_option ((Option)opt, optarg, conn, enroll); ++ if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ return res; ++ } + break; + } + } +@@ -519,7 +531,11 @@ adcli_tool_computer_update (adcli_conn *conn, + adcli_enroll_unref (enroll); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn, enroll); ++ res = parse_option ((Option)opt, optarg, conn, enroll); ++ if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ return res; ++ } + break; + } + } +@@ -610,7 +626,11 @@ adcli_tool_computer_testjoin (adcli_conn *conn, + adcli_enroll_unref (enroll); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn, enroll); ++ res = parse_option ((Option)opt, optarg, conn, enroll); ++ if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ return res; ++ } + break; + } + } +@@ -707,7 +727,11 @@ adcli_tool_computer_preset (adcli_conn *conn, + adcli_enroll_unref (enroll); + return 2; + default: +- parse_option ((Option)opt, optarg, conn, enroll); ++ res = parse_option ((Option)opt, optarg, conn, enroll); ++ if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ return res; ++ } + break; + } + } +@@ -801,7 +825,11 @@ adcli_tool_computer_reset (adcli_conn *conn, + adcli_enroll_unref (enroll); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn, enroll); ++ res = parse_option ((Option)opt, optarg, conn, enroll); ++ if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ return res; ++ } + break; + } + } +@@ -884,7 +912,11 @@ adcli_tool_computer_delete (adcli_conn *conn, + adcli_enroll_unref (enroll); + return opt == 'h' ? 0 : 2; + default: +- parse_option ((Option)opt, optarg, conn, enroll); ++ res = parse_option ((Option)opt, optarg, conn, enroll); ++ if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ return res; ++ } + break; + } + } +-- +2.20.1 + diff --git a/SPECS/adcli.spec b/SPECS/adcli.spec index c60909d..371dfe4 100644 --- a/SPECS/adcli.spec +++ b/SPECS/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.8.2 -Release: 2%{?dist} +Release: 3%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: http://cgit.freedesktop.org/realmd/adcli @@ -36,6 +36,60 @@ Patch26: 0002-_adcli_call_external_program-silence-noisy-debug-mes.patch Patch27: 0003-Do-not-add-service-principals-twice.patch Patch28: 0004-Do-not-depend-on-default_realm-in-krb5.conf.patch +# rhbz#1677194 - Realm cannot join domain when hostname is not FQDN +Patch29: 0001-adutil-add-_adcli_strv_add_unique.patch +Patch30: 0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch + +# Forward port of RHEL-7.7 ticket rhbz#1642546 - adcli exports kerberos ticket +# with old kvno +Patch31: 0001-Increment-kvno-after-password-change-with-user-creds.patch + +# Forward port of RHEL-7.7 ticket rhbz#1595911 - [RFE] Have `adcli join` work +# without FQDN in `hostname` output +Patch32: 0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch + +# Forward port of RHEL-7.7 ticket rhbz#1644311 - Improve handling of service +# principals +Patch33: 0001-join-always-add-service-principals.patch +Patch34: 0002-library-return-error-if-no-matching-key-was-found.patch + +# Forward port of RHEL-7.7 ticket rhbz#1337489 - [RFE] adcli command with +# --unix-* options doesn't update values in UnixAttributes Tab for user +Patch35: 0001-create-user-add-nis-domain-option.patch +Patch36: 0002-create-user-try-to-find-NIS-domain-if-needed.patch + +# Forward port of RHEL-7.7 ticket rhbz#1630187 - [RFE] adcli join should +# preserve SPN added by adcli preset-computer +Patch37: 0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch +Patch38: 0002-library-make-_adcli_strv_has_ex-public.patch +Patch39: 0003-library-_adcli_krb5_build_principal-allow-principals.patch +Patch40: 0004-library-make-sure-server-side-SPNs-are-preserved.patch + +# Forward port of RHEL-7.7 ticket rhbz#1622583 - [RFE] Need an option for adcli +# command which will show domain join status. +Patch41: 0001-Implement-adcli-testjoin.patch + +# Forward port of RHEL-7.7 ticket rhbz#1630187 - [RFE] adcli join should +# preserve SPN added by adcli preset-computer - additional patch +Patch42: 0001-library-add-missing-strdup.patch + +# Forward port of RHEL-7.7 ticket rhbz#1588596 - many adcli-krb5-????? +# directories are created /tmp +Patch43: 0001-tools-remove-errx-from-computer-commands.patch +Patch44: 0002-tools-remove-errx-from-user-and-group-commands.patch +Patch45: 0003-tools-remove-errx-from-info-commands.patch +Patch46: 0004-tools-remove-errx-from-adcli_read_password_func.patch +Patch47: 0005-tools-remove-errx-from-setup_krb5_conf_directory.patch +Patch48: 0006-tools-entry-remove-errx-from-parse_option.patch +Patch49: 0007-tools-computer-remove-errx-from-parse_option.patch + +# rhbz#1717355 - `adcli join` fails in FIPS enabled environment +Patch50: 0001-Fix-for-issues-found-by-Coverity.patch +Patch51: 0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch +Patch52: 0002-adconn-add-adcli_conn_set_krb5_context.patch +Patch53: 0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch +Patch54: 0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch + BuildRequires: gcc BuildRequires: intltool pkgconfig BuildRequires: libtool @@ -58,35 +112,7 @@ standard LDAP and Kerberos calls. %define _hardened_build 1 %prep -%setup -q -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 -%patch19 -p1 -%patch20 -p1 -%patch21 -p1 -%patch22 -p1 -%patch23 -p1 -%patch24 -p1 -%patch25 -p1 -%patch26 -p1 -%patch27 -p1 -%patch28 -p1 +%autosetup -p1 %build autoreconf --force --install --verbose @@ -124,6 +150,13 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Fri Jun 14 2019 Sumit Bose - 0.8.2-3 +- use autosetup macro to simplify patch handling +- fixed rpmlint warnings in the spec file +- join failed if hostname is not FQDN [#1677194] +- adcli join fails in FIPS enabled environment [#1717355] +- forward port of RHEL-7.7 fixes and enhancements + * Tue Oct 09 2018 Sumit Bose - 0.8.2-2 - Do not add service principals twice and related fixes - Resolves: rhbz#1631734