wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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"
|
||||
@@ -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
@@ -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"
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user