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
+64
View File
@@ -0,0 +1,64 @@
/*
Unix SMB/CIFS implementation.
common macros for the dcerpc server interfaces
Copyright (C) Stefan (metze) Metzmacher 2004
Copyright (C) Andrew Tridgell 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.
*/
/* a useful macro for generating a RPC fault in the backend code */
#define DCESRV_FAULT(code) do { \
dce_call->fault_code = code; \
return r->out.result; \
} while(0)
/* a useful macro for generating a RPC fault in the backend code */
#define DCESRV_FAULT_VOID(code) do { \
dce_call->fault_code = code; \
return; \
} while(0)
/* a useful macro for checking the validity of a dcerpc policy handle
and giving the right fault code if invalid */
#define DCESRV_CHECK_HANDLE(h) do {if (!(h)) DCESRV_FAULT(DCERPC_FAULT_CONTEXT_MISMATCH); } while (0)
/* this checks for a valid policy handle, and gives a fault if an
invalid handle or retval if the handle is of the
wrong type */
#define DCESRV_PULL_HANDLE_RETVAL(h, inhandle, t, retval) do { \
(h) = dcesrv_handle_fetch(dce_call->context, (inhandle), DCESRV_HANDLE_ANY); \
DCESRV_CHECK_HANDLE(h); \
if ((t) != DCESRV_HANDLE_ANY && (h)->wire_handle.handle_type != (t)) { \
return retval; \
} \
} while (0)
/* this checks for a valid policy handle and gives a dcerpc fault
if its the wrong type of handle */
#define DCESRV_PULL_HANDLE_FAULT(h, inhandle, t) do { \
(h) = dcesrv_handle_fetch(dce_call->context, (inhandle), t); \
DCESRV_CHECK_HANDLE(h); \
} while (0)
#define DCESRV_PULL_HANDLE(h, inhandle, t) DCESRV_PULL_HANDLE_RETVAL(h, inhandle, t, NT_STATUS_INVALID_HANDLE)
#define DCESRV_PULL_HANDLE_WERR(h, inhandle, t) DCESRV_PULL_HANDLE_RETVAL(h, inhandle, t, WERR_BADFID)
struct dcesrv_context;
#include "param/share.h"
#include "rpc_server/common/proto.h"
@@ -0,0 +1,144 @@
/*
Unix SMB/CIFS implementation.
common server info functions
Copyright (C) Stefan (metze) 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 "librpc/gen_ndr/ndr_srvsvc.h"
#include "rpc_server/dcerpc_server.h"
/*
Here are common server info functions used by some dcerpc server interfaces
*/
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ enum srvsvc_PlatformId dcesrv_common_get_platform_id(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
enum srvsvc_PlatformId id;
id = lp_parm_int(-1, "server_info", "platform_id", PLATFORM_ID_NT);
return id;
}
_PUBLIC_ const char *dcesrv_common_get_server_name(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, const char *server_unc)
{
const char *p = server_unc;
/* if there's no string return our NETBIOS name */
if (!p) {
return talloc_strdup(mem_ctx, lp_netbios_name());
}
/* if there're '\\\\' in front remove them otherwise just pass the string */
if (p[0] == '\\' && p[1] == '\\') {
p += 2;
}
return talloc_strdup(mem_ctx, p);
}
const char *dcesrv_common_get_domain_name(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return talloc_strdup(mem_ctx, lp_workgroup());
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_version_major(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return lp_parm_int(-1, "server_info", "version_major", 5);
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_version_minor(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return lp_parm_int(-1, "server_info", "version_minor", 2);
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_version_build(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return lp_parm_int(-1, "server_info", "version_build", 3790);
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_server_type(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return lp_default_server_announce();
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ const char *dcesrv_common_get_lan_root(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return talloc_strdup(mem_ctx, "");
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_users(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return -1;
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_disc(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return 15;
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_hidden(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return 0;
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_announce(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return 240;
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_anndelta(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return 3000;
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ uint32_t dcesrv_common_get_licenses(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return 0;
}
/* This hardcoded value should go into a ldb database! */
_PUBLIC_ const char *dcesrv_common_get_userpath(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx)
{
return talloc_strdup(mem_ctx, "c:\\");
}
#define INVALID_SHARE_NAME_CHARS " \"*+,./:;<=>?[\\]|"
_PUBLIC_ bool dcesrv_common_validate_share_name(TALLOC_CTX *mem_ctx, const char *share_name)
{
if (strpbrk(share_name, INVALID_SHARE_NAME_CHARS)) {
return False;
}
return True;
}
+118
View File
@@ -0,0 +1,118 @@
/*
Unix SMB/CIFS implementation.
common share info functions
Copyright (C) Stefan (metze) 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 "param/share.h"
#include "librpc/gen_ndr/srvsvc.h"
#include "rpc_server/dcerpc_server.h"
/*
Here are common server info functions used by some dcerpc server interfaces
*/
/* This hardcoded value should go into a ldb database! */
uint32_t dcesrv_common_get_share_permissions(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg)
{
return 0;
}
/* This hardcoded value should go into a ldb database! */
uint32_t dcesrv_common_get_share_current_users(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg)
{
return 1;
}
/* This hardcoded value should go into a ldb database! */
enum srvsvc_ShareType dcesrv_common_get_share_type(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg)
{
/* for disk share 0x00000000
* for print share 0x00000001
* for IPC$ share 0x00000003
*
* administrative shares:
* ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000
* this ones are hidden in NetShareEnum, but shown in NetShareEnumAll
*/
enum srvsvc_ShareType share_type = 0;
const char *sharetype;
if (!share_bool_option(scfg, SHARE_BROWSEABLE, SHARE_BROWSEABLE_DEFAULT)) {
share_type |= STYPE_HIDDEN;
}
sharetype = share_string_option(scfg, SHARE_TYPE, SHARE_TYPE_DEFAULT);
if (sharetype && strcasecmp(sharetype, "IPC") == 0) {
share_type |= STYPE_IPC;
return share_type;
}
if (sharetype && strcasecmp(sharetype, "PRINTER") == 0) {
share_type |= STYPE_PRINTQ;
return share_type;
}
share_type |= STYPE_DISKTREE;
return share_type;
}
/* This hardcoded value should go into a ldb database! */
const char *dcesrv_common_get_share_path(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg)
{
const char *sharetype;
char *p;
sharetype = share_string_option(scfg, SHARE_TYPE, SHARE_TYPE_DEFAULT);
if (sharetype && strcasecmp(sharetype, "IPC") == 0) {
return talloc_strdup(mem_ctx, "");
}
p = talloc_strdup(mem_ctx, share_string_option(scfg, SHARE_PATH, ""));
if (!p) {
return NULL;
}
if (p[0] == '\0') {
return p;
}
all_string_sub(p, "/", "\\", 0);
return talloc_asprintf(mem_ctx, "C:%s", p);
}
/* This hardcoded value should go into a ldb database! */
uint32_t dcesrv_common_get_share_dfs_flags(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg)
{
return 0;
}
/* This hardcoded value should go into a ldb database! */
uint32_t dcesrv_common_get_share_unknown(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg)
{
return 0;
}
/* This hardcoded value should go into a ldb database! */
struct security_descriptor *dcesrv_common_get_security_descriptor(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg)
{
return NULL;
}
+196
View File
@@ -0,0 +1,196 @@
# DCERPC Server subsystem
################################################
# Start SUBSYSTEM DCERPC_COMMON
[SUBSYSTEM::DCERPC_COMMON]
PUBLIC_PROTO_HEADER = common/proto.h
PUBLIC_HEADERS = common/common.h
OBJ_FILES = \
common/server_info.o \
common/share_info.o
#
# End SUBSYSTEM DCERPC_COMMON
################################################
################################################
# Start MODULE dcerpc_rpcecho
[MODULE::dcerpc_rpcecho]
INIT_FUNCTION = dcerpc_server_rpcecho_init
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
echo/rpc_echo.o
PUBLIC_DEPENDENCIES = NDR_ECHO
# End MODULE dcerpc_rpcecho
################################################
################################################
# Start MODULE dcerpc_epmapper
[MODULE::dcerpc_epmapper]
INIT_FUNCTION = dcerpc_server_epmapper_init
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
epmapper/rpc_epmapper.o
PUBLIC_DEPENDENCIES = NDR_EPMAPPER
# End MODULE dcerpc_epmapper
################################################
################################################
# Start MODULE dcerpc_remote
[MODULE::dcerpc_remote]
INIT_FUNCTION = dcerpc_server_remote_init
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
remote/dcesrv_remote.o
PUBLIC_DEPENDENCIES = \
LIBCLI_SMB NDR_TABLE
# End MODULE dcerpc_remote
################################################
################################################
# Start MODULE dcerpc_srvsvc
[MODULE::dcerpc_srvsvc]
INIT_FUNCTION = dcerpc_server_srvsvc_init
PRIVATE_PROTO_HEADER = srvsvc/proto.h
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
srvsvc/dcesrv_srvsvc.o \
srvsvc/srvsvc_ntvfs.o
PUBLIC_DEPENDENCIES = \
DCERPC_COMMON NDR_SRVSVC share
# End MODULE dcerpc_srvsvc
################################################
################################################
# Start MODULE dcerpc_wkssvc
[MODULE::dcerpc_wkssvc]
INIT_FUNCTION = dcerpc_server_wkssvc_init
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
wkssvc/dcesrv_wkssvc.o
PUBLIC_DEPENDENCIES = \
DCERPC_COMMON NDR_WKSSVC
# End MODULE dcerpc_wkssvc
################################################
################################################
# Start MODULE dcerpc_unixinfo
[MODULE::dcerpc_unixinfo]
INIT_FUNCTION = dcerpc_server_unixinfo_init
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
unixinfo/dcesrv_unixinfo.o
PUBLIC_DEPENDENCIES = \
DCERPC_COMMON \
SAMDB \
NDR_UNIXINFO
# End MODULE dcerpc_unixinfo
################################################
################################################
# Start MODULE dcerpc_samr
[MODULE::dcerpc_samr]
INIT_FUNCTION = dcerpc_server_samr_init
PRIVATE_PROTO_HEADER = samr/proto.h
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
samr/dcesrv_samr.o \
samr/samr_password.o
PUBLIC_DEPENDENCIES = \
SAMDB \
DCERPC_COMMON \
NDR_SAMR
# End MODULE dcerpc_samr
################################################
################################################
# Start MODULE dcerpc_winreg
[MODULE::dcerpc_winreg]
INIT_FUNCTION = dcerpc_server_winreg_init
SUBSYSTEM = dcerpc_server
OUTPUT_TYPE = INTEGRATED
OBJ_FILES = \
winreg/rpc_winreg.o
PUBLIC_DEPENDENCIES = \
registry NDR_WINREG
# End MODULE dcerpc_winreg
################################################
################################################
# Start MODULE dcerpc_netlogon
[MODULE::dcerpc_netlogon]
INIT_FUNCTION = dcerpc_server_netlogon_init
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
netlogon/dcerpc_netlogon.o
PUBLIC_DEPENDENCIES = \
DCERPC_COMMON \
SCHANNELDB \
NDR_NETLOGON \
auth_sam
# End MODULE dcerpc_netlogon
################################################
################################################
# Start MODULE dcerpc_lsa
[MODULE::dcerpc_lsarpc]
INIT_FUNCTION = dcerpc_server_lsa_init
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
lsa/dcesrv_lsa.o
PUBLIC_DEPENDENCIES = \
SAMDB \
DCERPC_COMMON \
NDR_LSA \
LIBCLI_AUTH \
NDR_DSSETUP
# End MODULE dcerpc_lsa
################################################
################################################
# Start MODULE dcerpc_spoolss
[MODULE::dcerpc_spoolss]
INIT_FUNCTION = dcerpc_server_spoolss_init
SUBSYSTEM = dcerpc_server
OUTPUT_TYPE = INTEGRATED
OBJ_FILES = \
spoolss/dcesrv_spoolss.o
PUBLIC_DEPENDENCIES = \
DCERPC_COMMON \
NDR_SPOOLSS \
ntptr
# End MODULE dcerpc_spoolss
################################################
################################################
# Start MODULE dcerpc_drsuapi
[MODULE::dcerpc_drsuapi]
INIT_FUNCTION = dcerpc_server_drsuapi_init
SUBSYSTEM = dcerpc_server
OBJ_FILES = \
drsuapi/dcesrv_drsuapi.o
PUBLIC_DEPENDENCIES = \
SAMDB \
DCERPC_COMMON \
NDR_DRSUAPI
# End MODULE dcerpc_drsuapi
################################################
################################################
# Start SUBSYSTEM dcerpc_server
[MODULE::dcerpc_server]
INIT_FUNCTION = server_service_rpc_init
SUBSYSTEM = service
PUBLIC_HEADERS = dcerpc_server.h
PUBLIC_PROTO_HEADER = dcerpc_server_proto.h
OBJ_FILES = \
dcerpc_server.o \
dcerpc_sock.o \
dcesrv_auth.o \
handles.o
PUBLIC_DEPENDENCIES = \
LIBCLI_AUTH \
LIBNDR \
dcerpc
#
# End SUBSYSTEM DCERPC
################################################
File diff suppressed because it is too large Load Diff
+274
View File
@@ -0,0 +1,274 @@
/*
Unix SMB/CIFS implementation.
server side dcerpc defines
Copyright (C) Andrew Tridgell 2003-2005
Copyright (C) Stefan (metze) Metzmacher 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.
*/
#ifndef SAMBA_DCERPC_SERVER_H
#define SAMBA_DCERPC_SERVER_H
#include "core.h"
#include "librpc/gen_ndr/misc.h"
#include "librpc/rpc/dcerpc.h"
#include "librpc/ndr/libndr.h"
/* modules can use the following to determine if the interface has changed
* please increment the version number after each interface change
* with a comment and maybe update struct dcesrv_critical_sizes.
*/
/* version 1 - initial version - metze */
#define DCERPC_MODULE_VERSION 1
struct dcesrv_connection;
struct dcesrv_call_state;
struct dcesrv_auth;
struct dcesrv_connection_context;
struct dcesrv_interface {
const char *name;
struct dcerpc_syntax_id syntax_id;
/* this function is called when the client binds to this interface */
NTSTATUS (*bind)(struct dcesrv_call_state *, const struct dcesrv_interface *);
/* this function is called when the client disconnects the endpoint */
void (*unbind)(struct dcesrv_connection_context *, const struct dcesrv_interface *);
/* the ndr_pull function for the chosen interface.
*/
NTSTATUS (*ndr_pull)(struct dcesrv_call_state *, TALLOC_CTX *, struct ndr_pull *, void **);
/* the dispatch function for the chosen interface.
*/
NTSTATUS (*dispatch)(struct dcesrv_call_state *, TALLOC_CTX *, void *);
/* the reply function for the chosen interface.
*/
NTSTATUS (*reply)(struct dcesrv_call_state *, TALLOC_CTX *, void *);
/* the ndr_push function for the chosen interface.
*/
NTSTATUS (*ndr_push)(struct dcesrv_call_state *, TALLOC_CTX *, struct ndr_push *, const void *);
/* for any private use by the interface code */
const void *private;
};
/* the state of an ongoing dcerpc call */
struct dcesrv_call_state {
struct dcesrv_call_state *next, *prev;
struct dcesrv_connection *conn;
struct dcesrv_connection_context *context;
struct ncacn_packet pkt;
/* the backend can mark the call
* with DCESRV_CALL_STATE_FLAG_ASYNC
* that will cause the frontend to not touch r->out
* and skip the reply
*
* this is only allowed to the backend when DCESRV_CALL_STATE_FLAG_MAY_ASYNC
* is alerady set by the frontend
*
* the backend then needs to call dcesrv_reply() when it's
* ready to send the reply
*/
#define DCESRV_CALL_STATE_FLAG_ASYNC (1<<0)
#define DCESRV_CALL_STATE_FLAG_MAY_ASYNC (1<<1)
uint32_t state_flags;
/* the time the request arrived in the server */
struct timeval time;
/* the backend can use this event context for async replies */
struct event_context *event_ctx;
/* the message_context that will be used for async replies */
struct messaging_context *msg_ctx;
/* this is the pointer to the allocated function struct */
void *r;
/*
* that's the ndr pull context used in dcesrv_request()
* needed by dcesrv_reply() to carry over information
* for full pointer support.
*/
struct ndr_pull *ndr_pull;
DATA_BLOB input;
struct data_blob_list_item *replies;
/* this is used by the boilerplate code to generate DCERPC faults */
uint32_t fault_code;
};
#define DCESRV_HANDLE_ANY 255
/* a dcerpc handle in internal format */
struct dcesrv_handle {
struct dcesrv_handle *next, *prev;
struct dcesrv_connection_context *context;
struct policy_handle wire_handle;
void *data;
};
/* hold the authentication state information */
struct dcesrv_auth {
struct dcerpc_auth *auth_info;
struct gensec_security *gensec_security;
struct auth_session_info *session_info;
NTSTATUS (*session_key)(struct dcesrv_connection *, DATA_BLOB *session_key);
};
struct dcesrv_connection_context {
struct dcesrv_connection_context *next, *prev;
uint32_t context_id;
/* the connection this is on */
struct dcesrv_connection *conn;
/* the ndr function table for the chosen interface */
const struct dcesrv_interface *iface;
/* private data for the interface implementation */
void *private;
/* current rpc handles - this is really the wrong scope for
them, but it will do for now */
struct dcesrv_handle *handles;
};
/* the state associated with a dcerpc server connection */
struct dcesrv_connection {
/* the top level context for this server */
struct dcesrv_context *dce_ctx;
/* the endpoint that was opened */
const struct dcesrv_endpoint *endpoint;
/* a list of established context_ids */
struct dcesrv_connection_context *contexts;
/* the state of the current incoming call fragments */
struct dcesrv_call_state *incoming_fragmented_call_list;
/* the state of the async pending calls */
struct dcesrv_call_state *pending_call_list;
/* the state of the current outgoing calls */
struct dcesrv_call_state *call_list;
/* the maximum size the client wants to receive */
uint32_t cli_max_recv_frag;
DATA_BLOB partial_input;
/* the current authentication state */
struct dcesrv_auth auth_state;
/* the event_context that will be used for this connection */
struct event_context *event_ctx;
/* the message_context that will be used for this connection */
struct messaging_context *msg_ctx;
/* the server_id that will be used for this connection */
uint32_t server_id;
/* the transport level session key */
DATA_BLOB transport_session_key;
BOOL processing;
/* this is the default state_flags for dcesrv_call_state structs */
uint32_t state_flags;
struct {
void *private_data;
void (*report_output_data)(struct dcesrv_connection *);
struct socket_address *(*get_my_addr)(struct dcesrv_connection *, TALLOC_CTX *mem_ctx);
struct socket_address *(*get_peer_addr)(struct dcesrv_connection *, TALLOC_CTX *mem_ctx);
} transport;
};
struct dcesrv_endpoint_server {
/* this is the name of the endpoint server */
const char *name;
/* this function should register endpoints and some other setup stuff,
* it is called when the dcesrv_context gets initialized.
*/
NTSTATUS (*init_server)(struct dcesrv_context *, const struct dcesrv_endpoint_server *);
/* this function can be used by other endpoint servers to
* ask for a dcesrv_interface implementation
* - iface must be reference to an already existing struct !
*/
BOOL (*interface_by_uuid)(struct dcesrv_interface *iface, const struct GUID *, uint32_t);
/* this function can be used by other endpoint servers to
* ask for a dcesrv_interface implementation
* - iface must be reference to an already existeng struct !
*/
BOOL (*interface_by_name)(struct dcesrv_interface *iface, const char *);
};
/* server-wide context information for the dcerpc server */
struct dcesrv_context {
/* the list of endpoints that have registered
* by the configured endpoint servers
*/
struct dcesrv_endpoint {
struct dcesrv_endpoint *next, *prev;
/* the type and location of the endpoint */
struct dcerpc_binding *ep_description;
/* the security descriptor for smb named pipes */
struct security_descriptor *sd;
/* the list of interfaces available on this endpoint */
struct dcesrv_if_list {
struct dcesrv_if_list *next, *prev;
struct dcesrv_interface iface;
} *interface_list;
} *endpoint_list;
};
/* this structure is used by modules to determine the size of some critical types */
struct dcesrv_critical_sizes {
int interface_version;
int sizeof_dcesrv_context;
int sizeof_dcesrv_endpoint;
int sizeof_dcesrv_endpoint_server;
int sizeof_dcesrv_interface;
int sizeof_dcesrv_if_list;
int sizeof_dcesrv_connection;
int sizeof_dcesrv_call_state;
int sizeof_dcesrv_auth;
int sizeof_dcesrv_handle;
};
struct model_ops;
#include "rpc_server/dcerpc_server_proto.h"
#endif /* SAMBA_DCERPC_SERVER_H */
+328
View File
@@ -0,0 +1,328 @@
/*
Unix SMB/CIFS implementation.
server side dcerpc using various kinds of sockets (tcp, unix domain)
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) Metzmacher 2004-2005
Copyright (C) Jelmer Vernooij 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 "lib/socket/socket.h"
#include "lib/events/events.h"
#include "rpc_server/dcerpc_server.h"
#include "smbd/service_stream.h"
#include "smbd/service.h"
#include "lib/messaging/irpc.h"
#include "system/network.h"
#include "lib/socket/netif.h"
#include "auth/auth.h"
struct dcesrv_socket_context {
const struct dcesrv_endpoint *endpoint;
struct dcesrv_context *dcesrv_ctx;
};
/*
write_fn callback for dcesrv_output()
*/
static NTSTATUS dcerpc_write_fn(void *private_data, DATA_BLOB *out, size_t *nwritten)
{
NTSTATUS status;
struct socket_context *sock = talloc_get_type(private_data, struct socket_context);
size_t sendlen;
status = socket_send(sock, out, &sendlen);
NT_STATUS_IS_ERR_RETURN(status);
*nwritten = sendlen;
return status;
}
static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
{
struct stream_connection *srv_conn;
srv_conn = talloc_get_type(dce_conn->transport.private_data,
struct stream_connection);
stream_terminate_connection(srv_conn, reason);
}
static void dcesrv_sock_report_output_data(struct dcesrv_connection *dcesrv_conn)
{
struct stream_connection *srv_conn;
srv_conn = talloc_get_type(dcesrv_conn->transport.private_data,
struct stream_connection);
if (srv_conn && srv_conn->event.fde) {
EVENT_FD_WRITEABLE(srv_conn->event.fde);
}
}
static struct socket_address *dcesrv_sock_get_my_addr(struct dcesrv_connection *dcesrv_conn, TALLOC_CTX *mem_ctx)
{
struct stream_connection *srv_conn;
srv_conn = talloc_get_type(dcesrv_conn->transport.private_data,
struct stream_connection);
return socket_get_my_addr(srv_conn->socket, mem_ctx);
}
static struct socket_address *dcesrv_sock_get_peer_addr(struct dcesrv_connection *dcesrv_conn, TALLOC_CTX *mem_ctx)
{
struct stream_connection *srv_conn;
srv_conn = talloc_get_type(dcesrv_conn->transport.private_data,
struct stream_connection);
return socket_get_peer_addr(srv_conn->socket, mem_ctx);
}
static void dcesrv_sock_accept(struct stream_connection *srv_conn)
{
NTSTATUS status;
struct dcesrv_socket_context *dcesrv_sock =
talloc_get_type(srv_conn->private, struct dcesrv_socket_context);
struct dcesrv_connection *dcesrv_conn = NULL;
struct auth_session_info *session_info = NULL;
status = auth_anonymous_session_info(srv_conn, &session_info);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
nt_errstr(status)));
stream_terminate_connection(srv_conn, nt_errstr(status));
return;
}
status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
srv_conn,
dcesrv_sock->endpoint,
session_info,
srv_conn->event.ctx,
srv_conn->msg_ctx,
srv_conn->server_id,
DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
&dcesrv_conn);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
nt_errstr(status)));
stream_terminate_connection(srv_conn, nt_errstr(status));
return;
}
dcesrv_conn->transport.private_data = srv_conn;
dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
dcesrv_conn->transport.get_my_addr = dcesrv_sock_get_my_addr;
dcesrv_conn->transport.get_peer_addr = dcesrv_sock_get_peer_addr;
srv_conn->private = dcesrv_conn;
irpc_add_name(srv_conn->msg_ctx, "rpc_server");
return;
}
static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
{
NTSTATUS status;
struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection);
DATA_BLOB tmp_blob;
size_t nread;
if (dce_conn->processing) {
EVENT_FD_NOT_READABLE(conn->event.fde);
return;
}
tmp_blob = data_blob_talloc(conn->socket, NULL, 0x1000);
if (tmp_blob.data == NULL) {
dcesrv_terminate_connection(dce_conn, "out of memory");
return;
}
status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread);
if (NT_STATUS_IS_ERR(status)) {
dcesrv_terminate_connection(dce_conn, nt_errstr(status));
return;
}
if (nread == 0) {
talloc_free(tmp_blob.data);
return;
}
tmp_blob.length = nread;
dce_conn->processing = True;
status = dcesrv_input(dce_conn, &tmp_blob);
dce_conn->processing = False;
talloc_free(tmp_blob.data);
EVENT_FD_READABLE(conn->event.fde);
if (!NT_STATUS_IS_OK(status)) {
dcesrv_terminate_connection(dce_conn, nt_errstr(status));
return;
}
if (dce_conn->call_list && dce_conn->call_list->replies) {
EVENT_FD_WRITEABLE(conn->event.fde);
}
}
static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
{
struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection);
NTSTATUS status;
status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn);
if (NT_STATUS_IS_ERR(status)) {
dcesrv_terminate_connection(dce_conn, "eof on socket");
return;
}
if (!dce_conn->call_list || !dce_conn->call_list->replies) {
EVENT_FD_NOT_WRITEABLE(conn->event.fde);
}
}
static const struct stream_server_ops dcesrv_stream_ops = {
.name = "rpc",
.accept_connection = dcesrv_sock_accept,
.recv_handler = dcesrv_sock_recv,
.send_handler = dcesrv_sock_send,
};
NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
struct event_context *event_ctx, const struct model_ops *model_ops)
{
struct dcesrv_socket_context *dcesrv_sock;
uint16_t port = 1;
NTSTATUS status;
dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
/* remember the endpoint of this socket */
dcesrv_sock->endpoint = e;
dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops,
"unix", e->ep_description->endpoint, &port,
dcesrv_sock);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
e->ep_description->endpoint, nt_errstr(status)));
}
return status;
}
NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
struct event_context *event_ctx, const struct model_ops *model_ops)
{
struct dcesrv_socket_context *dcesrv_sock;
uint16_t port = 1;
char *full_path;
NTSTATUS status;
if (!e->ep_description->endpoint) {
/* No identifier specified: use DEFAULT.
* DO NOT hardcode this value anywhere else. Rather, specify
* no endpoint and let the epmapper worry about it. */
e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
}
full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description->endpoint);
dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
/* remember the endpoint of this socket */
dcesrv_sock->endpoint = e;
dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops,
"unix", full_path, &port, dcesrv_sock);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
e->ep_description->endpoint, full_path, nt_errstr(status)));
}
return status;
}
/*
add a socket address to the list of events, one event per dcerpc endpoint
*/
static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
struct event_context *event_ctx, const struct model_ops *model_ops,
const char *address)
{
struct dcesrv_socket_context *dcesrv_sock;
uint16_t port = 0;
NTSTATUS status;
if (e->ep_description->endpoint) {
port = atoi(e->ep_description->endpoint);
}
dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
/* remember the endpoint of this socket */
dcesrv_sock->endpoint = e;
dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops,
"ipv4", address, &port, dcesrv_sock);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
address, port, nt_errstr(status)));
}
if (e->ep_description->endpoint == NULL) {
e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
}
return status;
}
NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
struct event_context *event_ctx, const struct model_ops *model_ops)
{
NTSTATUS status;
/* Add TCP/IP sockets */
if (lp_interfaces() && lp_bind_interfaces_only()) {
int num_interfaces = iface_count();
int i;
for(i = 0; i < num_interfaces; i++) {
const char *address = iface_n_ip(i);
status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
NT_STATUS_NOT_OK_RETURN(status);
}
} else {
status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, lp_socket_address());
NT_STATUS_NOT_OK_RETURN(status);
}
return NT_STATUS_OK;
}
+520
View File
@@ -0,0 +1,520 @@
/*
Unix SMB/CIFS implementation.
server side dcerpc authentication code
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) 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 "rpc_server/dcerpc_server.h"
#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "auth/credentials/credentials.h"
#include "auth/gensec/gensec.h"
/*
parse any auth information from a dcerpc bind request
return False if we can't handle the auth request for some
reason (in which case we send a bind_nak)
*/
BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
{
struct cli_credentials *server_credentials;
struct ncacn_packet *pkt = &call->pkt;
struct dcesrv_connection *dce_conn = call->conn;
struct dcesrv_auth *auth = &dce_conn->auth_state;
NTSTATUS status;
if (pkt->u.bind.auth_info.length == 0) {
dce_conn->auth_state.auth_info = NULL;
return True;
}
dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
if (!dce_conn->auth_state.auth_info) {
return False;
}
status = ndr_pull_struct_blob(&pkt->u.bind.auth_info,
call,
dce_conn->auth_state.auth_info,
(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
status = gensec_server_start(dce_conn, call->event_ctx, call->msg_ctx, &auth->gensec_security);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to start GENSEC for DCERPC server: %s\n", nt_errstr(status)));
return False;
}
server_credentials
= cli_credentials_init(call);
if (!server_credentials) {
DEBUG(1, ("Failed to init server credentials\n"));
return False;
}
cli_credentials_set_conf(server_credentials);
status = cli_credentials_set_machine_account(server_credentials);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
talloc_free(server_credentials);
server_credentials = NULL;
}
gensec_set_credentials(auth->gensec_security, server_credentials);
status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type,
auth->auth_info->auth_level);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to start GENSEC mechanism for DCERPC server: auth_type=%d, auth_level=%d: %s\n",
(int)auth->auth_info->auth_type,
(int)auth->auth_info->auth_level,
nt_errstr(status)));
return False;
}
return True;
}
/*
add any auth information needed in a bind ack, and process the authentication
information found in the bind.
*/
BOOL dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
{
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
if (!call->conn->auth_state.gensec_security) {
return True;
}
status = gensec_update(dce_conn->auth_state.gensec_security,
call,
dce_conn->auth_state.auth_info->credentials,
&dce_conn->auth_state.auth_info->credentials);
if (NT_STATUS_IS_OK(status)) {
status = gensec_session_info(dce_conn->auth_state.gensec_security,
&dce_conn->auth_state.session_info);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
return False;
}
/* Now that we are authenticated, go back to the generic session key... */
dce_conn->auth_state.session_key = dcesrv_generic_session_key;
return True;
} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
dce_conn->auth_state.auth_info->auth_pad_length = 0;
dce_conn->auth_state.auth_info->auth_reserved = 0;
return True;
} else {
DEBUG(2, ("Failed to start dcesrv auth negotiate: %s\n", nt_errstr(status)));
return False;
}
}
/*
process the final stage of a auth request
*/
BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
{
struct ncacn_packet *pkt = &call->pkt;
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
/* We can't work without an existing gensec state, and an new blob to feed it */
if (!dce_conn->auth_state.auth_info ||
!dce_conn->auth_state.gensec_security ||
pkt->u.auth3.auth_info.length == 0) {
return False;
}
status = ndr_pull_struct_blob(&pkt->u.auth3.auth_info,
call,
dce_conn->auth_state.auth_info,
(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
/* Pass the extra data we got from the client down to gensec for processing */
status = gensec_update(dce_conn->auth_state.gensec_security,
call,
dce_conn->auth_state.auth_info->credentials,
&dce_conn->auth_state.auth_info->credentials);
if (NT_STATUS_IS_OK(status)) {
status = gensec_session_info(dce_conn->auth_state.gensec_security,
&dce_conn->auth_state.session_info);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
return False;
}
/* Now that we are authenticated, go back to the generic session key... */
dce_conn->auth_state.session_key = dcesrv_generic_session_key;
return True;
} else {
DEBUG(4, ("dcesrv_auth_auth3: failed to authenticate: %s\n",
nt_errstr(status)));
return False;
}
return True;
}
/*
parse any auth information from a dcerpc alter request
return False if we can't handle the auth request for some
reason (in which case we send a bind_nak (is this true for here?))
*/
BOOL dcesrv_auth_alter(struct dcesrv_call_state *call)
{
struct ncacn_packet *pkt = &call->pkt;
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
/* on a pure interface change there is no auth blob */
if (pkt->u.alter.auth_info.length == 0) {
return True;
}
/* We can't work without an existing gensec state */
if (!dce_conn->auth_state.gensec_security) {
return False;
}
dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
if (!dce_conn->auth_state.auth_info) {
return False;
}
status = ndr_pull_struct_blob(&pkt->u.alter.auth_info,
call,
dce_conn->auth_state.auth_info,
(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
return True;
}
/*
add any auth information needed in a alter ack, and process the authentication
information found in the alter.
*/
BOOL dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
{
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
/* on a pure interface change there is no auth_info structure
setup */
if (!call->conn->auth_state.auth_info ||
dce_conn->auth_state.auth_info->credentials.length == 0) {
return True;
}
if (!call->conn->auth_state.gensec_security) {
return False;
}
status = gensec_update(dce_conn->auth_state.gensec_security,
call,
dce_conn->auth_state.auth_info->credentials,
&dce_conn->auth_state.auth_info->credentials);
if (NT_STATUS_IS_OK(status)) {
status = gensec_session_info(dce_conn->auth_state.gensec_security,
&dce_conn->auth_state.session_info);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
return False;
}
/* Now that we are authenticated, got back to the generic session key... */
dce_conn->auth_state.session_key = dcesrv_generic_session_key;
return True;
} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
dce_conn->auth_state.auth_info->auth_pad_length = 0;
dce_conn->auth_state.auth_info->auth_reserved = 0;
return True;
}
DEBUG(2, ("Failed to finish dcesrv auth alter_ack: %s\n", nt_errstr(status)));
return False;
}
/*
generate a CONNECT level verifier
*/
static NTSTATUS dcesrv_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
{
*blob = data_blob_talloc(mem_ctx, NULL, 16);
if (blob->data == NULL) {
return NT_STATUS_NO_MEMORY;
}
SIVAL(blob->data, 0, 1);
memset(blob->data+4, 0, 12);
return NT_STATUS_OK;
}
/*
generate a CONNECT level verifier
*/
static NTSTATUS dcesrv_check_connect_verifier(DATA_BLOB *blob)
{
if (blob->length != 16 ||
IVAL(blob->data, 0) != 1) {
return NT_STATUS_ACCESS_DENIED;
}
return NT_STATUS_OK;
}
/*
check credentials on a request
*/
BOOL dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
{
struct ncacn_packet *pkt = &call->pkt;
struct dcesrv_connection *dce_conn = call->conn;
DATA_BLOB auth_blob;
struct dcerpc_auth auth;
struct ndr_pull *ndr;
NTSTATUS status;
if (!dce_conn->auth_state.auth_info ||
!dce_conn->auth_state.gensec_security) {
return True;
}
auth_blob.length = 8 + pkt->auth_length;
/* check for a valid length */
if (pkt->u.request.stub_and_verifier.length < auth_blob.length) {
return False;
}
auth_blob.data =
pkt->u.request.stub_and_verifier.data +
pkt->u.request.stub_and_verifier.length - auth_blob.length;
pkt->u.request.stub_and_verifier.length -= auth_blob.length;
/* pull the auth structure */
ndr = ndr_pull_init_blob(&auth_blob, call);
if (!ndr) {
return False;
}
if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
}
status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(ndr);
return False;
}
/* check signature or unseal the packet */
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
call,
full_packet->data + DCERPC_REQUEST_LENGTH,
pkt->u.request.stub_and_verifier.length,
full_packet->data,
full_packet->length-auth.credentials.length,
&auth.credentials);
memcpy(pkt->u.request.stub_and_verifier.data,
full_packet->data + DCERPC_REQUEST_LENGTH,
pkt->u.request.stub_and_verifier.length);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
status = gensec_check_packet(dce_conn->auth_state.gensec_security,
call,
pkt->u.request.stub_and_verifier.data,
pkt->u.request.stub_and_verifier.length,
full_packet->data,
full_packet->length-auth.credentials.length,
&auth.credentials);
break;
case DCERPC_AUTH_LEVEL_CONNECT:
status = dcesrv_check_connect_verifier(&auth.credentials);
break;
default:
status = NT_STATUS_INVALID_LEVEL;
break;
}
/* remove the indicated amount of padding */
if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
talloc_free(ndr);
return False;
}
pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
talloc_free(ndr);
return NT_STATUS_IS_OK(status);
}
/*
push a signed or sealed dcerpc request packet into a blob
*/
BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
DATA_BLOB *blob, struct ncacn_packet *pkt)
{
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
struct ndr_push *ndr;
uint32_t payload_length;
DATA_BLOB creds2;
/* non-signed packets are simple */
if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) {
status = ncacn_push_auth(blob, call, pkt, NULL);
return NT_STATUS_IS_OK(status);
}
ndr = ndr_push_init_ctx(call);
if (!ndr) {
return False;
}
if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
}
status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
/* pad to 16 byte multiple, match win2k3 */
dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 16);
ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
payload_length = ndr->offset - DCERPC_REQUEST_LENGTH;
if (dce_conn->auth_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
status = dcesrv_connect_verifier(call,
&dce_conn->auth_state.auth_info->credentials);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
} else {
/* We hope this length is accruate. If must be if the
* GENSEC mech does AEAD signing of the packet
* headers */
dce_conn->auth_state.auth_info->credentials
= data_blob_talloc(call, NULL,
gensec_sig_size(dce_conn->auth_state.gensec_security,
payload_length));
data_blob_clear(&dce_conn->auth_state.auth_info->credentials);
}
/* add the auth verifier */
status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
dce_conn->auth_state.auth_info);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
/* extract the whole packet as a blob */
*blob = ndr_push_blob(ndr);
/* fill in the fragment length and auth_length, we can't fill
in these earlier as we don't know the signature length (it
could be variable length) */
dcerpc_set_frag_length(blob, blob->length);
/* We hope this value is accruate. If must be if the GENSEC
* mech does AEAD signing of the packet headers */
dcerpc_set_auth_length(blob, dce_conn->auth_state.auth_info->credentials.length);
/* sign or seal the packet */
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = gensec_seal_packet(dce_conn->auth_state.gensec_security,
call,
ndr->data + DCERPC_REQUEST_LENGTH,
payload_length,
blob->data,
blob->length - dce_conn->auth_state.auth_info->credentials.length,
&creds2);
if (NT_STATUS_IS_OK(status)) {
blob->length -= dce_conn->auth_state.auth_info->credentials.length;
status = data_blob_append(call, blob, creds2.data, creds2.length);
}
/* If we did AEAD signing of the packet headers, then we hope
* this value didn't change... */
dcerpc_set_auth_length(blob, creds2.length);
dcerpc_set_frag_length(blob, dcerpc_get_frag_length(blob)+creds2.length);
data_blob_free(&creds2);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
status = gensec_sign_packet(dce_conn->auth_state.gensec_security,
call,
ndr->data + DCERPC_REQUEST_LENGTH,
payload_length,
blob->data,
blob->length - dce_conn->auth_state.auth_info->credentials.length,
&creds2);
if (NT_STATUS_IS_OK(status)) {
blob->length -= dce_conn->auth_state.auth_info->credentials.length;
status = data_blob_append(call, blob, creds2.data, creds2.length);
}
/* If we did AEAD signing of the packet headers, then we hope
* this value didn't change... */
dcerpc_set_auth_length(blob, creds2.length);
dcerpc_set_frag_length(blob, dcerpc_get_frag_length(blob)+creds2.length);
data_blob_free(&creds2);
break;
case DCERPC_AUTH_LEVEL_CONNECT:
break;
default:
status = NT_STATUS_INVALID_LEVEL;
break;
}
data_blob_free(&dce_conn->auth_state.auth_info->credentials);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
return True;
}
@@ -0,0 +1,438 @@
/*
Unix SMB/CIFS implementation.
endpoint server for the drsuapi pipe
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 "librpc/gen_ndr/ndr_drsuapi.h"
#include "rpc_server/dcerpc_server.h"
#include "rpc_server/common/common.h"
#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
#include "dsdb/samdb/samdb.h"
/*
drsuapi_DsBind
*/
static WERROR drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsBind *r)
{
struct drsuapi_bind_state *b_state;
struct dcesrv_handle *handle;
struct drsuapi_DsBindInfoCtr *bind_info;
struct GUID site_guid;
r->out.bind_info = NULL;
ZERO_STRUCTP(r->out.bind_handle);
b_state = talloc(dce_call->conn, struct drsuapi_bind_state);
W_ERROR_HAVE_NO_MEMORY(b_state);
b_state->sam_ctx = samdb_connect(b_state, dce_call->conn->auth_state.session_info);
if (!b_state->sam_ctx) {
talloc_free(b_state);
return WERR_FOOBAR;
}
handle = dcesrv_handle_new(dce_call->context, DRSUAPI_BIND_HANDLE);
if (!handle) {
talloc_free(b_state);
return WERR_NOMEM;
}
handle->data = talloc_steal(handle, b_state);
bind_info = talloc(mem_ctx, struct drsuapi_DsBindInfoCtr);
W_ERROR_HAVE_NO_MEMORY(bind_info);
ZERO_STRUCT(site_guid);
bind_info->length = 28;
bind_info->info.info28.supported_extensions = 0;
bind_info->info.info28.site_guid = site_guid;
bind_info->info.info28.u1 = 0;
bind_info->info.info28.repl_epoch = 0;
r->out.bind_info = bind_info;
*r->out.bind_handle = handle->wire_handle;
return WERR_OK;
}
/*
drsuapi_DsUnbind
*/
static WERROR drsuapi_DsUnbind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsUnbind *r)
{
struct dcesrv_handle *h;
*r->out.bind_handle = *r->in.bind_handle;
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
talloc_free(h);
ZERO_STRUCTP(r->out.bind_handle);
return WERR_OK;
}
/*
drsuapi_DsReplicaSync
*/
static WERROR drsuapi_DsReplicaSync(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsReplicaSync *r)
{
/* TODO: implement this call correct!
* for now we just say yes,
* because we have no output parameter
*/
return WERR_OK;
}
/*
drsuapi_DsGetNCChanges
*/
static WERROR drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsGetNCChanges *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
drsuapi_DsReplicaUpdateRefs
*/
static WERROR drsuapi_DsReplicaUpdateRefs(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsReplicaUpdateRefs *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_REPLICA_ADD
*/
static WERROR DRSUAPI_REPLICA_ADD(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_REPLICA_ADD *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_REPLICA_DEL
*/
static WERROR DRSUAPI_REPLICA_DEL(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_REPLICA_DEL *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_REPLICA_MODIFY
*/
static WERROR DRSUAPI_REPLICA_MODIFY(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_REPLICA_MODIFY *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_VERIFY_NAMES
*/
static WERROR DRSUAPI_VERIFY_NAMES(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_VERIFY_NAMES *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
drsuapi_DsGetMemberships
*/
static WERROR drsuapi_DsGetMemberships(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsGetMemberships *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_INTER_DOMAIN_MOVE
*/
static WERROR DRSUAPI_INTER_DOMAIN_MOVE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_INTER_DOMAIN_MOVE *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_GET_NT4_CHANGELOG
*/
static WERROR DRSUAPI_GET_NT4_CHANGELOG(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_GET_NT4_CHANGELOG *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
drsuapi_DsCrackNames
*/
WERROR drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsCrackNames *r)
{
WERROR status;
struct drsuapi_bind_state *b_state;
struct dcesrv_handle *h;
r->out.level = r->in.level;
ZERO_STRUCT(r->out.ctr);
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
b_state = h->data;
switch (r->in.level) {
case 1: {
struct drsuapi_DsNameCtr1 *ctr1;
struct drsuapi_DsNameInfo1 *names;
int count;
int i;
ctr1 = talloc(mem_ctx, struct drsuapi_DsNameCtr1);
W_ERROR_HAVE_NO_MEMORY(ctr1);
count = r->in.req.req1.count;
names = talloc_array(mem_ctx, struct drsuapi_DsNameInfo1, count);
W_ERROR_HAVE_NO_MEMORY(names);
for (i=0; i < count; i++) {
status = DsCrackNameOneName(b_state->sam_ctx, mem_ctx,
r->in.req.req1.format_flags,
r->in.req.req1.format_offered,
r->in.req.req1.format_desired,
r->in.req.req1.names[i].str,
&names[i]);
if (!W_ERROR_IS_OK(status)) {
return status;
}
}
ctr1->count = count;
ctr1->array = names;
r->out.ctr.ctr1 = ctr1;
return WERR_OK;
}
}
return WERR_UNKNOWN_LEVEL;
}
/*
drsuapi_DsWriteAccountSpn
*/
static WERROR drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsWriteAccountSpn *r)
{
struct drsuapi_bind_state *b_state;
struct dcesrv_handle *h;
r->out.level = r->in.level;
DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
b_state = h->data;
switch (r->in.level) {
case 1: {
struct drsuapi_DsWriteAccountSpnRequest1 *req;
struct ldb_message *msg;
int count, i, ret;
req = &r->in.req.req1;
count = req->count;
msg = ldb_msg_new(mem_ctx);
if (msg == NULL) {
return WERR_NOMEM;
}
msg->dn = ldb_dn_new(msg, b_state->sam_ctx, req->object_dn);
if ( ! ldb_dn_validate(msg->dn)) {
r->out.res.res1.status = WERR_OK;
return WERR_OK;
}
/* construct mods */
for (i = 0; i < count; i++) {
samdb_msg_add_string(b_state->sam_ctx,
msg, msg, "servicePrincipalName",
req->spn_names[i].str);
}
for (i=0;i<msg->num_elements;i++) {
switch (req->operation) {
case DRSUAPI_DS_SPN_OPERATION_ADD:
msg->elements[i].flags = LDB_FLAG_MOD_ADD;
break;
case DRSUAPI_DS_SPN_OPERATION_REPLACE:
msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
break;
case DRSUAPI_DS_SPN_OPERATION_DELETE:
msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
break;
}
}
/* Apply to database */
ret = samdb_modify(b_state->sam_ctx, mem_ctx, msg);
if (ret != 0) {
DEBUG(0,("Failed to modify SPNs on %s: %s\n",
ldb_dn_get_linearized(msg->dn),
ldb_errstring(b_state->sam_ctx)));
r->out.res.res1.status = WERR_ACCESS_DENIED;
} else {
r->out.res.res1.status = WERR_OK;
}
return WERR_OK;
}
}
return WERR_UNKNOWN_LEVEL;
}
/*
drsuapi_DsRemoveDSServer
*/
static WERROR drsuapi_DsRemoveDSServer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsRemoveDSServer *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_REMOVE_DS_DOMAIN
*/
static WERROR DRSUAPI_REMOVE_DS_DOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_REMOVE_DS_DOMAIN *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
drsuapi_DsGetDomainControllerInfo
*/
static WERROR drsuapi_DsGetDomainControllerInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsGetDomainControllerInfo *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
drsuapi_DsAddEntry
*/
static WERROR drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsAddEntry *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_EXECUTE_KCC
*/
static WERROR DRSUAPI_EXECUTE_KCC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_EXECUTE_KCC *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
drsuapi_DsReplicaGetInfo
*/
static WERROR drsuapi_DsReplicaGetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsReplicaGetInfo *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_ADD_SID_HISTORY
*/
static WERROR DRSUAPI_ADD_SID_HISTORY(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_ADD_SID_HISTORY *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
drsuapi_DsGetMemberships2
*/
static WERROR drsuapi_DsGetMemberships2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct drsuapi_DsGetMemberships2 *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_REPLICA_VERIFY_OBJECTS
*/
static WERROR DRSUAPI_REPLICA_VERIFY_OBJECTS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_REPLICA_VERIFY_OBJECTS *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_GET_OBJECT_EXISTENCE
*/
static WERROR DRSUAPI_GET_OBJECT_EXISTENCE(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_GET_OBJECT_EXISTENCE *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
DRSUAPI_QUERY_SITES_BY_COST
*/
static WERROR DRSUAPI_QUERY_SITES_BY_COST(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct DRSUAPI_QUERY_SITES_BY_COST *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/* include the generated boilerplate */
#include "librpc/gen_ndr/ndr_drsuapi_s.c"
@@ -0,0 +1,35 @@
/*
Unix SMB/CIFS implementation.
endpoint server for the drsuapi pipe
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.
*/
/*
this type allows us to distinguish handle types
*/
enum drsuapi_handle {
DRSUAPI_BIND_HANDLE,
};
/*
state asscoiated with a drsuapi_DsBind*() operation
*/
struct drsuapi_bind_state {
void *sam_ctx;
};
+194
View File
@@ -0,0 +1,194 @@
/*
Unix SMB/CIFS implementation.
endpoint server for the echo pipe
Copyright (C) Andrew Tridgell 2003
Copyright (C) Stefan (metze) Metzmacher 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 "system/filesys.h"
#include "rpc_server/dcerpc_server.h"
#include "librpc/gen_ndr/ndr_echo.h"
#include "lib/events/events.h"
static NTSTATUS echo_AddOne(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_AddOne *r)
{
*r->out.out_data = r->in.in_data + 1;
return NT_STATUS_OK;
}
static NTSTATUS echo_EchoData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_EchoData *r)
{
if (!r->in.len) {
return NT_STATUS_OK;
}
r->out.out_data = talloc_memdup(mem_ctx, r->in.in_data, r->in.len);
if (!r->out.out_data) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
}
static NTSTATUS echo_SinkData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_SinkData *r)
{
return NT_STATUS_OK;
}
static NTSTATUS echo_SourceData(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_SourceData *r)
{
int i;
r->out.data = talloc_array(mem_ctx, uint8_t, r->in.len);
for (i=0;i<r->in.len;i++) {
r->out.data[i] = i;
}
return NT_STATUS_OK;
}
static NTSTATUS echo_TestCall(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestCall *r)
{
*r->out.s2 = talloc_strdup(mem_ctx, r->in.s1);
return NT_STATUS_OK;
}
static NTSTATUS echo_TestCall2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestCall2 *r)
{
r->out.info = talloc(mem_ctx, union echo_Info);
if (!r->out.info) {
return NT_STATUS_NO_MEMORY;
}
switch (r->in.level) {
case 1:
r->out.info->info1.v = 10;
break;
case 2:
r->out.info->info2.v = 20;
break;
case 3:
r->out.info->info3.v = 30;
break;
case 4:
r->out.info->info4.v = 40;
break;
case 5:
r->out.info->info5.v1 = 50;
r->out.info->info5.v2 = 60;
break;
case 6:
r->out.info->info6.v1 = 70;
r->out.info->info6.info1.v= 80;
break;
case 7:
r->out.info->info7.v1 = 80;
r->out.info->info7.info4.v = 90;
break;
default:
return NT_STATUS_INVALID_LEVEL;
}
return NT_STATUS_OK;
}
static NTSTATUS echo_TestEnum(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestEnum *r)
{
r->out.foo2->e1 = ECHO_ENUM2;
return NT_STATUS_OK;
}
static NTSTATUS echo_TestSurrounding(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestSurrounding *r)
{
if (!r->in.data) {
r->out.data = NULL;
return NT_STATUS_OK;
}
r->out.data = talloc(mem_ctx, struct echo_Surrounding);
r->out.data->x = 2 * r->in.data->x;
r->out.data->surrounding = talloc_zero_array(mem_ctx, uint16_t, r->out.data->x);
return NT_STATUS_OK;
}
static uint16_t echo_TestDoublePointer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestDoublePointer *r)
{
if (!*r->in.data)
return 0;
if (!**r->in.data)
return 0;
return ***r->in.data;
}
struct echo_TestSleep_private {
struct dcesrv_call_state *dce_call;
struct echo_TestSleep *r;
};
static void echo_TestSleep_handler(struct event_context *ev, struct timed_event *te,
struct timeval t, void *private)
{
struct echo_TestSleep_private *p = talloc_get_type(private,
struct echo_TestSleep_private);
struct echo_TestSleep *r = p->r;
NTSTATUS status;
r->out.result = r->in.seconds;
status = dcesrv_reply(p->dce_call);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("echo_TestSleep_handler: dcesrv_reply() failed - %s\n",
nt_errstr(status)));
}
}
static long echo_TestSleep(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestSleep *r)
{
struct echo_TestSleep_private *p;
if (!(dce_call->state_flags & DCESRV_CALL_STATE_FLAG_MAY_ASYNC)) {
/* we're not allowed to reply async */
sleep(r->in.seconds);
return r->in.seconds;
}
/* we're allowed to reply async */
p = talloc(mem_ctx, struct echo_TestSleep_private);
if (!p) {
return 0;
}
p->dce_call = dce_call;
p->r = r;
event_add_timed(dce_call->event_ctx, p,
timeval_add(&dce_call->time, r->in.seconds, 0),
echo_TestSleep_handler, p);
dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
return 0;
}
/* include the generated boilerplate */
#include "librpc/gen_ndr/ndr_echo_s.c"
@@ -0,0 +1,266 @@
/*
Unix SMB/CIFS implementation.
endpoint server for the epmapper pipe
Copyright (C) Andrew Tridgell 2003
Copyright (C) Jelmer Vernooij 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 "librpc/gen_ndr/ndr_epmapper.h"
#include "rpc_server/dcerpc_server.h"
#include "rpc_server/common/common.h"
typedef uint32_t error_status_t;
/* handle types for this module */
enum handle_types {HTYPE_LOOKUP};
/* a endpoint combined with an interface description */
struct dcesrv_ep_iface {
const char *name;
struct epm_tower ep;
};
/*
build a list of all interfaces handled by all endpoint servers
*/
static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
struct dcesrv_endpoint *endpoint_list,
struct dcesrv_ep_iface **eps)
{
struct dcesrv_endpoint *d;
uint32_t total = 0;
NTSTATUS status;
*eps = NULL;
for (d=endpoint_list; d; d=d->next) {
struct dcesrv_if_list *iface;
struct dcerpc_binding *description;
for (iface=d->interface_list;iface;iface=iface->next) {
(*eps) = talloc_realloc(mem_ctx,
*eps,
struct dcesrv_ep_iface,
total + 1);
if (!*eps) {
return 0;
}
(*eps)[total].name = iface->iface.name;
description = d->ep_description;
description->object = iface->iface.syntax_id;
status = dcerpc_binding_build_tower(mem_ctx, description, &(*eps)[total].ep);
if (NT_STATUS_IS_ERR(status)) {
DEBUG(1, ("Unable to build tower for %s\n", iface->iface.name));
continue;
}
total++;
}
}
return total;
}
static error_status_t epm_Insert(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_Insert *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
static error_status_t epm_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_Delete *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
implement epm_Lookup. This call is used to enumerate the interfaces
available on a rpc server
*/
static error_status_t epm_Lookup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_Lookup *r)
{
struct dcesrv_handle *h;
struct rpc_eps {
uint32_t count;
struct dcesrv_ep_iface *e;
} *eps;
uint32_t num_ents;
int i;
DCESRV_PULL_HANDLE_FAULT(h, r->in.entry_handle, HTYPE_LOOKUP);
eps = h->data;
if (!eps) {
/* this is the first call - fill the list. Subsequent calls
will feed from this list, stored in the handle */
eps = talloc(h, struct rpc_eps);
if (!eps) {
return EPMAPPER_STATUS_NO_MEMORY;
}
h->data = eps;
eps->count = build_ep_list(h, dce_call->conn->dce_ctx->endpoint_list, &eps->e);
}
/* return the next N elements */
num_ents = r->in.max_ents;
if (num_ents > eps->count) {
num_ents = eps->count;
}
*r->out.entry_handle = h->wire_handle;
r->out.num_ents = talloc(mem_ctx, uint32_t);
*r->out.num_ents = num_ents;
if (num_ents == 0) {
r->out.entries = NULL;
ZERO_STRUCTP(r->out.entry_handle);
talloc_free(h);
return EPMAPPER_STATUS_NO_MORE_ENTRIES;
}
r->out.entries = talloc_array(mem_ctx, struct epm_entry_t, num_ents);
if (!r->out.entries) {
return EPMAPPER_STATUS_NO_MEMORY;
}
for (i=0;i<num_ents;i++) {
ZERO_STRUCT(r->out.entries[i].object);
r->out.entries[i].annotation = eps->e[i].name;
r->out.entries[i].tower = talloc(mem_ctx, struct epm_twr_t);
if (!r->out.entries[i].tower) {
return EPMAPPER_STATUS_NO_MEMORY;
}
r->out.entries[i].tower->tower = eps->e[i].ep;
}
eps->count -= num_ents;
eps->e += num_ents;
return EPMAPPER_STATUS_OK;
}
/*
implement epm_Map. This is used to find the specific endpoint to talk to given
a generic protocol tower
*/
static error_status_t epm_Map(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_Map *r)
{
uint32_t count;
int i;
struct dcesrv_ep_iface *eps;
struct epm_floor *floors;
enum dcerpc_transport_t transport;
struct dcerpc_syntax_id ndr_syntax;
count = build_ep_list(mem_ctx, dce_call->conn->dce_ctx->endpoint_list, &eps);
ZERO_STRUCT(*r->out.entry_handle);
r->out.num_towers = talloc(mem_ctx, uint32_t);
*r->out.num_towers = 1;
r->out.towers = talloc(mem_ctx, struct epm_twr_p_t);
if (!r->out.towers) {
return EPMAPPER_STATUS_NO_MEMORY;
}
r->out.towers->twr = talloc(mem_ctx, struct epm_twr_t);
if (!r->out.towers->twr) {
return EPMAPPER_STATUS_NO_MEMORY;
}
if (!r->in.map_tower || r->in.max_towers == 0 ||
r->in.map_tower->tower.num_floors < 3) {
goto failed;
}
floors = r->in.map_tower->tower.floors;
dcerpc_floor_get_lhs_data(&r->in.map_tower->tower.floors[1], &ndr_syntax);
if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
!GUID_equal(&ndr_syntax.uuid, &ndr_transfer_syntax.uuid) ||
ndr_syntax.if_version != ndr_transfer_syntax.if_version) {
goto failed;
}
transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
if (transport == -1) {
DEBUG(2, ("Client requested unknown transport with levels: "));
for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
}
DEBUG(2, ("\n"));
goto failed;
}
for (i=0;i<count;i++) {
if (
!data_blob_equal(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
&eps[i].ep.floors[0].lhs.lhs_data)
|| transport != dcerpc_transport_by_tower(&eps[i].ep)) {
continue;
}
r->out.towers->twr->tower = eps[i].ep;
r->out.towers->twr->tower_length = 0;
return EPMAPPER_STATUS_OK;
}
failed:
*r->out.num_towers = 0;
r->out.towers->twr = NULL;
return EPMAPPER_STATUS_NO_MORE_ENTRIES;
}
static error_status_t epm_LookupHandleFree(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_LookupHandleFree *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
static error_status_t epm_InqObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_InqObject *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
static error_status_t epm_MgmtDelete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_MgmtDelete *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
static error_status_t epm_MapAuth(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct epm_MapAuth *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/* include the generated boilerplate */
#include "librpc/gen_ndr/ndr_epmapper_s.c"
+91
View File
@@ -0,0 +1,91 @@
/*
Unix SMB/CIFS implementation.
server side dcerpc handle code
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "lib/util/dlinklist.h"
#include "rpc_server/dcerpc_server.h"
/*
destroy a rpc handle
*/
static int dcesrv_handle_destructor(struct dcesrv_handle *h)
{
DLIST_REMOVE(h->context->handles, h);
talloc_free(h);
return 0;
}
/*
allocate a new rpc handle
*/
_PUBLIC_ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection_context *context,
uint8_t handle_type)
{
struct dcesrv_handle *h;
h = talloc(context, struct dcesrv_handle);
if (!h) {
return NULL;
}
h->data = NULL;
h->context = context;
h->wire_handle.handle_type = handle_type;
h->wire_handle.uuid = GUID_random();
DLIST_ADD(context->handles, h);
talloc_set_destructor(h, dcesrv_handle_destructor);
return h;
}
/*
find an internal handle given a wire handle. If the wire handle is NULL then
allocate a new handle
*/
_PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(struct dcesrv_connection_context *context,
struct policy_handle *p,
uint8_t handle_type)
{
struct dcesrv_handle *h;
if (policy_handle_empty(p)) {
return dcesrv_handle_new(context, handle_type);
}
for (h=context->handles; h; h=h->next) {
if (h->wire_handle.handle_type == p->handle_type &&
GUID_equal(&p->uuid, &h->wire_handle.uuid)) {
if (handle_type != DCESRV_HANDLE_ANY &&
p->handle_type != handle_type) {
DEBUG(0,("client gave us the wrong handle type (%d should be %d)\n",
p->handle_type, handle_type));
return NULL;
}
return h;
}
}
return NULL;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+38
View File
@@ -0,0 +1,38 @@
This is an RPC backend that implements all operations in terms of
remote RPC operations. This may be useful in certain debugging
situations, where the traffic is encrypted, or you wish to validate
that IDL is correct before implementing full test clients, or with
windows clients.
There are two modes of operation: Password specified and delegated
credentials.
Password specified:
-------------------
This uses a static username/password in the config file, example:
[global]
dcerpc endpoint servers = remote
dcerpc_remote:binding = ncacn_np:win2003
dcerpc_remote:username = administrator
dcerpc_remote:password = PASSWORD
dcerpc_remote:interfaces = samr, lsarpc, netlogon
Delegated credentials:
----------------------
If your incoming user is authenticated with Kerberos, and the machine
account for this Samba4 proxy server is 'trusted for delegation', then
the Samba4 proxy can forward the client's credentials to the target.
You must be joined to the domain (net join <domain> member).
To set 'trusted for delegation' with MMC, see the checkbox in the
Computer account property page under Users and Computers.
[global]
dcerpc endpoint servers = remote
dcerpc_remote:binding = ncacn_np:win2003
dcerpc_remote:interfaces = samr, lsarpc, netlogon
@@ -0,0 +1,323 @@
/*
Unix SMB/CIFS implementation.
remote dcerpc operations
Copyright (C) Stefan (metze) 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 "rpc_server/dcerpc_server.h"
#include "auth/auth.h"
#include "auth/credentials/credentials.h"
#include "librpc/rpc/dcerpc_table.h"
struct dcesrv_remote_private {
struct dcerpc_pipe *c_pipe;
};
static NTSTATUS remote_op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
return NT_STATUS_OK;
}
static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
{
NTSTATUS status;
const struct dcerpc_interface_table *table;
struct dcesrv_remote_private *private;
const char *binding = lp_parm_string(-1, "dcerpc_remote", "binding");
const char *user, *pass, *domain;
struct cli_credentials *credentials;
BOOL machine_account;
machine_account = lp_parm_bool(-1, "dcerpc_remote", "use_machine_account", False);
private = talloc(dce_call->conn, struct dcesrv_remote_private);
if (!private) {
return NT_STATUS_NO_MEMORY;
}
private->c_pipe = NULL;
dce_call->context->private = private;
if (!binding) {
DEBUG(0,("You must specify a DCE/RPC binding string\n"));
return NT_STATUS_INVALID_PARAMETER;
}
user = lp_parm_string(-1, "dcerpc_remote", "user");
pass = lp_parm_string(-1, "dcerpc_remote", "password");
domain = lp_parm_string(-1, "dceprc_remote", "domain");
table = idl_iface_by_uuid(&iface->syntax_id.uuid); /* FIXME: What about if_version ? */
if (!table) {
dce_call->fault_code = DCERPC_FAULT_UNK_IF;
return NT_STATUS_NET_WRITE_FAULT;
}
if (user && pass) {
DEBUG(5, ("dcerpc_remote: RPC Proxy: Using specified account\n"));
credentials = cli_credentials_init(private);
if (!credentials) {
return NT_STATUS_NO_MEMORY;
}
cli_credentials_set_conf(credentials);
cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
if (domain) {
cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
}
cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
} else if (machine_account) {
DEBUG(5, ("dcerpc_remote: RPC Proxy: Using machine account\n"));
credentials = cli_credentials_init(private);
cli_credentials_set_conf(credentials);
if (domain) {
cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
}
status = cli_credentials_set_machine_account(credentials);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
} else if (dce_call->conn->auth_state.session_info->credentials) {
DEBUG(5, ("dcerpc_remote: RPC Proxy: Using delegated credentials\n"));
credentials = dce_call->conn->auth_state.session_info->credentials;
} else {
DEBUG(1,("dcerpc_remote: RPC Proxy: You must supply binding, user and password or have delegated credentials\n"));
return NT_STATUS_INVALID_PARAMETER;
}
status = dcerpc_pipe_connect(private,
&(private->c_pipe), binding, table,
credentials, dce_call->event_ctx);
talloc_free(credentials);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return NT_STATUS_OK;
}
static void remote_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
{
struct dcesrv_remote_private *private = context->private;
talloc_free(private->c_pipe);
return;
}
static NTSTATUS remote_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
{
NTSTATUS status;
const struct dcerpc_interface_table *table = dce_call->context->iface->private;
uint16_t opnum = dce_call->pkt.u.request.opnum;
dce_call->fault_code = 0;
if (opnum >= table->num_calls) {
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
return NT_STATUS_NET_WRITE_FAULT;
}
*r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
if (!*r) {
return NT_STATUS_NO_MEMORY;
}
/* unravel the NDR for the packet */
status = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
if (!NT_STATUS_IS_OK(status)) {
dcerpc_log_packet(table, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
struct dcesrv_remote_private *private = dce_call->context->private;
uint16_t opnum = dce_call->pkt.u.request.opnum;
const struct dcerpc_interface_table *table = dce_call->context->iface->private;
const struct dcerpc_interface_call *call;
const char *name;
name = table->calls[opnum].name;
call = &table->calls[opnum];
if (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);
}
/* we didn't use the return code of this function as we only check the last_fault_code */
dcerpc_ndr_request(private->c_pipe, NULL, table, opnum, mem_ctx,r);
dce_call->fault_code = private->c_pipe->last_fault_code;
if (dce_call->fault_code != 0) {
DEBUG(0,("dcesrv_remote: call[%s] failed with: %s!\n",name, dcerpc_errstr(mem_ctx, dce_call->fault_code)));
return NT_STATUS_NET_WRITE_FAULT;
}
if ((dce_call->fault_code == 0) &&
(private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
ndr_print_function_debug(call->ndr_print, name, NDR_OUT, r);
}
return NT_STATUS_OK;
}
static NTSTATUS remote_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
{
NTSTATUS status;
const struct dcerpc_interface_table *table = dce_call->context->iface->private;
uint16_t opnum = dce_call->pkt.u.request.opnum;
/* unravel the NDR for the packet */
status = table->calls[opnum].ndr_push(push, NDR_OUT, r);
if (!NT_STATUS_IS_OK(status)) {
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
{
int i;
const struct dcerpc_interface_table *table = iface->private;
for (i=0;i<table->endpoints->count;i++) {
NTSTATUS ret;
const char *name = table->endpoints->names[i];
ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1,("remote_op_init_server: failed to register endpoint '%s'\n",name));
return ret;
}
}
return NT_STATUS_OK;
}
static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
{
int i;
const char **ifaces = str_list_make(dce_ctx, lp_parm_string(-1,"dcerpc_remote","interfaces"),NULL);
if (!ifaces) {
DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
return NT_STATUS_OK;
}
for (i=0;ifaces[i];i++) {
NTSTATUS ret;
struct dcesrv_interface iface;
if (!ep_server->interface_by_name(&iface, ifaces[i])) {
DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
talloc_free(ifaces);
return NT_STATUS_UNSUCCESSFUL;
}
ret = remote_register_one_iface(dce_ctx, &iface);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
talloc_free(ifaces);
return ret;
}
}
talloc_free(ifaces);
return NT_STATUS_OK;
}
static BOOL remote_fill_interface(struct dcesrv_interface *iface, const struct dcerpc_interface_table *if_tabl)
{
iface->name = if_tabl->name;
iface->syntax_id = if_tabl->syntax_id;
iface->bind = remote_op_bind;
iface->unbind = remote_op_unbind;
iface->ndr_pull = remote_op_ndr_pull;
iface->dispatch = remote_op_dispatch;
iface->reply = remote_op_reply;
iface->ndr_push = remote_op_ndr_push;
iface->private = if_tabl;
return True;
}
static BOOL remote_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
{
const struct dcerpc_interface_list *l;
for (l=librpc_dcerpc_pipes();l;l=l->next) {
if (l->table->syntax_id.if_version == if_version &&
GUID_equal(&l->table->syntax_id.uuid, uuid)==0) {
return remote_fill_interface(iface, l->table);
}
}
return False;
}
static BOOL remote_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
{
const struct dcerpc_interface_table *tbl = idl_iface_by_name(name);
if (tbl)
return remote_fill_interface(iface, tbl);
return False;
}
NTSTATUS dcerpc_server_remote_init(void)
{
NTSTATUS ret;
struct dcesrv_endpoint_server ep_server;
ZERO_STRUCT(ep_server);
/* fill in our name */
ep_server.name = "remote";
/* fill in all the operations */
ep_server.init_server = remote_op_init_server;
ep_server.interface_by_uuid = remote_op_interface_by_uuid;
ep_server.interface_by_name = remote_op_interface_by_name;
/* register ourselves with the DCERPC subsystem. */
ret = dcerpc_register_ep_server(&ep_server);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("Failed to register 'remote' endpoint server!\n"));
return ret;
}
/* We need the full DCE/RPC interface table */
dcerpc_table_init();
return ret;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
/*
Unix SMB/CIFS implementation.
endpoint server for the samr pipe - definitions
Copyright (C) Andrew Tridgell 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.
*/
/*
this type allows us to distinguish handle types
*/
enum samr_handle {
SAMR_HANDLE_CONNECT,
SAMR_HANDLE_DOMAIN,
SAMR_HANDLE_USER,
SAMR_HANDLE_GROUP,
SAMR_HANDLE_ALIAS
};
/*
state asscoiated with a samr_Connect*() operation
*/
struct samr_connect_state {
void *sam_ctx;
uint32_t access_mask;
};
/*
state associated with a samr_OpenDomain() operation
*/
struct samr_domain_state {
struct samr_connect_state *connect_state;
void *sam_ctx;
uint32_t access_mask;
struct dom_sid *domain_sid;
const char *domain_name;
struct ldb_dn *domain_dn;
};
/*
state associated with a open account handle
*/
struct samr_account_state {
struct samr_domain_state *domain_state;
void *sam_ctx;
uint32_t access_mask;
struct dom_sid *account_sid;
const char *account_name;
struct ldb_dn *account_dn;
};
@@ -0,0 +1,601 @@
/*
Unix SMB/CIFS implementation.
samr server password set/change handling
Copyright (C) Andrew Tridgell 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 "rpc_server/dcerpc_server.h"
#include "rpc_server/common/common.h"
#include "rpc_server/samr/dcesrv_samr.h"
#include "system/time.h"
#include "lib/crypto/crypto.h"
#include "dsdb/common/flags.h"
#include "libcli/ldap/ldap.h"
#include "dsdb/samdb/samdb.h"
#include "auth/auth.h"
#include "rpc_server/samr/proto.h"
#include "libcli/auth/libcli_auth.h"
#include "db_wrap.h"
/*
samr_ChangePasswordUser
*/
NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct samr_ChangePasswordUser *r)
{
struct dcesrv_handle *h;
struct samr_account_state *a_state;
struct ldb_context *sam_ctx;
struct ldb_message **res, *msg;
int ret;
struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
struct samr_Password *lm_pwd, *nt_pwd;
NTSTATUS status = NT_STATUS_OK;
const char * const attrs[] = { "lmPwdHash", "ntPwdHash" , NULL };
DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
a_state = h->data;
/* basic sanity checking on parameters. Do this before any database ops */
if (!r->in.lm_present || !r->in.nt_present ||
!r->in.old_lm_crypted || !r->in.new_lm_crypted ||
!r->in.old_nt_crypted || !r->in.new_nt_crypted) {
/* we should really handle a change with lm not
present */
return NT_STATUS_INVALID_PARAMETER_MIX;
}
if (!r->in.cross1_present || !r->in.nt_cross) {
return NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED;
}
if (!r->in.cross2_present || !r->in.lm_cross) {
return NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED;
}
/* To change a password we need to open as system */
sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
ret = ldb_transaction_start(sam_ctx);
if (ret) {
DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
return NT_STATUS_TRANSACTION_ABORTED;
}
/* fetch the old hashes */
ret = gendb_search_dn(sam_ctx, mem_ctx,
a_state->account_dn, &res, attrs);
if (ret != 1) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
msg = res[0];
status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
/* decrypt and check the new lm hash */
D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
/* decrypt and check the new nt hash */
D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
/* check the nt cross hash */
D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
/* check the lm cross hash */
D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
msg = ldb_msg_new(mem_ctx);
if (msg == NULL) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_NO_MEMORY;
}
msg->dn = ldb_dn_copy(msg, a_state->account_dn);
if (!msg->dn) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_NO_MEMORY;
}
/* setup password modify mods on the user DN specified. This may fail
* due to password policies. */
status = samdb_set_password(sam_ctx, mem_ctx,
a_state->account_dn, a_state->domain_state->domain_dn,
msg, NULL, &new_lmPwdHash, &new_ntPwdHash,
True, /* this is a user password change */
True, /* run restriction tests */
NULL,
NULL);
if (!NT_STATUS_IS_OK(status)) {
ldb_transaction_cancel(sam_ctx);
return status;
}
/* The above call only setup the modifications, this actually
* makes the write to the database. */
ret = samdb_replace(sam_ctx, mem_ctx, msg);
if (ret != 0) {
DEBUG(2,("Failed to modify record to change password on %s: %s\n",
ldb_dn_get_linearized(a_state->account_dn),
ldb_errstring(sam_ctx)));
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
/* And this confirms it in a transaction commit */
ret = ldb_transaction_commit(sam_ctx);
if (ret != 0) {
DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
ldb_dn_get_linearized(a_state->account_dn),
ldb_errstring(sam_ctx)));
return NT_STATUS_TRANSACTION_ABORTED;
}
return NT_STATUS_OK;
}
/*
samr_OemChangePasswordUser2
*/
NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct samr_OemChangePasswordUser2 *r)
{
NTSTATUS status;
char new_pass[512];
uint32_t new_pass_len;
struct samr_CryptPassword *pwbuf = r->in.password;
struct ldb_context *sam_ctx;
struct ldb_dn *user_dn;
int ret;
struct ldb_message **res, *mod;
const char * const attrs[] = { "objectSid", "lmPwdHash", NULL };
struct samr_Password *lm_pwd;
DATA_BLOB lm_pwd_blob;
uint8_t new_lm_hash[16];
struct samr_Password lm_verifier;
if (pwbuf == NULL) {
return NT_STATUS_WRONG_PASSWORD;
}
/* To change a password we need to open as system */
sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
ret = ldb_transaction_start(sam_ctx);
if (ret) {
DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
return NT_STATUS_TRANSACTION_ABORTED;
}
/* we need the users dn and the domain dn (derived from the
user SID). We also need the current lm password hash in
order to decrypt the incoming password */
ret = gendb_search(sam_ctx,
mem_ctx, NULL, &res, attrs,
"(&(sAMAccountName=%s)(objectclass=user))",
r->in.account->string);
if (ret != 1) {
ldb_transaction_cancel(sam_ctx);
/* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
return NT_STATUS_WRONG_PASSWORD;
}
user_dn = res[0]->dn;
status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
/* decrypt the password we have been given */
lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
data_blob_free(&lm_pwd_blob);
if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
&new_pass_len, STR_ASCII)) {
ldb_transaction_cancel(sam_ctx);
DEBUG(3,("samr: failed to decode password buffer\n"));
return NT_STATUS_WRONG_PASSWORD;
}
/* check LM verifier */
if (lm_pwd == NULL || r->in.hash == NULL) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
E_deshash(new_pass, new_lm_hash);
E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
}
mod = ldb_msg_new(mem_ctx);
if (mod == NULL) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_NO_MEMORY;
}
mod->dn = ldb_dn_copy(mod, user_dn);
if (!mod->dn) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_NO_MEMORY;
}
/* set the password on the user DN specified. This may fail
* due to password policies */
status = samdb_set_password(sam_ctx, mem_ctx,
user_dn, NULL,
mod, new_pass,
NULL, NULL,
True, /* this is a user password change */
True, /* run restriction tests */
NULL,
NULL);
if (!NT_STATUS_IS_OK(status)) {
ldb_transaction_cancel(sam_ctx);
return status;
}
/* The above call only setup the modifications, this actually
* makes the write to the database. */
ret = samdb_replace(sam_ctx, mem_ctx, mod);
if (ret != 0) {
DEBUG(2,("Failed to modify record to change password on %s: %s\n",
ldb_dn_get_linearized(user_dn),
ldb_errstring(sam_ctx)));
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
/* And this confirms it in a transaction commit */
ret = ldb_transaction_commit(sam_ctx);
if (ret != 0) {
DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
ldb_dn_get_linearized(user_dn),
ldb_errstring(sam_ctx)));
return NT_STATUS_TRANSACTION_ABORTED;
}
return NT_STATUS_OK;
}
/*
samr_ChangePasswordUser3
*/
NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct samr_ChangePasswordUser3 *r)
{
NTSTATUS status;
char new_pass[512];
uint32_t new_pass_len;
struct ldb_context *sam_ctx = NULL;
struct ldb_dn *user_dn;
int ret;
struct ldb_message **res, *mod;
const char * const attrs[] = { "ntPwdHash", "lmPwdHash", NULL };
struct samr_Password *nt_pwd, *lm_pwd;
DATA_BLOB nt_pwd_blob;
struct samr_DomInfo1 *dominfo = NULL;
struct samr_ChangeReject *reject = NULL;
enum samr_RejectReason reason = SAMR_REJECT_OTHER;
uint8_t new_nt_hash[16], new_lm_hash[16];
struct samr_Password nt_verifier, lm_verifier;
ZERO_STRUCT(r->out);
if (r->in.nt_password == NULL ||
r->in.nt_verifier == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
/* To change a password we need to open as system */
sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
ret = ldb_transaction_start(sam_ctx);
if (ret) {
talloc_free(sam_ctx);
DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
return NT_STATUS_TRANSACTION_ABORTED;
}
/* we need the users dn and the domain dn (derived from the
user SID). We also need the current lm and nt password hashes
in order to decrypt the incoming passwords */
ret = gendb_search(sam_ctx,
mem_ctx, NULL, &res, attrs,
"(&(sAMAccountName=%s)(objectclass=user))",
r->in.account->string);
if (ret != 1) {
/* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
status = NT_STATUS_WRONG_PASSWORD;
goto failed;
}
user_dn = res[0]->dn;
status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
if (!NT_STATUS_IS_OK(status) ) {
goto failed;
}
if (!nt_pwd) {
status = NT_STATUS_WRONG_PASSWORD;
goto failed;
}
/* decrypt the password we have been given */
nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
data_blob_free(&nt_pwd_blob);
if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
&new_pass_len, STR_UNICODE)) {
DEBUG(3,("samr: failed to decode password buffer\n"));
status = NT_STATUS_WRONG_PASSWORD;
goto failed;
}
if (r->in.nt_verifier == NULL) {
status = NT_STATUS_WRONG_PASSWORD;
goto failed;
}
/* check NT verifier */
E_md4hash(new_pass, new_nt_hash);
E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
status = NT_STATUS_WRONG_PASSWORD;
goto failed;
}
/* check LM verifier */
if (lm_pwd && r->in.lm_verifier != NULL) {
E_deshash(new_pass, new_lm_hash);
E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
status = NT_STATUS_WRONG_PASSWORD;
goto failed;
}
}
mod = ldb_msg_new(mem_ctx);
if (mod == NULL) {
return NT_STATUS_NO_MEMORY;
}
mod->dn = ldb_dn_copy(mod, user_dn);
if (!mod->dn) {
status = NT_STATUS_NO_MEMORY;
goto failed;
}
/* set the password on the user DN specified. This may fail
* due to password policies */
status = samdb_set_password(sam_ctx, mem_ctx,
user_dn, NULL,
mod, new_pass,
NULL, NULL,
True, /* this is a user password change */
True, /* run restriction tests */
&reason,
&dominfo);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
/* The above call only setup the modifications, this actually
* makes the write to the database. */
ret = samdb_replace(sam_ctx, mem_ctx, mod);
if (ret != 0) {
DEBUG(2,("samdb_replace failed to change password for %s: %s\n",
ldb_dn_get_linearized(user_dn),
ldb_errstring(sam_ctx)));
status = NT_STATUS_UNSUCCESSFUL;
goto failed;
}
/* And this confirms it in a transaction commit */
ret = ldb_transaction_commit(sam_ctx);
if (ret != 0) {
DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
ldb_dn_get_linearized(user_dn),
ldb_errstring(sam_ctx)));
status = NT_STATUS_TRANSACTION_ABORTED;
goto failed;
}
return NT_STATUS_OK;
failed:
ldb_transaction_cancel(sam_ctx);
talloc_free(sam_ctx);
reject = talloc(mem_ctx, struct samr_ChangeReject);
r->out.dominfo = dominfo;
r->out.reject = reject;
if (reject == NULL) {
return status;
}
ZERO_STRUCTP(reject);
reject->reason = reason;
return status;
}
/*
samr_ChangePasswordUser2
easy - just a subset of samr_ChangePasswordUser3
*/
NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct samr_ChangePasswordUser2 *r)
{
struct samr_ChangePasswordUser3 r2;
r2.in.server = r->in.server;
r2.in.account = r->in.account;
r2.in.nt_password = r->in.nt_password;
r2.in.nt_verifier = r->in.nt_verifier;
r2.in.lm_change = r->in.lm_change;
r2.in.lm_password = r->in.lm_password;
r2.in.lm_verifier = r->in.lm_verifier;
r2.in.password3 = NULL;
return samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
}
/*
set password via a samr_CryptPassword buffer
this will in the 'msg' with modify operations that will update the user
password when applied
*/
NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
void *sam_ctx,
struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
TALLOC_CTX *mem_ctx,
struct ldb_message *msg,
struct samr_CryptPassword *pwbuf)
{
NTSTATUS nt_status;
char new_pass[512];
uint32_t new_pass_len;
DATA_BLOB session_key = data_blob(NULL, 0);
nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
arcfour_crypt_blob(pwbuf->data, 516, &session_key);
if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
&new_pass_len, STR_UNICODE)) {
DEBUG(3,("samr: failed to decode password buffer\n"));
return NT_STATUS_WRONG_PASSWORD;
}
/* set the password - samdb needs to know both the domain and user DNs,
so the domain password policy can be used */
return samdb_set_password(sam_ctx, mem_ctx,
account_dn, domain_dn,
msg, new_pass,
NULL, NULL,
False, /* This is a password set, not change */
True, /* run restriction tests */
NULL, NULL);
}
/*
set password via a samr_CryptPasswordEx buffer
this will in the 'msg' with modify operations that will update the user
password when applied
*/
NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
struct ldb_context *sam_ctx,
struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
TALLOC_CTX *mem_ctx,
struct ldb_message *msg,
struct samr_CryptPasswordEx *pwbuf)
{
NTSTATUS nt_status;
char new_pass[512];
uint32_t new_pass_len;
DATA_BLOB co_session_key;
DATA_BLOB session_key = data_blob(NULL, 0);
struct MD5Context ctx;
nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
if (!co_session_key.data) {
return NT_STATUS_NO_MEMORY;
}
MD5Init(&ctx);
MD5Update(&ctx, &pwbuf->data[516], 16);
MD5Update(&ctx, session_key.data, session_key.length);
MD5Final(co_session_key.data, &ctx);
arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
&new_pass_len, STR_UNICODE)) {
DEBUG(3,("samr: failed to decode password buffer\n"));
return NT_STATUS_WRONG_PASSWORD;
}
/* set the password - samdb needs to know both the domain and user DNs,
so the domain password policy can be used */
return samdb_set_password(sam_ctx, mem_ctx,
account_dn, domain_dn,
msg, new_pass,
NULL, NULL,
False, /* This is a password set, not change */
True, /* run restriction tests */
NULL, NULL);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,137 @@
/*
Unix SMB/CIFS implementation.
srvsvc pipe ntvfs helper functions
Copyright (C) Stefan (metze) 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 "ntvfs/ntvfs.h"
#include "rpc_server/dcerpc_server.h"
#include "librpc/gen_ndr/ndr_srvsvc.h"
#include "rpc_server/common/common.h"
#include "rpc_server/srvsvc/proto.h"
#include "lib/socket/socket.h"
struct socket_address *srvsvc_get_my_addr(void *p, TALLOC_CTX *mem_ctx)
{
struct dcesrv_connection *conn = talloc_get_type(p, struct dcesrv_connection);
return dcesrv_connection_get_my_addr(conn, mem_ctx);
}
struct socket_address *srvsvc_get_peer_addr(void *p, TALLOC_CTX *mem_ctx)
{
struct dcesrv_connection *conn = talloc_get_type(p, struct dcesrv_connection);
return dcesrv_connection_get_peer_addr(conn, mem_ctx);
}
struct srvsvc_ntvfs_ctx {
struct ntvfs_context *ntvfs;
};
static int srvsvc_ntvfs_ctx_destructor(struct srvsvc_ntvfs_ctx *c)
{
ntvfs_disconnect(c->ntvfs);
return 0;
}
NTSTATUS srvsvc_create_ntvfs_context(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
const char *share,
struct ntvfs_context **_ntvfs)
{
NTSTATUS status;
struct srvsvc_ntvfs_ctx *c;
struct ntvfs_request *ntvfs_req;
enum ntvfs_type type;
struct share_context *sctx;
struct share_config *scfg;
const char *sharetype;
status = share_get_context(mem_ctx, &sctx);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = share_get_config(mem_ctx, sctx, share, &scfg);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("srvsvc_create_ntvfs_context: couldn't find service %s\n", share));
return status;
}
#if 0 /* TODO: fix access cecking */
if (!socket_check_access(dce_call->connection->socket,
scfg->name,
share_string_list_option(scfg, SHARE_HOSTS_ALLOW),
share_string_list_option(scfg, SHARE_HOSTS_DENY))) {
return NT_STATUS_ACCESS_DENIED;
}
#endif
/* work out what sort of connection this is */
sharetype = share_string_option(scfg, SHARE_TYPE, SHARE_TYPE_DEFAULT);
if (sharetype && strcmp(sharetype, "IPC") == 0) {
type = NTVFS_IPC;
} else if (sharetype && strcmp(sharetype, "PRINTER")) {
type = NTVFS_PRINT;
} else {
type = NTVFS_DISK;
}
c = talloc(mem_ctx, struct srvsvc_ntvfs_ctx);
NT_STATUS_HAVE_NO_MEMORY(c);
/* init ntvfs function pointers */
status = ntvfs_init_connection(c, scfg, type,
PROTOCOL_NT1,
dce_call->event_ctx,
dce_call->conn->msg_ctx,
dce_call->conn->server_id,
&c->ntvfs);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("srvsvc_create_ntvfs_context: ntvfs_init_connection failed for service %s\n",
scfg->name));
return status;
}
talloc_set_destructor(c, srvsvc_ntvfs_ctx_destructor);
/*
* NOTE: we only set the addr callbacks as we're not interesseted in oplocks or in getting file handles
*/
status = ntvfs_set_addr_callbacks(c->ntvfs, srvsvc_get_my_addr, srvsvc_get_peer_addr, dce_call->conn);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("srvsvc_create_ntvfs_context: NTVFS failed to set the addr callbacks!\n"));
return status;
}
ntvfs_req = ntvfs_request_create(c->ntvfs, mem_ctx,
dce_call->conn->auth_state.session_info,
0, /* TODO: fill in PID */
dce_call->time,
NULL, NULL, 0);
NT_STATUS_HAVE_NO_MEMORY(ntvfs_req);
/* Invoke NTVFS connection hook */
status = ntvfs_connect(ntvfs_req, scfg->name);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("srvsvc_create_ntvfs_context: NTVFS ntvfs_connect() failed!\n"));
return status;
}
*_ntvfs = c->ntvfs;
return NT_STATUS_OK;
}
@@ -0,0 +1,164 @@
/*
Unix SMB/CIFS implementation.
endpoint server for the unixinfo pipe
Copyright (C) Volker Lendecke 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "rpc_server/dcerpc_server.h"
#include "rpc_server/common/common.h"
#include "librpc/gen_ndr/ndr_unixinfo.h"
#include "lib/events/events.h"
#include "dsdb/samdb/samdb.h"
#include "system/passwd.h"
static NTSTATUS unixinfo_SidToUid(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct unixinfo_SidToUid *r)
{
NTSTATUS status;
struct sidmap_context *sidmap;
uid_t uid;
sidmap = sidmap_open(mem_ctx);
if (sidmap == NULL) {
DEBUG(10, ("sidmap_open failed\n"));
return NT_STATUS_NO_MEMORY;
}
status = sidmap_sid_to_unixuid(sidmap, &r->in.sid, &uid);
NT_STATUS_NOT_OK_RETURN(status);
*r->out.uid = uid;
return NT_STATUS_OK;
}
static NTSTATUS unixinfo_UidToSid(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct unixinfo_UidToSid *r)
{
struct sidmap_context *sidmap;
uid_t uid;
sidmap = sidmap_open(mem_ctx);
if (sidmap == NULL) {
DEBUG(10, ("sidmap_open failed\n"));
return NT_STATUS_NO_MEMORY;
}
uid = r->in.uid; /* This cuts uid to (probably) 32 bit */
if ((uint64_t)uid != r->in.uid) {
DEBUG(10, ("uid out of range\n"));
return NT_STATUS_INVALID_PARAMETER;
}
return sidmap_uid_to_sid(sidmap, mem_ctx, uid, &r->out.sid);
}
static NTSTATUS unixinfo_SidToGid(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct unixinfo_SidToGid *r)
{
NTSTATUS status;
struct sidmap_context *sidmap;
gid_t gid;
sidmap = sidmap_open(mem_ctx);
if (sidmap == NULL) {
DEBUG(10, ("sidmap_open failed\n"));
return NT_STATUS_NO_MEMORY;
}
status = sidmap_sid_to_unixgid(sidmap, &r->in.sid, &gid);
NT_STATUS_NOT_OK_RETURN(status);
*r->out.gid = gid;
return NT_STATUS_OK;
}
static NTSTATUS unixinfo_GidToSid(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct unixinfo_GidToSid *r)
{
struct sidmap_context *sidmap;
gid_t gid;
sidmap = sidmap_open(mem_ctx);
if (sidmap == NULL) {
DEBUG(10, ("sidmap_open failed\n"));
return NT_STATUS_NO_MEMORY;
}
gid = r->in.gid; /* This cuts gid to (probably) 32 bit */
if ((uint64_t)gid != r->in.gid) {
DEBUG(10, ("gid out of range\n"));
return NT_STATUS_INVALID_PARAMETER;
}
return sidmap_gid_to_sid(sidmap, mem_ctx, gid, &r->out.sid);
}
static NTSTATUS unixinfo_GetPWUid(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct unixinfo_GetPWUid *r)
{
int i;
*r->out.count = 0;
r->out.infos = talloc_zero_array(mem_ctx, struct unixinfo_GetPWUidInfo,
*r->in.count);
NT_STATUS_HAVE_NO_MEMORY(r->out.infos);
*r->out.count = *r->in.count;
for (i=0; i < *r->in.count; i++) {
uid_t uid;
struct passwd *pwd;
uid = r->in.uids[i];
pwd = getpwuid(uid);
if (pwd == NULL) {
DEBUG(10, ("uid %d not found\n", uid));
r->out.infos[i].homedir = "";
r->out.infos[i].shell = "";
r->out.infos[i].status = NT_STATUS_NO_SUCH_USER;
continue;
}
r->out.infos[i].homedir = talloc_strdup(mem_ctx, pwd->pw_dir);
r->out.infos[i].shell = talloc_strdup(mem_ctx, pwd->pw_shell);
if ((r->out.infos[i].homedir == NULL) ||
(r->out.infos[i].shell == NULL)) {
r->out.infos[i].homedir = "";
r->out.infos[i].shell = "";
r->out.infos[i].status = NT_STATUS_NO_MEMORY;
continue;
}
r->out.infos[i].status = NT_STATUS_OK;
}
return NT_STATUS_OK;
}
/* include the generated boilerplate */
#include "librpc/gen_ndr/ndr_unixinfo_s.c"
+3
View File
@@ -0,0 +1,3 @@
This is the RPC server for the registry for Samba. It is basically a
front-end for the registry library in lib/registry. See
lib/registry/README for more details.
+579
View File
@@ -0,0 +1,579 @@
/*
Unix SMB/CIFS implementation.
endpoint server for the winreg pipe
Copyright (C) Jelmer Vernooij 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 "rpc_server/dcerpc_server.h"
#include "lib/registry/registry.h"
#include "librpc/gen_ndr/ndr_winreg.h"
#include "rpc_server/common/common.h"
#include "librpc/gen_ndr/ndr_security.h"
enum handle_types { HTYPE_REGVAL, HTYPE_REGKEY };
static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
{
struct registry_context *ctx;
WERROR err;
err = reg_open_local(dce_call->context,
&ctx, dce_call->conn->auth_state.session_info, NULL);
dce_call->context->private = ctx;
return NT_STATUS_OK;
}
#define DCESRV_INTERFACE_WINREG_BIND dcerpc_winreg_bind
static WERROR winreg_openhive (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, uint32_t hkey, struct policy_handle **outh)
{
struct registry_context *ctx = dce_call->context->private;
struct dcesrv_handle *h;
WERROR error;
h = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
error = reg_get_predefined_key(ctx, hkey, (struct registry_key **)&h->data);
if (!W_ERROR_IS_OK(error)) {
return error;
}
*outh = &h->wire_handle;
return error;
}
#define func_winreg_OpenHive(k,n) static WERROR winreg_Open ## k (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_Open ## k *r) \
{ \
return winreg_openhive (dce_call, mem_ctx, n, &r->out.handle);\
}
func_winreg_OpenHive(HKCR,HKEY_CLASSES_ROOT)
func_winreg_OpenHive(HKCU,HKEY_CURRENT_USER)
func_winreg_OpenHive(HKLM,HKEY_LOCAL_MACHINE)
func_winreg_OpenHive(HKPD,HKEY_PERFORMANCE_DATA)
func_winreg_OpenHive(HKU,HKEY_USERS)
func_winreg_OpenHive(HKCC,HKEY_CURRENT_CONFIG)
func_winreg_OpenHive(HKDD,HKEY_DYN_DATA)
func_winreg_OpenHive(HKPT,HKEY_PERFORMANCE_TEXT)
func_winreg_OpenHive(HKPN,HKEY_PERFORMANCE_NLSTEXT)
/*
winreg_CloseKey
*/
static WERROR winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_CloseKey *r)
{
struct dcesrv_handle *h;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
talloc_free(h);
ZERO_STRUCTP(r->out.handle);
return WERR_OK;
}
/*
winreg_CreateKey
*/
static WERROR winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_CreateKey *r)
{
struct dcesrv_handle *h, *newh;
WERROR error;
struct security_descriptor sd;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
/* the security descriptor is optional */
if (r->in.secdesc != NULL) {
DATA_BLOB sdblob;
NTSTATUS status;
sdblob.data = r->in.secdesc->sd.data;
sdblob.length = r->in.secdesc->sd.len;
if (sdblob.data == NULL) {
return WERR_INVALID_PARAM;
}
status = ndr_pull_struct_blob_all(&sdblob, mem_ctx, &sd,
(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
if (!NT_STATUS_IS_OK(status)) {
return WERR_INVALID_PARAM;
}
}
error = reg_key_add_name(newh, (struct registry_key *)h->data, r->in.name.name,
r->in.access_mask,
r->in.secdesc?&sd:NULL,
(struct registry_key **)&newh->data);
if (W_ERROR_IS_OK(error)) {
r->out.new_handle = &newh->wire_handle;
} else {
talloc_free(newh);
}
return error;
}
/*
winreg_DeleteKey
*/
static WERROR winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_DeleteKey *r)
{
struct dcesrv_handle *h;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
return reg_key_del((struct registry_key *)h->data, r->in.key.name);
}
/*
winreg_DeleteValue
*/
static WERROR winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_DeleteValue *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
key = h->data;
return reg_del_value(key, r->in.value.name);
}
/*
winreg_EnumKey
*/
static WERROR winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_EnumKey *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
r->out.result = reg_key_get_subkey_by_index(mem_ctx, (struct registry_key *)h->data, r->in.enum_index, &key);
if (W_ERROR_IS_OK(r->out.result)) {
if (2*strlen_m_term(key->name) > r->in.name->size) {
return WERR_MORE_DATA;
}
r->out.name->length = 2*strlen_m_term(key->name);
r->out.name->name = key->name;
r->out.keyclass = talloc_zero(mem_ctx, struct winreg_StringBuf);
if (r->in.last_changed_time) {
r->out.last_changed_time = &key->last_mod;
}
}
return r->out.result;
}
/*
winreg_EnumValue
*/
static WERROR winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_EnumValue *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
struct registry_value *value;
WERROR result;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
key = h->data;
result = reg_key_get_value_by_index(mem_ctx, key, r->in.enum_index, &value);
if (!W_ERROR_IS_OK(result)) {
return result;
}
/* the client can optionally pass a NULL for type, meaning they don't
want that back */
if (r->in.type != NULL) {
r->out.type = talloc(mem_ctx, enum winreg_Type);
*r->out.type = value->data_type;
}
/* check the client has enough room for the value */
if (r->in.value != NULL &&
r->in.size != NULL &&
value->data.length > *r->in.size) {
return WERR_MORE_DATA;
}
/* and enough room for the name */
if (r->in.name->size < 2*strlen_m_term(value->name)) {
return WERR_MORE_DATA;
}
r->out.name->name = value->name;
r->out.name->length = 2*strlen_m_term(value->name);
r->out.name->size = 2*strlen_m_term(value->name);
if (r->in.value) {
r->out.value = value->data.data;
}
if (r->in.size) {
r->out.size = talloc(mem_ctx, uint32_t);
*r->out.size = value->data.length;
r->out.length = r->out.size;
}
return WERR_OK;
}
/*
winreg_FlushKey
*/
static WERROR winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_FlushKey *r)
{
struct dcesrv_handle *h;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
return reg_key_flush(h->data);
}
/*
winreg_GetKeySecurity
*/
static WERROR winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_GetKeySecurity *r)
{
struct dcesrv_handle *h;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
return WERR_NOT_SUPPORTED;
}
/*
winreg_LoadKey
*/
static WERROR winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_LoadKey *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_NotifyChangeKeyValue
*/
static WERROR winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_NotifyChangeKeyValue *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_OpenKey
*/
static WERROR winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_OpenKey *r)
{
struct dcesrv_handle *h, *newh;
WERROR result;
DCESRV_PULL_HANDLE_FAULT(h, r->in.parent_handle, HTYPE_REGKEY);
if (r->in.keyname.name && strcmp(r->in.keyname.name, "") == 0) {
newh = talloc_reference(dce_call->context, h);
result = WERR_OK;
} else {
newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
result = reg_open_key(newh, (struct registry_key *)h->data,
r->in.keyname.name, (struct registry_key **)&newh->data);
}
if (W_ERROR_IS_OK(result)) {
r->out.handle = &newh->wire_handle;
} else {
talloc_free(newh);
}
return result;
}
/*
winreg_QueryInfoKey
*/
static WERROR winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryInfoKey *r)
{
struct dcesrv_handle *h;
struct registry_key *k;
WERROR ret;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
k = h->data;
ret = reg_key_num_subkeys(k, r->out.num_subkeys);
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
ret = reg_key_num_values(k, r->out.num_values);
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
ret = reg_key_subkeysizes(k, r->out.max_subkeysize, r->out.max_subkeylen);
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
ret = reg_key_valuesizes(k, r->out.max_valnamelen, r->out.max_valbufsize);
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
r->out.secdescsize = 0; /* FIXME */
ZERO_STRUCT(r->out.last_changed_time); /* FIXME */
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
return WERR_OK;
}
/*
winreg_QueryValue
*/
static WERROR winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryValue *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
struct registry_value *val;
WERROR result;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
key = h->data;
result = reg_key_get_value_by_name(mem_ctx, key, r->in.value_name.name, &val);
if (!W_ERROR_IS_OK(result)) {
return result;
}
/* Just asking for the size of the buffer */
r->out.type = (enum winreg_Type *)&val->data_type;
r->out.length = talloc(mem_ctx, uint32_t);
if (!r->out.length) {
return WERR_NOMEM;
}
*r->out.length = val->data.length;
if (!r->in.data) {
r->out.size = talloc(mem_ctx, uint32_t);
*r->out.size = val->data.length;
} else {
r->out.size = r->in.size;
r->out.data = val->data.data;
}
return WERR_OK;
}
/*
winreg_ReplaceKey
*/
static WERROR winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_ReplaceKey *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_RestoreKey
*/
static WERROR winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_RestoreKey *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_SaveKey
*/
static WERROR winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_SaveKey *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_SetKeySecurity
*/
static WERROR winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_SetKeySecurity *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_SetValue
*/
static WERROR winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_SetValue *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
WERROR result;
DATA_BLOB data;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
key = h->data;
data.data = r->in.data;
data.length = r->in.size;
result = reg_val_set(key, r->in.name.name, r->in.type, data);
if (!W_ERROR_IS_OK(result)) {
return result;
}
return WERR_OK;
}
/*
winreg_UnLoadKey
*/
static WERROR winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_UnLoadKey *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_InitiateSystemShutdown
*/
static WERROR winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_InitiateSystemShutdown *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_AbortSystemShutdown
*/
static WERROR winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_AbortSystemShutdown *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_GetVersion
*/
static WERROR winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_GetVersion *r)
{
struct dcesrv_handle *h;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
r->out.version = talloc(mem_ctx, uint32_t);
W_ERROR_HAVE_NO_MEMORY(r->out.version);
*r->out.version = 5;
return WERR_OK;
}
/*
winreg_QueryMultipleValues
*/
static WERROR winreg_QueryMultipleValues(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryMultipleValues *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_InitiateSystemShutdownEx
*/
static WERROR winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_InitiateSystemShutdownEx *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_SaveKeyEx
*/
static WERROR winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_SaveKeyEx *r)
{
return WERR_NOT_SUPPORTED;
}
/*
winreg_QueryMultipleValues2
*/
static WERROR winreg_QueryMultipleValues2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryMultipleValues2 *r)
{
return WERR_NOT_SUPPORTED;
}
/* include the generated boilerplate */
#include "librpc/gen_ndr/ndr_winreg_s.c"
@@ -0,0 +1,417 @@
/*
Unix SMB/CIFS implementation.
endpoint server for the wkssvc pipe
Copyright (C) Stefan (metze) 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 "rpc_server/dcerpc_server.h"
#include "librpc/gen_ndr/ndr_wkssvc.h"
#include "rpc_server/common/common.h"
/*
wkssvc_NetWkstaGetInfo
*/
static WERROR wkssvc_NetWkstaGetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetWkstaGetInfo *r)
{
struct dcesrv_context *dce_ctx = dce_call->conn->dce_ctx;
ZERO_STRUCT(r->out);
r->out.info = talloc_zero(mem_ctx, union wkssvc_NetWkstaInfo);
W_ERROR_HAVE_NO_MEMORY(r->out.info);
/* NOTE: win2k3 ignores r->in.server_name completly so we do --metze */
switch(r->in.level) {
case 100:
{
struct wkssvc_NetWkstaInfo100 *info100;
info100 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo100);
W_ERROR_HAVE_NO_MEMORY(info100);
info100->platform_id = dcesrv_common_get_platform_id(mem_ctx, dce_ctx);
info100->server_name = dcesrv_common_get_server_name(mem_ctx, dce_ctx, NULL);
W_ERROR_HAVE_NO_MEMORY(info100->server_name);
info100->domain_name = dcesrv_common_get_domain_name(mem_ctx, dce_ctx);
W_ERROR_HAVE_NO_MEMORY(info100->domain_name);
info100->version_major = dcesrv_common_get_version_major(mem_ctx, dce_ctx);
info100->version_minor = dcesrv_common_get_version_minor(mem_ctx, dce_ctx);
r->out.info->info100 = info100;
return WERR_OK;
}
case 101:
{
struct wkssvc_NetWkstaInfo101 *info101;
info101 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo101);
W_ERROR_HAVE_NO_MEMORY(info101);
info101->platform_id = dcesrv_common_get_platform_id(mem_ctx, dce_ctx);
info101->server_name = dcesrv_common_get_server_name(mem_ctx, dce_ctx, NULL);
W_ERROR_HAVE_NO_MEMORY(info101->server_name);
info101->domain_name = dcesrv_common_get_domain_name(mem_ctx, dce_ctx);
W_ERROR_HAVE_NO_MEMORY(info101->domain_name);
info101->version_major = dcesrv_common_get_version_major(mem_ctx, dce_ctx);
info101->version_minor = dcesrv_common_get_version_minor(mem_ctx, dce_ctx);
info101->lan_root = dcesrv_common_get_lan_root(mem_ctx, dce_ctx);
r->out.info->info101 = info101;
return WERR_OK;
}
case 102:
{
return WERR_ACCESS_DENIED;
}
case 502:
{
return WERR_ACCESS_DENIED;
}
default:
return WERR_UNKNOWN_LEVEL;
}
return WERR_UNKNOWN_LEVEL;
}
/*
wkssvc_NetWkstaSetInfo
*/
static WERROR wkssvc_NetWkstaSetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetWkstaSetInfo *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
wkssvc_NetWkstaEnumUsers
*/
static WERROR wkssvc_NetWkstaEnumUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetWkstaEnumUsers *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRWKSTAUSERGETINFO
*/
static WERROR WKSSVC_NETRWKSTAUSERGETINFO(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRWKSTAUSERGETINFO *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRWKSTAUSERSETINFO
*/
static WERROR WKSSVC_NETRWKSTAUSERSETINFO(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRWKSTAUSERSETINFO *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
wkssvc_NetWkstaTransportEnum
*/
static WERROR wkssvc_NetWkstaTransportEnum(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetWkstaTransportEnum *r)
{
r->out.level = r->in.level;
r->out.totalentries = 0;
r->out.resume_handle = NULL;
switch (r->in.level) {
case 0:
r->out.ctr = talloc(mem_ctx, union wkssvc_NetWkstaTransportCtr);
W_ERROR_HAVE_NO_MEMORY(r->out.ctr);
r->out.ctr->ctr0 = talloc(mem_ctx, struct wkssvc_NetWkstaTransportCtr0);
W_ERROR_HAVE_NO_MEMORY(r->out.ctr->ctr0);
r->out.ctr->ctr0->count = 0;
r->out.ctr->ctr0->array = NULL;
return WERR_NOT_SUPPORTED;
default:
return WERR_UNKNOWN_LEVEL;
}
return WERR_UNKNOWN_LEVEL;
}
/*
WKSSVC_NETRWKSTATRANSPORTADD
*/
static WERROR WKSSVC_NETRWKSTATRANSPORTADD(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRWKSTATRANSPORTADD *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRWKSTATRANSPORTDEL
*/
static WERROR WKSSVC_NETRWKSTATRANSPORTDEL(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRWKSTATRANSPORTDEL *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRUSEADD
*/
static WERROR WKSSVC_NETRUSEADD(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRUSEADD *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRUSEGETINFO
*/
static WERROR WKSSVC_NETRUSEGETINFO(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRUSEGETINFO *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRUSEDEL
*/
static WERROR WKSSVC_NETRUSEDEL(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRUSEDEL *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRUSEENUM
*/
static WERROR WKSSVC_NETRUSEENUM(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRUSEENUM *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRMESSAGEBUFFERSEND
*/
static WERROR WKSSVC_NETRMESSAGEBUFFERSEND(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRMESSAGEBUFFERSEND *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRWORKSTATIONSTATISTICSGET
*/
static WERROR WKSSVC_NETRWORKSTATIONSTATISTICSGET(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRWORKSTATIONSTATISTICSGET *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRLOGONDOMAINNAMEADD
*/
static WERROR WKSSVC_NETRLOGONDOMAINNAMEADD(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRLOGONDOMAINNAMEADD *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRLOGONDOMAINNAMEDEL
*/
static WERROR WKSSVC_NETRLOGONDOMAINNAMEDEL(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRLOGONDOMAINNAMEDEL *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRJOINDOMAIN
*/
static WERROR WKSSVC_NETRJOINDOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRJOINDOMAIN *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRUNJOINDOMAIN
*/
static WERROR WKSSVC_NETRUNJOINDOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRUNJOINDOMAIN *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRRENAMEMACHINEINDOMAIN
*/
static WERROR WKSSVC_NETRRENAMEMACHINEINDOMAIN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRRENAMEMACHINEINDOMAIN *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRVALIDATENAME
*/
static WERROR WKSSVC_NETRVALIDATENAME(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRVALIDATENAME *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRGETJOININFORMATION
*/
static WERROR WKSSVC_NETRGETJOININFORMATION(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRGETJOININFORMATION *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRGETJOINABLEOUS
*/
static WERROR WKSSVC_NETRGETJOINABLEOUS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRGETJOINABLEOUS *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRJOINDOMAIN2
*/
static WERROR wkssvc_NetrJoinDomain2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetrJoinDomain2 *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRUNJOINDOMAIN2
*/
static WERROR wkssvc_NetrUnjoinDomain2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetrUnjoinDomain2 *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRRENAMEMACHINEINDOMAIN2
*/
static WERROR wkssvc_NetrRenameMachineInDomain2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetrRenameMachineInDomain2 *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRVALIDATENAME2
*/
static WERROR WKSSVC_NETRVALIDATENAME2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRVALIDATENAME2 *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRGETJOINABLEOUS2
*/
static WERROR WKSSVC_NETRGETJOINABLEOUS2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRGETJOINABLEOUS2 *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRADDALTERNATECOMPUTERNAME
*/
static WERROR wkssvc_NetrAddAlternateComputerName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetrAddAlternateComputerName *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRREMOVEALTERNATECOMPUTERNAME
*/
static WERROR wkssvc_NetrRemoveAlternateComputerName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct wkssvc_NetrRemoveAlternateComputerName *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRSETPRIMARYCOMPUTERNAME
*/
static WERROR WKSSVC_NETRSETPRIMARYCOMPUTERNAME(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRSETPRIMARYCOMPUTERNAME *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/*
WKSSVC_NETRENUMERATECOMPUTERNAMES
*/
static WERROR WKSSVC_NETRENUMERATECOMPUTERNAMES(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct WKSSVC_NETRENUMERATECOMPUTERNAMES *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
}
/* include the generated boilerplate */
#include "librpc/gen_ndr/ndr_wkssvc_s.c"