| File: | daemons/ipa-kdb/ipa_kdb.c |
| Warning: | line 378, column 26 Array access (from variable 'cvals') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * MIT Kerberos KDC database backend for FreeIPA | |||
| 3 | * | |||
| 4 | * Authors: Simo Sorce <ssorce@redhat.com> | |||
| 5 | * | |||
| 6 | * Copyright (C) 2011 Simo Sorce, Red Hat | |||
| 7 | * see file 'COPYING' for use and warranty information | |||
| 8 | * | |||
| 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. | |||
| 13 | * | |||
| 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. | |||
| 18 | * | |||
| 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/>. | |||
| 21 | */ | |||
| 22 | ||||
| 23 | #include <talloc.h> | |||
| 24 | #include <sys/utsname.h> | |||
| 25 | ||||
| 26 | #include "ipa_kdb.h" | |||
| 27 | #include "ipa_krb5.h" | |||
| 28 | ||||
| 29 | #define IPADB_GLOBAL_CONFIG_CACHE_TIME60 60 | |||
| 30 | ||||
| 31 | struct ipadb_context *ipadb_get_context(krb5_context kcontext) | |||
| 32 | { | |||
| 33 | void *db_ctx; | |||
| 34 | krb5_error_code kerr; | |||
| 35 | ||||
| 36 | kerr = krb5_db_get_context(kcontext, &db_ctx); | |||
| 37 | if (kerr != 0) { | |||
| 38 | return NULL((void*)0); | |||
| 39 | } | |||
| 40 | ||||
| 41 | return (struct ipadb_context *)db_ctx; | |||
| 42 | } | |||
| 43 | ||||
| 44 | static void ipadb_context_free(krb5_context kcontext, | |||
| 45 | struct ipadb_context **ctx) | |||
| 46 | { | |||
| 47 | struct ipadb_global_config *cfg; | |||
| 48 | size_t c; | |||
| 49 | ||||
| 50 | if (*ctx != NULL((void*)0)) { | |||
| 51 | free((*ctx)->uri); | |||
| 52 | free((*ctx)->base); | |||
| 53 | free((*ctx)->realm_base); | |||
| 54 | free((*ctx)->accounts_base); | |||
| 55 | free((*ctx)->kdc_hostname); | |||
| 56 | /* ldap free lcontext */ | |||
| 57 | if ((*ctx)->lcontext) { | |||
| 58 | ldap_unbind_ext_s((*ctx)->lcontext, NULL((void*)0), NULL((void*)0)); | |||
| 59 | } | |||
| 60 | free((*ctx)->supp_encs); | |||
| 61 | free((*ctx)->def_encs); | |||
| 62 | ipadb_mspac_struct_free(&(*ctx)->mspac); | |||
| 63 | krb5_free_principal(kcontext, (*ctx)->local_tgs); | |||
| 64 | krb5_free_default_realm(kcontext, (*ctx)->realm); | |||
| 65 | ||||
| 66 | cfg = &(*ctx)->config; | |||
| 67 | for (c = 0; cfg->authz_data && cfg->authz_data[c]; c++) { | |||
| 68 | free(cfg->authz_data[c]); | |||
| 69 | } | |||
| 70 | free(cfg->authz_data); | |||
| 71 | ||||
| 72 | #ifdef HAVE_KRB5_CERTAUTH_PLUGIN1 | |||
| 73 | ipa_certauth_free_moddata(&((*ctx)->certauth_moddata)); | |||
| 74 | #endif | |||
| 75 | ||||
| 76 | free(*ctx); | |||
| 77 | *ctx = NULL((void*)0); | |||
| 78 | } | |||
| 79 | } | |||
| 80 | ||||
| 81 | #define LDAPI_URI_PREFIX"ldapi://" "ldapi://" | |||
| 82 | #define LDAPI_PATH_PREFIX"%2fslapd-" "%2fslapd-" | |||
| 83 | #define SOCKET_SUFFIX".socket" ".socket" | |||
| 84 | #define APPEND_PATH_PART(pos, part)do { int partlen = strlen(part); strncpy(pos, part, partlen + 1); p += partlen; } while (0) \ | |||
| 85 | do { \ | |||
| 86 | int partlen = strlen(part); \ | |||
| 87 | strncpy(pos, part, partlen + 1); \ | |||
| 88 | p += partlen; \ | |||
| 89 | } while (0) | |||
| 90 | ||||
| 91 | static char *ipadb_realm_to_ldapi_uri(char *realm) | |||
| 92 | { | |||
| 93 | char *uri = NULL((void*)0); | |||
| 94 | char *p; | |||
| 95 | const char *q; | |||
| 96 | int len; | |||
| 97 | ||||
| 98 | /* uri length, assume worst case for LDAPIDIR */ | |||
| 99 | len = strlen(LDAPI_URI_PREFIX"ldapi://") + strlen(LDAPIDIR"/run") * 3 | |||
| 100 | + strlen(LDAPI_PATH_PREFIX"%2fslapd-") + strlen(realm) | |||
| 101 | + strlen(SOCKET_SUFFIX".socket") + 1; | |||
| 102 | ||||
| 103 | /* worst case they are all '/' to escape */ | |||
| 104 | uri = malloc(len); | |||
| 105 | if (!uri) { | |||
| 106 | return NULL((void*)0); | |||
| 107 | } | |||
| 108 | p = uri; | |||
| 109 | ||||
| 110 | APPEND_PATH_PART(p, LDAPI_URI_PREFIX)do { int partlen = strlen("ldapi://"); strncpy(p, "ldapi://", partlen + 1); p += partlen; } while (0); | |||
| 111 | ||||
| 112 | /* copy path and escape '/' to '%2f' */ | |||
| 113 | for (q = LDAPIDIR"/run"; *q; q++) { | |||
| 114 | if (*q == '/') { | |||
| 115 | memcpy(p, "%2f", 3); | |||
| 116 | p += 3; | |||
| 117 | } else { | |||
| 118 | *p = *q; | |||
| 119 | p++; | |||
| 120 | } | |||
| 121 | } | |||
| 122 | ||||
| 123 | APPEND_PATH_PART(p, LDAPI_PATH_PREFIX)do { int partlen = strlen("%2fslapd-"); strncpy(p, "%2fslapd-" , partlen + 1); p += partlen; } while (0); | |||
| 124 | ||||
| 125 | /* copy realm and convert '.' to '-' */ | |||
| 126 | for (q = realm; *q; q++) { | |||
| 127 | if (*q == '.') { | |||
| 128 | *p = '-'; | |||
| 129 | } else { | |||
| 130 | *p = *q; | |||
| 131 | } | |||
| 132 | p++; | |||
| 133 | } | |||
| 134 | ||||
| 135 | /* terminate string */ | |||
| 136 | APPEND_PATH_PART(p, SOCKET_SUFFIX)do { int partlen = strlen(".socket"); strncpy(p, ".socket", partlen + 1); p += partlen; } while (0); | |||
| 137 | ||||
| 138 | return uri; | |||
| 139 | } | |||
| 140 | ||||
| 141 | /* in IPA the base is always derived from the realm name */ | |||
| 142 | static char *ipadb_get_base_from_realm(krb5_context kcontext) | |||
| 143 | { | |||
| 144 | krb5_error_code kerr; | |||
| 145 | char *realm = NULL((void*)0); | |||
| 146 | char *base = NULL((void*)0); | |||
| 147 | char *tmp; | |||
| 148 | size_t bi, ri; | |||
| 149 | size_t len; | |||
| 150 | ||||
| 151 | kerr = krb5_get_default_realm(kcontext, &realm); | |||
| 152 | if (kerr != 0) { | |||
| 153 | return NULL((void*)0); | |||
| 154 | } | |||
| 155 | ||||
| 156 | bi = 3; | |||
| 157 | len = strlen(realm) + 3 + 1; | |||
| 158 | ||||
| 159 | base = malloc(len); | |||
| 160 | if (!base) { | |||
| 161 | goto done; | |||
| 162 | } | |||
| 163 | strcpy(base, "dc="); | |||
| 164 | ||||
| 165 | /* convert EXAMPLE.COM in dc=example,dc=com */ | |||
| 166 | for (ri = 0; realm[ri]; ri++) { | |||
| 167 | if (realm[ri] == '.') { | |||
| 168 | len += 4; | |||
| 169 | tmp = realloc(base, len); | |||
| 170 | if (!tmp) { | |||
| 171 | free(base); | |||
| 172 | base = NULL((void*)0); | |||
| 173 | goto done; | |||
| 174 | } | |||
| 175 | base = tmp; | |||
| 176 | strcpy(&base[bi], ",dc="); | |||
| 177 | bi += 4; | |||
| 178 | } else { | |||
| 179 | base[bi] = tolower(realm[ri]); | |||
| 180 | bi++; | |||
| 181 | } | |||
| 182 | } | |||
| 183 | base[bi] = '\0'; | |||
| 184 | ||||
| 185 | done: | |||
| 186 | krb5_free_default_realm(kcontext, realm); | |||
| 187 | return base; | |||
| 188 | } | |||
| 189 | ||||
| 190 | static const struct { | |||
| 191 | const char *name; | |||
| 192 | enum ipadb_user_auth flag; | |||
| 193 | } userauth_table[] = { | |||
| 194 | { "disabled", IPADB_USER_AUTH_DISABLED }, | |||
| 195 | { "password", IPADB_USER_AUTH_PASSWORD }, | |||
| 196 | { "radius", IPADB_USER_AUTH_RADIUS }, | |||
| 197 | { "otp", IPADB_USER_AUTH_OTP }, | |||
| 198 | { "pkinit", IPADB_USER_AUTH_PKINIT }, | |||
| 199 | { "hardened", IPADB_USER_AUTH_HARDENED }, | |||
| 200 | { } | |||
| 201 | }; | |||
| 202 | ||||
| 203 | void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le, | |||
| 204 | enum ipadb_user_auth *userauth) | |||
| 205 | { | |||
| 206 | struct berval **vals; | |||
| 207 | int i, j; | |||
| 208 | ||||
| 209 | *userauth = IPADB_USER_AUTH_NONE; | |||
| 210 | vals = ldap_get_values_len(lcontext, le, IPA_USER_AUTH_TYPE"ipaUserAuthType"); | |||
| 211 | if (!vals) | |||
| 212 | return; | |||
| 213 | ||||
| 214 | for (i = 0; vals[i]; i++) { | |||
| 215 | for (j = 0; userauth_table[j].name; j++) { | |||
| 216 | if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) { | |||
| 217 | *userauth |= userauth_table[j].flag; | |||
| 218 | break; | |||
| 219 | } | |||
| 220 | } | |||
| 221 | } | |||
| 222 | ||||
| 223 | ldap_value_free_len(vals); | |||
| 224 | } | |||
| 225 | ||||
| 226 | static int ipadb_load_global_config(struct ipadb_context *ipactx) | |||
| 227 | { | |||
| 228 | char *attrs[] = { "ipaConfigString", IPA_KRB_AUTHZ_DATA_ATTR"ipaKrbAuthzData", | |||
| 229 | IPA_USER_AUTH_TYPE"ipaUserAuthType", NULL((void*)0) }; | |||
| 230 | struct berval **vals = NULL((void*)0); | |||
| 231 | LDAPMessage *res = NULL((void*)0); | |||
| 232 | LDAPMessage *first; | |||
| 233 | char *base = NULL((void*)0); | |||
| 234 | int ret; | |||
| 235 | char **authz_data_list; | |||
| 236 | ||||
| 237 | if (!ipactx || !ipactx->lcontext) { | |||
| 238 | return EINVAL22; | |||
| 239 | } | |||
| 240 | ||||
| 241 | ret = asprintf(&base, "cn=ipaConfig,cn=etc,%s", ipactx->base); | |||
| 242 | if (ret == -1) { | |||
| 243 | ret = ENOMEM12; | |||
| 244 | goto done; | |||
| 245 | } | |||
| 246 | ||||
| 247 | ret = ipadb_simple_search(ipactx, base, LDAP_SCOPE_BASE((ber_int_t) 0x0000), | |||
| 248 | "(objectclass=*)", attrs, &res); | |||
| 249 | if (ret) { | |||
| 250 | goto done; | |||
| 251 | } | |||
| 252 | ||||
| 253 | first = ldap_first_entry(ipactx->lcontext, res); | |||
| 254 | if (!first) { | |||
| 255 | /* no results, set nothing */ | |||
| 256 | ret = 0; | |||
| 257 | goto done; | |||
| 258 | } | |||
| 259 | ||||
| 260 | /* Check for permitted authentication types. */ | |||
| 261 | ipadb_parse_user_auth(ipactx->lcontext, res, &ipactx->config.user_auth); | |||
| 262 | ||||
| 263 | /* Load config strings. */ | |||
| 264 | vals = ldap_get_values_len(ipactx->lcontext, first, "ipaConfigString"); | |||
| 265 | if (vals) { | |||
| 266 | ipactx->config.disable_last_success = false0; | |||
| 267 | ipactx->config.disable_lockout = false0; | |||
| 268 | for (int i = 0; vals[i]; i++) { | |||
| 269 | if (strncasecmp("KDC:Disable Last Success", | |||
| 270 | vals[i]->bv_val, vals[i]->bv_len) == 0) { | |||
| 271 | ipactx->config.disable_last_success = true1; | |||
| 272 | continue; | |||
| 273 | } else if (strncasecmp("KDC:Disable Lockout", | |||
| 274 | vals[i]->bv_val, vals[i]->bv_len) == 0) { | |||
| 275 | ipactx->config.disable_lockout = true1; | |||
| 276 | continue; | |||
| 277 | } else if (strncasecmp("KDC:Disable Default Preauth for SPNs", | |||
| 278 | vals[i]->bv_val, vals[i]->bv_len) == 0) { | |||
| 279 | ipactx->config.disable_preauth_for_spns = true1; | |||
| 280 | } | |||
| 281 | } | |||
| 282 | } | |||
| 283 | ||||
| 284 | /* Load authz data. */ | |||
| 285 | ret = ipadb_ldap_attr_to_strlist(ipactx->lcontext, first, | |||
| 286 | IPA_KRB_AUTHZ_DATA_ATTR"ipaKrbAuthzData", &authz_data_list); | |||
| 287 | if (ret == 0) { | |||
| 288 | if (ipactx->config.authz_data != NULL((void*)0)) { | |||
| 289 | for (int i = 0; ipactx->config.authz_data[i]; i++) | |||
| 290 | free(ipactx->config.authz_data[i]); | |||
| 291 | free(ipactx->config.authz_data); | |||
| 292 | } | |||
| 293 | ||||
| 294 | ipactx->config.authz_data = authz_data_list; | |||
| 295 | } else if (ret != ENOENT2) | |||
| 296 | goto done; | |||
| 297 | ||||
| 298 | /* Success! */ | |||
| 299 | ipactx->config.last_update = time(NULL((void*)0)); | |||
| 300 | ret = 0; | |||
| 301 | ||||
| 302 | done: | |||
| 303 | ldap_value_free_len(vals); | |||
| 304 | ldap_msgfree(res); | |||
| 305 | free(base); | |||
| 306 | return ret; | |||
| 307 | } | |||
| 308 | ||||
| 309 | const struct ipadb_global_config * | |||
| 310 | ipadb_get_global_config(struct ipadb_context *ipactx) | |||
| 311 | { | |||
| 312 | time_t now = 0; | |||
| 313 | int ret; | |||
| 314 | ||||
| 315 | if (time(&now) != (time_t)-1 && | |||
| 316 | now - ipactx->config.last_update > IPADB_GLOBAL_CONFIG_CACHE_TIME60) { | |||
| 317 | if (!ipactx->lcontext) { | |||
| 318 | ret = ipadb_get_connection(ipactx); | |||
| 319 | if (ret != 0) | |||
| 320 | return NULL((void*)0); | |||
| 321 | } | |||
| 322 | ret = ipadb_load_global_config(ipactx); | |||
| 323 | if (ret != 0) | |||
| 324 | return NULL((void*)0); | |||
| 325 | } | |||
| 326 | ||||
| 327 | return &ipactx->config; | |||
| 328 | } | |||
| 329 | ||||
| 330 | int ipadb_get_enc_salt_types(struct ipadb_context *ipactx, | |||
| 331 | LDAPMessage *entry, char *attr, | |||
| 332 | krb5_key_salt_tuple **enc_salt_types, | |||
| 333 | int *n_enc_salt_types) | |||
| 334 | { | |||
| 335 | struct berval **vals = NULL((void*)0); | |||
| 336 | char **cvals = NULL((void*)0); | |||
| 337 | int c = 0; | |||
| 338 | int i; | |||
| 339 | int ret = 0; | |||
| 340 | krb5_key_salt_tuple *kst; | |||
| 341 | int n_kst; | |||
| 342 | ||||
| 343 | vals = ldap_get_values_len(ipactx->lcontext, entry, attr); | |||
| 344 | if (!vals || !vals[0]) { | |||
| 345 | goto done; | |||
| 346 | } | |||
| 347 | ||||
| 348 | for (c = 0; vals[c]; c++) /* count */ ; | |||
| 349 | cvals = calloc(c, sizeof(char *)); | |||
| 350 | if (!cvals) { | |||
| 351 | ret = ENOMEM12; | |||
| 352 | goto done; | |||
| 353 | } | |||
| 354 | for (i = 0; i < c; i++) { | |||
| 355 | cvals[i] = strndup(vals[i]->bv_val, vals[i]->bv_len); | |||
| 356 | if (!cvals[i]) { | |||
| 357 | ret = ENOMEM12; | |||
| 358 | goto done; | |||
| 359 | } | |||
| 360 | } | |||
| 361 | ||||
| 362 | ret = parse_bval_key_salt_tuples(ipactx->kcontext, | |||
| 363 | (const char * const *)cvals, c, | |||
| 364 | &kst, &n_kst); | |||
| 365 | if (ret) { | |||
| 366 | goto done; | |||
| 367 | } | |||
| 368 | ||||
| 369 | if (*enc_salt_types) { | |||
| 370 | free(*enc_salt_types); | |||
| 371 | } | |||
| 372 | ||||
| 373 | *enc_salt_types = kst; | |||
| 374 | *n_enc_salt_types = n_kst; | |||
| 375 | ||||
| 376 | done: | |||
| 377 | ldap_value_free_len(vals); | |||
| 378 | for (i = 0; i
| |||
| ||||
| 379 | free(cvals[i]); | |||
| 380 | } | |||
| 381 | free(cvals); | |||
| 382 | return ret; | |||
| 383 | } | |||
| 384 | ||||
| 385 | int ipadb_get_connection(struct ipadb_context *ipactx) | |||
| 386 | { | |||
| 387 | struct timeval tv = { 5, 0 }; | |||
| 388 | LDAPMessage *res = NULL((void*)0); | |||
| 389 | LDAPMessage *first; | |||
| 390 | int ret; | |||
| 391 | int v3; | |||
| 392 | ||||
| 393 | if (!ipactx->uri) { | |||
| 394 | return EINVAL22; | |||
| 395 | } | |||
| 396 | ||||
| 397 | /* free existing conneciton if any */ | |||
| 398 | if (ipactx->lcontext) { | |||
| 399 | ldap_unbind_ext_s(ipactx->lcontext, NULL((void*)0), NULL((void*)0)); | |||
| 400 | ipactx->lcontext = NULL((void*)0); | |||
| 401 | } | |||
| 402 | ||||
| 403 | ret = ldap_initialize(&ipactx->lcontext, ipactx->uri); | |||
| 404 | if (ret != LDAP_SUCCESS0x00) { | |||
| 405 | goto done; | |||
| 406 | } | |||
| 407 | ||||
| 408 | /* make sure we talk LDAPv3 */ | |||
| 409 | v3 = LDAP_VERSION33; | |||
| 410 | ret = ldap_set_option(ipactx->lcontext, LDAP_OPT_PROTOCOL_VERSION0x0011, &v3); | |||
| 411 | if (ret != LDAP_OPT_SUCCESS0) { | |||
| 412 | goto done; | |||
| 413 | } | |||
| 414 | ||||
| 415 | ret = ldap_set_option(ipactx->lcontext, LDAP_OPT_NETWORK_TIMEOUT0x5005, &tv); | |||
| 416 | if (ret != LDAP_OPT_SUCCESS0) { | |||
| 417 | goto done; | |||
| 418 | } | |||
| 419 | ||||
| 420 | ret = ldap_set_option(ipactx->lcontext, LDAP_OPT_TIMEOUT0x5002, &tv); | |||
| 421 | if (ret != LDAP_OPT_SUCCESS0) { | |||
| 422 | goto done; | |||
| 423 | } | |||
| 424 | ||||
| 425 | ret = ldap_sasl_bind_s(ipactx->lcontext, | |||
| 426 | NULL((void*)0), "EXTERNAL", | |||
| 427 | NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)); | |||
| 428 | if (ret != LDAP_SUCCESS0x00) { | |||
| 429 | goto done; | |||
| 430 | } | |||
| 431 | ||||
| 432 | /* TODO: search rootdse */ | |||
| 433 | ||||
| 434 | ret = ipadb_simple_search(ipactx, | |||
| 435 | ipactx->realm_base, LDAP_SCOPE_BASE((ber_int_t) 0x0000), | |||
| 436 | "(objectclass=*)", NULL((void*)0), &res); | |||
| 437 | if (ret) { | |||
| 438 | goto done; | |||
| 439 | } | |||
| 440 | ||||
| 441 | first = ldap_first_entry(ipactx->lcontext, res); | |||
| 442 | if (!first) { | |||
| 443 | goto done; | |||
| 444 | } | |||
| 445 | ||||
| 446 | /* defaults first, this is used to tell what default enc:salts to use | |||
| 447 | * for kadmin password changes */ | |||
| 448 | ret = ipadb_get_enc_salt_types(ipactx, first, "krbDefaultEncSaltTypes", | |||
| 449 | &ipactx->def_encs, &ipactx->n_def_encs); | |||
| 450 | if (ret) { | |||
| 451 | goto done; | |||
| 452 | } | |||
| 453 | ||||
| 454 | /* supported enc salt types, use to tell kadmin what to accept | |||
| 455 | * but also to detect if kadmin is requesting the default set */ | |||
| 456 | ret = ipadb_get_enc_salt_types(ipactx, first, "krbSupportedEncSaltTypes", | |||
| 457 | &ipactx->supp_encs, &ipactx->n_supp_encs); | |||
| 458 | if (ret) { | |||
| 459 | goto done; | |||
| 460 | } | |||
| 461 | ||||
| 462 | /* get additional options */ | |||
| 463 | ret = ipadb_load_global_config(ipactx); | |||
| 464 | if (ret) { | |||
| 465 | goto done; | |||
| 466 | } | |||
| 467 | ||||
| 468 | /* get adtrust options using default refresh interval */ | |||
| 469 | ret = ipadb_reinit_mspac(ipactx, false0); | |||
| 470 | if (ret && ret != ENOENT2) { | |||
| 471 | /* TODO: log that there is an issue with adtrust settings */ | |||
| 472 | if (ipactx->lcontext == NULL((void*)0)) { | |||
| 473 | /* for some reason ldap connection was reset in ipadb_reinit_mspac | |||
| 474 | * and is no longer established => failure of ipadb_get_connection | |||
| 475 | */ | |||
| 476 | goto done; | |||
| 477 | } | |||
| 478 | } | |||
| 479 | ||||
| 480 | ret = 0; | |||
| 481 | ||||
| 482 | done: | |||
| 483 | ldap_msgfree(res); | |||
| 484 | ||||
| 485 | if (ret) { | |||
| 486 | if (ipactx->lcontext) { | |||
| 487 | ldap_unbind_ext_s(ipactx->lcontext, NULL((void*)0), NULL((void*)0)); | |||
| 488 | ipactx->lcontext = NULL((void*)0); | |||
| 489 | } | |||
| 490 | if (ret == LDAP_SERVER_DOWN(-1)) { | |||
| 491 | return ETIMEDOUT110; | |||
| 492 | } | |||
| 493 | return EIO5; | |||
| 494 | } | |||
| 495 | ||||
| 496 | return 0; | |||
| 497 | } | |||
| 498 | ||||
| 499 | static krb5_principal ipadb_create_local_tgs(krb5_context kcontext, | |||
| 500 | struct ipadb_context *ipactx) | |||
| 501 | { | |||
| 502 | krb5_principal tgtp; | |||
| 503 | unsigned int length = strlen(ipactx->realm); | |||
| 504 | krb5_error_code kerr = 0; | |||
| 505 | ||||
| 506 | kerr = krb5_build_principal_ext(kcontext, &tgtp, | |||
| 507 | length, | |||
| 508 | ipactx->realm, | |||
| 509 | KRB5_TGS_NAME_SIZE6, | |||
| 510 | KRB5_TGS_NAME"krbtgt", | |||
| 511 | length, | |||
| 512 | ipactx->realm, 0); | |||
| 513 | if (kerr != 0) { | |||
| 514 | return NULL((void*)0); | |||
| 515 | } | |||
| 516 | ||||
| 517 | return tgtp; | |||
| 518 | } | |||
| 519 | ||||
| 520 | /* INTERFACE */ | |||
| 521 | ||||
| 522 | static krb5_error_code ipadb_init_library(void) | |||
| 523 | { | |||
| 524 | return 0; | |||
| 525 | } | |||
| 526 | ||||
| 527 | static krb5_error_code ipadb_fini_library(void) | |||
| 528 | { | |||
| 529 | return 0; | |||
| 530 | } | |||
| 531 | ||||
| 532 | static krb5_error_code ipadb_init_module(krb5_context kcontext, | |||
| 533 | char *conf_section, | |||
| 534 | char **db_args, int mode) | |||
| 535 | { | |||
| 536 | struct ipadb_context *ipactx; | |||
| 537 | krb5_error_code kerr; | |||
| 538 | int ret; | |||
| 539 | int i; | |||
| 540 | struct utsname uname_data; | |||
| 541 | ||||
| 542 | /* make sure the context is freed to avoid leaking it */ | |||
| 543 | ipactx = ipadb_get_context(kcontext); | |||
| 544 | ipadb_context_free(kcontext, &ipactx); | |||
| 545 | ||||
| 546 | ipactx = calloc(1, sizeof(struct ipadb_context)); | |||
| 547 | if (!ipactx) { | |||
| 548 | return ENOMEM12; | |||
| 549 | } | |||
| 550 | ipactx->magic = IPA_CONTEXT_MAGIC0x0c027ea7; | |||
| 551 | ||||
| 552 | /* only check for unsupported 'temporary' value for now */ | |||
| 553 | for (i = 0; db_args != NULL((void*)0) && db_args[i] != NULL((void*)0); i++) { | |||
| 554 | ||||
| 555 | if (strncmp(db_args[i], IPA_SETUP"ipa-setup-override-restrictions", sizeof(IPA_SETUP"ipa-setup-override-restrictions")) == 0) { | |||
| 556 | ipactx->override_restrictions = true1; | |||
| 557 | } | |||
| 558 | ||||
| 559 | if (strncmp(db_args[i], "temporary", 9) == 0) { | |||
| 560 | krb5_set_error_message(kcontext, EINVAL22, | |||
| 561 | "Plugin requires -update argument!"); | |||
| 562 | ret = EINVAL22; | |||
| 563 | goto fail; | |||
| 564 | } | |||
| 565 | } | |||
| 566 | ||||
| 567 | ipactx->kcontext = kcontext; | |||
| 568 | ||||
| 569 | kerr = krb5_get_default_realm(kcontext, &ipactx->realm); | |||
| 570 | if (kerr != 0) { | |||
| 571 | ret = EINVAL22; | |||
| 572 | goto fail; | |||
| 573 | } | |||
| 574 | ||||
| 575 | ipactx->uri = ipadb_realm_to_ldapi_uri(ipactx->realm); | |||
| 576 | if (!ipactx->uri) { | |||
| 577 | ret = ENOMEM12; | |||
| 578 | goto fail; | |||
| 579 | } | |||
| 580 | ||||
| 581 | ipactx->local_tgs = ipadb_create_local_tgs(kcontext, ipactx); | |||
| 582 | if (!ipactx->local_tgs) { | |||
| 583 | ret = ENOMEM12; | |||
| 584 | goto fail; | |||
| 585 | } | |||
| 586 | ||||
| 587 | ipactx->base = ipadb_get_base_from_realm(kcontext); | |||
| 588 | if (!ipactx->base
| |||
| 589 | ret = ENOMEM12; | |||
| 590 | goto fail; | |||
| 591 | } | |||
| 592 | ||||
| 593 | ret = asprintf(&ipactx->realm_base, "cn=%s,cn=kerberos,%s", | |||
| 594 | ipactx->realm, ipactx->base); | |||
| 595 | if (ret == -1) { | |||
| 596 | ret = ENOMEM12; | |||
| 597 | goto fail; | |||
| 598 | } | |||
| 599 | ||||
| 600 | ret = asprintf(&ipactx->accounts_base, "cn=accounts,%s", ipactx->base); | |||
| 601 | if (ret == -1) { | |||
| 602 | ret = ENOMEM12; | |||
| 603 | goto fail; | |||
| 604 | } | |||
| 605 | ||||
| 606 | ret = uname(&uname_data); | |||
| 607 | if (ret) { | |||
| 608 | ret = EINVAL22; | |||
| 609 | goto fail; | |||
| 610 | } | |||
| 611 | ||||
| 612 | ipactx->kdc_hostname = strdup(uname_data.nodename); | |||
| 613 | if (!ipactx->kdc_hostname) { | |||
| 614 | ret = ENOMEM12; | |||
| 615 | goto fail; | |||
| 616 | } | |||
| 617 | ||||
| 618 | ret = ipadb_get_connection(ipactx); | |||
| 619 | if (ret != 0) { | |||
| 620 | /* Not a fatal failure, as the LDAP server may be temporarily down. */ | |||
| 621 | krb5_klog_syslog(LOG_INFO6, | |||
| 622 | "Didn't connect to LDAP on startup: %d", ret); | |||
| 623 | } | |||
| 624 | ||||
| 625 | kerr = krb5_db_set_context(kcontext, ipactx); | |||
| 626 | if (kerr != 0) { | |||
| 627 | ret = EACCES13; | |||
| 628 | goto fail; | |||
| 629 | } | |||
| 630 | ||||
| 631 | return 0; | |||
| 632 | ||||
| 633 | fail: | |||
| 634 | ipadb_context_free(kcontext, &ipactx); | |||
| 635 | return ret; | |||
| 636 | } | |||
| 637 | ||||
| 638 | static krb5_error_code ipadb_fini_module(krb5_context kcontext) | |||
| 639 | { | |||
| 640 | struct ipadb_context *ipactx; | |||
| 641 | ||||
| 642 | ipactx = ipadb_get_context(kcontext); | |||
| 643 | ipadb_context_free(kcontext, &ipactx); | |||
| 644 | talloc_free(talloc_autofree_context())_talloc_free(talloc_autofree_context(), "ipa_kdb.c" ":" "644" ); | |||
| 645 | ||||
| 646 | return 0; | |||
| 647 | } | |||
| 648 | ||||
| 649 | static krb5_error_code ipadb_create(krb5_context kcontext, | |||
| 650 | char *conf_section, | |||
| 651 | char **db_args) | |||
| 652 | { | |||
| 653 | return ipadb_init_module(kcontext, conf_section, db_args, 0); | |||
| ||||
| 654 | } | |||
| 655 | ||||
| 656 | static krb5_error_code ipadb_get_age(krb5_context kcontext, | |||
| 657 | char *db_name, time_t *age) | |||
| 658 | { | |||
| 659 | /* just return the current time for now, | |||
| 660 | * until we can use persistent searches and have | |||
| 661 | * a better estimate */ | |||
| 662 | *age = time(NULL((void*)0)); | |||
| 663 | return 0; | |||
| 664 | } | |||
| 665 | ||||
| 666 | /* KDB Virtual Table */ | |||
| 667 | ||||
| 668 | /* We explicitly want to keep different ABI tables below separate. */ | |||
| 669 | /* Do not merge them together. Older ABI does not need to be updated */ | |||
| 670 | ||||
| 671 | #if (KRB5_KDB_DAL_MAJOR_VERSION8 == 6) && !defined(HAVE_KDB_FREEPRINCIPAL_EDATA1) | |||
| 672 | kdb_vftabl kdb_function_table = { | |||
| 673 | .maj_ver = KRB5_KDB_DAL_MAJOR_VERSION8, | |||
| 674 | .min_ver = 0, | |||
| 675 | .init_library = ipadb_init_library, | |||
| 676 | .fini_library = ipadb_fini_library, | |||
| 677 | .init_module = ipadb_init_module, | |||
| 678 | .fini_module = ipadb_fini_module, | |||
| 679 | .create = ipadb_create, | |||
| 680 | .get_age = ipadb_get_age, | |||
| 681 | .get_principal = ipadb_get_principal, | |||
| 682 | .put_principal = ipadb_put_principal, | |||
| 683 | .delete_principal = ipadb_delete_principal, | |||
| 684 | .iterate = ipadb_iterate, | |||
| 685 | .create_policy = ipadb_create_pwd_policy, | |||
| 686 | .get_policy = ipadb_get_pwd_policy, | |||
| 687 | .put_policy = ipadb_put_pwd_policy, | |||
| 688 | .iter_policy = ipadb_iterate_pwd_policy, | |||
| 689 | .delete_policy = ipadb_delete_pwd_policy, | |||
| 690 | .fetch_master_key = ipadb_fetch_master_key, | |||
| 691 | .store_master_key_list = ipadb_store_master_key_list, | |||
| 692 | .change_pwd = ipadb_change_pwd, | |||
| 693 | .sign_authdata = ipadb_sign_authdata, | |||
| 694 | .check_transited_realms = ipadb_check_transited_realms, | |||
| 695 | .check_policy_as = ipadb_check_policy_as, | |||
| 696 | .audit_as_req = ipadb_audit_as_req, | |||
| 697 | .check_allowed_to_delegate = ipadb_check_allowed_to_delegate | |||
| 698 | }; | |||
| 699 | #endif | |||
| 700 | ||||
| 701 | #if ((KRB5_KDB_DAL_MAJOR_VERSION8 == 6) || \ | |||
| 702 | (KRB5_KDB_DAL_MAJOR_VERSION8 == 7)) && \ | |||
| 703 | defined(HAVE_KDB_FREEPRINCIPAL_EDATA1) | |||
| 704 | kdb_vftabl kdb_function_table = { | |||
| 705 | .maj_ver = KRB5_KDB_DAL_MAJOR_VERSION8, | |||
| 706 | .min_ver = 1, | |||
| 707 | .init_library = ipadb_init_library, | |||
| 708 | .fini_library = ipadb_fini_library, | |||
| 709 | .init_module = ipadb_init_module, | |||
| 710 | .fini_module = ipadb_fini_module, | |||
| 711 | .create = ipadb_create, | |||
| 712 | .get_age = ipadb_get_age, | |||
| 713 | .get_principal = ipadb_get_principal, | |||
| 714 | .put_principal = ipadb_put_principal, | |||
| 715 | .delete_principal = ipadb_delete_principal, | |||
| 716 | .iterate = ipadb_iterate, | |||
| 717 | .create_policy = ipadb_create_pwd_policy, | |||
| 718 | .get_policy = ipadb_get_pwd_policy, | |||
| 719 | .put_policy = ipadb_put_pwd_policy, | |||
| 720 | .iter_policy = ipadb_iterate_pwd_policy, | |||
| 721 | .delete_policy = ipadb_delete_pwd_policy, | |||
| 722 | .fetch_master_key = ipadb_fetch_master_key, | |||
| 723 | .store_master_key_list = ipadb_store_master_key_list, | |||
| 724 | .change_pwd = ipadb_change_pwd, | |||
| 725 | .sign_authdata = ipadb_sign_authdata, | |||
| 726 | .check_transited_realms = ipadb_check_transited_realms, | |||
| 727 | .check_policy_as = ipadb_check_policy_as, | |||
| 728 | .audit_as_req = ipadb_audit_as_req, | |||
| 729 | .check_allowed_to_delegate = ipadb_check_allowed_to_delegate, | |||
| 730 | /* The order is important, DAL version 6.1 added | |||
| 731 | * the free_principal_e_data callback */ | |||
| 732 | .free_principal_e_data = ipadb_free_principal_e_data, | |||
| 733 | }; | |||
| 734 | #endif | |||
| 735 | ||||
| 736 | #if (KRB5_KDB_DAL_MAJOR_VERSION8 == 8) | |||
| 737 | /* Version 8 adds several arguments here. However, if we want to actually use | |||
| 738 | * them in mspac, we really ought to drop support for older DAL versions. */ | |||
| 739 | static inline krb5_error_code | |||
| 740 | stub_sign_authdata(krb5_context context, unsigned int flags, | |||
| 741 | krb5_const_principal client_princ, | |||
| 742 | krb5_const_principal server_princ, krb5_db_entry *client, | |||
| 743 | krb5_db_entry *server, krb5_db_entry *header_server, | |||
| 744 | krb5_db_entry *local_tgt, krb5_keyblock *client_key, | |||
| 745 | krb5_keyblock *server_key, krb5_keyblock *header_key, | |||
| 746 | krb5_keyblock *local_tgt_key, krb5_keyblock *session_key, | |||
| 747 | krb5_timestamp authtime, krb5_authdata **tgt_auth_data, | |||
| 748 | void *ad_info, krb5_data ***auth_indicators, | |||
| 749 | krb5_authdata ***signed_auth_data) | |||
| 750 | { | |||
| 751 | krb5_db_entry *krbtgt = header_server ? header_server : local_tgt; | |||
| 752 | krb5_keyblock *krbtgt_key = header_key ? header_key : local_tgt_key; | |||
| 753 | ||||
| 754 | if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION0x00000200) { | |||
| 755 | client = header_server; | |||
| 756 | krbtgt = local_tgt; | |||
| 757 | krbtgt_key = local_tgt_key; | |||
| 758 | } | |||
| 759 | ||||
| 760 | return ipadb_sign_authdata(context, flags, client_princ, client, server, | |||
| 761 | krbtgt, client_key, server_key, krbtgt_key, | |||
| 762 | session_key, authtime, tgt_auth_data, | |||
| 763 | signed_auth_data); | |||
| 764 | } | |||
| 765 | ||||
| 766 | kdb_vftabl kdb_function_table = { | |||
| 767 | .maj_ver = KRB5_KDB_DAL_MAJOR_VERSION8, | |||
| 768 | .min_ver = 0, | |||
| 769 | .init_library = ipadb_init_library, | |||
| 770 | .fini_library = ipadb_fini_library, | |||
| 771 | .init_module = ipadb_init_module, | |||
| 772 | .fini_module = ipadb_fini_module, | |||
| 773 | .create = ipadb_create, | |||
| 774 | .get_age = ipadb_get_age, | |||
| 775 | .get_principal = ipadb_get_principal, | |||
| 776 | .put_principal = ipadb_put_principal, | |||
| 777 | .delete_principal = ipadb_delete_principal, | |||
| 778 | .iterate = ipadb_iterate, | |||
| 779 | .create_policy = ipadb_create_pwd_policy, | |||
| 780 | .get_policy = ipadb_get_pwd_policy, | |||
| 781 | .put_policy = ipadb_put_pwd_policy, | |||
| 782 | .iter_policy = ipadb_iterate_pwd_policy, | |||
| 783 | .delete_policy = ipadb_delete_pwd_policy, | |||
| 784 | .fetch_master_key = ipadb_fetch_master_key, | |||
| 785 | .store_master_key_list = ipadb_store_master_key_list, | |||
| 786 | .change_pwd = ipadb_change_pwd, | |||
| 787 | .sign_authdata = stub_sign_authdata, | |||
| 788 | .check_transited_realms = ipadb_check_transited_realms, | |||
| 789 | .check_policy_as = ipadb_check_policy_as, | |||
| 790 | .audit_as_req = ipadb_audit_as_req, | |||
| 791 | .check_allowed_to_delegate = ipadb_check_allowed_to_delegate, | |||
| 792 | .free_principal_e_data = ipadb_free_principal_e_data, | |||
| 793 | .get_s4u_x509_principal = NULL((void*)0), | |||
| 794 | .allowed_to_delegate_from = NULL((void*)0), | |||
| 795 | .get_authdata_info = NULL((void*)0), | |||
| 796 | .free_authdata_info = NULL((void*)0), | |||
| 797 | }; | |||
| 798 | #endif | |||
| 799 | ||||
| 800 | #if (KRB5_KDB_DAL_MAJOR_VERSION8 != 6) && \ | |||
| 801 | (KRB5_KDB_DAL_MAJOR_VERSION8 != 7) && \ | |||
| 802 | (KRB5_KDB_DAL_MAJOR_VERSION8 != 8) | |||
| 803 | #error unsupported DAL major version | |||
| 804 | #endif |