void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest) { krb5_int32 offset_seconds = 0, offset_microseconds = 0; int err; /* * allocate and copy * copy all of those damn fields back */ err = krb5_parse_name(context, src->client, &(dest->client)); err = krb5_parse_name(context, src->server, &(dest->server)); if (err) return; /* parsename fails w/o krb5.ini for example */ /* copy keyblock */ dest->keyblock.enctype = src->keyblock.type; dest->keyblock.length = src->keyblock.length; dest->keyblock.contents = (krb5_octet *)malloc(dest->keyblock.length); memcpy(dest->keyblock.contents, src->keyblock.data, dest->keyblock.length); /* copy times */ #if TARGET_OS_MAC err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); if (err) return; #endif dest->times.authtime = src->authtime + offset_seconds; dest->times.starttime = src->starttime + offset_seconds; dest->times.endtime = src->endtime + offset_seconds; dest->times.renew_till = src->renew_till + offset_seconds; dest->is_skey = src->is_skey; dest->ticket_flags = src->ticket_flags; /* more branching fields */ err = copyCCDataArrayToK5(src, dest, kAddressArray); if (err) return; dest->ticket.length = src->ticket.length; dest->ticket.data = (char *)malloc(src->ticket.length); memcpy(dest->ticket.data, src->ticket.data, src->ticket.length); dest->second_ticket.length = src->second_ticket.length; (dest->second_ticket).data = ( char *)malloc(src->second_ticket.length); memcpy(dest->second_ticket.data, src->second_ticket.data, src->second_ticket.length); /* zero out magic number */ dest->magic = 0; /* authdata */ err = copyCCDataArrayToK5(src, dest, kAuthDataArray); if (err) return; return; }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { char *ccname; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; char *tmp_str = NULL; krb5_context context = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int canonicalize = 0; int kdc_time_offset_usec; int ret; krberr = krb5_init_context(&context); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to init kerberos context\n")); return krberr; } DEBUG(SSSDBG_TRACE_INTERNAL, ("Kerberos context initialized\n")); krberr = set_child_debugging(context); if (krberr != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot set krb5_child debugging\n")); } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } realm_name = talloc_strdup(memctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(memctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } DEBUG(SSSDBG_TRACE_INTERNAL, ("got realm_name: [%s]\n", realm_name)); if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(memctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(memctx, princ_str); } } else { char hostname[512]; ret = gethostname(hostname, 511); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[511] = '\0'; DEBUG(SSSDBG_TRACE_LIBS, ("got hostname: [%s]\n", hostname)); ret = select_principal_from_keytab(memctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) { krberr = KRB5_KT_IOERR; goto done; } } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_CONF_SETTINGS, ("Principal name is: [%s]\n", full_princ)); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(2, ("Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } DEBUG(SSSDBG_CONF_SETTINGS, ("Using keytab [%s]\n", KEYTAB_CLEAN_NAME)); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to read keytab file [%s]: %s\n", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr))); goto done; } /* Verify the keytab */ ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to verify principal is present in the keytab\n")); krberr = KRB5_KT_IOERR; goto done; } ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); if (!ccname) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("keytab ccname: [%s]\n", ccname)); krberr = krb5_cc_resolve(context, ccname, &ccache); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); tmp_str = getenv("KRB5_CANONICALIZE"); if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) { DEBUG(SSSDBG_CONF_SETTINGS, ("Will canonicalize principals\n")); canonicalize = 1; } sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr))); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("credentials initialized\n")); /* Use updated principal if changed due to canonicalization. */ krberr = krb5_cc_initialize(context, ccache, my_creds.client); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, ("credentials stored\n")); #ifdef HAVE_KRB5_GET_TIME_OFFSETS krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr))); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } DEBUG(SSSDBG_TRACE_INTERNAL, ("Got KDC time offset\n")); #else /* If we don't have this function, just assume no offset */ kdc_time_offset = 0; #endif krberr = 0; *ccname_out = ccname; *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (krberr != 0) KRB5_SYSLOG(krberr); if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); return krberr; }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, krb5_context context, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { int fd; char *ccname; char *ccname_dummy; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; char *tmp_str = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int canonicalize = 0; int kdc_time_offset_usec; int ret; TALLOC_CTX *tmp_ctx; char *ccname_file_dummy = NULL; char *ccname_file; mode_t old_umask; tmp_ctx = talloc_new(memctx); if (tmp_ctx == NULL) { krberr = KRB5KRB_ERR_GENERIC; goto done; } krberr = set_child_debugging(context); if (krberr != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set krb5_child debugging\n"); } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } realm_name = talloc_strdup(tmp_ctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(tmp_ctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } DEBUG(SSSDBG_TRACE_INTERNAL, "got realm_name: [%s]\n", realm_name); if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(tmp_ctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(tmp_ctx, princ_str); } } else { char hostname[HOST_NAME_MAX + 1]; ret = gethostname(hostname, HOST_NAME_MAX); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[HOST_NAME_MAX] = '\0'; DEBUG(SSSDBG_TRACE_LIBS, "got hostname: [%s]\n", hostname); ret = select_principal_from_keytab(tmp_ctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) { krberr = KRB5_KT_IOERR; goto done; } } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(SSSDBG_CONF_SETTINGS, "Principal name is: [%s]\n", full_princ); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } DEBUG(SSSDBG_CONF_SETTINGS, "Using keytab [%s]\n", KEYTAB_CLEAN_NAME); if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to read keytab file [%s]: %s\n", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } /* Verify the keytab */ ret = lc_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Unable to verify principal is present in the keytab\n"); krberr = KRB5_KT_IOERR; goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); tmp_str = getenv("KRB5_CANONICALIZE"); if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) { DEBUG(SSSDBG_CONF_SETTINGS, "Will canonicalize principals\n"); canonicalize = 1; } sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize); ccname_file = talloc_asprintf(tmp_ctx, "%s/ccache_%s", DB_PATH, realm_name); if (ccname_file == NULL) { krberr = ENOMEM; DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed: %s:[%d].\n", strerror(krberr), krberr); goto done; } ccname_file_dummy = talloc_asprintf(tmp_ctx, "%s/ccache_%s_XXXXXX", DB_PATH, realm_name); if (ccname_file_dummy == NULL) { krberr = ENOMEM; DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed: %s:[%d].\n", strerror(krberr), krberr); goto done; } old_umask = umask(077); fd = mkstemp(ccname_file_dummy); umask(old_umask); if (fd == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "mkstemp failed: %s:[%d].\n", strerror(ret), ret); krberr = KRB5KRB_ERR_GENERIC; goto done; } /* We only care about creating a unique file name here, we don't * need the fd */ close(fd); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); krb5_kt_close(context, keytab); keytab = NULL; if (krberr) { DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr)); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", KEYTAB_CLEAN_NAME, sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "credentials initialized\n"); ccname_dummy = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file_dummy); ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file); if (ccname_dummy == NULL || ccname == NULL) { krberr = ENOMEM; goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname_dummy); krberr = krb5_cc_resolve(context, ccname_dummy, &ccache); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } /* Use updated principal if changed due to canonicalization. */ krberr = krb5_cc_initialize(context, ccache, my_creds.client); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr)); goto done; } DEBUG(SSSDBG_TRACE_INTERNAL, "credentials stored\n"); #ifdef HAVE_KRB5_GET_TIME_OFFSETS krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(SSSDBG_OP_FAILURE, "Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr)); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } DEBUG(SSSDBG_TRACE_INTERNAL, "Got KDC time offset\n"); #else /* If we don't have this function, just assume no offset */ kdc_time_offset = 0; #endif DEBUG(SSSDBG_TRACE_INTERNAL, "Renaming [%s] to [%s]\n", ccname_file_dummy, ccname_file); ret = rename(ccname_file_dummy, ccname_file); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "rename failed [%d][%s].\n", ret, strerror(ret)); goto done; } ccname_file_dummy = NULL; krberr = 0; *ccname_out = talloc_steal(memctx, ccname); *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (krberr != 0) KRB5_SYSLOG(krberr); if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); if (ccname_file_dummy) { DEBUG(SSSDBG_TRACE_INTERNAL, "Unlinking [%s]\n", ccname_file_dummy); ret = unlink(ccname_file_dummy); if (ret == -1) { ret = errno; DEBUG(SSSDBG_MINOR_FAILURE, "Unlink failed [%d][%s].\n", ret, strerror(ret)); } } talloc_free(tmp_ctx); return krberr; }
/* * dupK5toCC * - analagous to above but in the reverse direction */ void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu) { cc_creds *c; int err; krb5_int32 offset_seconds = 0, offset_microseconds = 0; if (cu == NULL) return; /* allocate the cred_union */ *cu = (cred_union *)malloc(sizeof(cred_union)); if ((*cu) == NULL) return; (*cu)->cred_type = CC_CRED_V5; /* allocate creds structure (and install) */ c = (cc_creds *)malloc(sizeof(cc_creds)); if (c == NULL) return; (*cu)->cred.pV5Cred = c; /* convert krb5 principals to flat principals */ err = krb5_unparse_name(context, creds->client, &(c->client)); err = krb5_unparse_name(context, creds->server, &(c->server)); if (err) return; /* copy more fields */ c->keyblock.type = creds->keyblock.enctype; c->keyblock.length = creds->keyblock.length; if (creds->keyblock.contents != NULL) { c->keyblock.data = (unsigned char *)malloc(creds->keyblock.length); memcpy(c->keyblock.data, creds->keyblock.contents, creds->keyblock.length); } else { c->keyblock.data = NULL; } #if TARGET_OS_MAC err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); if (err) return; #endif c->authtime = creds->times.authtime - offset_seconds; c->starttime = creds->times.starttime - offset_seconds; c->endtime = creds->times.endtime - offset_seconds; c->renew_till = creds->times.renew_till - offset_seconds; c->is_skey = creds->is_skey; c->ticket_flags = creds->ticket_flags; err = copyK5DataArrayToCC(creds, c, kAddressArray); if (err) return; c->ticket.length = creds->ticket.length; if (creds->ticket.data != NULL) { c->ticket.data = (unsigned char *)malloc(creds->ticket.length); memcpy(c->ticket.data, creds->ticket.data, creds->ticket.length); } else { c->ticket.data = NULL; } c->second_ticket.length = creds->second_ticket.length; if (creds->second_ticket.data != NULL) { c->second_ticket.data = (unsigned char *)malloc(creds->second_ticket.length); memcpy(c->second_ticket.data, creds->second_ticket.data, creds->second_ticket.length); } else { c->second_ticket.data = NULL; } err = copyK5DataArrayToCC(creds, c, kAuthDataArray); if (err) return; return; }
/* * copy_krb5_creds_to_cc_credentials * - analagous to above but in the reverse direction */ krb5_error_code copy_krb5_creds_to_cc_cred_union (krb5_context in_context, krb5_creds *in_creds, cc_credentials_union **out_cred_union) { krb5_error_code err = 0; cc_credentials_union *cred_union = NULL; cc_credentials_v5_t *cv5 = NULL; char *client = NULL; char *server = NULL; unsigned char *ticket_data = NULL; unsigned char *second_ticket_data = NULL; unsigned char *keyblock_data = NULL; krb5_int32 offset_seconds = 0, offset_microseconds = 0; cc_data **cc_address_array = NULL; cc_data **cc_authdata_array = NULL; if (out_cred_union == NULL) { err = KRB5_CC_NOMEM; } #if TARGET_OS_MAC if (!err) { err = krb5_get_time_offsets (in_context, &offset_seconds, &offset_microseconds); } #endif if (!err) { cred_union = (cc_credentials_union *) malloc (sizeof (*cred_union)); if (!cred_union) { err = KRB5_CC_NOMEM; } } if (!err) { cv5 = (cc_credentials_v5_t *) malloc (sizeof (*cv5)); if (!cv5) { err = KRB5_CC_NOMEM; } } if (!err) { err = krb5_unparse_name (in_context, in_creds->client, &client); } if (!err) { err = krb5_unparse_name (in_context, in_creds->server, &server); } if (!err && in_creds->keyblock.contents) { keyblock_data = (unsigned char *) malloc (in_creds->keyblock.length); if (!keyblock_data) { err = KRB5_CC_NOMEM; } } if (!err && in_creds->ticket.data) { ticket_data = (unsigned char *) malloc (in_creds->ticket.length); if (!ticket_data) { err = KRB5_CC_NOMEM; } } if (!err && in_creds->second_ticket.data) { second_ticket_data = (unsigned char *) malloc (in_creds->second_ticket.length); if (!second_ticket_data) { err = KRB5_CC_NOMEM; } } if (!err) { err = copy_addresses_to_cc_array (in_context, in_creds->addresses, &cc_address_array); } if (!err) { err = copy_authdata_to_cc_array (in_context, in_creds->authdata, &cc_authdata_array); } if (!err) { /* principals */ cv5->client = client; client = NULL; cv5->server = server; server = NULL; /* copy more fields */ if (in_creds->keyblock.contents) { memcpy(keyblock_data, in_creds->keyblock.contents, in_creds->keyblock.length); } cv5->keyblock.type = in_creds->keyblock.enctype; cv5->keyblock.length = in_creds->keyblock.length; cv5->keyblock.data = keyblock_data; keyblock_data = NULL; cv5->authtime = in_creds->times.authtime - offset_seconds; cv5->starttime = in_creds->times.starttime - offset_seconds; cv5->endtime = in_creds->times.endtime - offset_seconds; cv5->renew_till = in_creds->times.renew_till - offset_seconds; cv5->is_skey = in_creds->is_skey; cv5->ticket_flags = in_creds->ticket_flags; if (in_creds->ticket.data) { memcpy (ticket_data, in_creds->ticket.data, in_creds->ticket.length); } cv5->ticket.length = in_creds->ticket.length; cv5->ticket.data = ticket_data; ticket_data = NULL; if (in_creds->second_ticket.data) { memcpy (second_ticket_data, in_creds->second_ticket.data, in_creds->second_ticket.length); } cv5->second_ticket.length = in_creds->second_ticket.length; cv5->second_ticket.data = second_ticket_data; second_ticket_data = NULL; cv5->addresses = cc_address_array; cc_address_array = NULL; cv5->authdata = cc_authdata_array; cc_authdata_array = NULL; /* Set up the structures to return to the caller */ cred_union->version = cc_credentials_v5; cred_union->credentials.credentials_v5 = cv5; cv5 = NULL; *out_cred_union = cred_union; cred_union = NULL; } if (cc_address_array) { free_cc_array (cc_address_array); } if (cc_authdata_array) { free_cc_array (cc_authdata_array); } if (keyblock_data) { free (keyblock_data); } if (ticket_data) { free (ticket_data); } if (second_ticket_data) { free (second_ticket_data); } if (client) { krb5_free_unparsed_name (in_context, client); } if (server) { krb5_free_unparsed_name (in_context, server); } if (cv5) { free (cv5); } if (cred_union) { free (cred_union); } return err; }
krb5_error_code copy_cc_cred_union_to_krb5_creds (krb5_context in_context, const cc_credentials_union *in_cred_union, krb5_creds *out_creds) { krb5_error_code err = 0; cc_credentials_v5_t *cv5 = NULL; krb5_int32 offset_seconds = 0, offset_microseconds = 0; krb5_principal client = NULL; krb5_principal server = NULL; char *ticket_data = NULL; char *second_ticket_data = NULL; unsigned char *keyblock_contents = NULL; krb5_address **addresses = NULL; krb5_authdata **authdata = NULL; if (in_cred_union->version != cc_credentials_v5) { err = KRB5_CC_NOT_KTYPE; } else { cv5 = in_cred_union->credentials.credentials_v5; } #if TARGET_OS_MAC if (!err) { err = krb5_get_time_offsets (in_context, &offset_seconds, &offset_microseconds); } #endif if (!err) { err = krb5_parse_name (in_context, cv5->client, &client); } if (!err) { err = krb5_parse_name (in_context, cv5->server, &server); } if (!err && cv5->keyblock.data) { keyblock_contents = (unsigned char *) malloc (cv5->keyblock.length); if (!keyblock_contents) { err = KRB5_CC_NOMEM; } } if (!err && cv5->ticket.data) { ticket_data = (char *) malloc (cv5->ticket.length); if (!ticket_data) { err = KRB5_CC_NOMEM; } } if (!err && cv5->second_ticket.data) { second_ticket_data = (char *) malloc (cv5->second_ticket.length); if (!second_ticket_data) { err = KRB5_CC_NOMEM; } } if (!err) { /* addresses */ err = copy_cc_array_to_addresses (in_context, cv5->addresses, &addresses); } if (!err) { /* authdata */ err = copy_cc_array_to_authdata (in_context, cv5->authdata, &authdata); } if (!err) { /* principals */ out_creds->client = client; client = NULL; out_creds->server = server; server = NULL; /* copy keyblock */ if (cv5->keyblock.data) { memcpy (keyblock_contents, cv5->keyblock.data, cv5->keyblock.length); } out_creds->keyblock.enctype = cv5->keyblock.type; out_creds->keyblock.length = cv5->keyblock.length; out_creds->keyblock.contents = keyblock_contents; keyblock_contents = NULL; /* copy times */ out_creds->times.authtime = cv5->authtime + offset_seconds; out_creds->times.starttime = cv5->starttime + offset_seconds; out_creds->times.endtime = cv5->endtime + offset_seconds; out_creds->times.renew_till = cv5->renew_till + offset_seconds; out_creds->is_skey = cv5->is_skey; out_creds->ticket_flags = cv5->ticket_flags; /* first ticket */ if (cv5->ticket.data) { memcpy(ticket_data, cv5->ticket.data, cv5->ticket.length); } out_creds->ticket.length = cv5->ticket.length; out_creds->ticket.data = ticket_data; ticket_data = NULL; /* second ticket */ if (cv5->second_ticket.data) { memcpy(second_ticket_data, cv5->second_ticket.data, cv5->second_ticket.length); } out_creds->second_ticket.length = cv5->second_ticket.length; out_creds->second_ticket.data = second_ticket_data; second_ticket_data = NULL; out_creds->addresses = addresses; addresses = NULL; out_creds->authdata = authdata; authdata = NULL; /* zero out magic number */ out_creds->magic = 0; } if (addresses) { krb5_free_addresses (in_context, addresses); } if (authdata) { krb5_free_authdata (in_context, authdata); } if (keyblock_contents) { free (keyblock_contents); } if (ticket_data) { free (ticket_data); } if (second_ticket_data) { free (second_ticket_data); } if (client) { krb5_free_principal (in_context, client); } if (server) { krb5_free_principal (in_context, server); } return err; }
static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, const char *realm_str, const char *princ_str, const char *keytab_name, const krb5_deltat lifetime, const char **ccname_out, time_t *expire_time_out) { char *ccname; char *realm_name = NULL; char *full_princ = NULL; char *default_realm = NULL; krb5_context context = NULL; krb5_keytab keytab = NULL; krb5_ccache ccache = NULL; krb5_principal kprinc; krb5_creds my_creds; krb5_get_init_creds_opt options; krb5_error_code krberr; krb5_timestamp kdc_time_offset; int kdc_time_offset_usec; int ret; krberr = krb5_init_context(&context); if (krberr) { DEBUG(2, ("Failed to init kerberos context\n")); return krberr; } if (!realm_str) { krberr = krb5_get_default_realm(context, &default_realm); if (krberr) { DEBUG(2, ("Failed to get default realm name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } realm_name = talloc_strdup(memctx, default_realm); krb5_free_default_realm(context, default_realm); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } else { realm_name = talloc_strdup(memctx, realm_str); if (!realm_name) { krberr = KRB5KRB_ERR_GENERIC; goto done; } } if (princ_str) { if (!strchr(princ_str, '@')) { full_princ = talloc_asprintf(memctx, "%s@%s", princ_str, realm_name); } else { full_princ = talloc_strdup(memctx, princ_str); } } else { char hostname[512]; ret = gethostname(hostname, 511); if (ret == -1) { krberr = KRB5KRB_ERR_GENERIC; goto done; } hostname[511] = '\0'; ret = select_principal_from_keytab(memctx, hostname, realm_name, keytab_name, &full_princ, NULL, NULL); if (ret) goto done; } if (!full_princ) { krberr = KRB5KRB_ERR_GENERIC; goto done; } DEBUG(4, ("Principal name is: [%s]\n", full_princ)); krberr = krb5_parse_name(context, full_princ, &kprinc); if (krberr) { DEBUG(2, ("Unable to build principal: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } if (keytab_name) { krberr = krb5_kt_resolve(context, keytab_name, &keytab); } else { krberr = krb5_kt_default(context, &keytab); } if (krberr) { DEBUG(0, ("Failed to read keytab file: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } /* Verify the keytab */ ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab); if (ret) { DEBUG(2, ("Unable to verify principal is present in the keytab\n")); krberr = KRB5_KT_IOERR; goto done; } ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); if (!ccname) { krberr = KRB5KRB_ERR_GENERIC; goto done; } krberr = krb5_cc_resolve(context, ccname, &ccache); if (krberr) { DEBUG(2, ("Failed to set cache name: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, lifetime); krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, keytab, 0, NULL, &options); if (krberr) { DEBUG(0, ("Failed to init credentials: %s\n", sss_krb5_get_error_message(context, krberr))); sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. " "Unable to create GSSAPI-encrypted LDAP connection.", keytab_name, sss_krb5_get_error_message(context, krberr)); goto done; } krberr = krb5_cc_initialize(context, ccache, kprinc); if (krberr) { DEBUG(2, ("Failed to init ccache: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_cc_store_cred(context, ccache, &my_creds); if (krberr) { DEBUG(2, ("Failed to store creds: %s\n", sss_krb5_get_error_message(context, krberr))); goto done; } krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(2, ("Failed to get KDC time offset: %s\n", sss_krb5_get_error_message(context, krberr))); kdc_time_offset = 0; } else { if (kdc_time_offset_usec > 0) { kdc_time_offset++; } } krberr = 0; *ccname_out = ccname; *expire_time_out = my_creds.times.endtime - kdc_time_offset; done: if (keytab) krb5_kt_close(context, keytab); if (context) krb5_free_context(context); return krberr; }