wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
+47
View File
@@ -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
################################################
+755
View File
@@ -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;
}
+35
View File
@@ -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__ */
+128
View File
@@ -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;
}
+199
View File
@@ -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;
}
+125
View File
@@ -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);
}
+122
View File
@@ -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);
}
+150
View File
@@ -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);
}
+196
View File
@@ -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);
}
+361
View File
@@ -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);
}
+254
View File
@@ -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);
}
+163
View File
@@ -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);
}
+238
View File
@@ -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);
}
+372
View File
@@ -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);
}
+86
View File
@@ -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;
}
+388
View File
@@ -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);
}
+168
View File
@@ -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;
}
+663
View File
@@ -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);
}
+260
View File
@@ -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;
}
+215
View File
@@ -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);
}
+151
View File
@@ -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"
+215
View File
@@ -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);
}