Esempio n. 1
0
/*
  lsa_LookupSids3

  Identical to LookupSids2, but doesn't take a policy handle

*/
NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
                                TALLOC_CTX *mem_ctx,
                                struct lsa_LookupSids3 *r)
{
    struct lsa_LookupSids2 r2;
    struct lsa_OpenPolicy2 pol;
    NTSTATUS status;
    struct dcesrv_handle *h;

    ZERO_STRUCT(r2);

    /* No policy handle on the wire, so make one up here */
    r2.in.handle = talloc(mem_ctx, struct policy_handle);
    if (!r2.in.handle) {
        return NT_STATUS_NO_MEMORY;
    }

    pol.out.handle = r2.in.handle;
    pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
    pol.in.attr = NULL;
    pol.in.system_name = NULL;
    status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol);
    if (!NT_STATUS_IS_OK(status)) {
        return status;
    }

    /* ensure this handle goes away at the end of this call */
    DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY);
    talloc_steal(mem_ctx, h);

    r2.in.sids     = r->in.sids;
    r2.in.names    = r->in.names;
    r2.in.level    = r->in.level;
    r2.in.count    = r->in.count;
    r2.in.lookup_options = r->in.lookup_options;
    r2.in.client_revision = r->in.client_revision;
    r2.out.count   = r->out.count;
    r2.out.names   = r->out.names;
    r2.out.domains = r->out.domains;

    status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);

    r->out.domains = r2.out.domains;
    r->out.names   = r2.out.names;
    r->out.count   = r2.out.count;

    return status;
}
/*
  lsa_LookupNames3
*/
NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call,
				 TALLOC_CTX *mem_ctx,
				 struct lsa_LookupNames3 *r)
{
	enum dcerpc_transport_t transport =
		dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
	struct lsa_policy_state *policy_state;
	struct dcesrv_handle *policy_handle;

	if (transport != NCACN_NP && transport != NCALRPC) {
		DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
	}

	DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);

	policy_state = policy_handle->data;

	return dcesrv_lsa_LookupNames_common(dce_call,
					     mem_ctx,
					     policy_state,
					     r);
}
Esempio n. 3
0
/*
  lsa_LookupNames2
*/
NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call,
                                 TALLOC_CTX *mem_ctx,
                                 struct lsa_LookupNames2 *r)
{
    struct lsa_policy_state *state;
    struct dcesrv_handle *h;
    int i;
    struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
    struct lsa_RefDomainList *domains;

    *r->out.domains = NULL;

    DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);

    if (r->in.level < LSA_LOOKUP_NAMES_ALL ||
            r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) {
        return NT_STATUS_INVALID_PARAMETER;
    }

    state = h->data;

    domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
    if (domains == NULL) {
        return NT_STATUS_NO_MEMORY;
    }
    *r->out.domains = domains;

    r->out.sids = talloc_zero(mem_ctx,  struct lsa_TransSidArray2);
    if (r->out.sids == NULL) {
        return NT_STATUS_NO_MEMORY;
    }

    *r->out.count = 0;

    r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid2,
                                     r->in.num_names);
    if (r->out.sids->sids == NULL) {
        return NT_STATUS_NO_MEMORY;
    }

    for (i=0; i<r->in.num_names; i++) {
        const char *name = r->in.names[i].string;
        const char *authority_name;
        struct dom_sid *sid;
        uint32_t rtype, sid_index, rid=0;
        NTSTATUS status2;

        r->out.sids->count++;

        r->out.sids->sids[i].sid_type    = SID_NAME_UNKNOWN;
        /* MS-LSAT 3.1.4.7 - rid zero is considered equivalent
           to sid NULL - so we should return 0 rid for
           unmapped entries */
        r->out.sids->sids[i].rid         = 0;
        r->out.sids->sids[i].sid_index   = 0xFFFFFFFF;
        r->out.sids->sids[i].unknown     = 0;

        status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, state, mem_ctx, name,
                                         &authority_name, &sid, &rtype, &rid);
        if (!NT_STATUS_IS_OK(status2)) {
            continue;
        }

        status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, authority_name,
                                            sid, domains, &sid_index);
        if (!NT_STATUS_IS_OK(status2)) {
            continue;
        }

        r->out.sids->sids[i].sid_type    = rtype;
        r->out.sids->sids[i].rid         = rid;
        r->out.sids->sids[i].sid_index   = sid_index;
        r->out.sids->sids[i].unknown     = 0;

        (*r->out.count)++;
    }

    if (*r->out.count == 0) {
        return NT_STATUS_NONE_MAPPED;
    }
    if (*r->out.count != r->in.num_names) {
        return STATUS_SOME_UNMAPPED;
    }

    return NT_STATUS_OK;
}
Esempio n. 4
0
/*
  lsa_LookupNames3
*/
NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call,
                                 TALLOC_CTX *mem_ctx,
                                 struct lsa_LookupNames3 *r)
{
    struct lsa_policy_state *policy_state;
    struct dcesrv_handle *policy_handle;
    int i;
    struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
    struct lsa_RefDomainList *domains;

    DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);

    if (r->in.level < LSA_LOOKUP_NAMES_ALL ||
            r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) {
        return NT_STATUS_INVALID_PARAMETER;
    }

    policy_state = policy_handle->data;

    *r->out.domains = NULL;

    domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
    if (domains == NULL) {
        return NT_STATUS_NO_MEMORY;
    }
    *r->out.domains = domains;

    r->out.sids = talloc_zero(mem_ctx,  struct lsa_TransSidArray3);
    if (r->out.sids == NULL) {
        return NT_STATUS_NO_MEMORY;
    }

    *r->out.count = 0;

    r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid3,
                                     r->in.num_names);
    if (r->out.sids->sids == NULL) {
        return NT_STATUS_NO_MEMORY;
    }

    for (i=0; i<r->in.num_names; i++) {
        const char *name = r->in.names[i].string;
        const char *authority_name;
        struct dom_sid *sid;
        uint32_t sid_index, rid;
        enum lsa_SidType rtype;
        NTSTATUS status2;

        r->out.sids->count++;

        r->out.sids->sids[i].sid_type    = SID_NAME_UNKNOWN;
        r->out.sids->sids[i].sid         = NULL;
        r->out.sids->sids[i].sid_index   = 0xFFFFFFFF;
        r->out.sids->sids[i].flags       = 0;

        status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, policy_state, mem_ctx, name,
                                         &authority_name, &sid, &rtype, &rid);
        if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) {
            continue;
        }

        status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, rtype, authority_name,
                                            sid, domains, &sid_index);
        if (!NT_STATUS_IS_OK(status2)) {
            continue;
        }

        r->out.sids->sids[i].sid_type    = rtype;
        r->out.sids->sids[i].sid         = sid;
        r->out.sids->sids[i].sid_index   = sid_index;
        r->out.sids->sids[i].flags       = 0;

        (*r->out.count)++;
    }

    if (*r->out.count == 0) {
        return NT_STATUS_NONE_MAPPED;
    }
    if (*r->out.count != r->in.num_names) {
        return STATUS_SOME_UNMAPPED;
    }

    return NT_STATUS_OK;
}
Esempio n. 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;
	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;
}
Esempio n. 6
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;
}