wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# server subsystem
|
||||
|
||||
#######################
|
||||
# Start SUBSYSTEM WINBIND
|
||||
[MODULE::WINBIND]
|
||||
INIT_FUNCTION = server_service_winbind_init
|
||||
SUBSYSTEM = service
|
||||
PRIVATE_PROTO_HEADER = wb_proto.h
|
||||
OBJ_FILES = \
|
||||
wb_server.o \
|
||||
wb_irpc.o \
|
||||
wb_samba3_protocol.o \
|
||||
wb_samba3_cmd.o \
|
||||
wb_init_domain.o \
|
||||
wb_dom_info.o \
|
||||
wb_dom_info_trusted.o \
|
||||
wb_sid2domain.o \
|
||||
wb_connect_lsa.o \
|
||||
wb_connect_sam.o \
|
||||
wb_cmd_lookupname.o \
|
||||
wb_cmd_lookupsid.o \
|
||||
wb_cmd_getdcname.o \
|
||||
wb_cmd_userdomgroups.o \
|
||||
wb_cmd_usersids.o \
|
||||
wb_cmd_list_trustdom.o \
|
||||
wb_pam_auth.o \
|
||||
wb_sam_logon.o
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
WB_HELPER \
|
||||
NDR_WINBIND \
|
||||
process_model \
|
||||
RPC_NDR_LSA \
|
||||
RPC_NDR_SAMR \
|
||||
PAM_ERRORS \
|
||||
LIBCLI_LDAP
|
||||
# End SUBSYSTEM WINBIND
|
||||
#######################
|
||||
|
||||
################################################
|
||||
# Start SUBYSTEM WB_HELPER
|
||||
[SUBSYSTEM::WB_HELPER]
|
||||
PRIVATE_PROTO_HEADER = wb_helper.h
|
||||
OBJ_FILES = \
|
||||
wb_async_helpers.o
|
||||
PUBLIC_DEPENDENCIES = RPC_NDR_LSA RPC_NDR_SAMR
|
||||
# End SUBSYSTEM WB_HELPER
|
||||
################################################
|
||||
@@ -0,0 +1,755 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
a composite API for finding a DC and its name
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_async_helpers.h"
|
||||
|
||||
#include "lib/messaging/irpc.h"
|
||||
#include "librpc/gen_ndr/irpc.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "libcli/auth/libcli_auth.h"
|
||||
#include "librpc/gen_ndr/ndr_netlogon_c.h"
|
||||
#include "librpc/gen_ndr/ndr_lsa_c.h"
|
||||
#include "librpc/gen_ndr/ndr_samr_c.h"
|
||||
|
||||
#include "winbind/wb_helper.h"
|
||||
|
||||
struct get_schannel_creds_state {
|
||||
struct cli_credentials *wks_creds;
|
||||
struct dcerpc_pipe *p;
|
||||
struct netr_ServerReqChallenge r;
|
||||
|
||||
struct creds_CredentialState *creds_state;
|
||||
struct netr_Credential netr_cred;
|
||||
uint32_t negotiate_flags;
|
||||
struct netr_ServerAuthenticate2 a;
|
||||
};
|
||||
|
||||
static void get_schannel_creds_recv_anonbind(struct composite_context *creq);
|
||||
static void get_schannel_creds_recv_auth(struct rpc_request *req);
|
||||
static void get_schannel_creds_recv_chal(struct rpc_request *req);
|
||||
static void get_schannel_creds_recv_pipe(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_get_schannel_creds_send(TALLOC_CTX *mem_ctx,
|
||||
struct cli_credentials *wks_creds,
|
||||
struct smbcli_tree *tree,
|
||||
struct event_context *ev)
|
||||
{
|
||||
struct composite_context *c, *creq;
|
||||
struct get_schannel_creds_state *state;
|
||||
|
||||
c = talloc_zero(mem_ctx, struct composite_context);
|
||||
if (c == NULL) return NULL;
|
||||
|
||||
state = talloc(c, struct get_schannel_creds_state);
|
||||
if (state == NULL) {
|
||||
c->status = NT_STATUS_NO_MEMORY;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
c->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
c->private_data = state;
|
||||
c->event_ctx = ev;
|
||||
|
||||
state->wks_creds = wks_creds;
|
||||
|
||||
state->p = dcerpc_pipe_init(state, ev);
|
||||
if (state->p == NULL) {
|
||||
c->status = NT_STATUS_NO_MEMORY;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
creq = dcerpc_pipe_open_smb_send(state->p->conn, tree, "\\netlogon");
|
||||
if (creq == NULL) {
|
||||
c->status = NT_STATUS_NO_MEMORY;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
creq->async.fn = get_schannel_creds_recv_pipe;
|
||||
creq->async.private_data = c;
|
||||
|
||||
return c;
|
||||
|
||||
failed:
|
||||
composite_error(c, c->status);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void get_schannel_creds_recv_pipe(struct composite_context *creq)
|
||||
{
|
||||
struct composite_context *c =
|
||||
talloc_get_type(creq->async.private_data,
|
||||
struct composite_context);
|
||||
struct get_schannel_creds_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct get_schannel_creds_state);
|
||||
|
||||
c->status = dcerpc_pipe_open_smb_recv(creq);
|
||||
if (!composite_is_ok(c)) return;
|
||||
|
||||
creq = dcerpc_bind_auth_none_send(state, state->p,
|
||||
&dcerpc_table_netlogon);
|
||||
composite_continue(c, creq, get_schannel_creds_recv_anonbind, c);
|
||||
}
|
||||
|
||||
static void get_schannel_creds_recv_anonbind(struct composite_context *creq)
|
||||
{
|
||||
struct composite_context *c =
|
||||
talloc_get_type(creq->async.private_data,
|
||||
struct composite_context);
|
||||
struct get_schannel_creds_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct get_schannel_creds_state);
|
||||
struct rpc_request *req;
|
||||
|
||||
c->status = dcerpc_bind_auth_none_recv(creq);
|
||||
if (!composite_is_ok(c)) return;
|
||||
|
||||
state->r.in.computer_name =
|
||||
cli_credentials_get_workstation(state->wks_creds);
|
||||
state->r.in.server_name =
|
||||
talloc_asprintf(state, "\\\\%s",
|
||||
dcerpc_server_name(state->p));
|
||||
if (composite_nomem(state->r.in.server_name, c)) return;
|
||||
|
||||
state->r.in.credentials = talloc(state, struct netr_Credential);
|
||||
if (composite_nomem(state->r.in.credentials, c)) return;
|
||||
|
||||
state->r.out.credentials = talloc(state, struct netr_Credential);
|
||||
if (composite_nomem(state->r.out.credentials, c)) return;
|
||||
|
||||
generate_random_buffer(state->r.in.credentials->data,
|
||||
sizeof(state->r.in.credentials->data));
|
||||
|
||||
req = dcerpc_netr_ServerReqChallenge_send(state->p, state, &state->r);
|
||||
composite_continue_rpc(c, req, get_schannel_creds_recv_chal, c);
|
||||
}
|
||||
|
||||
static void get_schannel_creds_recv_chal(struct rpc_request *req)
|
||||
{
|
||||
struct composite_context *c =
|
||||
talloc_get_type(req->async.private,
|
||||
struct composite_context);
|
||||
struct get_schannel_creds_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct get_schannel_creds_state);
|
||||
const struct samr_Password *mach_pwd;
|
||||
|
||||
c->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(c)) return;
|
||||
c->status = state->r.out.result;
|
||||
if (!composite_is_ok(c)) return;
|
||||
|
||||
state->creds_state = talloc(state, struct creds_CredentialState);
|
||||
if (composite_nomem(state->creds_state, c)) return;
|
||||
|
||||
mach_pwd = cli_credentials_get_nt_hash(state->wks_creds, state);
|
||||
if (composite_nomem(mach_pwd, c)) return;
|
||||
|
||||
state->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
|
||||
|
||||
creds_client_init(state->creds_state, state->r.in.credentials,
|
||||
state->r.out.credentials, mach_pwd,
|
||||
&state->netr_cred, state->negotiate_flags);
|
||||
|
||||
state->a.in.server_name =
|
||||
talloc_reference(state, state->r.in.server_name);
|
||||
state->a.in.account_name =
|
||||
cli_credentials_get_username(state->wks_creds);
|
||||
state->a.in.secure_channel_type =
|
||||
cli_credentials_get_secure_channel_type(state->wks_creds);
|
||||
state->a.in.computer_name =
|
||||
cli_credentials_get_workstation(state->wks_creds);
|
||||
state->a.in.negotiate_flags = &state->negotiate_flags;
|
||||
state->a.out.negotiate_flags = &state->negotiate_flags;
|
||||
state->a.in.credentials = &state->netr_cred;
|
||||
state->a.out.credentials = &state->netr_cred;
|
||||
|
||||
req = dcerpc_netr_ServerAuthenticate2_send(state->p, state, &state->a);
|
||||
composite_continue_rpc(c, req, get_schannel_creds_recv_auth, c);
|
||||
}
|
||||
|
||||
static void get_schannel_creds_recv_auth(struct rpc_request *req)
|
||||
{
|
||||
struct composite_context *c =
|
||||
talloc_get_type(req->async.private,
|
||||
struct composite_context);
|
||||
struct get_schannel_creds_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct get_schannel_creds_state);
|
||||
|
||||
c->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(c)) return;
|
||||
c->status = state->a.out.result;
|
||||
if (!composite_is_ok(c)) return;
|
||||
|
||||
if (!creds_client_check(state->creds_state,
|
||||
state->a.out.credentials)) {
|
||||
DEBUG(5, ("Server got us invalid creds\n"));
|
||||
composite_error(c, NT_STATUS_UNSUCCESSFUL);
|
||||
return;
|
||||
}
|
||||
|
||||
cli_credentials_set_netlogon_creds(state->wks_creds,
|
||||
state->creds_state);
|
||||
|
||||
composite_done(c);
|
||||
}
|
||||
|
||||
NTSTATUS wb_get_schannel_creds_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct dcerpc_pipe **netlogon_pipe)
|
||||
{
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct get_schannel_creds_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct get_schannel_creds_state);
|
||||
*netlogon_pipe = talloc_steal(mem_ctx, state->p);
|
||||
}
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_get_schannel_creds(TALLOC_CTX *mem_ctx,
|
||||
struct cli_credentials *wks_creds,
|
||||
struct smbcli_tree *tree,
|
||||
struct event_context *event_ctx,
|
||||
struct dcerpc_pipe **netlogon_pipe)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_get_schannel_creds_send(mem_ctx, wks_creds, tree,
|
||||
event_ctx);
|
||||
return wb_get_schannel_creds_recv(c, mem_ctx, netlogon_pipe);
|
||||
}
|
||||
|
||||
struct lsa_lookupsids_state {
|
||||
struct composite_context *ctx;
|
||||
int num_sids;
|
||||
struct lsa_LookupSids r;
|
||||
struct lsa_SidArray sids;
|
||||
struct lsa_TransNameArray names;
|
||||
uint32_t count;
|
||||
struct wb_sid_object **result;
|
||||
};
|
||||
|
||||
static void lsa_lookupsids_recv_names(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_lsa_lookupsids_send(TALLOC_CTX *mem_ctx,
|
||||
struct dcerpc_pipe *lsa_pipe,
|
||||
struct policy_handle *handle,
|
||||
int num_sids,
|
||||
const struct dom_sid **sids)
|
||||
{
|
||||
struct composite_context *result;
|
||||
struct rpc_request *req;
|
||||
struct lsa_lookupsids_state *state;
|
||||
int i;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = lsa_pipe->conn->event_ctx;
|
||||
|
||||
state = talloc(result, struct lsa_lookupsids_state);
|
||||
if (state == NULL) goto failed;
|
||||
result->private_data = state;
|
||||
state->ctx = result;
|
||||
|
||||
state->sids.num_sids = num_sids;
|
||||
state->sids.sids = talloc_array(state, struct lsa_SidPtr, num_sids);
|
||||
if (state->sids.sids == NULL) goto failed;
|
||||
|
||||
for (i=0; i<num_sids; i++) {
|
||||
state->sids.sids[i].sid = dom_sid_dup(state->sids.sids,
|
||||
sids[i]);
|
||||
if (state->sids.sids[i].sid == NULL) goto failed;
|
||||
}
|
||||
|
||||
state->count = 0;
|
||||
state->num_sids = num_sids;
|
||||
state->names.count = 0;
|
||||
state->names.names = NULL;
|
||||
|
||||
state->r.in.handle = handle;
|
||||
state->r.in.sids = &state->sids;
|
||||
state->r.in.names = &state->names;
|
||||
state->r.in.level = 1;
|
||||
state->r.in.count = &state->count;
|
||||
state->r.out.names = &state->names;
|
||||
state->r.out.count = &state->count;
|
||||
|
||||
req = dcerpc_lsa_LookupSids_send(lsa_pipe, state, &state->r);
|
||||
if (req == NULL) goto failed;
|
||||
|
||||
req->async.callback = lsa_lookupsids_recv_names;
|
||||
req->async.private = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void lsa_lookupsids_recv_names(struct rpc_request *req)
|
||||
{
|
||||
struct lsa_lookupsids_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct lsa_lookupsids_state);
|
||||
int i;
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->r.out.result;
|
||||
if (!NT_STATUS_IS_OK(state->ctx->status) &&
|
||||
!NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
|
||||
composite_error(state->ctx, state->ctx->status);
|
||||
return;
|
||||
}
|
||||
|
||||
state->result = talloc_array(state, struct wb_sid_object *,
|
||||
state->num_sids);
|
||||
if (composite_nomem(state->result, state->ctx)) return;
|
||||
|
||||
for (i=0; i<state->num_sids; i++) {
|
||||
struct lsa_TranslatedName *name =
|
||||
&state->r.out.names->names[i];
|
||||
struct lsa_DomainInfo *dom;
|
||||
|
||||
state->result[i] = talloc_zero(state->result,
|
||||
struct wb_sid_object);
|
||||
if (composite_nomem(state->result[i], state->ctx)) return;
|
||||
|
||||
state->result[i]->type = name->sid_type;
|
||||
if (state->result[i]->type == SID_NAME_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name->sid_index >= state->r.out.domains->count) {
|
||||
composite_error(state->ctx,
|
||||
NT_STATUS_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
dom = &state->r.out.domains->domains[name->sid_index];
|
||||
state->result[i]->domain = talloc_reference(state->result[i],
|
||||
dom->name.string);
|
||||
if ((name->sid_type == SID_NAME_DOMAIN) ||
|
||||
(name->name.string == NULL)) {
|
||||
state->result[i]->name =
|
||||
talloc_strdup(state->result[i], "");
|
||||
} else {
|
||||
state->result[i]->name =
|
||||
talloc_steal(state->result[i],
|
||||
name->name.string);
|
||||
}
|
||||
|
||||
if (composite_nomem(state->result[i]->name, state->ctx)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_lsa_lookupsids_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct wb_sid_object ***names)
|
||||
{
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct lsa_lookupsids_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct lsa_lookupsids_state);
|
||||
*names = talloc_steal(mem_ctx, state->result);
|
||||
}
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_lsa_lookupsids(TALLOC_CTX *mem_ctx,
|
||||
struct dcerpc_pipe *lsa_pipe,
|
||||
struct policy_handle *handle,
|
||||
int num_sids, const struct dom_sid **sids,
|
||||
struct wb_sid_object ***names)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_lsa_lookupsids_send(mem_ctx, lsa_pipe, handle,
|
||||
num_sids, sids);
|
||||
return wb_lsa_lookupnames_recv(c, mem_ctx, names);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct lsa_lookupnames_state {
|
||||
struct composite_context *ctx;
|
||||
uint32_t num_names;
|
||||
struct lsa_LookupNames r;
|
||||
struct lsa_TransSidArray sids;
|
||||
uint32_t count;
|
||||
struct wb_sid_object **result;
|
||||
};
|
||||
|
||||
static void lsa_lookupnames_recv_sids(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_lsa_lookupnames_send(TALLOC_CTX *mem_ctx,
|
||||
struct dcerpc_pipe *lsa_pipe,
|
||||
struct policy_handle *handle,
|
||||
int num_names,
|
||||
const char **names)
|
||||
{
|
||||
struct composite_context *result;
|
||||
struct rpc_request *req;
|
||||
struct lsa_lookupnames_state *state;
|
||||
|
||||
struct lsa_String *lsa_names;
|
||||
int i;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = lsa_pipe->conn->event_ctx;
|
||||
|
||||
state = talloc(result, struct lsa_lookupnames_state);
|
||||
if (state == NULL) goto failed;
|
||||
result->private_data = state;
|
||||
state->ctx = result;
|
||||
|
||||
state->sids.count = 0;
|
||||
state->sids.sids = NULL;
|
||||
state->num_names = num_names;
|
||||
state->count = 0;
|
||||
|
||||
lsa_names = talloc_array(state, struct lsa_String, num_names);
|
||||
if (lsa_names == NULL) goto failed;
|
||||
|
||||
for (i=0; i<num_names; i++) {
|
||||
lsa_names[i].string = names[i];
|
||||
}
|
||||
|
||||
state->r.in.handle = handle;
|
||||
state->r.in.num_names = num_names;
|
||||
state->r.in.names = lsa_names;
|
||||
state->r.in.sids = &state->sids;
|
||||
state->r.in.level = 1;
|
||||
state->r.in.count = &state->count;
|
||||
state->r.out.count = &state->count;
|
||||
state->r.out.sids = &state->sids;
|
||||
|
||||
req = dcerpc_lsa_LookupNames_send(lsa_pipe, state, &state->r);
|
||||
if (req == NULL) goto failed;
|
||||
|
||||
req->async.callback = lsa_lookupnames_recv_sids;
|
||||
req->async.private = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void lsa_lookupnames_recv_sids(struct rpc_request *req)
|
||||
{
|
||||
struct lsa_lookupnames_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct lsa_lookupnames_state);
|
||||
int i;
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->r.out.result;
|
||||
if (!NT_STATUS_IS_OK(state->ctx->status) &&
|
||||
!NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
|
||||
composite_error(state->ctx, state->ctx->status);
|
||||
return;
|
||||
}
|
||||
|
||||
state->result = talloc_array(state, struct wb_sid_object *,
|
||||
state->num_names);
|
||||
if (composite_nomem(state->result, state->ctx)) return;
|
||||
|
||||
for (i=0; i<state->num_names; i++) {
|
||||
struct lsa_TranslatedSid *sid = &state->r.out.sids->sids[i];
|
||||
struct lsa_DomainInfo *dom;
|
||||
|
||||
state->result[i] = talloc_zero(state->result,
|
||||
struct wb_sid_object);
|
||||
if (composite_nomem(state->result[i], state->ctx)) return;
|
||||
|
||||
state->result[i]->type = sid->sid_type;
|
||||
if (state->result[i]->type == SID_NAME_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sid->sid_index >= state->r.out.domains->count) {
|
||||
composite_error(state->ctx,
|
||||
NT_STATUS_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
dom = &state->r.out.domains->domains[sid->sid_index];
|
||||
|
||||
state->result[i]->sid = dom_sid_add_rid(state->result[i],
|
||||
dom->sid, sid->rid);
|
||||
}
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_lsa_lookupnames_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct wb_sid_object ***sids)
|
||||
{
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct lsa_lookupnames_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct lsa_lookupnames_state);
|
||||
*sids = talloc_steal(mem_ctx, state->result);
|
||||
}
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_lsa_lookupnames(TALLOC_CTX *mem_ctx,
|
||||
struct dcerpc_pipe *lsa_pipe,
|
||||
struct policy_handle *handle,
|
||||
int num_names, const char **names,
|
||||
struct wb_sid_object ***sids)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_lsa_lookupnames_send(mem_ctx, lsa_pipe, handle,
|
||||
num_names, names);
|
||||
return wb_lsa_lookupnames_recv(c, mem_ctx, sids);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
struct cmd_checkmachacc_state {
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_call *call;
|
||||
struct wbsrv_domain *domain;
|
||||
};
|
||||
|
||||
static void cmd_checkmachacc_recv_init(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_cmd_checkmachacc_send(struct wbsrv_call *call)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct cmd_checkmachacc_state *state;
|
||||
struct wbsrv_service *service = call->wbconn->listen_socket->service;
|
||||
|
||||
result = talloc(call, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = call->event_ctx;
|
||||
|
||||
state = talloc(result, struct cmd_checkmachacc_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
state->call = call;
|
||||
|
||||
state->domain = service->domains;
|
||||
|
||||
ctx = wb_init_domain_send(service, state->domain);
|
||||
if (ctx == NULL) goto failed;
|
||||
ctx->async.fn = cmd_checkmachacc_recv_init;
|
||||
ctx->async.private_data = state;
|
||||
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cmd_checkmachacc_recv_init(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_checkmachacc_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_checkmachacc_state);
|
||||
|
||||
state->ctx->status = wb_init_domain_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_checkmachacc_recv(struct composite_context *c)
|
||||
{
|
||||
NTSTATUS status = composite_wait(c);
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_checkmachacc(struct wbsrv_call *call)
|
||||
{
|
||||
struct composite_context *c = wb_cmd_checkmachacc_send(call);
|
||||
return wb_cmd_checkmachacc_recv(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct samr_getuserdomgroups_state {
|
||||
struct composite_context *ctx;
|
||||
struct dcerpc_pipe *samr_pipe;
|
||||
|
||||
int num_rids;
|
||||
uint32_t *rids;
|
||||
|
||||
struct policy_handle *user_handle;
|
||||
struct samr_OpenUser o;
|
||||
struct samr_GetGroupsForUser g;
|
||||
struct samr_Close c;
|
||||
};
|
||||
|
||||
static void samr_usergroups_recv_open(struct rpc_request *req);
|
||||
static void samr_usergroups_recv_groups(struct rpc_request *req);
|
||||
static void samr_usergroups_recv_close(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_samr_userdomgroups_send(TALLOC_CTX *mem_ctx,
|
||||
struct dcerpc_pipe *samr_pipe,
|
||||
struct policy_handle *domain_handle,
|
||||
uint32_t rid)
|
||||
{
|
||||
struct composite_context *result;
|
||||
struct rpc_request *req;
|
||||
struct samr_getuserdomgroups_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = samr_pipe->conn->event_ctx;
|
||||
|
||||
state = talloc(result, struct samr_getuserdomgroups_state);
|
||||
if (state == NULL) goto failed;
|
||||
result->private_data = state;
|
||||
state->ctx = result;
|
||||
|
||||
state->samr_pipe = samr_pipe;
|
||||
|
||||
state->user_handle = talloc(state, struct policy_handle);
|
||||
if (state->user_handle == NULL) goto failed;
|
||||
|
||||
state->o.in.domain_handle = domain_handle;
|
||||
state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
state->o.in.rid = rid;
|
||||
state->o.out.user_handle = state->user_handle;
|
||||
|
||||
req = dcerpc_samr_OpenUser_send(state->samr_pipe, state, &state->o);
|
||||
if (req == NULL) goto failed;
|
||||
|
||||
req->async.callback = samr_usergroups_recv_open;
|
||||
req->async.private = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void samr_usergroups_recv_open(struct rpc_request *req)
|
||||
{
|
||||
struct samr_getuserdomgroups_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct samr_getuserdomgroups_state);
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->o.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->g.in.user_handle = state->user_handle;
|
||||
|
||||
req = dcerpc_samr_GetGroupsForUser_send(state->samr_pipe, state,
|
||||
&state->g);
|
||||
composite_continue_rpc(state->ctx, req, samr_usergroups_recv_groups,
|
||||
state);
|
||||
}
|
||||
|
||||
static void samr_usergroups_recv_groups(struct rpc_request *req)
|
||||
{
|
||||
struct samr_getuserdomgroups_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct samr_getuserdomgroups_state);
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->g.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->c.in.handle = state->user_handle;
|
||||
state->c.out.handle = state->user_handle;
|
||||
|
||||
req = dcerpc_samr_Close_send(state->samr_pipe, state, &state->c);
|
||||
composite_continue_rpc(state->ctx, req, samr_usergroups_recv_close,
|
||||
state);
|
||||
}
|
||||
|
||||
static void samr_usergroups_recv_close(struct rpc_request *req)
|
||||
{
|
||||
struct samr_getuserdomgroups_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct samr_getuserdomgroups_state);
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->c.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_samr_userdomgroups_recv(struct composite_context *ctx,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
int *num_rids, uint32_t **rids)
|
||||
{
|
||||
struct samr_getuserdomgroups_state *state =
|
||||
talloc_get_type(ctx->private_data,
|
||||
struct samr_getuserdomgroups_state);
|
||||
|
||||
int i;
|
||||
NTSTATUS status = composite_wait(ctx);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
*num_rids = state->g.out.rids->count;
|
||||
*rids = talloc_array(mem_ctx, uint32_t, *num_rids);
|
||||
if (*rids == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i=0; i<*num_rids; i++) {
|
||||
(*rids)[i] = state->g.out.rids->rids[i].rid;
|
||||
}
|
||||
|
||||
done:
|
||||
talloc_free(ctx);
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
SMB composite request interfaces
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __WB_ASYNC_HELPERS_H__
|
||||
#define __WB_ASYNC_HELPERS_H__
|
||||
|
||||
#include "librpc/gen_ndr/lsa.h"
|
||||
|
||||
struct wb_sid_object {
|
||||
enum lsa_SidType type;
|
||||
struct dom_sid *sid;
|
||||
const char *domain;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#endif /* __WB_ASYNC_HELPERS_H__ */
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Command backend for wbinfo --getdcname
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
|
||||
#include "librpc/gen_ndr/ndr_netlogon_c.h"
|
||||
|
||||
struct cmd_getdcname_state {
|
||||
struct composite_context *ctx;
|
||||
const char *domain_name;
|
||||
|
||||
struct netr_GetAnyDCName g;
|
||||
};
|
||||
|
||||
static void getdcname_recv_domain(struct composite_context *ctx);
|
||||
static void getdcname_recv_dcname(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_cmd_getdcname_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const char *domain_name)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct cmd_getdcname_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct cmd_getdcname_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->domain_name = talloc_strdup(state, domain_name);
|
||||
if (state->domain_name == NULL) goto failed;
|
||||
|
||||
ctx = wb_sid2domain_send(state, service, service->primary_sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = getdcname_recv_domain;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void getdcname_recv_domain(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_getdcname_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_getdcname_state);
|
||||
struct wbsrv_domain *domain;
|
||||
struct rpc_request *req;
|
||||
|
||||
state->ctx->status = wb_sid2domain_recv(ctx, &domain);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->g.in.logon_server = talloc_asprintf(
|
||||
state, "\\\\%s",
|
||||
dcerpc_server_name(domain->netlogon_pipe));
|
||||
state->g.in.domainname = state->domain_name;
|
||||
|
||||
req = dcerpc_netr_GetAnyDCName_send(domain->netlogon_pipe, state,
|
||||
&state->g);
|
||||
if (composite_nomem(req, state->ctx)) return;
|
||||
|
||||
composite_continue_rpc(state->ctx, req, getdcname_recv_dcname, state);
|
||||
}
|
||||
|
||||
static void getdcname_recv_dcname(struct rpc_request *req)
|
||||
{
|
||||
struct cmd_getdcname_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct cmd_getdcname_state);
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = werror_to_ntstatus(state->g.out.result);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_getdcname_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char **dcname)
|
||||
{
|
||||
struct cmd_getdcname_state *state =
|
||||
talloc_get_type(c->private_data, struct cmd_getdcname_state);
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
const char *p = state->g.out.dcname;
|
||||
if (*p == '\\') p += 1;
|
||||
if (*p == '\\') p += 1;
|
||||
*dcname = talloc_strdup(mem_ctx, p);
|
||||
if (*dcname == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
talloc_free(state);
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Command backend for wbinfo -m
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "librpc/gen_ndr/ndr_lsa_c.h"
|
||||
|
||||
/* List trusted domains. To avoid the trouble with having to wait for other
|
||||
* conflicting requests waiting for the lsa pipe we're opening our own lsa
|
||||
* pipe here. */
|
||||
|
||||
struct cmd_list_trustdom_state {
|
||||
struct composite_context *ctx;
|
||||
struct dcerpc_pipe *lsa_pipe;
|
||||
struct policy_handle *lsa_policy;
|
||||
int num_domains;
|
||||
struct wb_dom_info **domains;
|
||||
|
||||
uint32_t resume_handle;
|
||||
struct lsa_DomainList domainlist;
|
||||
struct lsa_EnumTrustDom r;
|
||||
};
|
||||
|
||||
static void cmd_list_trustdoms_recv_domain(struct composite_context *ctx);
|
||||
static void cmd_list_trustdoms_recv_lsa(struct composite_context *ctx);
|
||||
static void cmd_list_trustdoms_recv_doms(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_cmd_list_trustdoms_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct cmd_list_trustdom_state *state;
|
||||
|
||||
result = talloc_zero(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct cmd_list_trustdom_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
ctx = wb_sid2domain_send(state, service, service->primary_sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
ctx->async.fn = cmd_list_trustdoms_recv_domain;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cmd_list_trustdoms_recv_domain(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_list_trustdom_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_list_trustdom_state);
|
||||
struct wbsrv_domain *domain;
|
||||
struct smbcli_tree *tree;
|
||||
|
||||
state->ctx->status = wb_sid2domain_recv(ctx, &domain);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
tree = dcerpc_smb_tree(domain->lsa_pipe->conn);
|
||||
if (composite_nomem(tree, state->ctx)) return;
|
||||
|
||||
ctx = wb_init_lsa_send(state, tree, domain->lsa_auth_type,
|
||||
domain->schannel_creds);
|
||||
composite_continue(state->ctx, ctx, cmd_list_trustdoms_recv_lsa,
|
||||
state);
|
||||
}
|
||||
|
||||
static void cmd_list_trustdoms_recv_lsa(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_list_trustdom_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_list_trustdom_state);
|
||||
struct rpc_request *req;
|
||||
|
||||
state->ctx->status = wb_init_lsa_recv(ctx, state,
|
||||
&state->lsa_pipe,
|
||||
&state->lsa_policy);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->num_domains = 0;
|
||||
state->domains = NULL;
|
||||
|
||||
state->domainlist.count = 0;
|
||||
state->domainlist.domains = NULL;
|
||||
|
||||
state->resume_handle = 0;
|
||||
state->r.in.handle = state->lsa_policy;
|
||||
state->r.in.resume_handle = &state->resume_handle;
|
||||
state->r.in.max_size = 1000;
|
||||
state->r.out.resume_handle = &state->resume_handle;
|
||||
state->r.out.domains = &state->domainlist;
|
||||
|
||||
req = dcerpc_lsa_EnumTrustDom_send(state->lsa_pipe, state, &state->r);
|
||||
composite_continue_rpc(state->ctx, req, cmd_list_trustdoms_recv_doms,
|
||||
state);
|
||||
}
|
||||
|
||||
static void cmd_list_trustdoms_recv_doms(struct rpc_request *req)
|
||||
{
|
||||
struct cmd_list_trustdom_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct cmd_list_trustdom_state);
|
||||
int i, old_num_domains;
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->r.out.result;
|
||||
|
||||
if (!NT_STATUS_IS_OK(state->ctx->status) &&
|
||||
!NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_NO_MORE_ENTRIES) &&
|
||||
!NT_STATUS_EQUAL(state->ctx->status, STATUS_MORE_ENTRIES)) {
|
||||
composite_error(state->ctx, state->ctx->status);
|
||||
return;
|
||||
}
|
||||
|
||||
old_num_domains = state->num_domains;
|
||||
|
||||
state->num_domains += state->r.out.domains->count;
|
||||
state->domains = talloc_realloc(state, state->domains,
|
||||
struct wb_dom_info *,
|
||||
state->num_domains);
|
||||
if (composite_nomem(state->domains, state->ctx)) return;
|
||||
|
||||
for (i=0; i<state->r.out.domains->count; i++) {
|
||||
int j = i+old_num_domains;
|
||||
state->domains[j] = talloc(state->domains,
|
||||
struct wb_dom_info);
|
||||
if (composite_nomem(state->domains[i], state->ctx)) return;
|
||||
state->domains[j]->name = talloc_steal(
|
||||
state->domains[j],
|
||||
state->r.out.domains->domains[i].name.string);
|
||||
state->domains[j]->sid = talloc_steal(
|
||||
state->domains[j],
|
||||
state->r.out.domains->domains[i].sid);
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(state->ctx->status)) {
|
||||
composite_done(state->ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
state->domainlist.count = 0;
|
||||
state->domainlist.domains = NULL;
|
||||
state->r.in.handle = state->lsa_policy;
|
||||
state->r.in.resume_handle = &state->resume_handle;
|
||||
state->r.in.max_size = 1000;
|
||||
state->r.out.resume_handle = &state->resume_handle;
|
||||
state->r.out.domains = &state->domainlist;
|
||||
|
||||
req = dcerpc_lsa_EnumTrustDom_send(state->lsa_pipe, state, &state->r);
|
||||
composite_continue_rpc(state->ctx, req, cmd_list_trustdoms_recv_doms,
|
||||
state);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_list_trustdoms_recv(struct composite_context *ctx,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
int *num_domains,
|
||||
struct wb_dom_info ***domains)
|
||||
{
|
||||
NTSTATUS status = composite_wait(ctx);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct cmd_list_trustdom_state *state =
|
||||
talloc_get_type(ctx->private_data,
|
||||
struct cmd_list_trustdom_state);
|
||||
*num_domains = state->num_domains;
|
||||
*domains = talloc_steal(mem_ctx, state->domains);
|
||||
}
|
||||
talloc_free(ctx);
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Command backend for wbinfo -n
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "winbind/wb_async_helpers.h"
|
||||
#include "winbind/wb_helper.h"
|
||||
#include "smbd/service_task.h"
|
||||
|
||||
struct cmd_lookupname_state {
|
||||
struct composite_context *ctx;
|
||||
const char *name;
|
||||
struct wb_sid_object *result;
|
||||
};
|
||||
|
||||
static void lookupname_recv_domain(struct composite_context *ctx);
|
||||
static void lookupname_recv_sids(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_cmd_lookupname_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const char *dom_name,
|
||||
const char *name)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct cmd_lookupname_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct cmd_lookupname_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->name = talloc_asprintf(state, "%s\\%s", dom_name, name);
|
||||
if (state->name == NULL) goto failed;
|
||||
|
||||
ctx = wb_sid2domain_send(state, service, service->primary_sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = lookupname_recv_domain;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void lookupname_recv_domain(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_lookupname_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_lookupname_state);
|
||||
struct wbsrv_domain *domain;
|
||||
|
||||
state->ctx->status = wb_sid2domain_recv(ctx, &domain);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
ctx = wb_lsa_lookupnames_send(state, domain->lsa_pipe,
|
||||
domain->lsa_policy, 1, &state->name);
|
||||
composite_continue(state->ctx, ctx, lookupname_recv_sids, state);
|
||||
}
|
||||
|
||||
static void lookupname_recv_sids(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_lookupname_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_lookupname_state);
|
||||
struct wb_sid_object **sids;
|
||||
|
||||
state->ctx->status = wb_lsa_lookupnames_recv(ctx, state, &sids);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->result = sids[0];
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_lookupname_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct wb_sid_object **sid)
|
||||
{
|
||||
struct cmd_lookupname_state *state =
|
||||
talloc_get_type(c->private_data, struct cmd_lookupname_state);
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
*sid = talloc_steal(mem_ctx, state->result);
|
||||
}
|
||||
talloc_free(state);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_lookupname(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const char *dom_name,
|
||||
const char *name,
|
||||
struct wb_sid_object **sid)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_cmd_lookupname_send(mem_ctx, service, dom_name, name);
|
||||
return wb_cmd_lookupname_recv(c, mem_ctx, sid);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Command backend for wbinfo -s
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "winbind/wb_helper.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "libcli/security/security.h"
|
||||
|
||||
struct cmd_lookupsid_state {
|
||||
struct composite_context *ctx;
|
||||
const struct dom_sid *sid;
|
||||
struct wb_sid_object *result;
|
||||
};
|
||||
|
||||
static void lookupsid_recv_domain(struct composite_context *ctx);
|
||||
static void lookupsid_recv_names(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_cmd_lookupsid_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const struct dom_sid *sid)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct cmd_lookupsid_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct cmd_lookupsid_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->sid = dom_sid_dup(state, sid);
|
||||
if (state->sid == NULL) goto failed;
|
||||
|
||||
ctx = wb_sid2domain_send(state, service, service->primary_sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = lookupsid_recv_domain;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void lookupsid_recv_domain(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_lookupsid_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_lookupsid_state);
|
||||
struct wbsrv_domain *domain;
|
||||
|
||||
state->ctx->status = wb_sid2domain_recv(ctx, &domain);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
ctx = wb_lsa_lookupsids_send(state, domain->lsa_pipe,
|
||||
domain->lsa_policy, 1, &state->sid);
|
||||
composite_continue(state->ctx, ctx, lookupsid_recv_names, state);
|
||||
}
|
||||
|
||||
static void lookupsid_recv_names(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_lookupsid_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_lookupsid_state);
|
||||
struct wb_sid_object **names;
|
||||
|
||||
state->ctx->status = wb_lsa_lookupsids_recv(ctx, state, &names);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->result = names[0];
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_lookupsid_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct wb_sid_object **sid)
|
||||
{
|
||||
struct cmd_lookupsid_state *state =
|
||||
talloc_get_type(c->private_data, struct cmd_lookupsid_state);
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
*sid = talloc_steal(mem_ctx, state->result);
|
||||
}
|
||||
talloc_free(state);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_lookupsid(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
|
||||
const struct dom_sid *sid,
|
||||
struct wb_sid_object **name)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_cmd_lookupsid_send(mem_ctx, service, sid);
|
||||
return wb_cmd_lookupsid_recv(c, mem_ctx, name);
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Command backend for wbinfo --user-domgroups
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "winbind/wb_helper.h"
|
||||
#include "smbd/service_task.h"
|
||||
|
||||
struct cmd_userdomgroups_state {
|
||||
struct composite_context *ctx;
|
||||
struct dom_sid *dom_sid;
|
||||
uint32_t user_rid;
|
||||
int num_rids;
|
||||
uint32_t *rids;
|
||||
};
|
||||
|
||||
static void userdomgroups_recv_domain(struct composite_context *ctx);
|
||||
static void userdomgroups_recv_rids(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_cmd_userdomgroups_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const struct dom_sid *sid)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct cmd_userdomgroups_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct cmd_userdomgroups_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->dom_sid = dom_sid_dup(state, sid);
|
||||
if (state->dom_sid == NULL) goto failed;
|
||||
state->dom_sid->num_auths -= 1;
|
||||
|
||||
state->user_rid = sid->sub_auths[sid->num_auths-1];
|
||||
|
||||
ctx = wb_sid2domain_send(state, service, sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = userdomgroups_recv_domain;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void userdomgroups_recv_domain(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_userdomgroups_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_userdomgroups_state);
|
||||
struct wbsrv_domain *domain;
|
||||
|
||||
state->ctx->status = wb_sid2domain_recv(ctx, &domain);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
ctx = wb_samr_userdomgroups_send(state, domain->samr_pipe,
|
||||
domain->domain_handle,
|
||||
state->user_rid);
|
||||
composite_continue(state->ctx, ctx, userdomgroups_recv_rids, state);
|
||||
|
||||
}
|
||||
|
||||
static void userdomgroups_recv_rids(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_userdomgroups_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_userdomgroups_state);
|
||||
|
||||
state->ctx->status = wb_samr_userdomgroups_recv(ctx, state,
|
||||
&state->num_rids,
|
||||
&state->rids);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_userdomgroups_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
int *num_sids, struct dom_sid ***sids)
|
||||
{
|
||||
struct cmd_userdomgroups_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct cmd_userdomgroups_state);
|
||||
int i;
|
||||
NTSTATUS status;
|
||||
|
||||
status = composite_wait(c);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
*num_sids = state->num_rids;
|
||||
*sids = talloc_array(mem_ctx, struct dom_sid *, state->num_rids);
|
||||
if (*sids == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i=0; i<state->num_rids; i++) {
|
||||
(*sids)[i] = dom_sid_add_rid((*sids), state->dom_sid,
|
||||
state->rids[i]);
|
||||
if ((*sids)[i] == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_userdomgroups(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const struct dom_sid *sid,
|
||||
int *num_sids, struct dom_sid ***sids)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_cmd_userdomgroups_send(mem_ctx, service, sid);
|
||||
return wb_cmd_userdomgroups_recv(c, mem_ctx, num_sids, sids);
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Command backend for wbinfo --user-sids
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "librpc/gen_ndr/ndr_samr_c.h"
|
||||
#include "libcli/security/security.h"
|
||||
|
||||
/* Calculate the token in two steps: Go the user's originating domain, ask for
|
||||
* the user's domain groups. Then with the resulting list of sids go to our
|
||||
* own domain to expand the aliases aka domain local groups. */
|
||||
|
||||
struct cmd_usersids_state {
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service;
|
||||
struct dom_sid *user_sid;
|
||||
int num_domgroups;
|
||||
struct dom_sid **domgroups;
|
||||
|
||||
struct lsa_SidArray lsa_sids;
|
||||
struct samr_Ids rids;
|
||||
struct samr_GetAliasMembership r;
|
||||
|
||||
int num_sids;
|
||||
struct dom_sid **sids;
|
||||
};
|
||||
|
||||
static void usersids_recv_domgroups(struct composite_context *ctx);
|
||||
static void usersids_recv_domain(struct composite_context *ctx);
|
||||
static void usersids_recv_aliases(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_cmd_usersids_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const struct dom_sid *sid)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct cmd_usersids_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct cmd_usersids_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->service = service;
|
||||
state->user_sid = dom_sid_dup(state, sid);
|
||||
if (state->user_sid == NULL) goto failed;
|
||||
|
||||
ctx = wb_cmd_userdomgroups_send(state, service, sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = usersids_recv_domgroups;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usersids_recv_domgroups(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_usersids_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_usersids_state);
|
||||
|
||||
state->ctx->status = wb_cmd_userdomgroups_recv(ctx, state,
|
||||
&state->num_domgroups,
|
||||
&state->domgroups);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
ctx = wb_sid2domain_send(state, state->service,
|
||||
state->service->primary_sid);
|
||||
composite_continue(state->ctx, ctx, usersids_recv_domain, state);
|
||||
}
|
||||
|
||||
static void usersids_recv_domain(struct composite_context *ctx)
|
||||
{
|
||||
struct cmd_usersids_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct cmd_usersids_state);
|
||||
struct rpc_request *req;
|
||||
struct wbsrv_domain *domain;
|
||||
int i;
|
||||
|
||||
state->ctx->status = wb_sid2domain_recv(ctx, &domain);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->lsa_sids.num_sids = state->num_domgroups+1;
|
||||
state->lsa_sids.sids = talloc_array(state, struct lsa_SidPtr,
|
||||
state->lsa_sids.num_sids);
|
||||
if (composite_nomem(state->lsa_sids.sids, state->ctx)) return;
|
||||
|
||||
state->lsa_sids.sids[0].sid = state->user_sid;
|
||||
for (i=0; i<state->num_domgroups; i++) {
|
||||
state->lsa_sids.sids[i+1].sid = state->domgroups[i];
|
||||
}
|
||||
|
||||
state->rids.count = 0;
|
||||
state->rids.ids = NULL;
|
||||
|
||||
state->r.in.domain_handle = domain->domain_handle;
|
||||
state->r.in.sids = &state->lsa_sids;
|
||||
state->r.out.rids = &state->rids;
|
||||
|
||||
req = dcerpc_samr_GetAliasMembership_send(domain->samr_pipe, state,
|
||||
&state->r);
|
||||
composite_continue_rpc(state->ctx, req, usersids_recv_aliases, state);
|
||||
}
|
||||
|
||||
static void usersids_recv_aliases(struct rpc_request *req)
|
||||
{
|
||||
struct cmd_usersids_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct cmd_usersids_state);
|
||||
int i;
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->r.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->num_sids = 1 + state->num_domgroups + state->r.out.rids->count;
|
||||
state->sids = talloc_array(state, struct dom_sid *, state->num_sids);
|
||||
if (composite_nomem(state->sids, state->ctx)) return;
|
||||
|
||||
state->sids[0] = talloc_steal(state->sids, state->user_sid);
|
||||
|
||||
for (i=0; i<state->num_domgroups; i++) {
|
||||
state->sids[1+i] =
|
||||
talloc_steal(state->sids, state->domgroups[i]);
|
||||
}
|
||||
|
||||
for (i=0; i<state->r.out.rids->count; i++) {
|
||||
state->sids[1+state->num_domgroups+i] = dom_sid_add_rid(
|
||||
state->sids, state->service->primary_sid,
|
||||
state->r.out.rids->ids[i]);
|
||||
|
||||
if (composite_nomem(state->sids[1+state->num_domgroups+i],
|
||||
state->ctx)) return;
|
||||
}
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_usersids_recv(struct composite_context *ctx,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
int *num_sids, struct dom_sid ***sids)
|
||||
{
|
||||
NTSTATUS status = composite_wait(ctx);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct cmd_usersids_state *state =
|
||||
talloc_get_type(ctx->private_data,
|
||||
struct cmd_usersids_state);
|
||||
*num_sids = state->num_sids;
|
||||
*sids = talloc_steal(mem_ctx, state->sids);
|
||||
}
|
||||
talloc_free(ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_usersids(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
|
||||
const struct dom_sid *sid,
|
||||
int *num_sids, struct dom_sid ***sids)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_cmd_usersids_send(mem_ctx, service, sid);
|
||||
return wb_cmd_usersids_recv(c, mem_ctx, num_sids, sids);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Connect to the LSA pipe, given an smbcli_tree and possibly some
|
||||
credentials. Try ntlmssp, schannel and anon in that order.
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "librpc/gen_ndr/ndr_lsa_c.h"
|
||||
|
||||
/* Helper to initialize LSA with a specific auth methods. Verify by opening
|
||||
* the LSA policy. */
|
||||
|
||||
struct init_lsa_state {
|
||||
struct composite_context *ctx;
|
||||
struct dcerpc_pipe *lsa_pipe;
|
||||
|
||||
uint8_t auth_type;
|
||||
struct cli_credentials *creds;
|
||||
|
||||
struct lsa_ObjectAttribute objectattr;
|
||||
struct lsa_OpenPolicy2 openpolicy;
|
||||
struct policy_handle *handle;
|
||||
};
|
||||
|
||||
static void init_lsa_recv_pipe(struct composite_context *ctx);
|
||||
static void init_lsa_recv_anon_bind(struct composite_context *ctx);
|
||||
static void init_lsa_recv_auth_bind(struct composite_context *ctx);
|
||||
static void init_lsa_recv_openpol(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_init_lsa_send(TALLOC_CTX *mem_ctx,
|
||||
struct smbcli_tree *tree,
|
||||
uint8_t auth_type,
|
||||
struct cli_credentials *creds)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct init_lsa_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = tree->session->transport->socket->event.ctx;
|
||||
|
||||
state = talloc(result, struct init_lsa_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->auth_type = auth_type;
|
||||
state->creds = creds;
|
||||
|
||||
state->lsa_pipe = dcerpc_pipe_init(state, result->event_ctx);
|
||||
if (state->lsa_pipe == NULL) goto failed;
|
||||
|
||||
ctx = dcerpc_pipe_open_smb_send(state->lsa_pipe->conn, tree,
|
||||
"\\lsarpc");
|
||||
ctx->async.fn = init_lsa_recv_pipe;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void init_lsa_recv_pipe(struct composite_context *ctx)
|
||||
{
|
||||
struct init_lsa_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_lsa_state);
|
||||
|
||||
state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
switch (state->auth_type) {
|
||||
case DCERPC_AUTH_TYPE_NONE:
|
||||
ctx = dcerpc_bind_auth_none_send(state, state->lsa_pipe,
|
||||
&dcerpc_table_lsarpc);
|
||||
composite_continue(state->ctx, ctx, init_lsa_recv_anon_bind,
|
||||
state);
|
||||
break;
|
||||
case DCERPC_AUTH_TYPE_NTLMSSP:
|
||||
case DCERPC_AUTH_TYPE_SCHANNEL:
|
||||
{
|
||||
uint8_t auth_type;
|
||||
if (lp_winbind_sealed_pipes()) {
|
||||
auth_type = DCERPC_AUTH_LEVEL_PRIVACY;
|
||||
} else {
|
||||
auth_type = DCERPC_AUTH_LEVEL_INTEGRITY;
|
||||
}
|
||||
if (state->creds == NULL) {
|
||||
composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
ctx = dcerpc_bind_auth_send(state, state->lsa_pipe,
|
||||
&dcerpc_table_lsarpc,
|
||||
state->creds, state->auth_type,
|
||||
auth_type,
|
||||
NULL);
|
||||
composite_continue(state->ctx, ctx, init_lsa_recv_auth_bind,
|
||||
state);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_lsa_recv_anon_bind(struct composite_context *ctx)
|
||||
{
|
||||
struct init_lsa_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_lsa_state);
|
||||
struct rpc_request *req;
|
||||
|
||||
state->ctx->status = dcerpc_bind_auth_none_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->handle = talloc(state, struct policy_handle);
|
||||
if (composite_nomem(state->handle, state->ctx)) return;
|
||||
|
||||
state->openpolicy.in.system_name =
|
||||
talloc_asprintf(state, "\\\\%s",
|
||||
dcerpc_server_name(state->lsa_pipe));
|
||||
ZERO_STRUCT(state->objectattr);
|
||||
state->openpolicy.in.attr = &state->objectattr;
|
||||
state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
state->openpolicy.out.handle = state->handle;
|
||||
|
||||
req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
|
||||
&state->openpolicy);
|
||||
composite_continue_rpc(state->ctx, req, init_lsa_recv_openpol, state);
|
||||
}
|
||||
|
||||
static void init_lsa_recv_auth_bind(struct composite_context *ctx)
|
||||
{
|
||||
struct init_lsa_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_lsa_state);
|
||||
struct rpc_request *req;
|
||||
|
||||
state->ctx->status = dcerpc_bind_auth_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->handle = talloc(state, struct policy_handle);
|
||||
if (composite_nomem(state->handle, state->ctx)) return;
|
||||
|
||||
state->openpolicy.in.system_name =
|
||||
talloc_asprintf(state, "\\\\%s",
|
||||
dcerpc_server_name(state->lsa_pipe));
|
||||
ZERO_STRUCT(state->objectattr);
|
||||
state->openpolicy.in.attr = &state->objectattr;
|
||||
state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
state->openpolicy.out.handle = state->handle;
|
||||
|
||||
req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
|
||||
&state->openpolicy);
|
||||
composite_continue_rpc(state->ctx, req, init_lsa_recv_openpol, state);
|
||||
}
|
||||
|
||||
static void init_lsa_recv_openpol(struct rpc_request *req)
|
||||
{
|
||||
struct init_lsa_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct init_lsa_state);
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->openpolicy.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_init_lsa_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct dcerpc_pipe **lsa_pipe,
|
||||
struct policy_handle **lsa_policy)
|
||||
{
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct init_lsa_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct init_lsa_state);
|
||||
*lsa_pipe = talloc_steal(mem_ctx, state->lsa_pipe);
|
||||
*lsa_policy = talloc_steal(mem_ctx, state->handle);
|
||||
}
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Connect to LSA using the credentials, try NTLMSSP and SCHANNEL using the
|
||||
* given credentials. If both fail or no credentials are available, fall back
|
||||
* to an anonymous bind.
|
||||
*/
|
||||
|
||||
struct connect_lsa_state {
|
||||
struct composite_context *ctx;
|
||||
struct smbcli_tree *tree;
|
||||
struct cli_credentials *credentials;
|
||||
|
||||
uint8_t auth_type;
|
||||
struct dcerpc_pipe *lsa_pipe;
|
||||
struct policy_handle *lsa_policy;
|
||||
};
|
||||
|
||||
static void connect_lsa_recv_ntlmssp(struct composite_context *ctx);
|
||||
static void connect_lsa_recv_schannel(struct composite_context *ctx);
|
||||
static void connect_lsa_recv_anon(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_connect_lsa_send(TALLOC_CTX *mem_ctx,
|
||||
struct smbcli_tree *tree,
|
||||
struct cli_credentials *credentials)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct connect_lsa_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = tree->session->transport->socket->event.ctx;
|
||||
|
||||
state = talloc(result, struct connect_lsa_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->tree = tree;
|
||||
state->credentials = credentials;
|
||||
|
||||
if (credentials == NULL) {
|
||||
ctx = wb_init_lsa_send(state, tree, DCERPC_AUTH_TYPE_NONE,
|
||||
NULL);
|
||||
if (ctx == NULL) goto failed;
|
||||
ctx->async.fn = connect_lsa_recv_anon;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
}
|
||||
|
||||
ctx = wb_init_lsa_send(state, tree, DCERPC_AUTH_TYPE_NTLMSSP,
|
||||
credentials);
|
||||
if (ctx == NULL) goto failed;
|
||||
ctx->async.fn = connect_lsa_recv_ntlmssp;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void connect_lsa_recv_ntlmssp(struct composite_context *ctx)
|
||||
{
|
||||
struct connect_lsa_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct connect_lsa_state);
|
||||
|
||||
state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
|
||||
&state->lsa_policy);
|
||||
|
||||
if (NT_STATUS_IS_OK(state->ctx->status)) {
|
||||
state->auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
|
||||
composite_done(state->ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = wb_init_lsa_send(state, state->tree, DCERPC_AUTH_TYPE_SCHANNEL,
|
||||
state->credentials);
|
||||
composite_continue(state->ctx, ctx,
|
||||
connect_lsa_recv_schannel, state);
|
||||
}
|
||||
|
||||
static void connect_lsa_recv_schannel(struct composite_context *ctx)
|
||||
{
|
||||
struct connect_lsa_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct connect_lsa_state);
|
||||
|
||||
state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
|
||||
&state->lsa_policy);
|
||||
|
||||
if (NT_STATUS_IS_OK(state->ctx->status)) {
|
||||
state->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
|
||||
composite_done(state->ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = wb_init_lsa_send(state, state->tree, DCERPC_AUTH_TYPE_NONE,
|
||||
state->credentials);
|
||||
composite_continue(state->ctx, ctx,
|
||||
connect_lsa_recv_anon, state);
|
||||
}
|
||||
|
||||
static void connect_lsa_recv_anon(struct composite_context *ctx)
|
||||
{
|
||||
struct connect_lsa_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct connect_lsa_state);
|
||||
|
||||
state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
|
||||
&state->lsa_policy);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->auth_type = DCERPC_AUTH_TYPE_NONE;
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_connect_lsa_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint8_t *auth_type,
|
||||
struct dcerpc_pipe **lsa_pipe,
|
||||
struct policy_handle **lsa_policy)
|
||||
{
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct connect_lsa_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct connect_lsa_state);
|
||||
*auth_type = state->auth_type;
|
||||
*lsa_pipe = talloc_steal(mem_ctx, state->lsa_pipe);
|
||||
*lsa_policy = talloc_steal(mem_ctx, state->lsa_policy);
|
||||
}
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_connect_lsa(TALLOC_CTX *mem_ctx,
|
||||
struct smbcli_tree *tree,
|
||||
struct cli_credentials *credentials,
|
||||
uint8_t *auth_type,
|
||||
struct dcerpc_pipe **lsa_pipe,
|
||||
struct policy_handle **lsa_policy)
|
||||
{
|
||||
struct composite_context *c;
|
||||
c = wb_connect_lsa_send(mem_ctx, tree, credentials);
|
||||
return wb_connect_lsa_recv(c, mem_ctx, auth_type, lsa_pipe,
|
||||
lsa_policy);
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Connect to the SAMR pipe, given an smbcli_tree and possibly some
|
||||
credentials. Try ntlmssp, schannel and anon in that order.
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
|
||||
#include "libcli/raw/libcliraw.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "librpc/gen_ndr/ndr_samr_c.h"
|
||||
|
||||
|
||||
/* Helper to initialize SAMR with a specific auth methods. Verify by opening
|
||||
* the SAM handle */
|
||||
|
||||
struct connect_samr_state {
|
||||
struct composite_context *ctx;
|
||||
uint8_t auth_type;
|
||||
struct cli_credentials *creds;
|
||||
struct dom_sid *sid;
|
||||
|
||||
struct dcerpc_pipe *samr_pipe;
|
||||
struct policy_handle *connect_handle;
|
||||
struct policy_handle *domain_handle;
|
||||
|
||||
struct samr_Connect2 c;
|
||||
struct samr_OpenDomain o;
|
||||
};
|
||||
|
||||
static void connect_samr_recv_pipe(struct composite_context *ctx);
|
||||
static void connect_samr_recv_anon_bind(struct composite_context *ctx);
|
||||
static void connect_samr_recv_auth_bind(struct composite_context *ctx);
|
||||
static void connect_samr_recv_conn(struct rpc_request *req);
|
||||
static void connect_samr_recv_open(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_connect_sam_send(TALLOC_CTX *mem_ctx,
|
||||
struct smbcli_tree *tree,
|
||||
uint8_t auth_type,
|
||||
struct cli_credentials *creds,
|
||||
const struct dom_sid *domain_sid)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct connect_samr_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = tree->session->transport->socket->event.ctx;
|
||||
|
||||
state = talloc(result, struct connect_samr_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->auth_type = auth_type;
|
||||
state->creds = creds;
|
||||
state->sid = dom_sid_dup(state, domain_sid);
|
||||
if (state->sid == NULL) goto failed;
|
||||
|
||||
state->samr_pipe = dcerpc_pipe_init(state, result->event_ctx);
|
||||
if (state->samr_pipe == NULL) goto failed;
|
||||
|
||||
ctx = dcerpc_pipe_open_smb_send(state->samr_pipe->conn, tree,
|
||||
"\\samr");
|
||||
ctx->async.fn = connect_samr_recv_pipe;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void connect_samr_recv_pipe(struct composite_context *ctx)
|
||||
{
|
||||
struct connect_samr_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct connect_samr_state);
|
||||
|
||||
state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
switch (state->auth_type) {
|
||||
case DCERPC_AUTH_TYPE_NONE:
|
||||
ctx = dcerpc_bind_auth_none_send(state, state->samr_pipe,
|
||||
&dcerpc_table_samr);
|
||||
composite_continue(state->ctx, ctx,
|
||||
connect_samr_recv_anon_bind, state);
|
||||
break;
|
||||
case DCERPC_AUTH_TYPE_NTLMSSP:
|
||||
case DCERPC_AUTH_TYPE_SCHANNEL:
|
||||
{
|
||||
uint8_t auth_type;
|
||||
if (lp_winbind_sealed_pipes()) {
|
||||
auth_type = DCERPC_AUTH_LEVEL_PRIVACY;
|
||||
} else {
|
||||
auth_type = DCERPC_AUTH_LEVEL_INTEGRITY;
|
||||
}
|
||||
if (state->creds == NULL) {
|
||||
composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
ctx = dcerpc_bind_auth_send(state, state->samr_pipe,
|
||||
&dcerpc_table_samr,
|
||||
state->creds, state->auth_type,
|
||||
auth_type,
|
||||
NULL);
|
||||
composite_continue(state->ctx, ctx,
|
||||
connect_samr_recv_auth_bind, state);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_samr_recv_anon_bind(struct composite_context *ctx)
|
||||
{
|
||||
struct connect_samr_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct connect_samr_state);
|
||||
struct rpc_request *req;
|
||||
|
||||
state->ctx->status = dcerpc_bind_auth_none_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->connect_handle = talloc(state, struct policy_handle);
|
||||
if (composite_nomem(state->connect_handle, state->ctx)) return;
|
||||
|
||||
state->c.in.system_name =
|
||||
talloc_asprintf(state, "\\\\%s",
|
||||
dcerpc_server_name(state->samr_pipe));
|
||||
state->c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
state->c.out.connect_handle = state->connect_handle;
|
||||
|
||||
req = dcerpc_samr_Connect2_send(state->samr_pipe, state, &state->c);
|
||||
composite_continue_rpc(state->ctx, req, connect_samr_recv_conn, state);
|
||||
}
|
||||
|
||||
static void connect_samr_recv_auth_bind(struct composite_context *ctx)
|
||||
{
|
||||
struct connect_samr_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct connect_samr_state);
|
||||
struct rpc_request *req;
|
||||
|
||||
state->ctx->status = dcerpc_bind_auth_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->connect_handle = talloc(state, struct policy_handle);
|
||||
if (composite_nomem(state->connect_handle, state->ctx)) return;
|
||||
|
||||
state->c.in.system_name =
|
||||
talloc_asprintf(state, "\\\\%s",
|
||||
dcerpc_server_name(state->samr_pipe));
|
||||
state->c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
state->c.out.connect_handle = state->connect_handle;
|
||||
|
||||
req = dcerpc_samr_Connect2_send(state->samr_pipe, state, &state->c);
|
||||
composite_continue_rpc(state->ctx, req, connect_samr_recv_conn, state);
|
||||
}
|
||||
|
||||
static void connect_samr_recv_conn(struct rpc_request *req)
|
||||
{
|
||||
struct connect_samr_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct connect_samr_state);
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->c.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->domain_handle = talloc(state, struct policy_handle);
|
||||
if (composite_nomem(state->domain_handle, state->ctx)) return;
|
||||
|
||||
state->o.in.connect_handle = state->connect_handle;
|
||||
state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
||||
state->o.in.sid = state->sid;
|
||||
state->o.out.domain_handle = state->domain_handle;
|
||||
|
||||
req = dcerpc_samr_OpenDomain_send(state->samr_pipe, state, &state->o);
|
||||
composite_continue_rpc(state->ctx, req,
|
||||
connect_samr_recv_open, state);
|
||||
}
|
||||
|
||||
static void connect_samr_recv_open(struct rpc_request *req)
|
||||
{
|
||||
struct connect_samr_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct connect_samr_state);
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->o.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_connect_sam_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct dcerpc_pipe **samr_pipe,
|
||||
struct policy_handle **connect_handle,
|
||||
struct policy_handle **domain_handle)
|
||||
{
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct connect_samr_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct connect_samr_state);
|
||||
*samr_pipe = talloc_steal(mem_ctx, state->samr_pipe);
|
||||
*connect_handle = talloc_steal(mem_ctx, state->connect_handle);
|
||||
*domain_handle = talloc_steal(mem_ctx, state->domain_handle);
|
||||
}
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_connect_sam(TALLOC_CTX *mem_ctx,
|
||||
struct smbcli_tree *tree,
|
||||
uint8_t auth_type,
|
||||
struct cli_credentials *creds,
|
||||
const struct dom_sid *domain_sid,
|
||||
struct dcerpc_pipe **samr_pipe,
|
||||
struct policy_handle **connect_handle,
|
||||
struct policy_handle **domain_handle)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_connect_sam_send(mem_ctx, tree, auth_type, creds,
|
||||
domain_sid);
|
||||
return wb_connect_sam_recv(c, mem_ctx, samr_pipe, connect_handle,
|
||||
domain_handle);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Get a struct wb_dom_info for a domain using DNS, netbios, possibly cldap
|
||||
etc.
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "librpc/gen_ndr/ndr_irpc.h"
|
||||
#include "librpc/gen_ndr/samr.h"
|
||||
#include "lib/messaging/irpc.h"
|
||||
|
||||
struct get_dom_info_state {
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service;
|
||||
struct nbtd_getdcname r;
|
||||
struct wb_dom_info *info;
|
||||
};
|
||||
|
||||
static void get_dom_info_recv_addrs(struct composite_context *ctx);
|
||||
static void get_dom_info_recv_dcname(struct irpc_request *ireq);
|
||||
|
||||
struct composite_context *wb_get_dom_info_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const char *domain_name,
|
||||
const struct dom_sid *sid)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct get_dom_info_state *state;
|
||||
struct nbt_name name;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct get_dom_info_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->service = service;
|
||||
|
||||
state->info = talloc_zero(state, struct wb_dom_info);
|
||||
if (state->info == NULL) goto failed;
|
||||
|
||||
state->info->name = talloc_strdup(state->info, domain_name);
|
||||
if (state->info->name == NULL) goto failed;
|
||||
state->info->sid = dom_sid_dup(state->info, sid);
|
||||
if (state->info->sid == NULL) goto failed;
|
||||
|
||||
make_nbt_name(&name, state->info->name, NBT_NAME_LOGON);
|
||||
|
||||
ctx = resolve_name_send(&name, result->event_ctx,
|
||||
lp_name_resolve_order());
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = get_dom_info_recv_addrs;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void get_dom_info_recv_addrs(struct composite_context *ctx)
|
||||
{
|
||||
struct get_dom_info_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct get_dom_info_state);
|
||||
uint32_t *nbt_servers;
|
||||
struct irpc_request *ireq;
|
||||
|
||||
state->ctx->status = resolve_name_recv(ctx, state->info,
|
||||
&state->info->dc_address);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
nbt_servers = irpc_servers_byname(state->service->task->msg_ctx,
|
||||
"nbt_server");
|
||||
if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
|
||||
composite_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS);
|
||||
return;
|
||||
}
|
||||
|
||||
state->r.in.domainname = state->info->name;
|
||||
state->r.in.ip_address = state->info->dc_address;
|
||||
state->r.in.my_computername = lp_netbios_name();
|
||||
state->r.in.my_accountname = talloc_asprintf(state, "%s$",
|
||||
lp_netbios_name());
|
||||
if (composite_nomem(state->r.in.my_accountname, state->ctx)) return;
|
||||
state->r.in.account_control = ACB_WSTRUST;
|
||||
state->r.in.domain_sid = dom_sid_dup(state, state->info->sid);
|
||||
if (composite_nomem(state->r.in.domain_sid, state->ctx)) return;
|
||||
|
||||
ireq = irpc_call_send(state->service->task->msg_ctx, nbt_servers[0],
|
||||
&dcerpc_table_irpc, DCERPC_NBTD_GETDCNAME,
|
||||
&state->r, state);
|
||||
composite_continue_irpc(state->ctx, ireq, get_dom_info_recv_dcname,
|
||||
state);
|
||||
}
|
||||
|
||||
static void get_dom_info_recv_dcname(struct irpc_request *ireq)
|
||||
{
|
||||
struct get_dom_info_state *state =
|
||||
talloc_get_type(ireq->async.private,
|
||||
struct get_dom_info_state);
|
||||
|
||||
|
||||
state->ctx->status = irpc_call_recv(ireq);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->info->dc_name = talloc_steal(state->info, state->r.out.dcname);
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_get_dom_info_recv(struct composite_context *ctx,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct wb_dom_info **result)
|
||||
{
|
||||
NTSTATUS status = composite_wait(ctx);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct get_dom_info_state *state =
|
||||
talloc_get_type(ctx->private_data,
|
||||
struct get_dom_info_state);
|
||||
*result = talloc_steal(mem_ctx, state->info);
|
||||
}
|
||||
talloc_free(ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_get_dom_info(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const char *domain_name,
|
||||
const struct dom_sid *sid,
|
||||
struct wb_dom_info **result)
|
||||
{
|
||||
struct composite_context *ctx =
|
||||
wb_get_dom_info_send(mem_ctx, service, domain_name, sid);
|
||||
return wb_get_dom_info_recv(ctx, mem_ctx, result);
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Get a struct wb_dom_info for a trusted domain, relying on "our" DC.
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "librpc/gen_ndr/ndr_netlogon_c.h"
|
||||
|
||||
struct trusted_dom_info_state {
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service;
|
||||
struct wbsrv_domain *my_domain;
|
||||
|
||||
struct netr_DsRGetDCName d;
|
||||
struct netr_GetAnyDCName g;
|
||||
|
||||
struct wb_dom_info *info;
|
||||
};
|
||||
|
||||
static void trusted_dom_info_recv_domain(struct composite_context *ctx);
|
||||
static void trusted_dom_info_recv_dsr(struct rpc_request *req);
|
||||
static void trusted_dom_info_recv_dcname(struct rpc_request *req);
|
||||
static void trusted_dom_info_recv_dcaddr(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_trusted_dom_info_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const char *domain_name,
|
||||
const struct dom_sid *sid)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct trusted_dom_info_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct trusted_dom_info_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->info = talloc_zero(state, struct wb_dom_info);
|
||||
if (state->info == NULL) goto failed;
|
||||
|
||||
state->service = service;
|
||||
|
||||
state->info->sid = dom_sid_dup(state->info, sid);
|
||||
if (state->info->sid == NULL) goto failed;
|
||||
|
||||
state->info->name = talloc_strdup(state->info, domain_name);
|
||||
if (state->info->name == NULL) goto failed;
|
||||
|
||||
ctx = wb_sid2domain_send(state, service, service->primary_sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = trusted_dom_info_recv_domain;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void trusted_dom_info_recv_domain(struct composite_context *ctx)
|
||||
{
|
||||
struct trusted_dom_info_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct trusted_dom_info_state);
|
||||
struct rpc_request *req;
|
||||
|
||||
state->ctx->status = wb_sid2domain_recv(ctx, &state->my_domain);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->d.in.server_unc =
|
||||
talloc_asprintf(state, "\\\\%s",
|
||||
state->my_domain->info->dc_name);
|
||||
if (composite_nomem(state->d.in.server_unc,
|
||||
state->ctx)) return;
|
||||
|
||||
state->d.in.domain_name = state->info->name;
|
||||
state->d.in.domain_guid = NULL;
|
||||
state->d.in.site_guid = NULL;
|
||||
state->d.in.flags = 0x40000000;
|
||||
|
||||
req = dcerpc_netr_DsRGetDCName_send(state->my_domain->netlogon_pipe,
|
||||
state, &state->d);
|
||||
composite_continue_rpc(state->ctx, req, trusted_dom_info_recv_dsr,
|
||||
state);
|
||||
}
|
||||
|
||||
/*
|
||||
* dcerpc_netr_DsRGetDCName has replied
|
||||
*/
|
||||
|
||||
static void trusted_dom_info_recv_dsr(struct rpc_request *req)
|
||||
{
|
||||
struct trusted_dom_info_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct trusted_dom_info_state);
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!NT_STATUS_IS_OK(state->ctx->status)) {
|
||||
DEBUG(9, ("dcerpc_ndr_request_recv returned %s\n",
|
||||
nt_errstr(state->ctx->status)));
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
state->ctx->status =
|
||||
werror_to_ntstatus(state->d.out.result);
|
||||
if (!NT_STATUS_IS_OK(state->ctx->status)) {
|
||||
DEBUG(9, ("dsrgetdcname returned %s\n",
|
||||
nt_errstr(state->ctx->status)));
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
/* Hey, that was easy! */
|
||||
|
||||
state->info->dc_name = talloc_steal(state->info,
|
||||
state->d.out.info->dc_unc);
|
||||
if (*state->info->dc_name == '\\') state->info->dc_name++;
|
||||
if (*state->info->dc_name == '\\') state->info->dc_name++;
|
||||
|
||||
state->info->dc_address = talloc_steal(state->info,
|
||||
state->d.out.info->dc_address);
|
||||
if (*state->info->dc_address == '\\') state->info->dc_address++;
|
||||
if (*state->info->dc_address == '\\') state->info->dc_address++;
|
||||
|
||||
state->info->dns_name = talloc_steal(state->info,
|
||||
state->d.out.info->domain_name);
|
||||
|
||||
composite_done(state->ctx);
|
||||
return;
|
||||
|
||||
fallback:
|
||||
|
||||
state->g.in.logon_server = talloc_asprintf(
|
||||
state, "\\\\%s",
|
||||
dcerpc_server_name(state->my_domain->netlogon_pipe));
|
||||
state->g.in.domainname = state->info->name;
|
||||
|
||||
req = dcerpc_netr_GetAnyDCName_send(state->my_domain->netlogon_pipe,
|
||||
state, &state->g);
|
||||
if (composite_nomem(req, state->ctx)) return;
|
||||
|
||||
composite_continue_rpc(state->ctx, req, trusted_dom_info_recv_dcname,
|
||||
state);
|
||||
}
|
||||
|
||||
static void trusted_dom_info_recv_dcname(struct rpc_request *req)
|
||||
{
|
||||
struct trusted_dom_info_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct trusted_dom_info_state);
|
||||
struct composite_context *ctx;
|
||||
struct nbt_name name;
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = werror_to_ntstatus(state->g.out.result);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->info->dc_name = talloc_steal(state->info,
|
||||
state->g.out.dcname);
|
||||
|
||||
if (*state->info->dc_name == '\\') state->info->dc_name++;
|
||||
if (*state->info->dc_name == '\\') state->info->dc_name++;
|
||||
|
||||
make_nbt_name(&name, state->info->dc_name, 0x20);
|
||||
ctx = resolve_name_send(&name, state->service->task->event_ctx,
|
||||
lp_name_resolve_order());
|
||||
|
||||
composite_continue(state->ctx, ctx, trusted_dom_info_recv_dcaddr,
|
||||
state);
|
||||
}
|
||||
|
||||
static void trusted_dom_info_recv_dcaddr(struct composite_context *ctx)
|
||||
{
|
||||
struct trusted_dom_info_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct trusted_dom_info_state);
|
||||
|
||||
state->ctx->status = resolve_name_recv(ctx, state->info,
|
||||
&state->info->dc_address);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_trusted_dom_info_recv(struct composite_context *ctx,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct wb_dom_info **result)
|
||||
{
|
||||
NTSTATUS status = composite_wait(ctx);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct trusted_dom_info_state *state =
|
||||
talloc_get_type(ctx->private_data,
|
||||
struct trusted_dom_info_state);
|
||||
*result = talloc_steal(mem_ctx, state->info);
|
||||
}
|
||||
talloc_free(ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_trusted_dom_info(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const char *domain_name,
|
||||
const struct dom_sid *sid,
|
||||
struct wb_dom_info **result)
|
||||
{
|
||||
struct composite_context *ctx =
|
||||
wb_trusted_dom_info_send(mem_ctx, service, domain_name, sid);
|
||||
return wb_trusted_dom_info_recv(ctx, mem_ctx, result);
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
A composite API for initializing a domain
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "libcli/smb_composite/smb_composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "winbind/wb_async_helpers.h"
|
||||
#include "winbind/wb_helper.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "librpc/gen_ndr/ndr_netlogon.h"
|
||||
#include "librpc/gen_ndr/ndr_lsa_c.h"
|
||||
|
||||
#include "libcli/auth/credentials.h"
|
||||
#include "libcli/security/security.h"
|
||||
|
||||
#include "libcli/ldap/ldap_client.h"
|
||||
|
||||
#include "auth/credentials/credentials.h"
|
||||
|
||||
/*
|
||||
* Initialize a domain:
|
||||
*
|
||||
* - With schannel credentials, try to open the SMB connection with the
|
||||
* machine creds. This works against W2k3SP1 with an NTLMSSP session
|
||||
* setup. Fall back to anonymous.
|
||||
*
|
||||
* - If we have schannel creds, do the auth2 and open the schannel'ed netlogon
|
||||
* pipe.
|
||||
*
|
||||
* - Open LSA. If we have machine creds, try to open with ntlmssp. Fall back
|
||||
* to schannel and then to anon bind.
|
||||
*
|
||||
* - With queryinfopolicy, verify that we're talking to the right domain
|
||||
*
|
||||
* A bit complex, but with all the combinations I think it's the best we can
|
||||
* get. NT4, W2k3 and W2k all have different combinations, but in the end we
|
||||
* have a signed&sealed lsa connection on all of them.
|
||||
*
|
||||
* Not sure if it is overkill, but it seems to work.
|
||||
*/
|
||||
|
||||
struct init_domain_state {
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_domain *domain;
|
||||
struct wbsrv_service *service;
|
||||
|
||||
struct smb_composite_connect conn;
|
||||
|
||||
struct lsa_QueryInfoPolicy queryinfo;
|
||||
};
|
||||
|
||||
static void init_domain_recv_tree(struct composite_context *ctx);
|
||||
static void init_domain_recv_netlogoncreds(struct composite_context *ctx);
|
||||
static void init_domain_recv_netlogonpipe(struct composite_context *ctx);
|
||||
static void init_domain_recv_schannel(struct composite_context *ctx);
|
||||
static void init_domain_recv_lsa(struct composite_context *ctx);
|
||||
static void init_domain_recv_queryinfo(struct rpc_request *req);
|
||||
static void init_domain_recv_ldapconn(struct composite_context *ctx);
|
||||
static void init_domain_recv_samr(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
struct wb_dom_info *dom_info)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct init_domain_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc_zero(result, struct init_domain_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->service = service;
|
||||
|
||||
state->domain = talloc(state, struct wbsrv_domain);
|
||||
if (state->domain == NULL) goto failed;
|
||||
|
||||
state->domain->info = talloc_reference(state->domain, dom_info);
|
||||
if (state->domain->info == NULL) goto failed;
|
||||
|
||||
state->domain->schannel_creds = cli_credentials_init(state->domain);
|
||||
if (state->domain->schannel_creds == NULL) goto failed;
|
||||
|
||||
cli_credentials_set_conf(state->domain->schannel_creds);
|
||||
state->ctx->status =
|
||||
cli_credentials_set_machine_account(state->domain->
|
||||
schannel_creds);
|
||||
if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;
|
||||
|
||||
state->conn.in.dest_host = dom_info->dc_address;
|
||||
state->conn.in.port = 0;
|
||||
state->conn.in.called_name = dom_info->dc_name;
|
||||
state->conn.in.service = "IPC$";
|
||||
state->conn.in.service_type = "IPC";
|
||||
state->conn.in.workgroup = dom_info->name;
|
||||
state->conn.in.credentials = state->domain->schannel_creds;
|
||||
|
||||
state->conn.in.fallback_to_anonymous = True;
|
||||
|
||||
ctx = smb_composite_connect_send(&state->conn, state->domain,
|
||||
result->event_ctx);
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = init_domain_recv_tree;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void init_domain_recv_tree(struct composite_context *ctx)
|
||||
{
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_domain_state);
|
||||
state->ctx->status = smb_composite_connect_recv(ctx, state);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
if ((state->domain->schannel_creds != NULL) &&
|
||||
(!cli_credentials_is_anonymous(state->domain->schannel_creds)) &&
|
||||
((lp_server_role() == ROLE_DOMAIN_MEMBER) &&
|
||||
(dom_sid_equal(state->domain->info->sid,
|
||||
state->service->primary_sid)))) {
|
||||
ctx = wb_get_schannel_creds_send(state,
|
||||
state->domain->schannel_creds,
|
||||
state->conn.out.tree,
|
||||
state->ctx->event_ctx);
|
||||
composite_continue(state->ctx, ctx,
|
||||
init_domain_recv_netlogoncreds, state);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = wb_connect_lsa_send(state, state->conn.out.tree, NULL);
|
||||
composite_continue(state->ctx, ctx, init_domain_recv_lsa, state);
|
||||
}
|
||||
|
||||
static void init_domain_recv_netlogoncreds(struct composite_context *ctx)
|
||||
{
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_domain_state);
|
||||
struct dcerpc_pipe *auth2_pipe;
|
||||
struct smbcli_tree *tree = NULL;
|
||||
|
||||
state->ctx->status =
|
||||
wb_get_schannel_creds_recv(ctx, state, &auth2_pipe);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
if (!lp_winbind_sealed_pipes()) {
|
||||
state->domain->netlogon_pipe = talloc_reference(state->domain,
|
||||
auth2_pipe);
|
||||
ctx = wb_connect_lsa_send(state, state->conn.out.tree, NULL);
|
||||
composite_continue(state->ctx, ctx, init_domain_recv_lsa,
|
||||
state);
|
||||
return;
|
||||
}
|
||||
|
||||
state->domain->netlogon_pipe =
|
||||
dcerpc_pipe_init(state->domain, state->ctx->event_ctx);
|
||||
if (composite_nomem(state->domain->netlogon_pipe, state->ctx)) return;
|
||||
|
||||
tree = dcerpc_smb_tree(auth2_pipe->conn);
|
||||
if (tree == NULL) {
|
||||
composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = dcerpc_pipe_open_smb_send(state->domain->netlogon_pipe->conn,
|
||||
tree, "\\netlogon");
|
||||
composite_continue(state->ctx, ctx, init_domain_recv_netlogonpipe,
|
||||
state);
|
||||
}
|
||||
|
||||
static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
|
||||
{
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_domain_state);
|
||||
|
||||
state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
state->domain->netlogon_pipe->conn->flags |=
|
||||
(DCERPC_SIGN | DCERPC_SEAL);
|
||||
ctx = dcerpc_bind_auth_send(state, state->domain->netlogon_pipe,
|
||||
&dcerpc_table_netlogon,
|
||||
state->domain->schannel_creds,
|
||||
DCERPC_AUTH_TYPE_SCHANNEL,
|
||||
DCERPC_AUTH_LEVEL_PRIVACY,
|
||||
NULL);
|
||||
composite_continue(state->ctx, ctx, init_domain_recv_schannel, state);
|
||||
}
|
||||
|
||||
static void init_domain_recv_schannel(struct composite_context *ctx)
|
||||
{
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_domain_state);
|
||||
|
||||
state->ctx->status = dcerpc_bind_auth_recv(ctx);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
ctx = wb_connect_lsa_send(state, state->conn.out.tree,
|
||||
state->domain->schannel_creds);
|
||||
composite_continue(state->ctx, ctx, init_domain_recv_lsa, state);
|
||||
}
|
||||
|
||||
static void init_domain_recv_lsa(struct composite_context *ctx)
|
||||
{
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_domain_state);
|
||||
|
||||
struct rpc_request *req;
|
||||
|
||||
state->ctx->status = wb_connect_lsa_recv(ctx, state->domain,
|
||||
&state->domain->lsa_auth_type,
|
||||
&state->domain->lsa_pipe,
|
||||
&state->domain->lsa_policy);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
/* Give the tree to the pipes. */
|
||||
talloc_unlink(state, state->conn.out.tree);
|
||||
|
||||
state->queryinfo.in.handle = state->domain->lsa_policy;
|
||||
state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
|
||||
|
||||
req = dcerpc_lsa_QueryInfoPolicy_send(state->domain->lsa_pipe, state,
|
||||
&state->queryinfo);
|
||||
composite_continue_rpc(state->ctx, req,
|
||||
init_domain_recv_queryinfo, state);
|
||||
}
|
||||
|
||||
static void init_domain_recv_queryinfo(struct rpc_request *req)
|
||||
{
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(req->async.private, struct init_domain_state);
|
||||
struct lsa_DomainInfo *dominfo;
|
||||
struct composite_context *ctx;
|
||||
const char *ldap_url;
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
state->ctx->status = state->queryinfo.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
dominfo = &state->queryinfo.out.info->account_domain;
|
||||
|
||||
if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) {
|
||||
DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
|
||||
state->domain->info->name,
|
||||
dcerpc_server_name(state->domain->lsa_pipe),
|
||||
dominfo->name.string));
|
||||
composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dom_sid_equal(state->domain->info->sid, dominfo->sid)) {
|
||||
DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
|
||||
dom_sid_string(state, state->domain->info->sid),
|
||||
dcerpc_server_name(state->domain->lsa_pipe),
|
||||
dom_sid_string(state, dominfo->sid)));
|
||||
composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
|
||||
return;
|
||||
}
|
||||
|
||||
state->domain->ldap_conn =
|
||||
ldap4_new_connection(state->domain, state->ctx->event_ctx);
|
||||
composite_nomem(state->domain->ldap_conn, state->ctx);
|
||||
|
||||
ldap_url = talloc_asprintf(state, "ldap://%s/",
|
||||
state->domain->info->dc_address);
|
||||
composite_nomem(ldap_url, state->ctx);
|
||||
|
||||
ctx = ldap_connect_send(state->domain->ldap_conn, ldap_url);
|
||||
composite_continue(state->ctx, ctx, init_domain_recv_ldapconn, state);
|
||||
}
|
||||
|
||||
static void init_domain_recv_ldapconn(struct composite_context *ctx)
|
||||
{
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_domain_state);
|
||||
|
||||
state->ctx->status = ldap_connect_recv(ctx);
|
||||
if (NT_STATUS_IS_OK(state->ctx->status)) {
|
||||
state->domain->ldap_conn->host =
|
||||
talloc_strdup(state->domain->ldap_conn,
|
||||
state->domain->info->dc_name);
|
||||
state->ctx->status =
|
||||
ldap_bind_sasl(state->domain->ldap_conn,
|
||||
state->domain->schannel_creds);
|
||||
DEBUG(0, ("ldap_bind returned %s\n",
|
||||
nt_errstr(state->ctx->status)));
|
||||
}
|
||||
|
||||
state->domain->samr_pipe =
|
||||
dcerpc_pipe_init(state->domain, state->ctx->event_ctx);
|
||||
if (composite_nomem(state->domain->samr_pipe, state->ctx)) return;
|
||||
|
||||
ctx = wb_connect_sam_send(state, state->conn.out.tree,
|
||||
state->domain->lsa_auth_type,
|
||||
state->domain->schannel_creds,
|
||||
state->domain->info->sid);
|
||||
composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
|
||||
}
|
||||
|
||||
static void init_domain_recv_samr(struct composite_context *ctx)
|
||||
{
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct init_domain_state);
|
||||
|
||||
state->ctx->status = wb_connect_sam_recv(
|
||||
ctx, state->domain, &state->domain->samr_pipe,
|
||||
&state->domain->samr_handle, &state->domain->domain_handle);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_init_domain_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_domain **result)
|
||||
{
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct init_domain_state *state =
|
||||
talloc_get_type(c->private_data,
|
||||
struct init_domain_state);
|
||||
*result = talloc_steal(mem_ctx, state->domain);
|
||||
}
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_init_domain(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
|
||||
struct wb_dom_info *dom_info,
|
||||
struct wbsrv_domain **result)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_init_domain_send(mem_ctx, service, dom_info);
|
||||
return wb_init_domain_recv(c, mem_ctx, result);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Main winbindd irpc handlers
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2006
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "lib/messaging/irpc.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "librpc/gen_ndr/ndr_winbind.h"
|
||||
#include "smbd/service_task.h"
|
||||
|
||||
struct wb_irpc_SamLogon_state {
|
||||
struct irpc_message *msg;
|
||||
struct winbind_SamLogon *req;
|
||||
};
|
||||
|
||||
static void wb_irpc_SamLogon_callback(struct composite_context *ctx);
|
||||
|
||||
static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
|
||||
struct winbind_SamLogon *req)
|
||||
{
|
||||
struct wbsrv_service *service = talloc_get_type(msg->private,
|
||||
struct wbsrv_service);
|
||||
struct wb_irpc_SamLogon_state *s;
|
||||
struct composite_context *ctx;
|
||||
|
||||
DEBUG(5, ("wb_irpc_SamLogon called\n"));
|
||||
|
||||
s = talloc(msg, struct wb_irpc_SamLogon_state);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s);
|
||||
|
||||
s->msg = msg;
|
||||
s->req = req;
|
||||
|
||||
ctx = wb_sam_logon_send(msg, service, req);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
ctx->async.fn = wb_irpc_SamLogon_callback;
|
||||
ctx->async.private_data = s;
|
||||
|
||||
msg->defer_reply = True;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void wb_irpc_SamLogon_callback(struct composite_context *ctx)
|
||||
{
|
||||
struct wb_irpc_SamLogon_state *s = talloc_get_type(ctx->async.private_data,
|
||||
struct wb_irpc_SamLogon_state);
|
||||
NTSTATUS status;
|
||||
|
||||
DEBUG(5, ("wb_irpc_SamLogon_callback called\n"));
|
||||
|
||||
status = wb_sam_logon_recv(ctx, s, s->req);
|
||||
|
||||
irpc_send_reply(s->msg, status);
|
||||
}
|
||||
|
||||
NTSTATUS wbsrv_init_irpc(struct wbsrv_service *service)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
irpc_add_name(service->task->msg_ctx, "winbind_server");
|
||||
|
||||
status = IRPC_REGISTER(service->task->msg_ctx, winbind, WINBIND_SAMLOGON,
|
||||
wb_irpc_SamLogon, service);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Authenticate a user
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
#include "libcli/auth/libcli_auth.h"
|
||||
#include "librpc/gen_ndr/ndr_netlogon.h"
|
||||
#include "librpc/gen_ndr/ndr_netlogon_c.h"
|
||||
|
||||
/* Oh, there is so much to keep an eye on when authenticating a user. Oh my! */
|
||||
struct pam_auth_crap_state {
|
||||
struct composite_context *ctx;
|
||||
struct event_context *event_ctx;
|
||||
uint32_t logon_parameters;
|
||||
const char *domain_name;
|
||||
const char *user_name;
|
||||
char *unix_username;
|
||||
const char *workstation;
|
||||
DATA_BLOB chal, nt_resp, lm_resp;
|
||||
|
||||
struct creds_CredentialState *creds_state;
|
||||
struct netr_Authenticator auth, auth2;
|
||||
struct netr_NetworkInfo ninfo;
|
||||
struct netr_LogonSamLogon r;
|
||||
|
||||
struct netr_UserSessionKey user_session_key;
|
||||
struct netr_LMSessionKey lm_key;
|
||||
DATA_BLOB info3;
|
||||
};
|
||||
|
||||
/*
|
||||
* NTLM authentication.
|
||||
*/
|
||||
|
||||
static void pam_auth_crap_recv_domain(struct composite_context *ctx);
|
||||
static void pam_auth_crap_recv_samlogon(struct rpc_request *req);
|
||||
|
||||
struct composite_context *wb_cmd_pam_auth_crap_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
uint32_t logon_parameters,
|
||||
const char *domain,
|
||||
const char *user,
|
||||
const char *workstation,
|
||||
DATA_BLOB chal,
|
||||
DATA_BLOB nt_resp,
|
||||
DATA_BLOB lm_resp)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct pam_auth_crap_state *state;
|
||||
|
||||
result = talloc(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct pam_auth_crap_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->logon_parameters = logon_parameters;
|
||||
|
||||
state->domain_name = talloc_strdup(state, domain);
|
||||
if (state->domain_name == NULL) goto failed;
|
||||
|
||||
state->user_name = talloc_strdup(state, user);
|
||||
if (state->user_name == NULL) goto failed;
|
||||
|
||||
state->unix_username = NULL;
|
||||
|
||||
state->workstation = talloc_strdup(state, workstation);
|
||||
if (state->workstation == NULL) goto failed;
|
||||
|
||||
state->chal = data_blob_talloc(state, chal.data, chal.length);
|
||||
if ((chal.data != NULL) && (state->chal.data == NULL)) goto failed;
|
||||
|
||||
state->nt_resp = data_blob_talloc(state, nt_resp.data, nt_resp.length);
|
||||
if ((nt_resp.data != NULL) &&
|
||||
(state->nt_resp.data == NULL)) goto failed;
|
||||
|
||||
state->lm_resp = data_blob_talloc(state, lm_resp.data, lm_resp.length);
|
||||
if ((lm_resp.data != NULL) &&
|
||||
(state->lm_resp.data == NULL)) goto failed;
|
||||
|
||||
ctx = wb_sid2domain_send(state, service, service->primary_sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
|
||||
ctx->async.fn = pam_auth_crap_recv_domain;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
NTLM Authentication
|
||||
|
||||
Send of a SamLogon request to authenticate a user.
|
||||
*/
|
||||
static void pam_auth_crap_recv_domain(struct composite_context *ctx)
|
||||
{
|
||||
struct pam_auth_crap_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct pam_auth_crap_state);
|
||||
struct rpc_request *req;
|
||||
struct wbsrv_domain *domain;
|
||||
|
||||
state->ctx->status = wb_sid2domain_recv(ctx, &domain);
|
||||
state->creds_state =
|
||||
cli_credentials_get_netlogon_creds(domain->schannel_creds);
|
||||
|
||||
creds_client_authenticator(state->creds_state, &state->auth);
|
||||
|
||||
state->ninfo.identity_info.account_name.string = state->user_name;
|
||||
state->ninfo.identity_info.domain_name.string = state->domain_name;
|
||||
state->ninfo.identity_info.parameter_control = state->logon_parameters;
|
||||
state->ninfo.identity_info.logon_id_low = 0;
|
||||
state->ninfo.identity_info.logon_id_high = 0;
|
||||
state->ninfo.identity_info.workstation.string = state->workstation;
|
||||
|
||||
SMB_ASSERT(state->chal.length == sizeof(state->ninfo.challenge));
|
||||
memcpy(state->ninfo.challenge, state->chal.data,
|
||||
sizeof(state->ninfo.challenge));
|
||||
|
||||
state->ninfo.nt.length = state->nt_resp.length;
|
||||
state->ninfo.nt.data = state->nt_resp.data;
|
||||
state->ninfo.lm.length = state->lm_resp.length;
|
||||
state->ninfo.lm.data = state->lm_resp.data;
|
||||
|
||||
state->r.in.server_name = talloc_asprintf(
|
||||
state, "\\\\%s", dcerpc_server_name(domain->netlogon_pipe));
|
||||
if (composite_nomem(state->r.in.server_name, state->ctx)) return;
|
||||
|
||||
ZERO_STRUCT(state->auth2);
|
||||
|
||||
state->r.in.computer_name =
|
||||
cli_credentials_get_workstation(domain->schannel_creds);
|
||||
state->r.in.credential = &state->auth;
|
||||
state->r.in.return_authenticator = &state->auth2;
|
||||
state->r.in.logon_level = 2;
|
||||
state->r.in.validation_level = 3;
|
||||
state->r.in.logon.network = &state->ninfo;
|
||||
state->r.out.return_authenticator = NULL;
|
||||
|
||||
req = dcerpc_netr_LogonSamLogon_send(domain->netlogon_pipe, state,
|
||||
&state->r);
|
||||
composite_continue_rpc(state->ctx, req, pam_auth_crap_recv_samlogon,
|
||||
state);
|
||||
}
|
||||
|
||||
/*
|
||||
NTLM Authentication
|
||||
|
||||
Check the SamLogon reply, decrypt and parse out the session keys and the
|
||||
info3 structure.
|
||||
*/
|
||||
static void pam_auth_crap_recv_samlogon(struct rpc_request *req)
|
||||
{
|
||||
struct pam_auth_crap_state *state =
|
||||
talloc_get_type(req->async.private,
|
||||
struct pam_auth_crap_state);
|
||||
struct netr_SamBaseInfo *base;
|
||||
DATA_BLOB tmp_blob;
|
||||
|
||||
state->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
if ((state->r.out.return_authenticator == NULL) ||
|
||||
(!creds_client_check(state->creds_state,
|
||||
&state->r.out.return_authenticator->cred))) {
|
||||
DEBUG(0, ("Credentials check failed!\n"));
|
||||
composite_error(state->ctx, NT_STATUS_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
state->ctx->status = state->r.out.result;
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
/* Decrypt the session keys before we reform the info3, so the
|
||||
* person on the other end of winbindd pipe doesn't have to.
|
||||
* They won't have the encryption key anyway */
|
||||
creds_decrypt_samlogon(state->creds_state,
|
||||
state->r.in.validation_level,
|
||||
&state->r.out.validation);
|
||||
|
||||
state->ctx->status = ndr_push_struct_blob(
|
||||
&tmp_blob, state, state->r.out.validation.sam3,
|
||||
(ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
/* The Samba3 protocol is a bit broken (due to non-IDL
|
||||
* heritage, so for compatability we must add a non-zero 4
|
||||
* bytes to the info3 */
|
||||
state->info3 = data_blob_talloc(state, NULL, tmp_blob.length+4);
|
||||
if (composite_nomem(state->info3.data, state->ctx)) return;
|
||||
|
||||
SIVAL(state->info3.data, 0, 1);
|
||||
memcpy(state->info3.data+4, tmp_blob.data, tmp_blob.length);
|
||||
|
||||
/* We actually only ask for level 3, and assume it above, but
|
||||
* anyway... */
|
||||
|
||||
base = NULL;
|
||||
switch(state->r.in.validation_level) {
|
||||
case 2:
|
||||
base = &state->r.out.validation.sam2->base;
|
||||
break;
|
||||
case 3:
|
||||
base = &state->r.out.validation.sam3->base;
|
||||
break;
|
||||
case 6:
|
||||
base = &state->r.out.validation.sam6->base;
|
||||
break;
|
||||
}
|
||||
if (base == NULL) {
|
||||
composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
state->user_session_key = base->key;
|
||||
state->lm_key = base->LMSessKey;
|
||||
|
||||
/* Give the caller the most accurate username possible.
|
||||
* Assists where case sensitive comparisons may be done by our
|
||||
* ntlm_auth callers */
|
||||
if (base->account_name.string) {
|
||||
state->user_name = base->account_name.string;
|
||||
talloc_steal(state, base->account_name.string);
|
||||
}
|
||||
if (base->domain.string) {
|
||||
state->domain_name = base->domain.string;
|
||||
talloc_steal(state, base->domain.string);
|
||||
}
|
||||
|
||||
state->unix_username = talloc_asprintf(state, "%s%s%s",
|
||||
state->domain_name,
|
||||
lp_winbind_separator(),
|
||||
state->user_name);
|
||||
if (composite_nomem(state->unix_username, state->ctx)) return;
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_pam_auth_crap_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
DATA_BLOB *info3,
|
||||
struct netr_UserSessionKey *user_session_key,
|
||||
struct netr_LMSessionKey *lm_key,
|
||||
char **unix_username)
|
||||
{
|
||||
struct pam_auth_crap_state *state =
|
||||
talloc_get_type(c->private_data, struct pam_auth_crap_state);
|
||||
NTSTATUS status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
info3->length = state->info3.length;
|
||||
info3->data = talloc_steal(mem_ctx, state->info3.data);
|
||||
*user_session_key = state->user_session_key;
|
||||
*lm_key = state->lm_key;
|
||||
*unix_username = talloc_steal(mem_ctx, state->unix_username);
|
||||
}
|
||||
talloc_free(state);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_pam_auth_crap(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
uint32_t logon_parameters,
|
||||
const char *domain, const char *user,
|
||||
const char *workstation,
|
||||
DATA_BLOB chal, DATA_BLOB nt_resp,
|
||||
DATA_BLOB lm_resp,
|
||||
DATA_BLOB *info3,
|
||||
struct netr_UserSessionKey *user_session_key,
|
||||
struct netr_LMSessionKey *lm_key,
|
||||
char **unix_username)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_cmd_pam_auth_crap_send(mem_ctx, service, logon_parameters,
|
||||
domain, user, workstation,
|
||||
chal, nt_resp, lm_resp);
|
||||
return wb_cmd_pam_auth_crap_recv(c, mem_ctx, info3, user_session_key,
|
||||
lm_key, unix_username);
|
||||
}
|
||||
|
||||
struct composite_context *wb_cmd_pam_auth_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const char *domain,
|
||||
const char *user,
|
||||
const char *password)
|
||||
{
|
||||
struct cli_credentials *credentials;
|
||||
const char *workstation;
|
||||
NTSTATUS status;
|
||||
|
||||
DATA_BLOB chal, nt_resp, lm_resp, names_blob;
|
||||
int flags = CLI_CRED_NTLM_AUTH;
|
||||
if (lp_client_lanman_auth()) {
|
||||
flags |= CLI_CRED_LANMAN_AUTH;
|
||||
}
|
||||
|
||||
if (lp_client_ntlmv2_auth()) {
|
||||
flags |= CLI_CRED_NTLMv2_AUTH;
|
||||
}
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_pam_auth called\n"));
|
||||
|
||||
credentials = cli_credentials_init(mem_ctx);
|
||||
if (!credentials) {
|
||||
return NULL;
|
||||
}
|
||||
cli_credentials_set_conf(credentials);
|
||||
cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
|
||||
cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
|
||||
|
||||
cli_credentials_set_password(credentials, password, CRED_SPECIFIED);
|
||||
|
||||
chal = data_blob_talloc(mem_ctx, NULL, 8);
|
||||
if (!chal.data) {
|
||||
return NULL;
|
||||
}
|
||||
generate_random_buffer(chal.data, chal.length);
|
||||
cli_credentials_get_ntlm_username_domain(credentials, mem_ctx,
|
||||
&user, &domain);
|
||||
/* for best compatability with multiple vitual netbios names
|
||||
* on the host, this should be generated from the
|
||||
* cli_credentials associated with the machine account */
|
||||
workstation = cli_credentials_get_workstation(credentials);
|
||||
|
||||
names_blob = NTLMv2_generate_names_blob(
|
||||
mem_ctx,
|
||||
cli_credentials_get_workstation(credentials),
|
||||
cli_credentials_get_domain(credentials));
|
||||
|
||||
status = cli_credentials_get_ntlm_response(
|
||||
credentials, mem_ctx, &flags, chal, names_blob,
|
||||
&lm_resp, &nt_resp, NULL, NULL);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return NULL;
|
||||
}
|
||||
return wb_cmd_pam_auth_crap_send(mem_ctx, service,
|
||||
0 /* logon parameters */,
|
||||
domain, user, workstation,
|
||||
chal, nt_resp, lm_resp);
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_pam_auth_recv(struct composite_context *c)
|
||||
{
|
||||
struct pam_auth_crap_state *state =
|
||||
talloc_get_type(c->private_data, struct pam_auth_crap_state);
|
||||
NTSTATUS status = composite_wait(c);
|
||||
talloc_free(state);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_cmd_pam_auth(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
|
||||
const char *domain, const char *user,
|
||||
const char *password)
|
||||
{
|
||||
struct composite_context *c =
|
||||
wb_cmd_pam_auth_send(mem_ctx, service, domain, user, password);
|
||||
return wb_cmd_pam_auth_recv(c);
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Do a netr_LogonSamLogon to a remote DC
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
|
||||
Copyright (C) Stefan Metzmacher 2006
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "auth/credentials/credentials.h"
|
||||
#include "libcli/auth/libcli_auth.h"
|
||||
#include "librpc/gen_ndr/ndr_netlogon.h"
|
||||
#include "librpc/gen_ndr/ndr_netlogon_c.h"
|
||||
#include "librpc/gen_ndr/winbind.h"
|
||||
|
||||
struct wb_sam_logon_state {
|
||||
struct composite_context *ctx;
|
||||
|
||||
struct winbind_SamLogon *req;
|
||||
|
||||
struct creds_CredentialState *creds_state;
|
||||
struct netr_Authenticator auth1, auth2;
|
||||
|
||||
TALLOC_CTX *r_mem_ctx;
|
||||
struct netr_LogonSamLogon r;
|
||||
};
|
||||
|
||||
static void wb_sam_logon_recv_domain(struct composite_context *ctx);
|
||||
static void wb_sam_logon_recv_samlogon(struct rpc_request *req);
|
||||
|
||||
/*
|
||||
Find the connection to the DC (or find an existing connection)
|
||||
*/
|
||||
struct composite_context *wb_sam_logon_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
struct winbind_SamLogon *req)
|
||||
{
|
||||
struct composite_context *c, *creq;
|
||||
struct wb_sam_logon_state *s;
|
||||
|
||||
c = composite_create(mem_ctx, service->task->event_ctx);
|
||||
if (!c) return NULL;
|
||||
|
||||
s = talloc_zero(c, struct wb_sam_logon_state);
|
||||
if (composite_nomem(s, c)) return c;
|
||||
s->ctx = c;
|
||||
s->req = req;
|
||||
|
||||
c->private_data = s;
|
||||
|
||||
creq = wb_sid2domain_send(s, service, service->primary_sid);
|
||||
composite_continue(c, creq, wb_sam_logon_recv_domain, s);
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
Finish the connection to the DC
|
||||
Send of a SamLogon request to authenticate a user.
|
||||
*/
|
||||
static void wb_sam_logon_recv_domain(struct composite_context *creq)
|
||||
{
|
||||
struct wb_sam_logon_state *s = talloc_get_type(creq->async.private_data,
|
||||
struct wb_sam_logon_state);
|
||||
struct rpc_request *req;
|
||||
struct wbsrv_domain *domain;
|
||||
|
||||
s->ctx->status = wb_sid2domain_recv(creq, &domain);
|
||||
if (!composite_is_ok(s->ctx)) return;
|
||||
|
||||
s->creds_state = cli_credentials_get_netlogon_creds(domain->schannel_creds);
|
||||
creds_client_authenticator(s->creds_state, &s->auth1);
|
||||
|
||||
s->r.in.server_name = talloc_asprintf(s, "\\\\%s",
|
||||
dcerpc_server_name(domain->netlogon_pipe));
|
||||
if (composite_nomem(s->r.in.server_name, s->ctx)) return;
|
||||
|
||||
s->r.in.computer_name = cli_credentials_get_workstation(domain->schannel_creds);
|
||||
s->r.in.credential = &s->auth1;
|
||||
s->r.in.return_authenticator = &s->auth2;
|
||||
s->r.in.logon_level = s->req->in.logon_level;
|
||||
s->r.in.logon = s->req->in.logon;
|
||||
s->r.in.validation_level = s->req->in.validation_level;
|
||||
s->r.out.return_authenticator = NULL;
|
||||
|
||||
/*
|
||||
* use a new talloc context for the LogonSamLogon call
|
||||
* because then we can just to a talloc_steal on this context
|
||||
* in the final _recv() function to give the caller all the content of
|
||||
* the s->r.out.validation
|
||||
*/
|
||||
s->r_mem_ctx = talloc_new(s);
|
||||
if (composite_nomem(s->r_mem_ctx, s->ctx)) return;
|
||||
|
||||
req = dcerpc_netr_LogonSamLogon_send(domain->netlogon_pipe, s->r_mem_ctx, &s->r);
|
||||
composite_continue_rpc(s->ctx, req, wb_sam_logon_recv_samlogon, s);
|
||||
}
|
||||
|
||||
/*
|
||||
NTLM Authentication
|
||||
|
||||
Check the SamLogon reply and decrypt the session keys
|
||||
*/
|
||||
static void wb_sam_logon_recv_samlogon(struct rpc_request *req)
|
||||
{
|
||||
struct wb_sam_logon_state *s = talloc_get_type(req->async.private,
|
||||
struct wb_sam_logon_state);
|
||||
|
||||
s->ctx->status = dcerpc_ndr_request_recv(req);
|
||||
if (!composite_is_ok(s->ctx)) return;
|
||||
|
||||
s->ctx->status = s->r.out.result;
|
||||
if (!composite_is_ok(s->ctx)) return;
|
||||
|
||||
if ((s->r.out.return_authenticator == NULL) ||
|
||||
(!creds_client_check(s->creds_state,
|
||||
&s->r.out.return_authenticator->cred))) {
|
||||
DEBUG(0, ("Credentials check failed!\n"));
|
||||
composite_error(s->ctx, NT_STATUS_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decrypt the session keys before we reform the info3, so the
|
||||
* person on the other end of winbindd pipe doesn't have to.
|
||||
* They won't have the encryption key anyway */
|
||||
creds_decrypt_samlogon(s->creds_state,
|
||||
s->r.in.validation_level,
|
||||
&s->r.out.validation);
|
||||
|
||||
composite_done(s->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_sam_logon_recv(struct composite_context *c,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct winbind_SamLogon *req)
|
||||
{
|
||||
struct wb_sam_logon_state *s = talloc_get_type(c->private_data,
|
||||
struct wb_sam_logon_state);
|
||||
NTSTATUS status = composite_wait(c);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
talloc_steal(mem_ctx, s->r_mem_ctx);
|
||||
req->out.validation = s->r.out.validation;
|
||||
req->out.authoritative = 1;
|
||||
req->out.flags = 0;
|
||||
}
|
||||
|
||||
talloc_free(s);
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,663 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Main winbindd samba3 server routines
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "nsswitch/winbindd_nss.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "winbind/wb_async_helpers.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "version.h"
|
||||
#include "librpc/gen_ndr/netlogon.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "auth/pam_errors.h"
|
||||
|
||||
/*
|
||||
Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
|
||||
*/
|
||||
|
||||
static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
|
||||
struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct winbindd_response *resp = &s3call->response;
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
resp->result = WINBINDD_ERROR;
|
||||
WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
|
||||
nt_errstr(status));
|
||||
WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
|
||||
get_friendly_nt_error_msg(status));
|
||||
} else {
|
||||
resp->result = WINBINDD_OK;
|
||||
}
|
||||
|
||||
resp->data.auth.pam_error = nt_status_to_pam(status);
|
||||
resp->data.auth.nt_status = NT_STATUS_V(status);
|
||||
|
||||
wbsrv_samba3_send_reply(s3call);
|
||||
}
|
||||
|
||||
/*
|
||||
Send of a generic reply to a Samba3 query
|
||||
*/
|
||||
|
||||
static void wbsrv_samba3_async_epilogue(NTSTATUS status,
|
||||
struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct winbindd_response *resp = &s3call->response;
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
resp->result = WINBINDD_OK;
|
||||
} else {
|
||||
resp->result = WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
wbsrv_samba3_send_reply(s3call);
|
||||
}
|
||||
|
||||
/*
|
||||
Boilerplate commands, simple queries without network traffic
|
||||
*/
|
||||
|
||||
NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
s3call->response.data.info.winbind_separator = *lp_winbind_separator();
|
||||
WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
|
||||
SAMBA_VERSION_STRING);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
|
||||
lp_workgroup());
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
|
||||
lp_netbios_name());
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
s3call->response.extra_data =
|
||||
smbd_tmp_path(s3call, WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s3call->response.extra_data);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Validate that we have a working pipe to the domain controller.
|
||||
Return any NT error found in the process
|
||||
*/
|
||||
|
||||
static void checkmachacc_recv_creds(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_check_machacc called\n"));
|
||||
|
||||
ctx = wb_cmd_checkmachacc_send(s3call->call);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
ctx->async.fn = checkmachacc_recv_creds;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void checkmachacc_recv_creds(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
NTSTATUS status;
|
||||
|
||||
status = wb_cmd_checkmachacc_recv(ctx);
|
||||
|
||||
wbsrv_samba3_async_auth_epilogue(status, s3call);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Find the name of a suitable domain controller, by query on the
|
||||
netlogon pipe to the DC.
|
||||
*/
|
||||
|
||||
static void getdcname_recv_dc(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service =
|
||||
s3call->wbconn->listen_socket->service;
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
|
||||
|
||||
ctx = wb_cmd_getdcname_send(s3call, service,
|
||||
s3call->request.domain_name);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
ctx->async.fn = getdcname_recv_dc;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void getdcname_recv_dc(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
const char *dcname;
|
||||
NTSTATUS status;
|
||||
|
||||
status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
|
||||
|
||||
done:
|
||||
wbsrv_samba3_async_epilogue(status, s3call);
|
||||
}
|
||||
|
||||
/*
|
||||
Lookup a user's domain groups
|
||||
*/
|
||||
|
||||
static void userdomgroups_recv_groups(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
struct dom_sid *sid;
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
|
||||
|
||||
sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
|
||||
if (sid == NULL) {
|
||||
DEBUG(5, ("Could not parse sid %s\n",
|
||||
s3call->request.data.sid));
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ctx = wb_cmd_userdomgroups_send(
|
||||
s3call, s3call->wbconn->listen_socket->service, sid);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
ctx->async.fn = userdomgroups_recv_groups;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void userdomgroups_recv_groups(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
int i, num_sids;
|
||||
struct dom_sid **sids;
|
||||
char *sids_string;
|
||||
NTSTATUS status;
|
||||
|
||||
status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
sids_string = talloc_strdup(s3call, "");
|
||||
if (sids_string == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i=0; i<num_sids; i++) {
|
||||
sids_string = talloc_asprintf_append(
|
||||
sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
|
||||
}
|
||||
|
||||
if (sids_string == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
s3call->response.extra_data = sids_string;
|
||||
s3call->response.length += strlen(sids_string)+1;
|
||||
s3call->response.data.num_entries = num_sids;
|
||||
|
||||
done:
|
||||
wbsrv_samba3_async_epilogue(status, s3call);
|
||||
}
|
||||
|
||||
/*
|
||||
Lookup the list of SIDs for a user
|
||||
*/
|
||||
static void usersids_recv_sids(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
struct dom_sid *sid;
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_usersids called\n"));
|
||||
|
||||
sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
|
||||
if (sid == NULL) {
|
||||
DEBUG(5, ("Could not parse sid %s\n",
|
||||
s3call->request.data.sid));
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ctx = wb_cmd_usersids_send(
|
||||
s3call, s3call->wbconn->listen_socket->service, sid);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
ctx->async.fn = usersids_recv_sids;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void usersids_recv_sids(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
int i, num_sids;
|
||||
struct dom_sid **sids;
|
||||
char *sids_string;
|
||||
NTSTATUS status;
|
||||
|
||||
status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
sids_string = talloc_strdup(s3call, "");
|
||||
if (sids_string == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i=0; i<num_sids; i++) {
|
||||
sids_string = talloc_asprintf_append(
|
||||
sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
|
||||
if (sids_string == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
s3call->response.extra_data = sids_string;
|
||||
s3call->response.length += strlen(sids_string);
|
||||
s3call->response.data.num_entries = num_sids;
|
||||
|
||||
/* Hmmmm. Nasty protocol -- who invented the zeros between the
|
||||
* SIDs? Hmmm. Could have been me -- vl */
|
||||
|
||||
while (*sids_string != '\0') {
|
||||
if ((*sids_string) == '\n') {
|
||||
*sids_string = '\0';
|
||||
}
|
||||
sids_string += 1;
|
||||
}
|
||||
|
||||
done:
|
||||
wbsrv_samba3_async_epilogue(status, s3call);
|
||||
}
|
||||
|
||||
/*
|
||||
Lookup a DOMAIN\\user style name, and return a SID
|
||||
*/
|
||||
|
||||
static void lookupname_recv_sid(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service =
|
||||
s3call->wbconn->listen_socket->service;
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
|
||||
|
||||
ctx = wb_cmd_lookupname_send(s3call, service,
|
||||
s3call->request.data.name.dom_name,
|
||||
s3call->request.data.name.name);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
/* setup the callbacks */
|
||||
ctx->async.fn = lookupname_recv_sid;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void lookupname_recv_sid(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
struct wb_sid_object *sid;
|
||||
NTSTATUS status;
|
||||
|
||||
status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
s3call->response.data.sid.type = sid->type;
|
||||
WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
|
||||
dom_sid_string(s3call, sid->sid));
|
||||
|
||||
done:
|
||||
wbsrv_samba3_async_epilogue(status, s3call);
|
||||
}
|
||||
|
||||
/*
|
||||
Lookup a SID, and return a DOMAIN\\user style name
|
||||
*/
|
||||
|
||||
static void lookupsid_recv_name(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service =
|
||||
s3call->wbconn->listen_socket->service;
|
||||
struct dom_sid *sid;
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
|
||||
|
||||
sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
|
||||
if (sid == NULL) {
|
||||
DEBUG(5, ("Could not parse sid %s\n",
|
||||
s3call->request.data.sid));
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ctx = wb_cmd_lookupsid_send(s3call, service, sid);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
/* setup the callbacks */
|
||||
ctx->async.fn = lookupsid_recv_name;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void lookupsid_recv_name(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
struct wb_sid_object *sid;
|
||||
NTSTATUS status;
|
||||
|
||||
status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
s3call->response.data.name.type = sid->type;
|
||||
WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
|
||||
sid->domain);
|
||||
WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
|
||||
|
||||
done:
|
||||
wbsrv_samba3_async_epilogue(status, s3call);
|
||||
}
|
||||
|
||||
/*
|
||||
Challenge-response authentication. This interface is used by
|
||||
ntlm_auth and the smbd auth subsystem to pass NTLM authentication
|
||||
requests along a common pipe to the domain controller.
|
||||
|
||||
The return value (in the async reply) may include the 'info3'
|
||||
(effectivly most things you would want to know about the user), or
|
||||
the NT and LM session keys seperated.
|
||||
*/
|
||||
|
||||
static void pam_auth_crap_recv(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service =
|
||||
s3call->wbconn->listen_socket->service;
|
||||
DATA_BLOB chal, nt_resp, lm_resp;
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
|
||||
|
||||
chal.data = s3call->request.data.auth_crap.chal;
|
||||
chal.length = sizeof(s3call->request.data.auth_crap.chal);
|
||||
nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
|
||||
nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
|
||||
lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
|
||||
lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
|
||||
|
||||
ctx = wb_cmd_pam_auth_crap_send(
|
||||
s3call, service,
|
||||
s3call->request.data.auth_crap.logon_parameters,
|
||||
s3call->request.data.auth_crap.domain,
|
||||
s3call->request.data.auth_crap.user,
|
||||
s3call->request.data.auth_crap.workstation,
|
||||
chal, nt_resp, lm_resp);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
ctx->async.fn = pam_auth_crap_recv;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void pam_auth_crap_recv(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
NTSTATUS status;
|
||||
DATA_BLOB info3;
|
||||
struct netr_UserSessionKey user_session_key;
|
||||
struct netr_LMSessionKey lm_key;
|
||||
char *unix_username;
|
||||
|
||||
status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
|
||||
&user_session_key, &lm_key, &unix_username);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
|
||||
memcpy(s3call->response.data.auth.user_session_key,
|
||||
&user_session_key.key,
|
||||
sizeof(s3call->response.data.auth.user_session_key));
|
||||
}
|
||||
|
||||
if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
|
||||
s3call->response.extra_data = info3.data;
|
||||
s3call->response.length += info3.length;
|
||||
}
|
||||
|
||||
if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
|
||||
memcpy(s3call->response.data.auth.first_8_lm_hash,
|
||||
lm_key.key,
|
||||
sizeof(s3call->response.data.auth.first_8_lm_hash));
|
||||
}
|
||||
|
||||
if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
|
||||
s3call->response.extra_data = unix_username;
|
||||
s3call->response.length += strlen(unix_username)+1;
|
||||
}
|
||||
|
||||
done:
|
||||
wbsrv_samba3_async_auth_epilogue(status, s3call);
|
||||
}
|
||||
|
||||
/* Helper function: Split a domain\\user string into it's parts,
|
||||
* because the client supplies it as one string */
|
||||
|
||||
static BOOL samba3_parse_domuser(TALLOC_CTX *mem_ctx, const char *domuser,
|
||||
char **domain, char **user)
|
||||
{
|
||||
char *p = strchr(domuser, *lp_winbind_separator());
|
||||
|
||||
if (p == NULL) {
|
||||
*domain = talloc_strdup(mem_ctx, lp_workgroup());
|
||||
} else {
|
||||
*domain = talloc_strndup(mem_ctx, domuser,
|
||||
PTR_DIFF(p, domuser));
|
||||
domuser = p+1;
|
||||
}
|
||||
|
||||
*user = talloc_strdup(mem_ctx, domuser);
|
||||
|
||||
return ((*domain != NULL) && (*user != NULL));
|
||||
}
|
||||
|
||||
/* Plaintext authentication
|
||||
|
||||
This interface is used by ntlm_auth in it's 'basic' authentication
|
||||
mode, as well as by pam_winbind to authenticate users where we are
|
||||
given a plaintext password.
|
||||
*/
|
||||
|
||||
static void pam_auth_recv(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service =
|
||||
s3call->wbconn->listen_socket->service;
|
||||
char *user, *domain;
|
||||
|
||||
if (!samba3_parse_domuser(s3call,
|
||||
s3call->request.data.auth.user,
|
||||
&domain, &user)) {
|
||||
return NT_STATUS_NO_SUCH_USER;
|
||||
}
|
||||
|
||||
ctx = wb_cmd_pam_auth_send(s3call, service, domain, user,
|
||||
s3call->request.data.auth.pass);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
ctx->async.fn = pam_auth_recv;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void pam_auth_recv(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
NTSTATUS status;
|
||||
|
||||
status = wb_cmd_pam_auth_recv(ctx);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
done:
|
||||
wbsrv_samba3_async_auth_epilogue(status, s3call);
|
||||
}
|
||||
|
||||
/*
|
||||
List trusted domains
|
||||
*/
|
||||
|
||||
static void list_trustdom_recv_doms(struct composite_context *ctx);
|
||||
|
||||
NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service =
|
||||
s3call->wbconn->listen_socket->service;
|
||||
|
||||
DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
|
||||
|
||||
ctx = wb_cmd_list_trustdoms_send(s3call, service);
|
||||
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
||||
|
||||
ctx->async.fn = list_trustdom_recv_doms;
|
||||
ctx->async.private_data = s3call;
|
||||
s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void list_trustdom_recv_doms(struct composite_context *ctx)
|
||||
{
|
||||
struct wbsrv_samba3_call *s3call =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct wbsrv_samba3_call);
|
||||
int i, num_domains;
|
||||
struct wb_dom_info **domains;
|
||||
NTSTATUS status;
|
||||
char *result;
|
||||
|
||||
status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
|
||||
&domains);
|
||||
if (!NT_STATUS_IS_OK(status)) goto done;
|
||||
|
||||
result = talloc_strdup(s3call, "");
|
||||
if (result == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i=0; i<num_domains; i++) {
|
||||
result = talloc_asprintf_append(
|
||||
result, "%s\\%s\\%s",
|
||||
domains[i]->name, domains[i]->name,
|
||||
dom_sid_string(s3call, domains[i]->sid));
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
s3call->response.result = WINBINDD_OK;
|
||||
if (num_domains > 0) {
|
||||
s3call->response.extra_data = result;
|
||||
s3call->response.length += strlen(result)+1;
|
||||
}
|
||||
|
||||
done:
|
||||
wbsrv_samba3_async_epilogue(status, s3call);
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Main winbindd samba3 server routines
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "nsswitch/winbindd_nss.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_stream.h"
|
||||
#include "lib/stream/packet.h"
|
||||
|
||||
/*
|
||||
work out if a packet is complete for protocols that use a 32 bit host byte
|
||||
order length
|
||||
*/
|
||||
NTSTATUS wbsrv_samba3_packet_full_request(void *private, DATA_BLOB blob, size_t *size)
|
||||
{
|
||||
uint32_t *len;
|
||||
if (blob.length < 4) {
|
||||
return STATUS_MORE_ENTRIES;
|
||||
}
|
||||
len = (uint32_t *)blob.data;
|
||||
*size = (*len);
|
||||
if (*size > blob.length) {
|
||||
return STATUS_MORE_ENTRIES;
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS wbsrv_samba3_pull_request(DATA_BLOB blob, struct wbsrv_connection *wbconn,
|
||||
struct wbsrv_samba3_call **_call)
|
||||
{
|
||||
struct wbsrv_samba3_call *call;
|
||||
|
||||
if (blob.length != sizeof(call->request)) {
|
||||
DEBUG(0,("wbsrv_samba3_pull_request: invalid blob length %lu should be %lu\n"
|
||||
" make sure you use the correct winbind client tools!\n",
|
||||
(long)blob.length, (long)sizeof(call->request)));
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
call = talloc_zero(wbconn, struct wbsrv_samba3_call);
|
||||
NT_STATUS_HAVE_NO_MEMORY(call);
|
||||
|
||||
/* the packet layout is the same as the in memory layout of the request, so just copy it */
|
||||
memcpy(&call->request, blob.data, sizeof(call->request));
|
||||
|
||||
call->wbconn = wbconn;
|
||||
call->event_ctx = call->wbconn->conn->event.ctx;
|
||||
|
||||
*_call = call;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
NTSTATUS wbsrv_samba3_handle_call(struct wbsrv_samba3_call *s3call)
|
||||
{
|
||||
DEBUG(10, ("Got winbind samba3 request %d\n", s3call->request.cmd));
|
||||
|
||||
s3call->response.length = sizeof(s3call->response);
|
||||
|
||||
switch(s3call->request.cmd) {
|
||||
case WINBINDD_INTERFACE_VERSION:
|
||||
return wbsrv_samba3_interface_version(s3call);
|
||||
|
||||
#if 0
|
||||
case WINBINDD_CHECK_MACHACC:
|
||||
return wbsrv_samba3_check_machacc(s3call);
|
||||
#endif
|
||||
|
||||
case WINBINDD_PING:
|
||||
return wbsrv_samba3_ping(s3call);
|
||||
|
||||
case WINBINDD_INFO:
|
||||
return wbsrv_samba3_info(s3call);
|
||||
|
||||
case WINBINDD_DOMAIN_NAME:
|
||||
return wbsrv_samba3_domain_name(s3call);
|
||||
|
||||
case WINBINDD_NETBIOS_NAME:
|
||||
return wbsrv_samba3_netbios_name(s3call);
|
||||
|
||||
case WINBINDD_PRIV_PIPE_DIR:
|
||||
return wbsrv_samba3_priv_pipe_dir(s3call);
|
||||
|
||||
case WINBINDD_LOOKUPNAME:
|
||||
return wbsrv_samba3_lookupname(s3call);
|
||||
|
||||
case WINBINDD_LOOKUPSID:
|
||||
return wbsrv_samba3_lookupsid(s3call);
|
||||
|
||||
case WINBINDD_PAM_AUTH:
|
||||
return wbsrv_samba3_pam_auth(s3call);
|
||||
|
||||
case WINBINDD_PAM_AUTH_CRAP:
|
||||
return wbsrv_samba3_pam_auth_crap(s3call);
|
||||
|
||||
case WINBINDD_GETDCNAME:
|
||||
return wbsrv_samba3_getdcname(s3call);
|
||||
|
||||
case WINBINDD_GETUSERDOMGROUPS:
|
||||
return wbsrv_samba3_userdomgroups(s3call);
|
||||
|
||||
case WINBINDD_GETUSERSIDS:
|
||||
return wbsrv_samba3_usersids(s3call);
|
||||
|
||||
case WINBINDD_LIST_TRUSTDOM:
|
||||
return wbsrv_samba3_list_trustdom(s3call);
|
||||
|
||||
/* Unimplemented commands */
|
||||
|
||||
case WINBINDD_GETPWNAM:
|
||||
case WINBINDD_GETPWUID:
|
||||
case WINBINDD_GETGRNAM:
|
||||
case WINBINDD_GETGRGID:
|
||||
case WINBINDD_GETGROUPS:
|
||||
case WINBINDD_SETPWENT:
|
||||
case WINBINDD_ENDPWENT:
|
||||
case WINBINDD_GETPWENT:
|
||||
case WINBINDD_SETGRENT:
|
||||
case WINBINDD_ENDGRENT:
|
||||
case WINBINDD_GETGRENT:
|
||||
case WINBINDD_PAM_CHAUTHTOK:
|
||||
case WINBINDD_LIST_USERS:
|
||||
case WINBINDD_LIST_GROUPS:
|
||||
case WINBINDD_SID_TO_UID:
|
||||
case WINBINDD_SID_TO_GID:
|
||||
case WINBINDD_UID_TO_SID:
|
||||
case WINBINDD_GID_TO_SID:
|
||||
case WINBINDD_ALLOCATE_RID:
|
||||
case WINBINDD_ALLOCATE_RID_AND_GID:
|
||||
case WINBINDD_CHECK_MACHACC:
|
||||
case WINBINDD_DOMAIN_INFO:
|
||||
case WINBINDD_SHOW_SEQUENCE:
|
||||
case WINBINDD_WINS_BYIP:
|
||||
case WINBINDD_WINS_BYNAME:
|
||||
case WINBINDD_GETGRLST:
|
||||
case WINBINDD_INIT_CONNECTION:
|
||||
case WINBINDD_DUAL_SID2UID:
|
||||
case WINBINDD_DUAL_SID2GID:
|
||||
case WINBINDD_DUAL_IDMAPSET:
|
||||
case WINBINDD_DUAL_UID2NAME:
|
||||
case WINBINDD_DUAL_NAME2UID:
|
||||
case WINBINDD_DUAL_GID2NAME:
|
||||
case WINBINDD_DUAL_NAME2GID:
|
||||
case WINBINDD_DUAL_USERINFO:
|
||||
case WINBINDD_DUAL_GETSIDALIASES:
|
||||
case WINBINDD_NUM_CMDS:
|
||||
DEBUG(10, ("Unimplemented winbind samba3 request %d\n",
|
||||
s3call->request.cmd));
|
||||
break;
|
||||
}
|
||||
|
||||
s3call->response.result = WINBINDD_ERROR;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS wbsrv_samba3_push_reply(struct wbsrv_samba3_call *call, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob)
|
||||
{
|
||||
DATA_BLOB blob;
|
||||
uint8_t *extra_data;
|
||||
size_t extra_data_len = 0;
|
||||
|
||||
extra_data = call->response.extra_data;
|
||||
if (extra_data) {
|
||||
extra_data_len = call->response.length -
|
||||
sizeof(call->response);
|
||||
}
|
||||
|
||||
blob = data_blob_talloc(mem_ctx, NULL, call->response.length);
|
||||
NT_STATUS_HAVE_NO_MEMORY(blob.data);
|
||||
|
||||
/* don't push real pointer values into sockets */
|
||||
if (extra_data) {
|
||||
call->response.extra_data = (void *)0xFFFFFFFF;
|
||||
}
|
||||
memcpy(blob.data, &call->response, sizeof(call->response));
|
||||
/* set back the pointer */
|
||||
call->response.extra_data = extra_data;
|
||||
|
||||
if (extra_data) {
|
||||
memcpy(blob.data + sizeof(call->response), extra_data, extra_data_len);
|
||||
}
|
||||
|
||||
*_blob = blob;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* queue a wbsrv_call reply on a wbsrv_connection
|
||||
* NOTE: that this implies talloc_free(call),
|
||||
* use talloc_reference(call) if you need it after
|
||||
* calling wbsrv_queue_reply
|
||||
*/
|
||||
NTSTATUS wbsrv_samba3_send_reply(struct wbsrv_samba3_call *call)
|
||||
{
|
||||
struct wbsrv_connection *wbconn = call->wbconn;
|
||||
DATA_BLOB rep;
|
||||
NTSTATUS status;
|
||||
|
||||
status = wbsrv_samba3_push_reply(call, call, &rep);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
status = packet_send(call->wbconn->packet, rep);
|
||||
|
||||
talloc_free(call);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
wbsrv_terminate_connection(wbconn,
|
||||
"failed to packet_send winbindd reply");
|
||||
return status;
|
||||
}
|
||||
/* the call isn't needed any more */
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wbsrv_samba3_process(void *private, DATA_BLOB blob)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct wbsrv_connection *wbconn = talloc_get_type(private,
|
||||
struct wbsrv_connection);
|
||||
struct wbsrv_samba3_call *call;
|
||||
status = wbsrv_samba3_pull_request(blob, wbconn, &call);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = wbsrv_samba3_handle_call(call);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(call);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (call->flags & WBSRV_CALL_FLAGS_REPLY_ASYNC) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
status = wbsrv_samba3_send_reply(call);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Main winbindd server routines
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "smbd/process_model.h"
|
||||
#include "smbd/service_stream.h"
|
||||
#include "nsswitch/winbind_nss_config.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "lib/stream/packet.h"
|
||||
#include "smbd/service.h"
|
||||
#include "param/secrets.h"
|
||||
|
||||
void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *reason)
|
||||
{
|
||||
stream_terminate_connection(wbconn->conn, reason);
|
||||
}
|
||||
|
||||
/*
|
||||
called on a tcp recv error
|
||||
*/
|
||||
static void wbsrv_recv_error(void *private, NTSTATUS status)
|
||||
{
|
||||
struct wbsrv_connection *wbconn = talloc_get_type(private, struct wbsrv_connection);
|
||||
wbsrv_terminate_connection(wbconn, nt_errstr(status));
|
||||
}
|
||||
|
||||
static void wbsrv_accept(struct stream_connection *conn)
|
||||
{
|
||||
struct wbsrv_listen_socket *listen_socket = talloc_get_type(conn->private,
|
||||
struct wbsrv_listen_socket);
|
||||
struct wbsrv_connection *wbconn;
|
||||
|
||||
wbconn = talloc_zero(conn, struct wbsrv_connection);
|
||||
if (!wbconn) {
|
||||
stream_terminate_connection(conn, "wbsrv_accept: out of memory");
|
||||
return;
|
||||
}
|
||||
wbconn->conn = conn;
|
||||
wbconn->listen_socket = listen_socket;
|
||||
conn->private = wbconn;
|
||||
|
||||
wbconn->packet = packet_init(wbconn);
|
||||
if (wbconn->packet == NULL) {
|
||||
wbsrv_terminate_connection(wbconn, "wbsrv_accept: out of memory");
|
||||
return;
|
||||
}
|
||||
packet_set_private(wbconn->packet, wbconn);
|
||||
packet_set_socket(wbconn->packet, conn->socket);
|
||||
packet_set_callback(wbconn->packet, wbsrv_samba3_process);
|
||||
packet_set_full_request(wbconn->packet, wbsrv_samba3_packet_full_request);
|
||||
packet_set_error_handler(wbconn->packet, wbsrv_recv_error);
|
||||
packet_set_event_context(wbconn->packet, conn->event.ctx);
|
||||
packet_set_fde(wbconn->packet, conn->event.fde);
|
||||
packet_set_serialise(wbconn->packet);
|
||||
}
|
||||
|
||||
/*
|
||||
receive some data on a winbind connection
|
||||
*/
|
||||
static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
|
||||
{
|
||||
struct wbsrv_connection *wbconn = talloc_get_type(conn->private,
|
||||
struct wbsrv_connection);
|
||||
packet_recv(wbconn->packet);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
called when we can write to a connection
|
||||
*/
|
||||
static void wbsrv_send(struct stream_connection *conn, uint16_t flags)
|
||||
{
|
||||
struct wbsrv_connection *wbconn = talloc_get_type(conn->private,
|
||||
struct wbsrv_connection);
|
||||
packet_queue_run(wbconn->packet);
|
||||
}
|
||||
|
||||
static const struct stream_server_ops wbsrv_ops = {
|
||||
.name = "winbind samba3 protocol",
|
||||
.accept_connection = wbsrv_accept,
|
||||
.recv_handler = wbsrv_recv,
|
||||
.send_handler = wbsrv_send
|
||||
};
|
||||
|
||||
/*
|
||||
startup the winbind task
|
||||
*/
|
||||
static void winbind_task_init(struct task_server *task)
|
||||
{
|
||||
uint16_t port = 1;
|
||||
const struct model_ops *model_ops;
|
||||
NTSTATUS status;
|
||||
struct wbsrv_service *service;
|
||||
struct wbsrv_listen_socket *listen_socket;
|
||||
|
||||
task_server_set_title(task, "task[winbind]");
|
||||
|
||||
/* within the winbind task we want to be a single process, so
|
||||
ask for the single process model ops and pass these to the
|
||||
stream_setup_socket() call. */
|
||||
model_ops = process_model_byname("single");
|
||||
if (!model_ops) {
|
||||
task_server_terminate(task,
|
||||
"Can't find 'single' process model_ops");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
|
||||
if (!directory_create_or_exist(lp_winbindd_socket_directory(), geteuid(), 0755)) {
|
||||
task_server_terminate(task,
|
||||
"Cannot create winbindd pipe directory");
|
||||
return;
|
||||
}
|
||||
|
||||
service = talloc_zero(task, struct wbsrv_service);
|
||||
if (!service) goto nomem;
|
||||
service->task = task;
|
||||
|
||||
service->primary_sid = secrets_get_domain_sid(service,
|
||||
lp_workgroup());
|
||||
if (service->primary_sid == NULL) {
|
||||
task_server_terminate(
|
||||
task, nt_errstr(NT_STATUS_CANT_ACCESS_DOMAIN_INFO));
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup the unprivileged samba3 socket */
|
||||
listen_socket = talloc(service, struct wbsrv_listen_socket);
|
||||
if (!listen_socket) goto nomem;
|
||||
listen_socket->socket_path = talloc_asprintf(listen_socket, "%s/%s",
|
||||
lp_winbindd_socket_directory(),
|
||||
WINBINDD_SAMBA3_SOCKET);
|
||||
if (!listen_socket->socket_path) goto nomem;
|
||||
listen_socket->service = service;
|
||||
listen_socket->privileged = False;
|
||||
status = stream_setup_socket(task->event_ctx, model_ops,
|
||||
&wbsrv_ops, "unix",
|
||||
listen_socket->socket_path, &port,
|
||||
listen_socket);
|
||||
if (!NT_STATUS_IS_OK(status)) goto listen_failed;
|
||||
|
||||
/* setup the privileged samba3 socket */
|
||||
listen_socket = talloc(service, struct wbsrv_listen_socket);
|
||||
if (!listen_socket) goto nomem;
|
||||
listen_socket->socket_path =
|
||||
smbd_tmp_path(listen_socket,
|
||||
WINBINDD_SAMBA3_PRIVILEGED_SOCKET);
|
||||
if (!listen_socket->socket_path) goto nomem;
|
||||
listen_socket->service = service;
|
||||
listen_socket->privileged = True;
|
||||
status = stream_setup_socket(task->event_ctx, model_ops,
|
||||
&wbsrv_ops, "unix",
|
||||
listen_socket->socket_path, &port,
|
||||
listen_socket);
|
||||
if (!NT_STATUS_IS_OK(status)) goto listen_failed;
|
||||
|
||||
status = wbsrv_init_irpc(service);
|
||||
if (!NT_STATUS_IS_OK(status)) goto irpc_failed;
|
||||
|
||||
return;
|
||||
|
||||
listen_failed:
|
||||
DEBUG(0,("stream_setup_socket(path=%s) failed - %s\n",
|
||||
listen_socket->socket_path, nt_errstr(status)));
|
||||
task_server_terminate(task, nt_errstr(status));
|
||||
return;
|
||||
irpc_failed:
|
||||
DEBUG(0,("wbsrv_init_irpc() failed - %s\n",
|
||||
nt_errstr(status)));
|
||||
task_server_terminate(task, nt_errstr(status));
|
||||
return;
|
||||
nomem:
|
||||
task_server_terminate(task, nt_errstr(NT_STATUS_NO_MEMORY));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
initialise the winbind server
|
||||
*/
|
||||
static NTSTATUS winbind_init(struct event_context *event_ctx,
|
||||
const struct model_ops *model_ops)
|
||||
{
|
||||
return task_server_startup(event_ctx, model_ops, winbind_task_init);
|
||||
}
|
||||
|
||||
/*
|
||||
register ourselves as a available server
|
||||
*/
|
||||
NTSTATUS server_service_winbind_init(void)
|
||||
{
|
||||
return register_server_service("winbind", winbind_init);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Main winbindd server routines
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "nsswitch/winbindd_nss.h"
|
||||
|
||||
|
||||
|
||||
#define WINBINDD_SAMBA3_SOCKET "pipe"
|
||||
/* the privileged socket is in smbd_tmp_dir() */
|
||||
#define WINBINDD_SAMBA3_PRIVILEGED_SOCKET "winbind_pipe"
|
||||
|
||||
/* this struct stores global data for the winbind task */
|
||||
struct wbsrv_service {
|
||||
struct task_server *task;
|
||||
|
||||
const struct dom_sid *primary_sid;
|
||||
struct wbsrv_domain *domains;
|
||||
};
|
||||
|
||||
struct wbsrv_samconn {
|
||||
struct wbsrv_domain *domain;
|
||||
void *private_data;
|
||||
|
||||
struct composite_context (*seqnum_send)(struct wbsrv_samconn *);
|
||||
NTSTATUS (*seqnum_recv)(struct composite_context *, uint64_t *);
|
||||
};
|
||||
|
||||
struct wb_dom_info {
|
||||
const char *name;
|
||||
const char *dns_name;
|
||||
const struct dom_sid *sid;
|
||||
|
||||
const char *dc_name;
|
||||
const char *dc_dns_name;
|
||||
const char *dc_address;
|
||||
};
|
||||
|
||||
struct wbsrv_domain {
|
||||
struct wbsrv_domain *next, *prev;
|
||||
|
||||
struct wb_dom_info *info;
|
||||
|
||||
struct dcerpc_pipe *lsa_pipe;
|
||||
struct policy_handle *lsa_policy;
|
||||
uint8_t lsa_auth_type;
|
||||
|
||||
struct dcerpc_pipe *samr_pipe;
|
||||
struct policy_handle *samr_handle;
|
||||
struct policy_handle *domain_handle;
|
||||
|
||||
struct ldap_connection *ldap_conn;
|
||||
|
||||
struct dcerpc_pipe *netlogon_pipe;
|
||||
struct cli_credentials *schannel_creds;
|
||||
};
|
||||
|
||||
/*
|
||||
state of a listen socket and it's protocol information
|
||||
*/
|
||||
struct wbsrv_listen_socket {
|
||||
const char *socket_path;
|
||||
struct wbsrv_service *service;
|
||||
BOOL privileged;
|
||||
};
|
||||
|
||||
/*
|
||||
state of an open winbind connection
|
||||
*/
|
||||
struct wbsrv_connection {
|
||||
/* stream connection we belong to */
|
||||
struct stream_connection *conn;
|
||||
|
||||
/* the listening socket we belong to, it holds protocol hooks */
|
||||
struct wbsrv_listen_socket *listen_socket;
|
||||
|
||||
/* storage for protocol specific data */
|
||||
void *protocol_private_data;
|
||||
|
||||
/* how many calls are pending */
|
||||
uint32_t pending_calls;
|
||||
|
||||
struct packet_context *packet;
|
||||
};
|
||||
|
||||
#define WBSRV_SAMBA3_SET_STRING(dest, src) do { \
|
||||
strncpy(dest, src, sizeof(dest)-1);\
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
state of one request
|
||||
|
||||
NOTE about async replies:
|
||||
if the backend wants to reply later:
|
||||
|
||||
- it should set the WBSRV_CALL_FLAGS_REPLY_ASYNC flag, and may set a
|
||||
talloc_destructor on the this structure or on the private_data (if it's a
|
||||
talloc child of this structure), so that wbsrv_terminate_connection
|
||||
called by another call clean up the whole connection correct.
|
||||
- When the backend is ready to reply it should call wbsrv_send_reply(call),
|
||||
wbsrv_send_reply implies talloc_free(call), so the backend should use
|
||||
talloc_reference(call), if it needs it later.
|
||||
- If wbsrv_send_reply doesn't return NT_STATUS_OK, the backend function
|
||||
should call, wbsrv_terminate_connection(call->wbconn, nt_errstr(status));
|
||||
return;
|
||||
|
||||
*/
|
||||
struct wbsrv_samba3_call {
|
||||
#define WBSRV_CALL_FLAGS_REPLY_ASYNC 0x00000001
|
||||
uint32_t flags;
|
||||
|
||||
/* the connection the call belongs to */
|
||||
struct wbsrv_connection *wbconn;
|
||||
|
||||
/* the backend should use this event context */
|
||||
struct event_context *event_ctx;
|
||||
|
||||
/* here the backend can store stuff like composite_context's ... */
|
||||
void *private_data;
|
||||
|
||||
/* the request structure of the samba3 protocol */
|
||||
struct winbindd_request request;
|
||||
|
||||
/* the response structure of the samba3 protocol*/
|
||||
struct winbindd_response response;
|
||||
};
|
||||
|
||||
struct netr_LMSessionKey;
|
||||
struct netr_UserSessionKey;
|
||||
struct winbind_SamLogon;
|
||||
|
||||
#include "winbind/wb_async_helpers.h"
|
||||
#include "winbind/wb_proto.h"
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Find and init a domain struct for a SID
|
||||
|
||||
Copyright (C) Volker Lendecke 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "winbind/wb_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "winbind/wb_async_helpers.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
|
||||
static struct wbsrv_domain *find_domain_from_sid(struct wbsrv_service *service,
|
||||
const struct dom_sid *sid)
|
||||
{
|
||||
struct wbsrv_domain *domain;
|
||||
|
||||
for (domain = service->domains; domain!=NULL; domain = domain->next) {
|
||||
if (dom_sid_equal(domain->info->sid, sid)) {
|
||||
break;
|
||||
}
|
||||
if (dom_sid_in_domain(domain->info->sid, sid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
struct sid2domain_state {
|
||||
struct composite_context *ctx;
|
||||
struct wbsrv_service *service;
|
||||
struct dom_sid *sid;
|
||||
|
||||
struct wbsrv_domain *domain;
|
||||
};
|
||||
|
||||
static void sid2domain_recv_dom_info(struct composite_context *ctx);
|
||||
static void sid2domain_recv_name(struct composite_context *ctx);
|
||||
static void sid2domain_recv_trusted_dom_info(struct composite_context *ctx);
|
||||
static void sid2domain_recv_init(struct composite_context *ctx);
|
||||
|
||||
struct composite_context *wb_sid2domain_send(TALLOC_CTX *mem_ctx,
|
||||
struct wbsrv_service *service,
|
||||
const struct dom_sid *sid)
|
||||
{
|
||||
struct composite_context *result, *ctx;
|
||||
struct sid2domain_state *state;
|
||||
|
||||
result = talloc_zero(mem_ctx, struct composite_context);
|
||||
if (result == NULL) goto failed;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->async.fn = NULL;
|
||||
result->event_ctx = service->task->event_ctx;
|
||||
|
||||
state = talloc(result, struct sid2domain_state);
|
||||
if (state == NULL) goto failed;
|
||||
state->ctx = result;
|
||||
result->private_data = state;
|
||||
|
||||
state->service = service;
|
||||
state->sid = dom_sid_dup(state, sid);
|
||||
if (state->sid == NULL) goto failed;
|
||||
|
||||
state->domain = find_domain_from_sid(service, sid);
|
||||
if (state->domain != NULL) {
|
||||
result->status = NT_STATUS_OK;
|
||||
composite_done(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (dom_sid_equal(service->primary_sid, sid) ||
|
||||
dom_sid_in_domain(service->primary_sid, sid)) {
|
||||
ctx = wb_get_dom_info_send(state, service, lp_workgroup(),
|
||||
service->primary_sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
ctx->async.fn = sid2domain_recv_dom_info;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
}
|
||||
|
||||
ctx = wb_cmd_lookupsid_send(state, service, state->sid);
|
||||
if (ctx == NULL) goto failed;
|
||||
ctx->async.fn = sid2domain_recv_name;
|
||||
ctx->async.private_data = state;
|
||||
return result;
|
||||
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static void sid2domain_recv_dom_info(struct composite_context *ctx)
|
||||
{
|
||||
struct sid2domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct sid2domain_state);
|
||||
struct wb_dom_info *info;
|
||||
|
||||
state->ctx->status = wb_get_dom_info_recv(ctx, state, &info);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
ctx = wb_init_domain_send(state, state->service, info);
|
||||
|
||||
composite_continue(state->ctx, ctx, sid2domain_recv_init, state);
|
||||
}
|
||||
|
||||
static void sid2domain_recv_name(struct composite_context *ctx)
|
||||
{
|
||||
struct sid2domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct sid2domain_state);
|
||||
struct wb_sid_object *name;
|
||||
|
||||
state->ctx->status = wb_cmd_lookupsid_recv(ctx, state, &name);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
if (name->type == SID_NAME_UNKNOWN) {
|
||||
composite_error(state->ctx, NT_STATUS_NO_SUCH_DOMAIN);
|
||||
return;
|
||||
}
|
||||
|
||||
if (name->type != SID_NAME_DOMAIN) {
|
||||
state->sid->num_auths -= 1;
|
||||
}
|
||||
|
||||
ctx = wb_trusted_dom_info_send(state, state->service, name->domain,
|
||||
state->sid);
|
||||
|
||||
composite_continue(state->ctx, ctx, sid2domain_recv_trusted_dom_info,
|
||||
state);
|
||||
}
|
||||
|
||||
static void sid2domain_recv_trusted_dom_info(struct composite_context *ctx)
|
||||
{
|
||||
struct sid2domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct sid2domain_state);
|
||||
struct wb_dom_info *info;
|
||||
|
||||
state->ctx->status = wb_trusted_dom_info_recv(ctx, state, &info);
|
||||
if (!composite_is_ok(state->ctx)) return;
|
||||
|
||||
ctx = wb_init_domain_send(state, state->service, info);
|
||||
|
||||
composite_continue(state->ctx, ctx, sid2domain_recv_init, state);
|
||||
}
|
||||
|
||||
static void sid2domain_recv_init(struct composite_context *ctx)
|
||||
{
|
||||
struct sid2domain_state *state =
|
||||
talloc_get_type(ctx->async.private_data,
|
||||
struct sid2domain_state);
|
||||
struct wbsrv_domain *existing;
|
||||
|
||||
state->ctx->status = wb_init_domain_recv(ctx, state,
|
||||
&state->domain);
|
||||
if (!composite_is_ok(state->ctx)) {
|
||||
DEBUG(10, ("Could not init domain\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
existing = find_domain_from_sid(state->service, state->sid);
|
||||
if (existing != NULL) {
|
||||
DEBUG(5, ("Initialized domain twice, dropping second one\n"));
|
||||
talloc_free(state->domain);
|
||||
state->domain = existing;
|
||||
}
|
||||
|
||||
talloc_steal(state->service, state->domain);
|
||||
DLIST_ADD(state->service->domains, state->domain);
|
||||
|
||||
composite_done(state->ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wb_sid2domain_recv(struct composite_context *ctx,
|
||||
struct wbsrv_domain **result)
|
||||
{
|
||||
NTSTATUS status = composite_wait(ctx);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct sid2domain_state *state =
|
||||
talloc_get_type(ctx->private_data,
|
||||
struct sid2domain_state);
|
||||
*result = state->domain;
|
||||
}
|
||||
talloc_free(ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS wb_sid2domain(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
|
||||
const struct dom_sid *sid,
|
||||
struct wbsrv_domain **result)
|
||||
{
|
||||
struct composite_context *c = wb_sid2domain_send(mem_ctx, service,
|
||||
sid);
|
||||
return wb_sid2domain_recv(c, result);
|
||||
}
|
||||
Reference in New Issue
Block a user