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
+44
View File
@@ -0,0 +1,44 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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.
*/
/*
* Monitor structure and message types definitions. Composite function monitoring
* allows client application to be notified on function progress. This enables
* eg. gui client to display progress bars, status messages, etc.
*/
#define rpc_create_user (0x00000001) /* userman.h */
#define rpc_open_user (0x00000002) /* userinfo.h */
#define rpc_query_user (0x00000003) /* userinfo.h */
#define rpc_close_user (0x00000004) /* userinfo.h */
#define rpc_lookup_name (0x00000005) /* userman.h */
#define rpc_delete_user (0x00000006) /* userman.h */
#define rpc_set_user (0x00000007) /* userman.h */
#define net_lookup_dc (0x00000100) /* libnet_rpc.h */
#define net_pipe_connected (0x00000200) /* libnet_rpc.h */
struct monitor_msg {
uint32_t type;
void *data;
size_t data_size;
};
+30
View File
@@ -0,0 +1,30 @@
[LIBRARY::LIBSAMBA-NET]
VERSION = 0.0.1
SO_VERSION = 0
DESCRIPTION = Convenient high level access to Samba management interfaces
PRIVATE_PROTO_HEADER = libnet_proto.h
PUBLIC_HEADERS = libnet.h libnet_join.h libnet_lookup.h libnet_passwd.h \
libnet_rpc.h libnet_share.h libnet_time.h \
libnet_user.h libnet_site.h libnet_vampire.h \
userinfo.h userman.h
OBJ_FILES = \
libnet.o \
libnet_passwd.o \
libnet_time.o \
libnet_rpc.o \
libnet_join.o \
libnet_site.o \
libnet_become_dc.o \
libnet_unbecome_dc.o \
libnet_vampire.o \
libnet_samdump.o \
libnet_samdump_keytab.o \
libnet_samsync_ldb.o \
libnet_user.o \
libnet_share.o \
libnet_lookup.o \
libnet_domain.o \
userinfo.o \
userman.o \
prereq_domain.o
PUBLIC_DEPENDENCIES = dcerpc RPC_NDR_SAMR RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBCLI_FINDDCS LIBSAMBA3 LIBCLI_CLDAP LIBCLI_FINDDCS gensec_schannel
+53
View File
@@ -0,0 +1,53 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
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 "libnet/libnet.h"
#include "lib/events/events.h"
struct libnet_context *libnet_context_init(struct event_context *ev)
{
struct libnet_context *ctx;
/* create brand new libnet context */
ctx = talloc(ev, struct libnet_context);
if (!ctx) {
return NULL;
}
/* events */
if (ev == NULL) {
ev = event_context_find(ctx);
if (ev == NULL) {
talloc_free(ctx);
return NULL;
}
}
ctx->event_ctx = ev;
/* name resolution methods */
ctx->name_res_methods = str_list_copy(ctx, lp_name_resolve_order());
/* connected services' params */
ZERO_STRUCT(ctx->samr);
ZERO_STRUCT(ctx->lsa);
return ctx;
}
+68
View File
@@ -0,0 +1,68 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
Copyright (C) Rafal Szczesniak 2005-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.
*/
struct libnet_context {
/* here we need:
* a client env context
* a user env context
*/
struct cli_credentials *cred;
/* samr connection parameters - opened handles and related properties */
struct {
struct dcerpc_pipe *pipe;
const char *name;
uint32_t access_mask;
struct policy_handle handle;
} samr;
/* lsa connection parameters - opened handles and related properties */
struct {
struct dcerpc_pipe *pipe;
const char *name;
uint32_t access_mask;
struct policy_handle handle;
} lsa;
/* name resolution methods */
const char **name_res_methods;
struct event_context *event_ctx;
};
#include "lib/ldb/include/ldb.h"
#include "libnet/composite.h"
#include "libnet/userman.h"
#include "libnet/userinfo.h"
#include "libnet/libnet_passwd.h"
#include "libnet/libnet_time.h"
#include "libnet/libnet_rpc.h"
#include "libnet/libnet_join.h"
#include "libnet/libnet_site.h"
#include "libnet/libnet_become_dc.h"
#include "libnet/libnet_unbecome_dc.h"
#include "libnet/libnet_vampire.h"
#include "libnet/libnet_user.h"
#include "libnet/libnet_share.h"
#include "libnet/libnet_lookup.h"
#include "libnet/libnet_domain.h"
#include "libnet/libnet_proto.h"
File diff suppressed because it is too large Load Diff
+33
View File
@@ -0,0 +1,33 @@
/*
Unix SMB/CIFS implementation.
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.
*/
struct libnet_BecomeDC {
struct {
const char *domain_dns_name;
const char *domain_netbios_name;
const struct dom_sid *domain_sid;
const char *source_dsa_address;
const char *dest_dsa_netbios_name;
} in;
struct {
const char *error_string;
} out;
};
+885
View File
@@ -0,0 +1,885 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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 function for domain handling on samr and lsa pipes
*/
#include "includes.h"
#include "libcli/composite/composite.h"
#include "libnet/libnet.h"
#include "librpc/gen_ndr/ndr_samr_c.h"
#include "librpc/gen_ndr/ndr_lsa_c.h"
static void domain_open_handler(struct rpc_request*);
enum domain_open_stage { DOMOPEN_CONNECT, DOMOPEN_LOOKUP, DOMOPEN_OPEN,
DOMOPEN_CLOSE_EXISTING, DOMOPEN_RPC_CONNECT };
struct domain_open_samr_state {
enum domain_open_stage stage;
struct libnet_context *ctx;
struct dcerpc_pipe *pipe;
struct rpc_request *req;
struct composite_context *rpcconn_req;
struct samr_Connect connect;
struct samr_LookupDomain lookup;
struct samr_OpenDomain open;
struct samr_Close close;
struct libnet_RpcConnect rpcconn;
struct lsa_String domain_name;
uint32_t access_mask;
struct policy_handle connect_handle;
struct policy_handle domain_handle;
/* information about the progress */
void (*monitor_fn)(struct monitor_msg*);
};
/**
* Stage 0.5 (optional): Connect to samr rpc pipe
*/
static void domain_open_rpc_connect(struct composite_context *ctx)
{
struct composite_context *c;
struct domain_open_samr_state *s;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct domain_open_samr_state);
c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
if (!composite_is_ok(c)) return;
s->pipe = s->rpcconn.out.dcerpc_pipe;
/* preparing parameters for samr_Connect rpc call */
s->connect.in.system_name = 0;
s->connect.in.access_mask = s->access_mask;
s->connect.out.connect_handle = &s->connect_handle;
/* send request */
s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
if (composite_nomem(s->req, c)) return;
/* callback handler */
s->req->async.callback = domain_open_handler;
s->req->async.private = c;
s->stage = DOMOPEN_CONNECT;
}
/**
* Stage 0.5 (optional): Close existing (in libnet context) domain
* handle
*/
static NTSTATUS domain_open_close(struct composite_context *c,
struct domain_open_samr_state *s)
{
/* receive samr_Close reply */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* reset domain handle and associated data in libnet_context */
s->ctx->samr.name = NULL;
s->ctx->samr.access_mask = 0;
ZERO_STRUCT(s->ctx->samr.handle);
/* preparing parameters for samr_Connect rpc call */
s->connect.in.system_name = 0;
s->connect.in.access_mask = s->access_mask;
s->connect.out.connect_handle = &s->connect_handle;
/* send request */
s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
if (s->req == NULL) return NT_STATUS_NO_MEMORY;
/* callback handler */
s->req->async.callback = domain_open_handler;
s->req->async.private = c;
s->stage = DOMOPEN_CONNECT;
return NT_STATUS_OK;
}
/**
* Stage 1: Connect to SAM server.
*/
static NTSTATUS domain_open_connect(struct composite_context *c,
struct domain_open_samr_state *s)
{
struct samr_LookupDomain *r = &s->lookup;
/* receive samr_Connect reply */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* prepare for samr_LookupDomain call */
r->in.connect_handle = &s->connect_handle;
r->in.domain_name = &s->domain_name;
s->req = dcerpc_samr_LookupDomain_send(s->pipe, c, r);
if (s->req == NULL) goto failure;
s->req->async.callback = domain_open_handler;
s->req->async.private = c;
s->stage = DOMOPEN_LOOKUP;
return NT_STATUS_OK;
failure:
return NT_STATUS_UNSUCCESSFUL;
}
/**
* Stage 2: Lookup domain by name.
*/
static NTSTATUS domain_open_lookup(struct composite_context *c,
struct domain_open_samr_state *s)
{
struct samr_OpenDomain *r = &s->open;
/* receive samr_LookupDomain reply */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* prepare for samr_OpenDomain call */
r->in.connect_handle = &s->connect_handle;
r->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
r->in.sid = s->lookup.out.sid;
r->out.domain_handle = &s->domain_handle;
s->req = dcerpc_samr_OpenDomain_send(s->pipe, c, r);
if (s->req == NULL) goto failure;
s->req->async.callback = domain_open_handler;
s->req->async.private = c;
s->stage = DOMOPEN_OPEN;
return NT_STATUS_OK;
failure:
return NT_STATUS_UNSUCCESSFUL;
}
/*
* Stage 3: Open domain.
*/
static NTSTATUS domain_open_open(struct composite_context *c,
struct domain_open_samr_state *s)
{
/* receive samr_OpenDomain reply */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
c->state = COMPOSITE_STATE_DONE;
return NT_STATUS_OK;
}
/**
* Event handler for asynchronous request. Handles transition through
* intermediate stages of the call.
*
* @param req rpc call context
*/
static void domain_open_handler(struct rpc_request *req)
{
struct composite_context *c = req->async.private;
struct domain_open_samr_state *s = talloc_get_type(c->private_data,
struct domain_open_samr_state);
/* Stages of the call */
switch (s->stage) {
case DOMOPEN_CONNECT:
c->status = domain_open_connect(c, s);
break;
case DOMOPEN_LOOKUP:
c->status = domain_open_lookup(c, s);
break;
case DOMOPEN_OPEN:
c->status = domain_open_open(c, s);
break;
case DOMOPEN_CLOSE_EXISTING:
c->status = domain_open_close(c, s);
break;
case DOMOPEN_RPC_CONNECT:
/* this state shouldn't be handled here */
c->status = NT_STATUS_UNSUCCESSFUL;
break;
}
if (!NT_STATUS_IS_OK(c->status)) {
c->state = COMPOSITE_STATE_ERROR;
}
if (c->state == COMPOSITE_STATE_DONE) {
composite_done(c);
}
}
/**
* Sends asynchronous DomainOpenSamr request
*
* @param ctx initialised libnet context
* @param io arguments and results of the call
* @param monitor pointer to monitor function that is passed monitor message
*/
struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
struct libnet_DomainOpen *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct domain_open_samr_state *s;
c = composite_create(ctx, ctx->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct domain_open_samr_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
s->monitor_fn = monitor;
s->ctx = ctx;
s->pipe = ctx->samr.pipe;
s->access_mask = io->in.access_mask;
s->domain_name.string = talloc_strdup(c, io->in.domain_name);
/* check, if there's samr pipe opened already, before opening a domain */
if (ctx->samr.pipe == NULL) {
/* attempting to connect a domain controller */
s->rpcconn.level = LIBNET_RPC_CONNECT_DC;
s->rpcconn.in.name = io->in.domain_name;
s->rpcconn.in.dcerpc_iface = &dcerpc_table_samr;
/* send rpc pipe connect request */
s->rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn);
if (composite_nomem(s->rpcconn_req, c)) return c;
s->rpcconn_req->async.fn = domain_open_rpc_connect;
s->rpcconn_req->async.private_data = c;
s->stage = DOMOPEN_RPC_CONNECT;
return c;
}
/* libnet context's domain handle is not empty, so check out what
was opened first, before doing anything */
if (!policy_handle_empty(&ctx->samr.handle)) {
if (strequal(ctx->samr.name, io->in.domain_name) &&
ctx->samr.access_mask == io->in.access_mask) {
/* this domain is already opened */
composite_done(c);
return c;
} else {
/* another domain or access rights have been
requested - close the existing handle first */
s->close.in.handle = &ctx->samr.handle;
/* send request to close domain handle */
s->req = dcerpc_samr_Close_send(s->pipe, c, &s->close);
if (composite_nomem(s->req, c)) return c;
/* callback handler */
s->req->async.callback = domain_open_handler;
s->req->async.private = c;
s->stage = DOMOPEN_CLOSE_EXISTING;
return c;
}
}
/* preparing parameters for samr_Connect rpc call */
s->connect.in.system_name = 0;
s->connect.in.access_mask = s->access_mask;
s->connect.out.connect_handle = &s->connect_handle;
/* send request */
s->req = dcerpc_samr_Connect_send(s->pipe, c, &s->connect);
if (composite_nomem(s->req, c)) return c;
/* callback handler */
s->req->async.callback = domain_open_handler;
s->req->async.private = c;
s->stage = DOMOPEN_CONNECT;
return c;
}
/**
* Waits for and receives result of asynchronous DomainOpenSamr call
*
* @param c composite context returned by asynchronous DomainOpen call
* @param ctx initialised libnet context
* @param mem_ctx memory context of the call
* @param io pointer to results (and arguments) of the call
* @return nt status code of execution
*/
NTSTATUS libnet_DomainOpenSamr_recv(struct composite_context *c, struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
{
NTSTATUS status;
struct domain_open_samr_state *s;
/* wait for results of sending request */
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) && io) {
s = talloc_get_type(c->private_data, struct domain_open_samr_state);
io->out.domain_handle = s->domain_handle;
/* store the resulting handle and related data for use by other
libnet functions */
ctx->samr.handle = s->domain_handle;
ctx->samr.name = talloc_steal(ctx, s->domain_name.string);
ctx->samr.access_mask = s->access_mask;
}
talloc_free(c);
return status;
}
struct domain_open_lsa_state {
const char *name;
uint32_t access_mask;
struct libnet_context *ctx;
struct libnet_RpcConnect rpcconn;
struct lsa_OpenPolicy2 openpol;
struct policy_handle handle;
struct dcerpc_pipe *pipe;
/* information about the progress */
void (*monitor_fn)(struct monitor_msg*);
};
static void continue_rpc_connect_lsa(struct composite_context *ctx);
static void continue_lsa_policy_open(struct rpc_request *req);
/**
* Sends asynchronous DomainOpenLsa request
*
* @param ctx initialised libnet context
* @param io arguments and results of the call
* @param monitor pointer to monitor function that is passed monitor message
*/
struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
struct libnet_DomainOpen *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct domain_open_lsa_state *s;
struct composite_context *rpcconn_req;
struct rpc_request *openpol_req;
struct lsa_QosInfo *qos;
/* create composite context and state */
c = composite_create(ctx, ctx->event_ctx);
if (c == NULL) return c;
s = talloc_zero(c, struct domain_open_lsa_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
/* store arguments in the state structure */
s->name = talloc_strdup(c, io->in.domain_name);
s->access_mask = io->in.access_mask;
s->ctx = ctx;
/* check, if there's lsa pipe opened already, before opening a handle */
if (ctx->lsa.pipe == NULL) {
/* attempting to connect a domain controller */
s->rpcconn.level = LIBNET_RPC_CONNECT_DC;
s->rpcconn.in.name = talloc_strdup(c, io->in.domain_name);
s->rpcconn.in.dcerpc_iface = &dcerpc_table_lsarpc;
/* send rpc pipe connect request */
rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn);
if (composite_nomem(rpcconn_req, c)) return c;
composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
return c;
}
s->pipe = ctx->lsa.pipe;
/* preparing parameters for lsa_OpenPolicy2 rpc call */
s->openpol.in.system_name = s->name;
s->openpol.in.access_mask = s->access_mask;
s->openpol.in.attr = talloc_zero(c, struct lsa_ObjectAttribute);
qos = talloc_zero(c, struct lsa_QosInfo);
qos->len = 0;
qos->impersonation_level = 2;
qos->context_mode = 1;
qos->effective_only = 0;
s->openpol.in.attr->sec_qos = qos;
s->openpol.out.handle = &s->handle;
/* send rpc request */
openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
if (composite_nomem(openpol_req, c)) return c;
composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
return c;
}
/*
Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
*/
static void continue_rpc_connect_lsa(struct composite_context *ctx)
{
struct composite_context *c;
struct domain_open_lsa_state *s;
struct lsa_QosInfo *qos;
struct rpc_request *openpol_req;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
/* receive rpc connection */
c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
if (!composite_is_ok(c)) return;
/* RpcConnect function leaves the pipe in libnet context,
so get it from there */
s->pipe = s->ctx->lsa.pipe;
/* prepare lsa_OpenPolicy2 call */
s->openpol.in.system_name = s->name;
s->openpol.in.access_mask = s->access_mask;
s->openpol.in.attr = talloc_zero(c, struct lsa_ObjectAttribute);
qos = talloc_zero(c, struct lsa_QosInfo);
qos->len = 0;
qos->impersonation_level = 2;
qos->context_mode = 1;
qos->effective_only = 0;
s->openpol.in.attr->sec_qos = qos;
s->openpol.out.handle = &s->handle;
/* send rpc request */
openpol_req = dcerpc_lsa_OpenPolicy2_send(s->pipe, c, &s->openpol);
if (composite_nomem(openpol_req, c)) return;
composite_continue_rpc(c, openpol_req, continue_lsa_policy_open, c);
}
/*
Stage 1: Lsa policy opened - we're done, if successfully
*/
static void continue_lsa_policy_open(struct rpc_request *req)
{
struct composite_context *c;
struct domain_open_lsa_state *s;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
composite_done(c);
}
/**
* Receives result of asynchronous DomainOpenLsa call
*
* @param c composite context returned by asynchronous DomainOpenLsa call
* @param ctx initialised libnet context
* @param mem_ctx memory context of the call
* @param io pointer to results (and arguments) of the call
* @return nt status code of execution
*/
NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
{
NTSTATUS status;
struct domain_open_lsa_state *s;
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) && io) {
/* everything went fine - get the results and
return the error string */
s = talloc_get_type(c->private_data, struct domain_open_lsa_state);
io->out.domain_handle = s->handle;
ctx->lsa.handle = s->handle;
ctx->lsa.name = talloc_steal(ctx, s->name);
ctx->lsa.access_mask = s->access_mask;
io->out.error_string = talloc_strdup(mem_ctx, "Success");
} else if (!NT_STATUS_IS_OK(status)) {
/* there was an error, so provide nt status code description */
io->out.error_string = talloc_asprintf(mem_ctx,
"Failed to open domain: %s",
nt_errstr(status));
}
talloc_free(c);
return status;
}
/**
* Sends a request to open a domain in desired service
*
* @param ctx initalised libnet context
* @param io arguments and results of the call
* @param monitor pointer to monitor function that is passed monitor message
*/
struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
struct libnet_DomainOpen *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
switch (io->in.type) {
case DOMAIN_LSA:
/* reques to open a policy handle on \pipe\lsarpc */
c = libnet_DomainOpenLsa_send(ctx, io, monitor);
break;
case DOMAIN_SAMR:
default:
/* request to open a domain policy handle on \pipe\samr */
c = libnet_DomainOpenSamr_send(ctx, io, monitor);
break;
}
return c;
}
/**
* Receive result of domain open request
*
* @param c composite context returned by DomainOpen_send function
* @param ctx initialised libnet context
* @param mem_ctx memory context of the call
* @param io results and arguments of the call
*/
NTSTATUS libnet_DomainOpen_recv(struct composite_context *c, struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
{
NTSTATUS status;
switch (io->in.type) {
case DOMAIN_LSA:
status = libnet_DomainOpenLsa_recv(c, ctx, mem_ctx, io);
break;
case DOMAIN_SAMR:
default:
status = libnet_DomainOpenSamr_recv(c, ctx, mem_ctx, io);
break;
}
return status;
}
/**
* Synchronous version of DomainOpen call
*
* @param ctx initialised libnet context
* @param mem_ctx memory context for the call
* @param io arguments and results of the call
* @return nt status code of execution
*/
NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_DomainOpen *io)
{
struct composite_context *c = libnet_DomainOpen_send(ctx, io, NULL);
return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
}
struct domain_close_lsa_state {
struct dcerpc_pipe *pipe;
struct lsa_Close close;
struct policy_handle handle;
void (*monitor_fn)(struct monitor_msg*);
};
static void continue_lsa_close(struct rpc_request *req);
struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
struct libnet_DomainClose *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct domain_close_lsa_state *s;
struct rpc_request *close_req;
/* composite context and state structure allocation */
c = composite_create(ctx, ctx->event_ctx);
if (c == NULL) return c;
s = talloc_zero(c, struct domain_close_lsa_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
s->monitor_fn = monitor;
/* TODO: check if lsa pipe pointer is non-null */
if (!strequal(ctx->lsa.name, io->in.domain_name)) {
composite_error(c, NT_STATUS_INVALID_PARAMETER);
return c;
}
/* get opened lsarpc pipe pointer */
s->pipe = ctx->lsa.pipe;
/* prepare close handle call arguments */
s->close.in.handle = &ctx->lsa.handle;
s->close.out.handle = &s->handle;
/* send the request */
close_req = dcerpc_lsa_Close_send(s->pipe, c, &s->close);
if (composite_nomem(close_req, c)) return c;
composite_continue_rpc(c, close_req, continue_lsa_close, c);
return c;
}
/*
Stage 1: Receive result of lsa close call
*/
static void continue_lsa_close(struct rpc_request *req)
{
struct composite_context *c;
struct domain_close_lsa_state *s;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct domain_close_lsa_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
composite_done(c);
}
NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
{
NTSTATUS status;
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) && io) {
/* policy handle closed successfully */
ctx->lsa.name = NULL;
ZERO_STRUCT(ctx->lsa.handle);
io->out.error_string = talloc_asprintf(mem_ctx, "Success");
} else if (!NT_STATUS_IS_OK(status)) {
/* there was an error, so return description of the status code */
io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
}
talloc_free(c);
return status;
}
struct domain_close_samr_state {
struct samr_Close close;
struct policy_handle handle;
void (*monitor_fn)(struct monitor_msg*);
};
static void continue_samr_close(struct rpc_request *req);
struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
struct libnet_DomainClose *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct domain_close_samr_state *s;
struct rpc_request *close_req;
/* composite context and state structure allocation */
c = composite_create(ctx, ctx->event_ctx);
if (c == NULL) return c;
s = talloc_zero(c, struct domain_close_samr_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
s->monitor_fn = monitor;
/* TODO: check if samr pipe pointer is non-null */
if (!strequal(ctx->samr.name, io->in.domain_name)) {
composite_error(c, NT_STATUS_INVALID_PARAMETER);
return c;
}
/* prepare close domain handle call arguments */
ZERO_STRUCT(s->close);
s->close.in.handle = &ctx->samr.handle;
s->close.out.handle = &s->handle;
/* send the request */
close_req = dcerpc_samr_Close_send(ctx->samr.pipe, ctx, &s->close);
if (composite_nomem(close_req, c)) return c;
composite_continue_rpc(c, close_req, continue_samr_close, c);
return c;
}
/*
Stage 1: Receive result of samr close call
*/
static void continue_samr_close(struct rpc_request *req)
{
struct composite_context *c;
struct domain_close_samr_state *s;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct domain_close_samr_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
composite_done(c);
}
NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
{
NTSTATUS status;
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) && io) {
/* domain policy handle closed successfully */
ZERO_STRUCT(ctx->samr.handle);
ctx->samr.name = NULL;
io->out.error_string = talloc_asprintf(mem_ctx, "Success");
} else if (!NT_STATUS_IS_OK(status)) {
/* there was an error, so return description of the status code */
io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
}
talloc_free(c);
return status;
}
struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
struct libnet_DomainClose *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
switch (io->in.type) {
case DOMAIN_LSA:
/* request to close policy handle on \pipe\lsarpc */
c = libnet_DomainCloseLsa_send(ctx, io, monitor);
break;
case DOMAIN_SAMR:
default:
/* request to close domain policy handle on \pipe\samr */
c = libnet_DomainCloseSamr_send(ctx, io, monitor);
break;
}
return c;
}
NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
{
NTSTATUS status;
switch (io->in.type) {
case DOMAIN_LSA:
/* receive result of closing lsa policy handle */
status = libnet_DomainCloseLsa_recv(c, ctx, mem_ctx, io);
break;
case DOMAIN_SAMR:
default:
/* receive result of closing samr domain policy handle */
status = libnet_DomainCloseSamr_recv(c, ctx, mem_ctx, io);
break;
}
return status;
}
NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
struct libnet_DomainClose *io)
{
struct composite_context *c;
c = libnet_DomainClose_send(ctx, io, NULL);
return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
}
+49
View File
@@ -0,0 +1,49 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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.
*/
enum service_type { DOMAIN_SAMR, DOMAIN_LSA };
/*
* struct definition for opening a domain
*/
struct libnet_DomainOpen {
struct {
enum service_type type;
const char *domain_name;
uint32_t access_mask;
} in;
struct {
struct policy_handle domain_handle;
const char *error_string;
} out;
};
struct libnet_DomainClose {
struct {
enum service_type type;
const char *domain_name;
} in;
struct {
const char *error_string;
} out;
};
File diff suppressed because it is too large Load Diff
+83
View File
@@ -0,0 +1,83 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
Copyright (C) Brad Henry 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 __LIBNET_JOIN_H__
#define __LIBNET_JOIN_H__
#include "librpc/gen_ndr/netlogon.h"
enum libnet_Join_level {
LIBNET_JOIN_AUTOMATIC,
LIBNET_JOIN_SPECIFIED,
};
enum libnet_JoinDomain_level {
LIBNET_JOINDOMAIN_AUTOMATIC,
LIBNET_JOINDOMAIN_SPECIFIED,
};
struct libnet_JoinDomain {
struct {
const char *domain_name;
const char *account_name;
const char *netbios_name;
const char *binding;
enum libnet_JoinDomain_level level;
uint32_t acct_type;
BOOL recreate_account;
} in;
struct {
const char *error_string;
const char *join_password;
struct dom_sid *domain_sid;
const char *domain_name;
const char *realm;
const char *domain_dn_str;
const char *account_dn_str;
const char *server_dn_str;
uint32_t kvno; /* msDS-KeyVersionNumber */
struct dcerpc_pipe *samr_pipe;
struct dcerpc_binding *samr_binding;
struct policy_handle *user_handle;
struct dom_sid *account_sid;
} out;
};
struct libnet_Join {
struct {
const char *domain_name;
const char *netbios_name;
enum netr_SchannelType join_type;
enum libnet_Join_level level;
} in;
struct {
const char *error_string;
const char *join_password;
struct dom_sid *domain_sid;
const char *domain_name;
} out;
};
#endif /* __LIBNET_JOIN_H__ */
+448
View File
@@ -0,0 +1,448 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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 function for name resolving
*/
#include "includes.h"
#include "lib/events/events.h"
#include "libnet/libnet.h"
#include "libcli/composite/composite.h"
#include "auth/credentials/credentials.h"
#include "lib/messaging/messaging.h"
#include "lib/messaging/irpc.h"
#include "libcli/resolve/resolve.h"
#include "libcli/finddcs.h"
#include "libcli/security/security.h"
#include "librpc/gen_ndr/lsa.h"
#include "librpc/gen_ndr/ndr_lsa_c.h"
struct lookup_state {
struct nbt_name hostname;
const char *address;
};
static void continue_name_resolved(struct composite_context *ctx);
/**
* Sends asynchronous Lookup request
*
* @param io arguments and result of the call
*/
struct composite_context *libnet_Lookup_send(struct libnet_context *ctx,
struct libnet_Lookup *io)
{
struct composite_context *c;
struct lookup_state *s;
struct composite_context *cresolve_req;
const char** methods;
/* allocate context and state structures */
c = talloc_zero(NULL, struct composite_context);
if (c == NULL) return NULL;
s = talloc_zero(c, struct lookup_state);
if (s == NULL) {
composite_error(c, NT_STATUS_NO_MEMORY);
return c;
}
/* prepare event context */
c->event_ctx = event_context_find(c);
if (c->event_ctx == NULL) {
composite_error(c, NT_STATUS_NO_MEMORY);
return c;
}
if (io == NULL || io->in.hostname == NULL) {
composite_error(c, NT_STATUS_INVALID_PARAMETER);
return c;
}
/* parameters */
s->hostname.name = talloc_strdup(s, io->in.hostname);
s->hostname.type = io->in.type;
s->hostname.scope = NULL;
/* name resolution methods */
if (io->in.methods) {
methods = io->in.methods;
} else {
methods = ctx->name_res_methods;
}
c->private_data = s;
c->state = COMPOSITE_STATE_IN_PROGRESS;
/* send resolve request */
cresolve_req = resolve_name_send(&s->hostname, c->event_ctx, methods);
composite_continue(c, cresolve_req, continue_name_resolved, c);
return c;
}
static void continue_name_resolved(struct composite_context *ctx)
{
struct composite_context *c;
struct lookup_state *s;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct lookup_state);
c->status = resolve_name_recv(ctx, s, &s->address);
composite_done(c);
}
/**
* Waits for and receives results of asynchronous Lookup call
*
* @param c composite context returned by asynchronous Lookup call
* @param mem_ctx memory context of the call
* @param io pointer to results (and arguments) of the call
* @return nt status code of execution
*/
NTSTATUS libnet_Lookup_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
struct libnet_Lookup *io)
{
NTSTATUS status;
struct lookup_state *s;
status = composite_wait(c);
if (NT_STATUS_IS_OK(status)) {
s = talloc_get_type(c->private_data, struct lookup_state);
io->out.address = str_list_make(mem_ctx, s->address, NULL);
NT_STATUS_HAVE_NO_MEMORY(io->out.address);
}
talloc_free(c);
return status;
}
/**
* Synchronous version of Lookup call
*
* @param mem_ctx memory context for the call
* @param io arguments and results of the call
* @return nt status code of execution
*/
NTSTATUS libnet_Lookup(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
struct libnet_Lookup *io)
{
struct composite_context *c = libnet_Lookup_send(ctx, io);
return libnet_Lookup_recv(c, mem_ctx, io);
}
/*
* Shortcut functions to find common types of name
* (and skip nbt name type argument)
*/
/**
* Sends asynchronous LookupHost request
*/
struct composite_context* libnet_LookupHost_send(struct libnet_context *ctx,
struct libnet_Lookup *io)
{
io->in.type = NBT_NAME_SERVER;
return libnet_Lookup_send(ctx, io);
}
/**
* Synchronous version of LookupHost call
*/
NTSTATUS libnet_LookupHost(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
struct libnet_Lookup *io)
{
struct composite_context *c = libnet_LookupHost_send(ctx, io);
return libnet_Lookup_recv(c, mem_ctx, io);
}
/**
* Sends asynchronous LookupDCs request
*/
struct composite_context* libnet_LookupDCs_send(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_LookupDCs *io)
{
struct composite_context *c;
struct messaging_context *msg_ctx = messaging_client_init(mem_ctx, ctx->event_ctx);
c = finddcs_send(mem_ctx, io->in.domain_name, io->in.name_type,
NULL, ctx->name_res_methods, ctx->event_ctx, msg_ctx);
return c;
}
/**
* Waits for and receives results of asynchronous Lookup call
*
* @param c composite context returned by asynchronous Lookup call
* @param mem_ctx memory context of the call
* @param io pointer to results (and arguments) of the call
* @return nt status code of execution
*/
NTSTATUS libnet_LookupDCs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
struct libnet_LookupDCs *io)
{
NTSTATUS status;
status = finddcs_recv(c, mem_ctx, &io->out.num_dcs, &io->out.dcs);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return status;
}
static struct composite_context* lsa_policy_opened(struct libnet_context *ctx,
const char *domain_name,
struct composite_context *parent_ctx,
struct libnet_DomainOpen *domain_open,
void (*continue_fn)(struct composite_context*),
void (*monitor)(struct monitor_msg*))
{
struct composite_context *domopen_req;
if (domain_name == NULL) {
if (policy_handle_empty(&ctx->lsa.handle)) {
domain_open->in.type = DOMAIN_LSA;
domain_open->in.domain_name = cli_credentials_get_domain(ctx->cred);
domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
} else {
composite_error(parent_ctx, NT_STATUS_INVALID_PARAMETER);
return parent_ctx;
}
} else {
if (policy_handle_empty(&ctx->lsa.handle) ||
!strequal(domain_name, ctx->lsa.name)) {
domain_open->in.type = DOMAIN_LSA;
domain_open->in.domain_name = domain_name;
domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
} else {
return NULL;
}
}
domopen_req = libnet_DomainOpen_send(ctx, domain_open, monitor);
if (composite_nomem(domopen_req, parent_ctx)) return parent_ctx;
composite_continue(parent_ctx, domopen_req, continue_fn, parent_ctx);
return parent_ctx;
}
/**
* Synchronous version of LookupDCs
*/
NTSTATUS libnet_LookupDCs(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
struct libnet_LookupDCs *io)
{
struct composite_context *c = libnet_LookupDCs_send(ctx, mem_ctx, io);
return libnet_LookupDCs_recv(c, mem_ctx, io);
}
struct lookup_name_state {
struct libnet_context *ctx;
const char *name;
uint32_t count;
struct libnet_DomainOpen domopen;
struct lsa_LookupNames lookup;
struct lsa_TransSidArray sids;
struct lsa_String *names;
/* information about the progress */
void (*monitor_fn)(struct monitor_msg *);
};
static bool prepare_lookup_params(struct libnet_context *ctx,
struct composite_context *c,
struct lookup_name_state *s);
static void continue_lookup_name(struct composite_context *ctx);
static void continue_name_found(struct rpc_request *req);
struct composite_context* libnet_LookupName_send(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_LookupName *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct lookup_name_state *s;
struct composite_context *prereq_ctx;
struct rpc_request *lookup_req;
c = composite_create(mem_ctx, ctx->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct lookup_name_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
s->name = talloc_strdup(c, io->in.name);
s->monitor_fn = monitor;
s->ctx = ctx;
prereq_ctx = lsa_policy_opened(ctx, io->in.domain_name, c, &s->domopen,
continue_lookup_name, monitor);
if (prereq_ctx) return prereq_ctx;
if (!prepare_lookup_params(ctx, c, s)) return c;
lookup_req = dcerpc_lsa_LookupNames_send(ctx->lsa.pipe, c, &s->lookup);
if (composite_nomem(lookup_req, c)) return c;
composite_continue_rpc(c, lookup_req, continue_name_found, c);
return c;
}
static bool prepare_lookup_params(struct libnet_context *ctx,
struct composite_context *c,
struct lookup_name_state *s)
{
const int single_name = 1;
s->sids.count = 0;
s->sids.sids = NULL;
s->names = talloc_array(ctx, struct lsa_String, single_name);
if (composite_nomem(s->names, c)) return false;
s->names[0].string = s->name;
s->lookup.in.handle = &ctx->lsa.handle;
s->lookup.in.num_names = single_name;
s->lookup.in.names = s->names;
s->lookup.in.sids = &s->sids;
s->lookup.in.level = 1;
s->lookup.in.count = &s->count;
s->lookup.out.count = &s->count;
s->lookup.out.sids = &s->sids;
return true;
}
static void continue_lookup_name(struct composite_context *ctx)
{
struct composite_context *c;
struct lookup_name_state *s;
struct rpc_request *lookup_req;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct lookup_name_state);
c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domopen);
if (!composite_is_ok(c)) return;
if (!prepare_lookup_params(s->ctx, c, s)) return;
lookup_req = dcerpc_lsa_LookupNames_send(s->ctx->lsa.pipe, c, &s->lookup);
if (composite_nomem(lookup_req, c)) return;
composite_continue_rpc(c, lookup_req, continue_name_found, c);
}
static void continue_name_found(struct rpc_request *req)
{
struct composite_context *c;
struct lookup_name_state *s;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct lookup_name_state);
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
composite_done(c);
}
NTSTATUS libnet_LookupName_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
struct libnet_LookupName *io)
{
NTSTATUS status;
struct lookup_name_state *s;
status = composite_wait(c);
if (NT_STATUS_IS_OK(status)) {
s = talloc_get_type(c->private_data, struct lookup_name_state);
ZERO_STRUCT(io->out.domain_sid);
io->out.rid = 0;
io->out.sidstr = NULL;
if (*s->lookup.out.count > 0) {
int num_auths;
struct lsa_RefDomainList *domains = s->lookup.out.domains;
struct lsa_TransSidArray *sids = s->lookup.out.sids;
/* TODO: verify if returned pointers are non-null */
io->out.domain_sid = *domains->domains[0].sid;
io->out.rid = sids->sids[0].rid;
io->out.sid_type = sids->sids[0].sid_type;
num_auths = io->out.domain_sid.num_auths++;
io->out.domain_sid.sub_auths[num_auths] = io->out.rid;
io->out.sidstr = dom_sid_string(mem_ctx, &io->out.domain_sid);
}
io->out.error_string = talloc_strdup(mem_ctx, "Success");
} else if (!NT_STATUS_IS_OK(status)) {
io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
}
return status;
}
NTSTATUS libnet_LookupName(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
struct libnet_LookupName *io)
{
struct composite_context *c;
c = libnet_LookupName_send(ctx, mem_ctx, io, NULL);
return libnet_LookupName_recv(c, mem_ctx, io);
}
+58
View File
@@ -0,0 +1,58 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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.
*/
struct libnet_Lookup {
struct {
const char *hostname;
int type;
const char **methods;
} in;
struct {
const char **address;
} out;
};
struct libnet_LookupDCs {
struct {
const char *domain_name;
int name_type;
} in;
struct {
int num_dcs;
struct nbt_dc_name *dcs;
} out;
};
struct libnet_LookupName {
struct {
const char *name;
const char *domain_name;
} in;
struct {
struct dom_sid domain_sid;
int rid;
enum lsa_SidType sid_type;
const char *sidstr;
const char *error_string;
} out;
};
+703
View File
@@ -0,0 +1,703 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
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 "libnet/libnet.h"
#include "lib/crypto/crypto.h"
#include "libcli/auth/libcli_auth.h"
#include "librpc/gen_ndr/ndr_samr_c.h"
/*
* do a password change using DCERPC/SAMR calls
* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
* 2. try samr_ChangePasswordUser3
* 3. try samr_ChangePasswordUser2
* 4. try samr_OemChangePasswordUser2
* (not yet: 5. try samr_ChangePasswordUser)
*/
static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
{
NTSTATUS status;
struct libnet_RpcConnect c;
#if 0
struct policy_handle user_handle;
struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
struct samr_ChangePasswordUser pw;
#endif
struct samr_OemChangePasswordUser2 oe2;
struct samr_ChangePasswordUser2 pw2;
struct samr_ChangePasswordUser3 pw3;
struct lsa_String server, account;
struct lsa_AsciiString a_server, a_account;
struct samr_CryptPassword nt_pass, lm_pass;
struct samr_Password nt_verifier, lm_verifier;
uint8_t old_nt_hash[16], new_nt_hash[16];
uint8_t old_lm_hash[16], new_lm_hash[16];
/* prepare connect to the SAMR pipe of the users domain PDC */
c.level = LIBNET_RPC_CONNECT_PDC;
c.in.name = r->samr.in.domain_name;
c.in.dcerpc_iface = &dcerpc_table_samr;
/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"Connection to SAMR pipe of PDC of domain '%s' failed: %s",
r->samr.in.domain_name, nt_errstr(status));
return status;
}
/* prepare password change for account */
server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
account.string = r->samr.in.account_name;
E_md4hash(r->samr.in.oldpassword, old_nt_hash);
E_md4hash(r->samr.in.newpassword, new_nt_hash);
E_deshash(r->samr.in.oldpassword, old_lm_hash);
E_deshash(r->samr.in.newpassword, new_lm_hash);
/* prepare samr_ChangePasswordUser3 */
encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE);
arcfour_crypt(lm_pass.data, old_nt_hash, 516);
E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
arcfour_crypt(nt_pass.data, old_nt_hash, 516);
E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
pw3.in.server = &server;
pw3.in.account = &account;
pw3.in.nt_password = &nt_pass;
pw3.in.nt_verifier = &nt_verifier;
pw3.in.lm_change = 1;
pw3.in.lm_password = &lm_pass;
pw3.in.lm_verifier = &lm_verifier;
pw3.in.password3 = NULL;
/* 2. try samr_ChangePasswordUser3 */
status = dcerpc_samr_ChangePasswordUser3(c.out.dcerpc_pipe, mem_ctx, &pw3);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_ChangePasswordUser3 failed: %s",
nt_errstr(status));
goto ChangePasswordUser2;
}
/* check result of samr_ChangePasswordUser3 */
if (!NT_STATUS_IS_OK(pw3.out.result)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_ChangePasswordUser3 for '%s\\%s' failed: %s",
r->samr.in.domain_name, r->samr.in.account_name,
nt_errstr(pw3.out.result));
/* TODO: give the reason of the reject */
if (NT_STATUS_EQUAL(pw3.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
status = pw3.out.result;
goto disconnect;
}
goto ChangePasswordUser2;
}
goto disconnect;
ChangePasswordUser2:
/* prepare samr_ChangePasswordUser2 */
encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
arcfour_crypt(lm_pass.data, old_lm_hash, 516);
E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
arcfour_crypt(nt_pass.data, old_nt_hash, 516);
E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
pw2.in.server = &server;
pw2.in.account = &account;
pw2.in.nt_password = &nt_pass;
pw2.in.nt_verifier = &nt_verifier;
pw2.in.lm_change = 1;
pw2.in.lm_password = &lm_pass;
pw2.in.lm_verifier = &lm_verifier;
/* 3. try samr_ChangePasswordUser2 */
status = dcerpc_samr_ChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &pw2);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_ChangePasswordUser2 failed: %s",
nt_errstr(status));
goto OemChangePasswordUser2;
}
/* check result of samr_ChangePasswordUser2 */
if (!NT_STATUS_IS_OK(pw2.out.result)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_ChangePasswordUser2 for '%s\\%s' failed: %s",
r->samr.in.domain_name, r->samr.in.account_name,
nt_errstr(pw2.out.result));
if (NT_STATUS_EQUAL(pw2.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
status = pw2.out.result;
goto disconnect;
}
goto OemChangePasswordUser2;
}
goto disconnect;
OemChangePasswordUser2:
/* prepare samr_OemChangePasswordUser2 */
a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
a_account.string = r->samr.in.account_name;
encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
arcfour_crypt(lm_pass.data, old_lm_hash, 516);
E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
oe2.in.server = &a_server;
oe2.in.account = &a_account;
oe2.in.password = &lm_pass;
oe2.in.hash = &lm_verifier;
/* 4. try samr_OemChangePasswordUser2 */
status = dcerpc_samr_OemChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &oe2);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_OemChangePasswordUser2 failed: %s",
nt_errstr(status));
goto ChangePasswordUser;
}
/* check result of samr_OemChangePasswordUser2 */
if (!NT_STATUS_IS_OK(oe2.out.result)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_OemChangePasswordUser2 for '%s\\%s' failed: %s",
r->samr.in.domain_name, r->samr.in.account_name,
nt_errstr(oe2.out.result));
if (NT_STATUS_EQUAL(oe2.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
status = oe2.out.result;
goto disconnect;
}
goto ChangePasswordUser;
}
goto disconnect;
ChangePasswordUser:
#if 0
/* prepare samr_ChangePasswordUser */
E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
/* TODO: ask for a user_handle */
pw.in.handle = &user_handle;
pw.in.lm_present = 1;
pw.in.old_lm_crypted = &hash1;
pw.in.new_lm_crypted = &hash2;
pw.in.nt_present = 1;
pw.in.old_nt_crypted = &hash3;
pw.in.new_nt_crypted = &hash4;
pw.in.cross1_present = 1;
pw.in.nt_cross = &hash5;
pw.in.cross2_present = 1;
pw.in.lm_cross = &hash6;
/* 5. try samr_ChangePasswordUser */
status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_ChangePasswordUser failed: %s",
nt_errstr(status));
goto disconnect;
}
/* check result of samr_ChangePasswordUser */
if (!NT_STATUS_IS_OK(pw.out.result)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_ChangePasswordUser for '%s\\%s' failed: %s",
r->samr.in.domain_name, r->samr.in.account_name,
nt_errstr(pw.out.result));
if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
status = pw.out.result;
goto disconnect;
}
goto disconnect;
}
#endif
disconnect:
/* close connection */
talloc_free(c.out.dcerpc_pipe);
return status;
}
static NTSTATUS libnet_ChangePassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
{
NTSTATUS status;
union libnet_ChangePassword r2;
r2.samr.level = LIBNET_CHANGE_PASSWORD_SAMR;
r2.samr.in.account_name = r->generic.in.account_name;
r2.samr.in.domain_name = r->generic.in.domain_name;
r2.samr.in.oldpassword = r->generic.in.oldpassword;
r2.samr.in.newpassword = r->generic.in.newpassword;
status = libnet_ChangePassword(ctx, mem_ctx, &r2);
r->generic.out.error_string = r2.samr.out.error_string;
return status;
}
NTSTATUS libnet_ChangePassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
{
switch (r->generic.level) {
case LIBNET_CHANGE_PASSWORD_GENERIC:
return libnet_ChangePassword_generic(ctx, mem_ctx, r);
case LIBNET_CHANGE_PASSWORD_SAMR:
return libnet_ChangePassword_samr(ctx, mem_ctx, r);
case LIBNET_CHANGE_PASSWORD_KRB5:
return NT_STATUS_NOT_IMPLEMENTED;
case LIBNET_CHANGE_PASSWORD_LDAP:
return NT_STATUS_NOT_IMPLEMENTED;
case LIBNET_CHANGE_PASSWORD_RAP:
return NT_STATUS_NOT_IMPLEMENTED;
}
return NT_STATUS_INVALID_LEVEL;
}
static NTSTATUS libnet_SetPassword_samr_handle_26(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
NTSTATUS status;
struct samr_SetUserInfo2 sui;
union samr_UserInfo u_info;
DATA_BLOB session_key;
DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
uint8_t confounder[16];
struct MD5Context md5;
if (r->samr_handle.in.info21) {
return NT_STATUS_INVALID_PARAMETER_MIX;
}
/* prepare samr_SetUserInfo2 level 26 */
ZERO_STRUCT(u_info);
encode_pw_buffer(u_info.info26.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
u_info.info26.pw_len = strlen(r->samr_handle.in.newpassword);
status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
if (!NT_STATUS_IS_OK(status)) {
r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
"dcerpc_fetch_session_key failed: %s",
nt_errstr(status));
return status;
}
generate_random_buffer((uint8_t *)confounder, 16);
MD5Init(&md5);
MD5Update(&md5, confounder, 16);
MD5Update(&md5, session_key.data, session_key.length);
MD5Final(confounded_session_key.data, &md5);
arcfour_crypt_blob(u_info.info26.password.data, 516, &confounded_session_key);
memcpy(&u_info.info26.password.data[516], confounder, 16);
sui.in.user_handle = r->samr_handle.in.user_handle;
sui.in.info = &u_info;
sui.in.level = 26;
/* 7. try samr_SetUserInfo2 level 26 to set the password */
status = dcerpc_samr_SetUserInfo2(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
/* check result of samr_SetUserInfo2 level 26 */
if (!NT_STATUS_IS_OK(status)) {
r->samr_handle.out.error_string
= talloc_asprintf(mem_ctx,
"SetUserInfo2 level 26 for [%s] failed: %s",
r->samr_handle.in.account_name, nt_errstr(status));
}
return status;
}
static NTSTATUS libnet_SetPassword_samr_handle_25(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
NTSTATUS status;
struct samr_SetUserInfo2 sui;
union samr_UserInfo u_info;
DATA_BLOB session_key;
DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
uint8_t confounder[16];
struct MD5Context md5;
if (!r->samr_handle.in.info21) {
return NT_STATUS_INVALID_PARAMETER_MIX;
}
/* prepare samr_SetUserInfo2 level 25 */
ZERO_STRUCT(u_info);
u_info.info25.info = *r->samr_handle.in.info21;
u_info.info25.info.fields_present |= SAMR_FIELD_PASSWORD;
encode_pw_buffer(u_info.info25.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
if (!NT_STATUS_IS_OK(status)) {
r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
"dcerpc_fetch_session_key failed: %s",
nt_errstr(status));
return status;
}
generate_random_buffer((uint8_t *)confounder, 16);
MD5Init(&md5);
MD5Update(&md5, confounder, 16);
MD5Update(&md5, session_key.data, session_key.length);
MD5Final(confounded_session_key.data, &md5);
arcfour_crypt_blob(u_info.info25.password.data, 516, &confounded_session_key);
memcpy(&u_info.info25.password.data[516], confounder, 16);
sui.in.user_handle = r->samr_handle.in.user_handle;
sui.in.info = &u_info;
sui.in.level = 25;
/* 8. try samr_SetUserInfo2 level 25 to set the password */
status = dcerpc_samr_SetUserInfo2(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
if (!NT_STATUS_IS_OK(status)) {
r->samr_handle.out.error_string
= talloc_asprintf(mem_ctx,
"SetUserInfo2 level 25 for [%s] failed: %s",
r->samr_handle.in.account_name, nt_errstr(status));
}
return status;
}
static NTSTATUS libnet_SetPassword_samr_handle_24(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
NTSTATUS status;
struct samr_SetUserInfo2 sui;
union samr_UserInfo u_info;
DATA_BLOB session_key;
if (r->samr_handle.in.info21) {
return NT_STATUS_INVALID_PARAMETER_MIX;
}
/* prepare samr_SetUserInfo2 level 24 */
ZERO_STRUCT(u_info);
encode_pw_buffer(u_info.info24.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
/* w2k3 ignores this length */
u_info.info24.pw_len = strlen_m(r->samr_handle.in.newpassword)*2;
status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
if (!NT_STATUS_IS_OK(status)) {
r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
"dcerpc_fetch_session_key failed: %s",
nt_errstr(status));
return status;
}
arcfour_crypt_blob(u_info.info24.password.data, 516, &session_key);
sui.in.user_handle = r->samr_handle.in.user_handle;
sui.in.info = &u_info;
sui.in.level = 24;
/* 9. try samr_SetUserInfo2 level 24 to set the password */
status = dcerpc_samr_SetUserInfo2(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
if (!NT_STATUS_IS_OK(status)) {
r->samr_handle.out.error_string
= talloc_asprintf(mem_ctx,
"SetUserInfo2 level 24 for [%s] failed: %s",
r->samr_handle.in.account_name, nt_errstr(status));
}
return status;
}
static NTSTATUS libnet_SetPassword_samr_handle_23(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
NTSTATUS status;
struct samr_SetUserInfo2 sui;
union samr_UserInfo u_info;
DATA_BLOB session_key;
if (!r->samr_handle.in.info21) {
return NT_STATUS_INVALID_PARAMETER_MIX;
}
/* prepare samr_SetUserInfo2 level 23 */
ZERO_STRUCT(u_info);
u_info.info23.info = *r->samr_handle.in.info21;
u_info.info23.info.fields_present |= SAMR_FIELD_PASSWORD;
encode_pw_buffer(u_info.info23.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
if (!NT_STATUS_IS_OK(status)) {
r->samr_handle.out.error_string
= talloc_asprintf(mem_ctx,
"dcerpc_fetch_session_key failed: %s",
nt_errstr(status));
return status;
}
arcfour_crypt_blob(u_info.info23.password.data, 516, &session_key);
sui.in.user_handle = r->samr_handle.in.user_handle;
sui.in.info = &u_info;
sui.in.level = 23;
/* 10. try samr_SetUserInfo2 level 23 to set the password */
status = dcerpc_samr_SetUserInfo2(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
if (!NT_STATUS_IS_OK(status)) {
r->samr_handle.out.error_string
= talloc_asprintf(mem_ctx,
"SetUserInfo2 level 23 for [%s] failed: %s",
r->samr_handle.in.account_name, nt_errstr(status));
}
return status;
}
/*
* 1. try samr_SetUserInfo2 level 26 to set the password
* 2. try samr_SetUserInfo2 level 25 to set the password
* 3. try samr_SetUserInfo2 level 24 to set the password
* 4. try samr_SetUserInfo2 level 23 to set the password
*/
static NTSTATUS libnet_SetPassword_samr_handle(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
NTSTATUS status;
enum libnet_SetPassword_level levels[] = {
LIBNET_SET_PASSWORD_SAMR_HANDLE_26,
LIBNET_SET_PASSWORD_SAMR_HANDLE_25,
LIBNET_SET_PASSWORD_SAMR_HANDLE_24,
LIBNET_SET_PASSWORD_SAMR_HANDLE_23,
};
int i;
for (i=0; i < ARRAY_SIZE(levels); i++) {
r->generic.level = levels[i];
status = libnet_SetPassword(ctx, mem_ctx, r);
if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)
|| NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER_MIX)
|| NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
/* Try another password set mechanism */
continue;
}
break;
}
return status;
}
/*
* set a password with DCERPC/SAMR calls
* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
* is it correct to contact the the pdc of the domain of the user who's password should be set?
* 2. do a samr_Connect to get a policy handle
* 3. do a samr_LookupDomain to get the domain sid
* 4. do a samr_OpenDomain to get a domain handle
* 5. do a samr_LookupNames to get the users rid
* 6. do a samr_OpenUser to get a user handle
* 7 call libnet_SetPassword_samr_handle to set the password
*/
static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
NTSTATUS status;
struct libnet_RpcConnect c;
struct samr_Connect sc;
struct policy_handle p_handle;
struct samr_LookupDomain ld;
struct lsa_String d_name;
struct samr_OpenDomain od;
struct policy_handle d_handle;
struct samr_LookupNames ln;
struct samr_OpenUser ou;
struct policy_handle u_handle;
union libnet_SetPassword r2;
/* prepare connect to the SAMR pipe of users domain PDC */
c.level = LIBNET_RPC_CONNECT_PDC;
c.in.name = r->samr.in.domain_name;
c.in.dcerpc_iface = &dcerpc_table_samr;
/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"Connection to SAMR pipe of PDC of domain '%s' failed: %s",
r->samr.in.domain_name, nt_errstr(status));
return status;
}
/* prepare samr_Connect */
ZERO_STRUCT(p_handle);
sc.in.system_name = NULL;
sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
sc.out.connect_handle = &p_handle;
/* 2. do a samr_Connect to get a policy handle */
status = dcerpc_samr_Connect(c.out.dcerpc_pipe, mem_ctx, &sc);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_Connect failed: %s",
nt_errstr(status));
goto disconnect;
}
/* prepare samr_LookupDomain */
d_name.string = r->samr.in.domain_name;
ld.in.connect_handle = &p_handle;
ld.in.domain_name = &d_name;
/* 3. do a samr_LookupDomain to get the domain sid */
status = dcerpc_samr_LookupDomain(c.out.dcerpc_pipe, mem_ctx, &ld);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_LookupDomain for [%s] failed: %s",
r->samr.in.domain_name, nt_errstr(status));
goto disconnect;
}
/* prepare samr_OpenDomain */
ZERO_STRUCT(d_handle);
od.in.connect_handle = &p_handle;
od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
od.in.sid = ld.out.sid;
od.out.domain_handle = &d_handle;
/* 4. do a samr_OpenDomain to get a domain handle */
status = dcerpc_samr_OpenDomain(c.out.dcerpc_pipe, mem_ctx, &od);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_OpenDomain for [%s] failed: %s",
r->samr.in.domain_name, nt_errstr(status));
goto disconnect;
}
/* prepare samr_LookupNames */
ln.in.domain_handle = &d_handle;
ln.in.num_names = 1;
ln.in.names = talloc_array(mem_ctx, struct lsa_String, 1);
if (!ln.in.names) {
r->samr.out.error_string = "Out of Memory";
return NT_STATUS_NO_MEMORY;
}
ln.in.names[0].string = r->samr.in.account_name;
/* 5. do a samr_LookupNames to get the users rid */
status = dcerpc_samr_LookupNames(c.out.dcerpc_pipe, mem_ctx, &ln);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_LookupNames for [%s] failed: %s",
r->samr.in.account_name, nt_errstr(status));
goto disconnect;
}
/* check if we got one RID for the user */
if (ln.out.rids.count != 1) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_LookupNames for [%s] returns %d RIDs",
r->samr.in.account_name, ln.out.rids.count);
status = NT_STATUS_INVALID_PARAMETER;
goto disconnect;
}
/* prepare samr_OpenUser */
ZERO_STRUCT(u_handle);
ou.in.domain_handle = &d_handle;
ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
ou.in.rid = ln.out.rids.ids[0];
ou.out.user_handle = &u_handle;
/* 6. do a samr_OpenUser to get a user handle */
status = dcerpc_samr_OpenUser(c.out.dcerpc_pipe, mem_ctx, &ou);
if (!NT_STATUS_IS_OK(status)) {
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_OpenUser for [%s] failed: %s",
r->samr.in.account_name, nt_errstr(status));
goto disconnect;
}
r2.samr_handle.level = LIBNET_SET_PASSWORD_SAMR_HANDLE;
r2.samr_handle.in.account_name = r->samr.in.account_name;
r2.samr_handle.in.newpassword = r->samr.in.newpassword;
r2.samr_handle.in.user_handle = &u_handle;
r2.samr_handle.in.dcerpc_pipe = c.out.dcerpc_pipe;
status = libnet_SetPassword(ctx, mem_ctx, &r2);
r->generic.out.error_string = r2.samr_handle.out.error_string;
disconnect:
/* close connection */
talloc_free(c.out.dcerpc_pipe);
return status;
}
static NTSTATUS libnet_SetPassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
NTSTATUS status;
union libnet_SetPassword r2;
r2.samr.level = LIBNET_SET_PASSWORD_SAMR;
r2.samr.in.account_name = r->generic.in.account_name;
r2.samr.in.domain_name = r->generic.in.domain_name;
r2.samr.in.newpassword = r->generic.in.newpassword;
r->generic.out.error_string = "Unknown Error";
status = libnet_SetPassword(ctx, mem_ctx, &r2);
r->generic.out.error_string = r2.samr.out.error_string;
return status;
}
NTSTATUS libnet_SetPassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
switch (r->generic.level) {
case LIBNET_SET_PASSWORD_GENERIC:
return libnet_SetPassword_generic(ctx, mem_ctx, r);
case LIBNET_SET_PASSWORD_SAMR:
return libnet_SetPassword_samr(ctx, mem_ctx, r);
case LIBNET_SET_PASSWORD_SAMR_HANDLE:
return libnet_SetPassword_samr_handle(ctx, mem_ctx, r);
case LIBNET_SET_PASSWORD_SAMR_HANDLE_26:
return libnet_SetPassword_samr_handle_26(ctx, mem_ctx, r);
case LIBNET_SET_PASSWORD_SAMR_HANDLE_25:
return libnet_SetPassword_samr_handle_25(ctx, mem_ctx, r);
case LIBNET_SET_PASSWORD_SAMR_HANDLE_24:
return libnet_SetPassword_samr_handle_24(ctx, mem_ctx, r);
case LIBNET_SET_PASSWORD_SAMR_HANDLE_23:
return libnet_SetPassword_samr_handle_23(ctx, mem_ctx, r);
case LIBNET_SET_PASSWORD_KRB5:
return NT_STATUS_NOT_IMPLEMENTED;
case LIBNET_SET_PASSWORD_LDAP:
return NT_STATUS_NOT_IMPLEMENTED;
case LIBNET_SET_PASSWORD_RAP:
return NT_STATUS_NOT_IMPLEMENTED;
}
return NT_STATUS_INVALID_LEVEL;
}
+138
View File
@@ -0,0 +1,138 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
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.
*/
/* struct and enum for doing a remote password change */
enum libnet_ChangePassword_level {
LIBNET_CHANGE_PASSWORD_GENERIC,
LIBNET_CHANGE_PASSWORD_SAMR,
LIBNET_CHANGE_PASSWORD_KRB5,
LIBNET_CHANGE_PASSWORD_LDAP,
LIBNET_CHANGE_PASSWORD_RAP
};
union libnet_ChangePassword {
struct {
enum libnet_ChangePassword_level level;
struct _libnet_ChangePassword_in {
const char *account_name;
const char *domain_name;
const char *oldpassword;
const char *newpassword;
} in;
struct _libnet_ChangePassword_out {
const char *error_string;
} out;
} generic;
struct {
enum libnet_ChangePassword_level level;
struct _libnet_ChangePassword_in in;
struct _libnet_ChangePassword_out out;
} samr;
struct {
enum libnet_ChangePassword_level level;
struct _libnet_ChangePassword_in in;
struct _libnet_ChangePassword_out out;
} krb5;
struct {
enum libnet_ChangePassword_level level;
struct _libnet_ChangePassword_in in;
struct _libnet_ChangePassword_out out;
} ldap;
struct {
enum libnet_ChangePassword_level level;
struct _libnet_ChangePassword_in in;
struct _libnet_ChangePassword_out out;
} rap;
};
/* struct and enum for doing a remote password set */
enum libnet_SetPassword_level {
LIBNET_SET_PASSWORD_GENERIC,
LIBNET_SET_PASSWORD_SAMR,
LIBNET_SET_PASSWORD_SAMR_HANDLE,
LIBNET_SET_PASSWORD_SAMR_HANDLE_26,
LIBNET_SET_PASSWORD_SAMR_HANDLE_25,
LIBNET_SET_PASSWORD_SAMR_HANDLE_24,
LIBNET_SET_PASSWORD_SAMR_HANDLE_23,
LIBNET_SET_PASSWORD_KRB5,
LIBNET_SET_PASSWORD_LDAP,
LIBNET_SET_PASSWORD_RAP
};
union libnet_SetPassword {
struct {
enum libnet_SetPassword_level level;
struct _libnet_SetPassword_in {
const char *account_name;
const char *domain_name;
const char *newpassword;
} in;
struct _libnet_SetPassword_out {
const char *error_string;
} out;
} generic;
struct {
enum libnet_SetPassword_level level;
struct _libnet_SetPassword_samr_handle_in {
const char *account_name; /* for debug only */
struct policy_handle *user_handle;
struct dcerpc_pipe *dcerpc_pipe;
const char *newpassword;
struct samr_UserInfo21 *info21; /* can be NULL,
* for level 26,24 it must be NULL
* for level 25,23 it must be non-NULL
*/
} in;
struct _libnet_SetPassword_out out;
} samr_handle;
struct {
enum libnet_SetPassword_level level;
struct _libnet_SetPassword_in in;
struct _libnet_SetPassword_out out;
} samr;
struct {
enum libnet_SetPassword_level level;
struct _libnet_SetPassword_in in;
struct _libnet_SetPassword_out out;
} krb5;
struct {
enum libnet_SetPassword_level level;
struct _libnet_SetPassword_in in;
struct _libnet_SetPassword_out out;
} ldap;
struct {
enum libnet_ChangePassword_level level;
struct _libnet_SetPassword_in in;
struct _libnet_SetPassword_out out;
} rap;
};
+871
View File
@@ -0,0 +1,871 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
Copyright (C) Rafal Szczesniak 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 "libnet/libnet.h"
#include "libcli/libcli.h"
#include "libcli/composite/composite.h"
#include "librpc/rpc/dcerpc.h"
#include "librpc/gen_ndr/ndr_lsa_c.h"
#include "librpc/gen_ndr/ndr_samr.h"
struct rpc_connect_srv_state {
struct libnet_context *ctx;
struct libnet_RpcConnect r;
const char *binding;
};
static void continue_pipe_connect(struct composite_context *ctx);
/**
* Initiates connection to rpc pipe on remote server
*
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing necessary parameters and return values
* @return composite context of this call
**/
static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_RpcConnect *r)
{
struct composite_context *c;
struct rpc_connect_srv_state *s;
struct dcerpc_binding *b;
struct composite_context *pipe_connect_req;
/* composite context allocation and setup */
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
s = talloc_zero(c, struct rpc_connect_srv_state);
if (composite_nomem(s, c)) return c;
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
c->event_ctx = ctx->event_ctx;
s->ctx = ctx;
s->r = *r;
ZERO_STRUCT(s->r.out);
/* prepare binding string */
switch (r->level) {
case LIBNET_RPC_CONNECT_SERVER:
s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
break;
case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.address);
break;
case LIBNET_RPC_CONNECT_BINDING:
s->binding = talloc_strdup(s, r->in.binding);
break;
case LIBNET_RPC_CONNECT_DC:
case LIBNET_RPC_CONNECT_PDC:
/* this should never happen - DC and PDC level has a separate
composite function */
case LIBNET_RPC_CONNECT_DC_INFO:
/* this should never happen - DC_INFO level has a separate
composite function */
composite_error(c, NT_STATUS_INVALID_LEVEL);
return c;
}
/* parse binding string to the structure */
c->status = dcerpc_parse_binding(c, s->binding, &b);
if (!NT_STATUS_IS_OK(c->status)) {
DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));
composite_error(c, c->status);
return c;
}
if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) {
b->target_hostname = talloc_reference(b, r->in.name);
if (composite_nomem(b->target_hostname, c)) {
return c;
}
}
/* connect to remote dcerpc pipe */
pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
ctx->cred, c->event_ctx);
if (composite_nomem(pipe_connect_req, c)) return c;
composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
return c;
}
/*
Step 2 of RpcConnectSrv - get rpc connection
*/
static void continue_pipe_connect(struct composite_context *ctx)
{
struct composite_context *c;
struct rpc_connect_srv_state *s;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
/* receive result of rpc pipe connection */
c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
composite_done(c);
}
/**
* Receives result of connection to rpc pipe on remote server
*
* @param c composite context
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing necessary parameters and return values
* @return nt status of rpc connection
**/
static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_RpcConnect *r)
{
NTSTATUS status;
struct rpc_connect_srv_state *s = talloc_get_type(c->private_data,
struct rpc_connect_srv_state);
status = composite_wait(c);
if (NT_STATUS_IS_OK(status)) {
/* move the returned rpc pipe between memory contexts */
s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
/* reference created pipe structure to long-term libnet_context
so that it can be used by other api functions even after short-term
mem_ctx is freed */
if (r->in.dcerpc_iface == &dcerpc_table_samr) {
ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
} else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
}
r->out.error_string = talloc_strdup(mem_ctx, "Success");
} else {
r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
}
talloc_free(c);
return status;
}
struct rpc_connect_dc_state {
struct libnet_context *ctx;
struct libnet_RpcConnect r;
struct libnet_RpcConnect r2;
struct libnet_LookupDCs f;
const char *connect_name;
/* information about the progress */
void (*monitor_fn)(struct monitor_msg *);
};
static void continue_lookup_dc(struct composite_context *ctx);
static void continue_rpc_connect(struct composite_context *ctx);
/**
* Initiates connection to rpc pipe on domain pdc
*
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing necessary parameters and return values
* @return composite context of this call
**/
static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_RpcConnect *r)
{
struct composite_context *c;
struct rpc_connect_dc_state *s;
struct composite_context *lookup_dc_req;
/* composite context allocation and setup */
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
s = talloc_zero(c, struct rpc_connect_dc_state);
if (composite_nomem(s, c)) return c;
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
c->event_ctx = ctx->event_ctx;
s->ctx = ctx;
s->r = *r;
ZERO_STRUCT(s->r.out);
switch (r->level) {
case LIBNET_RPC_CONNECT_PDC:
s->f.in.name_type = NBT_NAME_PDC;
break;
case LIBNET_RPC_CONNECT_DC:
s->f.in.name_type = NBT_NAME_LOGON;
break;
default:
break;
}
s->f.in.domain_name = r->in.name;
s->f.out.num_dcs = 0;
s->f.out.dcs = NULL;
/* find the domain pdc first */
lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
if (composite_nomem(lookup_dc_req, c)) return c;
composite_continue(c, lookup_dc_req, continue_lookup_dc, c);
return c;
}
/*
Step 2 of RpcConnectDC: get domain controller name and
initiate RpcConnect to it
*/
static void continue_lookup_dc(struct composite_context *ctx)
{
struct composite_context *c;
struct rpc_connect_dc_state *s;
struct composite_context *rpc_connect_req;
struct monitor_msg msg;
struct msg_net_lookup_dc data;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
/* receive result of domain controller lookup */
c->status = libnet_LookupDCs_recv(ctx, c, &s->f);
if (!composite_is_ok(c)) return;
/* decide on preferred address type depending on DC type */
s->connect_name = s->f.out.dcs[0].name;
/* prepare a monitor message and post it */
msg.type = net_lookup_dc;
msg.data = &data;
msg.data_size = sizeof(data);
data.domain_name = s->f.in.domain_name;
data.hostname = s->f.out.dcs[0].name;
data.address = s->f.out.dcs[0].address;
if (s->monitor_fn) s->monitor_fn(&msg);
/* ok, pdc has been found so do attempt to rpc connect */
s->r2.level = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
/* this will cause yet another name resolution, but at least
* we pass the right name down the stack now */
s->r2.in.name = talloc_strdup(s, s->connect_name);
s->r2.in.address = talloc_steal(s, s->f.out.dcs[0].address);
s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface;
/* send rpc connect request to the server */
rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2);
if (composite_nomem(rpc_connect_req, c)) return;
composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
}
/*
Step 3 of RpcConnectDC: get rpc connection to the server
*/
static void continue_rpc_connect(struct composite_context *ctx)
{
struct composite_context *c;
struct rpc_connect_dc_state *s;
struct monitor_msg msg;
struct msg_net_pipe_connected data;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
/* error string is to be passed anyway */
s->r.out.error_string = s->r2.out.error_string;
if (!composite_is_ok(c)) return;
s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
/* prepare a monitor message and post it */
data.host = s->r.out.dcerpc_pipe->binding->host;
data.endpoint = s->r.out.dcerpc_pipe->binding->endpoint;
data.transport = s->r.out.dcerpc_pipe->binding->transport;
msg.type = net_pipe_connected;
msg.data = (void*)&data;
msg.data_size = sizeof(data);
if (s->monitor_fn) s->monitor_fn(&msg);
composite_done(c);
}
/**
* Receives result of connection to rpc pipe on domain pdc
*
* @param c composite context
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing necessary parameters and return values
* @return nt status of rpc connection
**/
static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_RpcConnect *r)
{
NTSTATUS status;
struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
struct rpc_connect_dc_state);
status = composite_wait(c);
if (NT_STATUS_IS_OK(status)) {
/* move connected rpc pipe between memory contexts */
r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
/* reference created pipe structure to long-term libnet_context
so that it can be used by other api functions even after short-term
mem_ctx is freed */
if (r->in.dcerpc_iface == &dcerpc_table_samr) {
ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
} else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
}
} else {
r->out.error_string = talloc_asprintf(mem_ctx,
"Failed to rpc connect: %s",
nt_errstr(status));
}
talloc_free(c);
return status;
}
struct rpc_connect_dci_state {
struct libnet_context *ctx;
struct libnet_RpcConnect r;
struct libnet_RpcConnect rpc_conn;
struct policy_handle lsa_handle;
struct lsa_QosInfo qos;
struct lsa_ObjectAttribute attr;
struct lsa_OpenPolicy2 lsa_open_policy;
struct dcerpc_pipe *lsa_pipe;
struct lsa_QueryInfoPolicy2 lsa_query_info2;
struct lsa_QueryInfoPolicy lsa_query_info;
struct dcerpc_binding *final_binding;
struct dcerpc_pipe *final_pipe;
};
static void continue_dci_rpc_connect(struct composite_context *ctx);
static void continue_lsa_policy(struct rpc_request *req);
static void continue_lsa_query_info(struct rpc_request *req);
static void continue_lsa_query_info2(struct rpc_request *req);
static void continue_epm_map_binding(struct composite_context *ctx);
static void continue_secondary_conn(struct composite_context *ctx);
static void continue_epm_map_binding_send(struct composite_context *c);
/**
* Initiates connection to rpc pipe on remote server or pdc. Received result
* contains info on the domain name, domain sid and realm.
*
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing necessary parameters and return values. Must be a talloc context
* @return composite context of this call
**/
static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_RpcConnect *r)
{
struct composite_context *c, *conn_req;
struct rpc_connect_dci_state *s;
/* composite context allocation and setup */
c = talloc_zero(mem_ctx, struct composite_context);
if (c == NULL) return NULL;
s = talloc_zero(c, struct rpc_connect_dci_state);
if (composite_nomem(s, c)) return c;
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
c->event_ctx = ctx->event_ctx;
s->ctx = ctx;
s->r = *r;
ZERO_STRUCT(s->r.out);
/* proceed to pure rpc connection if the binding string is provided,
otherwise try to connect domain controller */
if (r->in.binding == NULL) {
s->rpc_conn.in.name = r->in.name;
s->rpc_conn.level = LIBNET_RPC_CONNECT_DC;
} else {
s->rpc_conn.in.binding = r->in.binding;
s->rpc_conn.level = LIBNET_RPC_CONNECT_BINDING;
}
/* we need to query information on lsarpc interface first */
s->rpc_conn.in.dcerpc_iface = &dcerpc_table_lsarpc;
/* request connection to the lsa pipe on the pdc */
conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn);
if (composite_nomem(c, conn_req)) return c;
composite_continue(c, conn_req, continue_dci_rpc_connect, c);
return c;
}
/*
Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
lsa policy handle
*/
static void continue_dci_rpc_connect(struct composite_context *ctx)
{
struct composite_context *c;
struct rpc_connect_dci_state *s;
struct rpc_request *open_pol_req;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
if (!NT_STATUS_IS_OK(c->status)) {
composite_error(c, c->status);
return;
}
/* prepare to open a policy handle on lsa pipe */
s->lsa_pipe = s->ctx->lsa.pipe;
s->qos.len = 0;
s->qos.impersonation_level = 2;
s->qos.context_mode = 1;
s->qos.effective_only = 0;
s->attr.sec_qos = &s->qos;
s->lsa_open_policy.in.attr = &s->attr;
s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
s->lsa_open_policy.out.handle = &s->lsa_handle;
open_pol_req = dcerpc_lsa_OpenPolicy2_send(s->lsa_pipe, c, &s->lsa_open_policy);
if (composite_nomem(open_pol_req, c)) return;
composite_continue_rpc(c, open_pol_req, continue_lsa_policy, c);
}
/*
Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
for kerberos realm (dns name) and guid. The query may fail.
*/
static void continue_lsa_policy(struct rpc_request *req)
{
struct composite_context *c;
struct rpc_connect_dci_state *s;
struct rpc_request *query_info_req;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
c->status = dcerpc_ndr_request_recv(req);
if (!NT_STATUS_IS_OK(c->status)) {
composite_error(c, c->status);
return;
}
if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
s->r.out.realm = NULL;
s->r.out.guid = NULL;
s->r.out.domain_name = NULL;
s->r.out.domain_sid = NULL;
/* Skip to the creating the actual connection, no info available on this transport */
continue_epm_map_binding_send(c);
return;
} else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
composite_error(c, s->lsa_open_policy.out.result);
return;
}
/* query lsa info for dns domain name and guid */
s->lsa_query_info2.in.handle = &s->lsa_handle;
s->lsa_query_info2.in.level = LSA_POLICY_INFO_DNS;
query_info_req = dcerpc_lsa_QueryInfoPolicy2_send(s->lsa_pipe, c, &s->lsa_query_info2);
if (composite_nomem(query_info_req, c)) return;
composite_continue_rpc(c, query_info_req, continue_lsa_query_info2, c);
}
/*
Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
may result in failure) and query lsa info for domain name and sid.
*/
static void continue_lsa_query_info2(struct rpc_request *req)
{
struct composite_context *c;
struct rpc_connect_dci_state *s;
struct rpc_request *query_info_req;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
c->status = dcerpc_ndr_request_recv(req);
/* In case of error just null the realm and guid and proceed
to the next step. After all, it doesn't have to be AD domain
controller we talking to - NT-style PDC also counts */
if (NT_STATUS_EQUAL(c->status, NT_STATUS_NET_WRITE_FAULT)) {
s->r.out.realm = NULL;
s->r.out.guid = NULL;
} else {
if (!NT_STATUS_IS_OK(c->status)) {
s->r.out.error_string = talloc_asprintf(c,
"lsa_QueryInfoPolicy2 failed: %s",
nt_errstr(c->status));
composite_error(c, c->status);
return;
}
if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
s->r.out.error_string = talloc_asprintf(c,
"lsa_QueryInfoPolicy2 failed: %s",
nt_errstr(s->lsa_query_info2.out.result));
composite_error(c, s->lsa_query_info2.out.result);
return;
}
/* Copy the dns domain name and guid from the query result */
/* this should actually be a conversion from lsa_StringLarge */
s->r.out.realm = s->lsa_query_info2.out.info->dns.dns_domain.string;
s->r.out.guid = talloc(c, struct GUID);
if (composite_nomem(s->r.out.guid, c)) {
s->r.out.error_string = NULL;
return;
}
*s->r.out.guid = s->lsa_query_info2.out.info->dns.domain_guid;
}
/* query lsa info for domain name and sid */
s->lsa_query_info.in.handle = &s->lsa_handle;
s->lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN;
query_info_req = dcerpc_lsa_QueryInfoPolicy_send(s->lsa_pipe, c, &s->lsa_query_info);
if (composite_nomem(query_info_req, c)) return;
composite_continue_rpc(c, query_info_req, continue_lsa_query_info, c);
}
/*
Step 5 of RpcConnectDCInfo: Get domain name and sid
*/
static void continue_lsa_query_info(struct rpc_request *req)
{
struct composite_context *c;
struct rpc_connect_dci_state *s;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
c->status = dcerpc_ndr_request_recv(req);
if (!NT_STATUS_IS_OK(c->status)) {
s->r.out.error_string = talloc_asprintf(c,
"lsa_QueryInfoPolicy failed: %s",
nt_errstr(c->status));
composite_error(c, c->status);
return;
}
/* Copy the domain name and sid from the query result */
s->r.out.domain_sid = s->lsa_query_info.out.info->domain.sid;
s->r.out.domain_name = s->lsa_query_info.out.info->domain.name.string;
continue_epm_map_binding_send(c);
}
/*
Step 5 (continued) of RpcConnectDCInfo: request endpoint
map binding.
We may short-cut to this step if we dont' support LSA OpenPolicy on this transport
*/
static void continue_epm_map_binding_send(struct composite_context *c)
{
struct rpc_connect_dci_state *s;
struct composite_context *epm_map_req;
s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
/* prepare to get endpoint mapping for the requested interface */
s->final_binding = talloc(s, struct dcerpc_binding);
if (composite_nomem(s->final_binding, c)) return;
*s->final_binding = *s->lsa_pipe->binding;
/* Ensure we keep hold of the member elements */
if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
s->lsa_pipe->conn->event_ctx);
if (composite_nomem(epm_map_req, c)) return;
composite_continue(c, epm_map_req, continue_epm_map_binding, c);
}
/*
Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
rpc connection derived from already used pipe but connected to the requested
one (as specified in libnet_RpcConnect structure)
*/
static void continue_epm_map_binding(struct composite_context *ctx)
{
struct composite_context *c, *sec_conn_req;
struct rpc_connect_dci_state *s;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
c->status = dcerpc_epm_map_binding_recv(ctx);
if (!NT_STATUS_IS_OK(c->status)) {
s->r.out.error_string = talloc_asprintf(c,
"failed to map pipe with endpoint mapper - %s",
nt_errstr(c->status));
composite_error(c, c->status);
return;
}
/* create secondary connection derived from lsa pipe */
sec_conn_req = dcerpc_secondary_connection_send(s->lsa_pipe, s->final_binding);
if (composite_nomem(sec_conn_req, c)) return;
composite_continue(c, sec_conn_req, continue_secondary_conn, c);
}
/*
Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
and complete this composite call
*/
static void continue_secondary_conn(struct composite_context *ctx)
{
struct composite_context *c;
struct rpc_connect_dci_state *s;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
c->status = dcerpc_secondary_connection_recv(ctx, &s->final_pipe);
if (!NT_STATUS_IS_OK(c->status)) {
s->r.out.error_string = talloc_asprintf(c,
"secondary connection failed: %s",
nt_errstr(c->status));
composite_error(c, c->status);
return;
}
s->r.out.dcerpc_pipe = s->final_pipe;
composite_done(c);
}
/**
* Receives result of connection to rpc pipe and gets basic
* domain info (name, sid, realm, guid)
*
* @param c composite context
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing return values
* @return nt status of rpc connection
**/
static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
{
NTSTATUS status;
struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
struct rpc_connect_dci_state);
status = composite_wait(c);
if (NT_STATUS_IS_OK(status)) {
r->out.realm = talloc_steal(mem_ctx, s->r.out.realm);
r->out.guid = talloc_steal(mem_ctx, s->r.out.guid);
r->out.domain_name = talloc_steal(mem_ctx, s->r.out.domain_name);
r->out.domain_sid = talloc_steal(mem_ctx, s->r.out.domain_sid);
r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
/* reference created pipe structure to long-term libnet_context
so that it can be used by other api functions even after short-term
mem_ctx is freed */
if (r->in.dcerpc_iface == &dcerpc_table_samr) {
ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
} else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
}
} else {
if (s->r.out.error_string) {
r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
} else {
r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
}
}
talloc_free(c);
return status;
}
/**
* Initiates connection to rpc pipe on remote server or pdc, optionally
* providing domain info
*
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing necessary parameters and return values
* @return composite context of this call
**/
struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx,
struct libnet_RpcConnect *r)
{
struct composite_context *c;
switch (r->level) {
case LIBNET_RPC_CONNECT_SERVER:
case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
case LIBNET_RPC_CONNECT_BINDING:
c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r);
break;
case LIBNET_RPC_CONNECT_PDC:
case LIBNET_RPC_CONNECT_DC:
c = libnet_RpcConnectDC_send(ctx, mem_ctx, r);
break;
case LIBNET_RPC_CONNECT_DC_INFO:
c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r);
break;
default:
c = talloc_zero(mem_ctx, struct composite_context);
composite_error(c, NT_STATUS_INVALID_LEVEL);
}
return c;
}
/**
* Receives result of connection to rpc pipe on remote server or pdc
*
* @param c composite context
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing necessary parameters and return values
* @return nt status of rpc connection
**/
NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
{
switch (r->level) {
case LIBNET_RPC_CONNECT_SERVER:
case LIBNET_RPC_CONNECT_BINDING:
return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
case LIBNET_RPC_CONNECT_PDC:
case LIBNET_RPC_CONNECT_DC:
return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
case LIBNET_RPC_CONNECT_DC_INFO:
return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
default:
ZERO_STRUCT(r->out);
return NT_STATUS_INVALID_LEVEL;
}
}
/**
* Connect to a rpc pipe on a remote server - sync version
*
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
* @param r data structure containing necessary parameters and return values
* @return nt status of rpc connection
**/
NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
struct libnet_RpcConnect *r)
{
struct composite_context *c;
c = libnet_RpcConnect_send(ctx, mem_ctx, r);
return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
}
+79
View File
@@ -0,0 +1,79 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
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 "librpc/rpc/dcerpc.h"
/*
* struct definition for connecting to a dcerpc inferface
*/
enum libnet_RpcConnect_level {
LIBNET_RPC_CONNECT_SERVER, /* connect to a standalone rpc server */
LIBNET_RPC_CONNECT_SERVER_ADDRESS, /* connect to a standalone rpc server,
knowing both name and address */
LIBNET_RPC_CONNECT_PDC, /* connect to a domain pdc (resolves domain
name to a pdc address before connecting) */
LIBNET_RPC_CONNECT_DC, /* connect to any DC (resolves domain
name to a DC address before connecting) */
LIBNET_RPC_CONNECT_BINDING, /* specified binding string */
LIBNET_RPC_CONNECT_DC_INFO /* connect to a DC and provide basic domain
information (name, realm, sid, guid) */
};
struct libnet_RpcConnect {
enum libnet_RpcConnect_level level;
struct {
const char *name;
const char *address;
const char *binding;
const struct dcerpc_interface_table *dcerpc_iface;
} in;
struct {
struct dcerpc_pipe *dcerpc_pipe;
/* parameters provided in LIBNET_RPC_CONNECT_DC_INFO level, null otherwise */
const char *domain_name;
struct dom_sid *domain_sid;
const char *realm; /* these parameters are only present if */
struct GUID *guid; /* the remote server is known to be AD */
const char *error_string;
} out;
};
/*
* Monitor messages sent from libnet_rpc.c functions
*/
struct msg_net_lookup_dc {
const char *domain_name;
const char *hostname;
const char *address;
};
struct msg_net_pipe_connected {
const char *host;
const char *endpoint;
enum dcerpc_transport_t transport;
};
+204
View File
@@ -0,0 +1,204 @@
/*
Unix SMB/CIFS implementation.
Extract the user/system database from a remote SamSync server
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-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 "libnet/libnet.h"
#include "lib/util/dlinklist.h"
#include "samba3/samba3.h"
#include "libcli/security/security.h"
struct samdump_secret {
struct samdump_secret *prev, *next;
DATA_BLOB secret;
char *name;
NTTIME mtime;
};
struct samdump_trusted_domain {
struct samdump_trusted_domain *prev, *next;
struct dom_sid *sid;
char *name;
};
struct samdump_state {
struct samdump_secret *secrets;
struct samdump_trusted_domain *trusted_domains;
};
static NTSTATUS vampire_samdump_handle_user(TALLOC_CTX *mem_ctx,
struct netr_DELTA_ENUM *delta)
{
uint32_t rid = delta->delta_id_union.rid;
struct netr_DELTA_USER *user = delta->delta_union.user;
const char *username = user->account_name.string;
char *hex_lm_password;
char *hex_nt_password;
hex_lm_password = smbpasswd_sethexpwd(mem_ctx,
user->lm_password_present ? &user->lmpassword : NULL,
user->acct_flags);
hex_nt_password = smbpasswd_sethexpwd(mem_ctx,
user->nt_password_present ? &user->ntpassword : NULL,
user->acct_flags);
printf("%s:%d:%s:%s:%s:LCT-%08X\n", username,
rid, hex_lm_password, hex_nt_password,
smbpasswd_encode_acb_info(mem_ctx, user->acct_flags),
(unsigned int)nt_time_to_unix(user->last_password_change));
return NT_STATUS_OK;
}
static NTSTATUS vampire_samdump_handle_secret(TALLOC_CTX *mem_ctx,
struct samdump_state *samdump_state,
struct netr_DELTA_ENUM *delta)
{
struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
const char *name = delta->delta_id_union.name;
struct samdump_secret *new = talloc(samdump_state, struct samdump_secret);
new->name = talloc_strdup(new, name);
new->secret = data_blob_talloc(new, secret->current_cipher.cipher_data, secret->current_cipher.maxlen);
new->mtime = secret->current_cipher_set_time;
DLIST_ADD(samdump_state->secrets, new);
return NT_STATUS_OK;
}
static NTSTATUS vampire_samdump_handle_trusted_domain(TALLOC_CTX *mem_ctx,
struct samdump_state *samdump_state,
struct netr_DELTA_ENUM *delta)
{
struct netr_DELTA_TRUSTED_DOMAIN *trusted_domain = delta->delta_union.trusted_domain;
struct dom_sid *dom_sid = delta->delta_id_union.sid;
struct samdump_trusted_domain *new = talloc(samdump_state, struct samdump_trusted_domain);
new->name = talloc_strdup(new, trusted_domain->domain_name.string);
new->sid = talloc_steal(new, dom_sid);
DLIST_ADD(samdump_state->trusted_domains, new);
return NT_STATUS_OK;
}
static NTSTATUS libnet_samdump_fn(TALLOC_CTX *mem_ctx,
void *private,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string)
{
NTSTATUS nt_status = NT_STATUS_OK;
struct samdump_state *samdump_state = private;
*error_string = NULL;
switch (delta->delta_type) {
case NETR_DELTA_USER:
{
/* not interested in builtin users */
if (database == SAM_DATABASE_DOMAIN) {
nt_status = vampire_samdump_handle_user(mem_ctx,
delta);
}
break;
}
case NETR_DELTA_SECRET:
{
nt_status = vampire_samdump_handle_secret(mem_ctx,
samdump_state,
delta);
break;
}
case NETR_DELTA_TRUSTED_DOMAIN:
{
nt_status = vampire_samdump_handle_trusted_domain(mem_ctx,
samdump_state,
delta);
break;
}
default:
/* Can't dump them all right now */
break;
}
return nt_status;
}
NTSTATUS libnet_SamDump(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamDump *r)
{
NTSTATUS nt_status;
struct libnet_SamSync r2;
struct samdump_state *samdump_state = talloc(mem_ctx, struct samdump_state);
struct samdump_trusted_domain *t;
struct samdump_secret *s;
if (!samdump_state) {
return NT_STATUS_NO_MEMORY;
}
samdump_state->secrets = NULL;
samdump_state->trusted_domains = NULL;
r2.out.error_string = NULL;
r2.in.binding_string = r->in.binding_string;
r2.in.init_fn = NULL;
r2.in.delta_fn = libnet_samdump_fn;
r2.in.fn_ctx = samdump_state;
r2.in.machine_account = r->in.machine_account;
nt_status = libnet_SamSync_netlogon(ctx, samdump_state, &r2);
r->out.error_string = r2.out.error_string;
talloc_steal(mem_ctx, r->out.error_string);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(samdump_state);
return nt_status;
}
printf("Trusted domains, sids and secrets:\n");
for (t=samdump_state->trusted_domains; t; t=t->next) {
char *secret_name = talloc_asprintf(mem_ctx, "G$$%s", t->name);
for (s=samdump_state->secrets; s; s=s->next) {
char *secret_string;
if (strcasecmp_m(s->name, secret_name) != 0) {
continue;
}
if (convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
s->secret.data, s->secret.length,
(void **)&secret_string) == -1) {
r->out.error_string = talloc_asprintf(mem_ctx,
"Could not convert secret for domain %s to a string",
t->name);
talloc_free(samdump_state);
return NT_STATUS_INVALID_PARAMETER;
}
printf("%s\t%s\t%s\n",
t->name, dom_sid_string(mem_ctx, t->sid),
secret_string);
}
}
talloc_free(samdump_state);
return nt_status;
}
+116
View File
@@ -0,0 +1,116 @@
/*
Unix SMB/CIFS implementation.
Extract kerberos keys from a remote SamSync server
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-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 "libnet/libnet.h"
#include "system/kerberos.h"
#include "auth/credentials/credentials.h"
#include "auth/credentials/credentials_krb5.h"
static NTSTATUS samdump_keytab_handle_user(TALLOC_CTX *mem_ctx,
const char *keytab_name,
struct netr_DELTA_ENUM *delta)
{
struct netr_DELTA_USER *user = delta->delta_union.user;
const char *username = user->account_name.string;
struct cli_credentials *credentials;
int ret;
if (!user->nt_password_present) {
/* We can't do anything here */
return NT_STATUS_OK;
}
credentials = cli_credentials_init(mem_ctx);
if (!credentials) {
return NT_STATUS_NO_MEMORY;
}
cli_credentials_set_conf(credentials);
cli_credentials_set_username(credentials, username, CRED_SPECIFIED);
/* We really should consult ldap in the main SamSync code, and
* pass a value in here */
cli_credentials_set_kvno(credentials, 0);
cli_credentials_set_nt_hash(credentials, &user->ntpassword, CRED_SPECIFIED);
ret = cli_credentials_set_keytab_name(credentials, keytab_name, CRED_SPECIFIED);
if (ret) {
return NT_STATUS_UNSUCCESSFUL;
}
ret = cli_credentials_update_keytab(credentials);
if (ret) {
return NT_STATUS_UNSUCCESSFUL;
}
return NT_STATUS_OK;
}
static NTSTATUS libnet_samdump_keytab_fn(TALLOC_CTX *mem_ctx,
void *private,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string)
{
NTSTATUS nt_status = NT_STATUS_OK;
const char *keytab_name = private;
*error_string = NULL;
switch (delta->delta_type) {
case NETR_DELTA_USER:
{
/* not interested in builtin users */
if (database == SAM_DATABASE_DOMAIN) {
nt_status = samdump_keytab_handle_user(mem_ctx,
keytab_name,
delta);
break;
}
}
default:
/* Can't dump them all right now */
break;
}
return nt_status;
}
NTSTATUS libnet_SamDump_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamDump_keytab *r)
{
NTSTATUS nt_status;
struct libnet_SamSync r2;
r2.out.error_string = NULL;
r2.in.binding_string = r->in.binding_string;
r2.in.init_fn = NULL;
r2.in.delta_fn = libnet_samdump_keytab_fn;
r2.in.fn_ctx = discard_const(r->in.keytab_name);
r2.in.machine_account = r->in.machine_account;
nt_status = libnet_SamSync_netlogon(ctx, mem_ctx, &r2);
r->out.error_string = r2.out.error_string;
talloc_steal(mem_ctx, r->out.error_string);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
return nt_status;
}
File diff suppressed because it is too large Load Diff
+202
View File
@@ -0,0 +1,202 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Grégory LEOCADIE <gleocadie@idealx.com>
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 "libnet/libnet.h"
#include "librpc/gen_ndr/ndr_srvsvc_c.h"
NTSTATUS libnet_ListShares(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_ListShares *r)
{
NTSTATUS status;
struct libnet_RpcConnect c;
struct srvsvc_NetShareEnumAll s;
uint32_t resume_handle = 0;
struct srvsvc_NetShareCtr0 ctr0;
struct srvsvc_NetShareCtr1 ctr1;
struct srvsvc_NetShareCtr2 ctr2;
struct srvsvc_NetShareCtr501 ctr501;
struct srvsvc_NetShareCtr502 ctr502;
c.level = LIBNET_RPC_CONNECT_SERVER;
c.in.name = r->in.server_name;
c.in.dcerpc_iface = &dcerpc_table_srvsvc;
s.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", c.in.name);
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"Connection to SRVSVC pipe of server %s "
"failed: %s",
r->in.server_name,
nt_errstr(status));
return status;
}
s.in.level = r->in.level;
switch (s.in.level) {
case 0:
s.in.ctr.ctr0 = &ctr0;
ZERO_STRUCT(ctr0);
break;
case 1:
s.in.ctr.ctr1 = &ctr1;
ZERO_STRUCT(ctr1);
break;
case 2:
s.in.ctr.ctr2 = &ctr2;
ZERO_STRUCT(ctr2);
break;
case 501:
s.in.ctr.ctr501 = &ctr501;
ZERO_STRUCT(ctr501);
break;
case 502:
s.in.ctr.ctr502 = &ctr502;
ZERO_STRUCT(ctr502);
break;
default:
r->out.error_string = talloc_asprintf(mem_ctx,
"libnet_ListShares: Invalid info level requested: %d",
s.in.level);
return NT_STATUS_INVALID_PARAMETER;
}
s.in.max_buffer = ~0;
s.in.resume_handle = &resume_handle;
status = dcerpc_srvsvc_NetShareEnumAll(c.out.dcerpc_pipe, mem_ctx, &s);
if (!NT_STATUS_IS_OK(status)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"srvsvc_NetShareEnumAll on server '%s' failed"
": %s",
r->in.server_name, nt_errstr(status));
goto disconnect;
}
if (!W_ERROR_IS_OK(s.out.result) && !W_ERROR_EQUAL(s.out.result, WERR_MORE_DATA)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"srvsvc_NetShareEnumAll on server '%s' failed: %s",
r->in.server_name, win_errstr(s.out.result));
goto disconnect;
}
r->out.ctr = s.out.ctr;
disconnect:
talloc_free(c.out.dcerpc_pipe);
return status;
}
NTSTATUS libnet_AddShare(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_AddShare *r)
{
NTSTATUS status;
struct libnet_RpcConnect c;
struct srvsvc_NetShareAdd s;
c.level = LIBNET_RPC_CONNECT_SERVER;
c.in.name = r->in.server_name;
c.in.dcerpc_iface = &dcerpc_table_srvsvc;
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"Connection to SRVSVC pipe of server %s "
"failed: %s",
r->in.server_name, nt_errstr(status));
return status;
}
s.in.level = 2;
s.in.info.info2 = &r->in.share;
s.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", r->in.server_name);
status = dcerpc_srvsvc_NetShareAdd(c.out.dcerpc_pipe, mem_ctx, &s);
if (!NT_STATUS_IS_OK(status)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"srvsvc_NetShareAdd '%s' on server '%s' failed"
": %s",
r->in.share.name, r->in.server_name,
nt_errstr(status));
} else if (!W_ERROR_IS_OK(s.out.result)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"srvsvc_NetShareAdd '%s' on server '%s' failed"
": %s",
r->in.share.name, r->in.server_name,
win_errstr(s.out.result));
status = werror_to_ntstatus(s.out.result);
}
talloc_free(c.out.dcerpc_pipe);
return status;
}
NTSTATUS libnet_DelShare(struct libnet_context *ctx,
TALLOC_CTX *mem_ctx, struct libnet_DelShare *r)
{
NTSTATUS status;
struct libnet_RpcConnect c;
struct srvsvc_NetShareDel s;
c.level = LIBNET_RPC_CONNECT_SERVER;
c.in.name = r->in.server_name;
c.in.dcerpc_iface = &dcerpc_table_srvsvc;
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"Connection to SRVSVC pipe of server %s "
"failed: %s",
r->in.server_name, nt_errstr(status));
return status;
}
s.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", r->in.server_name);
s.in.share_name = r->in.share_name;
status = dcerpc_srvsvc_NetShareDel(c.out.dcerpc_pipe, mem_ctx, &s);
if (!NT_STATUS_IS_OK(status)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"srvsvc_NetShareDel '%s' on server '%s' failed"
": %s",
r->in.share_name, r->in.server_name,
nt_errstr(status));
} else if (!W_ERROR_IS_OK(s.out.result)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"srvsvc_NetShareDel '%s' on server '%s' failed"
": %s",
r->in.share_name, r->in.server_name,
win_errstr(s.out.result));
status = werror_to_ntstatus(s.out.result);
}
talloc_free(c.out.dcerpc_pipe);
return status;
}
+71
View File
@@ -0,0 +1,71 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Grégory LEOCADIE <gleocadie@idealx.com>
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 "librpc/gen_ndr/srvsvc.h"
enum libnet_ListShares_level {
LIBNET_LIST_SHARES_GENERIC,
LIBNET_LIST_SHARES_SRVSVC
};
struct libnet_ListShares {
struct {
const char *server_name;
uint32_t *resume_handle;
uint32_t level;
} in;
struct {
const char *error_string;
union srvsvc_NetShareCtr ctr;
uint32_t *resume_handle;
} out;
};
enum libnet_AddShare_level {
LIBNET_ADD_SHARE_GENERIC,
LIBNET_ADD_SHARE_SRVSVC
};
struct libnet_AddShare {
enum libnet_AddShare_level level;
struct {
const char * server_name;
struct srvsvc_NetShareInfo2 share;
} in;
struct {
const char* error_string;
} out;
};
enum libnet_DelShare_level {
LIBNET_DEL_SHARE_GENERIC,
LIBNET_DEL_SHARE_SRVSVC
};
struct libnet_DelShare {
enum libnet_DelShare_level level;
struct {
const char *server_name;
const char *share_name;
} in;
struct {
const char *error_string;
} out;
};
+254
View File
@@ -0,0 +1,254 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Brad Henry 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 "libnet/libnet.h"
#include "libcli/cldap/cldap.h"
#include "lib/ldb/include/ldb.h"
#include "lib/ldb/include/ldb_errors.h"
#include "librpc/rpc/dcerpc.h"
/*
* 1. Setup a CLDAP socket.
* 2. Lookup the default Site-Name.
*/
NTSTATUS libnet_FindSite(TALLOC_CTX *ctx, struct libnet_JoinSite *r)
{
NTSTATUS status;
TALLOC_CTX *tmp_ctx;
char *site_name_str;
char *config_dn_str;
char *server_dn_str;
struct cldap_socket *cldap = NULL;
struct cldap_netlogon search;
tmp_ctx = talloc_named(ctx, 0, "libnet_FindSite temp context");
if (!tmp_ctx) {
r->out.error_string = NULL;
return NT_STATUS_NO_MEMORY;
}
/* Resolve the site name. */
ZERO_STRUCT(search);
search.in.dest_address = r->in.dest_address;
search.in.acct_control = -1;
search.in.version = 6;
cldap = cldap_socket_init(tmp_ctx, NULL);
status = cldap_netlogon(cldap, tmp_ctx, &search);
if (!NT_STATUS_IS_OK(status)) {
/*
If cldap_netlogon() returns in error,
default to using Default-First-Site-Name.
*/
site_name_str = talloc_asprintf(tmp_ctx, "%s",
"Default-First-Site-Name");
if (!site_name_str) {
r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
} else {
site_name_str = talloc_asprintf(tmp_ctx, "%s",
search.out.netlogon.logon5.client_site);
if (!site_name_str) {
r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
}
/* Generate the CN=Configuration,... DN. */
/* TODO: look it up! */
config_dn_str = talloc_asprintf(tmp_ctx, "CN=Configuration,%s", r->in.domain_dn_str);
if (!config_dn_str) {
r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
/* Generate the CN=Servers,... DN. */
server_dn_str = talloc_asprintf(tmp_ctx, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
r->in.netbios_name, site_name_str, config_dn_str);
if (!server_dn_str) {
r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
r->out.site_name_str = site_name_str;
talloc_steal(r, site_name_str);
r->out.config_dn_str = config_dn_str;
talloc_steal(r, config_dn_str);
r->out.server_dn_str = server_dn_str;
talloc_steal(r, server_dn_str);
talloc_free(tmp_ctx);
return NT_STATUS_OK;
}
/*
* find out Site specific stuff:
* 1. Lookup the Site name.
* 2. Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>.
* TODO: 3.) use DsAddEntry() to create CN=NTDS Settings,CN=<netbios name>,CN=Servers,CN=<site name>,...
*/
NTSTATUS libnet_JoinSite(struct ldb_context *remote_ldb,
struct libnet_JoinDomain *libnet_r)
{
NTSTATUS status;
TALLOC_CTX *tmp_ctx;
struct libnet_JoinSite *r;
struct ldb_dn *server_dn;
struct ldb_message *msg;
int rtn;
const char *server_dn_str;
const char *config_dn_str;
tmp_ctx = talloc_named(libnet_r, 0, "libnet_JoinSite temp context");
if (!tmp_ctx) {
libnet_r->out.error_string = NULL;
return NT_STATUS_NO_MEMORY;
}
r = talloc(tmp_ctx, struct libnet_JoinSite);
if (!r) {
libnet_r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
/* Resolve the site name and AD DN's. */
r->in.dest_address = libnet_r->out.samr_binding->host;
r->in.netbios_name = libnet_r->in.netbios_name;
r->in.domain_dn_str = libnet_r->out.domain_dn_str;
status = libnet_FindSite(tmp_ctx, r);
if (!NT_STATUS_IS_OK(status)) {
libnet_r->out.error_string =
talloc_steal(libnet_r, r->out.error_string);
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
config_dn_str = r->out.config_dn_str;
server_dn_str = r->out.server_dn_str;
/*
Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>.
*/
msg = ldb_msg_new(tmp_ctx);
if (!msg) {
libnet_r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
rtn = ldb_msg_add_string(msg, "objectClass", "server");
if (rtn != 0) {
libnet_r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
rtn = ldb_msg_add_string(msg, "systemFlags", "50000000");
if (rtn != 0) {
libnet_r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
rtn = ldb_msg_add_string(msg, "serverReference", libnet_r->out.account_dn_str);
if (rtn != 0) {
libnet_r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
server_dn = ldb_dn_new(tmp_ctx, remote_ldb, server_dn_str);
if ( ! ldb_dn_validate(server_dn)) {
libnet_r->out.error_string = talloc_asprintf(libnet_r,
"Invalid server dn: %s",
server_dn_str);
talloc_free(tmp_ctx);
return NT_STATUS_UNSUCCESSFUL;
}
msg->dn = server_dn;
rtn = ldb_add(remote_ldb, msg);
if (rtn == LDB_ERR_ENTRY_ALREADY_EXISTS) {
int i;
/* make a 'modify' msg, and only for serverReference */
msg = ldb_msg_new(tmp_ctx);
if (!msg) {
libnet_r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
msg->dn = server_dn;
rtn = ldb_msg_add_string(msg, "serverReference",libnet_r->out.account_dn_str);
if (rtn != 0) {
libnet_r->out.error_string = NULL;
talloc_free(tmp_ctx);
return NT_STATUS_NO_MEMORY;
}
/* mark all the message elements (should be just one)
as LDB_FLAG_MOD_REPLACE */
for (i=0;i<msg->num_elements;i++) {
msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
}
rtn = ldb_modify(remote_ldb, msg);
if (rtn != 0) {
libnet_r->out.error_string
= talloc_asprintf(libnet_r,
"Failed to modify server entry %s: %s: %d",
server_dn_str,
ldb_errstring(remote_ldb), rtn);
talloc_free(tmp_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
} else if (rtn != 0) {
libnet_r->out.error_string
= talloc_asprintf(libnet_r,
"Failed to add server entry %s: %s: %d",
server_dn_str, ldb_errstring(remote_ldb),
rtn);
talloc_free(tmp_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
DEBUG(0, ("We still need to perform a DsAddEntry() so that we can create the CN=NTDS Settings container.\n"));
/* Store the server DN in libnet_r */
libnet_r->out.server_dn_str = server_dn_str;
talloc_steal(libnet_r, server_dn_str);
talloc_free(tmp_ctx);
return NT_STATUS_OK;
}
+35
View File
@@ -0,0 +1,35 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Brad Henry 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.
*/
struct libnet_JoinSite {
struct {
const char *dest_address;
const char *netbios_name;
const char *domain_dn_str;
} in;
struct {
const char *error_string;
const char *site_name_str;
const char *config_dn_str;
const char *server_dn_str;
} out;
};
+122
View File
@@ -0,0 +1,122 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
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 "libnet/libnet.h"
#include "system/time.h"
#include "librpc/gen_ndr/ndr_srvsvc_c.h"
/*
* get the remote time of a server via srvsvc_NetRemoteTOD
*/
static NTSTATUS libnet_RemoteTOD_srvsvc(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_RemoteTOD *r)
{
NTSTATUS status;
struct libnet_RpcConnect c;
struct srvsvc_NetRemoteTOD tod;
struct tm tm;
/* prepare connect to the SRVSVC pipe of a timeserver */
c.level = LIBNET_RPC_CONNECT_SERVER;
c.in.name = r->srvsvc.in.server_name;
c.in.dcerpc_iface = &dcerpc_table_srvsvc;
/* 1. connect to the SRVSVC pipe of a timeserver */
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
r->srvsvc.out.error_string = talloc_asprintf(mem_ctx,
"Connection to SRVSVC pipe of server '%s' failed: %s",
r->srvsvc.in.server_name, nt_errstr(status));
return status;
}
/* prepare srvsvc_NetrRemoteTOD */
tod.in.server_unc = talloc_asprintf(mem_ctx, "\\%s", c.in.name);
/* 2. try srvsvc_NetRemoteTOD */
status = dcerpc_srvsvc_NetRemoteTOD(c.out.dcerpc_pipe, mem_ctx, &tod);
if (!NT_STATUS_IS_OK(status)) {
r->srvsvc.out.error_string = talloc_asprintf(mem_ctx,
"srvsvc_NetrRemoteTOD on server '%s' failed: %s",
r->srvsvc.in.server_name, nt_errstr(status));
goto disconnect;
}
/* check result of srvsvc_NetrRemoteTOD */
if (!W_ERROR_IS_OK(tod.out.result)) {
r->srvsvc.out.error_string = talloc_asprintf(mem_ctx,
"srvsvc_NetrRemoteTOD on server '%s' failed: %s",
r->srvsvc.in.server_name, win_errstr(tod.out.result));
status = werror_to_ntstatus(tod.out.result);
goto disconnect;
}
/* need to set the out parameters */
tm.tm_sec = (int)tod.out.info->secs;
tm.tm_min = (int)tod.out.info->mins;
tm.tm_hour = (int)tod.out.info->hours;
tm.tm_mday = (int)tod.out.info->day;
tm.tm_mon = (int)tod.out.info->month -1;
tm.tm_year = (int)tod.out.info->year - 1900;
tm.tm_wday = -1;
tm.tm_yday = -1;
tm.tm_isdst = -1;
r->srvsvc.out.time = timegm(&tm);
r->srvsvc.out.time_zone = tod.out.info->timezone * 60;
goto disconnect;
disconnect:
/* close connection */
talloc_free(c.out.dcerpc_pipe);
return status;
}
static NTSTATUS libnet_RemoteTOD_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_RemoteTOD *r)
{
NTSTATUS status;
union libnet_RemoteTOD r2;
r2.srvsvc.level = LIBNET_REMOTE_TOD_SRVSVC;
r2.srvsvc.in.server_name = r->generic.in.server_name;
status = libnet_RemoteTOD(ctx, mem_ctx, &r2);
r->generic.out.time = r2.srvsvc.out.time;
r->generic.out.time_zone = r2.srvsvc.out.time_zone;
r->generic.out.error_string = r2.srvsvc.out.error_string;
return status;
}
NTSTATUS libnet_RemoteTOD(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_RemoteTOD *r)
{
switch (r->generic.level) {
case LIBNET_REMOTE_TOD_GENERIC:
return libnet_RemoteTOD_generic(ctx, mem_ctx, r);
case LIBNET_REMOTE_TOD_SRVSVC:
return libnet_RemoteTOD_srvsvc(ctx, mem_ctx, r);
}
return NT_STATUS_INVALID_LEVEL;
}
+47
View File
@@ -0,0 +1,47 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2004
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.
*/
/* struct and enum for getting the time of a remote system */
enum libnet_RemoteTOD_level {
LIBNET_REMOTE_TOD_GENERIC,
LIBNET_REMOTE_TOD_SRVSVC
};
union libnet_RemoteTOD {
struct {
enum libnet_RemoteTOD_level level;
struct _libnet_RemoteTOD_in {
const char *server_name;
} in;
struct _libnet_RemoteTOD_out {
time_t time;
int time_zone;
const char *error_string;
} out;
} generic;
struct {
enum libnet_RemoteTOD_level level;
struct _libnet_RemoteTOD_in in;
struct _libnet_RemoteTOD_out out;
} srvsvc;
};
+571
View File
@@ -0,0 +1,571 @@
/*
Unix SMB/CIFS implementation.
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 "libnet/libnet.h"
#include "libcli/composite/composite.h"
#include "libcli/cldap/cldap.h"
#include "lib/ldb/include/ldb.h"
#include "lib/ldb/include/ldb_errors.h"
#include "lib/db_wrap.h"
#include "dsdb/samdb/samdb.h"
#include "dsdb/common/flags.h"
#include "librpc/gen_ndr/ndr_drsuapi_c.h"
struct libnet_UnbecomeDC_state {
struct composite_context *creq;
struct libnet_context *libnet;
struct {
struct cldap_socket *sock;
struct cldap_netlogon io;
struct nbt_cldap_netlogon_5 netlogon5;
} cldap;
struct {
struct ldb_context *ldb;
} ldap;
struct {
struct dcerpc_binding *binding;
struct dcerpc_pipe *pipe;
struct drsuapi_DsBind bind_r;
struct GUID bind_guid;
struct drsuapi_DsBindInfoCtr bind_info_ctr;
struct drsuapi_DsBindInfo28 local_info28;
struct drsuapi_DsBindInfo28 remote_info28;
struct policy_handle bind_handle;
struct drsuapi_DsRemoveDSServer rm_ds_srv_r;
} drsuapi;
struct {
/* input */
const char *dns_name;
const char *netbios_name;
/* constructed */
struct GUID guid;
const char *dn_str;
} domain;
struct {
/* constructed */
const char *config_dn_str;
} forest;
struct {
/* input */
const char *address;
/* constructed */
const char *dns_name;
const char *netbios_name;
const char *site_name;
} source_dsa;
struct {
/* input */
const char *netbios_name;
/* constructed */
const char *dns_name;
const char *site_name;
const char *computer_dn_str;
const char *server_dn_str;
uint32_t user_account_control;
} dest_dsa;
};
static void unbecomeDC_connect_ldap(struct libnet_UnbecomeDC_state *s);
static void unbecomeDC_recv_cldap(struct cldap_request *req)
{
struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private,
struct libnet_UnbecomeDC_state);
struct composite_context *c = s->creq;
c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
if (!composite_is_ok(c)) return;
s->cldap.netlogon5 = s->cldap.io.out.netlogon.logon5;
s->domain.dns_name = s->cldap.netlogon5.dns_domain;
s->domain.netbios_name = s->cldap.netlogon5.domain;
s->domain.guid = s->cldap.netlogon5.domain_uuid;
s->source_dsa.dns_name = s->cldap.netlogon5.pdc_dns_name;
s->source_dsa.netbios_name = s->cldap.netlogon5.pdc_name;
s->source_dsa.site_name = s->cldap.netlogon5.server_site;
s->dest_dsa.site_name = s->cldap.netlogon5.client_site;
unbecomeDC_connect_ldap(s);
}
static void unbecomeDC_send_cldap(struct libnet_UnbecomeDC_state *s)
{
struct composite_context *c = s->creq;
struct cldap_request *req;
s->cldap.io.in.dest_address = s->source_dsa.address;
s->cldap.io.in.realm = s->domain.dns_name;
s->cldap.io.in.host = s->dest_dsa.netbios_name;
s->cldap.io.in.user = NULL;
s->cldap.io.in.domain_guid = NULL;
s->cldap.io.in.domain_sid = NULL;
s->cldap.io.in.acct_control = -1;
s->cldap.io.in.version = 6;
s->cldap.sock = cldap_socket_init(s, s->libnet->event_ctx);
if (composite_nomem(s->cldap.sock, c)) return;
req = cldap_netlogon_send(s->cldap.sock, &s->cldap.io);
if (composite_nomem(req, c)) return;
req->async.fn = unbecomeDC_recv_cldap;
req->async.private = s;
}
static NTSTATUS unbecomeDC_ldap_connect(struct libnet_UnbecomeDC_state *s)
{
char *url;
url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
NT_STATUS_HAVE_NO_MEMORY(url);
s->ldap.ldb = ldb_wrap_connect(s, url,
NULL,
s->libnet->cred,
0, NULL);
talloc_free(url);
if (s->ldap.ldb == NULL) {
return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
}
return NT_STATUS_OK;
}
static NTSTATUS unbecomeDC_ldap_rootdse(struct libnet_UnbecomeDC_state *s)
{
int ret;
struct ldb_result *r;
struct ldb_dn *basedn;
static const char *attrs[] = {
"defaultNamingContext",
"configurationNamingContext",
NULL
};
basedn = ldb_dn_new(s, s->ldap.ldb, NULL);
NT_STATUS_HAVE_NO_MEMORY(basedn);
ret = ldb_search(s->ldap.ldb, basedn, LDB_SCOPE_BASE,
"(objectClass=*)", attrs, &r);
talloc_free(basedn);
if (ret != LDB_SUCCESS) {
return NT_STATUS_LDAP(ret);
} else if (r->count != 1) {
talloc_free(r);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
talloc_steal(s, r);
s->domain.dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "defaultNamingContext", NULL);
if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
talloc_steal(s, s->domain.dn_str);
s->forest.config_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "configurationNamingContext", NULL);
if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
talloc_steal(s, s->forest.config_dn_str);
s->dest_dsa.server_dn_str = talloc_asprintf(s, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
s->dest_dsa.netbios_name,
s->dest_dsa.site_name,
s->forest.config_dn_str);
NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.server_dn_str);
talloc_free(r);
return NT_STATUS_OK;
}
static NTSTATUS unbecomeDC_ldap_computer_object(struct libnet_UnbecomeDC_state *s)
{
int ret;
struct ldb_result *r;
struct ldb_dn *basedn;
char *filter;
static const char *attrs[] = {
"distinguishedName",
"userAccountControl",
NULL
};
basedn = ldb_dn_new(s, s->ldap.ldb, s->domain.dn_str);
NT_STATUS_HAVE_NO_MEMORY(basedn);
filter = talloc_asprintf(basedn, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
s->dest_dsa.netbios_name);
NT_STATUS_HAVE_NO_MEMORY(filter);
ret = ldb_search(s->ldap.ldb, basedn, LDB_SCOPE_SUBTREE,
filter, attrs, &r);
talloc_free(basedn);
if (ret != LDB_SUCCESS) {
return NT_STATUS_LDAP(ret);
} else if (r->count != 1) {
talloc_free(r);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
s->dest_dsa.computer_dn_str = samdb_result_string(r->msgs[0], "distinguishedName", NULL);
if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
talloc_steal(s, s->dest_dsa.computer_dn_str);
s->dest_dsa.user_account_control = samdb_result_uint(r->msgs[0], "userAccountControl", 0);
talloc_free(r);
return NT_STATUS_OK;
}
static NTSTATUS unbecomeDC_ldap_modify_computer(struct libnet_UnbecomeDC_state *s)
{
int ret;
struct ldb_message *msg;
uint32_t user_account_control = UF_WORKSTATION_TRUST_ACCOUNT;
uint32_t i;
/* as the value is already as we want it to be, we're done */
if (s->dest_dsa.user_account_control == user_account_control) {
return NT_STATUS_OK;
}
/* make a 'modify' msg, and only for serverReference */
msg = ldb_msg_new(s);
NT_STATUS_HAVE_NO_MEMORY(msg);
msg->dn = ldb_dn_new(msg, s->ldap.ldb, s->dest_dsa.computer_dn_str);
NT_STATUS_HAVE_NO_MEMORY(msg->dn);
ret = ldb_msg_add_fmt(msg, "userAccountControl", "%u", user_account_control);
if (ret != 0) {
talloc_free(msg);
return NT_STATUS_NO_MEMORY;
}
/* mark all the message elements (should be just one)
as LDB_FLAG_MOD_REPLACE */
for (i=0;i<msg->num_elements;i++) {
msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
}
ret = ldb_modify(s->ldap.ldb, msg);
talloc_free(msg);
if (ret != LDB_SUCCESS) {
return NT_STATUS_LDAP(ret);
}
s->dest_dsa.user_account_control = user_account_control;
return NT_STATUS_OK;
}
static NTSTATUS unbecomeDC_ldap_move_computer(struct libnet_UnbecomeDC_state *s)
{
int ret;
struct ldb_result *r;
struct ldb_dn *basedn;
struct ldb_dn *old_dn;
struct ldb_dn *new_dn;
static const char *_1_1_attrs[] = {
"1.1",
NULL
};
basedn = ldb_dn_new_fmt(s, s->ldap.ldb, "<WKGUID=aa312825768811d1aded00c04fd8d5cd,%s>",
s->domain.dn_str);
NT_STATUS_HAVE_NO_MEMORY(basedn);
ret = ldb_search(s->ldap.ldb, basedn, LDB_SCOPE_BASE,
"(objectClass=*)", _1_1_attrs, &r);
talloc_free(basedn);
if (ret != LDB_SUCCESS) {
return NT_STATUS_LDAP(ret);
} else if (r->count != 1) {
talloc_free(r);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
old_dn = ldb_dn_new(r, s->ldap.ldb, s->dest_dsa.computer_dn_str);
NT_STATUS_HAVE_NO_MEMORY(old_dn);
new_dn = r->msgs[0]->dn;
if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
talloc_free(r);
return NT_STATUS_NO_MEMORY;
}
if (ldb_dn_compare(old_dn, new_dn) == 0) {
/* we don't need to rename if the old and new dn match */
talloc_free(r);
return NT_STATUS_OK;
}
ret = ldb_rename(s->ldap.ldb, old_dn, new_dn);
if (ret != LDB_SUCCESS) {
talloc_free(r);
return NT_STATUS_LDAP(ret);
}
s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn);
NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str);
talloc_free(r);
return NT_STATUS_OK;
}
static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s);
static void unbecomeDC_connect_ldap(struct libnet_UnbecomeDC_state *s)
{
struct composite_context *c = s->creq;
c->status = unbecomeDC_ldap_connect(s);
if (!composite_is_ok(c)) return;
c->status = unbecomeDC_ldap_rootdse(s);
if (!composite_is_ok(c)) return;
c->status = unbecomeDC_ldap_computer_object(s);
if (!composite_is_ok(c)) return;
c->status = unbecomeDC_ldap_modify_computer(s);
if (!composite_is_ok(c)) return;
c->status = unbecomeDC_ldap_move_computer(s);
if (!composite_is_ok(c)) return;
unbecomeDC_drsuapi_connect_send(s);
}
static void unbecomeDC_drsuapi_connect_recv(struct composite_context *creq);
static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s)
{
struct composite_context *c = s->creq;
struct composite_context *creq;
char *binding_str;
binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal]", s->source_dsa.dns_name);
if (composite_nomem(binding_str, c)) return;
c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi.binding);
talloc_free(binding_str);
if (!composite_is_ok(c)) return;
creq = dcerpc_pipe_connect_b_send(s, s->drsuapi.binding, &dcerpc_table_drsuapi,
s->libnet->cred, s->libnet->event_ctx);
composite_continue(c, creq, unbecomeDC_drsuapi_connect_recv, s);
}
static void unbecomeDC_drsuapi_bind_send(struct libnet_UnbecomeDC_state *s);
static void unbecomeDC_drsuapi_connect_recv(struct composite_context *req)
{
struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private_data,
struct libnet_UnbecomeDC_state);
struct composite_context *c = s->creq;
c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi.pipe);
if (!composite_is_ok(c)) return;
unbecomeDC_drsuapi_bind_send(s);
}
static void unbecomeDC_drsuapi_bind_recv(struct rpc_request *req);
static void unbecomeDC_drsuapi_bind_send(struct libnet_UnbecomeDC_state *s)
{
struct composite_context *c = s->creq;
struct rpc_request *req;
struct drsuapi_DsBindInfo28 *bind_info28;
GUID_from_string(DRSUAPI_DS_BIND_GUID, &s->drsuapi.bind_guid);
bind_info28 = &s->drsuapi.local_info28;
bind_info28->supported_extensions = 0;
bind_info28->site_guid = GUID_zero();
bind_info28->u1 = 508;
bind_info28->repl_epoch = 0;
s->drsuapi.bind_info_ctr.length = 28;
s->drsuapi.bind_info_ctr.info.info28 = *bind_info28;
s->drsuapi.bind_r.in.bind_guid = &s->drsuapi.bind_guid;
s->drsuapi.bind_r.in.bind_info = &s->drsuapi.bind_info_ctr;
s->drsuapi.bind_r.out.bind_handle = &s->drsuapi.bind_handle;
req = dcerpc_drsuapi_DsBind_send(s->drsuapi.pipe, s, &s->drsuapi.bind_r);
composite_continue_rpc(c, req, unbecomeDC_drsuapi_bind_recv, s);
}
static void unbecomeDC_drsuapi_remove_ds_server_send(struct libnet_UnbecomeDC_state *s);
static void unbecomeDC_drsuapi_bind_recv(struct rpc_request *req)
{
struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private,
struct libnet_UnbecomeDC_state);
struct composite_context *c = s->creq;
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
if (!W_ERROR_IS_OK(s->drsuapi.bind_r.out.result)) {
composite_error(c, werror_to_ntstatus(s->drsuapi.bind_r.out.result));
return;
}
ZERO_STRUCT(s->drsuapi.remote_info28);
if (s->drsuapi.bind_r.out.bind_info) {
switch (s->drsuapi.bind_r.out.bind_info->length) {
case 24: {
struct drsuapi_DsBindInfo24 *info24;
info24 = &s->drsuapi.bind_r.out.bind_info->info.info24;
s->drsuapi.remote_info28.supported_extensions = info24->supported_extensions;
s->drsuapi.remote_info28.site_guid = info24->site_guid;
s->drsuapi.remote_info28.u1 = info24->u1;
s->drsuapi.remote_info28.repl_epoch = 0;
break;
}
case 28:
s->drsuapi.remote_info28 = s->drsuapi.bind_r.out.bind_info->info.info28;
break;
}
}
unbecomeDC_drsuapi_remove_ds_server_send(s);
}
static void unbecomeDC_drsuapi_remove_ds_server_recv(struct rpc_request *req);
static void unbecomeDC_drsuapi_remove_ds_server_send(struct libnet_UnbecomeDC_state *s)
{
struct composite_context *c = s->creq;
struct rpc_request *req;
struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r;
r->in.bind_handle = &s->drsuapi.bind_handle;
r->in.level = 1;
r->in.req.req1.server_dn= s->dest_dsa.server_dn_str;
r->in.req.req1.domain_dn= s->domain.dn_str;
r->in.req.req1.unknown = 0x00000001;
req = dcerpc_drsuapi_DsRemoveDSServer_send(s->drsuapi.pipe, s, r);
composite_continue_rpc(c, req, unbecomeDC_drsuapi_remove_ds_server_recv, s);
}
static void unbecomeDC_drsuapi_remove_ds_server_recv(struct rpc_request *req)
{
struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private,
struct libnet_UnbecomeDC_state);
struct composite_context *c = s->creq;
struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r;
c->status = dcerpc_ndr_request_recv(req);
if (!composite_is_ok(c)) return;
if (!W_ERROR_IS_OK(r->out.result)) {
composite_error(c, werror_to_ntstatus(r->out.result));
return;
}
if (r->out.level != 1) {
composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
if (!W_ERROR_IS_OK(r->out.res.res1.status)) {
composite_error(c, werror_to_ntstatus(r->out.res.res1.status));
return;
}
composite_done(c);
}
struct composite_context *libnet_UnbecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_UnbecomeDC *r)
{
struct composite_context *c;
struct libnet_UnbecomeDC_state *s;
char *tmp_name;
c = composite_create(mem_ctx, ctx->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct libnet_UnbecomeDC_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
s->creq = c;
s->libnet = ctx;
/* Domain input */
s->domain.dns_name = talloc_strdup(s, r->in.domain_dns_name);
if (composite_nomem(s->domain.dns_name, c)) return c;
s->domain.netbios_name = talloc_strdup(s, r->in.domain_netbios_name);
if (composite_nomem(s->domain.netbios_name, c)) return c;
/* Source DSA input */
s->source_dsa.address = talloc_strdup(s, r->in.source_dsa_address);
if (composite_nomem(s->source_dsa.address, c)) return c;
/* Destination DSA input */
s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
/* Destination DSA dns_name construction */
tmp_name = strlower_talloc(s, s->dest_dsa.netbios_name);
if (composite_nomem(tmp_name, c)) return c;
s->dest_dsa.dns_name = talloc_asprintf_append(tmp_name, ".%s",
s->domain.dns_name);
if (composite_nomem(s->dest_dsa.dns_name, c)) return c;
unbecomeDC_send_cldap(s);
return c;
}
NTSTATUS libnet_UnbecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_UnbecomeDC *r)
{
NTSTATUS status;
status = composite_wait(c);
ZERO_STRUCT(r->out);
talloc_free(c);
return status;
}
NTSTATUS libnet_UnbecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_UnbecomeDC *r)
{
NTSTATUS status;
struct composite_context *c;
c = libnet_UnbecomeDC_send(ctx, mem_ctx, r);
status = libnet_UnbecomeDC_recv(c, mem_ctx, r);
return status;
}
+32
View File
@@ -0,0 +1,32 @@
/*
Unix SMB/CIFS implementation.
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.
*/
struct libnet_UnbecomeDC {
struct {
const char *domain_dns_name;
const char *domain_netbios_name;
const char *source_dsa_address;
const char *dest_dsa_netbios_name;
} in;
struct {
const char *error_string;
} out;
};
File diff suppressed because it is too large Load Diff
+134
View File
@@ -0,0 +1,134 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak <mimir@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.
*/
struct libnet_CreateUser {
struct {
const char *user_name;
const char *domain_name;
} in;
struct {
const char *error_string;
} out;
};
struct libnet_DeleteUser {
struct {
const char *user_name;
const char *domain_name;
} in;
struct {
const char *error_string;
} out;
};
struct libnet_ModifyUser {
struct {
const char *user_name;
const char *domain_name;
const char *account_name;
const char *full_name;
const char *description;
const char *home_directory;
const char *home_drive;
const char *comment;
const char *logon_script;
const char *profile_path;
struct timeval *acct_expiry;
struct timeval *allow_password_change;
struct timeval *force_password_change;
struct timeval *last_password_change;
uint32_t acct_flags;
} in;
struct {
const char *error_string;
} out;
};
#define SET_FIELD_LSA_STRING(new, current, mod, field, flag) \
if (new.field != NULL && \
!strequal_w(current->field.string, new.field)) { \
\
mod->field = talloc_strdup(mem_ctx, new.field); \
if (mod->field == NULL) return NT_STATUS_NO_MEMORY; \
\
mod->fields |= flag; \
}
#define SET_FIELD_NTTIME(new, current, mod, field, flag) \
if (new.field != 0) { \
NTTIME newval = timeval_to_nttime(new.field); \
if (newval != current->field) { \
mod->field = talloc_memdup(mem_ctx, new.field, sizeof(*new.field)); \
if (mod->field == NULL) return NT_STATUS_NO_MEMORY; \
mod->fields |= flag; \
} \
}
struct libnet_UserInfo {
struct {
const char *user_name;
const char *domain_name;
} in;
struct {
const char *account_name;
const char *full_name;
const char *description;
const char *home_directory;
const char *home_drive;
const char *comment;
const char *logon_script;
const char *profile_path;
struct timeval *acct_expiry;
struct timeval *allow_password_change;
struct timeval *force_password_change;
struct timeval *last_logon;
struct timeval *last_logoff;
struct timeval *last_password_change;
uint32_t acct_flags;
const char *error_string;
} out;
};
struct libnet_UserList {
struct {
const char *domain_name;
int page_size;
uint resume_index;
} in;
struct {
int count;
uint resume_index;
struct userlist {
const char *sid;
const char *username;
} *users;
const char *error_string;
} out;
};
+384
View File
@@ -0,0 +1,384 @@
/*
Unix SMB/CIFS implementation.
Extract the user/system database from a remote SamSync server
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-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 "libnet/libnet.h"
#include "libcli/auth/libcli_auth.h"
#include "auth/gensec/gensec.h"
#include "auth/credentials/credentials.h"
#include "auth/gensec/schannel_proto.h"
#include "librpc/gen_ndr/ndr_netlogon.h"
#include "librpc/gen_ndr/ndr_netlogon_c.h"
/**
* Decrypt and extract the user's passwords.
*
* The writes decrypted (no longer 'RID encrypted' or arcfour encrypted) passwords back into the structure
*/
static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
struct creds_CredentialState *creds,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string)
{
uint32_t rid = delta->delta_id_union.rid;
struct netr_DELTA_USER *user = delta->delta_union.user;
struct samr_Password lm_hash;
struct samr_Password nt_hash;
const char *username = user->account_name.string;
NTSTATUS nt_status;
if (user->lm_password_present) {
sam_rid_crypt(rid, user->lmpassword.hash, lm_hash.hash, 0);
user->lmpassword = lm_hash;
}
if (user->nt_password_present) {
sam_rid_crypt(rid, user->ntpassword.hash, nt_hash.hash, 0);
user->ntpassword = nt_hash;
}
if (user->user_private_info.SensitiveData) {
DATA_BLOB data;
struct netr_USER_KEYS keys;
data.data = user->user_private_info.SensitiveData;
data.length = user->user_private_info.DataLength;
creds_arcfour_crypt(creds, data.data, data.length);
user->user_private_info.SensitiveData = data.data;
user->user_private_info.DataLength = data.length;
nt_status = ndr_pull_struct_blob(&data, mem_ctx, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
if (NT_STATUS_IS_OK(nt_status)) {
if (keys.keys.keys2.lmpassword.length == 16) {
sam_rid_crypt(rid, keys.keys.keys2.lmpassword.pwd.hash, lm_hash.hash, 0);
user->lmpassword = lm_hash;
user->lm_password_present = True;
}
if (keys.keys.keys2.ntpassword.length == 16) {
sam_rid_crypt(rid, keys.keys.keys2.ntpassword.pwd.hash, nt_hash.hash, 0);
user->ntpassword = nt_hash;
user->nt_password_present = True;
}
} else {
*error_string = talloc_asprintf(mem_ctx, "Failed to parse Sensitive Data for %s:", username);
dump_data(10, data.data, data.length);
return nt_status;
}
}
return NT_STATUS_OK;
}
/**
* Decrypt and extract the secrets
*
* The writes decrypted secrets back into the structure
*/
static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
struct creds_CredentialState *creds,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string)
{
struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
creds_arcfour_crypt(creds, secret->current_cipher.cipher_data,
secret->current_cipher.maxlen);
creds_arcfour_crypt(creds, secret->old_cipher.cipher_data,
secret->old_cipher.maxlen);
return NT_STATUS_OK;
}
/**
* Fix up the delta, dealing with encryption issues so that the final
* callback need only do the printing or application logic
*/
static NTSTATUS fix_delta(TALLOC_CTX *mem_ctx,
struct creds_CredentialState *creds,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string)
{
NTSTATUS nt_status = NT_STATUS_OK;
*error_string = NULL;
switch (delta->delta_type) {
case NETR_DELTA_USER:
{
nt_status = fix_user(mem_ctx,
creds,
database,
delta,
error_string);
break;
}
case NETR_DELTA_SECRET:
{
nt_status = fix_secret(mem_ctx,
creds,
database,
delta,
error_string);
break;
}
default:
break;
}
return nt_status;
}
NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamSync *r)
{
NTSTATUS nt_status, dbsync_nt_status;
TALLOC_CTX *samsync_ctx, *loop_ctx, *delta_ctx;
struct creds_CredentialState *creds;
struct netr_DatabaseSync dbsync;
struct cli_credentials *machine_account;
struct dcerpc_pipe *p;
struct libnet_context *machine_net_ctx;
struct libnet_RpcConnect *c;
struct libnet_SamSync_state *state;
const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS};
int i;
samsync_ctx = talloc_named(mem_ctx, 0, "SamSync top context");
if (!r->in.machine_account) {
machine_account = cli_credentials_init(samsync_ctx);
if (!machine_account) {
talloc_free(samsync_ctx);
return NT_STATUS_NO_MEMORY;
}
cli_credentials_set_conf(machine_account);
nt_status = cli_credentials_set_machine_account(machine_account);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
talloc_free(samsync_ctx);
return nt_status;
}
} else {
machine_account = r->in.machine_account;
}
/* We cannot do this unless we are a BDC. Check, before we get odd errors later */
if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
r->out.error_string
= talloc_asprintf(mem_ctx,
"Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
cli_credentials_get_domain(machine_account),
cli_credentials_get_secure_channel_type(machine_account));
talloc_free(samsync_ctx);
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
c = talloc(samsync_ctx, struct libnet_RpcConnect);
if (!c) {
r->out.error_string = NULL;
talloc_free(samsync_ctx);
return NT_STATUS_NO_MEMORY;
}
c->level = LIBNET_RPC_CONNECT_DC_INFO;
if (r->in.binding_string) {
c->in.binding = r->in.binding_string;
c->in.name = NULL;
} else {
c->in.binding = NULL;
c->in.name = cli_credentials_get_domain(machine_account);
}
/* prepare connect to the NETLOGON pipe of PDC */
c->in.dcerpc_iface = &dcerpc_table_netlogon;
/* We must do this as the machine, not as any command-line
* user. So we override the credentials in the
* libnet_context */
machine_net_ctx = talloc(samsync_ctx, struct libnet_context);
if (!machine_net_ctx) {
r->out.error_string = NULL;
talloc_free(samsync_ctx);
return NT_STATUS_NO_MEMORY;
}
*machine_net_ctx = *ctx;
machine_net_ctx->cred = machine_account;
/* connect to the NETLOGON pipe of the PDC */
nt_status = libnet_RpcConnect(machine_net_ctx, samsync_ctx, c);
if (!NT_STATUS_IS_OK(nt_status)) {
if (r->in.binding_string) {
r->out.error_string = talloc_asprintf(mem_ctx,
"Connection to NETLOGON pipe of DC %s failed: %s",
r->in.binding_string, c->out.error_string);
} else {
r->out.error_string = talloc_asprintf(mem_ctx,
"Connection to NETLOGON pipe of DC for %s failed: %s",
c->in.name, c->out.error_string);
}
talloc_free(samsync_ctx);
return nt_status;
}
/* This makes a new pipe, on which we can do schannel. We
* should do this in the RpcConnect code, but the abstaction
* layers do not suit yet */
nt_status = dcerpc_secondary_connection(c->out.dcerpc_pipe, &p,
c->out.dcerpc_pipe->binding);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"Secondary connection to NETLOGON pipe of DC %s failed: %s",
dcerpc_server_name(p), nt_errstr(nt_status));
talloc_free(samsync_ctx);
return nt_status;
}
nt_status = dcerpc_bind_auth_schannel(samsync_ctx, p, &dcerpc_table_netlogon,
machine_account, DCERPC_AUTH_LEVEL_PRIVACY);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.error_string = talloc_asprintf(mem_ctx,
"SCHANNEL authentication to NETLOGON pipe of DC %s failed: %s",
dcerpc_server_name(p), nt_errstr(nt_status));
talloc_free(samsync_ctx);
return nt_status;
}
state = talloc(samsync_ctx, struct libnet_SamSync_state);
if (!state) {
r->out.error_string = NULL;
talloc_free(samsync_ctx);
return nt_status;
}
state->domain_name = c->out.domain_name;
state->domain_sid = c->out.domain_sid;
state->realm = c->out.realm;
state->domain_guid = c->out.guid;
state->machine_net_ctx = machine_net_ctx;
state->netlogon_pipe = p;
/* initialise the callback layer. It may wish to contact the
* server with ldap, now we know the name */
if (r->in.init_fn) {
char *error_string;
nt_status = r->in.init_fn(samsync_ctx,
r->in.fn_ctx,
state,
&error_string);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.error_string = talloc_steal(mem_ctx, error_string);
talloc_free(samsync_ctx);
return nt_status;
}
}
/* get NETLOGON credentails */
nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, samsync_ctx, &creds);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer");
talloc_free(samsync_ctx);
return nt_status;
}
/* Setup details for the synchronisation */
dbsync.in.logon_server = talloc_asprintf(samsync_ctx, "\\\\%s", dcerpc_server_name(p));
dbsync.in.computername = cli_credentials_get_workstation(machine_account);
dbsync.in.preferredmaximumlength = (uint32_t)-1;
ZERO_STRUCT(dbsync.in.return_authenticator);
for (i=0;i< ARRAY_SIZE(database_ids); i++) {
dbsync.in.sync_context = 0;
dbsync.in.database_id = database_ids[i];
do {
int d;
loop_ctx = talloc_named(samsync_ctx, 0, "DatabaseSync loop context");
creds_client_authenticator(creds, &dbsync.in.credential);
dbsync_nt_status = dcerpc_netr_DatabaseSync(p, loop_ctx, &dbsync);
if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
!NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
r->out.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
talloc_free(samsync_ctx);
return nt_status;
}
if (!creds_client_check(creds, &dbsync.out.return_authenticator.cred)) {
r->out.error_string = talloc_strdup(mem_ctx, "Credential chaining on incoming DatabaseSync failed");
talloc_free(samsync_ctx);
return NT_STATUS_ACCESS_DENIED;
}
dbsync.in.sync_context = dbsync.out.sync_context;
/* For every single remote 'delta' entry: */
for (d=0; d < dbsync.out.delta_enum_array->num_deltas; d++) {
char *error_string = NULL;
delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
/* 'Fix' elements, by decrypting and
* de-obfuscating the data */
nt_status = fix_delta(delta_ctx,
creds,
dbsync.in.database_id,
&dbsync.out.delta_enum_array->delta_enum[d],
&error_string);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.error_string = talloc_steal(mem_ctx, error_string);
talloc_free(samsync_ctx);
return nt_status;
}
/* Now call the callback. This will
* do something like print the data or
* write to an ldb */
nt_status = r->in.delta_fn(delta_ctx,
r->in.fn_ctx,
dbsync.in.database_id,
&dbsync.out.delta_enum_array->delta_enum[d],
&error_string);
if (!NT_STATUS_IS_OK(nt_status)) {
r->out.error_string = talloc_steal(mem_ctx, error_string);
talloc_free(samsync_ctx);
return nt_status;
}
talloc_free(delta_ctx);
}
talloc_free(loop_ctx);
} while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
if (!NT_STATUS_IS_OK(dbsync_nt_status)) {
r->out.error_string = talloc_asprintf(mem_ctx, "libnet_SamSync_netlogon failed: unexpected inconsistancy. Should not get error %s here", nt_errstr(nt_status));
talloc_free(samsync_ctx);
return dbsync_nt_status;
}
nt_status = NT_STATUS_OK;
}
talloc_free(samsync_ctx);
return nt_status;
}
+84
View File
@@ -0,0 +1,84 @@
/*
Unix SMB/CIFS implementation.
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 "librpc/gen_ndr/netlogon.h"
struct libnet_SamSync_state {
struct libnet_context *machine_net_ctx;
struct dcerpc_pipe *netlogon_pipe;
const char *domain_name;
const struct dom_sid *domain_sid;
const char *realm;
struct GUID *domain_guid;
};
/* struct and enum for doing a remote domain vampire dump */
struct libnet_SamSync {
struct {
const char *binding_string;
NTSTATUS (*init_fn)(TALLOC_CTX *mem_ctx,
void *private,
struct libnet_SamSync_state *samsync_state,
char **error_string);
NTSTATUS (*delta_fn)(TALLOC_CTX *mem_ctx,
void *private,
enum netr_SamDatabaseID database,
struct netr_DELTA_ENUM *delta,
char **error_string);
void *fn_ctx;
struct cli_credentials *machine_account;
} in;
struct {
const char *error_string;
} out;
};
struct libnet_SamDump {
struct {
const char *binding_string;
struct cli_credentials *machine_account;
} in;
struct {
const char *error_string;
} out;
};
struct libnet_SamDump_keytab {
struct {
const char *binding_string;
const char *keytab_name;
struct cli_credentials *machine_account;
} in;
struct {
const char *error_string;
} out;
};
struct libnet_samsync_ldb {
struct {
const char *binding_string;
struct cli_credentials *machine_account;
struct auth_session_info *session_info;
} in;
struct {
const char *error_string;
} out;
};
+138
View File
@@ -0,0 +1,138 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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 "libnet/libnet.h"
#include "libcli/composite/composite.h"
#include "auth/credentials/credentials.h"
#include "librpc/ndr/libndr.h"
#include "librpc/gen_ndr/samr.h"
#include "librpc/gen_ndr/ndr_samr.h"
#include "librpc/gen_ndr/lsa.h"
#include "librpc/gen_ndr/ndr_lsa.h"
struct composite_context* samr_domain_opened(struct libnet_context *ctx,
const char *domain_name,
struct composite_context *parent_ctx,
struct libnet_DomainOpen *domain_open,
void (*continue_fn)(struct composite_context*),
void (*monitor)(struct monitor_msg*))
{
struct composite_context *domopen_req;
if (domain_name == NULL) {
/*
* Try to guess the domain name from credentials,
* if it's not been explicitly specified.
*/
if (policy_handle_empty(&ctx->samr.handle)) {
domain_open->in.type = DOMAIN_SAMR;
domain_open->in.domain_name = cli_credentials_get_domain(ctx->cred);
domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
} else {
composite_error(parent_ctx, NT_STATUS_INVALID_PARAMETER);
return parent_ctx;
}
} else {
/*
* The domain name has been specified, so check whether the same
* domain is already opened. If it is - just return NULL. Start
* opening a new domain otherwise.
*/
if (policy_handle_empty(&ctx->samr.handle) ||
!strequal(domain_name, ctx->samr.name)) {
domain_open->in.type = DOMAIN_SAMR;
domain_open->in.domain_name = domain_name;
domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
} else {
/* domain has already been opened and it's the same domain
as requested */
return NULL;
}
}
/* send request to open the domain */
domopen_req = libnet_DomainOpen_send(ctx, domain_open, monitor);
if (composite_nomem(domopen_req, parent_ctx)) return parent_ctx;
composite_continue(parent_ctx, domopen_req, continue_fn, parent_ctx);
return parent_ctx;
}
struct composite_context* lsa_domain_opened(struct libnet_context *ctx,
const char *domain_name,
struct composite_context *parent_ctx,
struct libnet_DomainOpen *domain_open,
void (*continue_fn)(struct composite_context*),
void (*monitor)(struct monitor_msg*))
{
struct composite_context *domopen_req;
if (domain_name == NULL) {
/*
* Try to guess the domain name from credentials,
* if it's not been explicitly specified.
*/
if (policy_handle_empty(&ctx->lsa.handle)) {
domain_open->in.type = DOMAIN_LSA;
domain_open->in.domain_name = cli_credentials_get_domain(ctx->cred);
domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
} else {
composite_error(parent_ctx, NT_STATUS_INVALID_PARAMETER);
return parent_ctx;
}
} else {
/*
* The domain name has been specified, so check whether the same
* domain is already opened. If it is - just return NULL. Start
* opening a new domain otherwise.
*/
if (policy_handle_empty(&ctx->lsa.handle) ||
!strequal(domain_name, ctx->lsa.name)) {
domain_open->in.type = DOMAIN_LSA;
domain_open->in.domain_name = domain_name;
domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
} else {
/* domain has already been opened and it's the same domain
as requested */
return NULL;
}
}
/* send request to open the domain */
domopen_req = libnet_DomainOpen_send(ctx, domain_open, monitor);
if (composite_nomem(domopen_req, parent_ctx)) return parent_ctx;
composite_continue(parent_ctx, domopen_req, continue_fn, parent_ctx);
return parent_ctx;
}
+368
View File
@@ -0,0 +1,368 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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 function for getting user information via samr pipe
*/
#include "includes.h"
#include "libcli/composite/composite.h"
#include "libnet/composite.h"
#include "librpc/gen_ndr/security.h"
#include "libcli/security/security.h"
#include "libnet/userman.h"
#include "libnet/userinfo.h"
#include "librpc/gen_ndr/ndr_samr_c.h"
static void userinfo_handler(struct rpc_request *req);
enum userinfo_stage { USERINFO_LOOKUP, USERINFO_OPENUSER, USERINFO_GETUSER, USERINFO_CLOSEUSER };
struct userinfo_state {
enum userinfo_stage stage;
struct dcerpc_pipe *pipe;
struct rpc_request *req;
struct policy_handle domain_handle;
struct policy_handle user_handle;
uint16_t level;
struct samr_LookupNames lookup;
struct samr_OpenUser openuser;
struct samr_QueryUserInfo queryuserinfo;
struct samr_Close samrclose;
union samr_UserInfo *info;
/* information about the progress */
void (*monitor_fn)(struct monitor_msg *);
};
/**
* Stage 1 (optional): Look for a username in SAM server.
*/
static NTSTATUS userinfo_lookup(struct composite_context *c,
struct userinfo_state *s)
{
/* receive samr_Lookup reply */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* there could be a problem with name resolving itself */
NT_STATUS_NOT_OK_RETURN(s->lookup.out.result);
/* have we actually got name resolved
- we're looking for only one at the moment */
if (s->lookup.out.rids.count == 0) {
return NT_STATUS_NO_SUCH_USER;
}
/* TODO: find proper status code for more than one rid found */
/* prepare parameters for LookupNames */
s->openuser.in.domain_handle = &s->domain_handle;
s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
s->openuser.in.rid = s->lookup.out.rids.ids[0];
s->openuser.out.user_handle = &s->user_handle;
/* send request */
s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
if (s->req == NULL) goto failure;
s->req->async.callback = userinfo_handler;
s->req->async.private = c;
s->stage = USERINFO_OPENUSER;
return NT_STATUS_OK;
failure:
return NT_STATUS_UNSUCCESSFUL;
}
/**
* Stage 2: Open user policy handle.
*/
static NTSTATUS userinfo_openuser(struct composite_context *c,
struct userinfo_state *s)
{
/* receive samr_OpenUser reply */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* prepare parameters for QueryUserInfo call */
s->queryuserinfo.in.user_handle = &s->user_handle;
s->queryuserinfo.in.level = s->level;
/* queue rpc call, set event handling and new state */
s->req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuserinfo);
if (s->req == NULL) goto failure;
s->req->async.callback = userinfo_handler;
s->req->async.private = c;
s->stage = USERINFO_GETUSER;
return NT_STATUS_OK;
failure:
return NT_STATUS_UNSUCCESSFUL;
}
/**
* Stage 3: Get requested user information.
*/
static NTSTATUS userinfo_getuser(struct composite_context *c,
struct userinfo_state *s)
{
/* receive samr_QueryUserInfo reply */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* check if queryuser itself went ok */
NT_STATUS_NOT_OK_RETURN(s->queryuserinfo.out.result);
s->info = talloc_steal(s, s->queryuserinfo.out.info);
/* prepare arguments for Close call */
s->samrclose.in.handle = &s->user_handle;
s->samrclose.out.handle = &s->user_handle;
/* queue rpc call, set event handling and new state */
s->req = dcerpc_samr_Close_send(s->pipe, c, &s->samrclose);
s->req->async.callback = userinfo_handler;
s->req->async.private = c;
s->stage = USERINFO_CLOSEUSER;
return NT_STATUS_OK;
}
/**
* Stage 4: Close policy handle associated with opened user.
*/
static NTSTATUS userinfo_closeuser(struct composite_context *c,
struct userinfo_state *s)
{
/* receive samr_Close reply */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
c->state = COMPOSITE_STATE_DONE;
return NT_STATUS_OK;
}
/**
* Event handler for asynchronous request. Handles transition through
* intermediate stages of the call.
*
* @param req rpc call context
*/
static void userinfo_handler(struct rpc_request *req)
{
struct composite_context *c = req->async.private;
struct userinfo_state *s = talloc_get_type(c->private_data, struct userinfo_state);
struct monitor_msg msg;
struct msg_rpc_lookup_name *msg_lookup;
struct msg_rpc_open_user *msg_open;
struct msg_rpc_query_user *msg_query;
struct msg_rpc_close_user *msg_close;
/* Stages of the call */
switch (s->stage) {
case USERINFO_LOOKUP:
c->status = userinfo_lookup(c, s);
msg.type = rpc_lookup_name;
msg_lookup = talloc(s, struct msg_rpc_lookup_name);
msg_lookup->rid = s->lookup.out.rids.ids;
msg_lookup->count = s->lookup.out.rids.count;
msg.data = (void*)msg_lookup;
msg.data_size = sizeof(*msg_lookup);
break;
case USERINFO_OPENUSER:
c->status = userinfo_openuser(c, s);
msg.type = rpc_open_user;
msg_open = talloc(s, struct msg_rpc_open_user);
msg_open->rid = s->openuser.in.rid;
msg_open->access_mask = s->openuser.in.access_mask;
msg.data = (void*)msg_open;
msg.data_size = sizeof(*msg_open);
break;
case USERINFO_GETUSER:
c->status = userinfo_getuser(c, s);
msg.type = rpc_query_user;
msg_query = talloc(s, struct msg_rpc_query_user);
msg_query->level = s->queryuserinfo.in.level;
msg.data = (void*)msg_query;
msg.data_size = sizeof(*msg_query);
break;
case USERINFO_CLOSEUSER:
c->status = userinfo_closeuser(c, s);
msg.type = rpc_close_user;
msg_close = talloc(s, struct msg_rpc_close_user);
msg_close->rid = s->openuser.in.rid;
msg.data = (void*)msg_close;
msg.data_size = sizeof(*msg_close);
break;
}
if (!NT_STATUS_IS_OK(c->status)) {
c->state = COMPOSITE_STATE_ERROR;
}
if (s->monitor_fn) {
s->monitor_fn(&msg);
}
if (c->state >= COMPOSITE_STATE_DONE &&
c->async.fn) {
c->async.fn(c);
}
}
/**
* Sends asynchronous userinfo request
*
* @param p dce/rpc call pipe
* @param io arguments and results of the call
*/
struct composite_context *libnet_rpc_userinfo_send(struct dcerpc_pipe *p,
struct libnet_rpc_userinfo *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct userinfo_state *s;
struct dom_sid *sid;
if (!p || !io) return NULL;
c = talloc_zero(p, struct composite_context);
if (c == NULL) goto failure;
s = talloc_zero(c, struct userinfo_state);
if (s == NULL) goto failure;
s->level = io->in.level;
s->pipe = p;
s->domain_handle = io->in.domain_handle;
s->monitor_fn = monitor;
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
c->event_ctx = dcerpc_event_context(p);
if (io->in.sid) {
sid = dom_sid_parse_talloc(s, io->in.sid);
if (sid == NULL) goto failure;
s->openuser.in.domain_handle = &s->domain_handle;
s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
s->openuser.in.rid = sid->sub_auths[sid->num_auths - 1];
s->openuser.out.user_handle = &s->user_handle;
/* send request */
s->req = dcerpc_samr_OpenUser_send(p, c, &s->openuser);
if (s->req == NULL) goto failure;
s->stage = USERINFO_OPENUSER;
} else {
/* preparing parameters to send rpc request */
s->lookup.in.domain_handle = &s->domain_handle;
s->lookup.in.num_names = 1;
s->lookup.in.names = talloc_array(s, struct lsa_String, 1);
if (composite_nomem(s->lookup.in.names, c)) return c;
s->lookup.in.names[0].string = talloc_strdup(s, io->in.username);
/* send request */
s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookup);
if (s->req == NULL) goto failure;
s->stage = USERINFO_LOOKUP;
}
/* callback handler */
s->req->async.callback = userinfo_handler;
s->req->async.private = c;
return c;
failure:
talloc_free(c);
return NULL;
}
/**
* Waits for and receives result of asynchronous userinfo call
*
* @param c composite context returned by asynchronous userinfo call
* @param mem_ctx memory context of the call
* @param io pointer to results (and arguments) of the call
* @return nt status code of execution
*/
NTSTATUS libnet_rpc_userinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
struct libnet_rpc_userinfo *io)
{
NTSTATUS status;
struct userinfo_state *s;
/* wait for results of sending request */
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) && io) {
s = talloc_get_type(c->private_data, struct userinfo_state);
talloc_steal(mem_ctx, s->info);
io->out.info = *s->info;
}
/* memory context associated to composite context is no longer needed */
talloc_free(c);
return status;
}
/**
* Synchronous version of userinfo call
*
* @param pipe dce/rpc call pipe
* @param mem_ctx memory context for the call
* @param io arguments and results of the call
* @return nt status code of execution
*/
NTSTATUS libnet_rpc_userinfo(struct dcerpc_pipe *p,
TALLOC_CTX *mem_ctx,
struct libnet_rpc_userinfo *io)
{
struct composite_context *c = libnet_rpc_userinfo_send(p, io, NULL);
return libnet_rpc_userinfo_recv(c, mem_ctx, io);
}
+55
View File
@@ -0,0 +1,55 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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 "librpc/gen_ndr/samr.h"
/*
* IO structures for userinfo.c functions
*/
struct libnet_rpc_userinfo {
struct {
struct policy_handle domain_handle;
const char *username;
const char *sid;
uint16_t level;
} in;
struct {
union samr_UserInfo info;
} out;
};
/*
* Monitor messages sent from userinfo.c functions
*/
struct msg_rpc_open_user {
uint32_t rid, access_mask;
};
struct msg_rpc_query_user {
uint16_t level;
};
struct msg_rpc_close_user {
uint32_t rid;
};
+968
View File
@@ -0,0 +1,968 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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 functions for user management operations (add/del/chg)
*/
#include "includes.h"
#include "libcli/composite/composite.h"
#include "libnet/composite.h"
#include "libnet/userman.h"
#include "libnet/userinfo.h"
#include "librpc/gen_ndr/ndr_samr_c.h"
/*
* Composite USER ADD functionality
*/
static void useradd_handler(struct rpc_request*);
enum useradd_stage { USERADD_CREATE };
struct useradd_state {
enum useradd_stage stage;
struct dcerpc_pipe *pipe;
struct rpc_request *req;
struct policy_handle domain_handle;
struct samr_CreateUser createuser;
struct policy_handle user_handle;
uint32_t user_rid;
/* information about the progress */
void (*monitor_fn)(struct monitor_msg *);
};
/**
* Stage 1 (and the only one for now): Create user account.
*/
static NTSTATUS useradd_create(struct composite_context *c,
struct useradd_state *s)
{
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
c->state = COMPOSITE_STATE_DONE;
return NT_STATUS_OK;
}
/**
* Event handler for asynchronous request. Handles transition through
* intermediate stages of the call.
*
* @param req rpc call context
*/
static void useradd_handler(struct rpc_request *req)
{
struct composite_context *c = req->async.private;
struct useradd_state *s = talloc_get_type(c->private_data, struct useradd_state);
struct monitor_msg msg;
struct msg_rpc_create_user *rpc_create;
switch (s->stage) {
case USERADD_CREATE:
c->status = useradd_create(c, s);
/* prepare a message to pass to monitor function */
msg.type = rpc_create_user;
rpc_create = talloc(s, struct msg_rpc_create_user);
rpc_create->rid = *s->createuser.out.rid;
msg.data = (void*)rpc_create;
msg.data_size = sizeof(*rpc_create);
break;
}
/* are we ok so far ? */
if (!NT_STATUS_IS_OK(c->status)) {
c->state = COMPOSITE_STATE_ERROR;
}
/* call monitor function provided the pointer has been passed */
if (s->monitor_fn) {
s->monitor_fn(&msg);
}
/* are we done yet ? */
if (c->state >= COMPOSITE_STATE_DONE &&
c->async.fn) {
c->async.fn(c);
}
}
/**
* Sends asynchronous useradd request
*
* @param p dce/rpc call pipe
* @param io arguments and results of the call
* @param monitor monitor function for providing information about the progress
*/
struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
struct libnet_rpc_useradd *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct useradd_state *s;
/* composite allocation and setup */
c = talloc_zero(p, struct composite_context);
if (c == NULL) return NULL;
s = talloc_zero(c, struct useradd_state);
if (composite_nomem(s, c)) return c;
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
c->event_ctx = dcerpc_event_context(p);
/* put passed arguments to the state structure */
s->domain_handle = io->in.domain_handle;
s->pipe = p;
s->monitor_fn = monitor;
/* preparing parameters to send rpc request */
s->createuser.in.domain_handle = &io->in.domain_handle;
s->createuser.in.account_name = talloc_zero(c, struct lsa_String);
s->createuser.in.account_name->string = talloc_strdup(c, io->in.username);
s->createuser.out.user_handle = &s->user_handle;
s->createuser.out.rid = &s->user_rid;
/* send the request */
s->req = dcerpc_samr_CreateUser_send(p, c, &s->createuser);
if (composite_nomem(s->req, c)) return c;
/* callback handler for continuation */
s->req->async.callback = useradd_handler;
s->req->async.private = c;
s->stage = USERADD_CREATE;
return c;
}
/**
* Waits for and receives result of asynchronous useradd call
*
* @param c composite context returned by asynchronous useradd call
* @param mem_ctx memory context of the call
* @param io pointer to results (and arguments) of the call
* @return nt status code of execution
*/
NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
struct libnet_rpc_useradd *io)
{
NTSTATUS status;
struct useradd_state *s;
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) && io) {
/* get and return result of the call */
s = talloc_get_type(c->private_data, struct useradd_state);
io->out.user_handle = s->user_handle;
}
talloc_free(c);
return status;
}
/**
* Synchronous version of useradd call
*
* @param pipe dce/rpc call pipe
* @param mem_ctx memory context for the call
* @param io arguments and results of the call
* @return nt status code of execution
*/
NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p,
TALLOC_CTX *mem_ctx,
struct libnet_rpc_useradd *io)
{
struct composite_context *c = libnet_rpc_useradd_send(p, io, NULL);
return libnet_rpc_useradd_recv(c, mem_ctx, io);
}
/*
* Composite USER DELETE functionality
*/
static void userdel_handler(struct rpc_request*);
enum userdel_stage { USERDEL_LOOKUP, USERDEL_OPEN, USERDEL_DELETE };
struct userdel_state {
enum userdel_stage stage;
struct dcerpc_pipe *pipe;
struct rpc_request *req;
struct policy_handle domain_handle;
struct policy_handle user_handle;
struct samr_LookupNames lookupname;
struct samr_OpenUser openuser;
struct samr_DeleteUser deleteuser;
/* information about the progress */
void (*monitor_fn)(struct monitor_msg *);
};
/**
* Stage 1: Lookup the user name and resolve it to rid
*/
static NTSTATUS userdel_lookup(struct composite_context *c,
struct userdel_state *s)
{
/* receive samr_LookupNames result */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* what to do when there's no user account to delete
and what if there's more than one rid resolved */
if (!s->lookupname.out.rids.count) {
c->status = NT_STATUS_NO_SUCH_USER;
composite_error(c, c->status);
} else if (!s->lookupname.out.rids.count > 1) {
c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
composite_error(c, c->status);
}
/* prepare the next rpc call arguments */
s->openuser.in.domain_handle = &s->domain_handle;
s->openuser.in.rid = s->lookupname.out.rids.ids[0];
s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
s->openuser.out.user_handle = &s->user_handle;
/* send rpc request */
s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
if (s->req == NULL) return NT_STATUS_NO_MEMORY;
/* callback handler setup */
s->req->async.callback = userdel_handler;
s->req->async.private = c;
s->stage = USERDEL_OPEN;
return NT_STATUS_OK;
}
/**
* Stage 2: Open user account.
*/
static NTSTATUS userdel_open(struct composite_context *c,
struct userdel_state *s)
{
/* receive samr_OpenUser result */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* prepare the final rpc call arguments */
s->deleteuser.in.user_handle = &s->user_handle;
s->deleteuser.out.user_handle = &s->user_handle;
/* send rpc request */
s->req = dcerpc_samr_DeleteUser_send(s->pipe, c, &s->deleteuser);
if (s->req == NULL) return NT_STATUS_NO_MEMORY;
/* callback handler setup */
s->req->async.callback = userdel_handler;
s->req->async.private = c;
s->stage = USERDEL_DELETE;
return NT_STATUS_OK;
}
/**
* Stage 3: Delete user account
*/
static NTSTATUS userdel_delete(struct composite_context *c,
struct userdel_state *s)
{
/* receive samr_DeleteUser result */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
c->state = COMPOSITE_STATE_DONE;
return NT_STATUS_OK;
}
/**
* Event handler for asynchronous request. Handles transition through
* intermediate stages of the call.
*
* @param req rpc call context
*/
static void userdel_handler(struct rpc_request *req)
{
struct composite_context *c;
struct userdel_state *s;
struct monitor_msg msg;
struct msg_rpc_lookup_name *msg_lookup;
struct msg_rpc_open_user *msg_open;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct userdel_state);
switch (s->stage) {
case USERDEL_LOOKUP:
c->status = userdel_lookup(c, s);
/* monitor message */
msg.type = rpc_lookup_name;
msg_lookup = talloc(s, struct msg_rpc_lookup_name);
msg_lookup->rid = s->lookupname.out.rids.ids;
msg_lookup->count = s->lookupname.out.rids.count;
msg.data = (void*)msg_lookup;
msg.data_size = sizeof(*msg_lookup);
break;
case USERDEL_OPEN:
c->status = userdel_open(c, s);
/* monitor message */
msg.type = rpc_open_user;
msg_open = talloc(s, struct msg_rpc_open_user);
msg_open->rid = s->openuser.in.rid;
msg_open->access_mask = s->openuser.in.rid;
msg.data = (void*)msg_open;
msg.data_size = sizeof(*msg_open);
break;
case USERDEL_DELETE:
c->status = userdel_delete(c, s);
/* monitor message */
msg.type = rpc_delete_user;
msg.data = NULL;
msg.data_size = 0;
break;
}
/* are we ok, so far ? */
if (!NT_STATUS_IS_OK(c->status)) {
c->state = COMPOSITE_STATE_ERROR;
}
/* call monitor function provided the pointer has been passed */
if (s->monitor_fn) {
s->monitor_fn(&msg);
}
/* are we done yet */
if (c->state >= COMPOSITE_STATE_DONE &&
c->async.fn) {
c->async.fn(c);
}
}
/**
* Sends asynchronous userdel request
*
* @param p dce/rpc call pipe
* @param io arguments and results of the call
* @param monitor monitor function for providing information about the progress
*/
struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
struct libnet_rpc_userdel *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct userdel_state *s;
/* composite context allocation and setup */
c = talloc_zero(p, struct composite_context);
if (c == NULL) return NULL;
s = talloc_zero(c, struct userdel_state);
if (composite_nomem(s, c)) return c;
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
c->event_ctx = dcerpc_event_context(p);
/* store function parameters in the state structure */
s->pipe = p;
s->domain_handle = io->in.domain_handle;
s->monitor_fn = monitor;
/* preparing parameters to send rpc request */
s->lookupname.in.domain_handle = &io->in.domain_handle;
s->lookupname.in.num_names = 1;
s->lookupname.in.names = talloc_zero(s, struct lsa_String);
s->lookupname.in.names->string = io->in.username;
/* send the request */
s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
/* callback handler setup */
s->req->async.callback = userdel_handler;
s->req->async.private = c;
s->stage = USERDEL_LOOKUP;
return c;
}
/**
* Waits for and receives results of asynchronous userdel call
*
* @param c composite context returned by asynchronous userdel call
* @param mem_ctx memory context of the call
* @param io pointer to results (and arguments) of the call
* @return nt status code of execution
*/
NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
struct libnet_rpc_userdel *io)
{
NTSTATUS status;
struct userdel_state *s;
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) && io) {
s = talloc_get_type(c->private_data, struct userdel_state);
io->out.user_handle = s->user_handle;
}
talloc_free(c);
return status;
}
/**
* Synchronous version of userdel call
*
* @param pipe dce/rpc call pipe
* @param mem_ctx memory context for the call
* @param io arguments and results of the call
* @return nt status code of execution
*/
NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p,
TALLOC_CTX *mem_ctx,
struct libnet_rpc_userdel *io)
{
struct composite_context *c = libnet_rpc_userdel_send(p, io, NULL);
return libnet_rpc_userdel_recv(c, mem_ctx, io);
}
/*
* USER MODIFY functionality
*/
static void usermod_handler(struct rpc_request*);
enum usermod_stage { USERMOD_LOOKUP, USERMOD_OPEN, USERMOD_QUERY, USERMOD_MODIFY };
struct usermod_state {
enum usermod_stage stage;
struct dcerpc_pipe *pipe;
struct rpc_request *req;
struct policy_handle domain_handle;
struct policy_handle user_handle;
struct usermod_change change;
union samr_UserInfo info;
struct samr_LookupNames lookupname;
struct samr_OpenUser openuser;
struct samr_SetUserInfo setuser;
struct samr_QueryUserInfo queryuser;
/* information about the progress */
void (*monitor_fn)(struct monitor_msg *);
};
/**
* Step 1: Lookup user name
*/
static NTSTATUS usermod_lookup(struct composite_context *c,
struct usermod_state *s)
{
/* receive samr_LookupNames result */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* what to do when there's no user account to delete
and what if there's more than one rid resolved */
if (!s->lookupname.out.rids.count) {
c->status = NT_STATUS_NO_SUCH_USER;
c->state = COMPOSITE_STATE_ERROR;
return c->status;
} else if (!s->lookupname.out.rids.count > 1) {
c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
c->state = COMPOSITE_STATE_ERROR;
return c->status;
}
/* prepare the next rpc call */
s->openuser.in.domain_handle = &s->domain_handle;
s->openuser.in.rid = s->lookupname.out.rids.ids[0];
s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
s->openuser.out.user_handle = &s->user_handle;
/* send the rpc request */
s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
/* callback handler setup */
s->req->async.callback = usermod_handler;
s->req->async.private = c;
s->stage = USERMOD_OPEN;
return NT_STATUS_OK;
}
/**
* Choose a proper level of samr_UserInfo structure depending on required
* change specified by means of flags field. Subsequent calls of this
* function are made until there's no flags set meaning that all of the
* changes have been made.
*/
static uint32_t usermod_setfields(struct usermod_state *s, uint16_t *level,
union samr_UserInfo *i)
{
if (s->change.fields == 0) return s->change.fields;
*level = 0;
if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
(*level == 0 || *level == 7)) {
*level = 7;
i->info7.account_name.string = s->change.account_name;
s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
}
if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
(*level == 0 || *level == 8)) {
*level = 8;
i->info8.full_name.string = s->change.full_name;
s->change.fields ^= USERMOD_FIELD_FULL_NAME;
}
if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
(*level == 0 || *level == 13)) {
*level = 13;
i->info13.description.string = s->change.description;
s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
}
if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
(*level == 0 || *level == 2)) {
*level = 2;
if (s->stage == USERMOD_QUERY) {
/* the user info is obtained, so now set the required field */
i->info2.comment.string = s->change.comment;
s->change.fields ^= USERMOD_FIELD_COMMENT;
} else {
/* we need to query the user info before setting one field in it */
s->stage = USERMOD_QUERY;
return s->change.fields;
}
}
if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
(*level == 0 || *level == 11)) {
*level = 11;
i->info11.logon_script.string = s->change.logon_script;
s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
}
if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
(*level == 0 || *level == 12)) {
*level = 12;
i->info12.profile_path.string = s->change.profile_path;
s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
}
if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
(*level == 0 || *level == 10)) {
*level = 10;
if (s->stage == USERMOD_QUERY) {
i->info10.home_directory.string = s->change.home_directory;
s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
} else {
s->stage = USERMOD_QUERY;
return s->change.fields;
}
}
if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
(*level == 0 || *level == 10)) {
*level = 10;
if (s->stage == USERMOD_QUERY) {
i->info10.home_drive.string = s->change.home_drive;
s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
} else {
s->stage = USERMOD_QUERY;
return s->change.fields;
}
}
if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
(*level == 0 || *level == 17)) {
*level = 17;
i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
}
if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
(*level == 0 || *level == 16)) {
*level = 16;
i->info16.acct_flags = s->change.acct_flags;
s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
}
/* We're going to be here back again soon unless all fields have been set */
if (s->change.fields) {
s->stage = USERMOD_OPEN;
} else {
s->stage = USERMOD_MODIFY;
}
return s->change.fields;
}
static NTSTATUS usermod_change(struct composite_context *c,
struct usermod_state *s)
{
union samr_UserInfo *i = &s->info;
/* set the level to invalid value, so that unless setfields routine
gives it a valid value we report the error correctly */
uint16_t level = 27;
/* prepare UserInfo level and data based on bitmask field */
s->change.fields = usermod_setfields(s, &level, i);
if (level < 1 || level > 26) {
/* apparently there's a field that the setfields routine
does not know how to set */
c->state = COMPOSITE_STATE_ERROR;
return NT_STATUS_INVALID_PARAMETER;
}
/* If some specific level is used to set user account data and the change
itself does not cover all fields then we need to query the user info
first, right before changing the data. Otherwise we could set required
fields and accidentally reset the others.
*/
if (s->stage == USERMOD_QUERY) {
s->queryuser.in.user_handle = &s->user_handle;
s->queryuser.in.level = level;
/* send query user info request to retrieve complete data of
a particular info level */
s->req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuser);
} else {
s->setuser.in.user_handle = &s->user_handle;
s->setuser.in.level = level;
s->setuser.in.info = i;
/* send set user info request after making required change */
s->req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
}
/* callback handler setup */
s->req->async.callback = usermod_handler;
s->req->async.private = c;
return NT_STATUS_OK;
}
/**
* Stage 2: Open user account
*/
static NTSTATUS usermod_open(struct composite_context *c,
struct usermod_state *s)
{
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
return usermod_change(c, s);
}
/**
* Stage 2a (optional): Query the user information
*/
static NTSTATUS usermod_query(struct composite_context *c,
struct usermod_state *s)
{
union samr_UserInfo *i = &s->info;
uint16_t level;
/* receive samr_QueryUserInfo result */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
/* get returned user data and make a change (potentially one
of many) */
s->info = *s->queryuser.out.info;
s->change.fields = usermod_setfields(s, &level, i);
/* prepare rpc call arguments */
s->setuser.in.user_handle = &s->user_handle;
s->setuser.in.level = level;
s->setuser.in.info = i;
/* send the rpc request */
s->req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
/* callback handler setup */
s->req->async.callback = usermod_handler;
s->req->async.private = c;
return NT_STATUS_OK;
}
/**
* Stage 3: Set new user account data
*/
static NTSTATUS usermod_modify(struct composite_context *c,
struct usermod_state *s)
{
/* receive samr_SetUserInfo result */
c->status = dcerpc_ndr_request_recv(s->req);
NT_STATUS_NOT_OK_RETURN(c->status);
NT_STATUS_NOT_OK_RETURN(s->setuser.out.result);
if (s->change.fields == 0) {
/* all fields have been set - we're done */
c->state = COMPOSITE_STATE_DONE;
} else {
/* something's still not changed - repeat the procedure */
return usermod_change(c, s);
}
return NT_STATUS_OK;
}
/**
* Event handler for asynchronous request. Handles transition through
* intermediate stages of the call.
*
* @param req rpc call context
*/
static void usermod_handler(struct rpc_request *req)
{
struct composite_context *c;
struct usermod_state *s;
struct monitor_msg msg;
struct msg_rpc_lookup_name *msg_lookup;
struct msg_rpc_open_user *msg_open;
c = talloc_get_type(req->async.private, struct composite_context);
s = talloc_get_type(c->private_data, struct usermod_state);
switch (s->stage) {
case USERMOD_LOOKUP:
c->status = usermod_lookup(c, s);
if (NT_STATUS_IS_OK(c->status)) {
/* monitor message */
msg.type = rpc_lookup_name;
msg_lookup = talloc(s, struct msg_rpc_lookup_name);
msg_lookup->rid = s->lookupname.out.rids.ids;
msg_lookup->count = s->lookupname.out.rids.count;
msg.data = (void*)msg_lookup;
msg.data_size = sizeof(*msg_lookup);
}
break;
case USERMOD_OPEN:
c->status = usermod_open(c, s);
if (NT_STATUS_IS_OK(c->status)) {
/* monitor message */
msg.type = rpc_open_user;
msg_open = talloc(s, struct msg_rpc_open_user);
msg_open->rid = s->openuser.in.rid;
msg_open->access_mask = s->openuser.in.rid;
msg.data = (void*)msg_open;
msg.data_size = sizeof(*msg_open);
}
break;
case USERMOD_QUERY:
c->status = usermod_query(c, s);
if (NT_STATUS_IS_OK(c->status)) {
/* monitor message */
msg.type = rpc_query_user;
msg.data = NULL;
msg.data_size = 0;
}
break;
case USERMOD_MODIFY:
c->status = usermod_modify(c, s);
if (NT_STATUS_IS_OK(c->status)) {
/* monitor message */
msg.type = rpc_set_user;
msg.data = NULL;
msg.data_size = 0;
}
break;
}
/* are we ok, so far ? */
if (!NT_STATUS_IS_OK(c->status)) {
c->state = COMPOSITE_STATE_ERROR;
}
/* call monitor function provided the pointer has been passed */
if (s->monitor_fn) {
s->monitor_fn(&msg);
}
/* are we done yet ? */
if (c->state >= COMPOSITE_STATE_DONE &&
c->async.fn) {
c->async.fn(c);
}
}
/**
* Sends asynchronous usermod request
*
* @param p dce/rpc call pipe
* @param io arguments and results of the call
* @param monitor monitor function for providing information about the progress
*/
struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
struct libnet_rpc_usermod *io,
void (*monitor)(struct monitor_msg*))
{
struct composite_context *c;
struct usermod_state *s;
/* composite context allocation and setup */
c = talloc_zero(p, struct composite_context);
if (c == NULL) return NULL;
s = talloc_zero(c, struct usermod_state);
if (composite_nomem(s, c)) return c;
c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
c->event_ctx = dcerpc_event_context(p);
/* store parameters in the call structure */
s->pipe = p;
s->domain_handle = io->in.domain_handle;
s->change = io->in.change;
s->monitor_fn = monitor;
/* prepare rpc call arguments */
s->lookupname.in.domain_handle = &io->in.domain_handle;
s->lookupname.in.num_names = 1;
s->lookupname.in.names = talloc_zero(s, struct lsa_String);
s->lookupname.in.names->string = io->in.username;
/* send the rpc request */
s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
/* callback handler setup */
s->req->async.callback = usermod_handler;
s->req->async.private = c;
s->stage = USERMOD_LOOKUP;
return c;
}
/**
* Waits for and receives results of asynchronous usermod call
*
* @param c composite context returned by asynchronous usermod call
* @param mem_ctx memory context of the call
* @param io pointer to results (and arguments) of the call
* @return nt status code of execution
*/
NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
struct libnet_rpc_usermod *io)
{
NTSTATUS status;
status = composite_wait(c);
talloc_free(c);
return status;
}
/**
* Synchronous version of usermod call
*
* @param pipe dce/rpc call pipe
* @param mem_ctx memory context for the call
* @param io arguments and results of the call
* @return nt status code of execution
*/
NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
TALLOC_CTX *mem_ctx,
struct libnet_rpc_usermod *io)
{
struct composite_context *c = libnet_rpc_usermod_send(p, io, NULL);
return libnet_rpc_usermod_recv(c, mem_ctx, io);
}
+105
View File
@@ -0,0 +1,105 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Rafal Szczesniak 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.
*/
/*
* IO structures for userman.c functions
*/
struct libnet_rpc_useradd {
struct {
struct policy_handle domain_handle;
const char *username;
} in;
struct {
struct policy_handle user_handle;
} out;
};
struct libnet_rpc_userdel {
struct {
struct policy_handle domain_handle;
const char *username;
} in;
struct {
struct policy_handle user_handle;
} out;
};
#define USERMOD_FIELD_ACCOUNT_NAME ( 0x00000001 )
#define USERMOD_FIELD_FULL_NAME ( 0x00000002 )
#define USERMOD_FIELD_DESCRIPTION ( 0x00000010 )
#define USERMOD_FIELD_COMMENT ( 0x00000020 )
#define USERMOD_FIELD_HOME_DIRECTORY ( 0x00000040 )
#define USERMOD_FIELD_HOME_DRIVE ( 0x00000080 )
#define USERMOD_FIELD_LOGON_SCRIPT ( 0x00000100 )
#define USERMOD_FIELD_PROFILE_PATH ( 0x00000200 )
#define USERMOD_FIELD_WORKSTATIONS ( 0x00000400 )
#define USERMOD_FIELD_LOGON_HOURS ( 0x00002000 )
#define USERMOD_FIELD_ACCT_EXPIRY ( 0x00004000 )
#define USERMOD_FIELD_ACCT_FLAGS ( 0x00100000 )
#define USERMOD_FIELD_PARAMETERS ( 0x00200000 )
#define USERMOD_FIELD_COUNTRY_CODE ( 0x00400000 )
#define USERMOD_FIELD_CODE_PAGE ( 0x00800000 )
struct libnet_rpc_usermod {
struct {
struct policy_handle domain_handle;
const char *username;
struct usermod_change {
uint32_t fields; /* bitmask field */
const char *account_name;
const char *full_name;
const char *description;
const char *comment;
const char *logon_script;
const char *profile_path;
const char *home_directory;
const char *home_drive;
const char *workstations;
struct timeval *acct_expiry;
struct timeval *allow_password_change;
struct timeval *force_password_change;
struct timeval *last_logon;
struct timeval *last_logoff;
struct timeval *last_password_change;
uint32_t acct_flags;
} change;
} in;
};
/*
* Monitor messages sent from userman.c functions
*/
struct msg_rpc_create_user {
uint32_t rid;
};
struct msg_rpc_lookup_name {
uint32_t *rid;
uint32_t count;
};