예제 #1
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;
}
예제 #2
0
파일: ldap_child.c 프로젝트: abbra/sssd
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;
}