File 0015-update-allow-to-add-service-names.patch of Package adcli
388
1
From 8629dd3a8be410d7d13e034af5f07adb26d52da4 Mon Sep 17 00:00:00 2001
2
From: Sumit Bose <sbose@redhat.com>
3
Date: Mon, 4 Jun 2018 10:49:33 +0200
4
Subject: [PATCH 15/25] update: allow to add service names
5
6
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547013
7
https://bugzilla.redhat.com/show_bug.cgi?id=1545568
8
---
9
library/adenroll.c | 136 +++++++++++++++++++++++++++++++++-------------------
10
library/adkrb5.c | 113 +++++++++++++++++++++++++++++++++++++++++++
11
library/adprivate.h | 6 +++
12
3 files changed, 206 insertions(+), 49 deletions(-)
13
14
diff --git a/library/adenroll.c b/library/adenroll.c
15
index 1cc8ffc..6b6630f 100644
16
--- a/library/adenroll.c
17
+++ b/library/adenroll.c
18
19
}
20
21
static adcli_result
22
-ensure_service_principals (adcli_result res,
23
- adcli_enroll *enroll)
24
+add_service_names_to_service_principals (adcli_enroll *enroll)
25
{
26
char *name;
27
int length = 0;
28
int i;
29
30
+ if (enroll->service_principals != NULL) {
31
+ length = seq_count (enroll->service_principals);
32
+ }
33
+
34
+ for (i = 0; enroll->service_names[i] != NULL; i++) {
35
+ if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
36
+ return_unexpected_if_reached ();
37
+ enroll->service_principals = _adcli_strv_add (enroll->service_principals,
38
+ name, &length);
39
+
40
+ if (enroll->host_fqdn) {
41
+ if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
42
+ return_unexpected_if_reached ();
43
+ enroll->service_principals = _adcli_strv_add (enroll->service_principals,
44
+ name, &length);
45
+ }
46
+ }
47
+
48
+ return ADCLI_SUCCESS;
49
+}
50
+
51
+static adcli_result
52
+ensure_service_principals (adcli_result res,
53
+ adcli_enroll *enroll)
54
+{
55
if (res != ADCLI_SUCCESS)
56
return res;
57
58
59
60
if (!enroll->service_principals) {
61
assert (enroll->service_names != NULL);
62
-
63
- for (i = 0; enroll->service_names[i] != NULL; i++) {
64
- if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
65
- return_unexpected_if_reached ();
66
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
67
- name, &length);
68
-
69
- if (enroll->host_fqdn) {
70
- if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
71
- return_unexpected_if_reached ();
72
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
73
- name, &length);
74
- }
75
- }
76
+ return add_service_names_to_service_principals (enroll);
77
}
78
79
return ADCLI_SUCCESS;
80
81
return_unexpected_if_fail (k5 != NULL);
82
83
enroll->keytab_principals = calloc (count + 3, sizeof (krb5_principal));
84
+ return_unexpected_if_fail (enroll->keytab_principals != NULL);
85
at = 0;
86
87
/* First add the principal for the computer account name */
88
89
}
90
}
91
92
- if (res == ADCLI_SUCCESS && !enroll->user_princpal_generate) {
93
+ if (res == ADCLI_SUCCESS && enroll->user_principal != NULL && !enroll->user_princpal_generate) {
94
char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
95
LDAPMod userPrincipalName = { LDAP_MOD_REPLACE, "userPrincipalName", { vals_userPrincipalName, }, };
96
LDAPMod *mods[] = { &userPrincipalName, NULL, };
97
98
krb5_context k5,
99
krb5_principal principal,
100
const char *principal_name,
101
- int *which_salt)
102
+ int *which_salt,
103
+ adcli_enroll_flags flags)
104
{
105
match_principal_kvno closure;
106
krb5_data password;
107
108
enroll->keytab_name);
109
}
110
111
- password.data = enroll->computer_password;
112
- password.length = strlen (enroll->computer_password);
113
-
114
enctypes = adcli_enroll_get_keytab_enctypes (enroll);
115
116
- /*
117
- * So we need to discover which salt to use. As a side effect we are
118
- * also testing that our account works.
119
- */
120
+ if (flags & ADCLI_ENROLL_PASSWORD_VALID) {
121
+ code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal,
122
+ enroll->kvno, enctypes);
123
+ } else {
124
125
- salts = build_principal_salts (enroll, k5, principal);
126
- return_unexpected_if_fail (salts != NULL);
127
+ password.data = enroll->computer_password;
128
+ password.length = strlen (enroll->computer_password);
129
130
- if (*which_salt < 0) {
131
- code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
132
- enctypes, salts, which_salt);
133
- if (code != 0) {
134
- _adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s",
135
- principal_name, krb5_get_error_message (k5, code));
136
- *which_salt = DEFAULT_SALT;
137
- } else {
138
- assert (*which_salt >= 0);
139
- _adcli_info ("Discovered which keytab salt to use");
140
+ /*
141
+ * So we need to discover which salt to use. As a side effect we are
142
+ * also testing that our account works.
143
+ */
144
+
145
+ salts = build_principal_salts (enroll, k5, principal);
146
+ return_unexpected_if_fail (salts != NULL);
147
+
148
+ if (*which_salt < 0) {
149
+ code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
150
+ enctypes, salts, which_salt);
151
+ if (code != 0) {
152
+ _adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s",
153
+ principal_name, krb5_get_error_message (k5, code));
154
+ *which_salt = DEFAULT_SALT;
155
+ } else {
156
+ assert (*which_salt >= 0);
157
+ _adcli_info ("Discovered which keytab salt to use");
158
+ }
159
}
160
- }
161
162
- code = _adcli_krb5_keytab_add_entries (k5, enroll->keytab, principal,
163
- enroll->kvno, &password, enctypes, &salts[*which_salt]);
164
+ code = _adcli_krb5_keytab_add_entries (k5, enroll->keytab, principal,
165
+ enroll->kvno, &password, enctypes, &salts[*which_salt]);
166
167
- free_principal_salts (k5, salts);
168
+ free_principal_salts (k5, salts);
169
170
- if (code != 0) {
171
- _adcli_err ("Couldn't add keytab entries: %s: %s",
172
- enroll->keytab_name, krb5_get_error_message (k5, code));
173
- return ADCLI_ERR_FAIL;
174
+ if (code != 0) {
175
+ _adcli_err ("Couldn't add keytab entries: %s: %s",
176
+ enroll->keytab_name, krb5_get_error_message (k5, code));
177
+ return ADCLI_ERR_FAIL;
178
+ }
179
}
180
181
182
183
}
184
185
static adcli_result
186
-update_keytab_for_principals (adcli_enroll *enroll)
187
+update_keytab_for_principals (adcli_enroll *enroll,
188
+ adcli_enroll_flags flags)
189
{
190
krb5_context k5;
191
adcli_result res;
192
193
if (krb5_unparse_name (k5, enroll->keytab_principals[i], &name) != 0)
194
name = "";
195
res = add_principal_to_keytab (enroll, k5, enroll->keytab_principals[i],
196
- name, &which_salt);
197
+ name, &which_salt, flags);
198
krb5_free_unparsed_name (k5, name);
199
200
if (res != ADCLI_SUCCESS)
201
202
/* We ignore failures of setting these fields */
203
update_and_calculate_enctypes (enroll);
204
update_computer_account (enroll);
205
+
206
+ /* service_names is only set from input on the command line, so no
207
+ * additional check for explicit is needed here */
208
+ if (enroll->service_names != NULL) {
209
+ res = add_service_names_to_service_principals (enroll);
210
+ if (res != ADCLI_SUCCESS) {
211
+ return res;
212
+ }
213
+ res = ensure_keytab_principals (res, enroll);
214
+ if (res != ADCLI_SUCCESS) {
215
+ return res;
216
+ }
217
+ }
218
+
219
update_service_principals (enroll);
220
221
if (flags & ADCLI_ENROLL_NO_KEYTAB)
222
223
* that we use for salting.
224
*/
225
226
- return update_keytab_for_principals (enroll);
227
+ return update_keytab_for_principals (enroll, flags);
228
}
229
230
adcli_result
231
232
233
if (_adcli_check_nt_time_string_lifetime (value,
234
adcli_enroll_get_computer_password_lifetime (enroll))) {
235
- flags |= ADCLI_ENROLL_NO_KEYTAB;
236
+ /* Do not update keytab if neither new service principals have
237
+ * to be added nor the user principal has to be changed. */
238
+ if (enroll->service_names == NULL && (enroll->user_principal == NULL || enroll->user_princpal_generate)) {
239
+ flags |= ADCLI_ENROLL_NO_KEYTAB;
240
+ }
241
flags |= ADCLI_ENROLL_PASSWORD_VALID;
242
}
243
free (value);
244
diff --git a/library/adkrb5.c b/library/adkrb5.c
245
index b0e903e..033c181 100644
246
--- a/library/adkrb5.c
247
+++ b/library/adkrb5.c
248
249
return ADCLI_SUCCESS;
250
}
251
252
+typedef struct {
253
+ krb5_kvno kvno;
254
+ krb5_enctype enctype;
255
+ int matched;
256
+} match_enctype_kvno;
257
+
258
+static krb5_boolean
259
+match_enctype_and_kvno (krb5_context k5,
260
+ krb5_keytab_entry *entry,
261
+ void *data)
262
+{
263
+ krb5_boolean similar = FALSE;
264
+ match_enctype_kvno *closure = data;
265
+ krb5_error_code code;
266
+
267
+ assert (closure->enctype);
268
+
269
+ code = krb5_c_enctype_compare (k5, closure->enctype, entry->key.enctype,
270
+ &similar);
271
+
272
+ if (code == 0 && entry->vno == closure->kvno && similar) {
273
+ closure->matched = 1;
274
+ return 1;
275
+ }
276
+
277
+ return 0;
278
+}
279
+
280
+static krb5_error_code
281
+_adcli_krb5_get_keyblock (krb5_context k5,
282
+ krb5_keytab keytab,
283
+ krb5_keyblock *keyblock,
284
+ krb5_boolean (* match_func) (krb5_context,
285
+ krb5_keytab_entry *,
286
+ void *),
287
+ void *match_data)
288
+{
289
+ krb5_kt_cursor cursor;
290
+ krb5_keytab_entry entry;
291
+ krb5_error_code code;
292
+
293
+ code = krb5_kt_start_seq_get (k5, keytab, &cursor);
294
+ if (code == KRB5_KT_END || code == ENOENT)
295
+ return 0;
296
+ else if (code != 0)
297
+ return code;
298
+
299
+ for (;;) {
300
+ code = krb5_kt_next_entry (k5, keytab, &entry, &cursor);
301
+ if (code != 0)
302
+ break;
303
+
304
+ /* See if we should remove this entry */
305
+ if (!match_func (k5, &entry, match_data)) {
306
+ krb5_free_keytab_entry_contents (k5, &entry);
307
+ continue;
308
+ }
309
+
310
+ code = krb5_copy_keyblock_contents (k5, &entry.key, keyblock);
311
+ krb5_free_keytab_entry_contents (k5, &entry);
312
+ break;
313
+
314
+
315
+ }
316
+
317
+ if (code == KRB5_KT_END)
318
+ code = 0;
319
+
320
+ krb5_kt_end_seq_get (k5, keytab, &cursor);
321
+ return code;
322
+}
323
+
324
+krb5_error_code
325
+_adcli_krb5_keytab_copy_entries (krb5_context k5,
326
+ krb5_keytab keytab,
327
+ krb5_principal principal,
328
+ krb5_kvno kvno,
329
+ krb5_enctype *enctypes)
330
+{
331
+ krb5_keytab_entry entry;
332
+ krb5_error_code code;
333
+ int i;
334
+ match_enctype_kvno closure;
335
+
336
+ for (i = 0; enctypes[i] != 0; i++) {
337
+
338
+ closure.kvno = kvno;
339
+ closure.enctype = enctypes[i];
340
+ closure.matched = 0;
341
+
342
+ memset (&entry, 0, sizeof (entry));
343
+
344
+ code = _adcli_krb5_get_keyblock (k5, keytab, &entry.key,
345
+ match_enctype_and_kvno, &closure);
346
+ if (code != 0) {
347
+ return code;
348
+ }
349
+
350
+
351
+ entry.principal = principal;
352
+ entry.vno = kvno;
353
+
354
+ code = krb5_kt_add_entry (k5, keytab, &entry);
355
+
356
+ entry.principal = NULL;
357
+ krb5_free_keytab_entry_contents (k5, &entry);
358
+
359
+ if (code != 0)
360
+ return code;
361
+ }
362
+
363
+ return 0;
364
+}
365
366
krb5_error_code
367
_adcli_krb5_keytab_add_entries (krb5_context k5,
368
diff --git a/library/adprivate.h b/library/adprivate.h
369
index 83a88f6..7485249 100644
370
--- a/library/adprivate.h
371
+++ b/library/adprivate.h
372
373
374
char * _adcli_krb5_format_enctypes (krb5_enctype *enctypes);
375
376
+krb5_error_code _adcli_krb5_keytab_copy_entries (krb5_context k5,
377
+ krb5_keytab keytab,
378
+ krb5_principal principal,
379
+ krb5_kvno kvno,
380
+ krb5_enctype *enctypes);
381
+
382
struct _adcli_attrs {
383
LDAPMod **mods;
384
int len;
385
--
386
2.16.4
387
388