Example #1
0
/*
  lookup a SID for 1 name
*/
static NTSTATUS dcesrv_lsa_lookup_name(struct tevent_context *ev_ctx,
                                       struct loadparm_context *lp_ctx,
                                       struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
                                       const char *name, const char **authority_name,
                                       struct dom_sid **sid, enum lsa_SidType *rtype,
                                       uint32_t *rid)
{
    int ret, i;
    uint32_t atype;
    struct ldb_message **res;
    const char * const attrs[] = { "objectSid", "sAMAccountType", NULL};
    const char *p;
    const char *domain;
    const char *username;
    struct ldb_dn *domain_dn;
    struct dom_sid *domain_sid;
    NTSTATUS status;

    p = strchr_m(name, '\\');
    if (p != NULL) {
        domain = talloc_strndup(mem_ctx, name, p-name);
        if (!domain) {
            return NT_STATUS_NO_MEMORY;
        }
        username = p + 1;
    } else if (strchr_m(name, '@')) {
        status = crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username);
        if (!NT_STATUS_IS_OK(status)) {
            DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", name, nt_errstr(status)));
            return status;
        }
    } else {
        domain = NULL;
        username = name;
    }

    if (!domain) {
        /* Look up table of well known names */
        status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype);
        if (NT_STATUS_IS_OK(status)) {
            dom_sid_split_rid(NULL, *sid, NULL, rid);
            return NT_STATUS_OK;
        }

        if (username == NULL) {
            *authority_name = NAME_BUILTIN;
            *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN);
            *rtype = SID_NAME_DOMAIN;
            *rid = 0xFFFFFFFF;
            return NT_STATUS_OK;
        }

        if (strcasecmp_m(username, NAME_NT_AUTHORITY) == 0) {
            *authority_name = NAME_NT_AUTHORITY;
            *sid =  dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
            *rtype = SID_NAME_DOMAIN;
            dom_sid_split_rid(NULL, *sid, NULL, rid);
            return NT_STATUS_OK;
        }
        if (strcasecmp_m(username, NAME_BUILTIN) == 0) {
            *authority_name = NAME_BUILTIN;
            *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN);
            *rtype = SID_NAME_DOMAIN;
            *rid = 0xFFFFFFFF;
            return NT_STATUS_OK;
        }
        if (strcasecmp_m(username, state->domain_dns) == 0) {
            *authority_name = state->domain_name;
            *sid =  state->domain_sid;
            *rtype = SID_NAME_DOMAIN;
            *rid = 0xFFFFFFFF;
            return NT_STATUS_OK;
        }
        if (strcasecmp_m(username, state->domain_name) == 0) {
            *authority_name = state->domain_name;
            *sid =  state->domain_sid;
            *rtype = SID_NAME_DOMAIN;
            *rid = 0xFFFFFFFF;
            return NT_STATUS_OK;
        }

        /* Perhaps this is a well known user? */
        name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_NT_AUTHORITY, username);
        if (!name) {
            return NT_STATUS_NO_MEMORY;
        }
        status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
        if (NT_STATUS_IS_OK(status)) {
            return status;
        }

        /* Perhaps this is a BUILTIN user? */
        name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_BUILTIN, username);
        if (!name) {
            return NT_STATUS_NO_MEMORY;
        }
        status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
        if (NT_STATUS_IS_OK(status)) {
            return status;
        }

        /* OK, I give up - perhaps we need to assume the user is in our domain? */
        name = talloc_asprintf(mem_ctx, "%s\\%s", state->domain_name, username);
        if (!name) {
            return NT_STATUS_NO_MEMORY;
        }
        status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
        if (NT_STATUS_IS_OK(status)) {
            return status;
        }

        return STATUS_SOME_UNMAPPED;
    } else if (strcasecmp_m(domain, NAME_NT_AUTHORITY) == 0) {
        if (!*username) {
            *authority_name = NAME_NT_AUTHORITY;
            *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
            *rtype = SID_NAME_DOMAIN;
            dom_sid_split_rid(NULL, *sid, NULL, rid);
            return NT_STATUS_OK;
        }

        /* Look up table of well known names */
        status = lookup_well_known_names(mem_ctx, domain, username, authority_name,
                                         sid, rtype);
        if (NT_STATUS_IS_OK(status)) {
            dom_sid_split_rid(NULL, *sid, NULL, rid);
        }
        return status;
    } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) {
        *authority_name = NAME_BUILTIN;
        domain_dn = state->builtin_dn;
    } else if (strcasecmp_m(domain, state->domain_dns) == 0) {
        *authority_name = state->domain_name;
        domain_dn = state->domain_dn;
    } else if (strcasecmp_m(domain, state->domain_name) == 0) {
        *authority_name = state->domain_name;
        domain_dn = state->domain_dn;
    } else {
        /* Not local, need to ask winbind in future */
        return STATUS_SOME_UNMAPPED;
    }

    ret = gendb_search_dn(state->sam_ldb, mem_ctx, domain_dn, &res, attrs);
    if (ret == 1) {
        domain_sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
        if (domain_sid == NULL) {
            return NT_STATUS_INVALID_SID;
        }
    } else {
        return NT_STATUS_INVALID_SID;
    }

    if (!*username) {
        *sid = domain_sid;
        *rtype = SID_NAME_DOMAIN;
        *rid = 0xFFFFFFFF;
        return NT_STATUS_OK;
    }

    ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs,
                       "(&(sAMAccountName=%s)(objectSid=*))",
                       ldb_binary_encode_string(mem_ctx, username));
    if (ret == -1) {
        return NT_STATUS_INVALID_SID;
    }

    for (i=0; i < ret; i++) {
        *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
        if (*sid == NULL) {
            return NT_STATUS_INVALID_SID;
        }

        /* Check that this is in the domain */
        if (!dom_sid_in_domain(domain_sid, *sid)) {
            continue;
        }

        atype = samdb_result_uint(res[i], "sAMAccountType", 0);

        *rtype = ds_atype_map(atype);
        if (*rtype == SID_NAME_UNKNOWN) {
            return STATUS_SOME_UNMAPPED;
        }

        dom_sid_split_rid(NULL, *sid, NULL, rid);
        return NT_STATUS_OK;
    }

    /* need to check for an allocated sid */

    return NT_STATUS_INVALID_SID;
}
Example #2
0
/*
  samr_ChangePasswordUser
*/
NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
					TALLOC_CTX *mem_ctx,
					struct samr_ChangePasswordUser *r)
{
	struct dcesrv_handle *h;
	struct samr_account_state *a_state;
	struct ldb_context *sam_ctx;
	struct ldb_message **res;
	int ret;
	struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
	struct samr_Password *lm_pwd, *nt_pwd;
	NTSTATUS status = NT_STATUS_OK;
	const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };

	DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);

	a_state = h->data;

	/* basic sanity checking on parameters.  Do this before any database ops */
	if (!r->in.lm_present || !r->in.nt_present ||
	    !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
	    !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
		/* we should really handle a change with lm not
		   present */
		return NT_STATUS_INVALID_PARAMETER_MIX;
	}

	/* Connect to a SAMDB with system privileges for fetching the old pw
	 * hashes. */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
				dce_call->conn->dce_ctx->lp_ctx,
				system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	/* fetch the old hashes */
	ret = gendb_search_dn(sam_ctx, mem_ctx,
			      a_state->account_dn, &res, attrs);
	if (ret != 1) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	status = samdb_result_passwords(mem_ctx,
					dce_call->conn->dce_ctx->lp_ctx,
					res[0], &lm_pwd, &nt_pwd);
	if (!NT_STATUS_IS_OK(status) || !nt_pwd) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* decrypt and check the new lm hash */
	if (lm_pwd) {
		D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
		D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
		if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
			return NT_STATUS_WRONG_PASSWORD;
		}
	}

	/* decrypt and check the new nt hash */
	D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
	D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
	if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* The NT Cross is not required by Win2k3 R2, but if present
	   check the nt cross hash */
	if (r->in.cross1_present && r->in.nt_cross && lm_pwd) {
		D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
		if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
			return NT_STATUS_WRONG_PASSWORD;
		}
	}

	/* The LM Cross is not required by Win2k3 R2, but if present
	   check the lm cross hash */
	if (r->in.cross2_present && r->in.lm_cross && lm_pwd) {
		D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
		if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
			return NT_STATUS_WRONG_PASSWORD;
		}
	}

	/* Start a SAM with user privileges for the password change */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
				dce_call->conn->dce_ctx->lp_ctx,
				dce_call->conn->auth_state.session_info, 0);
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	/* Start transaction */
	ret = ldb_transaction_start(sam_ctx);
	if (ret != LDB_SUCCESS) {
		DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	/* Performs the password modification. We pass the old hashes read out
	 * from the database since they were already checked against the user-
	 * provided ones. */
	status = samdb_set_password(sam_ctx, mem_ctx,
				    a_state->account_dn,
				    a_state->domain_state->domain_dn,
				    NULL, &new_lmPwdHash, &new_ntPwdHash,
				    lm_pwd, nt_pwd, /* this is a user password change */
				    NULL,
				    NULL);
	if (!NT_STATUS_IS_OK(status)) {
		ldb_transaction_cancel(sam_ctx);
		return status;
	}

	/* And this confirms it in a transaction commit */
	ret = ldb_transaction_commit(sam_ctx);
	if (ret != LDB_SUCCESS) {
		DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
			 ldb_dn_get_linearized(a_state->account_dn),
			 ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	return NT_STATUS_OK;
}
static WERROR DsCrackNameOneFilter(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,
				   struct ldb_dn *name_dn, const char *name, 
				   const char *domain_filter, const char *result_filter, 
				   struct drsuapi_DsNameInfo1 *info1,
				   int scope, struct ldb_dn *search_dn)
{
	int ldb_ret;
	struct ldb_result *domain_res = NULL;
	const char * const *domain_attrs;
	const char * const *result_attrs;
	struct ldb_message **result_res = NULL;
	struct ldb_message *result = NULL;
	int i;
	char *p;
	struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);

	const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL};
	const char * const _result_attrs_null[] = { NULL };

	const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL};
	const char * const _result_attrs_canonical[] = { "canonicalName", NULL };

	const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
	const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL};

	const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
	const char * const _result_attrs_guid[] = { "objectGUID", NULL};

	const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL};
	const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL};

	const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL};
	const char * const _result_attrs_none[] = { NULL};

	/* here we need to set the attrs lists for domain and result lookups */
	switch (format_desired) {
	case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
	case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
		domain_attrs = _domain_attrs_1779;
		result_attrs = _result_attrs_null;
		break;
	case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
		domain_attrs = _domain_attrs_canonical;
		result_attrs = _result_attrs_canonical;
		break;
	case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT:
		domain_attrs = _domain_attrs_nt4;
		result_attrs = _result_attrs_nt4;
		break;
	case DRSUAPI_DS_NAME_FORMAT_GUID:		
		domain_attrs = _domain_attrs_guid;
		result_attrs = _result_attrs_guid;
		break;
	case DRSUAPI_DS_NAME_FORMAT_DISPLAY:		
		domain_attrs = _domain_attrs_display;
		result_attrs = _result_attrs_display;
		break;
	default:
		domain_attrs = _domain_attrs_none;
		result_attrs = _result_attrs_none;
		break;
	}

	if (domain_filter) {
		/* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
		ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
					     partitions_basedn,
					     LDB_SCOPE_ONELEVEL,
					     domain_attrs,
					     "%s", domain_filter);

		if (ldb_ret != LDB_SUCCESS) {
			DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
			info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
			return WERR_OK;
		}

		switch (domain_res->count) {
		case 1:
			break;
		case 0:
			info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
			return WERR_OK;
		default:
			info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
			return WERR_OK;
		}

		info1->dns_domain_name	= ldb_msg_find_attr_as_string(domain_res->msgs[0], "dnsRoot", NULL);
		W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
		info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
	} else {
		info1->dns_domain_name	= NULL;
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
	}

	if (result_filter) {
		int ret;
		struct ldb_result *res;
		uint32_t dsdb_flags = 0;
		struct ldb_dn *real_search_dn = NULL;
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;

		/*
		 * From 4.1.4.2.11 of MS-DRSR
		 * if DS_NAME_FLAG_GCVERIFY in flags then
		 * rt := select all O from all
		 * where attrValue in GetAttrVals(O, att, false)
		 * else
		 * rt := select all O from subtree DefaultNC()
		 * where attrValue in GetAttrVals(O, att, false)
		 * endif
		 * return rt
		 */
		if (format_flags & DRSUAPI_DS_NAME_FLAG_GCVERIFY ||
		    format_offered == DRSUAPI_DS_NAME_FORMAT_GUID)
		{
			dsdb_flags = DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
		} else if (domain_res) {
			if (!search_dn) {
				struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
				real_search_dn = tmp_dn;
			} else {
				real_search_dn = search_dn;
			}
		} else {
			real_search_dn = ldb_get_default_basedn(sam_ctx);
		}
		if (format_desired == DRSUAPI_DS_NAME_FORMAT_GUID){
			 dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
		}
		/* search with the 'phantom root' flag */
		ret = dsdb_search(sam_ctx, mem_ctx, &res,
				  real_search_dn,
				  scope,
				  result_attrs,
				  dsdb_flags,
				  "%s", result_filter);
		if (ret != LDB_SUCCESS) {
			DEBUG(2, ("DsCrackNameOneFilter search from '%s' with flags 0x%08x failed: %s\n",
				  ldb_dn_get_linearized(real_search_dn),
				  dsdb_flags,
				  ldb_errstring(sam_ctx)));
			info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
			return WERR_OK;
		}

		ldb_ret = res->count;
		result_res = res->msgs;
	} else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
		ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
					  result_attrs);
	} else if (domain_res) {
		name_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
		ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
					  result_attrs);
	} else {
		/* Can't happen */
		DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not available: This can't happen...\n"));
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		return WERR_OK;
	}

	switch (ldb_ret) {
	case 1:
		result = result_res[0];
		break;
	case 0:
		switch (format_offered) {
		case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: 
			return DsCrackNameSPNAlias(sam_ctx, mem_ctx, 
						   smb_krb5_context, 
						   format_flags, format_offered, format_desired,
						   name, info1);

		case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
			return DsCrackNameUPN(sam_ctx, mem_ctx, smb_krb5_context, 
					      format_flags, format_offered, format_desired,
					      name, info1);
		default:
			break;
		}
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
		return WERR_OK;
	case -1:
		DEBUG(2, ("DsCrackNameOneFilter result search failed: %s\n", ldb_errstring(sam_ctx)));
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		return WERR_OK;
	default:
		switch (format_offered) {
		case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
		case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
		{
			const char *canonical_name = NULL; /* Not required, but we get warnings... */
			/* We may need to manually filter further */
			for (i = 0; i < ldb_ret; i++) {
				switch (format_offered) {
				case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
					canonical_name = ldb_dn_canonical_string(mem_ctx, result_res[i]->dn);
					break;
				case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
					canonical_name = ldb_dn_canonical_ex_string(mem_ctx, result_res[i]->dn);
					break;
				default:
					break;
				}
				if (strcasecmp_m(canonical_name, name) == 0) {
					result = result_res[i];
					break;
				}
			}
			if (!result) {
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
				return WERR_OK;
			}
		}
		/* FALL TROUGH */
		default:
			info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
			return WERR_OK;
		}
	}

	info1->dns_domain_name = ldb_dn_canonical_string(mem_ctx, result->dn);
	W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
	p = strchr(info1->dns_domain_name, '/');
	if (p) {
		p[0] = '\0';
	}

	/* here we can use result and domain_res[0] */
	switch (format_desired) {
	case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
		info1->result_name	= ldb_dn_alloc_linearized(mem_ctx, result->dn);
		W_ERROR_HAVE_NO_MEMORY(info1->result_name);

		info1->status		= DRSUAPI_DS_NAME_STATUS_OK;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
		info1->result_name	= ldb_msg_find_attr_as_string(result, "canonicalName", NULL);
		info1->status		= DRSUAPI_DS_NAME_STATUS_OK;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: {
		/* Not in the virtual ldb attribute */
		return DsCrackNameOneSyntactical(mem_ctx, 
						 DRSUAPI_DS_NAME_FORMAT_FQDN_1779, 
						 DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
						 result->dn, name, info1);
	}
	case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {

		const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid");
		const char *_acc = "", *_dom = "";
		if (sid == NULL) {
			info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
			return WERR_OK;
		}

		if (samdb_find_attribute(sam_ctx, result, "objectClass",
					 "domain")) {
			/* This can also find a DomainDNSZones entry,
			 * but it won't have the SID we just
			 * checked.  */
			ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
						     partitions_basedn,
						     LDB_SCOPE_ONELEVEL,
						     domain_attrs,
						     "(ncName=%s)", ldb_dn_get_linearized(result->dn));

			if (ldb_ret != LDB_SUCCESS) {
				DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
				info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
				return WERR_OK;
			}

			switch (domain_res->count) {
			case 1:
				break;
			case 0:
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
				return WERR_OK;
			default:
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
				return WERR_OK;
			}
			_dom = ldb_msg_find_attr_as_string(domain_res->msgs[0], "nETBIOSName", NULL);
			W_ERROR_HAVE_NO_MEMORY(_dom);
		} else {
			_acc = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
			if (!_acc) {
				info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
				return WERR_OK;
			}
			if (dom_sid_in_domain(dom_sid_parse_talloc(mem_ctx, SID_BUILTIN), sid)) {
				_dom = "BUILTIN";
			} else {
				const char *attrs[] = { NULL };
				struct ldb_result *domain_res2;
				struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid);
				if (!dom_sid) {
					return WERR_OK;
				}
				dom_sid->num_auths--;
				ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
							     NULL,
							     LDB_SCOPE_BASE,
							     attrs,
							     "(&(objectSid=%s)(objectClass=domain))", 
							     ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));

				if (ldb_ret != LDB_SUCCESS) {
					DEBUG(2, ("DsCrackNameOneFilter domain search failed: %s\n", ldb_errstring(sam_ctx)));
					info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
					return WERR_OK;
				}

				switch (domain_res->count) {
				case 1:
					break;
				case 0:
					info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
					return WERR_OK;
				default:
					info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
					return WERR_OK;
				}

				ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res2,
							     partitions_basedn,
							     LDB_SCOPE_ONELEVEL,
							     domain_attrs,
							     "(ncName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));

				if (ldb_ret != LDB_SUCCESS) {
					DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
					info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
					return WERR_OK;
				}

				switch (domain_res2->count) {
				case 1:
					break;
				case 0:
					info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
					return WERR_OK;
				default:
					info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
					return WERR_OK;
				}
				_dom = ldb_msg_find_attr_as_string(domain_res2->msgs[0], "nETBIOSName", NULL);
				W_ERROR_HAVE_NO_MEMORY(_dom);
			}
		}

		info1->result_name	= talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
		W_ERROR_HAVE_NO_MEMORY(info1->result_name);

		info1->status		= DRSUAPI_DS_NAME_STATUS_OK;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_GUID: {
		struct GUID guid;

		guid = samdb_result_guid(result, "objectGUID");

		info1->result_name	= GUID_string2(mem_ctx, &guid);
		W_ERROR_HAVE_NO_MEMORY(info1->result_name);

		info1->status		= DRSUAPI_DS_NAME_STATUS_OK;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
		info1->result_name	= ldb_msg_find_attr_as_string(result, "displayName", NULL);
		if (!info1->result_name) {
			info1->result_name	= ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL);
		} 
		if (!info1->result_name) {
			info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
		} else {
			info1->status = DRSUAPI_DS_NAME_STATUS_OK;
		}
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
		info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
		return WERR_OK;
	}
	case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN:	
	case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
		info1->dns_domain_name = NULL;
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		return WERR_OK;
	}
	default:
		info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
		return WERR_OK;
	}
}
Example #4
0
                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
            }

            talloc_free(req);

            if (ret != LDB_SUCCESS) {
                DEBUG(2, ("DsCrackNameOneFilter phantom root search failed: %s",
                          ldb_errstring(sam_ctx)));
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            ldb_ret = res->count;
            result_res = res->msgs;
        }
    } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
        ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
                                  result_attrs);
    } else if (domain_res) {
        name_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
        ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res,
                                  result_attrs);
    } else {
        /* Can't happen */
        DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not availible: This can't happen..."));
        info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
        return WERR_OK;
    }

    switch (ldb_ret) {
    case 1:
        result = result_res[0];
        break;
Example #5
0
/* 
  samr_ChangePasswordUser 
*/
NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, 
					TALLOC_CTX *mem_ctx,
					struct samr_ChangePasswordUser *r)
{
	struct dcesrv_handle *h;
	struct samr_account_state *a_state;
	struct ldb_context *sam_ctx;
	struct ldb_message **res, *msg;
	int ret;
	struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
	struct samr_Password *lm_pwd, *nt_pwd;
	NTSTATUS status = NT_STATUS_OK;
	const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };

	DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);

	a_state = h->data;

	/* basic sanity checking on parameters.  Do this before any database ops */
	if (!r->in.lm_present || !r->in.nt_present ||
	    !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
	    !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
		/* we should really handle a change with lm not
		   present */
		return NT_STATUS_INVALID_PARAMETER_MIX;
	}

	/* To change a password we need to open as system */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	ret = ldb_transaction_start(sam_ctx);
	if (ret) {
		DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	/* fetch the old hashes */
	ret = gendb_search_dn(sam_ctx, mem_ctx,
			      a_state->account_dn, &res, attrs);
	if (ret != 1) {
		ldb_transaction_cancel(sam_ctx);
		return NT_STATUS_WRONG_PASSWORD;
	}
	msg = res[0];

	status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
					msg, &lm_pwd, &nt_pwd);
	if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
		ldb_transaction_cancel(sam_ctx);
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* decrypt and check the new lm hash */
	D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
	D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
	if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
		ldb_transaction_cancel(sam_ctx);
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* decrypt and check the new nt hash */
	D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
	D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
	if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
		ldb_transaction_cancel(sam_ctx);
		return NT_STATUS_WRONG_PASSWORD;
	}
	
	/* The NT Cross is not required by Win2k3 R2, but if present
	   check the nt cross hash */
	if (r->in.cross1_present && r->in.nt_cross) {
		D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
		if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
			ldb_transaction_cancel(sam_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}
	}

	/* The LM Cross is not required by Win2k3 R2, but if present
	   check the lm cross hash */
	if (r->in.cross2_present && r->in.lm_cross) {
		D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
		if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
			ldb_transaction_cancel(sam_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}
	}

	msg = ldb_msg_new(mem_ctx);
	if (msg == NULL) {
		ldb_transaction_cancel(sam_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	msg->dn = ldb_dn_copy(msg, a_state->account_dn);
	if (!msg->dn) {
		ldb_transaction_cancel(sam_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	/* setup password modify mods on the user DN specified.  This may fail
	 * due to password policies.  */
	status = samdb_set_password(sam_ctx, mem_ctx,
				    a_state->account_dn, a_state->domain_state->domain_dn,
				    msg, NULL, &new_lmPwdHash, &new_ntPwdHash, 
				    true, /* this is a user password change */
				    NULL,
				    NULL);
	if (!NT_STATUS_IS_OK(status)) {
		ldb_transaction_cancel(sam_ctx);
		return status;
	}

	/* The above call only setup the modifications, this actually
	 * makes the write to the database. */
	ret = samdb_replace(sam_ctx, mem_ctx, msg);
	if (ret != 0) {
		DEBUG(2,("Failed to modify record to change password on %s: %s\n",
			 ldb_dn_get_linearized(a_state->account_dn),
			 ldb_errstring(sam_ctx)));
		ldb_transaction_cancel(sam_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* And this confirms it in a transaction commit */
	ret = ldb_transaction_commit(sam_ctx);
	if (ret != 0) {
		DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
			 ldb_dn_get_linearized(a_state->account_dn),
			 ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	return NT_STATUS_OK;
}