diff --git a/0001-Implement-adcli-testjoin.patch b/0001-Implement-adcli-testjoin.patch new file mode 100644 index 0000000..d75cbf2 --- /dev/null +++ b/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/0001-Increment-kvno-after-password-change-with-user-creds.patch b/0001-Increment-kvno-after-password-change-with-user-creds.patch new file mode 100644 index 0000000..aeef509 --- /dev/null +++ b/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/0001-adutil-add-_adcli_strv_add_unique.patch b/0001-adutil-add-_adcli_strv_add_unique.patch new file mode 100644 index 0000000..f49f5f8 --- /dev/null +++ b/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/0001-create-user-add-nis-domain-option.patch b/0001-create-user-add-nis-domain-option.patch new file mode 100644 index 0000000..32b0ca9 --- /dev/null +++ b/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/0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch b/0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch new file mode 100644 index 0000000..dfdf745 --- /dev/null +++ b/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/0001-fix-typo-in-flag-value.patch b/0001-fix-typo-in-flag-value.patch new file mode 100644 index 0000000..07577b7 --- /dev/null +++ b/0001-fix-typo-in-flag-value.patch @@ -0,0 +1,25 @@ +From 870ecd8f982ebb97092a93d730ad4006bd78505c Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 8 Aug 2018 12:03:01 +0200 +Subject: [PATCH 1/4] fix typo in flag value + +--- + library/adenroll.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/library/adenroll.h b/library/adenroll.h +index f87dffa..abbbfd4 100644 +--- a/library/adenroll.h ++++ b/library/adenroll.h +@@ -30,7 +30,7 @@ typedef enum { + ADCLI_ENROLL_NO_KEYTAB = 1 << 1, + ADCLI_ENROLL_ALLOW_OVERWRITE = 1 << 2, + ADCLI_ENROLL_PASSWORD_VALID = 1 << 3, +- ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 3, ++ ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 4, + } adcli_enroll_flags; + + typedef struct _adcli_enroll adcli_enroll; +-- +2.17.1 + diff --git a/0001-join-always-add-service-principals.patch b/0001-join-always-add-service-principals.patch new file mode 100644 index 0000000..0281dc6 --- /dev/null +++ b/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/0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch b/0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch new file mode 100644 index 0000000..c682c5a --- /dev/null +++ b/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/0001-tools-properly-release-internal-data-on-error.patch b/0001-tools-properly-release-internal-data-on-error.patch new file mode 100644 index 0000000..b78c8a4 --- /dev/null +++ b/0001-tools-properly-release-internal-data-on-error.patch @@ -0,0 +1,152 @@ +From 41fdcb1af885d99a91e27406e9343b322f67756a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 28 Jun 2018 20:13:26 +0200 +Subject: [PATCH] tools: properly release internal data on error + +Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1588596 +--- + tools/computer.c | 39 ++++++++++++++++++++++++++++++++++++--- + 1 file changed, 36 insertions(+), 3 deletions(-) + +diff --git a/tools/computer.c b/tools/computer.c +index 3813f0a..112340e 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -415,11 +415,16 @@ adcli_tool_computer_join (adcli_conn *conn, + + if (argc == 1) + adcli_conn_set_domain_name (conn, argv[0]); +- else if (argc > 1) ++ else if (argc > 1) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); + errx (2, "extra arguments specified"); ++ } + + 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 ()); +@@ -427,6 +432,8 @@ adcli_tool_computer_join (adcli_conn *conn, + + res = adcli_enroll_join (enroll, flags); + if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); + errx (-res, "joining domain %s failed: %s", + adcli_conn_get_domain_name (conn), + adcli_get_last_error ()); +@@ -525,12 +532,16 @@ adcli_tool_computer_update (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 ()); + } + + 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 ()); +@@ -538,6 +549,8 @@ adcli_tool_computer_update (adcli_conn *conn, + + res = adcli_enroll_update (enroll, flags); + if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); + errx (-res, "updating membership with domain %s failed: %s", + adcli_conn_get_domain_name (conn), + adcli_get_last_error ()); +@@ -630,6 +643,8 @@ adcli_tool_computer_preset (adcli_conn *conn, + + 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 ()); +@@ -643,6 +658,8 @@ adcli_tool_computer_preset (adcli_conn *conn, + + res = adcli_enroll_join (enroll, flags); + if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); + errx (-res, "presetting %s in %s domain failed: %s", argv[i], + adcli_conn_get_domain_name (conn), + adcli_get_last_error ()); +@@ -707,11 +724,16 @@ adcli_tool_computer_reset (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc != 1) ++ if (argc != 1) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); + errx (EUSAGE, "specify one host name of computer account to reset"); ++ } + + 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 ()); +@@ -722,6 +744,8 @@ adcli_tool_computer_reset (adcli_conn *conn, + + res = adcli_enroll_password (enroll, 0); + if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); + errx (-res, "resetting %s in %s domain failed: %s", argv[0], + adcli_conn_get_domain_name (conn), + adcli_get_last_error ()); +@@ -781,19 +805,26 @@ adcli_tool_computer_delete (adcli_conn *conn, + argc -= optind; + argv += optind; + +- if (argc > 1) ++ if (argc > 1) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); + errx (EUSAGE, "specify one host name of computer account to delete"); ++ } + + adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); + + 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 ()); +@@ -804,6 +835,8 @@ adcli_tool_computer_delete (adcli_conn *conn, + + res = adcli_enroll_delete (enroll, 0); + if (res != ADCLI_SUCCESS) { ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); + errx (-res, "deleting %s in %s domain failed: %s", argv[0], + adcli_conn_get_domain_name (conn), + adcli_get_last_error ()); +-- +2.20.1 + diff --git a/0002-_adcli_call_external_program-silence-noisy-debug-mes.patch b/0002-_adcli_call_external_program-silence-noisy-debug-mes.patch new file mode 100644 index 0000000..76fe1dc --- /dev/null +++ b/0002-_adcli_call_external_program-silence-noisy-debug-mes.patch @@ -0,0 +1,25 @@ +From 8cc4ef1cae7d4d753f2cf9aeb8021dd96cb75d36 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 8 Aug 2018 12:17:18 +0200 +Subject: [PATCH 2/4] _adcli_call_external_program: silence noisy debug message + +--- + library/adutil.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/library/adutil.c b/library/adutil.c +index 6334b52..17d2caa 100644 +--- a/library/adutil.c ++++ b/library/adutil.c +@@ -672,7 +672,7 @@ done: + if (wret == -1) { + _adcli_err ("No sure what happend to net command."); + } else { +- if (WIFEXITED (status)) { ++ if (WIFEXITED (status) && WEXITSTATUS (status) != 0) { + _adcli_err ("net command failed with %d.", + WEXITSTATUS (status)); + } +-- +2.17.1 + diff --git a/0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch b/0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch new file mode 100644 index 0000000..e4a6bc5 --- /dev/null +++ b/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/0002-create-user-try-to-find-NIS-domain-if-needed.patch b/0002-create-user-try-to-find-NIS-domain-if-needed.patch new file mode 100644 index 0000000..0ecdc90 --- /dev/null +++ b/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/0002-library-make-_adcli_strv_has_ex-public.patch b/0002-library-make-_adcli_strv_has_ex-public.patch new file mode 100644 index 0000000..db18951 --- /dev/null +++ b/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/0002-library-return-error-if-no-matching-key-was-found.patch b/0002-library-return-error-if-no-matching-key-was-found.patch new file mode 100644 index 0000000..f9c68d6 --- /dev/null +++ b/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/0003-Do-not-add-service-principals-twice.patch b/0003-Do-not-add-service-principals-twice.patch new file mode 100644 index 0000000..5d0bfcf --- /dev/null +++ b/0003-Do-not-add-service-principals-twice.patch @@ -0,0 +1,57 @@ +From f05adc23d5cc9f1dfa5638e31949dcd81d632df9 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 13 Aug 2018 17:32:24 +0200 +Subject: [PATCH 3/4] Do not add service principals twice + +--- + library/adenroll.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index c4ba537..bb50365 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -313,6 +313,7 @@ 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); +@@ -321,14 +322,28 @@ 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 (); +- enroll->service_principals = _adcli_strv_add (enroll->service_principals, +- name, &length); ++ 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); ++ } + + if (enroll->host_fqdn) { + if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0) + return_unexpected_if_reached (); +- enroll->service_principals = _adcli_strv_add (enroll->service_principals, +- name, &length); ++ 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); ++ } + } + } + +-- +2.17.1 + diff --git a/0003-library-_adcli_krb5_build_principal-allow-principals.patch b/0003-library-_adcli_krb5_build_principal-allow-principals.patch new file mode 100644 index 0000000..217636c --- /dev/null +++ b/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/0004-Do-not-depend-on-default_realm-in-krb5.conf.patch b/0004-Do-not-depend-on-default_realm-in-krb5.conf.patch new file mode 100644 index 0000000..d12f335 --- /dev/null +++ b/0004-Do-not-depend-on-default_realm-in-krb5.conf.patch @@ -0,0 +1,27 @@ +From 8f726817b9ff643a382fa12ea9ff489cd5ab9068 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 13 Aug 2018 18:24:58 +0200 +Subject: [PATCH 4/4] Do not depend on default_realm in krb5.conf + +--- + library/adenroll.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index bb50365..02bd9e3 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -1661,7 +1661,9 @@ remove_principal_from_keytab (adcli_enroll *enroll, + krb5_principal principal; + match_principal_kvno closure; + +- code = krb5_parse_name (k5, principal_name, &principal); ++ code = _adcli_krb5_build_principal (k5, principal_name, ++ adcli_conn_get_domain_realm (enroll->conn), ++ &principal); + if (code != 0) { + _adcli_err ("Couldn't parse principal: %s: %s", + principal_name, krb5_get_error_message (k5, code)); +-- +2.17.1 + diff --git a/0004-library-make-sure-server-side-SPNs-are-preserved.patch b/0004-library-make-sure-server-side-SPNs-are-preserved.patch new file mode 100644 index 0000000..07cc8fb --- /dev/null +++ b/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/adcli.spec b/adcli.spec index d6348c1..e935f24 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.8.2 -Release: 3%{?dist} +Release: 4%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: http://cgit.freedesktop.org/realmd/adcli @@ -31,6 +31,48 @@ Patch22: 0022-Add-add-service-principal-and-remove-service-princip.patch Patch23: 0023-adcli_conn_is_writeable-do-not-crash-id-domain_disco.patch Patch24: 0024-doc-fix-typos-in-the-adcli-man-page.patch +# Additional fixes for rhbz#1593240 +Patch25: 0001-fix-typo-in-flag-value.patch +Patch26: 0002-_adcli_call_external_program-silence-noisy-debug-mes.patch + +# rhbz#1608212 +Patch27: 0003-Do-not-add-service-principals-twice.patch + +# Additional fixed for rhbz#1547014 +Patch28: 0004-Do-not-depend-on-default_realm-in-krb5.conf.patch + +# rhbz#1649868 +Patch29: 0001-adutil-add-_adcli_strv_add_unique.patch +Patch30: 0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch + +# rhbz#1588596 - many adcli-krb5-????? directories are created /tmp +Patch31: 0001-tools-properly-release-internal-data-on-error.patch + +# rhbz#1642546 - adcli exports kerberos ticket with old kvno +Patch32: 0001-Increment-kvno-after-password-change-with-user-creds.patch + +# rhbz#1595911 - [RFE] Have `adcli join` work without FQDN in `hostname` output +# with some additional man page fixes from rhbz#1440533 +Patch33: 0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch + +# rhbz#1644311 - Improve handling of service principals +Patch34: 0001-join-always-add-service-principals.patch +Patch35: 0002-library-return-error-if-no-matching-key-was-found.patch + +# rhbz#1337489 - [RFE] adcli command with --unix-* options doesn't update +# values in UnixAttributes Tab for user +Patch36: 0001-create-user-add-nis-domain-option.patch +Patch37: 0002-create-user-try-to-find-NIS-domain-if-needed.patch + +# rhbz#1630187 - [RFE] adcli join should preserve SPN added by adcli preset-computer +Patch38: 0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch +Patch39: 0002-library-make-_adcli_strv_has_ex-public.patch +Patch40: 0003-library-_adcli_krb5_build_principal-allow-principals.patch +Patch41: 0004-library-make-sure-server-side-SPNs-are-preserved.patch + +# rhbz#1622583 - [RFE] Need an option for adcli command which will show domain join status. +Patch42: 0001-Implement-adcli-testjoin.patch + BuildRequires: gcc BuildRequires: intltool pkgconfig BuildRequires: libtool @@ -53,31 +95,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 +%autosetup -p1 %build autoreconf --force --install --verbose @@ -111,6 +129,12 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Fri Mar 22 2019 Sumit Bose - 0.8.2-4 +- various fixes and improvements + Resolves: rhbz#1593240, rhbz#1608212, rhbz#1547014, rhbz#1547014, + rhbz#1649868, rhbz#1588596, rhbz#1642546, rhbz#1595911, + rhbz#1644311, rhbz#1337489, rhbz#1630187, rhbz#1622583 + * Thu Jan 31 2019 Fedora Release Engineering - 0.8.2-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild