From 8e2d624a588552f5d06f21fe37281615f3ec6296 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 3 Sep 2007 13:13:25 +0000 Subject: r24937: Merge tests spoolss RPC callbacks. (This used to be commit 9b256a0ca232ea6e89771bf73a1adf877273a752) --- source4/lib/socket/netif.h | 2 + source4/libcli/nbt/nbtname.c | 2 +- source4/librpc/rpc/dcerpc_connect.c | 5 +- source4/librpc/rpc/dcerpc_smb.c | 4 +- source4/main.mk | 4 +- source4/rpc_server/config.mk | 5 +- source4/rpc_server/dcerpc_server.c | 97 +- source4/rpc_server/dcerpc_sock.c | 371 ------- source4/rpc_server/service_rpc.c | 456 ++++++++ source4/rpc_server/spoolss/dcesrv_spoolss.c | 75 +- source4/smb_server/smb_server.c | 6 +- source4/smb_server/smb_server.h | 4 + source4/smbd/process_model.h | 2 + source4/smbd/process_single.c | 2 +- source4/smbd/service_stream.c | 6 +- source4/torture/config.mk | 4 +- source4/torture/rpc/rpc.c | 1 + source4/torture/rpc/spoolss.c | 1517 ++++++++++----------------- source4/torture/rpc/spoolss_notify.c | 295 ++++++ 19 files changed, 1442 insertions(+), 1416 deletions(-) delete mode 100644 source4/rpc_server/dcerpc_sock.c create mode 100644 source4/rpc_server/service_rpc.c create mode 100644 source4/torture/rpc/spoolss_notify.c (limited to 'source4') diff --git a/source4/lib/socket/netif.h b/source4/lib/socket/netif.h index dea7476193..4855f4bd73 100644 --- a/source4/lib/socket/netif.h +++ b/source4/lib/socket/netif.h @@ -19,6 +19,8 @@ along with this program. If not, see . */ +#include "system/network.h" + struct iface_struct { char name[16]; struct in_addr ip; diff --git a/source4/libcli/nbt/nbtname.c b/source4/libcli/nbt/nbtname.c index af3f62b987..911eb0cb5f 100644 --- a/source4/libcli/nbt/nbtname.c +++ b/source4/libcli/nbt/nbtname.c @@ -401,7 +401,7 @@ _PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx, n->scope = NULL; n->type = type; - if (is_ipaddress(name)) { + if (is_ipaddress(name) || name == NULL) { n->name = "*SMBSERVER"; return; } diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c index be95f21594..bd05498aed 100644 --- a/source4/librpc/rpc/dcerpc_connect.c +++ b/source4/librpc/rpc/dcerpc_connect.c @@ -110,7 +110,10 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CT remote rpc server */ conn->in.dest_host = s->io.binding->host; conn->in.port = 0; - conn->in.called_name = s->io.binding->target_hostname; + if (s->io.binding->target_hostname == NULL) + conn->in.called_name = "*SMBSERVER"; + else + conn->in.called_name = s->io.binding->target_hostname; conn->in.service = "IPC$"; conn->in.service_type = NULL; conn->in.workgroup = lp_workgroup(); diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c index 6b43de3358..5064e998dd 100644 --- a/source4/librpc/rpc/dcerpc_smb.c +++ b/source4/librpc/rpc/dcerpc_smb.c @@ -430,7 +430,9 @@ struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_pipe *p, /* if we don't have a binding on this pipe yet, then create one */ if (p->binding == NULL) { NTSTATUS status; - char *s = talloc_asprintf(p, "ncacn_np:%s", tree->session->transport->socket->hostname); + char *s; + SMB_ASSERT(tree->session->transport->socket->hostname != NULL); + s = talloc_asprintf(p, "ncacn_np:%s", tree->session->transport->socket->hostname); if (s == NULL) return NULL; status = dcerpc_parse_binding(p, s, &p->binding); talloc_free(s); diff --git a/source4/main.mk b/source4/main.mk index a0fafec3a3..609560e4a7 100644 --- a/source4/main.mk +++ b/source4/main.mk @@ -315,7 +315,7 @@ quicktestone: all testenv: everything $(SELFTEST) --socket-wrapper --testenv -valgrindtest: valgrindtest-quick +valgrindtest: valgrindtest-all valgrindtest-quick: all SMBD_VALGRIND="xterm -n smbd -e valgrind -q --db-attach=yes --num-callers=30" \ @@ -332,7 +332,7 @@ valgrindtest-env: everything VALGRIND="valgrind -q --num-callers=30 --log-file=${selftest_prefix}/valgrind.log" \ $(SELFTEST) --socket-wrapper --testenv -gdbtest: gdbtest-quick +gdbtest: gdbtest-all gdbtest-quick: all SMBD_VALGRIND="xterm -n smbd -e $(srcdir)/script/gdb_run " \ diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk index 0de09b572e..7a39e56060 100644 --- a/source4/rpc_server/config.mk +++ b/source4/rpc_server/config.mk @@ -157,7 +157,8 @@ OBJ_FILES = \ PRIVATE_DEPENDENCIES = \ DCERPC_COMMON \ NDR_SPOOLSS \ - ntptr + ntptr \ + RPC_NDR_SPOOLSS # End MODULE dcerpc_spoolss ################################################ @@ -182,7 +183,6 @@ PUBLIC_HEADERS = dcerpc_server.h PUBLIC_PROTO_HEADER = dcerpc_server_proto.h OBJ_FILES = \ dcerpc_server.o \ - dcerpc_sock.o \ dcesrv_auth.o \ dcesrv_mgmt.o \ handles.o @@ -196,5 +196,6 @@ PRIVATE_DEPENDENCIES = \ [MODULE::DCESRV] INIT_FUNCTION = server_service_rpc_init +OBJ_FILES = service_rpc.o SUBSYSTEM = service PRIVATE_DEPENDENCIES = dcerpc_server diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 35b37b3af6..466d35c373 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -39,11 +39,11 @@ extern const struct dcesrv_interface dcesrv_mgmt_interface; /* see if two endpoints match */ -static BOOL endpoints_match(const struct dcerpc_binding *ep1, +static bool endpoints_match(const struct dcerpc_binding *ep1, const struct dcerpc_binding *ep2) { if (ep1->transport != ep2->transport) { - return False; + return false; } if (!ep1->endpoint || !ep2->endpoint) { @@ -51,9 +51,9 @@ static BOOL endpoints_match(const struct dcerpc_binding *ep1, } if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) - return False; + return false; - return True; + return true; } /* @@ -1246,7 +1246,7 @@ _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, return status; } -static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx) +_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx) { NTSTATUS status; struct dcesrv_context *dce_ctx; @@ -1282,21 +1282,6 @@ static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_s return NT_STATUS_OK; } -/* - initialise the dcerpc server context for ncacn_np based services -*/ -_PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx) -{ - NTSTATUS status; - struct dcesrv_context *dce_ctx; - - status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx); - NT_STATUS_NOT_OK_RETURN(status); - - *_dce_ctx = dce_ctx; - return NT_STATUS_OK; -} - /* the list of currently registered DCERPC endpoint servers. */ static struct ep_server { @@ -1379,78 +1364,18 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void) } /* - open the dcerpc server sockets + initialise the dcerpc server context for ncacn_np based services */ -static void dcesrv_task_init(struct task_server *task) +_PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx) { NTSTATUS status; struct dcesrv_context *dce_ctx; - struct dcesrv_endpoint *e; - task_server_set_title(task, "task[dcesrv]"); - - status = dcesrv_init_context(task->event_ctx, - lp_dcerpc_endpoint_servers(), - &dce_ctx); - if (!NT_STATUS_IS_OK(status)) goto failed; - - /* Make sure the directory for NCALRPC exists */ - if (!directory_exist(lp_ncalrpc_dir())) { - mkdir(lp_ncalrpc_dir(), 0755); - } - - for (e=dce_ctx->endpoint_list;e;e=e->next) { - switch (e->ep_description->transport) { - case NCACN_UNIX_STREAM: - status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops); - if (!NT_STATUS_IS_OK(status)) goto failed; - break; - - case NCALRPC: - status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops); - if (!NT_STATUS_IS_OK(status)) goto failed; - break; - - case NCACN_IP_TCP: - status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops); - if (!NT_STATUS_IS_OK(status)) goto failed; - break; - - case NCACN_NP: - status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops); - if (!NT_STATUS_IS_OK(status)) goto failed; - break; - - default: - status = NT_STATUS_NOT_SUPPORTED; - if (!NT_STATUS_IS_OK(status)) goto failed; - } - } - - return; -failed: - task_server_terminate(task, "Failed to startup dcerpc server task"); -} + status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx); + NT_STATUS_NOT_OK_RETURN(status); -/* - called on startup of the smb server service It's job is to start - listening on all configured sockets -*/ -static NTSTATUS dcesrv_init(struct event_context *event_context, - const struct model_ops *model_ops) -{ - return task_server_startup(event_context, model_ops, dcesrv_task_init); + *_dce_ctx = dce_ctx; + return NT_STATUS_OK; } -NTSTATUS server_service_rpc_init(void) -{ - init_module_fn static_init[] = STATIC_dcerpc_server_MODULES; - init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server"); - - run_init_functions(static_init); - run_init_functions(shared_init); - talloc_free(shared_init); - - return register_server_service("rpc", dcesrv_init); -} diff --git a/source4/rpc_server/dcerpc_sock.c b/source4/rpc_server/dcerpc_sock.c deleted file mode 100644 index 834758356b..0000000000 --- a/source4/rpc_server/dcerpc_sock.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - server side dcerpc using various kinds of sockets (tcp, unix domain) - - Copyright (C) Andrew Tridgell 2003 - Copyright (C) Stefan (metze) Metzmacher 2004-2005 - Copyright (C) Jelmer Vernooij 2004 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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 . -*/ - -#include "includes.h" -#include "lib/socket/socket.h" -#include "lib/events/events.h" -#include "rpc_server/dcerpc_server.h" -#include "smbd/service_stream.h" -#include "smbd/service.h" -#include "lib/messaging/irpc.h" -#include "system/network.h" -#include "lib/socket/netif.h" -#include "auth/auth.h" - -struct dcesrv_socket_context { - const struct dcesrv_endpoint *endpoint; - struct dcesrv_context *dcesrv_ctx; -}; - -/* - write_fn callback for dcesrv_output() -*/ -static NTSTATUS dcerpc_write_fn(void *private_data, DATA_BLOB *out, size_t *nwritten) -{ - NTSTATUS status; - struct socket_context *sock = talloc_get_type(private_data, struct socket_context); - size_t sendlen; - - status = socket_send(sock, out, &sendlen); - NT_STATUS_IS_ERR_RETURN(status); - - *nwritten = sendlen; - return status; -} - -static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason) -{ - struct stream_connection *srv_conn; - srv_conn = talloc_get_type(dce_conn->transport.private_data, - struct stream_connection); - - stream_terminate_connection(srv_conn, reason); -} - -static void dcesrv_sock_report_output_data(struct dcesrv_connection *dcesrv_conn) -{ - struct stream_connection *srv_conn; - srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, - struct stream_connection); - - if (srv_conn && srv_conn->event.fde) { - EVENT_FD_WRITEABLE(srv_conn->event.fde); - } -} - -static struct socket_address *dcesrv_sock_get_my_addr(struct dcesrv_connection *dcesrv_conn, TALLOC_CTX *mem_ctx) -{ - struct stream_connection *srv_conn; - srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, - struct stream_connection); - - return socket_get_my_addr(srv_conn->socket, mem_ctx); -} - -static struct socket_address *dcesrv_sock_get_peer_addr(struct dcesrv_connection *dcesrv_conn, TALLOC_CTX *mem_ctx) -{ - struct stream_connection *srv_conn; - srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, - struct stream_connection); - - return socket_get_peer_addr(srv_conn->socket, mem_ctx); -} - -static void dcesrv_sock_accept(struct stream_connection *srv_conn) -{ - NTSTATUS status; - struct dcesrv_socket_context *dcesrv_sock = - talloc_get_type(srv_conn->private, struct dcesrv_socket_context); - struct dcesrv_connection *dcesrv_conn = NULL; - struct auth_session_info *session_info = NULL; - - status = auth_anonymous_session_info(srv_conn, &session_info); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n", - nt_errstr(status))); - stream_terminate_connection(srv_conn, nt_errstr(status)); - return; - } - - status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, - srv_conn, - dcesrv_sock->endpoint, - session_info, - srv_conn->event.ctx, - srv_conn->msg_ctx, - srv_conn->server_id, - DCESRV_CALL_STATE_FLAG_MAY_ASYNC, - &dcesrv_conn); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", - nt_errstr(status))); - stream_terminate_connection(srv_conn, nt_errstr(status)); - return; - } - - dcesrv_conn->transport.private_data = srv_conn; - dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data; - dcesrv_conn->transport.get_my_addr = dcesrv_sock_get_my_addr; - dcesrv_conn->transport.get_peer_addr = dcesrv_sock_get_peer_addr; - - srv_conn->private = dcesrv_conn; - - irpc_add_name(srv_conn->msg_ctx, "rpc_server"); - - return; -} - -static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags) -{ - NTSTATUS status; - struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection); - DATA_BLOB tmp_blob; - size_t nread; - - if (dce_conn->processing) { - EVENT_FD_NOT_READABLE(conn->event.fde); - return; - } - - tmp_blob = data_blob_talloc(conn->socket, NULL, 0x1000); - if (tmp_blob.data == NULL) { - dcesrv_terminate_connection(dce_conn, "out of memory"); - return; - } - - status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread); - if (NT_STATUS_IS_ERR(status)) { - dcesrv_terminate_connection(dce_conn, nt_errstr(status)); - return; - } - if (nread == 0) { - talloc_free(tmp_blob.data); - return; - } - - tmp_blob.length = nread; - - dce_conn->processing = True; - status = dcesrv_input(dce_conn, &tmp_blob); - dce_conn->processing = False; - talloc_free(tmp_blob.data); - - EVENT_FD_READABLE(conn->event.fde); - - if (!NT_STATUS_IS_OK(status)) { - dcesrv_terminate_connection(dce_conn, nt_errstr(status)); - return; - } - - if (dce_conn->call_list && dce_conn->call_list->replies) { - EVENT_FD_WRITEABLE(conn->event.fde); - } -} - -static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags) -{ - struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection); - NTSTATUS status; - - status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn); - if (NT_STATUS_IS_ERR(status)) { - dcesrv_terminate_connection(dce_conn, "eof on socket"); - return; - } - - if (!dce_conn->call_list || !dce_conn->call_list->replies) { - EVENT_FD_NOT_WRITEABLE(conn->event.fde); - } -} - - -static const struct stream_server_ops dcesrv_stream_ops = { - .name = "rpc", - .accept_connection = dcesrv_sock_accept, - .recv_handler = dcesrv_sock_recv, - .send_handler = dcesrv_sock_send, -}; - - - -NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - struct dcesrv_socket_context *dcesrv_sock; - uint16_t port = 1; - NTSTATUS status; - - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); - NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); - - /* remember the endpoint of this socket */ - dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - - status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, - "unix", e->ep_description->endpoint, &port, - dcesrv_sock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", - e->ep_description->endpoint, nt_errstr(status))); - } - - return status; -} - -NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - struct dcesrv_socket_context *dcesrv_sock; - uint16_t port = 1; - char *full_path; - NTSTATUS status; - - if (!e->ep_description->endpoint) { - /* No identifier specified: use DEFAULT. - * DO NOT hardcode this value anywhere else. Rather, specify - * no endpoint and let the epmapper worry about it. */ - e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT"); - } - - full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description->endpoint); - - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); - NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); - - /* remember the endpoint of this socket */ - dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - - status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, - "unix", full_path, &port, dcesrv_sock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n", - e->ep_description->endpoint, full_path, nt_errstr(status))); - } - return status; -} - - -/* - add a socket address to the list of events, one event per dcerpc endpoint -*/ -static NTSTATUS add_socket_rpc_pipe_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - struct dcesrv_socket_context *dcesrv_sock; - NTSTATUS status; - - if (e->ep_description->endpoint == NULL) { - DEBUG(0, ("Endpoint mandatory for named pipes\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); - NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); - - /* remember the endpoint of this socket */ - dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - - status = NT_STATUS_OK; -#if 0 - - status = stream_setup_smb_pipe(event_ctx, model_ops, &dcesrv_stream_ops, - e->ep_description->endpoint, dcesrv_sock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", - e->ep_description->endpoint, nt_errstr(status))); - } -#endif - return status; -} - -NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - NTSTATUS status; - - status = add_socket_rpc_pipe_iface(dce_ctx, e, event_ctx, model_ops); - NT_STATUS_NOT_OK_RETURN(status); - - return status; -} - -/* - add a socket address to the list of events, one event per dcerpc endpoint -*/ -static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops, - const char *address) -{ - struct dcesrv_socket_context *dcesrv_sock; - uint16_t port = 0; - NTSTATUS status; - - if (e->ep_description->endpoint) { - port = atoi(e->ep_description->endpoint); - } - - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); - NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); - - /* remember the endpoint of this socket */ - dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - - status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, - "ipv4", address, &port, dcesrv_sock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", - address, port, nt_errstr(status))); - } - - if (e->ep_description->endpoint == NULL) { - e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port); - } - - return status; -} - -NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - NTSTATUS status; - - /* Add TCP/IP sockets */ - if (lp_interfaces() && lp_bind_interfaces_only()) { - int num_interfaces = iface_count(); - int i; - for(i = 0; i < num_interfaces; i++) { - const char *address = iface_n_ip(i); - status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address); - NT_STATUS_NOT_OK_RETURN(status); - } - } else { - status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, lp_socket_address()); - NT_STATUS_NOT_OK_RETURN(status); - } - - return NT_STATUS_OK; -} diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c new file mode 100644 index 0000000000..6d70dd0bae --- /dev/null +++ b/source4/rpc_server/service_rpc.c @@ -0,0 +1,456 @@ +/* + Unix SMB/CIFS implementation. + + smbd-specific dcerpc server code + + Copyright (C) Andrew Tridgell 2003-2005 + Copyright (C) Stefan (metze) Metzmacher 2004-2005 + Copyright (C) Jelmer Vernooij 2004,2007 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_dcerpc.h" +#include "auth/auth.h" +#include "auth/gensec/gensec.h" +#include "lib/util/dlinklist.h" +#include "rpc_server/dcerpc_server.h" +#include "lib/events/events.h" +#include "smbd/service_task.h" +#include "smbd/service_stream.h" +#include "smbd/service.h" +#include "system/filesys.h" +#include "libcli/security/security.h" +#include "lib/socket/socket.h" +#include "lib/messaging/irpc.h" +#include "system/network.h" +#include "lib/socket/netif.h" +#include "build.h" + +struct dcesrv_socket_context { + const struct dcesrv_endpoint *endpoint; + struct dcesrv_context *dcesrv_ctx; +}; + +/* + write_fn callback for dcesrv_output() +*/ +static NTSTATUS dcerpc_write_fn(void *private_data, DATA_BLOB *out, size_t *nwritten) +{ + NTSTATUS status; + struct socket_context *sock = talloc_get_type(private_data, struct socket_context); + size_t sendlen; + + status = socket_send(sock, out, &sendlen); + NT_STATUS_IS_ERR_RETURN(status); + + *nwritten = sendlen; + return status; +} + +static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason) +{ + struct stream_connection *srv_conn; + srv_conn = talloc_get_type(dce_conn->transport.private_data, + struct stream_connection); + + stream_terminate_connection(srv_conn, reason); +} + +static void dcesrv_sock_report_output_data(struct dcesrv_connection *dcesrv_conn) +{ + struct stream_connection *srv_conn; + srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, + struct stream_connection); + + if (srv_conn && srv_conn->event.fde) { + EVENT_FD_WRITEABLE(srv_conn->event.fde); + } +} + +static struct socket_address *dcesrv_sock_get_my_addr(struct dcesrv_connection *dcesrv_conn, TALLOC_CTX *mem_ctx) +{ + struct stream_connection *srv_conn; + srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, + struct stream_connection); + + return socket_get_my_addr(srv_conn->socket, mem_ctx); +} + +static struct socket_address *dcesrv_sock_get_peer_addr(struct dcesrv_connection *dcesrv_conn, TALLOC_CTX *mem_ctx) +{ + struct stream_connection *srv_conn; + srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, + struct stream_connection); + + return socket_get_peer_addr(srv_conn->socket, mem_ctx); +} + +static void dcesrv_sock_accept(struct stream_connection *srv_conn) +{ + NTSTATUS status; + struct dcesrv_socket_context *dcesrv_sock = + talloc_get_type(srv_conn->private, struct dcesrv_socket_context); + struct dcesrv_connection *dcesrv_conn = NULL; + struct auth_session_info *session_info = NULL; + + status = auth_anonymous_session_info(srv_conn, &session_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n", + nt_errstr(status))); + stream_terminate_connection(srv_conn, nt_errstr(status)); + return; + } + + status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, + srv_conn, + dcesrv_sock->endpoint, + session_info, + srv_conn->event.ctx, + srv_conn->msg_ctx, + srv_conn->server_id, + DCESRV_CALL_STATE_FLAG_MAY_ASYNC, + &dcesrv_conn); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", + nt_errstr(status))); + stream_terminate_connection(srv_conn, nt_errstr(status)); + return; + } + + dcesrv_conn->transport.private_data = srv_conn; + dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data; + dcesrv_conn->transport.get_my_addr = dcesrv_sock_get_my_addr; + dcesrv_conn->transport.get_peer_addr = dcesrv_sock_get_peer_addr; + + srv_conn->private = dcesrv_conn; + + irpc_add_name(srv_conn->msg_ctx, "rpc_server"); + + return; +} + +static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags) +{ + NTSTATUS status; + struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection); + DATA_BLOB tmp_blob; + size_t nread; + + if (dce_conn->processing) { + EVENT_FD_NOT_READABLE(conn->event.fde); + return; + } + + tmp_blob = data_blob_talloc(conn->socket, NULL, 0x1000); + if (tmp_blob.data == NULL) { + dcesrv_terminate_connection(dce_conn, "out of memory"); + return; + } + + status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread); + if (NT_STATUS_IS_ERR(status)) { + dcesrv_terminate_connection(dce_conn, nt_errstr(status)); + return; + } + if (nread == 0) { + talloc_free(tmp_blob.data); + return; + } + + tmp_blob.length = nread; + + dce_conn->processing = True; + status = dcesrv_input(dce_conn, &tmp_blob); + dce_conn->processing = False; + talloc_free(tmp_blob.data); + + EVENT_FD_READABLE(conn->event.fde); + + if (!NT_STATUS_IS_OK(status)) { + dcesrv_terminate_connection(dce_conn, nt_errstr(status)); + return; + } + + if (dce_conn->call_list && dce_conn->call_list->replies) { + EVENT_FD_WRITEABLE(conn->event.fde); + } +} + +static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags) +{ + struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection); + NTSTATUS status; + + status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn); + if (NT_STATUS_IS_ERR(status)) { + dcesrv_terminate_connection(dce_conn, "eof on socket"); + return; + } + + if (!dce_conn->call_list || !dce_conn->call_list->replies) { + EVENT_FD_NOT_WRITEABLE(conn->event.fde); + } +} + + +static const struct stream_server_ops dcesrv_stream_ops = { + .name = "rpc", + .accept_connection = dcesrv_sock_accept, + .recv_handler = dcesrv_sock_recv, + .send_handler = dcesrv_sock_send, +}; + + + +NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) +{ + struct dcesrv_socket_context *dcesrv_sock; + uint16_t port = 1; + NTSTATUS status; + + dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); + NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); + + /* remember the endpoint of this socket */ + dcesrv_sock->endpoint = e; + dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); + + status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, + "unix", e->ep_description->endpoint, &port, + dcesrv_sock); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", + e->ep_description->endpoint, nt_errstr(status))); + } + + return status; +} + +NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) +{ + struct dcesrv_socket_context *dcesrv_sock; + uint16_t port = 1; + char *full_path; + NTSTATUS status; + + if (!e->ep_description->endpoint) { + /* No identifier specified: use DEFAULT. + * DO NOT hardcode this value anywhere else. Rather, specify + * no endpoint and let the epmapper worry about it. */ + e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT"); + } + + full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description->endpoint); + + dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); + NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); + + /* remember the endpoint of this socket */ + dcesrv_sock->endpoint = e; + dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); + + status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, + "unix", full_path, &port, dcesrv_sock); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n", + e->ep_description->endpoint, full_path, nt_errstr(status))); + } + return status; +} + + +/* + add a socket address to the list of events, one event per dcerpc endpoint +*/ +static NTSTATUS add_socket_rpc_pipe_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) +{ + struct dcesrv_socket_context *dcesrv_sock; + NTSTATUS status; + + if (e->ep_description->endpoint == NULL) { + DEBUG(0, ("Endpoint mandatory for named pipes\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); + NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); + + /* remember the endpoint of this socket */ + dcesrv_sock->endpoint = e; + dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); + + status = NT_STATUS_OK; +#if 0 + + status = stream_setup_smb_pipe(event_ctx, model_ops, &dcesrv_stream_ops, + e->ep_description->endpoint, dcesrv_sock); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", + e->ep_description->endpoint, nt_errstr(status))); + } +#endif + return status; +} + +NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) +{ + NTSTATUS status; + + status = add_socket_rpc_pipe_iface(dce_ctx, e, event_ctx, model_ops); + NT_STATUS_NOT_OK_RETURN(status); + + return status; +} + +/* + add a socket address to the list of events, one event per dcerpc endpoint +*/ +static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops, + const char *address) +{ + struct dcesrv_socket_context *dcesrv_sock; + uint16_t port = 0; + NTSTATUS status; + + if (e->ep_description->endpoint) { + port = atoi(e->ep_description->endpoint); + } + + dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); + NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); + + /* remember the endpoint of this socket */ + dcesrv_sock->endpoint = e; + dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); + + status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, + "ipv4", address, &port, dcesrv_sock); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", + address, port, nt_errstr(status))); + } + + if (e->ep_description->endpoint == NULL) { + e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port); + } + + return status; +} + +NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) +{ + NTSTATUS status; + + /* Add TCP/IP sockets */ + if (lp_interfaces() && lp_bind_interfaces_only()) { + int num_interfaces = iface_count(); + int i; + for(i = 0; i < num_interfaces; i++) { + const char *address = iface_n_ip(i); + status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address); + NT_STATUS_NOT_OK_RETURN(status); + } + } else { + status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, lp_socket_address()); + NT_STATUS_NOT_OK_RETURN(status); + } + + return NT_STATUS_OK; +} + + +NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) +{ + switch (e->ep_description->transport) { + case NCACN_UNIX_STREAM: + return dcesrv_add_ep_unix(dce_ctx, e, event_ctx, model_ops); + + case NCALRPC: + return dcesrv_add_ep_ncalrpc(dce_ctx, e, event_ctx, model_ops); + + case NCACN_IP_TCP: + return dcesrv_add_ep_tcp(dce_ctx, e, event_ctx, model_ops); + + case NCACN_NP: + return dcesrv_add_ep_np(dce_ctx, e, event_ctx, model_ops); + + default: + return NT_STATUS_NOT_SUPPORTED; + } +} + +/* + open the dcerpc server sockets +*/ +static void dcesrv_task_init(struct task_server *task) +{ + NTSTATUS status; + struct dcesrv_context *dce_ctx; + struct dcesrv_endpoint *e; + + task_server_set_title(task, "task[dcesrv]"); + + status = dcesrv_init_context(task->event_ctx, + lp_dcerpc_endpoint_servers(), + &dce_ctx); + if (!NT_STATUS_IS_OK(status)) goto failed; + + /* Make sure the directory for NCALRPC exists */ + if (!directory_exist(lp_ncalrpc_dir())) { + mkdir(lp_ncalrpc_dir(), 0755); + } + + for (e=dce_ctx->endpoint_list;e;e=e->next) { + status = dcesrv_add_ep(dce_ctx, e, task->event_ctx, task->model_ops); + if (!NT_STATUS_IS_OK(status)) goto failed; + } + + return; +failed: + task_server_terminate(task, "Failed to startup dcerpc server task"); +} + +/* + called on startup of the smb server service It's job is to start + listening on all configured sockets +*/ +static NTSTATUS dcesrv_init(struct event_context *event_context, + const struct model_ops *model_ops) +{ + return task_server_startup(event_context, model_ops, dcesrv_task_init); +} + +NTSTATUS server_service_rpc_init(void) +{ + init_module_fn static_init[] = STATIC_dcerpc_server_MODULES; + init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server"); + + run_init_functions(static_init); + run_init_functions(shared_init); + + talloc_free(shared_init); + + return register_server_service("rpc", dcesrv_init); +} + + diff --git a/source4/rpc_server/spoolss/dcesrv_spoolss.c b/source4/rpc_server/spoolss/dcesrv_spoolss.c index 2dca178245..cd39bcda3d 100644 --- a/source4/rpc_server/spoolss/dcesrv_spoolss.c +++ b/source4/rpc_server/spoolss/dcesrv_spoolss.c @@ -27,6 +27,12 @@ #include "ntptr/ntptr.h" #include "lib/socket/socket.h" #include "smbd/service_stream.h" +#include "librpc/gen_ndr/ndr_spoolss_c.h" +#include "auth/credentials/credentials.h" + +enum spoolss_handle { + SPOOLSS_NOTIFY +}; #define SPOOLSS_BUFFER_UNION(fn,info,level) \ ((info)?ndr_size_##fn(info, level, 0):0) @@ -1036,7 +1042,16 @@ static WERROR dcesrv_spoolss_RouterFindFirstPrinterChangeNotificationOld(struct static WERROR dcesrv_spoolss_ReplyOpenPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct spoolss_ReplyOpenPrinter *r) { - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); + struct dcesrv_handle *handle; + + handle = dcesrv_handle_new(dce_call->context, SPOOLSS_NOTIFY); + W_ERROR_HAVE_NO_MEMORY(handle); + + /* For now, just return a handle */ + + *r->out.handle = handle->wire_handle; + + return WERR_OK; } @@ -1056,9 +1071,16 @@ static WERROR dcesrv_spoolss_RouterReplyPrinter(struct dcesrv_call_state *dce_ca static WERROR dcesrv_spoolss_ReplyClosePrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct spoolss_ReplyClosePrinter *r) { - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); -} + struct dcesrv_handle *handle; + + DCESRV_PULL_HANDLE_WERR(handle, r->in.handle, SPOOLSS_NOTIFY); + talloc_free(handle); + + ZERO_STRUCTP(r->out.handle); + + return WERR_OK; +} /* spoolss_AddPortEx @@ -1106,11 +1128,56 @@ static WERROR dcesrv_spoolss_ResetPrinterEx(struct dcesrv_call_state *dce_call, static WERROR dcesrv_spoolss_RemoteFindFirstPrinterChangeNotifyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct spoolss_RemoteFindFirstPrinterChangeNotifyEx *r) { + struct dcerpc_pipe *p; + struct dcerpc_binding *binding; + NTSTATUS status; + struct spoolss_ReplyOpenPrinter rop; + struct cli_credentials *creds; + struct policy_handle notify_handle; + + DEBUG(2, ("Received RFFPCNex from %s\n", r->in.str)); + /* - * TODO: for now just return ok, + * TODO: for now just open a connection to the client and drop it again * to keep the w2k3 PrintServer * happy to allow to open the Add Printer GUI + * and the torture suite passing */ + + binding = talloc_zero(mem_ctx, struct dcerpc_binding); + + binding->transport = NCACN_NP; + if (strncmp(r->in.str, "\\\\", 2)) + return WERR_INVALID_COMPUTERNAME; + binding->host = r->in.str+2; + + creds = cli_credentials_init_anon(mem_ctx); /* FIXME: Use machine credentials instead ? */ + + status = dcerpc_pipe_connect_b(mem_ctx, &p, binding, &ndr_table_spoolss, + creds, NULL); + + if (NT_STATUS_IS_ERR(status)) { + DEBUG(0, ("unable to call back to %s\n", r->in.str)); + return WERR_SERVER_UNAVAILABLE; + } + + ZERO_STRUCT(rop); + rop.in.server_name = lp_netbios_name(); + W_ERROR_HAVE_NO_MEMORY(rop.in.server_name); + rop.in.printer_local = 0; + rop.in.type = REG_NONE; + rop.in.unknown1 = 0; + rop.in.unknown2 = 0; + rop.out.handle = ¬ify_handle; + + status = dcerpc_spoolss_ReplyOpenPrinter(p, mem_ctx, &rop); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(0, ("unable to open remote printer %s\n", r->in.str)); + return WERR_SERVER_UNAVAILABLE; + } + + talloc_free(p); + return WERR_OK; } diff --git a/source4/smb_server/smb_server.c b/source4/smb_server/smb_server.c index 30c78eb3a7..e4a9f982cd 100644 --- a/source4/smb_server/smb_server.c +++ b/source4/smb_server/smb_server.c @@ -173,7 +173,7 @@ static const struct stream_server_ops smb_stream_ops = { /* setup a listening socket on all the SMB ports for a particular address */ -static NTSTATUS smb_add_socket(struct event_context *event_context, +_PUBLIC_ NTSTATUS smbsrv_add_socket(struct event_context *event_context, const struct model_ops *model_ops, const char *address) { @@ -224,12 +224,12 @@ static void smbsrv_task_init(struct task_server *task) */ for(i = 0; i < num_interfaces; i++) { const char *address = iface_n_ip(i); - status = smb_add_socket(task->event_ctx, task->model_ops, address); + status = smbsrv_add_socket(task->event_ctx, task->model_ops, address); if (!NT_STATUS_IS_OK(status)) goto failed; } } else { /* Just bind to lp_socket_address() (usually 0.0.0.0) */ - status = smb_add_socket(task->event_ctx, task->model_ops, lp_socket_address()); + status = smbsrv_add_socket(task->event_ctx, task->model_ops, lp_socket_address()); if (!NT_STATUS_IS_OK(status)) goto failed; } diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h index 10bafcd208..348ac70f1f 100644 --- a/source4/smb_server/smb_server.h +++ b/source4/smb_server/smb_server.h @@ -376,6 +376,10 @@ struct smbsrv_connection { struct share_context *share_context; }; +NTSTATUS smbsrv_add_socket(struct event_context *event_context, + const struct model_ops *model_ops, + const char *address); + #include "smb_server/smb_server_proto.h" #include "smb_server/smb/smb_proto.h" diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h index 513e903781..19212606c1 100644 --- a/source4/smbd/process_model.h +++ b/source4/smbd/process_model.h @@ -67,6 +67,8 @@ struct process_model_critical_sizes { int sizeof_model_ops; }; +extern const struct model_ops single_ops; + #include "smbd/process_model_proto.h" #endif /* __PROCESS_MODEL_H__ */ diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c index 65f5a7e375..5ba2c8df88 100644 --- a/source4/smbd/process_single.c +++ b/source4/smbd/process_single.c @@ -87,7 +87,7 @@ static void single_set_title(struct event_context *ev, const char *title) { } -static const struct model_ops single_ops = { +const struct model_ops single_ops = { .name = "single", .model_init = single_model_init, .new_task = single_new_task, diff --git a/source4/smbd/service_stream.c b/source4/smbd/service_stream.c index 08c323fc0a..5117697f87 100644 --- a/source4/smbd/service_stream.c +++ b/source4/smbd/service_stream.c @@ -224,11 +224,13 @@ static void stream_accept_handler(struct event_context *ev, struct fd_event *fde stream_new_connection, stream_socket); } - - /* setup a listen stream socket if you pass *port == 0, then a port > 1024 is used + + FIXME: This function is TCP/IP specific - uses an int rather than + a string for the port. Should leave allocating a port nr + to the socket implementation - JRV20070903 */ NTSTATUS stream_setup_socket(struct event_context *event_context, const struct model_ops *model_ops, diff --git a/source4/torture/config.mk b/source4/torture/config.mk index fc85cc160a..3ad3d44b81 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -128,6 +128,7 @@ OBJ_FILES = \ rpc/drsuapi_cracknames.o \ rpc/dssync.o \ rpc/spoolss.o \ + rpc/spoolss_notify.o \ rpc/unixinfo.o \ rpc/samr.o \ rpc/wkssvc.o \ @@ -164,7 +165,8 @@ PRIVATE_DEPENDENCIES = \ RPC_NDR_LSA RPC_NDR_EPMAPPER RPC_NDR_DFS RPC_NDR_SPOOLSS \ RPC_NDR_SRVSVC RPC_NDR_WKSSVC RPC_NDR_ROT RPC_NDR_DSSETUP \ RPC_NDR_REMACT RPC_NDR_OXIDRESOLVER WB_HELPER LIBSAMBA-NET \ - LIBCLI_AUTH POPT_CREDENTIALS TORTURE_LDAP TORTURE_UTIL TORTURE_RAP + LIBCLI_AUTH POPT_CREDENTIALS TORTURE_LDAP TORTURE_UTIL TORTURE_RAP \ + dcerpc_server service process_model ################################# # Start SUBSYSTEM TORTURE_RAP diff --git a/source4/torture/rpc/rpc.c b/source4/torture/rpc/rpc.c index c6d22ba5c3..9c61e85ae6 100644 --- a/source4/torture/rpc/rpc.c +++ b/source4/torture/rpc/rpc.c @@ -388,6 +388,7 @@ NTSTATUS torture_rpc_init(void) torture_suite_add_suite(suite, torture_rpc_handles(suite)); torture_suite_add_suite(suite, torture_rpc_winreg(suite)); torture_suite_add_simple_test(suite, "SPOOLSS", torture_rpc_spoolss); + torture_suite_add_suite(suite, torture_rpc_spoolss_notify(suite)); torture_suite_add_simple_test(suite, "SAMR", torture_rpc_samr); torture_suite_add_simple_test(suite, "SAMR-USERS", torture_rpc_samr_users); torture_suite_add_simple_test(suite, "SAMR-PASSWORDS", torture_rpc_samr_passwords); diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c index 0bf0ee87a1..0a0abc5740 100644 --- a/source4/torture/rpc/spoolss.c +++ b/source4/torture/rpc/spoolss.c @@ -4,6 +4,7 @@ Copyright (C) Tim Potter 2003 Copyright (C) Stefan Metzmacher 2005 + Copyright (C) Jelmer Vernooij 2007 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 @@ -25,8 +26,6 @@ #include "librpc/gen_ndr/ndr_spoolss_c.h" struct test_spoolss_context { - struct dcerpc_pipe *p; - /* print server handle */ struct policy_handle server_handle; @@ -51,109 +50,58 @@ struct test_spoolss_context { union spoolss_PrinterInfo *printers[6]; }; -#define COMPARE_STRING(c,r,e) do {\ - BOOL _ok = True;\ - if (c.e && !r.e) _ok = False;\ - if (!c.e && r.e) _ok = False;\ - if (c.e && r.e && strcmp_safe(c.e, r.e) != 0) _ok = False;\ - if (!_ok){\ - printf("%s: " #c "." #e " [%s] doesn't match " #r "." #e " [%s]\n",\ - __location__, c.e, r.e);\ - ret = False;\ - }\ -} while(0) +#define COMPARE_STRING(tctx, c,r,e) \ + torture_assert_str_equal(tctx, c.e, r.e, "invalid value") /* not every compiler supports __typeof__() */ #if (__GNUC__ >= 3) #define _CHECK_FIELD_SIZE(c,r,e,type) do {\ if (sizeof(__typeof__(c.e)) != sizeof(type)) { \ - printf(__location__ ":" #c "." #e "field is not " #type "\n"); \ - smb_panic(__location__ ":" #c "." #e "field is not " #type ); \ - ret = False; \ + torture_fail(tctx, #c "." #e "field is not " #type "\n"); \ }\ if (sizeof(__typeof__(r.e)) != sizeof(type)) { \ - printf(__location__ ":" #r "." #e "field is not " #type "\n"); \ - smb_panic(__location__ ":" #r "." #e "field is not " #type ); \ - ret = False; \ + torture_fail(tctx, #r "." #e "field is not " #type "\n"); \ }\ } while(0) #else #define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0) #endif -#if 0 /* unused */ -#define COMPARE_UINT16(c,r,e) do {\ - _CHECK_FIELD_SIZE(c,r,e,uint16_t); \ - if (c.e != r.e){\ - printf("%s: " #c "." #e " 0x%04X (%u) doesn't match " #r "." #e " 0x%04X (%u)\n",\ - __location__, c.e, c.e, r.e, r.e);\ - ret = False;\ - }\ +#define COMPARE_UINT32(tctx, c, r, e) do {\ + _CHECK_FIELD_SIZE(c, r, e,uint32_t); \ + torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \ } while(0) -#endif -#define COMPARE_UINT32(c,r,e) do {\ - _CHECK_FIELD_SIZE(c,r,e,uint32_t); \ - if (c.e != r.e){\ - printf("%s: " #c "." #e " 0x%08X (%u) doesn't match " #r "." #e " 0x%08X (%u)\n",\ - __location__, c.e, c.e, r.e, r.e);\ - ret = False;\ - }\ -} while(0) +#define COMPARE_STRING_ARRAY(tctx, c,r,e) -#if 0 /* unused */ -#define COMPARE_UINT64(c,r,e) do {\ - _CHECK_FIELD_SIZE(c,r,e,uint64_t); \ - if (c.e != r.e){\ - printf("%s: " #c "." #e " 0x%016llX (%llu) doesn't match " #r "." #e " 0x%016llX (%llu)\n",\ - __location__, c.e, c.e, r.e, r.e);\ - ret = False;\ - }\ -} while(0) -#endif - -/* TODO: ! */ -#if 0 /* unused */ -#define COMPARE_SEC_DESC(c,r,e) -#define COMPARE_SPOOLSS_TIME(c,r,e) -#endif -#define COMPARE_STRING_ARRAY(c,r,e) - -static BOOL test_OpenPrinter_server(struct test_spoolss_context *ctx) +static bool test_OpenPrinter_server(struct torture_context *tctx, struct dcerpc_pipe *p, struct test_spoolss_context *ctx) { NTSTATUS status; struct spoolss_OpenPrinter op; - BOOL ret = True; - op.in.printername = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(ctx->p)); + op.in.printername = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p)); op.in.datatype = NULL; op.in.devmode_ctr.devmode= NULL; op.in.access_mask = 0; op.out.handle = &ctx->server_handle; - printf("\nTesting OpenPrinter(%s)\n", op.in.printername); + torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername); - status = dcerpc_spoolss_OpenPrinter(ctx->p, ctx, &op); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_OpenPrinter failed - %s\n", nt_errstr(status)); - ret = False; - } - if (!W_ERROR_IS_OK(op.out.result)) { - printf("OpenPrinter(%s) failed - %s\n", - op.in.printername, win_errstr(op.out.result)); - ret = False; - } + status = dcerpc_spoolss_OpenPrinter(p, ctx, &op); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed"); + torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed"); - return ret; + return true; } -static BOOL test_EnumPorts(struct test_spoolss_context *ctx) +static bool test_EnumPorts(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct test_spoolss_context *ctx) { NTSTATUS status; struct spoolss_EnumPorts r; uint16_t levels[] = { 1, 2 }; int i, j; - BOOL ret = True; for (i=0;ip, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumPorts failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumPorts(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed"); if (W_ERROR_IS_OK(r.out.result)) { /* TODO: do some more checks here */ continue; } - if (!W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { - printf("EnumPorts unexspected return code %s, should be WERR_INSUFFICIENT_BUFFER\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, + "EnumPorts unexpected return code"); blob = data_blob_talloc(ctx, NULL, r.out.needed); data_blob_clear(&blob); r.in.buffer = &blob; r.in.offered = r.out.needed; - status = dcerpc_spoolss_EnumPorts(ctx->p, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumPorts failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumPorts(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("EnumPorts failed - %s\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed"); ctx->port_count[level] = r.out.count; ctx->ports[level] = r.out.info; @@ -209,14 +140,10 @@ static BOOL test_EnumPorts(struct test_spoolss_context *ctx) for (i=1;iport_count[level] != ctx->port_count[old_level]) { - printf("EnumPorts level[%d] returns [%u] ports, but level[%d] returns [%u]\n", - level, ctx->port_count[level], old_level, ctx->port_count[old_level]); - ret = False; - } + torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level], + "EnumPorts invalid value"); } /* if the array sizes are not the same we would maybe segfault in the following code */ - if (!ret) return ret; for (i=0;iports[2][j]; switch (level) { case 1: - COMPARE_STRING(cur->info1, ref->info2, port_name); + COMPARE_STRING(tctx, cur->info1, ref->info2, port_name); break; case 2: /* level 2 is our reference, and it makes no sense to compare it to itself */ @@ -234,10 +161,12 @@ static BOOL test_EnumPorts(struct test_spoolss_context *ctx) } } - return True; + return true; } -static BOOL test_GetPrinterDriverDirectory(struct test_spoolss_context *ctx) +static bool test_GetPrinterDriverDirectory(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct test_spoolss_context *ctx) { NTSTATUS status; struct spoolss_GetPrinterDriverDirectory r; @@ -255,14 +184,13 @@ static BOOL test_GetPrinterDriverDirectory(struct test_spoolss_context *ctx) .server = "" },{ .level = 1, - .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(ctx->p)) + .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p)) },{ .level = 1024, - .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(ctx->p)) + .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p)) } }; int i; - BOOL ret = True; for (i=0;ip, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_GetPrinterDriverDirectory failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } - if (!W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { - printf("GetPrinterDriverDirectory unexspected return code %s, should be WERR_INSUFFICIENT_BUFFER\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, + "dcerpc_spoolss_GetPrinterDriverDirectory failed"); + torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, + "GetPrinterDriverDirectory unexpected return code"); blob = data_blob_talloc(ctx, NULL, r.out.needed); data_blob_clear(&blob); r.in.buffer = &blob; r.in.offered = r.out.needed; - status = dcerpc_spoolss_GetPrinterDriverDirectory(ctx->p, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_GetPrinterDriverDirectory failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_GetPrinterDriverDirectory(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("GetPrinterDriverDirectory failed - %s\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed"); } - return True; + return true; } -static BOOL test_EnumPrinterDrivers(struct test_spoolss_context *ctx) +static bool test_EnumPrinterDrivers(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct test_spoolss_context *ctx) { NTSTATUS status; struct spoolss_EnumPrinterDrivers r; uint16_t levels[] = { 1, 2, 3, 4, 5, 6 }; int i, j; - BOOL ret = True; for (i=0;ip, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumPrinterDrivers failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, + "dcerpc_spoolss_EnumPrinterDrivers failed"); if (W_ERROR_IS_OK(r.out.result)) { /* TODO: do some more checks here */ continue; } - if (!W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { - printf("EnumPrinterDrivers unexspected return code %s, should be WERR_INSUFFICIENT_BUFFER\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, + "EnumPrinterDrivers failed"); blob = data_blob_talloc(ctx, NULL, r.out.needed); data_blob_clear(&blob); r.in.buffer = &blob; r.in.offered = r.out.needed; - status = dcerpc_spoolss_EnumPrinterDrivers(ctx->p, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumPrinterDrivers failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumPrinterDrivers(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinterDrivers failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("EnumPrinterDrivers failed - %s\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDrivers failed"); ctx->driver_count[level] = r.out.count; ctx->drivers[level] = r.out.info; @@ -375,14 +272,9 @@ static BOOL test_EnumPrinterDrivers(struct test_spoolss_context *ctx) for (i=1;idriver_count[level] != ctx->driver_count[old_level]) { - printf("EnumPrinterDrivers level[%d] returns [%u] drivers, but level[%d] returns [%u]\n", - level, ctx->driver_count[level], old_level, ctx->driver_count[old_level]); - ret = False; - } + torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level], + "EnumPrinterDrivers invalid value"); } - /* if the array sizes are not the same we would maybe segfault in the following code */ - if (!ret) return ret; for (i=0;idrivers[6][j]; switch (level) { case 1: - COMPARE_STRING(cur->info1, ref->info6, driver_name); + COMPARE_STRING(tctx, cur->info1, ref->info6, driver_name); break; case 2: - COMPARE_UINT32(cur->info2, ref->info6, version); - COMPARE_STRING(cur->info2, ref->info6, driver_name); - COMPARE_STRING(cur->info2, ref->info6, architecture); - COMPARE_STRING(cur->info2, ref->info6, driver_path); - COMPARE_STRING(cur->info2, ref->info6, data_file); - COMPARE_STRING(cur->info2, ref->info6, config_file); + COMPARE_UINT32(tctx, cur->info2, ref->info6, version); + COMPARE_STRING(tctx, cur->info2, ref->info6, driver_name); + COMPARE_STRING(tctx, cur->info2, ref->info6, architecture); + COMPARE_STRING(tctx, cur->info2, ref->info6, driver_path); + COMPARE_STRING(tctx, cur->info2, ref->info6, data_file); + COMPARE_STRING(tctx, cur->info2, ref->info6, config_file); break; case 3: - COMPARE_UINT32(cur->info3, ref->info6, version); - COMPARE_STRING(cur->info3, ref->info6, driver_name); - COMPARE_STRING(cur->info3, ref->info6, architecture); - COMPARE_STRING(cur->info3, ref->info6, driver_path); - COMPARE_STRING(cur->info3, ref->info6, data_file); - COMPARE_STRING(cur->info3, ref->info6, config_file); - COMPARE_STRING(cur->info3, ref->info6, help_file); - COMPARE_STRING_ARRAY(cur->info3, ref->info6, dependent_files); - COMPARE_STRING(cur->info3, ref->info6, monitor_name); - COMPARE_STRING(cur->info3, ref->info6, default_datatype); + COMPARE_UINT32(tctx, cur->info3, ref->info6, version); + COMPARE_STRING(tctx, cur->info3, ref->info6, driver_name); + COMPARE_STRING(tctx, cur->info3, ref->info6, architecture); + COMPARE_STRING(tctx, cur->info3, ref->info6, driver_path); + COMPARE_STRING(tctx, cur->info3, ref->info6, data_file); + COMPARE_STRING(tctx, cur->info3, ref->info6, config_file); + COMPARE_STRING(tctx, cur->info3, ref->info6, help_file); + COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info6, dependent_files); + COMPARE_STRING(tctx, cur->info3, ref->info6, monitor_name); + COMPARE_STRING(tctx, cur->info3, ref->info6, default_datatype); break; case 4: - COMPARE_UINT32(cur->info4, ref->info6, version); - COMPARE_STRING(cur->info4, ref->info6, driver_name); - COMPARE_STRING(cur->info4, ref->info6, architecture); - COMPARE_STRING(cur->info4, ref->info6, driver_path); - COMPARE_STRING(cur->info4, ref->info6, data_file); - COMPARE_STRING(cur->info4, ref->info6, config_file); - COMPARE_STRING(cur->info4, ref->info6, help_file); - COMPARE_STRING_ARRAY(cur->info4, ref->info6, dependent_files); - COMPARE_STRING(cur->info4, ref->info6, monitor_name); - COMPARE_STRING(cur->info4, ref->info6, default_datatype); - COMPARE_STRING_ARRAY(cur->info4, ref->info6, previous_names); + COMPARE_UINT32(tctx, cur->info4, ref->info6, version); + COMPARE_STRING(tctx, cur->info4, ref->info6, driver_name); + COMPARE_STRING(tctx, cur->info4, ref->info6, architecture); + COMPARE_STRING(tctx, cur->info4, ref->info6, driver_path); + COMPARE_STRING(tctx, cur->info4, ref->info6, data_file); + COMPARE_STRING(tctx, cur->info4, ref->info6, config_file); + COMPARE_STRING(tctx, cur->info4, ref->info6, help_file); + COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info6, dependent_files); + COMPARE_STRING(tctx, cur->info4, ref->info6, monitor_name); + COMPARE_STRING(tctx, cur->info4, ref->info6, default_datatype); + COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info6, previous_names); break; case 5: - COMPARE_UINT32(cur->info5, ref->info6, version); - COMPARE_STRING(cur->info5, ref->info6, driver_name); - COMPARE_STRING(cur->info5, ref->info6, architecture); - COMPARE_STRING(cur->info5, ref->info6, driver_path); - COMPARE_STRING(cur->info5, ref->info6, data_file); - COMPARE_STRING(cur->info5, ref->info6, config_file); - /*COMPARE_UINT32(cur->info5, ref->info6, driver_attributes);*/ - /*COMPARE_UINT32(cur->info5, ref->info6, config_version);*/ - /*TODO: ! COMPARE_UINT32(cur->info5, ref->info6, driver_version); */ + COMPARE_UINT32(tctx, cur->info5, ref->info6, version); + COMPARE_STRING(tctx, cur->info5, ref->info6, driver_name); + COMPARE_STRING(tctx, cur->info5, ref->info6, architecture); + COMPARE_STRING(tctx, cur->info5, ref->info6, driver_path); + COMPARE_STRING(tctx, cur->info5, ref->info6, data_file); + COMPARE_STRING(tctx, cur->info5, ref->info6, config_file); + /*COMPARE_UINT32(tctx, cur->info5, ref->info6, driver_attributes);*/ + /*COMPARE_UINT32(tctx, cur->info5, ref->info6, config_version);*/ + /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info6, driver_version); */ break; case 6: /* level 6 is our reference, and it makes no sense to compare it to itself */ @@ -444,16 +336,17 @@ static BOOL test_EnumPrinterDrivers(struct test_spoolss_context *ctx) } } - return ret; + return true; } -static BOOL test_EnumMonitors(struct test_spoolss_context *ctx) +static bool test_EnumMonitors(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct test_spoolss_context *ctx) { NTSTATUS status; struct spoolss_EnumMonitors r; uint16_t levels[] = { 1, 2 }; int i, j; - BOOL ret = True; for (i=0;ip, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumMonitors failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumMonitors(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed"); if (W_ERROR_IS_OK(r.out.result)) { /* TODO: do some more checks here */ continue; } - if (!W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { - printf("EnumMonitors unexspected return code %s, should be WERR_INSUFFICIENT_BUFFER\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, + "EnumMonitors failed"); blob = data_blob_talloc(ctx, NULL, r.out.needed); data_blob_clear(&blob); r.in.buffer = &blob; r.in.offered = r.out.needed; - status = dcerpc_spoolss_EnumMonitors(ctx->p, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumMonitors failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumMonitors(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("EnumMonitors failed - %s\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed"); ctx->monitor_count[level] = r.out.count; ctx->monitors[level] = r.out.info; @@ -509,14 +385,9 @@ static BOOL test_EnumMonitors(struct test_spoolss_context *ctx) for (i=1;imonitor_count[level] != ctx->monitor_count[old_level]) { - printf("EnumMonitors level[%d] returns [%u] monitors, but level[%d] returns [%u]\n", - level, ctx->monitor_count[level], old_level, ctx->monitor_count[old_level]); - ret = False; - } + torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level], + "EnumMonitors invalid value"); } - /* if the array sizes are not the same we would maybe segfault in the following code */ - if (!ret) return ret; for (i=0;imonitors[2][j]; switch (level) { case 1: - COMPARE_STRING(cur->info1, ref->info2, monitor_name); + COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name); break; case 2: /* level 2 is our reference, and it makes no sense to compare it to itself */ @@ -534,16 +405,17 @@ static BOOL test_EnumMonitors(struct test_spoolss_context *ctx) } } - return ret; + return true; } -static BOOL test_EnumPrintProcessors(struct test_spoolss_context *ctx) +static bool test_EnumPrintProcessors(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct test_spoolss_context *ctx) { NTSTATUS status; struct spoolss_EnumPrintProcessors r; uint16_t levels[] = { 1 }; int i, j; - BOOL ret = True; for (i=0;ip, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumPrintProcessors failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed"); if (W_ERROR_IS_OK(r.out.result)) { /* TODO: do some more checks here */ continue; } - if (!W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { - printf("EnumPrintProcessors unexspected return code %s, should be WERR_INSUFFICIENT_BUFFER\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, + "EnumPrintProcessors unexpected return code"); blob = data_blob_talloc(ctx, NULL, r.out.needed); data_blob_clear(&blob); r.in.buffer = &blob; r.in.offered = r.out.needed; - status = dcerpc_spoolss_EnumPrintProcessors(ctx->p, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumPrintProcessors failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumPrintProcessors(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrintProcessors failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("EnumPrintProcessors failed - %s\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_ok(tctx, r.out.result, "EnumPrintProcessors failed"); ctx->print_processor_count[level] = r.out.count; ctx->print_processors[level] = r.out.info; @@ -600,14 +455,9 @@ static BOOL test_EnumPrintProcessors(struct test_spoolss_context *ctx) for (i=1;iprint_processor_count[level] != ctx->print_processor_count[old_level]) { - printf("EnumPrintProcessors level[%d] returns [%u] print_processors, but level[%d] returns [%u]\n", - level, ctx->print_processor_count[level], old_level, ctx->print_processor_count[old_level]); - ret = False; - } + torture_assert_int_equal(tctx, ctx->print_processor_count[level], ctx->print_processor_count[old_level], + "EnumPrintProcessors failed"); } - /* if the array sizes are not the same we would maybe segfault in the following code */ - if (!ret) return ret; for (i=0;ip, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumPrinters failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumPrinters(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed"); if (W_ERROR_IS_OK(r.out.result)) { /* TODO: do some more checks here */ continue; } - if (!W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { - printf("EnumPrinters unexspected return code %s, should be WERR_INSUFFICIENT_BUFFER\n", - win_errstr(r.out.result)); - ret = False; - continue; - } + torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER, + "EnumPrinters unexpected return code"); blob = data_blob_talloc(ctx, NULL, r.out.needed); data_blob_clear(&blob); r.in.buffer = &blob; r.in.offered = r.out.needed; - status = dcerpc_spoolss_EnumPrinters(ctx->p, ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("dcerpc_spoolss_EnumPrinters failed - %s\n", nt_errstr(status)); - ret = False; - continue; - } + status = dcerpc_spoolss_EnumPrinters(p, ctx, &r); + torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("EnumPrinters failed - %s\n", - win_errstr(r.out.result)); - continue; - } + torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed"); ctx->printer_count[level] = r.out.count; ctx->printers[level] = r.out.info; @@ -689,14 +524,9 @@ static BOOL test_EnumPrinters(struct test_spoolss_context *ctx) for (i=1;iprinter_count[level] != ctx->printer_count[old_level]) { - printf("EnumPrinters level[%d] returns [%u] printers, but level[%d] returns [%u]\n", - level, ctx->printer_count[level], old_level, ctx->printer_count[old_level]); - ret = False; - } + torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level], + "EnumPrinters invalid value"); } - /* if the array sizes are not the same we would maybe segfault in the following code */ - if (!ret) return ret; for (i=0;iprinters[2][j]; switch (level) { case 0: - COMPARE_STRING(cur->info0, ref->info2, printername); - COMPARE_STRING(cur->info0, ref->info2, servername); - COMPARE_UINT32(cur->info0, ref->info2, cjobs); - /*COMPARE_UINT32(cur->info0, ref->info2, total_jobs); - COMPARE_UINT32(cur->info0, ref->info2, total_bytes); + COMPARE_STRING(tctx, cur->info0, ref->info2, printername); + COMPARE_STRING(tctx, cur->info0, ref->info2, servername); + COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs); + /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs); + COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes); COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time); - COMPARE_UINT32(cur->info0, ref->info2, global_counter); - COMPARE_UINT32(cur->info0, ref->info2, total_pages); - COMPARE_UINT32(cur->info0, ref->info2, version); - COMPARE_UINT32(cur->info0, ref->info2, unknown10); - COMPARE_UINT32(cur->info0, ref->info2, unknown11); - COMPARE_UINT32(cur->info0, ref->info2, unknown12); - COMPARE_UINT32(cur->info0, ref->info2, session_counter); - COMPARE_UINT32(cur->info0, ref->info2, unknown14); - COMPARE_UINT32(cur->info0, ref->info2, printer_errors); - COMPARE_UINT32(cur->info0, ref->info2, unknown16); - COMPARE_UINT32(cur->info0, ref->info2, unknown17); - COMPARE_UINT32(cur->info0, ref->info2, unknown18); - COMPARE_UINT32(cur->info0, ref->info2, unknown19); - COMPARE_UINT32(cur->info0, ref->info2, change_id); - COMPARE_UINT32(cur->info0, ref->info2, unknown21);*/ - COMPARE_UINT32(cur->info0, ref->info2, status); - /*COMPARE_UINT32(cur->info0, ref->info2, unknown23); - COMPARE_UINT32(cur->info0, ref->info2, c_setprinter); + COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter); + COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages); + COMPARE_UINT32(tctx, cur->info0, ref->info2, version); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12); + COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14); + COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19); + COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/ + COMPARE_UINT32(tctx, cur->info0, ref->info2, status); + /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23); + COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter); COMPARE_UINT16(cur->info0, ref->info2, unknown25); COMPARE_UINT16(cur->info0, ref->info2, unknown26); - COMPARE_UINT32(cur->info0, ref->info2, unknown27); - COMPARE_UINT32(cur->info0, ref->info2, unknown28); - COMPARE_UINT32(cur->info0, ref->info2, unknown29);*/ + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28); + COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/ break; case 1: - /*COMPARE_UINT32(cur->info1, ref->info2, flags);*/ - /*COMPARE_STRING(cur->info1, ref->info2, name);*/ - /*COMPARE_STRING(cur->info1, ref->info2, description);*/ - COMPARE_STRING(cur->info1, ref->info2, comment); + /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/ + /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/ + /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/ + COMPARE_STRING(tctx, cur->info1, ref->info2, comment); break; case 2: /* level 2 is our reference, and it makes no sense to compare it to itself */ break; case 4: - COMPARE_STRING(cur->info4, ref->info2, printername); - COMPARE_STRING(cur->info4, ref->info2, servername); - COMPARE_UINT32(cur->info4, ref->info2, attributes); + COMPARE_STRING(tctx, cur->info4, ref->info2, printername); + COMPARE_STRING(tctx, cur->info4, ref->info2, servername); + COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes); break; case 5: - COMPARE_STRING(cur->info5, ref->info2, printername); - COMPARE_STRING(cur->info5, ref->info2, portname); - COMPARE_UINT32(cur->info5, ref->info2, attributes); - /*COMPARE_UINT32(cur->info5, ref->info2, device_not_selected_timeout); - COMPARE_UINT32(cur->info5, ref->info2, transmission_retry_timeout);*/ + COMPARE_STRING(tctx, cur->info5, ref->info2, printername); + COMPARE_STRING(tctx, cur->info5, ref->info2, portname); + COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes); + /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout); + COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/ break; } } @@ -764,17 +594,17 @@ static BOOL test_EnumPrinters(struct test_spoolss_context *ctx) * - verify that the port of a printer was in the list returned by EnumPorts */ - return ret; + return true; } -static BOOL test_GetPrinter(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_GetPrinter(struct torture_context *tctx, + struct dcerpc_pipe *p, struct policy_handle *handle) { NTSTATUS status; struct spoolss_GetPrinter r; uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; int i; - BOOL ret = True; for (i=0;ilast_fault_code == DCERPC_FAULT_OP_RNG_ERROR) { - printf("GetPrinterDataEx not supported by server\n"); - return True; + torture_skip(tctx, "GetPrinterDataEx not supported by server\n"); } - printf("GetPrinterDataEx failed - %s\n", nt_errstr(status)); - return False; + torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed"); } if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) { r.in.offered = r.out.needed; - status = dcerpc_spoolss_GetPrinterDataEx(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("GetPrinterDataEx failed - %s\n", - nt_errstr(status)); - return False; - } + status = dcerpc_spoolss_GetPrinterDataEx(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("GetPrinterDataEx failed - %s\n", - win_errstr(r.out.result)); - return False; - } + torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDataEx failed"); } - return True; + return true; } -static BOOL test_EnumPrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_EnumPrinterData(struct torture_context *tctx, struct dcerpc_pipe *p, struct policy_handle *handle) { NTSTATUS status; @@ -1507,28 +1189,22 @@ static BOOL test_EnumPrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.data_size = &data_size; r.out.data_size = &data_size; - printf("Testing EnumPrinterData\n"); + torture_comment(tctx, "Testing EnumPrinterData\n"); - status = dcerpc_spoolss_EnumPrinterData(p, mem_ctx, &r); + status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("EnumPrinterData failed - %s\n", nt_errstr(status)); - return False; - } + torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed"); r.in.value_offered = r.out.value_needed; - status = dcerpc_spoolss_EnumPrinterData(p, mem_ctx, &r); + status = dcerpc_spoolss_EnumPrinterData(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("EnumPrinterData failed - %s\n", nt_errstr(status)); - return False; - } + torture_assert_ntstatus_ok(tctx, status, "EnumPrinterData failed"); - test_GetPrinterData(p, mem_ctx, handle, r.out.value_name); + test_GetPrinterData(tctx, p, handle, r.out.value_name); - test_GetPrinterDataEx( - p, mem_ctx, handle, "PrinterDriverData", + test_GetPrinterDataEx(tctx, + p, handle, "PrinterDriverData", r.out.value_name); r.in.enum_index++; @@ -1538,7 +1214,8 @@ static BOOL test_EnumPrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return True; } -static BOOL test_EnumPrinterDataEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_EnumPrinterDataEx(struct torture_context *tctx, + struct dcerpc_pipe *p, struct policy_handle *handle) { NTSTATUS status; @@ -1548,28 +1225,23 @@ static BOOL test_EnumPrinterDataEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.key_name = "PrinterDriverData"; r.in.offered = 0; - printf("Testing EnumPrinterDataEx\n"); + torture_comment(tctx, "Testing EnumPrinterDataEx\n"); - status = dcerpc_spoolss_EnumPrinterDataEx(p, mem_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("EnumPrinterDataEx failed - %s\n", nt_errstr(status)); - return False; - } + status = dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r); + torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDataEx failed"); r.in.offered = r.out.needed; - status = dcerpc_spoolss_EnumPrinterDataEx(p, mem_ctx, &r); + status = dcerpc_spoolss_EnumPrinterDataEx(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("EnumPrinterDataEx failed - %s\n", nt_errstr(status)); - return False; - } + torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDataEx failed"); - return True; + return true; } -static BOOL test_DeletePrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_DeletePrinterData(struct torture_context *tctx, + struct dcerpc_pipe *p, struct policy_handle *handle, const char *value_name) { @@ -1579,20 +1251,18 @@ static BOOL test_DeletePrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.handle = handle; r.in.value_name = value_name; - printf("Testing DeletePrinterData\n"); + torture_comment(tctx, "Testing DeletePrinterData\n"); - status = dcerpc_spoolss_DeletePrinterData(p, mem_ctx, &r); + status = dcerpc_spoolss_DeletePrinterData(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("DeletePrinterData failed - %s\n", nt_errstr(status)); - return False; - } + torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed"); - return True; + return true; } -static BOOL test_SetPrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *handle) +static bool test_SetPrinterData(struct torture_context *tctx, + struct dcerpc_pipe *p, + struct policy_handle *handle) { NTSTATUS status; struct spoolss_SetPrinterData r; @@ -1603,84 +1273,69 @@ static BOOL test_SetPrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.type = SPOOLSS_PRINTER_DATA_TYPE_STRING; r.in.data.string = "dog"; - printf("Testing SetPrinterData\n"); + torture_comment(tctx, "Testing SetPrinterData\n"); - status = dcerpc_spoolss_SetPrinterData(p, mem_ctx, &r); + status = dcerpc_spoolss_SetPrinterData(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("SetPrinterData failed - %s\n", nt_errstr(status)); - return False; - } + torture_assert_ntstatus_ok(tctx, status, "SetPrinterData failed"); - if (!test_GetPrinterData(p, mem_ctx, handle, value_name)) { - return False; + if (!test_GetPrinterData(tctx, p, handle, value_name)) { + return false; } - if (!test_DeletePrinterData(p, mem_ctx, handle, value_name)) { - return False; + if (!test_DeletePrinterData(tctx, p, handle, value_name)) { + return false; } - return True; + return true; } -static BOOL test_SecondaryClosePrinter(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_SecondaryClosePrinter(struct torture_context *tctx, + struct dcerpc_pipe *p, struct policy_handle *handle) { NTSTATUS status; struct dcerpc_binding *b; struct dcerpc_pipe *p2; - BOOL ret = True; + bool ret = true; /* only makes sense on SMB */ if (p->conn->transport.transport != NCACN_NP) { return True; } - printf("testing close on secondary pipe\n"); + torture_comment(tctx, "testing close on secondary pipe\n"); - status = dcerpc_parse_binding(mem_ctx, p->conn->binding_string, &b); - if (!NT_STATUS_IS_OK(status)) { - printf("Failed to parse dcerpc binding '%s'\n", p->conn->binding_string); - return False; - } + status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b); + torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding"); status = dcerpc_secondary_connection(p, &p2, b); - if (!NT_STATUS_IS_OK(status)) { - printf("Failed to create secondary connection\n"); - return False; - } + torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection"); status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss); - if (!NT_STATUS_IS_OK(status)) { - printf("Failed to create bind on secondary connection\n"); - talloc_free(p2); - - return False; - } + torture_assert_ntstatus_ok(tctx, status, "Failed to create bind on secondary connection"); - if (test_ClosePrinter(p2, mem_ctx, handle)) { - printf("ERROR: Allowed close on secondary connection!\n"); - ret = False; + if (test_ClosePrinter(tctx, p2, handle)) { + torture_comment(tctx, "ERROR: Allowed close on secondary connection!\n"); + ret = false; } - if (p2->last_fault_code != DCERPC_FAULT_CONTEXT_MISMATCH) { - printf("Unexpected fault code 0x%x - expected 0x%x\n", - p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH); - ret = False; - } + torture_assert_int_equal(tctx, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH, + "Unexpected fault code"); talloc_free(p2); - return ret; + return true; } -static BOOL test_OpenPrinter_badname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *name) +static bool test_OpenPrinter_badname(struct torture_context *tctx, + struct dcerpc_pipe *p, const char *name) { NTSTATUS status; struct spoolss_OpenPrinter op; struct spoolss_OpenPrinterEx opEx; struct policy_handle handle; - BOOL ret = True; + bool ret = true; op.in.printername = name; op.in.datatype = NULL; @@ -1688,20 +1343,17 @@ static BOOL test_OpenPrinter_badname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, op.in.access_mask = 0; op.out.handle = &handle; - printf("\nTesting OpenPrinter(%s) with bad name\n", op.in.printername); + torture_comment(tctx, "\nTesting OpenPrinter(%s) with bad name\n", op.in.printername); - status = dcerpc_spoolss_OpenPrinter(p, mem_ctx, &op); - if (!NT_STATUS_IS_OK(status)) { - printf("OpenPrinter failed - %s\n", nt_errstr(status)); - ret = False; - } + status = dcerpc_spoolss_OpenPrinter(p, tctx, &op); + torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed"); if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) { - printf("OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n", + torture_comment(tctx, "OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n", name, win_errstr(op.out.result)); } if (W_ERROR_IS_OK(op.out.result)) { - ret &=test_ClosePrinter(p, mem_ctx, &handle); + ret &=test_ClosePrinter(tctx, p, &handle); } opEx.in.printername = name; @@ -1712,48 +1364,24 @@ static BOOL test_OpenPrinter_badname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, opEx.in.userlevel.level1 = NULL; opEx.out.handle = &handle; - printf("\nTesting OpenPrinterEx(%s) with bad name\n", opEx.in.printername); + torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername); - status = dcerpc_spoolss_OpenPrinterEx(p, mem_ctx, &opEx); - if (!NT_STATUS_IS_OK(status)) { - printf("OpenPrinter failed - %s\n", nt_errstr(status)); - ret = False; - } + status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &opEx); + torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed"); if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,opEx.out.result)) { - printf("OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n", + torture_comment(tctx, "OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n", name, win_errstr(opEx.out.result)); } if (W_ERROR_IS_OK(opEx.out.result)) { - ret &=test_ClosePrinter(p, mem_ctx, &handle); + ret &=test_ClosePrinter(tctx, p, &handle); } return ret; } -static BOOL test_OpenPrinter_badnames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) -{ - BOOL ret = True; - char *name; - - ret &= test_OpenPrinter_badname(p, mem_ctx, "__INVALID_PRINTER__"); - ret &= test_OpenPrinter_badname(p, mem_ctx, "\\\\__INVALID_HOST__"); - ret &= test_OpenPrinter_badname(p, mem_ctx, ""); - ret &= test_OpenPrinter_badname(p, mem_ctx, "\\\\\\"); - ret &= test_OpenPrinter_badname(p, mem_ctx, "\\\\\\__INVALID_PRINTER__"); - - name = talloc_asprintf(mem_ctx, "\\\\%s\\", dcerpc_server_name(p)); - ret &= test_OpenPrinter_badname(p, mem_ctx, name); - talloc_free(name); - - name = talloc_asprintf(mem_ctx, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)); - ret &= test_OpenPrinter_badname(p, mem_ctx, name); - talloc_free(name); - - return ret; -} - -static BOOL test_OpenPrinter(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_OpenPrinter(struct torture_context *tctx, + struct dcerpc_pipe *p, const char *name) { NTSTATUS status; @@ -1761,42 +1389,37 @@ static BOOL test_OpenPrinter(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle handle; BOOL ret = True; - r.in.printername = talloc_asprintf(mem_ctx, "\\\\%s\\%s", dcerpc_server_name(p), name); + r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name); r.in.datatype = NULL; r.in.devmode_ctr.devmode= NULL; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.handle = &handle; - printf("\nTesting OpenPrinter(%s)\n", r.in.printername); + torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername); - status = dcerpc_spoolss_OpenPrinter(p, mem_ctx, &r); + status = dcerpc_spoolss_OpenPrinter(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("OpenPrinter failed - %s\n", nt_errstr(status)); - return False; - } + torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("OpenPrinter failed - %s\n", win_errstr(r.out.result)); - return False; - } + torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed"); - if (!test_GetPrinter(p, mem_ctx, &handle)) { - ret = False; + if (!test_GetPrinter(tctx, p, &handle)) { + ret = false; } - if (!test_SecondaryClosePrinter(p, mem_ctx, &handle)) { - ret = False; + if (!test_SecondaryClosePrinter(tctx, p, &handle)) { + ret = false; } - if (!test_ClosePrinter(p, mem_ctx, &handle)) { - ret = False; + if (!test_ClosePrinter(tctx, p, &handle)) { + ret = false; } return ret; } -static BOOL call_OpenPrinterEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool call_OpenPrinterEx(struct torture_context *tctx, + struct dcerpc_pipe *p, const char *name, struct policy_handle *handle) { struct spoolss_OpenPrinterEx r; @@ -1804,10 +1427,10 @@ static BOOL call_OpenPrinterEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, NTSTATUS status; if (name && name[0]) { - r.in.printername = talloc_asprintf(mem_ctx, "\\\\%s\\%s", + r.in.printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name); } else { - r.in.printername = talloc_asprintf(mem_ctx, "\\\\%s", + r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); } @@ -1826,87 +1449,82 @@ static BOOL call_OpenPrinterEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, userlevel1.minor = 3; userlevel1.processor = 4; - printf("Testing OpenPrinterEx(%s)\n", r.in.printername); + torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername); - status = dcerpc_spoolss_OpenPrinterEx(p, mem_ctx, &r); + status = dcerpc_spoolss_OpenPrinterEx(p, tctx, &r); - if (!NT_STATUS_IS_OK(status)) { - printf("OpenPrinterEx failed - %s\n", nt_errstr(status)); - return False; - } + torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed"); - if (!W_ERROR_IS_OK(r.out.result)) { - printf("OpenPrinterEx failed - %s\n", win_errstr(r.out.result)); - return False; - } + torture_assert_werr_ok(tctx, r.out.result, "OpenPrinterEx failed"); - return True; + return true; } -static BOOL test_OpenPrinterEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, +static bool test_OpenPrinterEx(struct torture_context *tctx, + struct dcerpc_pipe *p, const char *name) { struct policy_handle handle; - BOOL ret = True; + bool ret = true; - if (!call_OpenPrinterEx(p, mem_ctx, name, &handle)) { - return False; + if (!call_OpenPrinterEx(tctx, p, name, &handle)) { + return false; } - if (!test_GetPrinter(p, mem_ctx, &handle)) { - ret = False; + if (!test_GetPrinter(tctx, p, &handle)) { + ret = false; } - if (!test_EnumForms(p, mem_ctx, &handle, False)) { - ret = False; + if (!test_EnumForms(tctx, p, &handle, false)) { + ret = false; } - if (!test_AddForm(p, mem_ctx, &handle, False)) { - ret = False; + if (!test_AddForm(tctx, p, &handle, false)) { + ret = false; } - if (!test_EnumPrinterData(p, mem_ctx, &handle)) { - ret = False; + if (!test_EnumPrinterData(tctx, p, &handle)) { + ret = false; } - if (!test_EnumPrinterDataEx(p, mem_ctx, &handle)) { - ret = False; + if (!test_EnumPrinterDataEx(tctx, p, &handle)) { + ret = false; } - if (!test_PausePrinter(p, mem_ctx, &handle)) { - ret = False; + if (!test_PausePrinter(tctx, p, &handle)) { + ret = false; } - if (!test_DoPrintTest(p, mem_ctx, &handle)) { - ret = False; + if (!test_DoPrintTest(tctx, p, &handle)) { + ret = false; } - if (!test_ResumePrinter(p, mem_ctx, &handle)) { - ret = False; + if (!test_ResumePrinter(tctx, p, &handle)) { + ret = false; } - if (!test_SetPrinterData(p, mem_ctx, &handle)) { - ret = False; + if (!test_SetPrinterData(tctx, p, &handle)) { + ret = false; } - if (!test_SecondaryClosePrinter(p, mem_ctx, &handle)) { - ret = False; + if (!test_SecondaryClosePrinter(tctx, p, &handle)) { + ret = false; } - if (!test_ClosePrinter(p, mem_ctx, &handle)) { - ret = False; + if (!test_ClosePrinter(tctx, p, &handle)) { + ret = false; } return ret; } -static BOOL test_EnumPrinters_old(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) +static bool test_EnumPrinters_old(struct torture_context *tctx, struct dcerpc_pipe *p) { struct spoolss_EnumPrinters r; NTSTATUS status; uint16_t levels[] = {1, 2, 4, 5}; int i; - BOOL ret = True; + bool ret = true; for (i=0;ip = p; - - ret &= test_OpenPrinter_server(ctx); - - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "W3SvcInstalled"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "BeepEnabled"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "EventLog"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "NetPopup"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "NetPopupToComputer"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "MajorVersion"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "MinorVersion"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "DefaultSpoolDirectory"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "Architecture"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "DsPresent"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "OSVersion"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "OSVersionEx"); - ret &= test_GetPrinterData(ctx->p, ctx, &ctx->server_handle, "DNSMachineName"); - ret &= test_EnumForms(ctx->p, ctx, &ctx->server_handle, True); - ret &= test_AddForm(ctx->p, ctx, &ctx->server_handle, True); - ret &= test_EnumPorts(ctx); - ret &= test_GetPrinterDriverDirectory(ctx); - ret &= test_EnumPrinterDrivers(ctx); - ret &= test_EnumMonitors(ctx); - ret &= test_EnumPrintProcessors(ctx); - ret &= test_EnumPrinters(ctx); - ret &= test_OpenPrinter_badnames(p, torture); - ret &= test_AddPort(p, torture); - ret &= test_EnumPorts_old(p, torture); - ret &= test_EnumPrinters_old(p, torture); - ret &= test_EnumPrinterDrivers_old(p, torture); + + ret &= test_OpenPrinter_server(torture, p, ctx); + + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "W3SvcInstalled"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "BeepEnabled"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "EventLog"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "NetPopup"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "NetPopupToComputer"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "MajorVersion"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "MinorVersion"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "DefaultSpoolDirectory"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "Architecture"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "DsPresent"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "OSVersion"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "OSVersionEx"); + ret &= test_GetPrinterData(torture, p, &ctx->server_handle, "DNSMachineName"); + ret &= test_EnumForms(torture, p, &ctx->server_handle, true); + ret &= test_AddForm(torture, p, &ctx->server_handle, true); + ret &= test_EnumPorts(torture, p, ctx); + ret &= test_GetPrinterDriverDirectory(torture, p, ctx); + ret &= test_EnumPrinterDrivers(torture, p, ctx); + ret &= test_EnumMonitors(torture, p, ctx); + ret &= test_EnumPrintProcessors(torture, p, ctx); + ret &= test_EnumPrinters(torture, p, ctx); + ret &= test_OpenPrinter_badname(torture, p, "__INVALID_PRINTER__"); + ret &= test_OpenPrinter_badname(torture, p, "\\\\__INVALID_HOST__"); + ret &= test_OpenPrinter_badname(torture, p, ""); + ret &= test_OpenPrinter_badname(torture, p, "\\\\\\"); + ret &= test_OpenPrinter_badname(torture, p, "\\\\\\__INVALID_PRINTER__"); + ret &= test_OpenPrinter_badname(torture, p, talloc_asprintf(torture, "\\\\%s\\", dcerpc_server_name(p))); + ret &= test_OpenPrinter_badname(torture, p, + talloc_asprintf(torture, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p))); + + + ret &= test_AddPort(torture, p); + ret &= test_EnumPorts_old(torture, p); + ret &= test_EnumPrinters_old(torture, p); + ret &= test_EnumPrinterDrivers_old(torture, p); + ret &= test_ReplyOpenPrinter(torture, p); return ret; } diff --git a/source4/torture/rpc/spoolss_notify.c b/source4/torture/rpc/spoolss_notify.c new file mode 100644 index 0000000000..43955888f5 --- /dev/null +++ b/source4/torture/rpc/spoolss_notify.c @@ -0,0 +1,295 @@ +/* + Unix SMB/CIFS implementation. + test suite for spoolss rpc notify operations + + Copyright (C) Jelmer Vernooij 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "torture/torture.h" +#include "torture/ui.h" +#include "torture/rpc/rpc.h" +#include "librpc/gen_ndr/ndr_spoolss_c.h" +#include "rpc_server/dcerpc_server.h" +#include "lib/events/events.h" +#include "smbd/process_model.h" +#include "smb_server/smb_server.h" +#include "lib/socket/netif.h" +#include "dlinklist.h" +#include "ntvfs/ntvfs.h" + +static NTSTATUS spoolss__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface) +{ + return NT_STATUS_OK; +} + +static void spoolss__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface) +{ +} + +static NTSTATUS spoolss__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r) +{ + NTSTATUS status; + uint16_t opnum = dce_call->pkt.u.request.opnum; + + dce_call->fault_code = 0; + + if (opnum >= ndr_table_spoolss.num_calls) { + dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR; + return NT_STATUS_NET_WRITE_FAULT; + } + + *r = talloc_size(mem_ctx, ndr_table_spoolss.calls[opnum].struct_size); + NT_STATUS_HAVE_NO_MEMORY(*r); + + /* unravel the NDR for the packet */ + status = ndr_table_spoolss.calls[opnum].ndr_pull(pull, NDR_IN, *r); + if (!NT_STATUS_IS_OK(status)) { + dcerpc_log_packet(&ndr_table_spoolss, opnum, NDR_IN, + &dce_call->pkt.u.request.stub_and_verifier); + dce_call->fault_code = DCERPC_FAULT_NDR; + return NT_STATUS_NET_WRITE_FAULT; + } + + return NT_STATUS_OK; +} + +/* FIXME: What context does this belong in ? -- JRV20070903 */ +static struct received_packet { + uint16_t opnum; + void *r; + struct received_packet *prev, *next; +} *received_packets = NULL; + + +static NTSTATUS spoolss__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r) +{ + uint16_t opnum = dce_call->pkt.u.request.opnum; + struct received_packet *rp; + + rp = talloc_zero(mem_ctx, struct received_packet); + rp->opnum = opnum; + rp->r = talloc_reference(mem_ctx, r); + + DLIST_ADD_END(received_packets, rp, struct received_packet *); + + switch (opnum) { + case 58: { + struct spoolss_ReplyOpenPrinter *r2 = (struct spoolss_ReplyOpenPrinter *)r; + r2->out.result = WERR_OK; + break; + } + + default: + dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR; + break; + } + + if (dce_call->fault_code != 0) { + dcerpc_log_packet(&ndr_table_spoolss, opnum, NDR_IN, + &dce_call->pkt.u.request.stub_and_verifier); + return NT_STATUS_NET_WRITE_FAULT; + } + return NT_STATUS_OK; +} + + +static NTSTATUS spoolss__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r) +{ + return NT_STATUS_OK; +} + + +static NTSTATUS spoolss__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r) +{ + NTSTATUS status; + uint16_t opnum = dce_call->pkt.u.request.opnum; + + status = ndr_table_spoolss.calls[opnum].ndr_push(push, NDR_OUT, r); + if (!NT_STATUS_IS_OK(status)) { + dce_call->fault_code = DCERPC_FAULT_NDR; + return NT_STATUS_NET_WRITE_FAULT; + } + + return NT_STATUS_OK; +} + +const static struct dcesrv_interface notify_test_spoolss_interface = { + .name = "spoolss", + .syntax_id = {{0x12345678,0x1234,0xabcd,{0xef,0x00},{0x01,0x23,0x45,0x67,0x89,0xab}},1.0}, + .bind = spoolss__op_bind, + .unbind = spoolss__op_unbind, + .ndr_pull = spoolss__op_ndr_pull, + .dispatch = spoolss__op_dispatch, + .reply = spoolss__op_reply, + .ndr_push = spoolss__op_ndr_push +}; + +static bool spoolss__op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version) +{ + if (notify_test_spoolss_interface.syntax_id.if_version == if_version && + GUID_equal(¬ify_test_spoolss_interface.syntax_id.uuid, uuid)) { + memcpy(iface,¬ify_test_spoolss_interface, sizeof(*iface)); + return true; + } + + return false; +} + +static bool spoolss__op_interface_by_name(struct dcesrv_interface *iface, const char *name) +{ + if (strcmp(notify_test_spoolss_interface.name, name)==0) { + memcpy(iface, ¬ify_test_spoolss_interface, sizeof(*iface)); + return true; + } + + return false; +} + +static NTSTATUS spoolss__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server) +{ + int i; + + for (i=0;icount;i++) { + NTSTATUS ret; + const char *name = ndr_table_spoolss.endpoints->names[i]; + + ret = dcesrv_interface_register(dce_ctx, name, ¬ify_test_spoolss_interface, NULL); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1,("spoolss_op_init_server: failed to register endpoint '%s'\n",name)); + return ret; + } + } + + return NT_STATUS_OK; +} + +static bool test_RFFPCNEx(struct torture_context *tctx, + struct dcerpc_pipe *p) +{ + struct spoolss_OpenPrinter q; + struct spoolss_RemoteFindFirstPrinterChangeNotifyEx r; + struct dcesrv_endpoint_server ep_server; + NTSTATUS status; + struct dcesrv_context *dce_ctx; + const char *endpoints[] = { "spoolss", NULL }; + struct spoolss_NotifyOptionsContainer t1; + struct spoolss_ClosePrinter cp; + + struct policy_handle handle; + const char *address; + + ZERO_STRUCT(q); + + q.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); + q.in.datatype = NULL; + q.in.devmode_ctr.devmode= NULL; + q.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + q.out.handle = &handle; + + torture_comment(tctx, "Testing OpenPrinter(%s)\n", q.in.printername); + + status = dcerpc_spoolss_OpenPrinter(p, tctx, &q); + + torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed"); + + torture_assert_werr_ok(tctx, q.out.result, "OpenPrinter failed"); + + /* Start DCE/RPC server */ + + /* fill in our name */ + ep_server.name = "spoolss"; + + /* fill in all the operations */ + ep_server.init_server = spoolss__op_init_server; + + ep_server.interface_by_uuid = spoolss__op_interface_by_uuid; + ep_server.interface_by_name = spoolss__op_interface_by_name; + + torture_assert_ntstatus_ok(tctx, dcerpc_register_ep_server(&ep_server), + "unable to register spoolss server"); + + lp_set_cmdline("dcerpc endpoint servers", "spoolss"); + + address = iface_n_ip(0); + torture_comment(tctx, "Listening for callbacks on %s\n", address); + status = smbsrv_add_socket(p->conn->event_ctx, &single_ops, address); + torture_assert_ntstatus_ok(tctx, status, "starting smb server"); + + status = dcesrv_init_context(tctx, endpoints, &dce_ctx); + torture_assert_ntstatus_ok(tctx, status, + "unable to initialize DCE/RPC server"); + + + r.in.flags = 0; + r.in.str = talloc_asprintf(tctx, "\\\\%s", address); + r.in.options = 0; + r.in.printer_local = 123; + t1.version = 2; + t1.flags = 0; + t1.count = 2; + t1.options = talloc_zero_array(tctx, struct spoolss_NotifyOptionsArray, 2); + t1.options[0].type = SPOOLSS_NOTIFY_PRINTER; + t1.options[0].count = 1; + t1.options[0].fields = talloc_array(t1.options, enum spoolss_Field, 1); + t1.options[0].fields[0] = SPOOLSS_FIELD_SERVER_NAME; + + t1.options[1].type = SPOOLSS_NOTIFY_JOB; + t1.options[1].count = 1; + t1.options[1].fields = talloc_array(t1.options, enum spoolss_Field, 1); + t1.options[1].fields[0] = SPOOLSS_FIELD_PRINTER_NAME; + + r.in.t1 = &t1; + r.in.handle = &handle; + + + status = dcerpc_spoolss_RemoteFindFirstPrinterChangeNotifyEx(p, tctx, &r); + + torture_assert_ntstatus_ok(tctx, status, "FFPCNEx failed"); + + torture_assert_werr_ok(tctx, r.out.result, "error return code for FFPCNEx"); + + cp.in.handle = &handle; + cp.out.handle = &handle; + + torture_comment(tctx, "Testing ClosePrinter\n"); + + status = dcerpc_spoolss_ClosePrinter(p, tctx, &cp); + torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed"); + + /* We should've had an incoming packet 58 (ReplyOpenPrinter) */ + torture_assert(tctx, received_packets != NULL, "no packets received"); + torture_assert_int_equal(tctx, received_packets->opnum, 58, "invalid opnum"); + + /* Shut down DCE/RPC server */ + talloc_free(dce_ctx); + + return true; +} + +struct torture_suite *torture_rpc_spoolss_notify(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "SPOOLSS-NOTIFY"); + + struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite, + "notify", &ndr_table_spoolss); + + ntvfs_init(); + torture_rpc_tcase_add_test(tcase, "testRFFPCNEx", test_RFFPCNEx); + + return suite; +} -- cgit