summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c42
-rw-r--r--source4/heimdal/lib/gssapi/krb5/creds.c1
-rw-r--r--source4/libcli/security/tests/bindings.py17
-rw-r--r--source4/librpc/ndr/py_security.c4
-rw-r--r--source4/ntvfs/config.mk4
-rw-r--r--source4/ntvfs/ipc/vfs_ipc.c884
-rw-r--r--source4/rpc_server/config.mk3
-rw-r--r--source4/rpc_server/dcerpc_server.c184
-rw-r--r--source4/rpc_server/dcerpc_server.h15
-rw-r--r--source4/rpc_server/service_rpc.c11
-rwxr-xr-xsource4/scripting/bin/fullschema2
-rwxr-xr-xsource4/scripting/bin/minschema2
-rwxr-xr-xsource4/scripting/bin/reorgldb.py60
-rw-r--r--source4/scripting/python/samba/idmap.py2
-rw-r--r--source4/scripting/python/samba/provision.py13
-rw-r--r--source4/scripting/python/samba/samdb.py90
-rwxr-xr-xsource4/setup/domainlevel187
-rwxr-xr-xsource4/setup/enableaccount72
-rwxr-xr-xsource4/setup/newuser10
-rw-r--r--source4/setup/provision.ldif15
-rw-r--r--source4/setup/provision_configuration.ldif263
-rw-r--r--source4/setup/provision_self_join.ldif82
-rwxr-xr-xsource4/setup/pwsettings47
-rwxr-xr-xsource4/setup/setexpiry50
-rwxr-xr-xsource4/setup/setpassword14
-rw-r--r--source4/smbd/config.mk4
-rw-r--r--source4/smbd/service_named_pipe.c100
-rw-r--r--source4/torture/rpc/spoolss_notify.c26
28 files changed, 1571 insertions, 633 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 26703528a7..283bdf7806 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -2123,7 +2123,9 @@ linked_attributes[0]:
talloc_free(tmp_ctx);
return ret;
}
- ret_el->values = talloc_array(msg, struct ldb_val, 1);
+ /* we allocate two entries here, in case we need a remove/add
+ pair */
+ ret_el->values = talloc_array(msg, struct ldb_val, 2);
if (!ret_el->values) {
ldb_oom(ldb);
talloc_free(tmp_ctx);
@@ -2168,10 +2170,48 @@ linked_attributes[0]:
ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
}
+ if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
+ /* the link destination exists, we need to update it
+ * by deleting the old one for the same DN then adding
+ * the new one */
+ msg->elements = talloc_realloc(msg, msg->elements,
+ struct ldb_message_element,
+ msg->num_elements+1);
+ if (msg->elements == NULL) {
+ ldb_oom(ldb);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /* this relies on the backend matching the old entry
+ only by the DN portion of the extended DN */
+ msg->elements[1] = msg->elements[0];
+ msg->elements[0].flags = LDB_FLAG_MOD_DELETE;
+ msg->num_elements++;
+
+ ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
+ msg,
+ NULL,
+ NULL,
+ ldb_op_default_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* Run the new request */
+ ret = ldb_next_request(module, mod_req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
+ }
+ }
+
if (ret != LDB_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
ldb_errstring(ldb),
ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
+ ret = LDB_SUCCESS;
}
talloc_free(tmp_ctx);
diff --git a/source4/heimdal/lib/gssapi/krb5/creds.c b/source4/heimdal/lib/gssapi/krb5/creds.c
index c9befe9d77..68cb766bc3 100644
--- a/source4/heimdal/lib/gssapi/krb5/creds.c
+++ b/source4/heimdal/lib/gssapi/krb5/creds.c
@@ -249,5 +249,6 @@ _gsskrb5_import_cred(OM_uint32 * minor_status,
handle->ccache = id;
handle->cred_flags = flags;
+ *cred_handle = (gss_cred_id_t)handle;
return GSS_S_COMPLETE;
}
diff --git a/source4/libcli/security/tests/bindings.py b/source4/libcli/security/tests/bindings.py
index f0d55f12ca..00fa05d070 100644
--- a/source4/libcli/security/tests/bindings.py
+++ b/source4/libcli/security/tests/bindings.py
@@ -57,6 +57,16 @@ class SecurityDescriptorTests(unittest.TestCase):
self.assertEquals(desc.sacl, None)
self.assertEquals(desc.type, 0x8004)
+ def test_from_sddl_invalidsddl(self):
+ self.assertRaises(TypeError,security.descriptor.from_sddl, "foo",security.dom_sid("S-2-0-0"))
+
+ def test_from_sddl_invalidtype1(self):
+ self.assertRaises(TypeError,security.descriptor.from_sddl, security.dom_sid('S-2-0-0-512'),security.dom_sid("S-2-0-0"))
+
+ def test_from_sddl_invalidtype1(self):
+ sddl = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
+ self.assertRaises(TypeError,security.descriptor.from_sddl, sddl,"S-2-0-0")
+
def test_as_sddl(self):
text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
dom = security.dom_sid("S-2-0-0")
@@ -67,6 +77,13 @@ class SecurityDescriptorTests(unittest.TestCase):
self.assertEquals(desc1.sacl, desc2.sacl)
self.assertEquals(desc1.type, desc2.type)
+ def test_as_sddl_invalid(self):
+ text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
+ dom = security.dom_sid("S-2-0-0")
+ desc1 = security.descriptor.from_sddl(text, dom)
+ self.assertRaises(TypeError, desc1.as_sddl,text)
+
+
def test_as_sddl_no_domainsid(self):
dom = security.dom_sid("S-2-0-0")
text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
diff --git a/source4/librpc/ndr/py_security.c b/source4/librpc/ndr/py_security.c
index 8ab790d470..02dc059f05 100644
--- a/source4/librpc/ndr/py_security.c
+++ b/source4/librpc/ndr/py_security.c
@@ -173,7 +173,7 @@ static PyObject *py_descriptor_from_sddl(PyObject *self, PyObject *args)
PyObject *py_sid;
struct dom_sid *sid;
- if (!PyArg_ParseTuple(args, "sO", &sddl, &py_sid))
+ if (!PyArg_ParseTuple(args, "sO!", &sddl, &dom_sid_Type, &py_sid))
return NULL;
sid = py_talloc_get_ptr(py_sid);
@@ -195,7 +195,7 @@ static PyObject *py_descriptor_as_sddl(PyObject *self, PyObject *args)
char *text;
PyObject *ret;
- if (!PyArg_ParseTuple(args, "|O", &py_sid))
+ if (!PyArg_ParseTuple(args, "|O!", &dom_sid_Type, &py_sid))
return NULL;
if (py_sid != Py_None)
diff --git a/source4/ntvfs/config.mk b/source4/ntvfs/config.mk
index 593c526edb..060ee19115 100644
--- a/source4/ntvfs/config.mk
+++ b/source4/ntvfs/config.mk
@@ -71,7 +71,9 @@ ntvfs_print_OBJ_FILES = $(ntvfssrcdir)/print/vfs_print.o
[MODULE::ntvfs_ipc]
SUBSYSTEM = ntvfs
INIT_FUNCTION = ntvfs_ipc_init
-PRIVATE_DEPENDENCIES = dcerpc_server DCERPC_COMMON
+PRIVATE_DEPENDENCIES = \
+ NDR_NAMED_PIPE_AUTH NAMED_PIPE_AUTH_TSTREAM \
+ HEIMDAL_GSSAPI CREDENTIALS
# End MODULE ntvfs_ipc
################################################
diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c
index 95ad1c51fb..0cd909e351 100644
--- a/source4/ntvfs/ipc/vfs_ipc.c
+++ b/source4/ntvfs/ipc/vfs_ipc.c
@@ -29,9 +29,16 @@
#include "ntvfs/ntvfs.h"
#include "libcli/rap/rap.h"
#include "ntvfs/ipc/proto.h"
-#include "rpc_server/dcerpc_server.h"
#include "libcli/raw/ioctl.h"
#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/named_pipe_auth/npa_tstream.h"
+#include "auth/auth.h"
+#include "auth/auth_sam_reply.h"
+#include "lib/socket/socket.h"
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+#include <gssapi/gssapi.h>
/* this is the private structure used to keep the state of an open
ipc$ connection. It needs to keep information about all open
@@ -39,16 +46,18 @@
struct ipc_private {
struct ntvfs_module_context *ntvfs;
- struct dcesrv_context *dcesrv;
-
/* a list of open pipes */
struct pipe_state {
struct pipe_state *next, *prev;
struct ipc_private *ipriv;
const char *pipe_name;
struct ntvfs_handle *handle;
- struct dcesrv_connection *dce_conn;
- uint16_t ipc_state;
+ struct tstream_context *npipe;
+ uint16_t file_type;
+ uint16_t device_state;
+ uint64_t allocation_size;
+ struct tevent_queue *write_queue;
+ struct tevent_queue *read_queue;
} *pipe_list;
};
@@ -91,7 +100,6 @@ static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req,
union smb_tcon* tcon)
{
- NTSTATUS status;
struct ipc_private *ipriv;
const char *sharename;
@@ -136,10 +144,6 @@ static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
ipriv->ntvfs = ntvfs;
ipriv->pipe_list = NULL;
- /* setup the DCERPC server subsystem */
- status = dcesrv_init_ipc_context(ipriv, ntvfs->ctx->lp_ctx, &ipriv->dcesrv);
- NT_STATUS_NOT_OK_RETURN(status);
-
return NT_STATUS_OK;
}
@@ -207,32 +211,61 @@ static int ipc_fd_destructor(struct pipe_state *p)
return 0;
}
-static struct socket_address *ipc_get_my_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
-{
- struct ipc_private *ipriv = dce_conn->transport.private_data;
-
- return ntvfs_get_my_addr(ipriv->ntvfs, mem_ctx);
-}
-
-static struct socket_address *ipc_get_peer_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
-{
- struct ipc_private *ipriv = dce_conn->transport.private_data;
+struct ipc_open_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ union smb_open *oi;
+ struct netr_SamInfo3 *info3;
+};
- return ntvfs_get_peer_addr(ipriv->ntvfs, mem_ctx);
-}
+static void ipc_open_done(struct tevent_req *subreq);
/*
- open a file backend - used for MSRPC pipes
+ open a file - used for MSRPC pipes
*/
-static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
- struct ntvfs_request *req, const char *fname,
- struct pipe_state **ps)
+static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_open *oi)
{
- struct pipe_state *p;
NTSTATUS status;
- struct dcerpc_binding *ep_description;
- struct ipc_private *ipriv = ntvfs->private_data;
+ struct pipe_state *p;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
+ struct smb_iconv_convenience *smb_ic
+ = lp_iconv_convenience(ipriv->ntvfs->ctx->lp_ctx);
struct ntvfs_handle *h;
+ struct ipc_open_state *state;
+ struct tevent_req *subreq;
+ const char *fname;
+ const char *directory;
+ struct socket_address *client_sa;
+ struct tsocket_address *client_addr;
+ struct socket_address *server_sa;
+ struct tsocket_address *server_addr;
+ int ret;
+ DATA_BLOB delegated_creds = data_blob_null;
+
+ switch (oi->generic.level) {
+ case RAW_OPEN_NTCREATEX:
+ fname = oi->ntcreatex.in.fname;
+ break;
+ case RAW_OPEN_OPENX:
+ fname = oi->openx.in.fname;
+ break;
+ case RAW_OPEN_SMB2:
+ fname = oi->smb2.in.fname;
+ break;
+ default:
+ status = NT_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ directory = talloc_asprintf(req, "%s/np",
+ lp_ncalrpc_dir(ipriv->ntvfs->ctx->lp_ctx));
+ NT_STATUS_HAVE_NO_MEMORY(directory);
+
+ state = talloc(req, struct ipc_open_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
status = ntvfs_handle_new(ntvfs, req, &h);
NT_STATUS_NOT_OK_RETURN(status);
@@ -240,156 +273,192 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
p = talloc(h, struct pipe_state);
NT_STATUS_HAVE_NO_MEMORY(p);
- ep_description = talloc(req, struct dcerpc_binding);
- NT_STATUS_HAVE_NO_MEMORY(ep_description);
-
while (fname[0] == '\\') fname++;
p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
p->handle = h;
- p->ipc_state = 0x5ff;
-
- /*
- we're all set, now ask the dcerpc server subsystem to open the
- endpoint. At this stage the pipe isn't bound, so we don't
- know what interface the user actually wants, just that they want
- one of the interfaces attached to this pipe endpoint.
- */
- ep_description->transport = NCACN_NP;
- ep_description->endpoint = talloc_strdup(ep_description, p->pipe_name);
- NT_STATUS_HAVE_NO_MEMORY(ep_description->endpoint);
-
- /* The session info is refcount-increased in the
- * dcesrv_endpoint_search_connect() function
- */
- status = dcesrv_endpoint_search_connect(ipriv->dcesrv,
- p,
- ep_description,
- h->session_info,
- ntvfs->ctx->event_ctx,
- ntvfs->ctx->msg_ctx,
- ntvfs->ctx->server_id,
- 0,
- &p->dce_conn);
- NT_STATUS_NOT_OK_RETURN(status);
+ p->ipriv = ipriv;
- p->dce_conn->transport.private_data = ipriv;
- p->dce_conn->transport.report_output_data = NULL;
- p->dce_conn->transport.get_my_addr = ipc_get_my_addr;
- p->dce_conn->transport.get_peer_addr = ipc_get_peer_addr;
-
- DLIST_ADD(ipriv->pipe_list, p);
+ p->write_queue = tevent_queue_create(p, "ipc_write_queue");
+ NT_STATUS_HAVE_NO_MEMORY(p->write_queue);
- p->ipriv = ipriv;
+ p->read_queue = tevent_queue_create(p, "ipc_read_queue");
+ NT_STATUS_HAVE_NO_MEMORY(p->read_queue);
- talloc_set_destructor(p, ipc_fd_destructor);
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->oi = oi;
- status = ntvfs_handle_set_backend_data(h, ipriv->ntvfs, p);
+ status = auth_convert_server_info_saminfo3(state,
+ req->session_info->server_info,
+ &state->info3);
NT_STATUS_NOT_OK_RETURN(status);
- *ps = p;
- return NT_STATUS_OK;
-}
+ client_sa = ntvfs_get_peer_addr(ntvfs, state);
+ if (!client_sa) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
-/*
- open a file with ntcreatex - used for MSRPC pipes
-*/
-static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
- struct ntvfs_request *req, union smb_open *oi)
-{
- struct pipe_state *p;
- NTSTATUS status;
+ server_sa = ntvfs_get_my_addr(ntvfs, state);
+ if (!server_sa) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
- status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
- if (!NT_STATUS_IS_OK(status)) {
+ ret = tsocket_address_inet_from_strings(state, "ip",
+ client_sa->addr,
+ client_sa->port,
+ &client_addr);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
return status;
}
- ZERO_STRUCT(oi->ntcreatex.out);
- oi->ntcreatex.out.file.ntvfs= p->handle;
- oi->ntcreatex.out.ipc_state = p->ipc_state;
- oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
+ ret = tsocket_address_inet_from_strings(state, "ip",
+ server_sa->addr,
+ server_sa->port,
+ &server_addr);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ return status;
+ }
- return status;
-}
+ if (req->session_info->credentials) {
+ struct gssapi_creds_container *gcc;
+ OM_uint32 gret;
+ OM_uint32 minor_status;
+ gss_buffer_desc cred_token;
+
+ ret = cli_credentials_get_client_gss_creds(req->session_info->credentials,
+ ipriv->ntvfs->ctx->event_ctx,
+ ipriv->ntvfs->ctx->lp_ctx,
+ &gcc);
+ if (ret) {
+ goto skip;
+ }
-/*
- open a file with openx - used for MSRPC pipes
-*/
-static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
- struct ntvfs_request *req, union smb_open *oi)
-{
- struct pipe_state *p;
- NTSTATUS status;
- const char *fname = oi->openx.in.fname;
+ gret = gss_export_cred(&minor_status,
+ gcc->creds,
+ &cred_token);
+ if (gret != GSS_S_COMPLETE) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
- status = ipc_open_generic(ntvfs, req, fname, &p);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (cred_token.length) {
+ delegated_creds = data_blob_talloc(req,
+ cred_token.value,
+ cred_token.length);
+ gss_release_buffer(&minor_status, &cred_token);
+ NT_STATUS_HAVE_NO_MEMORY(delegated_creds.data);
+ }
}
- ZERO_STRUCT(oi->openx.out);
- oi->openx.out.file.ntvfs= p->handle;
- oi->openx.out.ftype = 2;
- oi->openx.out.devstate = p->ipc_state;
-
- return status;
+skip:
+
+ subreq = tstream_npa_connect_send(p,
+ ipriv->ntvfs->ctx->event_ctx,
+ smb_ic,
+ directory,
+ fname,
+ client_addr,
+ NULL,
+ server_addr,
+ NULL,
+ state->info3,
+ req->session_info->session_key,
+ delegated_creds);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_open_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
}
-/*
- open a file with SMB2 Create - used for MSRPC pipes
-*/
-static NTSTATUS ipc_open_smb2(struct ntvfs_module_context *ntvfs,
- struct ntvfs_request *req, union smb_open *oi)
+static void ipc_open_done(struct tevent_req *subreq)
{
- struct pipe_state *p;
+ struct ipc_open_state *state = tevent_req_callback_data(subreq,
+ struct ipc_open_state);
+ struct ipc_private *ipriv = state->ipriv;
+ struct pipe_state *p = state->p;
+ struct ntvfs_request *req = state->req;
+ union smb_open *oi = state->oi;
+ int ret;
+ int sys_errno;
NTSTATUS status;
- status = ipc_open_generic(ntvfs, req, oi->smb2.in.fname, &p);
- NT_STATUS_NOT_OK_RETURN(status);
-
- ZERO_STRUCT(oi->smb2.out);
- oi->smb2.out.file.ntvfs = p->handle;
- oi->smb2.out.oplock_level = oi->smb2.in.oplock_level;
- oi->smb2.out.create_action = NTCREATEX_ACTION_EXISTED;
- oi->smb2.out.create_time = 0;
- oi->smb2.out.access_time = 0;
- oi->smb2.out.write_time = 0;
- oi->smb2.out.change_time = 0;
- oi->smb2.out.alloc_size = 4096;
- oi->smb2.out.size = 0;
- oi->smb2.out.file_attr = FILE_ATTRIBUTE_NORMAL;
- oi->smb2.out.reserved2 = 0;
+ ret = tstream_npa_connect_recv(subreq, &sys_errno,
+ p, &p->npipe,
+ &p->file_type,
+ &p->device_state,
+ &p->allocation_size);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
- return status;
-}
+ DLIST_ADD(ipriv->pipe_list, p);
+ talloc_set_destructor(p, ipc_fd_destructor);
-/*
- open a file - used for MSRPC pipes
-*/
-static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
- struct ntvfs_request *req, union smb_open *oi)
-{
- NTSTATUS status;
+ status = ntvfs_handle_set_backend_data(p->handle, ipriv->ntvfs, p);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto reply;
+ }
switch (oi->generic.level) {
case RAW_OPEN_NTCREATEX:
- status = ipc_open_ntcreatex(ntvfs, req, oi);
+ ZERO_STRUCT(oi->ntcreatex.out);
+ oi->ntcreatex.out.file.ntvfs = p->handle;
+ oi->ntcreatex.out.oplock_level = 0;
+ oi->ntcreatex.out.create_action = NTCREATEX_ACTION_EXISTED;
+ oi->ntcreatex.out.create_time = 0;
+ oi->ntcreatex.out.access_time = 0;
+ oi->ntcreatex.out.write_time = 0;
+ oi->ntcreatex.out.change_time = 0;
+ oi->ntcreatex.out.attrib = FILE_ATTRIBUTE_NORMAL;
+ oi->ntcreatex.out.alloc_size = p->allocation_size;
+ oi->ntcreatex.out.size = 0;
+ oi->ntcreatex.out.file_type = p->file_type;
+ oi->ntcreatex.out.ipc_state = p->device_state;
+ oi->ntcreatex.out.is_directory = 0;
break;
case RAW_OPEN_OPENX:
- status = ipc_open_openx(ntvfs, req, oi);
+ ZERO_STRUCT(oi->openx.out);
+ oi->openx.out.file.ntvfs = p->handle;
+ oi->openx.out.attrib = FILE_ATTRIBUTE_NORMAL;
+ oi->openx.out.write_time = 0;
+ oi->openx.out.size = 0;
+ oi->openx.out.access = 0;
+ oi->openx.out.ftype = p->file_type;
+ oi->openx.out.devstate = p->device_state;
+ oi->openx.out.action = 0;
+ oi->openx.out.unique_fid = 0;
+ oi->openx.out.access_mask = 0;
+ oi->openx.out.unknown = 0;
break;
case RAW_OPEN_SMB2:
- status = ipc_open_smb2(ntvfs, req, oi);
+ ZERO_STRUCT(oi->smb2.out);
+ oi->smb2.out.file.ntvfs = p->handle;
+ oi->smb2.out.oplock_level = oi->smb2.in.oplock_level;
+ oi->smb2.out.create_action = NTCREATEX_ACTION_EXISTED;
+ oi->smb2.out.create_time = 0;
+ oi->smb2.out.access_time = 0;
+ oi->smb2.out.write_time = 0;
+ oi->smb2.out.change_time = 0;
+ oi->smb2.out.alloc_size = p->allocation_size;
+ oi->smb2.out.size = 0;
+ oi->smb2.out.file_attr = FILE_ATTRIBUTE_NORMAL;
+ oi->smb2.out.reserved2 = 0;
break;
default:
- status = NT_STATUS_NOT_SUPPORTED;
break;
}
- return status;
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
}
/*
@@ -428,28 +497,108 @@ static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
return NT_STATUS_ACCESS_DENIED;
}
-static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
+struct ipc_readv_next_vector_state {
+ uint8_t *buf;
+ size_t len;
+ off_t ofs;
+ size_t remaining;
+};
+
+static void ipc_readv_next_vector_init(struct ipc_readv_next_vector_state *s,
+ uint8_t *buf, size_t len)
+{
+ ZERO_STRUCTP(s);
+
+ s->buf = buf;
+ s->len = MIN(len, UINT16_MAX);
+ //DEBUG(0,("readv_next_vector_init[%u 0x%04X]\n", s->len, s->len));
+}
+
+static int ipc_readv_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *count)
{
- DATA_BLOB *blob = private_data;
+ struct ipc_readv_next_vector_state *state =
+ (struct ipc_readv_next_vector_state *)private_data;
+ struct iovec *vector;
+ ssize_t pending;
+ size_t wanted;
+
+ if (state->ofs == state->len) {
+ *_vector = NULL;
+ *count = 0;
+// DEBUG(0,("readv_next_vector done ofs[%u 0x%04X]\n",
+// state->ofs, state->ofs));
+ return 0;
+ }
- if (out->length < blob->length) {
- blob->length = out->length;
+ pending = tstream_pending_bytes(stream);
+ if (pending == -1) {
+ return -1;
}
- memcpy(blob->data, out->data, blob->length);
- *nwritten = blob->length;
- return NT_STATUS_OK;
+
+ if (pending == 0 && state->ofs != 0) {
+ /* return a short read */
+ *_vector = NULL;
+ *count = 0;
+// DEBUG(0,("readv_next_vector short read ofs[%u 0x%04X]\n",
+// state->ofs, state->ofs));
+ return 0;
+ }
+
+ if (pending == 0) {
+ /* we want at least one byte and recheck again */
+ wanted = 1;
+ } else {
+ size_t missing = state->len - state->ofs;
+ if (pending > missing) {
+ /* there's more available */
+ state->remaining = pending - missing;
+ wanted = missing;
+ } else {
+ /* read what we can get and recheck in the next cycle */
+ wanted = pending;
+ }
+ }
+
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (!vector) {
+ return -1;
+ }
+
+ vector[0].iov_base = state->buf + state->ofs;
+ vector[0].iov_len = wanted;
+
+ state->ofs += wanted;
+
+ *_vector = vector;
+ *count = 1;
+ return 0;
}
+struct ipc_read_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ union smb_read *rd;
+ struct ipc_readv_next_vector_state next_vector;
+};
+
+static void ipc_read_done(struct tevent_req *subreq);
+
/*
read from a file
*/
static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req, union smb_read *rd)
{
- struct ipc_private *ipriv = ntvfs->private_data;
- DATA_BLOB data;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
- NTSTATUS status = NT_STATUS_OK;
+ struct ipc_read_state *state;
+ struct tevent_req *subreq;
if (rd->generic.level != RAW_READ_GENERIC) {
return ntvfs_map_read(ntvfs, req, rd);
@@ -460,58 +609,143 @@ static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- data.length = rd->readx.in.maxcnt;
- data.data = rd->readx.out.data;
- if (data.length > UINT16_MAX) {
- data.length = UINT16_MAX;
+ state = talloc(req, struct ipc_read_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->rd = rd;
+
+ /* rd->readx.out.data is already allocated */
+ ipc_readv_next_vector_init(&state->next_vector,
+ rd->readx.out.data,
+ rd->readx.in.maxcnt);
+
+ subreq = tstream_readv_pdu_queue_send(req,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->read_queue,
+ ipc_readv_next_vector,
+ &state->next_vector);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_read_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void ipc_read_done(struct tevent_req *subreq)
+{
+ struct ipc_read_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_read_state);
+ struct ntvfs_request *req = state->req;
+ union smb_read *rd = state->rd;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
}
- if (data.length != 0) {
- status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
- if (NT_STATUS_IS_ERR(status)) {
- return status;
- }
+ status = NT_STATUS_OK;
+ if (state->next_vector.remaining > 0) {
+ status = STATUS_BUFFER_OVERFLOW;
}
- rd->readx.out.remaining = 0;
+ rd->readx.out.remaining = state->next_vector.remaining;
rd->readx.out.compaction_mode = 0;
- rd->readx.out.nread = data.length;
+ rd->readx.out.nread = ret;
- return status;
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
}
+struct ipc_write_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ union smb_write *wr;
+ struct iovec iov;
+};
+
+static void ipc_write_done(struct tevent_req *subreq);
+
/*
write to a file
*/
static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req, union smb_write *wr)
{
- struct ipc_private *ipriv = ntvfs->private_data;
- DATA_BLOB data;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
- NTSTATUS status;
+ struct tevent_req *subreq;
+ struct ipc_write_state *state;
if (wr->generic.level != RAW_WRITE_GENERIC) {
return ntvfs_map_write(ntvfs, req, wr);
}
- data.data = discard_const_p(void, wr->writex.in.data);
- data.length = wr->writex.in.count;
-
p = pipe_state_find(ipriv, wr->writex.in.file.ntvfs);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
}
- status = dcesrv_input(p->dce_conn, &data);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ state = talloc(req, struct ipc_write_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->wr = wr;
+ state->iov.iov_base = discard_const_p(void, wr->writex.in.data);
+ state->iov.iov_len = wr->writex.in.count;
+
+ subreq = tstream_writev_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->write_queue,
+ &state->iov, 1);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_write_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void ipc_write_done(struct tevent_req *subreq)
+{
+ struct ipc_write_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_write_state);
+ struct ntvfs_request *req = state->req;
+ union smb_write *wr = state->wr;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_writev_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
}
- wr->writex.out.nwritten = data.length;
+ status = NT_STATUS_OK;
+
+ wr->writex.out.nwritten = ret;
wr->writex.out.remaining = 0;
- return NT_STATUS_OK;
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
}
/*
@@ -540,7 +774,8 @@ static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req, union smb_close *io)
{
- struct ipc_private *ipriv = ntvfs->private_data;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
if (io->generic.level != RAW_CLOSE_CLOSE) {
@@ -563,7 +798,8 @@ static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req)
{
- struct ipc_private *ipriv = ntvfs->private_data;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p, *next;
for (p=ipriv->pipe_list; p; p=next) {
@@ -583,7 +819,8 @@ static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req)
{
- struct ipc_private *ipriv = ntvfs->private_data;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p, *next;
for (p=ipriv->pipe_list; p; p=next) {
@@ -639,7 +876,8 @@ static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req, union smb_fileinfo *info)
{
- struct ipc_private *ipriv = ntvfs->private_data;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p = pipe_state_find(ipriv, info->generic.in.file.ntvfs);
if (!p) {
return NT_STATUS_INVALID_HANDLE;
@@ -724,32 +962,29 @@ static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
return NT_STATUS_ACCESS_DENIED;
}
-static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
-{
- NTSTATUS status = NT_STATUS_OK;
- DATA_BLOB *blob = private_data;
-
- if (out->length > blob->length) {
- status = STATUS_BUFFER_OVERFLOW;
- }
+struct ipc_trans_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ struct smb_trans2 *trans;
+ struct iovec writev_iov;
+ struct ipc_readv_next_vector_state next_vector;
+};
- if (out->length < blob->length) {
- blob->length = out->length;
- }
- memcpy(blob->data, out->data, blob->length);
- *nwritten = blob->length;
- return status;
-}
+static void ipc_trans_writev_done(struct tevent_req *subreq);
+static void ipc_trans_readv_done(struct tevent_req *subreq);
/* SMBtrans - handle a DCERPC command */
static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req, struct smb_trans2 *trans)
{
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
- struct ipc_private *ipriv = ntvfs->private_data;
- NTSTATUS status;
DATA_BLOB fnum_key;
uint16_t fnum;
+ struct ipc_trans_state *state;
+ struct tevent_req *subreq;
/*
* the fnum is in setup[1], a 16 bit value
@@ -765,43 +1000,122 @@ static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
- if (!trans->out.data.data) {
- return NT_STATUS_NO_MEMORY;
- }
-
- /* pass the data to the dcerpc server. Note that we don't
- expect this to fail, and things like NDR faults are not
- reported at this stage. Those sorts of errors happen in the
- dcesrv_output stage */
- status = dcesrv_input(p->dce_conn, &trans->in.data);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
/*
- now ask the dcerpc system for some output. This doesn't yet handle
- async calls. Again, we only expect NT_STATUS_OK. If the call fails then
- the error is encoded at the dcerpc level
- */
- status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
- if (NT_STATUS_IS_ERR(status)) {
- return status;
+ * Trans requests are only allowed
+ * if no other Trans or Read is active
+ */
+ if (tevent_queue_length(p->read_queue) > 0) {
+ return NT_STATUS_PIPE_BUSY;
}
+ state = talloc(req, struct ipc_trans_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
trans->out.setup_count = 0;
trans->out.setup = NULL;
trans->out.params = data_blob(NULL, 0);
+ trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
+ NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
+
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->trans = trans;
+ state->writev_iov.iov_base = trans->in.data.data;
+ state->writev_iov.iov_len = trans->in.data.length;
+
+ ipc_readv_next_vector_init(&state->next_vector,
+ trans->out.data.data,
+ trans->out.data.length);
+
+ subreq = tstream_writev_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->write_queue,
+ &state->writev_iov, 1);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_trans_writev_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
+}
- return status;
+static void ipc_trans_writev_done(struct tevent_req *subreq)
+{
+ struct ipc_trans_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_trans_state);
+ struct ipc_private *ipriv = state->ipriv;
+ struct pipe_state *p = state->p;
+ struct ntvfs_request *req = state->req;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_writev_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == 0) {
+ status = NT_STATUS_PIPE_DISCONNECTED;
+ goto reply;
+ } else if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ subreq = tstream_readv_pdu_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->read_queue,
+ ipc_readv_next_vector,
+ &state->next_vector);
+ if (!subreq) {
+ status = NT_STATUS_NO_MEMORY;
+ goto reply;
+ }
+ tevent_req_set_callback(subreq, ipc_trans_readv_done, state);
+ return;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
}
+static void ipc_trans_readv_done(struct tevent_req *subreq)
+{
+ struct ipc_trans_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_trans_state);
+ struct ntvfs_request *req = state->req;
+ struct smb_trans2 *trans = state->trans;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ status = NT_STATUS_OK;
+ if (state->next_vector.remaining > 0) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ trans->out.data.length = ret;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
+}
/* SMBtrans - set named pipe state */
static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req, struct smb_trans2 *trans)
{
- struct ipc_private *ipriv = ntvfs->private_data;
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
DATA_BLOB fnum_key;
@@ -816,7 +1130,11 @@ static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
if (trans->in.params.length != 2) {
return NT_STATUS_INVALID_PARAMETER;
}
- p->ipc_state = SVAL(trans->in.params.data, 0);
+
+ /*
+ * TODO: pass this to the tstream_npa logic
+ */
+ p->device_state = SVAL(trans->in.params.data, 0);
trans->out.setup_count = 0;
trans->out.setup = NULL;
@@ -855,12 +1173,26 @@ static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
return status;
}
+struct ipc_ioctl_state {
+ struct ipc_private *ipriv;
+ struct pipe_state *p;
+ struct ntvfs_request *req;
+ union smb_ioctl *io;
+ struct iovec writev_iov;
+ struct ipc_readv_next_vector_state next_vector;
+};
+
+static void ipc_ioctl_writev_done(struct tevent_req *subreq);
+static void ipc_ioctl_readv_done(struct tevent_req *subreq);
+
static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req, union smb_ioctl *io)
{
+ struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
+ struct ipc_private);
struct pipe_state *p;
- struct ipc_private *ipriv = ntvfs->private_data;
- NTSTATUS status;
+ struct ipc_ioctl_state *state;
+ struct tevent_req *subreq;
switch (io->smb2.in.function) {
case FSCTL_NAMED_PIPE_READ_WRITE:
@@ -875,31 +1207,113 @@ static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
- NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
-
- /* pass the data to the dcerpc server. Note that we don't
- expect this to fail, and things like NDR faults are not
- reported at this stage. Those sorts of errors happen in the
- dcesrv_output stage */
- status = dcesrv_input(p->dce_conn, &io->smb2.in.out);
- NT_STATUS_NOT_OK_RETURN(status);
-
/*
- now ask the dcerpc system for some output. This doesn't yet handle
- async calls. Again, we only expect NT_STATUS_OK. If the call fails then
- the error is encoded at the dcerpc level
- */
- status = dcesrv_output(p->dce_conn, &io->smb2.out.out, ipc_trans_dcesrv_output);
- NT_STATUS_IS_ERR_RETURN(status);
+ * Trans requests are only allowed
+ * if no other Trans or Read is active
+ */
+ if (tevent_queue_length(p->read_queue) > 0) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ state = talloc(req, struct ipc_ioctl_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
io->smb2.out._pad = 0;
io->smb2.out.function = io->smb2.in.function;
io->smb2.out.unknown2 = 0;
io->smb2.out.unknown3 = 0;
io->smb2.out.in = io->smb2.in.out;
+ io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
+ NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
- return status;
+ state->ipriv = ipriv;
+ state->p = p;
+ state->req = req;
+ state->io = io;
+ state->writev_iov.iov_base = io->smb2.in.out.data;
+ state->writev_iov.iov_len = io->smb2.in.out.length;
+
+ ipc_readv_next_vector_init(&state->next_vector,
+ io->smb2.out.out.data,
+ io->smb2.out.out.length);
+
+ subreq = tstream_writev_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->write_queue,
+ &state->writev_iov, 1);
+ NT_STATUS_HAVE_NO_MEMORY(subreq);
+ tevent_req_set_callback(subreq, ipc_ioctl_writev_done, state);
+
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void ipc_ioctl_writev_done(struct tevent_req *subreq)
+{
+ struct ipc_ioctl_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_ioctl_state);
+ struct ipc_private *ipriv = state->ipriv;
+ struct pipe_state *p = state->p;
+ struct ntvfs_request *req = state->req;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_writev_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ subreq = tstream_readv_pdu_queue_send(state,
+ ipriv->ntvfs->ctx->event_ctx,
+ p->npipe,
+ p->read_queue,
+ ipc_readv_next_vector,
+ &state->next_vector);
+ if (!subreq) {
+ status = NT_STATUS_NO_MEMORY;
+ goto reply;
+ }
+ tevent_req_set_callback(subreq, ipc_ioctl_readv_done, state);
+ return;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
+}
+
+static void ipc_ioctl_readv_done(struct tevent_req *subreq)
+{
+ struct ipc_ioctl_state *state =
+ tevent_req_callback_data(subreq,
+ struct ipc_ioctl_state);
+ struct ntvfs_request *req = state->req;
+ union smb_ioctl *io = state->io;
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(sys_errno);
+ goto reply;
+ }
+
+ status = NT_STATUS_OK;
+ if (state->next_vector.remaining > 0) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ io->smb2.out.out.length = ret;
+
+reply:
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
}
/*
diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk
index 93617c2c98..527770a8cd 100644
--- a/source4/rpc_server/config.mk
+++ b/source4/rpc_server/config.mk
@@ -230,3 +230,6 @@ SUBSYSTEM = service
PRIVATE_DEPENDENCIES = dcerpc_server
DCESRV_OBJ_FILES = $(rpc_serversrcdir)/service_rpc.o
+
+$(eval $(call proto_header_template,$(rpc_serversrcdir)/service_rpc.h,$(DCESRV_OBJ_FILES:.o=.c)))
+
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index f2402605d9..e055d1671b 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -339,44 +339,6 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
return NT_STATUS_OK;
}
-/*
- search and connect to a dcerpc endpoint
-*/
-_PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
- TALLOC_CTX *mem_ctx,
- const struct dcerpc_binding *ep_description,
- struct auth_session_info *session_info,
- struct tevent_context *event_ctx,
- struct messaging_context *msg_ctx,
- struct server_id server_id,
- uint32_t state_flags,
- struct dcesrv_connection **dce_conn_p)
-{
- NTSTATUS status;
- const struct dcesrv_endpoint *ep;
-
- /* make sure this endpoint exists */
- ep = find_endpoint(dce_ctx, ep_description);
- if (!ep) {
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
-
- status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
- event_ctx, msg_ctx, server_id,
- state_flags, dce_conn_p);
- NT_STATUS_NOT_OK_RETURN(status);
-
- (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
-
- /* TODO: check security descriptor of the endpoint here
- * if it's a smb named pipe
- * if it's failed free dce_conn_p
- */
-
- return NT_STATUS_OK;
-}
-
-
static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
{
pkt->rpc_vers = 5;
@@ -1255,133 +1217,6 @@ NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
return status;
}
-
-/*
- provide some input to a dcerpc endpoint server. This passes data
- from a dcerpc client into the server
-*/
-_PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
-{
- dce_conn->partial_input.data = talloc_realloc(dce_conn,
- dce_conn->partial_input.data,
- uint8_t,
- dce_conn->partial_input.length + data->length);
- if (!dce_conn->partial_input.data) {
- return NT_STATUS_NO_MEMORY;
- }
- memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
- data->data, data->length);
- dce_conn->partial_input.length += data->length;
-
- while (dce_full_packet(&dce_conn->partial_input)) {
- NTSTATUS status;
- struct ndr_pull *ndr;
- enum ndr_err_code ndr_err;
- DATA_BLOB blob;
- struct ncacn_packet *pkt;
-
- blob = dce_conn->partial_input;
- blob.length = dcerpc_get_frag_length(&blob);
- blob = data_blob_talloc(dce_conn, blob.data, blob.length);
- if (!blob.data) {
- data_blob_free(&dce_conn->partial_input);
- return NT_STATUS_NO_MEMORY;
- }
-
- dce_partial_advance(dce_conn, blob.length);
-
- pkt = talloc(dce_conn, struct ncacn_packet);
- if (!pkt) {
- data_blob_free(&blob);
- return NT_STATUS_NO_MEMORY;
- }
-
- ndr = ndr_pull_init_blob(&blob, pkt, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx));
- if (!ndr) {
- data_blob_free(&blob);
- talloc_free(pkt);
- return NT_STATUS_NO_MEMORY;
- }
-
- if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
- ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
- }
-
- if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
- ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
- }
-
- ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
- TALLOC_FREE(ndr);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- data_blob_free(&blob);
- talloc_free(pkt);
- return ndr_map_error2ntstatus(ndr_err);
- }
-
- status = dcesrv_process_ncacn_packet(dce_conn, pkt, blob);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- }
-
- return NT_STATUS_OK;
-}
-
-/*
- retrieve some output from a dcerpc server
- The caller supplies a function that will be called to do the
- actual output.
-
- The first argument to write_fn() will be 'private', the second will
- be a pointer to a buffer containing the data to be sent and the 3rd
- will be a pointer to a size_t variable that will be set to the
- number of bytes that are consumed from the output.
-
- from the current fragment
-*/
-_PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
- void *private_data,
- NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
-{
- NTSTATUS status;
- struct dcesrv_call_state *call;
- struct data_blob_list_item *rep;
- size_t nwritten;
-
- call = dce_conn->call_list;
- if (!call || !call->replies) {
- if (dce_conn->pending_call_list) {
- /* TODO: we need to say act async here
- * as we know we have pending requests
- * which will be finished at a time
- */
- return NT_STATUS_FOOBAR;
- }
- return NT_STATUS_FOOBAR;
- }
- rep = call->replies;
-
- status = write_fn(private_data, &rep->blob, &nwritten);
- NT_STATUS_IS_ERR_RETURN(status);
-
- rep->blob.length -= nwritten;
- rep->blob.data += nwritten;
-
- if (rep->blob.length == 0) {
- /* we're done with this section of the call */
- DLIST_REMOVE(call->replies, rep);
- }
-
- if (call->replies == NULL) {
- /* we're done with the whole call */
- dcesrv_call_set_list(call, DCESRV_LIST_NONE);
- talloc_free(call);
- }
-
- return status;
-}
-
_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
@@ -1534,22 +1369,3 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void)
return &critical_sizes;
}
-/*
- initialise the dcerpc server context for ncacn_np based services
-*/
-_PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
- struct dcesrv_context **_dce_ctx)
-{
- NTSTATUS status;
- struct dcesrv_context *dce_ctx;
-
- dcerpc_server_init(lp_ctx);
-
- status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
- NT_STATUS_NOT_OK_RETURN(status);
-
- *_dce_ctx = dce_ctx;
- return NT_STATUS_OK;
-}
-
-
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 23806630d2..0c4d4d413d 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -298,21 +298,6 @@ NTSTATUS dcerpc_register_ep_server(const void *_ep_server);
NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
const char **endpoint_servers, struct dcesrv_context **_dce_ctx);
-NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
- struct dcesrv_context **_dce_ctx);
-NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
- TALLOC_CTX *mem_ctx,
- const struct dcerpc_binding *ep_description,
- struct auth_session_info *session_info,
- struct tevent_context *event_ctx,
- struct messaging_context *msg_ctx,
- struct server_id server_id,
- uint32_t state_flags,
- struct dcesrv_connection **dce_conn_p);
-NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
- void *private_data,
- NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten));
-NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data);
NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
TALLOC_CTX *mem_ctx,
const struct dcesrv_endpoint *ep,
diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c
index 01bc00762d..3d5c364ec9 100644
--- a/source4/rpc_server/service_rpc.c
+++ b/source4/rpc_server/service_rpc.c
@@ -28,6 +28,7 @@
#include "../lib/util/dlinklist.h"
#include "rpc_server/dcerpc_server.h"
#include "rpc_server/dcerpc_server_proto.h"
+#include "rpc_server/service_rpc.h"
#include "lib/events/events.h"
#include "smbd/service_task.h"
#include "smbd/service_stream.h"
@@ -658,11 +659,11 @@ static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
return NT_STATUS_OK;
}
-
-static NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
- struct loadparm_context *lp_ctx,
- struct dcesrv_endpoint *e,
- struct tevent_context *event_ctx, const struct model_ops *model_ops)
+NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
+ struct loadparm_context *lp_ctx,
+ struct dcesrv_endpoint *e,
+ struct tevent_context *event_ctx,
+ const struct model_ops *model_ops)
{
switch (e->ep_description->transport) {
case NCACN_UNIX_STREAM:
diff --git a/source4/scripting/bin/fullschema b/source4/scripting/bin/fullschema
index 4c73100492..4a01b6aed0 100755
--- a/source4/scripting/bin/fullschema
+++ b/source4/scripting/bin/fullschema
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# work out the minimal schema for a set of objectclasses
+# Works out the full schema
#
import base64
diff --git a/source4/scripting/bin/minschema b/source4/scripting/bin/minschema
index c860495e96..43f7816116 100755
--- a/source4/scripting/bin/minschema
+++ b/source4/scripting/bin/minschema
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# work out the minimal schema for a set of objectclasses
+# Works out the minimal schema for a set of objectclasses
#
import base64
diff --git a/source4/scripting/bin/reorgldb.py b/source4/scripting/bin/reorgldb.py
new file mode 100755
index 0000000000..571363fdc7
--- /dev/null
+++ b/source4/scripting/bin/reorgldb.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+#
+# Copyright (C) Matthieu Patou <mat@matws.net> 2009
+# This script realize an offline reorganisation of an LDB
+# file it helps to reduce (sometime drastically) the
+# size of LDB files.
+import sys
+import optparse
+import os
+sys.path.insert(0, "bin/python")
+
+import samba
+from samba.credentials import DONT_USE_KERBEROS
+from samba.auth import system_session
+from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted
+from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
+import ldb
+import samba.getopt as options
+from samba.samdb import SamDB
+from samba import param
+from samba.provision import ProvisionPaths, ProvisionNames,provision_paths_from_lp, Schema
+
+parser = optparse.OptionParser("provision [options]")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+parser.add_option("--database", type="string", metavar="FILE",
+ help="LDB to reorganize")
+opts = parser.parse_args()[0]
+lp = sambaopts.get_loadparm()
+smbconf = lp.configfile
+
+if not opts.database:
+ print "Parameter database is mandatory"
+ sys.exit(1)
+creds = credopts.get_credentials(lp)
+creds.set_kerberos_state(DONT_USE_KERBEROS)
+session = system_session()
+empty = ldb.Message()
+newname="%s.new"%(opts.database)
+if os.path.exists(newname):
+ os.remove(newname)
+old_ldb = Ldb(opts.database, session_info=session, credentials=creds,lp=lp)
+new_ldb = Ldb(newname,session_info=session, credentials=creds,lp=lp)
+
+new_ldb.transaction_start()
+res = old_ldb.search(expression="(dn=*)",base="", scope=SCOPE_SUBTREE)
+for i in range(0,len(res)):
+ if str(res[i].dn) == "@BASEINFO":
+ continue
+ if str(res[i].dn).startswith("@INDEX:"):
+ continue
+ delta = new_ldb.msg_diff(empty,res[i])
+ delta.dn = res[i].dn
+ delta.remove("distinguishedName")
+ new_ldb.add(delta)
+
+new_ldb.transaction_commit()
diff --git a/source4/scripting/python/samba/idmap.py b/source4/scripting/python/samba/idmap.py
index acc98a56e8..ad209f42de 100644
--- a/source4/scripting/python/samba/idmap.py
+++ b/source4/scripting/python/samba/idmap.py
@@ -34,7 +34,7 @@ class IDmapDB(samba.Ldb):
def __init__(self, url=None, lp=None, modules_dir=None, session_info=None,
credentials=None, flags=0, options=None):
- """Opens the IDmap Database.
+ """Opens the IDMap Database
For parameter meanings see the super class (samba.Ldb)
"""
diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py
index 4840efcb63..065677fa68 100644
--- a/source4/scripting/python/samba/provision.py
+++ b/source4/scripting/python/samba/provision.py
@@ -44,7 +44,7 @@ from credentials import Credentials, DONT_USE_KERBEROS
from auth import system_session, admin_session
from samba import version, Ldb, substitute_var, valid_netbios_name
from samba import check_all_substituted
-from samba import DS_DOMAIN_FUNCTION_2008_R2, DS_DC_FUNCTION_2008_R2
+from samba import DS_DOMAIN_FUNCTION_2000, DS_DC_FUNCTION_2008_R2
from samba.samdb import SamDB
from samba.idmap import IDmapDB
from samba.dcerpc import security
@@ -835,8 +835,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
:note: This will wipe the main SAM database file!
"""
- domainFunctionality = DS_DOMAIN_FUNCTION_2008_R2
- forestFunctionality = DS_DOMAIN_FUNCTION_2008_R2
+ domainFunctionality = DS_DOMAIN_FUNCTION_2000
+ forestFunctionality = DS_DOMAIN_FUNCTION_2000
domainControllerFunctionality = DS_DC_FUNCTION_2008_R2
# Also wipes the database
@@ -978,6 +978,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
"DOMAINDN": names.domaindn})
message("Setting up sam.ldb data")
setup_add_ldif(samdb, setup_path("provision.ldif"), {
+ "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks
"DOMAINDN": names.domaindn,
"NETBIOSNAME": names.netbiosname,
"DEFAULTSITE": names.sitename,
@@ -1005,10 +1006,10 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
policyguid_dc=policyguid_dc,
setup_path=setup_path,
domainControllerFunctionality=domainControllerFunctionality)
- # add the NTDSGUID based SPNs
+
ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
- names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
- expression="", scope=SCOPE_BASE)
+ names.ntdsguid = samdb.searchone(basedn=ntds_dn,
+ attribute="objectGUID", expression="", scope=SCOPE_BASE)
assert isinstance(names.ntdsguid, str)
except:
diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py
index a58d6c5b12..ef2a0b1644 100644
--- a/source4/scripting/python/samba/samdb.py
+++ b/source4/scripting/python/samba/samdb.py
@@ -37,7 +37,7 @@ class SamDB(samba.Ldb):
def __init__(self, url=None, lp=None, modules_dir=None, session_info=None,
credentials=None, flags=0, options=None):
- """Opens the Sam Database.
+ """Opens the SAM Database
For parameter meanings see the super class (samba.Ldb)
"""
@@ -55,13 +55,25 @@ class SamDB(samba.Ldb):
super(SamDB, self).connect(url=self.lp.private_path(url), flags=flags,
options=options)
- def enable_account(self, user_dn):
- """Enable an account.
+ def domain_dn(self):
+ # find the DNs for the domain
+ res = self.search(base="",
+ scope=ldb.SCOPE_BASE,
+ expression="(defaultNamingContext=*)",
+ attrs=["defaultNamingContext"])
+ assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None)
+ return res[0]["defaultNamingContext"][0]
+
+ def enable_account(self, filter):
+ """Enables an account
- :param user_dn: Dn of the account to enable.
+ :param filter: LDAP filter to find the user (eg samccountname=name)
"""
- res = self.search(user_dn, ldb.SCOPE_BASE, None, ["userAccountControl"])
- assert len(res) == 1
+ res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
+ expression=filter, attrs=["userAccountControl"])
+ assert(len(res) == 1)
+ user_dn = res[0].dn
+
userAccountControl = int(res[0]["userAccountControl"][0])
if (userAccountControl & 0x2):
userAccountControl = userAccountControl & ~0x2 # remove disabled bit
@@ -76,11 +88,16 @@ userAccountControl: %u
""" % (user_dn, userAccountControl)
self.modify_ldif(mod)
- def force_password_change_at_next_login(self, user_dn):
- """Force a password change at next login
+ def force_password_change_at_next_login(self, filter):
+ """Forces a password change at next login
- :param user_dn: Dn of the account to force password change on
+ :param filter: LDAP filter to find the user (eg samccountname=name)
"""
+ res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
+ expression=filter, attrs=[])
+ assert(len(res) == 1)
+ user_dn = res[0].dn
+
mod = """
dn: %s
changetype: modify
@@ -89,17 +106,12 @@ pwdLastSet: 0
""" % (user_dn)
self.modify_ldif(mod)
- def domain_dn(self):
- # find the DNs for the domain
- res = self.search(base="",
- scope=ldb.SCOPE_BASE,
- expression="(defaultNamingContext=*)",
- attrs=["defaultNamingContext"])
- assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None)
- return res[0]["defaultNamingContext"][0]
-
def newuser(self, username, unixname, password, force_password_change_at_next_login=False):
- """add a new user record.
+ """Adds a new user
+
+ Note: This call uses the "userPassword" attribute to set the password.
+ This works correctly on SAMBA 4 DCs and on Windows DCs with
+ "2003 Native" or higer domain function level.
:param username: Name of the new user.
:param unixname: Name of the unix user to map to.
@@ -110,11 +122,8 @@ pwdLastSet: 0
try:
user_dn = "CN=%s,CN=Users,%s" % (username, self.domain_dn())
- #
- # the new user record. note the reliance on the samdb module to
- # fill in a sid, guid etc
- #
- # now the real work
+ # The new user record. Note the reliance on the SAMLDB module which
+ # fills in the default informations
self.add({"dn": user_dn,
"sAMAccountName": username,
"userPassword": password,
@@ -130,30 +139,34 @@ pwdLastSet: 0
idmap = IDmapDB(lp=self.lp)
user = pwd.getpwnam(unixname)
+
# setup ID mapping for this UID
-
idmap.setup_name_mapping(user_sid, idmap.TYPE_UID, user[2])
except KeyError:
pass
if force_password_change_at_next_login:
- self.force_password_change_at_next_login(user_dn)
+ self.force_password_change_at_next_login("(dn=" + user_dn + ")")
# modify the userAccountControl to remove the disabled bit
- self.enable_account(user_dn)
+ self.enable_account("(dn=" + user_dn + ")")
except:
self.transaction_cancel()
raise
self.transaction_commit()
def setpassword(self, filter, password, force_password_change_at_next_login=False):
- """Set a password on a user record
+ """Sets the password for a user
+ Note: This call uses the "userPassword" attribute to set the password.
+ This works correctly on SAMBA 4 DCs and on Windows DCs with
+ "2003 Native" or higer domain function level.
+
:param filter: LDAP filter to find the user (eg samccountname=name)
:param password: Password for the user
+ :param force_password_change_at_next_login: Force password change
"""
- # connect to the sam
self.transaction_start()
try:
res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
@@ -174,24 +187,27 @@ userPassword:: %s
self.force_password_change_at_next_login(user_dn)
# modify the userAccountControl to remove the disabled bit
- self.enable_account(user_dn)
+ self.enable_account(filter)
except:
self.transaction_cancel()
raise
self.transaction_commit()
- def setexpiry(self, user, expiry_seconds, noexpiry):
- """Set the account expiry for a user
+ def setexpiry(self, filter, expiry_seconds, noexpiry=False):
+ """Sets the account expiry for a user
+ :param filter: LDAP filter to find the user (eg samccountname=name)
:param expiry_seconds: expiry time from now in seconds
:param noexpiry: if set, then don't expire password
"""
self.transaction_start()
try:
res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
- expression=("(samAccountName=%s)" % user),
+ expression=filter,
attrs=["userAccountControl", "accountExpires"])
assert len(res) == 1
+ user_dn = res[0].dn
+
userAccountControl = int(res[0]["userAccountControl"][0])
accountExpires = int(res[0]["accountExpires"][0])
if noexpiry:
@@ -201,16 +217,16 @@ userPassword:: %s
userAccountControl = userAccountControl & ~0x10000
accountExpires = glue.unix2nttime(expiry_seconds + int(time.time()))
- mod = """
+ setexp = """
dn: %s
changetype: modify
replace: userAccountControl
userAccountControl: %u
replace: accountExpires
accountExpires: %u
-""" % (res[0].dn, userAccountControl, accountExpires)
- # now change the database
- self.modify_ldif(mod)
+""" % (user_dn, userAccountControl, accountExpires)
+
+ self.modify_ldif(setexp)
except:
self.transaction_cancel()
raise
diff --git a/source4/setup/domainlevel b/source4/setup/domainlevel
new file mode 100755
index 0000000000..811e29cb2d
--- /dev/null
+++ b/source4/setup/domainlevel
@@ -0,0 +1,187 @@
+#!/usr/bin/python
+#
+# Raises domain and forest function levels
+#
+# Copyright Matthias Dieter Wallnoefer 2009
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+
+import sys
+
+# Find right directory when running from source tree
+sys.path.insert(0, "bin/python")
+
+import samba.getopt as options
+import optparse
+import ldb
+
+from samba.auth import system_session
+from samba.samdb import SamDB
+from samba import DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2003
+from samba import DS_DOMAIN_FUNCTION_2008, DS_DOMAIN_FUNCTION_2008_R2
+
+parser = optparse.OptionParser("domainlevel (show | raise <options>)")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+parser.add_option("--quiet", help="Be quiet", action="store_true")
+parser.add_option("--forest",
+ help="The forest function level (2000 | 2003 | 2008 | 2008_R2). We don't support mixed/interim (NT4 DC support) levels.", type=str)
+parser.add_option("--domain",
+ help="The domain function level (2000 | 2003 | 2008 | 2008_R2). We don't support mixed/interim (NT4 DC support) levels.", type=str)
+opts, args = parser.parse_args()
+
+#
+# print a message if quiet is not set
+#
+def message(text):
+ if not opts.quiet:
+ print text
+
+if len(args) == 0:
+ parser.print_usage()
+ sys.exit(1)
+
+lp = sambaopts.get_loadparm()
+creds = credopts.get_credentials(lp)
+
+samdb = SamDB(url=lp.get("sam database"), session_info=system_session(),
+ credentials=creds, lp=lp)
+
+domain_dn = SamDB.domain_dn(samdb)
+
+res_forest = samdb.search("CN=Partitions,CN=Configuration," + domain_dn,
+ scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"])
+assert(len(res_forest) == 1)
+
+res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
+ attrs=["msDS-Behavior-Version"])
+assert(len(res_domain) == 1)
+
+try:
+ level_forest = int(res_forest[0]["msDS-Behavior-Version"][0])
+ level_domain = int(res_domain[0]["msDS-Behavior-Version"][0])
+
+ if level_forest < 0 or level_forest == 1 or level_forest > 4 or level_domain < 0 or level_domain == 1 or level_domain > 4:
+ print "ERROR: Domain and/or forest functional level(s) is/are invalid. Correct them or reprovision!"
+ sys.exit(1)
+ if level_forest > level_domain:
+ print "ERROR: Forest function level is higher than the domain level(s). That can't be. Correct this or reprovision!"
+ sys.exit(1)
+except:
+ print "ERROR: Could not retrieve the actual domain and forest level!"
+ if args[0] == "show":
+ print "So the levels can't be displayed!"
+ sys.exit(1)
+
+if args[0] == "show":
+ message("Domain and forest function level for domain '" + domain_dn + "'")
+ message("")
+
+ if level_forest == DS_DOMAIN_FUNCTION_2000:
+ outstr = "2000"
+ elif level_forest == DS_DOMAIN_FUNCTION_2003:
+ outstr = "2003"
+ elif level_forest == DS_DOMAIN_FUNCTION_2008:
+ outstr = "2008"
+ elif level_forest == DS_DOMAIN_FUNCTION_2008_R2:
+ outstr = "2008 R2"
+ message("Forest function level: (Windows) " + outstr)
+
+ if level_domain == DS_DOMAIN_FUNCTION_2000:
+ outstr = "2000"
+ elif level_domain == DS_DOMAIN_FUNCTION_2003:
+ outstr = "2003"
+ elif level_domain == DS_DOMAIN_FUNCTION_2008:
+ outstr = "2008"
+ elif level_domain == DS_DOMAIN_FUNCTION_2008_R2:
+ outstr = "2008 R2"
+ message("Domain function level: (Windows) " + outstr)
+
+elif args[0] == "raise":
+ msgs = []
+
+ if opts.domain is not None:
+ arg = opts.domain
+
+ if arg == "2000":
+ new_level_domain = DS_DOMAIN_FUNCTION_2000
+ elif arg == "2003":
+ new_level_domain = DS_DOMAIN_FUNCTION_2003
+ elif arg == "2008":
+ new_level_domain = DS_DOMAIN_FUNCTION_2008
+ elif arg == "2008_R2":
+ new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
+ else:
+ print "ERROR: Wrong argument '" + arg + "'!"
+ sys.exit(1)
+
+ if new_level_domain <= level_domain:
+ print "ERROR: Domain function level can't be smaller equal to the actual one!"
+ sys.exit(1)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, domain_dn)
+ m["msDS-Behavior-Version"]= ldb.MessageElement(
+ str(new_level_domain), ldb.FLAG_MOD_REPLACE,
+ "msDS-Behavior-Version")
+ samdb.modify(m)
+
+ level_domain = new_level_domain
+
+ msgs.append("Domain function level changed!")
+
+ if opts.forest is not None:
+ arg = opts.forest
+
+ if arg == "2000":
+ new_level_forest = DS_DOMAIN_FUNCTION_2000
+ elif arg == "2003":
+ new_level_forest = DS_DOMAIN_FUNCTION_2003
+ elif arg == "2008":
+ new_level_forest = DS_DOMAIN_FUNCTION_2008
+ elif arg == "2008_R2":
+ new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
+ else:
+ print "ERROR: Wrong argument '" + arg + "'!"
+ sys.exit(1)
+
+ if new_level_forest <= level_forest:
+ print "ERROR: Forest function level can't be smaller equal to the actual one!"
+ sys.exit(1)
+
+ if new_level_forest > level_domain:
+ print "ERROR: Forest function level can't be higher than the domain function level(s). Please raise it/them first!"
+ sys.exit(1)
+
+ m = ldb.Message()
+
+ m.dn = ldb.Dn(samdb, "CN=Partitions,CN=Configuration,"
+ + domain_dn)
+ m["msDS-Behavior-Version"]= ldb.MessageElement(
+ str(new_level_forest), ldb.FLAG_MOD_REPLACE,
+ "msDS-Behavior-Version")
+ samdb.modify(m)
+
+ msgs.append("Forest function level changed!")
+
+ msgs.append("All changes applied successfully!")
+
+ message("\n".join(msgs))
+else:
+ print "ERROR: Wrong argument '" + args[0] + "'!"
+ sys.exit(1)
diff --git a/source4/setup/enableaccount b/source4/setup/enableaccount
index d4e954074b..0ca5b39faa 100755
--- a/source4/setup/enableaccount
+++ b/source4/setup/enableaccount
@@ -1,18 +1,31 @@
#!/usr/bin/python
#
-# Enables a disabled user account on a Samba4 server
-# Copyright Andrew Tridgell 2005
-# Copyright Jelmer Vernooij 2008
-# Released under the GNU GPL version 3 or later
+# Enables an user account on a Samba4 server
+# Copyright Jelmer Vernooij 2008
+#
+# Based on the original in EJS:
+# Copyright Andrew Tridgell 2005
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
#
-import os, sys
-sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "../bin/python"))
+import sys
+
+sys.path.insert(0, "bin/python")
import samba.getopt as options
import optparse
-import pwd
-import ldb
from samba.auth import system_session
from samba.samdb import SamDB
@@ -23,49 +36,24 @@ parser.add_option_group(sambaopts)
parser.add_option_group(options.VersionOptions(parser))
credopts = options.CredentialsOptions(parser)
parser.add_option_group(credopts)
-parser.add_option("-H", help="LDB URL for database or target server", type=str)
-parser.add_option("--base", help="Base DN to search for user under", type=str)
+parser.add_option("--filter", help="LDAP Filter to set password on", type=str)
opts, args = parser.parse_args()
-#
-# print a message if quiet is not set
-#
-def message(text):
- if not opts.quiet:
- print text
+filter = opts.filter
-if len(args) == 0:
+if (len(args) == 0) and (filter is None):
+ print "Either the username or '--filter' must be specified!"
parser.print_usage()
sys.exit(1)
-username = args[0]
-
-if username is None:
- print "username must be specified"
+if filter is None:
+ username = args[0]
+ filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
lp = sambaopts.get_loadparm()
-
creds = credopts.get_credentials(lp)
-if opts.H is not None:
- url = opts.H
-else:
- url = lp.get("sam database")
-
-samdb = SamDB(url=url, session_info=system_session(),
+samdb = SamDB(url=lp.get("sam database"), session_info=system_session(),
credentials=creds, lp=lp)
-
-domain_dn = opts.base
-if domain_dn is None:
- domain_dn = SamDB.domain_dn(samdb)
-
-filter = "(&(objectClass=user)(samAccountName=%s))" % username
-
-res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE,
- expression=filter,
- attrs=[])
-assert(len(res) == 1)
-user_dn = res[0].dn
-
-samdb.enable_account(user_dn)
+samdb.enable_account(filter)
diff --git a/source4/setup/newuser b/source4/setup/newuser
index cc89e922a7..422677c301 100755
--- a/source4/setup/newuser
+++ b/source4/setup/newuser
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Add a new user to a Samba4 server
+# Adds a new user to a Samba4 server
# Copyright Jelmer Vernooij 2008
#
# Based on the original in EJS:
@@ -18,6 +18,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
import sys
# Find right directory when running from source tree
@@ -25,8 +26,10 @@ sys.path.insert(0, "bin/python")
import samba.getopt as options
import optparse
+
from getpass import getpass
from samba.auth import system_session
+from samba.samdb import SamDB
parser = optparse.OptionParser("newuser [options] <username> [<password>]")
sambaopts = options.SambaOptions(parser)
@@ -34,7 +37,6 @@ parser.add_option_group(sambaopts)
parser.add_option_group(options.VersionOptions(parser))
credopts = options.CredentialsOptions(parser)
parser.add_option_group(credopts)
-parser.add_option("--quiet", help="Be quiet", action="store_true")
parser.add_option("--unixname", help="Unix Username", type=str)
parser.add_option("--must-change-at-next-login", help="Force password to be changed on next login", action="store_true")
@@ -56,6 +58,6 @@ if opts.unixname is None:
lp = sambaopts.get_loadparm()
creds = credopts.get_credentials(lp)
-samdb = sambaopts.get_hostconfig().get_samdb(session_info=system_session(),
- credentials=creds)
+samdb = SamDB(url=lp.get("sam database"), session_info=system_session(),
+ credentials=creds, lp=lp)
samdb.newuser(username, opts.unixname, password, force_password_change_at_next_login=opts.must_change_at_next_login)
diff --git a/source4/setup/provision.ldif b/source4/setup/provision.ldif
index 1690dc6c02..d46406e144 100644
--- a/source4/setup/provision.ldif
+++ b/source4/setup/provision.ldif
@@ -5,24 +5,25 @@
dn: CN=Builtin,${DOMAINDN}
objectClass: top
objectClass: builtinDomain
+creationTime: ${CREATTIME}
forceLogoff: -9223372036854775808
+isCriticalSystemObject: TRUE
lockoutDuration: -18000000000
lockOutObservationWindow: -18000000000
lockoutThreshold: 0
maxPwdAge: -37108517437440
minPwdAge: 0
minPwdLength: 0
+modifiedCount: 1
modifiedCountAtLastProm: 0
nextRid: 1000
-pwdProperties: 0
-pwdHistoryLength: 0
objectSid: S-1-5-32
+pwdHistoryLength: 0
+pwdProperties: 0
serverState: 1
-uASCompat: 1
-modifiedCount: 1
-systemFlags: -1946157056
-isCriticalSystemObject: TRUE
showInAdvancedViewOnly: FALSE
+systemFlags: -1946157056
+uASCompat: 1
dn: CN=Deleted Objects,${DOMAINDN}
objectClass: top
@@ -366,6 +367,8 @@ objectClass: nTFRSSettings
systemFlags: -1946157056
isCriticalSystemObject: TRUE
+# Here are missing the FRS objects since we don't support this technique yet
+
dn: CN=FileLinks,CN=System,${DOMAINDN}
objectClass: top
objectClass: fileLinkTracking
diff --git a/source4/setup/provision_configuration.ldif b/source4/setup/provision_configuration.ldif
index ac641da775..506ff21641 100644
--- a/source4/setup/provision_configuration.ldif
+++ b/source4/setup/provision_configuration.ldif
@@ -15,6 +15,8 @@ isDeleted: TRUE
isCriticalSystemObject: TRUE
systemFlags: -1946157056
+# Extended rights
+
dn: CN=Extended-Rights,${CONFIGDN}
objectClass: top
objectClass: container
@@ -637,6 +639,8 @@ appliesTo: bf967a8f-0de6-11d0-a285-00aa003049e2
localizationDisplayId: 28
validAccesses: 256
+# Forest updates
+
dn: CN=ForestUpdates,${CONFIGDN}
objectClass: top
objectClass: container
@@ -645,6 +649,154 @@ dn: CN=Operations,CN=ForestUpdates,${CONFIGDN}
objectClass: top
objectClass: container
+dn: CN=6b800a81-affe-4a15-8e41-6ea0c7aa89e4,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=dd07182c-3174-4c95-902a-d64fee285bbf,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=ffa5ee3c-1405-476d-b344-7ad37d69cc25,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=099f1587-af70-49c6-ab6c-7b3e82be0fe2,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=94fdebc6-8eeb-4640-80de-ec52b9ca17fa,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=1a3f6b15-55f2-4752-ba27-3d38a8232c4d,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=dee21a17-4e8e-4f40-a58c-c0c009b685a7,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=9bd98bb4-4047-4de5-bf4c-7bd1d0f6d21d,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=3fe80fbf-bf39-4773-b5bd-3e5767a30d2d,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=f02915e2-9141-4f73-b8e7-2804662782da,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=39902c52-ef24-4b4b-8033-2c9dfdd173a2,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=20bf09b4-6d0b-4cd1-9c09-4231edf1209b,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=94f238bb-831c-11d6-977b-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=94f238bc-831c-11d6-977b-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=94f238bd-831c-11d6-977b-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=94f238be-831c-11d6-977b-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=94f238bf-831c-11d6-977b-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=94f238c0-831c-11d6-977b-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=eda27b47-e610-11d6-9793-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=eda27b48-e610-11d6-9793-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=eda27b49-e610-11d6-9793-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=eda27b4a-e610-11d6-9793-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=26d9c510-e61a-11d6-9793-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=26d9c511-e61a-11d6-9793-00c04f613221,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=3467dae5-dedd-4648-9066-f48ac186b20a,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=33b7ee33-1386-47cf-baa1-b03e06473253,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=e9ee8d55-c2fb-4723-a333-c80ff4dfbf45,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=ccfae63a-7fb5-454c-83ab-0e8e1214974e,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=ad3c7909-b154-4c16-8bf7-2c3a7870bb3d,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=26ad2ebf-f8f5-44a4-b97c-a616c8b9d09a,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=4444c516-f43a-4c12-9c4b-b5c064941d61,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=436a1a4b-f41a-46e6-ac86-427720ef29f3,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=b2b7fb45-f50d-41bc-a73b-8f580f3b636a,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=1bdf6366-c3db-4d0b-b8cb-f99ba9bce20f,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=63c0f51a-067c-4640-8a4f-044fb33f1049,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=dae441c0-366e-482e-98d9-60a99a1898cc,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=7dd09ca6-f0d6-43bf-b7f8-ef348f435617,CN=Operations,CN=ForestUpdates,${CONFIGDN}
+objectClass: top
+objectClass: container
+
dn: CN=Windows2003Update,CN=ForestUpdates,${CONFIGDN}
objectClass: top
objectClass: container
@@ -662,6 +814,8 @@ description: Quota specifications container
msDS-TombstoneQuotaFactor: 100
systemFlags: -2147483648
+# Partitions
+
dn: CN=Partitions,${CONFIGDN}
objectClass: top
objectClass: crossRefContainer
@@ -669,27 +823,30 @@ systemFlags: -2147483648
msDS-Behavior-Version: ${FOREST_FUNCTIONALALITY}
showInAdvancedViewOnly: TRUE
+# Partitions for DNS are missing since we don't support AD DNS
+
dn: CN=Enterprise Configuration,CN=Partitions,${CONFIGDN}
objectClass: top
objectClass: crossRef
-systemFlags: 1
-nCName: ${CONFIGDN}
dnsRoot: ${DNSDOMAIN}
+nCName: ${CONFIGDN}
+systemFlags: 1
dn: CN=Enterprise Schema,CN=Partitions,${CONFIGDN}
objectClass: top
objectClass: crossRef
-systemFlags: 1
-nCName: ${SCHEMADN}
dnsRoot: ${DNSDOMAIN}
+nCName: ${SCHEMADN}
+systemFlags: 1
dn: CN=${DOMAIN},CN=Partitions,${CONFIGDN}
objectClass: top
objectClass: crossRef
-systemFlags: 3
+dnsRoot: ${DNSDOMAIN}
nCName: ${DOMAINDN}
nETBIOSName: ${DOMAIN}
-dnsRoot: ${DNSDOMAIN}
+nTMixedDomain: 0
+systemFlags: 3
dn: CN=Physical Locations,${CONFIGDN}
objectClass: top
@@ -699,11 +856,91 @@ l: Physical Locations tree root
# Schema located in "ad-schema/*.txt"
+# Services
+
dn: CN=Services,${CONFIGDN}
objectClass: top
objectClass: container
systemFlags: -2147483648
+dn: CN=MsmqServices,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: mSMQEnterpriseSettings
+mSMQVersion: 200
+
+dn: CN=NetServices,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=Public Key Services,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=Certificate Templates,CN=Public Key Services,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=Enrollment Services,CN=Public Key Services,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=Certification Authorities,CN=Public Key Services,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=AIA,CN=Public Key Services,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=CDP,CN=Public Key Services,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=KRA,CN=Public Key Services,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=OID,CN=Public Key Services,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: msPKI-Enterprise-Oid
+
+dn: CN=RRAS,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: container
+
+dn: CN=IdentityDictionary,CN=RRAS,CN=Services,${CONFIGDN}
+objectClass: top
+objectClass: rRASAdministrationDictionary
+msRRASVendorAttributeEntry: 311:6:803:RADIUS Accouting
+msRRASVendorAttributeEntry: 311:6:802:RADIUS Authentication
+msRRASVendorAttributeEntry: 311:6:801:NT Domain Authentication
+msRRASVendorAttributeEntry: 311:6:714:Point to point parallel connection
+msRRASVendorAttributeEntry: 311:6:713:Point to point serial connection
+msRRASVendorAttributeEntry: 311:6:712:Generic LAN
+msRRASVendorAttributeEntry: 311:6:711:Generic WAN
+msRRASVendorAttributeEntry: 311:6:710:X.25
+msRRASVendorAttributeEntry: 311:6:709:IrDA
+msRRASVendorAttributeEntry: 311:6:708:Switched 56
+msRRASVendorAttributeEntry: 311:6:707:SONET
+msRRASVendorAttributeEntry: 311:6:706:Modem
+msRRASVendorAttributeEntry: 311:6:705:ISDN
+msRRASVendorAttributeEntry: 311:6:704:ATM
+msRRASVendorAttributeEntry: 311:6:703:Frame Relay
+msRRASVendorAttributeEntry: 311:6:702:Layer 2 Tunneling Protocol
+msRRASVendorAttributeEntry: 311:6:701:Point-to-Point Tunneling Protocol
+msRRASVendorAttributeEntry: 311:6:604:Network Address and Port Translation
+msRRASVendorAttributeEntry: 311:6:603:Demand Dial Router
+msRRASVendorAttributeEntry: 311:6:602:Remote Access Server
+msRRASVendorAttributeEntry: 311:6:601:LAN-to- LAN Router
+msRRASVendorAttributeEntry: 311:6:503:AppleTalk Forwarding Enabled
+msRRASVendorAttributeEntry: 311:6:502:IPX Forwarding Enabled
+msRRASVendorAttributeEntry: 311:6:501:IP Forwarding Enabled
+msRRASVendorAttributeEntry: 311:5:2:IPX SAP
+msRRASVendorAttributeEntry: 311::5:1:IPX RIP
+msRRASVendorAttributeEntry: 311:1:10:IGMP Only
+msRRASVendorAttributeEntry: 311:0:13:OSPF
+msRRASVendorAttributeEntry: 311:0:8:RIP (version 1 or 2)
+
dn: CN=Windows NT,CN=Services,${CONFIGDN}
objectClass: top
objectClass: container
@@ -711,7 +948,12 @@ objectClass: container
dn: CN=Directory Service,CN=Windows NT,CN=Services,${CONFIGDN}
objectClass: top
objectClass: nTDSService
-sPNMappings: host=ldap,dns,cifs,http
+msDS-Other-Settings: DisableVLVSupport=0
+msDS-Other-Settings: DynamicObjectMinTTL=900
+msDS-Other-Settings: DynamicObjectDefaultTTL=86400
+# "sPNMappings" needs to be enhanced when we add features
+sPNMappings: host=dns,netlogon,rpc,cifs,wins,http
+tombstoneLifetime: 180
dn: CN=Query-Policies,CN=Directory Service,CN=Windows NT,CN=Services,${CONFIGDN}
objectClass: top
@@ -734,6 +976,8 @@ lDAPAdminLimits: MaxConnIdleTime=900
lDAPAdminLimits: InitRecvTimeout=120
lDAPAdminLimits: MaxConnections=5000
+# Sites
+
dn: CN=Sites,${CONFIGDN}
objectClass: top
objectClass: sitesContainer
@@ -759,6 +1003,7 @@ objectClass: top
objectClass: interSiteTransport
transportAddressAttribute: dNSHostName
transportDLLName: ismip.dll
+systemFlags: -2147483648
dn: CN=DEFAULTIPSITELINK,CN=IP,CN=Inter-Site Transports,CN=Sites,${CONFIGDN}
objectClass: top
@@ -785,3 +1030,7 @@ objectClass: top
objectClass: serversContainer
systemFlags: 33554432
+dn: CN=Subnets,CN=Sites,${CONFIGDN}
+objectClass: top
+objectClass: subnetContainer
+systemFlags: -1073741824
diff --git a/source4/setup/provision_self_join.ldif b/source4/setup/provision_self_join.ldif
index c59c421b7f..639bc96040 100644
--- a/source4/setup/provision_self_join.ldif
+++ b/source4/setup/provision_self_join.ldif
@@ -1,41 +1,43 @@
-# Join the DC to itself
+# Accounts for selfjoin (joins DC to itself)
+# Object under "Domain Controllers"
dn: CN=${NETBIOSNAME},OU=Domain Controllers,${DOMAINDN}
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
objectClass: computer
-userAccountControl: 532480
-localPolicyFlags: 0
-primaryGroupID: 516
accountExpires: 9223372036854775807
-sAMAccountName: ${NETBIOSNAME}$
+dNSHostName: ${DNSNAME}
+# "frsComputerReferenceBL" doesn't exist since we still miss FRS support
+isCriticalSystemObject: TRUE
+localPolicyFlags: 0
operatingSystem: Samba
operatingSystemVersion: ${SAMBA_VERSION_STRING}
-dNSHostName: ${DNSNAME}
-userPassword:: ${MACHINEPASS_B64}
-servicePrincipalName: HOST/${DNSNAME}
+primaryGroupID: 516
+# "rIDSetReferences" doesn't exist since we still miss distributed RIDs
+sAMAccountName: ${NETBIOSNAME}$
+# "servicePrincipalName" for FRS doesn't exit since we still miss FRS support
+# "servicePrincipalName"s for DNS ("ldap/../ForestDnsZones",
+# "ldap/../DomainDnsZones", "DNS/..") don't exist since we don't support AD DNS
+servicePrincipalName: GC/${DNSNAME}/${REALM}
+servicePrincipalName: HOST/${DNSNAME}/${DOMAIN}
servicePrincipalName: HOST/${NETBIOSNAME}
+servicePrincipalName: HOST/${DNSNAME}
servicePrincipalName: HOST/${DNSNAME}/${REALM}
-servicePrincipalName: HOST/${NETBIOSNAME}/${REALM}
-servicePrincipalName: HOST/${DNSNAME}/${DOMAIN}
-servicePrincipalName: HOST/${NETBIOSNAME}/${DOMAIN}
-isCriticalSystemObject: TRUE
+# "servicePrincipalName"s with GUIDs are located in
+# "provision_self_join_modify.ldif"
+servicePrincipalName: ldap/${DNSNAME}/${DOMAIN}
+servicePrincipalName: ldap/${NETBIOSNAME}
+servicePrincipalName: ldap/${DNSNAME}
+servicePrincipalName: ldap/${DNSNAME}/${REALM}
+userAccountControl: 532480
+userPassword:: ${MACHINEPASS_B64}
-#Provide a account for DNS keytab export
-dn: CN=dns,CN=Users,${DOMAINDN}
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-description: DNS Service Account
-userAccountControl: 514
-accountExpires: 9223372036854775807
-sAMAccountName: dns
-servicePrincipalName: DNS/${DNSDOMAIN}
-userPassword:: ${DNSPASS_B64}
-isCriticalSystemObject: TRUE
+# Here are missing the objects for the NTFRS subscription and the RID set since
+# we don't support those techniques (FRS, distributed RIDs) yet.
+
+# Objects under "Configuration/Sites/<Default sitename>/Servers"
dn: ${SERVERDN}
objectClass: top
@@ -48,14 +50,34 @@ dn: CN=NTDS Settings,${SERVERDN}
objectClass: top
objectClass: applicationSettings
objectClass: nTDSDSA
-options: 1
-systemFlags: 33554432
dMDLocation: ${SCHEMADN}
+hasMasterNCs: ${CONFIGDN}
+hasMasterNCs: ${SCHEMADN}
+hasMasterNCs: ${DOMAINDN}
invocationId: ${INVOCATIONID}
msDS-Behavior-Version: ${DOMAIN_CONTROLLER_FUNCTIONALITY}
+msDS-HasDomainNCs: ${DOMAINDN}
+# "msDS-HasInstantiatedNCs"s for DNS don't exist since we don't support AD DNS
+msDS-HasInstantiatedNCs: B:8:0000000D:${CONFIGDN}
+msDS-HasInstantiatedNCs: B:8:0000000D:${SCHEMADN}
+msDS-HasInstantiatedNCs: B:8:00000005:${DOMAINDN}
+# "msDS-hasMasterNCs"s for DNS don't exist since we don't support AD DNS
msDS-hasMasterNCs: ${CONFIGDN}
msDS-hasMasterNCs: ${SCHEMADN}
msDS-hasMasterNCs: ${DOMAINDN}
-hasMasterNCs: ${CONFIGDN}
-hasMasterNCs: ${SCHEMADN}
-hasMasterNCs: ${DOMAINDN}
+options: 1
+systemFlags: 33554432
+
+# Provides an account for DNS keytab export
+dn: CN=dns,CN=Users,${DOMAINDN}
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+description: DNS Service Account
+userAccountControl: 514
+accountExpires: 9223372036854775807
+sAMAccountName: dns
+servicePrincipalName: DNS/${DNSDOMAIN}
+userPassword:: ${DNSPASS_B64}
+isCriticalSystemObject: TRUE
diff --git a/source4/setup/pwsettings b/source4/setup/pwsettings
index cd9c07dfb5..6a5e18ef59 100755
--- a/source4/setup/pwsettings
+++ b/source4/setup/pwsettings
@@ -1,21 +1,32 @@
#!/usr/bin/python
#
-# Sets password settings (Password complexity, history length,
-# minimum password length, the minimum and maximum password age) on a
-# Samba4 server
+# Sets password settings (Password complexity, history length, minimum password
+# length, the minimum and maximum password age) on a Samba4 server
#
-# Copyright Jelmer Vernooij 2008
-# Copyright Matthias Dieter Wallnoefer 2009
-# Copyright Andrew Kroeger 2009
-# Released under the GNU GPL version 3 or later
+# Copyright Matthias Dieter Wallnoefer 2009
+# Copyright Andrew Kroeger 2009
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
#
-import os, sys
-sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "../bin/python"))
+import sys
+
+# Find right directory when running from source tree
+sys.path.insert(0, "bin/python")
import samba.getopt as options
import optparse
-import pwd
import ldb
from samba.auth import system_session
@@ -29,7 +40,6 @@ parser.add_option_group(options.VersionOptions(parser))
credopts = options.CredentialsOptions(parser)
parser.add_option_group(credopts)
parser.add_option("--quiet", help="Be quiet", action="store_true")
-parser.add_option("-H", help="LDB URL for database or target server", type=str)
parser.add_option("--complexity",
help="The password complexity (on | off | default). Default is 'on'", type=str)
parser.add_option("--history-length",
@@ -55,15 +65,9 @@ if len(args) == 0:
sys.exit(1)
lp = sambaopts.get_loadparm()
-
creds = credopts.get_credentials(lp)
-if opts.H is not None:
- url = opts.H
-else:
- url = lp.get("sam database")
-
-samdb = SamDB(url=url, session_info=system_session(),
+samdb = SamDB(url=lp.get("sam database"), session_info=system_session(),
credentials=creds, lp=lp)
domain_dn = SamDB.domain_dn(samdb)
@@ -79,13 +83,10 @@ try:
min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24))
max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24))
except:
+ print "ERROR: Could not retrieve password properties!"
if args[0] == "show":
- print "ERROR: Password informations missing in your AD domain object!"
print "So no settings can be displayed!"
- sys.exit(1)
- else:
- print "ERROR: Could not retrieve password properties (used for password complexity setting)"
- sys.exit(1)
+ sys.exit(1)
if args[0] == "show":
message("Password informations for domain '" + domain_dn + "'")
diff --git a/source4/setup/setexpiry b/source4/setup/setexpiry
index db7cdd412f..6c6305ceaf 100755
--- a/source4/setup/setexpiry
+++ b/source4/setup/setexpiry
@@ -1,9 +1,23 @@
#!/usr/bin/python
#
-# Sets the password expiry for a user on a Samba4 server
-# Copyright Andrew Tridgell 2005
-# Copyright Jelmer Vernooij 2008
-# Released under the GNU GPL version 3 or later
+# Sets the user password expiry on a Samba4 server
+# Copyright Jelmer Vernooij 2008
+#
+# Based on the original in EJS:
+# Copyright Andrew Tridgell 2005
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
#
import sys
@@ -13,32 +27,38 @@ sys.path.insert(0, "bin/python")
import samba.getopt as options
import optparse
-from getpass import getpass
+
from samba.auth import system_session
+from samba.samdb import SamDB
-parser = optparse.OptionParser("setexpiry [options] <username>")
+parser = optparse.OptionParser("setexpiry [username] [options]")
sambaopts = options.SambaOptions(parser)
parser.add_option_group(sambaopts)
parser.add_option_group(options.VersionOptions(parser))
credopts = options.CredentialsOptions(parser)
parser.add_option_group(credopts)
+parser.add_option("--filter", help="LDAP Filter to set password on", type=str)
parser.add_option("--days", help="Days to expiry", type=int)
-parser.add_option("--noexpiry", help="Never expire", action="store_true")
+parser.add_option("--noexpiry", help="Password does never expire", action="store_true")
opts, args = parser.parse_args()
-if len(args) == 0:
+if (len(args) == 0) and (filter is None):
+ print "Either the username or '--filter' must be specified!"
parser.print_usage()
sys.exit(1)
-username = args[0]
+days = opts.days
+if days is None:
+ days = 0
+
+if filter is None:
+ username = args[0]
+ filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
lp = sambaopts.get_loadparm()
creds = credopts.get_credentials(lp)
-samdb = sambaopts.get_hostconfig().get_samdb(session_info=system_session(),
- credentials=creds)
-days = opts.days
-if days is None:
- days = 0
-samdb.setexpiry(username, days*24*3600, opts.noexpiry)
+samdb = SamDB(url=lp.get("sam database"), session_info=system_session(),
+ credentials=creds, lp=lp)
+samdb.setexpiry(filter, days*24*3600, noexpiry=opts.noexpiry)
diff --git a/source4/setup/setpassword b/source4/setup/setpassword
index 513730d649..d8a2a1144a 100755
--- a/source4/setup/setpassword
+++ b/source4/setup/setpassword
@@ -20,15 +20,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-import os, sys
+import sys
# Find right directory when running from source tree
sys.path.insert(0, "bin/python")
import samba.getopt as options
import optparse
-import pwd
-import sys
+
from getpass import getpass
from samba.auth import system_session
from samba.samdb import SamDB
@@ -45,13 +44,6 @@ parser.add_option("--must-change-at-next-login", help="Force password to be chan
opts, args = parser.parse_args()
-#
-# print a message if quiet is not set
-#
-def message(text):
- if not opts.quiet:
- print text
-
filter = opts.filter
if (len(args) == 0) and (filter is None):
@@ -65,7 +57,7 @@ if password is None:
if filter is None:
username = args[0]
- filter = "(&(objectclass=user)(samAccountName=%s))" % (username)
+ filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
lp = sambaopts.get_loadparm()
creds = credopts.get_credentials(lp)
diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk
index b850548b3d..b85beb0bc0 100644
--- a/source4/smbd/config.mk
+++ b/source4/smbd/config.mk
@@ -2,7 +2,9 @@
[SUBSYSTEM::service]
PRIVATE_DEPENDENCIES = \
- LIBTEVENT MESSAGING samba_socket NDR_NAMED_PIPE_AUTH NAMED_PIPE_AUTH_TSTREAM
+ LIBTEVENT MESSAGING samba_socket \
+ NDR_NAMED_PIPE_AUTH NAMED_PIPE_AUTH_TSTREAM \
+ HEIMDAL_GSSAPI CREDENTIALS
service_OBJ_FILES = $(addprefix $(smbdsrcdir)/, \
service.o \
diff --git a/source4/smbd/service_named_pipe.c b/source4/smbd/service_named_pipe.c
index f82d91e867..940edf2cb5 100644
--- a/source4/smbd/service_named_pipe.c
+++ b/source4/smbd/service_named_pipe.c
@@ -30,6 +30,9 @@
#include "librpc/gen_ndr/ndr_named_pipe_auth.h"
#include "system/passwd.h"
#include "libcli/raw/smb.h"
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+#include <gssapi/gssapi.h>
struct named_pipe_socket {
const char *pipe_name;
@@ -53,6 +56,11 @@ static void named_pipe_handover_connection(void *private_data)
TEVENT_FD_NOT_WRITEABLE(conn->event.fde);
+ packet_set_socket(pipe_conn->packet, NULL);
+ packet_set_event_context(pipe_conn->packet, NULL);
+ packet_set_fde(pipe_conn->packet, NULL);
+ TALLOC_FREE(pipe_conn->packet);
+
if (!NT_STATUS_IS_OK(pipe_conn->status)) {
stream_terminate_connection(conn, nt_errstr(pipe_conn->status));
return;
@@ -63,7 +71,7 @@ static void named_pipe_handover_connection(void *private_data)
*/
conn->ops = pipe_conn->pipe_sock->ops;
conn->private_data = pipe_conn->pipe_sock->private_data;
- talloc_free(pipe_conn);
+ talloc_unlink(conn, pipe_conn);
/* we're now ready to start receiving events on this stream */
TEVENT_FD_READABLE(conn->event.fde);
@@ -214,6 +222,94 @@ static NTSTATUS named_pipe_recv_auth_request(void *private_data,
talloc_steal(conn->session_info, req.info.info2.session_key);
break;
+ case 3:
+ rep.level = 3;
+ rep.info.info3.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
+ rep.info.info3.device_state = 0xff | 0x0400 | 0x0100;
+ rep.info.info3.allocation_size = 4096;
+
+ if (!req.info.info3.sam_info3) {
+ /*
+ * anon connection, we don't create a session info
+ * and leave it NULL
+ */
+ rep.status = NT_STATUS_OK;
+ break;
+ }
+
+ val.sam3 = req.info.info3.sam_info3;
+
+ rep.status = make_server_info_netlogon_validation(pipe_conn,
+ val.sam3->base.account_name.string,
+ 3, &val, &server_info);
+ if (!NT_STATUS_IS_OK(rep.status)) {
+ DEBUG(2, ("make_server_info_netlogon_validation returned "
+ "%s\n", nt_errstr(rep.status)));
+ goto reply;
+ }
+
+ /* setup the session_info on the connection */
+ rep.status = auth_generate_session_info(conn,
+ conn->event.ctx,
+ conn->lp_ctx,
+ server_info,
+ &conn->session_info);
+ if (!NT_STATUS_IS_OK(rep.status)) {
+ DEBUG(2, ("auth_generate_session_info failed: %s\n",
+ nt_errstr(rep.status)));
+ goto reply;
+ }
+
+ if (req.info.info3.gssapi_delegated_creds_length) {
+ OM_uint32 minor_status;
+ gss_buffer_desc cred_token;
+ gss_cred_id_t cred_handle;
+ int ret;
+
+ DEBUG(10, ("named_pipe_auth: delegated credentials supplied by client\n"));
+
+ cred_token.value = req.info.info3.gssapi_delegated_creds;
+ cred_token.length = req.info.info3.gssapi_delegated_creds_length;
+
+ ret = gss_import_cred(&minor_status,
+ &cred_token,
+ &cred_handle);
+ if (ret != GSS_S_COMPLETE) {
+ rep.status = NT_STATUS_INTERNAL_ERROR;
+ goto reply;
+ }
+
+ conn->session_info->credentials = cli_credentials_init(conn->session_info);
+ if (!conn->session_info->credentials) {
+ rep.status = NT_STATUS_NO_MEMORY;
+ goto reply;
+ }
+
+ cli_credentials_set_conf(conn->session_info->credentials,
+ conn->lp_ctx);
+ /* Just so we don't segfault trying to get at a username */
+ cli_credentials_set_anonymous(conn->session_info->credentials);
+
+ ret = cli_credentials_set_client_gss_creds(conn->session_info->credentials,
+ conn->event.ctx,
+ conn->lp_ctx,
+ cred_handle,
+ CRED_SPECIFIED);
+ if (ret) {
+ rep.status = NT_STATUS_INTERNAL_ERROR;
+ goto reply;
+ }
+
+ /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
+ cli_credentials_set_kerberos_state(conn->session_info->credentials,
+ CRED_MUST_USE_KERBEROS);
+ }
+
+ conn->session_info->session_key = data_blob_const(req.info.info3.session_key,
+ req.info.info3.session_key_length);
+ talloc_steal(conn->session_info, req.info.info3.session_key);
+
+ break;
default:
DEBUG(2, ("named_pipe_auth_req: unknown level %u\n",
req.level));
@@ -235,7 +331,7 @@ reply:
return status;
}
- DEBUG(10,("named_pipe_auth reply[%u]\n", rep_blob.length));
+ DEBUG(10,("named_pipe_auth reply[%u]\n", (unsigned)rep_blob.length));
dump_data(11, rep_blob.data, rep_blob.length);
if (DEBUGLVL(10)) {
NDR_PRINT_DEBUG(named_pipe_auth_rep, &rep);
diff --git a/source4/torture/rpc/spoolss_notify.c b/source4/torture/rpc/spoolss_notify.c
index a8a0ca5df6..60f1175f27 100644
--- a/source4/torture/rpc/spoolss_notify.c
+++ b/source4/torture/rpc/spoolss_notify.c
@@ -20,10 +20,12 @@
*/
#include "includes.h"
+#include "system/filesys.h"
#include "torture/torture.h"
#include "torture/rpc/rpc.h"
#include "librpc/gen_ndr/ndr_spoolss_c.h"
#include "rpc_server/dcerpc_server.h"
+#include "rpc_server/service_rpc.h"
#include "lib/events/events.h"
#include "smbd/process_model.h"
#include "smb_server/smb_server.h"
@@ -191,6 +193,7 @@ static bool test_RFFPCNEx(struct torture_context *tctx,
NTSTATUS status;
struct dcesrv_context *dce_ctx;
const char *endpoints[] = { "spoolss", NULL };
+ struct dcesrv_endpoint *e;
struct spoolss_NotifyOption t1;
struct spoolss_ClosePrinter cp;
@@ -244,6 +247,23 @@ static bool test_RFFPCNEx(struct torture_context *tctx,
torture_assert_ntstatus_ok(tctx, status,
"unable to initialize DCE/RPC server");
+ /* Make sure the directory for NCALRPC exists */
+ if (!directory_exist(lp_ncalrpc_dir(tctx->lp_ctx))) {
+ int ret;
+ ret = mkdir(lp_ncalrpc_dir(tctx->lp_ctx), 0755);
+ torture_assert(tctx, (ret == 0), talloc_asprintf(tctx,
+ "failed to mkdir(%s) ret[%d] errno[%d - %s]",
+ lp_ncalrpc_dir(tctx->lp_ctx), ret,
+ errno, strerror(errno)));
+ }
+
+ for (e=dce_ctx->endpoint_list;e;e=e->next) {
+ status = dcesrv_add_ep(dce_ctx, tctx->lp_ctx,
+ e, tctx->ev, &single_ops);
+ torture_assert_ntstatus_ok(tctx, status,
+ "unable listen on dcerpc endpoint server");
+ }
+
r.in.flags = 0;
r.in.local_machine = talloc_asprintf(tctx, "\\\\%s", address);
r.in.options = 0;
@@ -293,7 +313,7 @@ static bool test_RFFPCNEx(struct torture_context *tctx,
* on Samba 4 will cause an irpc broadcast call.
*/
static bool test_ReplyOpenPrinter(struct torture_context *tctx,
- struct dcerpc_pipe *pipe)
+ struct dcerpc_pipe *p)
{
struct spoolss_ReplyOpenPrinter r;
struct spoolss_ReplyClosePrinter s;
@@ -307,7 +327,7 @@ static bool test_ReplyOpenPrinter(struct torture_context *tctx,
r.out.handle = &h;
torture_assert_ntstatus_ok(tctx,
- dcerpc_spoolss_ReplyOpenPrinter(pipe, tctx, &r),
+ dcerpc_spoolss_ReplyOpenPrinter(p, tctx, &r),
"spoolss_ReplyOpenPrinter call failed");
torture_assert_werr_ok(tctx, r.out.result, "error return code");
@@ -316,7 +336,7 @@ static bool test_ReplyOpenPrinter(struct torture_context *tctx,
s.out.handle = &h;
torture_assert_ntstatus_ok(tctx,
- dcerpc_spoolss_ReplyClosePrinter(pipe, tctx, &s),
+ dcerpc_spoolss_ReplyClosePrinter(p, tctx, &s),
"spoolss_ReplyClosePrinter call failed");
torture_assert_werr_ok(tctx, r.out.result, "error return code");