static krb5_error_code k5_insert_client_info(krb5_context context, krb5_pac pac, krb5_timestamp authtime, krb5_const_principal principal) { krb5_error_code ret; krb5_data client_info; char *princ_name_utf8 = NULL; unsigned char *princ_name_ucs2 = NULL, *p; size_t princ_name_ucs2_len = 0; krb5_ui_8 nt_authtime; /* If we already have a CLIENT_INFO buffer, then just validate it */ if (k5_pac_locate_buffer(context, pac, KRB5_PAC_CLIENT_INFO, &client_info) == 0) { return k5_pac_validate_client(context, pac, authtime, principal); } ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &princ_name_utf8); if (ret != 0) goto cleanup; ret = krb5int_utf8s_to_ucs2les(princ_name_utf8, &princ_name_ucs2, &princ_name_ucs2_len); if (ret != 0) goto cleanup; client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_ucs2_len; client_info.data = NULL; ret = k5_pac_add_buffer(context, pac, KRB5_PAC_CLIENT_INFO, &client_info, TRUE, &client_info); if (ret != 0) goto cleanup; p = (unsigned char *)client_info.data; /* copy in authtime converted to a 64-bit NT time */ k5_seconds_since_1970_to_time(authtime, &nt_authtime); store_64_le(nt_authtime, p); p += 8; /* copy in number of UCS-2 characters in principal name */ store_16_le(princ_name_ucs2_len, p); p += 2; /* copy in principal name */ memcpy(p, princ_name_ucs2, princ_name_ucs2_len); cleanup: if (princ_name_ucs2 != NULL) free(princ_name_ucs2); krb5_free_unparsed_name(context, princ_name_utf8); return ret; }
static void get_tickets(krb5_context context) { char *server; krb5_error_code retval; krb5_keytab keytab = NULL; krb5_principal server_princ = NULL; /* Figure out what tickets we'll be using to send. */ retval = sn2princ_realm(context, NULL, KPROP_SERVICE_NAME, realm, &my_principal); if (retval) { com_err(progname, errno, _("while setting client principal name")); exit(1); } /* Construct the principal name for the slave host. */ memset(&creds, 0, sizeof(creds)); retval = sn2princ_realm(context, slave_host, KPROP_SERVICE_NAME, realm, &server_princ); if (retval) { com_err(progname, errno, _("while setting server principal name")); exit(1); } retval = krb5_unparse_name_flags(context, server_princ, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server); if (retval) { com_err(progname, retval, _("while unparsing server name")); exit(1); } if (srvtab != NULL) { retval = krb5_kt_resolve(context, srvtab, &keytab); if (retval) { com_err(progname, retval, _("while resolving keytab")); exit(1); } } retval = krb5_get_init_creds_keytab(context, &creds, my_principal, keytab, 0, server, NULL); if (retval) { com_err(progname, retval, _("while getting initial credentials\n")); exit(1); } if (keytab != NULL) krb5_kt_close(context, keytab); krb5_free_unparsed_name(context, server); krb5_free_principal(context, server_princ); }
/* * This function implements MIT's auth_to_local_names configuration for * configuration compatibility. Specifically: * * [realms] * <realm-name> = { * auth_to_local_names = { * <unparsed-principal-name> = <username> * } * } * * If multiple usernames are configured then the last one is taken. * * The configuration can only be expected to hold a relatively small * number of mappings. For lots of mappings use a DB. */ static krb5_error_code an2ln_local_names(krb5_context context, krb5_const_principal aname, size_t lnsize, char *lname) { krb5_error_code ret; char *unparsed; char **values; char *res; size_t i; if (!princ_realm_is_default(context, aname)) return KRB5_PLUGIN_NO_HANDLE; ret = krb5_unparse_name_flags(context, aname, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed); if (ret) return ret; ret = KRB5_PLUGIN_NO_HANDLE; values = krb5_config_get_strings(context, NULL, "realms", aname->realm, "auth_to_local_names", unparsed, NULL); free(unparsed); if (!values) return ret; /* Take the last value, just like MIT */ for (res = NULL, i = 0; values[i]; i++) res = values[i]; if (res) { ret = 0; if (strlcpy(lname, res, lnsize) >= lnsize) ret = KRB5_CONFIG_NOTENUFSPACE; if (!*res || strcmp(res, ":") == 0) ret = KRB5_NO_LOCALNAME; } krb5_config_free_strings(values); return ret; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_display_name (OM_uint32 * minor_status, const gss_name_t input_name, gss_buffer_t output_name_buffer, gss_OID * output_name_type ) { krb5_context context; krb5_const_principal name = (krb5_const_principal)input_name; krb5_error_code kret; char *buf; size_t len; GSSAPI_KRB5_INIT (&context); kret = krb5_unparse_name_flags (context, name, KRB5_PRINCIPAL_UNPARSE_DISPLAY, &buf); if (kret) { *minor_status = kret; return GSS_S_FAILURE; } len = strlen (buf); output_name_buffer->length = len; output_name_buffer->value = malloc(len + 1); if (output_name_buffer->value == NULL) { free (buf); *minor_status = ENOMEM; return GSS_S_FAILURE; } memcpy (output_name_buffer->value, buf, len); ((char *)output_name_buffer->value)[len] = '\0'; free (buf); if (output_name_type) *output_name_type = GSS_KRB5_NT_PRINCIPAL_NAME; *minor_status = 0; return GSS_S_COMPLETE; }
static void test_princ(krb5_context context) { const char *princ = "*****@*****.**"; const char *princ_short = "lha"; const char *noquote; krb5_error_code ret; char *princ_unparsed; char *princ_reformed = NULL; const char *realm; krb5_principal p, p2; ret = krb5_parse_name(context, princ, &p); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_unparse_name(context, p, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (strcmp(princ, princ_unparsed)) { krb5_errx(context, 1, "%s != %s", princ, princ_unparsed); } free(princ_unparsed); ret = krb5_unparse_name_flags(context, p, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (strcmp(princ_short, princ_unparsed)) krb5_errx(context, 1, "%s != %s", princ_short, princ_unparsed); free(princ_unparsed); realm = krb5_principal_get_realm(context, p); if (asprintf(&princ_reformed, "%s@%s", princ_short, realm) < 0 || princ_reformed == NULL) errx(1, "malloc"); ret = krb5_parse_name(context, princ_reformed, &p2); free(princ_reformed); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (!krb5_principal_compare(context, p, p2)) { krb5_errx(context, 1, "p != p2"); } krb5_free_principal(context, p2); ret = krb5_set_default_realm(context, "SU.SE"); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_unparse_name_flags(context, p, KRB5_PRINCIPAL_UNPARSE_SHORT, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (strcmp(princ_short, princ_unparsed)) krb5_errx(context, 1, "'%s' != '%s'", princ_short, princ_unparsed); free(princ_unparsed); ret = krb5_parse_name(context, princ_short, &p2); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (!krb5_principal_compare(context, p, p2)) krb5_errx(context, 1, "p != p2"); krb5_free_principal(context, p2); ret = krb5_unparse_name(context, p, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (strcmp(princ, princ_unparsed)) krb5_errx(context, 1, "'%s' != '%s'", princ, princ_unparsed); free(princ_unparsed); ret = krb5_set_default_realm(context, "SAMBA.ORG"); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_parse_name(context, princ_short, &p2); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (krb5_principal_compare(context, p, p2)) krb5_errx(context, 1, "p == p2"); if (!krb5_principal_compare_any_realm(context, p, p2)) krb5_errx(context, 1, "(ignoring realms) p != p2"); ret = krb5_unparse_name(context, p2, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (strcmp(princ, princ_unparsed) == 0) krb5_errx(context, 1, "%s == %s", princ, princ_unparsed); free(princ_unparsed); krb5_free_principal(context, p2); ret = krb5_parse_name(context, princ, &p2); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (!krb5_principal_compare(context, p, p2)) krb5_errx(context, 1, "p != p2"); ret = krb5_unparse_name(context, p2, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (strcmp(princ, princ_unparsed)) krb5_errx(context, 1, "'%s' != '%s'", princ, princ_unparsed); free(princ_unparsed); krb5_free_principal(context, p2); ret = krb5_unparse_name_flags(context, p, KRB5_PRINCIPAL_UNPARSE_SHORT, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name_short"); if (strcmp(princ, princ_unparsed) != 0) krb5_errx(context, 1, "'%s' != '%s'", princ, princ_unparsed); free(princ_unparsed); ret = krb5_unparse_name(context, p, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name_short"); if (strcmp(princ, princ_unparsed)) krb5_errx(context, 1, "'%s' != '%s'", princ, princ_unparsed); free(princ_unparsed); ret = krb5_parse_name_flags(context, princ, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); if (!ret) krb5_err(context, 1, ret, "Should have failed to parse %s a " "short name", princ); ret = krb5_parse_name_flags(context, princ_short, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_unparse_name_flags(context, p2, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &princ_unparsed); krb5_free_principal(context, p2); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name_norealm"); if (strcmp(princ_short, princ_unparsed)) krb5_errx(context, 1, "'%s' != '%s'", princ_short, princ_unparsed); free(princ_unparsed); ret = krb5_parse_name_flags(context, princ_short, KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &p2); if (!ret) krb5_err(context, 1, ret, "Should have failed to parse %s " "because it lacked a realm", princ_short); ret = krb5_parse_name_flags(context, princ, KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &p2); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); if (!krb5_principal_compare(context, p, p2)) krb5_errx(context, 1, "p != p2"); ret = krb5_unparse_name_flags(context, p2, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &princ_unparsed); krb5_free_principal(context, p2); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name_norealm"); if (strcmp(princ_short, princ_unparsed)) krb5_errx(context, 1, "'%s' != '%s'", princ_short, princ_unparsed); free(princ_unparsed); krb5_free_principal(context, p); /* test quoting */ princ = "test\\ [email protected]"; noquote = "test [email protected]"; ret = krb5_parse_name_flags(context, princ, 0, &p); if (ret) krb5_err(context, 1, ret, "krb5_parse_name"); ret = krb5_unparse_name_flags(context, p, 0, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name_flags"); if (strcmp(princ, princ_unparsed)) krb5_errx(context, 1, "q '%s' != '%s'", princ, princ_unparsed); free(princ_unparsed); ret = krb5_unparse_name_flags(context, p, KRB5_PRINCIPAL_UNPARSE_DISPLAY, &princ_unparsed); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name_flags"); if (strcmp(noquote, princ_unparsed)) krb5_errx(context, 1, "nq '%s' != '%s'", noquote, princ_unparsed); free(princ_unparsed); krb5_free_principal(context, p); }
static void test_enterprise(krb5_context context) { krb5_error_code ret; char *unparsed; krb5_principal p; ret = krb5_set_default_realm(context, "SAMBA.ORG"); if (ret) err(context, ret, "krb5_parse_name"); ret = krb5_parse_name_flags(context, "[email protected]@WIN.SU.SE", KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p); if (ret) err(context, ret, "krb5_parse_name_flags"); ret = krb5_unparse_name(context, p, &unparsed); if (ret) err(context, ret, "krb5_unparse_name"); krb5_free_principal(context, p); if (strcmp(unparsed, "lha\\@[email protected]") != 0) err(context, 0, "enterprise name failed 1"); free(unparsed); /* * */ ret = krb5_parse_name_flags(context, "lha\\@[email protected]", KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p); if (ret) err(context, ret, "krb5_parse_name_flags"); ret = krb5_unparse_name(context, p, &unparsed); if (ret) err(context, ret, "krb5_unparse_name"); krb5_free_principal(context, p); if (strcmp(unparsed, "lha\\@su.se\\@[email protected]") != 0) err(context, 0, "enterprise name failed 2: %s", unparsed); free(unparsed); /* * */ ret = krb5_parse_name_flags(context, "lha\\@[email protected]", 0, &p); if (ret) err(context, ret, "krb5_parse_name_flags"); ret = krb5_unparse_name(context, p, &unparsed); if (ret) err(context, ret, "krb5_unparse_name"); krb5_free_principal(context, p); if (strcmp(unparsed, "lha\\@[email protected]") != 0) err(context, 0, "enterprise name failed 3"); free(unparsed); /* * */ ret = krb5_parse_name_flags(context, "*****@*****.**", KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p); if (ret) err(context, ret, "krb5_parse_name_flags"); ret = krb5_unparse_name(context, p, &unparsed); if (ret) err(context, ret, "krb5_unparse_name"); krb5_free_principal(context, p); if (strcmp(unparsed, "lha\\@[email protected]") != 0) err(context, 0, "enterprise name failed 2: %s", unparsed); free(unparsed); ret = krb5_parse_name_flags(context, "*****@*****.**", KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p); if (ret) err(context, ret, "krb5_parse_name_flags"); ret = krb5_unparse_name_flags(context, p, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed); if (ret) err(context, ret, "krb5_unparse_name"); krb5_free_principal(context, p); if (strcmp(unparsed, "*****@*****.**") != 0) err(context, 0, "enterprise name failed 4: %s", unparsed); free(unparsed); }
static void get_tickets(krb5_context context) { char *def_realm, *server; krb5_error_code retval; krb5_keytab keytab = NULL; krb5_principal server_princ = NULL; /* Figure out what tickets we'll be using to send. */ retval = krb5_sname_to_principal(context, NULL, NULL, KRB5_NT_SRV_HST, &my_principal); if (retval) { com_err(progname, errno, _("while setting client principal name")); exit(1); } if (realm != NULL) { retval = krb5_set_principal_realm(context, my_principal, realm); if (retval) { com_err(progname, errno, _("while setting client principal realm")); exit(1); } } else if (krb5_is_referral_realm(krb5_princ_realm(context, my_principal))) { /* We're going to use this as a client principal, so it can't have the * referral realm. Use the default realm instead. */ retval = krb5_get_default_realm(context, &def_realm); if (retval) { com_err(progname, errno, _("while getting default realm")); exit(1); } retval = krb5_set_principal_realm(context, my_principal, def_realm); if (retval) { com_err(progname, errno, _("while setting client principal realm")); exit(1); } } /* Construct the principal name for the slave host. */ memset(&creds, 0, sizeof(creds)); retval = krb5_sname_to_principal(context, slave_host, KPROP_SERVICE_NAME, KRB5_NT_SRV_HST, &server_princ); if (retval) { com_err(progname, errno, _("while setting server principal name")); exit(1); } retval = krb5_unparse_name_flags(context, server_princ, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server); if (retval) { com_err(progname, retval, _("while unparsing server name")); exit(1); } /* Fill in the client. */ retval = krb5_copy_principal(context, my_principal, &creds.client); if (retval) { com_err(progname, retval, _("while copying client principal")); exit(1); } if (srvtab != NULL) { retval = krb5_kt_resolve(context, srvtab, &keytab); if (retval) { com_err(progname, retval, _("while resolving keytab")); exit(1); } } retval = krb5_get_init_creds_keytab(context, &creds, my_principal, keytab, 0, server, NULL); if (retval) { com_err(progname, retval, _("while getting initial credentials\n")); exit(1); } if (keytab != NULL) krb5_kt_close(context, keytab); krb5_free_unparsed_name(context, server); krb5_free_principal(context, server_princ); }
static krb5_error_code verify_logonname(krb5_context context, const struct PAC_INFO_BUFFER *logon_name, const krb5_data *data, time_t authtime, krb5_const_principal principal) { krb5_error_code ret; uint32_t time1, time2; krb5_storage *sp; uint16_t len; char *s = NULL; char *principal_string = NULL; char *logon_string = NULL; sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, logon_name->buffersize); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_ret_uint32(sp, &time1), out); CHECK(ret, krb5_ret_uint32(sp, &time2), out); { uint64_t t1, t2; t1 = unix2nttime(authtime); t2 = ((uint64_t)time2 << 32) | time1; /* * When neither the ticket nor the PAC set an explicit authtime, * both times are zero, but relative to different time scales. * So we must compare "not set" values without converting to a * common time reference. */ if (t1 != t2 && (t2 != 0 && authtime != 0)) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC timestamp mismatch"); return EINVAL; } } CHECK(ret, krb5_ret_uint16(sp, &len), out); if (len == 0) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "PAC logon name length missing"); return EINVAL; } s = malloc(len); if (s == NULL) { krb5_storage_free(sp); return krb5_enomem(context); } ret = krb5_storage_read(sp, s, len); if (ret != len) { krb5_storage_free(sp); krb5_set_error_message(context, EINVAL, "Failed to read PAC logon name"); return EINVAL; } krb5_storage_free(sp); { size_t ucs2len = len / 2; uint16_t *ucs2; size_t u8len; unsigned int flags = WIND_RW_LE; ucs2 = malloc(sizeof(ucs2[0]) * ucs2len); if (ucs2 == NULL) return krb5_enomem(context); ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len); free(s); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to convert string to UCS-2"); return ret; } ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Failed to count length of UCS-2 string"); return ret; } u8len += 1; /* Add space for NUL */ logon_string = malloc(u8len); if (logon_string == NULL) { free(ucs2); return krb5_enomem(context); } ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len); free(ucs2); if (ret) { free(logon_string); krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); return ret; } } ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM | KRB5_PRINCIPAL_UNPARSE_DISPLAY, &principal_string); if (ret) { free(logon_string); return ret; } ret = strcmp(logon_string, principal_string); if (ret != 0) { ret = EINVAL; krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]", logon_string, principal_string); } free(logon_string); free(principal_string); return ret; out: return ret; }
WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, uint32_t format_flags, uint32_t format_offered, uint32_t format_desired, const char *name, struct drsuapi_DsNameInfo1 *info1) { krb5_error_code ret; const char *domain_filter = NULL; const char *result_filter = NULL; struct ldb_dn *name_dn = NULL; struct smb_krb5_context *smb_krb5_context = NULL; info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; info1->dns_domain_name = NULL; info1->result_name = NULL; if (!name) { return WERR_INVALID_PARAM; } /* TODO: - fill the correct names in all cases! * - handle format_flags */ /* here we need to set the domain_filter and/or the result_filter */ switch (format_offered) { case DRSUAPI_DS_NAME_FORMAT_UNKNOWN: { int i; enum drsuapi_DsNameFormat formats[] = { DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL, DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY, DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL, DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY, DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX }; WERROR werr; for (i=0; i < ARRAY_SIZE(formats); i++) { werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1); if (!W_ERROR_IS_OK(werr)) { return werr; } if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) { return werr; } } return werr; } case DRSUAPI_DS_NAME_FORMAT_CANONICAL: case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: { char *str, *s, *account; if (strlen(name) == 0) { info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } str = talloc_strdup(mem_ctx, name); W_ERROR_HAVE_NO_MEMORY(str); if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) { /* Look backwards for the \n, and replace it with / */ s = strrchr(str, '\n'); if (!s) { info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } s[0] = '/'; } s = strchr(str, '/'); if (!s) { /* there must be at least one / */ info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } s[0] = '\0'; s++; domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(ncName=%s))", ldb_dn_get_linearized(samdb_dns_domain_to_dn(sam_ctx, mem_ctx, str))); W_ERROR_HAVE_NO_MEMORY(domain_filter); /* There may not be anything after the domain component (search for the domain itself) */ if (s[0]) { account = strrchr(s, '/'); if (!account) { account = s; } else { account++; } account = ldb_binary_encode_string(mem_ctx, account); W_ERROR_HAVE_NO_MEMORY(account); result_filter = talloc_asprintf(mem_ctx, "(name=%s)", account); W_ERROR_HAVE_NO_MEMORY(result_filter); } break; } case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: { char *p; char *domain; const char *account = NULL; domain = talloc_strdup(mem_ctx, name); W_ERROR_HAVE_NO_MEMORY(domain); p = strchr(domain, '\\'); if (!p) { /* invalid input format */ info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } p[0] = '\0'; if (p[1]) { account = &p[1]; } domain_filter = talloc_asprintf(mem_ctx, "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", ldb_binary_encode_string(mem_ctx, domain)); W_ERROR_HAVE_NO_MEMORY(domain_filter); if (account) { result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)", ldb_binary_encode_string(mem_ctx, account)); W_ERROR_HAVE_NO_MEMORY(result_filter); } talloc_free(domain); break; } /* A LDAP DN as a string */ case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: { domain_filter = NULL; name_dn = ldb_dn_new(mem_ctx, sam_ctx, name); if (! ldb_dn_validate(name_dn)) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } break; } /* A GUID as a string */ case DRSUAPI_DS_NAME_FORMAT_GUID: { struct GUID guid; char *ldap_guid; NTSTATUS nt_status; domain_filter = NULL; nt_status = GUID_from_string(name, &guid); if (!NT_STATUS_IS_OK(nt_status)) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid); if (!ldap_guid) { return WERR_NOMEM; } result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)", ldap_guid); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } case DRSUAPI_DS_NAME_FORMAT_DISPLAY: { domain_filter = NULL; result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))", ldb_binary_encode_string(mem_ctx, name), ldb_binary_encode_string(mem_ctx, name)); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } /* A S-1234-5678 style string */ case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: { struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name); char *ldap_sid; domain_filter = NULL; if (!sid) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx, sid); if (!ldap_sid) { return WERR_NOMEM; } result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", ldap_sid); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: { krb5_principal principal; char *unparsed_name; ret = smb_krb5_init_context(mem_ctx, ldb_get_event_context(sam_ctx), (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), &smb_krb5_context); if (ret) { return WERR_NOMEM; } /* Ensure we reject compleate junk first */ ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal); if (ret) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } domain_filter = NULL; /* By getting the unparsed name here, we ensure the escaping is correct (and trust the client less) */ ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name); if (ret) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_NOMEM; } krb5_free_principal(smb_krb5_context->krb5_context, principal); /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))", ldb_binary_encode_string(mem_ctx, unparsed_name)); free(unparsed_name); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: { krb5_principal principal; char *unparsed_name_short; char *service; ret = smb_krb5_init_context(mem_ctx, ldb_get_event_context(sam_ctx), (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), &smb_krb5_context); if (ret) { return WERR_NOMEM; } ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal); if (ret == 0 && principal->name.name_string.len < 2) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_OK; } ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal); if (ret) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return dns_domain_from_principal(mem_ctx, smb_krb5_context, name, info1); } domain_filter = NULL; ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short); if (ret) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_NOMEM; } service = principal->name.name_string.val[0]; if ((principal->name.name_string.len == 2) && (strcasecmp(service, "host") == 0)) { /* the 'cn' attribute is just the leading part of the name */ char *computer_name; computer_name = talloc_strndup(mem_ctx, principal->name.name_string.val[1], strcspn(principal->name.name_string.val[1], ".")); if (computer_name == NULL) { return WERR_NOMEM; } result_filter = talloc_asprintf(mem_ctx, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))", ldb_binary_encode_string(mem_ctx, unparsed_name_short), ldb_binary_encode_string(mem_ctx, computer_name)); } else { result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))", ldb_binary_encode_string(mem_ctx, unparsed_name_short)); } krb5_free_principal(smb_krb5_context->krb5_context, principal); free(unparsed_name_short); W_ERROR_HAVE_NO_MEMORY(result_filter); break; } default: { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } } if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) { return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired, name_dn, name, info1); } return DsCrackNameOneFilter(sam_ctx, mem_ctx, smb_krb5_context, format_flags, format_offered, format_desired, name_dn, name, domain_filter, result_filter, info1); }
static int get_user_ccache(const ntlm_name name, char **username, struct ntlm_buf *key) { krb5_context context = NULL; krb5_principal client; krb5_ccache id = NULL; krb5_error_code ret; char *confname; krb5_data data; *username = NULL; krb5_data_zero(&data); key->length = 0; key->data = NULL; ret = krb5_init_context(&context); if (ret) return ret; ret = krb5_cc_default(context, &id); if (ret) goto out; ret = krb5_cc_get_principal(context, id, &client); if (ret) goto out; ret = krb5_unparse_name_flags(context, client, KRB5_PRINCIPAL_UNPARSE_NO_REALM, username); krb5_free_principal(context, client); if (ret) goto out; asprintf(&confname, "ntlm-key-%s", name->domain); if (confname == NULL) { krb5_clear_error_message(context); ret = ENOMEM; goto out; } ret = krb5_cc_get_config(context, id, NULL, confname, &data); if (ret) goto out; key->data = malloc(data.length); if (key->data == NULL) { ret = ENOMEM; goto out; } key->length = data.length; memcpy(key->data, data.data, data.length); out: krb5_data_free(&data); if (id) krb5_cc_close(context, id); krb5_free_context(context); return ret; }
static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, uint32_t format_flags, uint32_t format_offered, uint32_t format_desired, const char *name, struct drsuapi_DsNameInfo1 *info1) { int ldb_ret; WERROR status; const char *domain_filter = NULL; const char *result_filter = NULL; krb5_error_code ret; krb5_principal principal; const char *realm; char *unparsed_name_short; const char *domain_attrs[] = { NULL }; struct ldb_result *domain_res = NULL; /* Prevent recursion */ if (!name) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal); if (ret) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal); ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res, samdb_partitions_dn(sam_ctx, mem_ctx), LDB_SCOPE_ONELEVEL, domain_attrs, "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))", ldb_binary_encode_string(mem_ctx, realm), ldb_binary_encode_string(mem_ctx, realm)); if (ldb_ret != LDB_SUCCESS) { DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s", ldb_errstring(sam_ctx))); info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } switch (domain_res->count) { case 1: break; case 0: return dns_domain_from_principal(mem_ctx, smb_krb5_context, name, info1); default: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE; return WERR_OK; } ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short); krb5_free_principal(smb_krb5_context->krb5_context, principal); if (ret) { free(unparsed_name_short); return WERR_NOMEM; } /* This may need to be extended for more userPrincipalName variations */ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", ldb_binary_encode_string(mem_ctx, unparsed_name_short)); domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn)); if (!result_filter || !domain_filter) { free(unparsed_name_short); return WERR_NOMEM; } status = DsCrackNameOneFilter(sam_ctx, mem_ctx, smb_krb5_context, format_flags, format_offered, format_desired, NULL, unparsed_name_short, domain_filter, result_filter, info1); free(unparsed_name_short); return status; }
static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, uint32_t format_flags, uint32_t format_offered, uint32_t format_desired, const char *name, struct drsuapi_DsNameInfo1 *info1) { WERROR wret; krb5_error_code ret; krb5_principal principal; const char *service, *dns_name; char *new_service; char *new_princ; enum drsuapi_DsNameStatus namestatus; /* parse principal */ ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name, KRB5_PRINCIPAL_PARSE_NO_REALM, &principal); if (ret) { DEBUG(2, ("Could not parse principal: %s: %s", name, smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); return WERR_NOMEM; } /* grab cifs/, http/ etc */ /* This is checked for in callers, but be safe */ if (principal->name.name_string.len < 2) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } service = principal->name.name_string.val[0]; dns_name = principal->name.name_string.val[1]; /* MAP it */ namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context, sam_ctx, mem_ctx, service, &new_service); if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) { info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY; info1->dns_domain_name = talloc_strdup(mem_ctx, dns_name); if (!info1->dns_domain_name) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_NOMEM; } return WERR_OK; } else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) { info1->status = namestatus; krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_OK; } /* ooh, very nasty playing around in the Principal... */ free(principal->name.name_string.val[0]); principal->name.name_string.val[0] = strdup(new_service); if (!principal->name.name_string.val[0]) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_NOMEM; } /* reform principal */ ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &new_princ); if (ret) { krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_NOMEM; } wret = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, format_offered, format_desired, new_princ, info1); free(new_princ); if (W_ERROR_IS_OK(wret) && (info1->status == DRSUAPI_DS_NAME_STATUS_NOT_FOUND)) { info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY; info1->dns_domain_name = talloc_strdup(mem_ctx, dns_name); if (!info1->dns_domain_name) { wret = WERR_NOMEM; } } krb5_free_principal(smb_krb5_context->krb5_context, principal); return wret; }
static krb5_error_code get_new_tickets(krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_deltat ticket_life, int interactive) { krb5_error_code ret; krb5_get_init_creds_opt *opt; krb5_creds cred; char passwd[256]; krb5_deltat start_time = 0; krb5_deltat renew = 0; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache; krb5_init_creds_context icc; krb5_keytab kt = NULL; int will_use_keytab = (use_keytab || keytab_str); krb5_prompter_fct prompter = NULL; int need_prompt; passwd[0] = '\0'; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) krb5_errx(context, 1, "Failed to open the password file %s", password_file); if (fgets(passwd, sizeof(passwd), f) == NULL) krb5_errx(context, 1, N_("Failed to read password from file %s", ""), password_file); if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #if defined(__APPLE__) && !defined(__APPLE_TARGET_EMBEDDED__) if (passwd[0] == '\0' && !will_use_keytab && home_directory_flag) { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, (UInt32)strlen(realm), realm, (UInt32)strlen(name), name, &length, &buffer, &passwordItem); free(name); if (osret != noErr) goto nopassword; if (length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } SecKeychainItemFreeContent(NULL, buffer); nopassword: do { } while(0); } #endif need_prompt = !(pk_user_id || ent_user_id || anonymous_flag || will_use_keytab || passwd[0] != '\0') && interactive; if (need_prompt) prompter = krb5_prompter_posix; else prompter = krb5_prompter_print_only; memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc (context, &opt); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if(forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable (opt, forwardable_flag); if(proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable (opt, proxiable_flag); if(anonymous_flag) krb5_get_init_creds_opt_set_anonymous (opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, interactive ? krb5_prompter_posix : krb5_prompter_print_only, NULL, passwd); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_cert(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time (renewstr, "s"); if (renew < 0) errx (1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life (opt, renew); } if(ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life (opt, ticket_life); if(start_str) { int tmp = parse_time (start_str, "s"); if (tmp < 0) errx (1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if(etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if(enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if(ret) krb5_err(context, 1, ret, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &icc); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_init"); if (server_str) { ret = krb5_init_creds_set_service(context, icc, server_str); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_set_service"); } if (kdc_hostname) krb5_init_creds_set_kdc_hostname(context, icc, kdc_hostname); if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) krb5_err(context, 1, ret, "krb5_cc_resolve(FAST cache)"); ret = krb5_init_creds_set_fast_ccache(context, icc, fastid); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_fast_ccache"); } if(will_use_keytab) { if(keytab_str) ret = krb5_kt_resolve(context, keytab_str, &kt); else ret = krb5_kt_default(context, &kt); if (ret) krb5_err (context, 1, ret, "resolving keytab"); ret = krb5_init_creds_set_keytab(context, icc, kt); if (ret) krb5_err (context, 1, ret, "krb5_init_creds_set_keytab"); } if (passwd[0] == '\0' && need_prompt) { char *p, *prompt; krb5_unparse_name(context, principal, &p); asprintf (&prompt, N_("%s's Password: "******""), p); free(p); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); errx(1, "failed to read password"); } free (prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, icc, passwd); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_set_password"); } ret = krb5_init_creds_get(context, icc); #ifdef __APPLE__ /* * Save password in Keychain */ if (ret == 0 && keychain_flag && passwordItem == NULL) { krb5_error_code ret2; const char *realm; char *name; realm = krb5_principal_get_realm(context, principal); ret2 = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret2 == 0) { (void)SecKeychainAddGenericPassword(NULL, (UInt32)strlen(realm), realm, (UInt32)strlen(name), name, (UInt32)strlen(passwd), passwd, NULL); free(name); } } #endif memset(passwd, 0, sizeof(passwd)); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ exit(1); case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5_GET_IN_TKT_LOOP: #ifdef __APPLE__ if (passwordItem) SecKeychainItemDelete(passwordItem); #endif krb5_errx(context, 1, N_("Password incorrect", "")); case KRB5KRB_AP_ERR_V4_REPLY: krb5_errx(context, 1, N_("Looks like a Kerberos 4 reply", "")); case KRB5KDC_ERR_KEY_EXPIRED: krb5_errx(context, 1, N_("Password expired", "")); default: krb5_err(context, 1, ret, "krb5_get_init_creds"); } ret = krb5_init_creds_get_creds(context, icc, &cred); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_get_creds"); krb5_process_last_request(context, opt, icc); ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) krb5_err (context, 1, ret, "krb5_cc_new_unique"); ret = krb5_init_creds_store(context, icc, tempccache); if (ret) krb5_err(context, 1, ret, "krb5_init_creds_store"); ret = krb5_init_creds_store_config(context, icc, tempccache); if (ret) krb5_warn(context, ret, "krb5_init_creds_store_config"); ret = krb5_init_creds_warn_user(context, icc); if (ret) krb5_warn(context, ret, "krb5_init_creds_warn_user"); #ifdef __APPLE__ /* * Set for this case, default to * so that all processes can use * this cache. */ { heim_array_t bundleacl = heim_array_create(); heim_string_t ace; if (bundle_acl_strings.num_strings > 0) { int i; for (i = 0; i < bundle_acl_strings.num_strings; i++) { ace = heim_string_create(bundle_acl_strings.strings[i]); heim_array_append_value(bundleacl, ace); heim_release(ace); } } else { ace = heim_string_create("*"); heim_array_append_value(bundleacl, ace); heim_release(ace); } krb5_cc_set_acl(context, tempccache, "kHEIMAttrBundleIdentifierACL", bundleacl); heim_release(bundleacl); } #endif ret = krb5_cc_move(context, tempccache, ccache); if (ret) { (void)krb5_cc_destroy(context, tempccache); krb5_err (context, 1, ret, "krb5_cc_move"); } if (switch_cache_flags) krb5_cc_switch(context, ccache); if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } if (enctype) free(enctype); krb5_init_creds_free(context, icc); krb5_get_init_creds_opt_free(context, opt); if (kt) krb5_kt_close(context, kt); #ifdef __APPLE__ if (passwordItem) CFRelease(passwordItem); #endif return 0; }
static krb5_error_code s4u2proxy_get_attribute(krb5_context kcontext, krb5_authdata_context context, void *plugin_context, void *request_context, const krb5_data *attribute, krb5_boolean *authenticated, krb5_boolean *complete, krb5_data *value, krb5_data *display_value, int *more) { struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; krb5_error_code code; krb5_principal principal; int i; if (display_value != NULL) { display_value->data = NULL; display_value->length = 0; } if (!data_eq(*attribute, s4u2proxy_transited_services_attr)) return ENOENT; i = -(*more) - 1; if (i < 0) return EINVAL; else if (i >= s4uctx->count) return ENOENT; principal = s4uctx->delegated[i]; assert(principal != NULL); code = krb5_unparse_name_flags(kcontext, principal, 0, &value->data); if (code != 0) return code; value->length = strlen(value->data); if (display_value != NULL) { code = krb5_unparse_name_flags(kcontext, principal, KRB5_PRINCIPAL_UNPARSE_DISPLAY, &display_value->data); if (code != 0) return code; display_value->length = strlen(display_value->data); } i++; if (i == s4uctx->count) *more = 0; else *more = -(i + 1); *authenticated = s4uctx->authenticated; *complete = TRUE; return 0; }
static krb5_error_code build_logon_name(krb5_context context, time_t authtime, krb5_const_principal principal, krb5_data *logon) { krb5_error_code ret; krb5_storage *sp; uint64_t t; char *s, *s2; size_t s2_len; t = unix2nttime(authtime); krb5_data_zero(logon); sp = krb5_storage_emem(); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out); CHECK(ret, krb5_store_uint32(sp, t >> 32), out); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM | KRB5_PRINCIPAL_UNPARSE_DISPLAY, &s); if (ret) goto out; { size_t ucs2_len; uint16_t *ucs2; unsigned int flags; ret = wind_utf8ucs2_length(s, &ucs2_len); if (ret) { krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s); free(s); return ret; } ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len); if (ucs2 == NULL) { free(s); return krb5_enomem(context); } ret = wind_utf8ucs2(s, ucs2, &ucs2_len); if (ret) { free(ucs2); krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s); free(s); return ret; } else free(s); s2_len = (ucs2_len + 1) * 2; s2 = malloc(s2_len); if (s2 == NULL) { free(ucs2); return krb5_enomem(context); } flags = WIND_RW_LE; ret = wind_ucs2write(ucs2, ucs2_len, &flags, s2, &s2_len); free(ucs2); if (ret) { free(s2); krb5_set_error_message(context, ret, "Failed to write to UCS-2 buffer"); return ret; } /* * we do not want zero termination */ s2_len = ucs2_len * 2; } CHECK(ret, krb5_store_uint16(sp, s2_len), out); ret = krb5_storage_write(sp, s2, s2_len); free(s2); if (ret != (int)s2_len) { ret = krb5_enomem(context); goto out; } ret = krb5_storage_to_data(sp, logon); if (ret) goto out; krb5_storage_free(sp); return 0; out: krb5_storage_free(sp); return ret; }
static krb5_error_code build_logon_name(krb5_context context, time_t authtime, krb5_const_principal principal, krb5_data *logon) { krb5_error_code ret; krb5_storage *sp; uint64_t t; char *s, *s2; size_t i, len; t = unix2nttime(authtime); krb5_data_zero(logon); sp = krb5_storage_emem(); if (sp == NULL) return krb5_enomem(context); krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out); CHECK(ret, krb5_store_uint32(sp, t >> 32), out); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &s); if (ret) goto out; len = strlen(s); CHECK(ret, krb5_store_uint16(sp, len * 2), out); #if 1 /* cheat for now */ s2 = malloc(len * 2); if (s2 == NULL) { ret = krb5_enomem(context); free(s); goto out; } for (i = 0; i < len; i++) { s2[i * 2] = s[i]; s2[i * 2 + 1] = 0; } free(s); #else /* write libwind code here */ #endif ret = krb5_storage_write(sp, s2, len * 2); free(s2); if (ret != len * 2) { ret = krb5_enomem(context); goto out; } ret = krb5_storage_to_data(sp, logon); if (ret) goto out; krb5_storage_free(sp); return 0; out: krb5_storage_free(sp); return ret; }
krb5_error_code sss_krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal, int flags, char **name) { #ifdef HAVE_KRB5_UNPARSE_NAME_FLAGS return krb5_unparse_name_flags(context, principal, flags, name); #else char *cp, *q; int i; int length; krb5_int32 nelem; unsigned int totalsize = 0; char *default_realm = NULL; krb5_error_code ret = 0; if (name != NULL) *name = NULL; if (!principal || !name) return KRB5_PARSE_MALFORMED; if (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) { /* omit realm if local realm */ krb5_principal_data p; ret = krb5_get_default_realm(context, &default_realm); if (ret != 0) goto cleanup; krb5_princ_realm(context, &p)->length = strlen(default_realm); krb5_princ_realm(context, &p)->data = default_realm; if (krb5_realm_compare(context, &p, principal)) flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM; } if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) { totalsize += sss_krb5_component_length_quoted(krb5_princ_realm(context, principal), flags); totalsize++; } nelem = krb5_princ_size(context, principal); for (i = 0; i < (int) nelem; i++) { cp = krb5_princ_component(context, principal, i)->data; totalsize += sss_krb5_component_length_quoted(krb5_princ_component(context, principal, i), flags); totalsize++; } if (nelem == 0) totalsize++; *name = malloc(totalsize); if (!*name) { ret = ENOMEM; goto cleanup; } q = *name; for (i = 0; i < (int) nelem; i++) { cp = krb5_princ_component(context, principal, i)->data; length = krb5_princ_component(context, principal, i)->length; q += sss_krb5_copy_component_quoting(q, krb5_princ_component(context, principal, i), flags); *q++ = COMPONENT_SEP; } if (i > 0) q--; if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) { *q++ = REALM_SEP; q += sss_krb5_copy_component_quoting(q, krb5_princ_realm(context, principal), flags); } *q++ = '\0'; cleanup: free(default_realm); return ret; #endif /* HAVE_KRB5_UNPARSE_NAME_FLAGS */ }
static int get_user_ccache(const ntlm_name name, char **domainp, char **usernamep, struct ntlm_buf *key) { krb5_context context = NULL; krb5_principal client; krb5_ccache id = NULL; krb5_error_code ret; char *confname; krb5_data data; int aret; *domainp = NULL; *usernamep = NULL; krb5_data_zero(&data); key->length = 0; key->data = NULL; ret = krb5_init_context(&context); if (ret) return ret; ret = krb5_cc_default(context, &id); if (ret) goto out; ret = krb5_cc_get_principal(context, id, &client); if (ret) goto out; ret = krb5_unparse_name_flags(context, client, KRB5_PRINCIPAL_UNPARSE_NO_REALM, usernamep); krb5_free_principal(context, client); if (ret) goto out; if (name != NULL) { *domainp = strdup(name->domain); } else { krb5_data data_domain; krb5_data_zero(&data_domain); ret = krb5_cc_get_config(context, id, NULL, "default-ntlm-domain", &data_domain); if (ret) goto out; *domainp = strndup(data_domain.data, data_domain.length); krb5_data_free(&data_domain); } if (*domainp == NULL) { ret = krb5_enomem(context); goto out; } aret = asprintf(&confname, "ntlm-key-%s", *domainp); if (aret == -1) { ret = krb5_enomem(context); goto out; } ret = krb5_cc_get_config(context, id, NULL, confname, &data); if (ret) goto out; key->data = malloc(data.length); if (key->data == NULL) { ret = ENOMEM; goto out; } key->length = data.length; memcpy(key->data, data.data, data.length); out: krb5_data_free(&data); if (id) krb5_cc_close(context, id); krb5_free_context(context); return ret; }
krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx, struct auth_user_info_dc *user_info_dc, krb5_context context, const krb5_keyblock *krbtgt_keyblock, const krb5_keyblock *service_keyblock, krb5_principal client_principal, time_t tgs_authtime, DATA_BLOB *pac) { NTSTATUS nt_status; krb5_error_code ret; struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA); struct netr_SamInfo3 *sam3; union PAC_INFO *u_LOGON_INFO; struct PAC_LOGON_INFO *LOGON_INFO; union PAC_INFO *u_LOGON_NAME; struct PAC_LOGON_NAME *LOGON_NAME; union PAC_INFO *u_KDC_CHECKSUM; union PAC_INFO *u_SRV_CHECKSUM; char *name; enum { PAC_BUF_LOGON_INFO = 0, PAC_BUF_LOGON_NAME = 1, PAC_BUF_SRV_CHECKSUM = 2, PAC_BUF_KDC_CHECKSUM = 3, PAC_BUF_NUM_BUFFERS = 4 }; if (!pac_data) { return ENOMEM; } pac_data->num_buffers = PAC_BUF_NUM_BUFFERS; pac_data->version = 0; pac_data->buffers = talloc_array(pac_data, struct PAC_BUFFER, pac_data->num_buffers); if (!pac_data->buffers) { talloc_free(pac_data); return ENOMEM; } /* LOGON_INFO */ u_LOGON_INFO = talloc_zero(pac_data->buffers, union PAC_INFO); if (!u_LOGON_INFO) { talloc_free(pac_data); return ENOMEM; } pac_data->buffers[PAC_BUF_LOGON_INFO].type = PAC_TYPE_LOGON_INFO; pac_data->buffers[PAC_BUF_LOGON_INFO].info = u_LOGON_INFO; /* LOGON_NAME */ u_LOGON_NAME = talloc_zero(pac_data->buffers, union PAC_INFO); if (!u_LOGON_NAME) { talloc_free(pac_data); return ENOMEM; } pac_data->buffers[PAC_BUF_LOGON_NAME].type = PAC_TYPE_LOGON_NAME; pac_data->buffers[PAC_BUF_LOGON_NAME].info = u_LOGON_NAME; LOGON_NAME = &u_LOGON_NAME->logon_name; /* SRV_CHECKSUM */ u_SRV_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO); if (!u_SRV_CHECKSUM) { talloc_free(pac_data); return ENOMEM; } pac_data->buffers[PAC_BUF_SRV_CHECKSUM].type = PAC_TYPE_SRV_CHECKSUM; pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info = u_SRV_CHECKSUM; /* KDC_CHECKSUM */ u_KDC_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO); if (!u_KDC_CHECKSUM) { talloc_free(pac_data); return ENOMEM; } pac_data->buffers[PAC_BUF_KDC_CHECKSUM].type = PAC_TYPE_KDC_CHECKSUM; pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info = u_KDC_CHECKSUM; /* now the real work begins... */ LOGON_INFO = talloc_zero(u_LOGON_INFO, struct PAC_LOGON_INFO); if (!LOGON_INFO) { talloc_free(pac_data); return ENOMEM; } nt_status = auth_convert_user_info_dc_saminfo3(LOGON_INFO, user_info_dc, &sam3); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status))); talloc_free(pac_data); return EINVAL; } u_LOGON_INFO->logon_info.info = LOGON_INFO; LOGON_INFO->info3 = *sam3; ret = krb5_unparse_name_flags(context, client_principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM | KRB5_PRINCIPAL_UNPARSE_DISPLAY, &name); if (ret) { return ret; } LOGON_NAME->account_name = talloc_strdup(LOGON_NAME, name); free(name); /* this logon_time field is absolutely critical. This is what caused all our PAC troubles :-) */ unix_to_nt_time(&LOGON_NAME->logon_time, tgs_authtime); ret = kerberos_encode_pac(mem_ctx, pac_data, context, krbtgt_keyblock, service_keyblock, pac); talloc_free(pac_data); return ret; }
static krb5_error_code get_new_tickets(krb5_context context, krb5_principal principal, krb5_ccache ccache, krb5_deltat ticket_life, int interactive) { krb5_error_code ret; krb5_creds cred; char passwd[256]; krb5_deltat start_time = 0; krb5_deltat renew = 0; const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache = NULL; krb5_init_creds_context ctx = NULL; krb5_get_init_creds_opt *opt = NULL; krb5_prompter_fct prompter = krb5_prompter_posix; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); #endif passwd[0] = '\0'; if (!interactive) prompter = NULL; if (password_file) { FILE *f; if (strcasecmp("STDIN", password_file) == 0) f = stdin; else f = fopen(password_file, "r"); if (f == NULL) { krb5_warnx(context, "Failed to open the password file %s", password_file); return errno; } if (fgets(passwd, sizeof(passwd), f) == NULL) { krb5_warnx(context, N_("Failed to read password from file %s", ""), password_file); fclose(f); return EINVAL; /* XXX Need a better error */ } if (f != stdin) fclose(f); passwd[strcspn(passwd, "\n")] = '\0'; } #ifdef __APPLE__ if (passwd[0] == '\0') { const char *realm; OSStatus osret; UInt32 length; void *buffer; char *name; realm = krb5_principal_get_realm(context, principal); ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); if (ret) goto nopassword; osret = SecKeychainFindGenericPassword(NULL, strlen(realm), realm, strlen(name), name, &length, &buffer, NULL); free(name); if (osret == noErr && length < sizeof(passwd) - 1) { memcpy(passwd, buffer, length); passwd[length] = '\0'; } nopassword: do { } while(0); } #endif memset(&cred, 0, sizeof(cred)); ret = krb5_get_init_creds_opt_alloc(context, &opt); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_alloc"); goto out; } krb5_get_init_creds_opt_set_default_flags(context, "kinit", krb5_principal_get_realm(context, principal), opt); if (forwardable_flag != -1) krb5_get_init_creds_opt_set_forwardable(opt, forwardable_flag); if (proxiable_flag != -1) krb5_get_init_creds_opt_set_proxiable(opt, proxiable_flag); if (anonymous_flag) krb5_get_init_creds_opt_set_anonymous(opt, anonymous_flag); if (pac_flag != -1) krb5_get_init_creds_opt_set_pac_request(context, opt, pac_flag ? TRUE : FALSE); if (canonicalize_flag) krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); if (pk_user_id || ent_user_id || anonymous_flag) { ret = krb5_get_init_creds_opt_set_pkinit(context, opt, principal, pk_user_id, pk_x509_anchors, NULL, NULL, pk_use_enckey ? 2 : 0 | anonymous_flag ? 4 : 0, prompter, NULL, passwd); if (ret) { krb5_warn(context, ret, "krb5_get_init_creds_opt_set_pkinit"); goto out; } if (ent_user_id) krb5_get_init_creds_opt_set_pkinit_user_certs(context, opt, ent_user_id); } if (addrs_flag != -1) krb5_get_init_creds_opt_set_addressless(context, opt, addrs_flag ? FALSE : TRUE); if (renew_life == NULL && renewable_flag) renewstr = "1 month"; if (renew_life) renewstr = renew_life; if (renewstr) { renew = parse_time(renewstr, "s"); if (renew < 0) errx(1, "unparsable time: %s", renewstr); krb5_get_init_creds_opt_set_renew_life(opt, renew); } if (ticket_life != 0) krb5_get_init_creds_opt_set_tkt_life(opt, ticket_life); if (start_str) { int tmp = parse_time(start_str, "s"); if (tmp < 0) errx(1, N_("unparsable time: %s", ""), start_str); start_time = tmp; } if (etype_str.num_strings) { int i; enctype = malloc(etype_str.num_strings * sizeof(*enctype)); if (enctype == NULL) errx(1, "out of memory"); for(i = 0; i < etype_str.num_strings; i++) { ret = krb5_string_to_enctype(context, etype_str.strings[i], &enctype[i]); if (ret) errx(1, "unrecognized enctype: %s", etype_str.strings[i]); } krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); } ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &ctx); if (ret) { krb5_warn(context, ret, "krb5_init_creds_init"); goto out; } if (server_str) { ret = krb5_init_creds_set_service(context, ctx, server_str); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_service"); goto out; } } if (fast_armor_cache_string) { krb5_ccache fastid; ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); if (ret) { krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)"); goto out; } ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache"); goto out; } } if (use_keytab || keytab_str) { ret = krb5_init_creds_set_keytab(context, ctx, kt); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_keytab"); goto out; } } else if (pk_user_id || ent_user_id || anonymous_flag) { } else if (!interactive && passwd[0] == '\0') { static int already_warned = 0; if (!already_warned) krb5_warnx(context, "Not interactive, failed to get " "initial ticket"); krb5_get_init_creds_opt_free(context, opt); already_warned = 1; return 0; } else { if (passwd[0] == '\0') { char *p, *prompt; int aret = 0; ret = krb5_unparse_name(context, principal, &p); if (ret) errx(1, "failed to generate passwd prompt: not enough memory"); aret = asprintf(&prompt, N_("%s's Password: "******""), p); free(p); if (aret == -1) errx(1, "failed to generate passwd prompt: not enough memory"); if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); errx(1, "failed to read password"); } free(prompt); } if (passwd[0]) { ret = krb5_init_creds_set_password(context, ctx, passwd); if (ret) { krb5_warn(context, ret, "krb5_init_creds_set_password"); goto out; } } } ret = krb5_init_creds_get(context, ctx); #ifndef NO_NTLM if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); #endif memset(passwd, 0, sizeof(passwd)); switch(ret){ case 0: break; case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ exit(1); case KRB5KRB_AP_ERR_BAD_INTEGRITY: case KRB5KRB_AP_ERR_MODIFIED: case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5_GET_IN_TKT_LOOP: krb5_warnx(context, N_("Password incorrect", "")); goto out; case KRB5KRB_AP_ERR_V4_REPLY: krb5_warnx(context, N_("Looks like a Kerberos 4 reply", "")); goto out; case KRB5KDC_ERR_KEY_EXPIRED: krb5_warnx(context, N_("Password expired", "")); goto out; default: krb5_warn(context, ret, "krb5_get_init_creds"); goto out; } krb5_process_last_request(context, opt, ctx); ret = krb5_init_creds_get_creds(context, ctx, &cred); if (ret) { krb5_warn(context, ret, "krb5_init_creds_get_creds"); goto out; } if (ticket_life != 0) { if (abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { char life[64]; unparse_time_approx(cred.times.endtime - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket lifetime is %s", ""), life); } } if (renew_life) { if (abs(cred.times.renew_till - cred.times.starttime - renew) > 30) { char life[64]; unparse_time_approx(cred.times.renew_till - cred.times.starttime, life, sizeof(life)); krb5_warnx(context, N_("NOTICE: ticket renewable lifetime is %s", ""), life); } } krb5_free_cred_contents(context, &cred); ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, ccache), NULL, &tempccache); if (ret) { krb5_warn(context, ret, "krb5_cc_new_unique"); goto out; } ret = krb5_init_creds_store(context, ctx, tempccache); if (ret) { krb5_warn(context, ret, "krb5_init_creds_store"); goto out; } krb5_init_creds_free(context, ctx); ctx = NULL; ret = krb5_cc_move(context, tempccache, ccache); if (ret) { krb5_warn(context, ret, "krb5_cc_move"); goto out; } tempccache = NULL; if (switch_cache_flags) krb5_cc_switch(context, ccache); #ifndef NO_NTLM if (ntlm_domain && ntlmkey.data) store_ntlmkey(context, ccache, ntlm_domain, &ntlmkey); #endif if (ok_as_delegate_flag || windows_flag || use_referrals_flag) { unsigned char d = 0; krb5_data data; if (ok_as_delegate_flag || windows_flag) d |= 1; if (use_referrals_flag || windows_flag) d |= 2; data.length = 1; data.data = &d; krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } out: krb5_get_init_creds_opt_free(context, opt); if (ctx) krb5_init_creds_free(context, ctx); if (tempccache) krb5_cc_close(context, tempccache); if (enctype) free(enctype); return ret; }
static krb5_error_code kpasswd_set_password(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, struct auth_session_info *session_info, DATA_BLOB *decoded_data, DATA_BLOB *kpasswd_reply, const char **error_string) { krb5_context context = kdc->smb_krb5_context->krb5_context; krb5_data k_dec_data; krb5_data *k_clear_data; krb5_principal target_principal; krb5_error_code code; DATA_BLOB password; char *target_realm = NULL; char *target_name = NULL; char *target_principal_string = NULL; bool is_service_principal = false; bool ok; size_t num_components; enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR; struct samr_DomInfo1 *dominfo = NULL; NTSTATUS status; k_dec_data.length = decoded_data->length; k_dec_data.data = (char *)decoded_data->data; code = decode_krb5_setpw_req(&k_dec_data, &k_clear_data, &target_principal); if (code != 0) { DBG_WARNING("decode_krb5_setpw_req failed: %s\n", error_message(code)); ok = kpasswd_make_error_reply(mem_ctx, KRB5_KPASSWD_MALFORMED, "Failed to decode packet", kpasswd_reply); if (!ok) { *error_string = "Failed to create reply"; return KRB5_KPASSWD_HARDERROR; } return 0; } ok = convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(kdc->task->lp_ctx), CH_UTF8, CH_UTF16, (const char *)k_clear_data->data, k_clear_data->length, (void **)&password.data, &password.length); krb5_free_data(context, k_clear_data); if (!ok) { DBG_WARNING("String conversion failed\n"); *error_string = "String conversion failed"; return KRB5_KPASSWD_HARDERROR; } target_realm = smb_krb5_principal_get_realm(context, target_principal); code = krb5_unparse_name_flags(context, target_principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &target_name); if (code != 0) { DBG_WARNING("Failed to parse principal\n"); *error_string = "String conversion failed"; return KRB5_KPASSWD_HARDERROR; } if ((target_name != NULL && target_realm == NULL) || (target_name == NULL && target_realm != NULL)) { krb5_free_principal(context, target_principal); SAFE_FREE(target_realm); SAFE_FREE(target_name); ok = kpasswd_make_error_reply(mem_ctx, KRB5_KPASSWD_MALFORMED, "Realm and principal must be " "both present, or neither " "present", kpasswd_reply); if (!ok) { *error_string = "Failed to create reply"; return KRB5_KPASSWD_HARDERROR; } return 0; } if (target_name != NULL && target_realm != NULL) { SAFE_FREE(target_realm); SAFE_FREE(target_name); } else { krb5_free_principal(context, target_principal); SAFE_FREE(target_realm); SAFE_FREE(target_name); return kpasswd_change_password(kdc, mem_ctx, session_info, &password, kpasswd_reply, error_string); } num_components = krb5_princ_size(context, target_principal); if (num_components >= 2) { is_service_principal = true; code = krb5_unparse_name_flags(context, target_principal, KRB5_PRINCIPAL_UNPARSE_SHORT, &target_principal_string); } else { code = krb5_unparse_name(context, target_principal, &target_principal_string); } krb5_free_principal(context, target_principal); if (code != 0) { ok = kpasswd_make_error_reply(mem_ctx, KRB5_KPASSWD_MALFORMED, "Failed to parse principal", kpasswd_reply); if (!ok) { *error_string = "Failed to create reply"; return KRB5_KPASSWD_HARDERROR; } } status = kpasswd_samdb_set_password(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info, is_service_principal, target_principal_string, &password, &reject_reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { DBG_ERR("kpasswd_samdb_set_password failed - %s\n", nt_errstr(status)); } ok = kpasswd_make_pwchange_reply(mem_ctx, status, reject_reason, dominfo, kpasswd_reply); if (!ok) { *error_string = "Failed to create reply"; return KRB5_KPASSWD_HARDERROR; } return 0; }