2 Unix SMB/CIFS implementation.
4 Samba KDB plugin for MIT Kerberos
6 Copyright (c) 2010 Simo Sorce <idra@samba.org>.
7 Copyright (c) 2014 Andreas Schneider <asn@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "system/kerberos.h"
30 #include "kdc/samba_kdc.h"
31 #include "kdc/mit_samba.h"
32 #include "kdb_samba.h"
35 #define DBGC_CLASS DBGC_KERBEROS
37 #define ADMIN_LIFETIME 60*60*3 /* 3 hours */
39 krb5_error_code
ks_get_principal(krb5_context context
,
40 krb5_const_principal principal
,
42 krb5_db_entry
**kentry
)
44 struct mit_samba_context
*mit_ctx
;
47 mit_ctx
= ks_get_context(context
);
48 if (mit_ctx
== NULL
) {
49 return KRB5_KDB_DBNOTINITED
;
52 code
= mit_samba_get_principal(mit_ctx
,
65 static void ks_free_principal_e_data(krb5_context context
, krb5_octet
*e_data
)
67 struct samba_kdc_entry
*skdc_entry
;
69 skdc_entry
= talloc_get_type_abort(e_data
,
70 struct samba_kdc_entry
);
71 skdc_entry
->kdc_entry
= NULL
;
72 TALLOC_FREE(skdc_entry
);
75 void ks_free_principal(krb5_context context
, krb5_db_entry
*entry
)
77 krb5_tl_data
*tl_data_next
= NULL
;
78 krb5_tl_data
*tl_data
= NULL
;
82 krb5_free_principal(context
, entry
->princ
);
84 for (tl_data
= entry
->tl_data
; tl_data
; tl_data
= tl_data_next
) {
85 tl_data_next
= tl_data
->tl_data_next
;
86 if (tl_data
->tl_data_contents
!= NULL
) {
87 free(tl_data
->tl_data_contents
);
92 if (entry
->key_data
!= NULL
) {
93 for (i
= 0; i
< entry
->n_key_data
; i
++) {
94 for (j
= 0; j
< entry
->key_data
[i
].key_data_ver
; j
++) {
95 if (entry
->key_data
[i
].key_data_length
[j
] != 0) {
96 if (entry
->key_data
[i
].key_data_contents
[j
] != NULL
) {
97 memset(entry
->key_data
[i
].key_data_contents
[j
], 0, entry
->key_data
[i
].key_data_length
[j
]);
98 free(entry
->key_data
[i
].key_data_contents
[j
]);
101 entry
->key_data
[i
].key_data_contents
[j
] = NULL
;
102 entry
->key_data
[i
].key_data_length
[j
] = 0;
103 entry
->key_data
[i
].key_data_type
[j
] = 0;
106 free(entry
->key_data
);
110 ks_free_principal_e_data(context
, entry
->e_data
);
117 static krb5_boolean
ks_is_master_key_principal(krb5_context context
,
118 krb5_const_principal princ
)
120 return krb5_princ_size(context
, princ
) == 2 &&
121 ks_data_eq_string(princ
->data
[0], "K") &&
122 ks_data_eq_string(princ
->data
[1], "M");
125 static krb5_error_code
ks_get_master_key_principal(krb5_context context
,
126 krb5_const_principal princ
,
127 krb5_db_entry
**kentry_ptr
)
129 krb5_error_code code
;
130 krb5_key_data
*key_data
;
132 krb5_db_entry
*kentry
;
136 kentry
= calloc(1, sizeof(krb5_db_entry
));
137 if (kentry
== NULL
) {
141 kentry
->magic
= KRB5_KDB_MAGIC_NUMBER
;
142 kentry
->len
= KRB5_KDB_V1_BASE_LENGTH
;
143 kentry
->attributes
= KRB5_KDB_DISALLOW_ALL_TIX
;
146 code
= krb5_parse_name(context
, KRB5_KDB_M_NAME
, &kentry
->princ
);
148 code
= krb5_copy_principal(context
, princ
, &kentry
->princ
);
151 krb5_db_free_principal(context
, kentry
);
157 code
= krb5_dbe_update_mod_princ_data(context
, kentry
, now
, kentry
->princ
);
159 krb5_db_free_principal(context
, kentry
);
163 /* Return a dummy key */
164 kentry
->n_key_data
= 1;
165 kentry
->key_data
= calloc(1, sizeof(krb5_key_data
));
167 krb5_db_free_principal(context
, kentry
);
171 key_data
= &kentry
->key_data
[0];
173 key_data
->key_data_ver
= KRB5_KDB_V1_KEY_DATA_ARRAY
;
174 key_data
->key_data_kvno
= 1;
175 key_data
->key_data_type
[0] = ENCTYPE_UNKNOWN
;
177 krb5_db_free_principal(context
, kentry
);
181 *kentry_ptr
= kentry
;
186 static krb5_error_code
ks_create_principal(krb5_context context
,
187 krb5_const_principal princ
,
190 const char *password
,
191 krb5_db_entry
**kentry_ptr
)
193 krb5_error_code code
;
194 krb5_key_data
*key_data
;
196 krb5_db_entry
*kentry
;
200 int enctype
= ENCTYPE_AES256_CTS_HMAC_SHA1_96
;
201 int sts
= KRB5_KDB_SALTTYPE_SPECIAL
;
204 return KRB5_KDB_NOENTRY
;
209 kentry
= calloc(1, sizeof(krb5_db_entry
));
210 if (kentry
== NULL
) {
214 kentry
->magic
= KRB5_KDB_MAGIC_NUMBER
;
215 kentry
->len
= KRB5_KDB_V1_BASE_LENGTH
;
217 if (attributes
> 0) {
218 kentry
->attributes
= attributes
;
222 kentry
->max_life
= max_life
;
225 code
= krb5_copy_principal(context
, princ
, &kentry
->princ
);
227 krb5_db_free_principal(context
, kentry
);
233 code
= krb5_dbe_update_mod_princ_data(context
, kentry
, now
, kentry
->princ
);
235 krb5_db_free_principal(context
, kentry
);
239 code
= mit_samba_generate_salt(&salt
);
241 krb5_db_free_principal(context
, kentry
);
245 if (password
!= NULL
) {
246 pwd
.data
= strdup(password
);
247 pwd
.length
= strlen(password
);
249 /* create a random password */
250 code
= mit_samba_generate_random_password(&pwd
);
252 krb5_db_free_principal(context
, kentry
);
257 code
= krb5_c_string_to_key(context
, enctype
, &pwd
, &salt
, &key
);
260 krb5_db_free_principal(context
, kentry
);
264 kentry
->n_key_data
= 1;
265 kentry
->key_data
= calloc(1, sizeof(krb5_key_data
));
267 krb5_db_free_principal(context
, kentry
);
271 key_data
= &kentry
->key_data
[0];
273 key_data
->key_data_ver
= KRB5_KDB_V1_KEY_DATA_ARRAY
;
274 key_data
->key_data_kvno
= 1;
275 key_data
->key_data_type
[0] = key
.enctype
;
276 key_data
->key_data_length
[0] = key
.length
;
277 key_data
->key_data_contents
[0] = key
.contents
;
278 key_data
->key_data_type
[1] = sts
;
279 key_data
->key_data_length
[1] = salt
.length
;
280 key_data
->key_data_contents
[1] = (krb5_octet
*)salt
.data
;
282 *kentry_ptr
= kentry
;
287 static krb5_error_code
ks_get_admin_principal(krb5_context context
,
288 krb5_const_principal princ
,
289 krb5_db_entry
**kentry_ptr
)
291 krb5_error_code code
= EINVAL
;
293 code
= ks_create_principal(context
,
295 KRB5_KDB_DISALLOW_TGT_BASED
,
303 krb5_error_code
kdb_samba_db_get_principal(krb5_context context
,
304 krb5_const_principal princ
,
306 krb5_db_entry
**kentry
)
308 struct mit_samba_context
*mit_ctx
;
309 krb5_error_code code
;
311 mit_ctx
= ks_get_context(context
);
312 if (mit_ctx
== NULL
) {
313 return KRB5_KDB_DBNOTINITED
;
316 if (ks_is_master_key_principal(context
, princ
)) {
317 return ks_get_master_key_principal(context
, princ
, kentry
);
321 * Fake a kadmin/admin and kadmin/history principal so that kadmindd can
324 if (ks_is_kadmin_admin(context
, princ
) ||
325 ks_is_kadmin_history(context
, princ
)) {
326 return ks_get_admin_principal(context
, princ
, kentry
);
329 code
= ks_get_principal(context
, princ
, kflags
, kentry
);
332 * This restricts the changepw account so it isn't able to request a
333 * service ticket. It also marks the principal as the changepw service.
335 if (ks_is_kadmin_changepw(context
, princ
)) {
336 /* FIXME: shouldn't we also set KRB5_KDB_DISALLOW_TGT_BASED ?
337 * testing showed that setpw kpasswd command fails then on the
338 * server though... */
339 (*kentry
)->attributes
|= KRB5_KDB_PWCHANGE_SERVICE
;
340 (*kentry
)->max_life
= CHANGEPW_LIFETIME
;
346 krb5_error_code
kdb_samba_db_put_principal(krb5_context context
,
347 krb5_db_entry
*entry
,
351 /* NOTE: deferred, samba does not allow the KDC to store
352 * principals for now. We should not return KRB5_KDB_DB_INUSE as this
353 * would result in confusing error messages after password changes. */
357 krb5_error_code
kdb_samba_db_delete_principal(krb5_context context
,
358 krb5_const_principal princ
)
361 /* NOTE: deferred, samba does not allow the KDC to delete
362 * principals for now */
363 return KRB5_KDB_DB_INUSE
;
366 krb5_error_code
kdb_samba_db_iterate(krb5_context context
,
368 int (*func
)(krb5_pointer
, krb5_db_entry
*),
369 krb5_pointer func_arg
,
370 krb5_flags iterflags
)
372 struct mit_samba_context
*mit_ctx
;
373 krb5_db_entry
*kentry
= NULL
;
374 krb5_error_code code
;
377 mit_ctx
= ks_get_context(context
);
378 if (mit_ctx
== NULL
) {
379 return KRB5_KDB_DBNOTINITED
;
382 code
= mit_samba_get_firstkey(mit_ctx
, &kentry
);
384 code
= (*func
)(func_arg
, kentry
);
389 code
= mit_samba_get_nextkey(mit_ctx
, &kentry
);
392 if (code
== KRB5_KDB_NOENTRY
) {