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;
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}
Exemple #7
0
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;
}