NTSTATUS crack_service_principal_name(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, const char *service_principal_name, struct ldb_dn **user_dn, struct ldb_dn **domain_dn) { WERROR werr; struct drsuapi_DsNameInfo1 info1; werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0, DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL, DRSUAPI_DS_NAME_FORMAT_FQDN_1779, service_principal_name, &info1); if (!W_ERROR_IS_OK(werr)) { return werror_to_ntstatus(werr); } switch (info1.status) { case DRSUAPI_DS_NAME_STATUS_OK: break; case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: return NT_STATUS_NO_SUCH_USER; case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: default: return NT_STATUS_UNSUCCESSFUL; } *user_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name); if (domain_dn) { werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0, DRSUAPI_DS_NAME_FORMAT_CANONICAL, DRSUAPI_DS_NAME_FORMAT_FQDN_1779, talloc_asprintf(mem_ctx, "%s/", info1.dns_domain_name), &info1); if (!W_ERROR_IS_OK(werr)) { return werror_to_ntstatus(werr); } switch (info1.status) { case DRSUAPI_DS_NAME_STATUS_OK: break; case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: return NT_STATUS_NO_SUCH_USER; case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: default: return NT_STATUS_UNSUCCESSFUL; } *domain_dn = ldb_dn_new(mem_ctx, sam_ctx, info1.result_name); } return NT_STATUS_OK; }
WERROR dcesrv_drsuapi_CrackNamesByNameFormat(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, const struct drsuapi_DsNameRequest1 *req1, struct drsuapi_DsNameCtr1 **ctr1) { struct drsuapi_DsNameInfo1 *names; uint32_t i, count; WERROR status; *ctr1 = talloc_zero(mem_ctx, struct drsuapi_DsNameCtr1); W_ERROR_HAVE_NO_MEMORY(*ctr1); count = req1->count; names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count); W_ERROR_HAVE_NO_MEMORY(names); for (i=0; i < count; i++) { status = DsCrackNameOneName(sam_ctx, mem_ctx, req1->format_flags, req1->format_offered, req1->format_desired, req1->names[i].str, &names[i]); if (!W_ERROR_IS_OK(status)) { return status; } } (*ctr1)->count = count; (*ctr1)->array = names; return WERR_OK; }
/* drsuapi_DsCrackNames */ static WERROR dcesrv_drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsCrackNames *r) { WERROR status; struct drsuapi_bind_state *b_state; struct dcesrv_handle *h; *r->out.level_out = r->in.level; DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; r->out.ctr = talloc_zero(mem_ctx, union drsuapi_DsNameCtr); W_ERROR_HAVE_NO_MEMORY(r->out.ctr); switch (r->in.level) { case 1: { struct drsuapi_DsNameCtr1 *ctr1; struct drsuapi_DsNameInfo1 *names; int count; int i; ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1); W_ERROR_HAVE_NO_MEMORY(ctr1); count = r->in.req->req1.count; names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count); W_ERROR_HAVE_NO_MEMORY(names); for (i=0; i < count; i++) { status = DsCrackNameOneName(b_state->sam_ctx, mem_ctx, r->in.req->req1.format_flags, r->in.req->req1.format_offered, r->in.req->req1.format_desired, r->in.req->req1.names[i].str, &names[i]); if (!W_ERROR_IS_OK(status)) { return status; } } ctr1->count = count; ctr1->array = names; r->out.ctr->ctr1 = ctr1; return WERR_OK; } } return WERR_UNKNOWN_LEVEL; }
/**************************************************************************** Create an auth_usersupplied_data structure after appropriate mapping. ****************************************************************************/ static NTSTATUS map_user_info_cracknames(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, const char *default_domain, const struct auth_usersupplied_info *user_info, struct auth_usersupplied_info **user_info_mapped) { char *domain; char *account_name; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); WERROR werr; struct drsuapi_DsNameInfo1 info1; DEBUG(5,("map_user_info_cracknames: Mapping user [%s]\\[%s] from workstation [%s]\n", user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); account_name = talloc_strdup(tmp_ctx, user_info->client.account_name); if (!account_name) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* use cracknames to work out what domain is being asked for */ if (strchr_m(user_info->client.account_name, '@') != NULL) { werr = DsCrackNameOneName(sam_ctx, tmp_ctx, 0, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, user_info->client.account_name, &info1); if (!W_ERROR_IS_OK(werr)) { DEBUG(2,("map_user_info: Failed cracknames of account '%s'\n", user_info->client.account_name)); talloc_free(tmp_ctx); return werror_to_ntstatus(werr); } switch (info1.status) { case DRSUAPI_DS_NAME_STATUS_OK: break; case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: DEBUG(2,("map_user_info: Cracknames of account '%s' -> NOT_FOUND\n", user_info->client.account_name)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: DEBUG(2,("map_user_info: Cracknames of account '%s' -> DOMAIN_ONLY\n", user_info->client.account_name)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: DEBUG(2,("map_user_info: Cracknames of account '%s' -> NOT_UNIQUE\n", user_info->client.account_name)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: DEBUG(2,("map_user_info: Cracknames of account '%s' -> RESOLVE_ERROR\n", user_info->client.account_name)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; default: DEBUG(2,("map_user_info: Cracknames of account '%s' -> unknown error %u\n", user_info->client.account_name, info1.status)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; } /* info1.result_name is in DOMAIN\username * form, which we need to split up into the * user_info_mapped structure */ domain = talloc_strdup(tmp_ctx, info1.result_name); if (domain == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } account_name = strchr_m(domain, '\\'); if (account_name == NULL) { DEBUG(2,("map_user_info: Cracknames of account '%s' gave invalid result '%s'\n", user_info->client.account_name, info1.result_name)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; } *account_name = 0; account_name = talloc_strdup(tmp_ctx, account_name+1); if (account_name == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } } else { char *domain_name; if (user_info->client.domain_name && *user_info->client.domain_name) { domain_name = talloc_asprintf(tmp_ctx, "%s\\", user_info->client.domain_name); } else { domain_name = talloc_strdup(tmp_ctx, default_domain); } if (domain_name == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0, DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, domain_name, &info1); if (!W_ERROR_IS_OK(werr)) { DEBUG(2,("map_user_info: Failed cracknames of domain '%s'\n", domain_name)); talloc_free(tmp_ctx); return werror_to_ntstatus(werr); } /* we use the account_name as-is, but get the * domain name from cracknames if possible */ account_name = talloc_strdup(mem_ctx, user_info->client.account_name); if (account_name == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } switch (info1.status) { case DRSUAPI_DS_NAME_STATUS_OK: case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: domain = talloc_strdup(tmp_ctx, info1.result_name); if (domain == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } if (domain[strlen_m(domain)-1] == '\\') { domain[strlen_m(domain)-1] = 0; } break; case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: /* the domain is unknown - use the default domain */ domain = talloc_strdup(tmp_ctx, default_domain); break; case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: DEBUG(2,("map_user_info: Cracknames of domain '%s' -> NOT_UNIQUE\n", domain_name)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: DEBUG(2,("map_user_info: Cracknames of domain '%s' -> RESOLVE_ERROR\n", domain_name)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; default: DEBUG(2,("map_user_info: Cracknames of account '%s' -> unknown error %u\n", domain_name, info1.status)); talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; } /* domain and account_name are filled in above */ } *user_info_mapped = talloc_zero(mem_ctx, struct auth_usersupplied_info); if (!*user_info_mapped) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } if (!talloc_reference(*user_info_mapped, user_info)) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } **user_info_mapped = *user_info; (*user_info_mapped)->mapped_state = true; (*user_info_mapped)->mapped.domain_name = talloc_strdup(*user_info_mapped, domain); (*user_info_mapped)->mapped.account_name = talloc_strdup(*user_info_mapped, account_name); talloc_free(tmp_ctx); if (!(*user_info_mapped)->mapped.domain_name || !(*user_info_mapped)->mapped.account_name) { return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK; }
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 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 WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, uint32_t format_flags, enum drsuapi_DsNameFormat format_offered, enum drsuapi_DsNameFormat format_desired, const char *name, struct drsuapi_DsNameInfo1 *info1) { WERROR wret; krb5_error_code ret; krb5_principal principal; const krb5_data *component; 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\n", 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 (krb5_princ_size(smb_krb5_context->krb5_context, principal) < 2) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_OK; } component = krb5_princ_component(smb_krb5_context->krb5_context, principal, 0); service = (const char *)component->data; component = krb5_princ_component(smb_krb5_context->krb5_context, principal, 1); dns_name = (const char *)component->data; /* 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) { wret = WERR_OK; 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; } else if (namestatus != DRSUAPI_DS_NAME_STATUS_OK) { info1->status = namestatus; krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_OK; } /* reform principal */ new_princ = talloc_asprintf(mem_ctx, "%s/%s", new_service, dns_name); if (!new_princ) { 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); talloc_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; }
NTSTATUS crack_name_to_nt4_name(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, enum drsuapi_DsNameFormat format_offered, const char *name, const char **nt4_domain, const char **nt4_account) { WERROR werr; struct drsuapi_DsNameInfo1 info1; struct ldb_context *ldb; char *p; /* Handle anonymous bind */ if (!name || !*name) { *nt4_domain = ""; *nt4_account = ""; return NT_STATUS_OK; } ldb = samdb_connect(mem_ctx, ev_ctx, lp_ctx, system_session(lp_ctx), 0); if (ldb == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } werr = DsCrackNameOneName(ldb, mem_ctx, 0, format_offered, DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, name, &info1); if (!W_ERROR_IS_OK(werr)) { return werror_to_ntstatus(werr); } switch (info1.status) { case DRSUAPI_DS_NAME_STATUS_OK: break; case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: return NT_STATUS_NO_SUCH_USER; case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: default: return NT_STATUS_UNSUCCESSFUL; } *nt4_domain = talloc_strdup(mem_ctx, info1.result_name); if (*nt4_domain == NULL) { return NT_STATUS_NO_MEMORY; } p = strchr(*nt4_domain, '\\'); if (!p) { return NT_STATUS_INVALID_PARAMETER; } p[0] = '\0'; *nt4_account = talloc_strdup(mem_ctx, &p[1]); if (*nt4_account == NULL) { return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK; }