summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/Makefile.in6
-rw-r--r--source3/include/proto.h18
-rwxr-xr-xsource3/include/rpc_spoolss.h28
-rw-r--r--source3/rpc_client/cli_spoolss_notify.c295
-rw-r--r--source3/rpc_parse/parse_spoolss.c119
-rw-r--r--source3/rpc_server/srv_spoolss_nt.c150
6 files changed, 602 insertions, 14 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 716afcd927..7ad6f6e64e 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -45,8 +45,6 @@ LOGFILEBASE = $(VARDIR)
CONFIGFILE = $(LIBDIR)/smb.conf
LMHOSTSFILE = $(LIBDIR)/lmhosts
DRIVERFILE = $(LIBDIR)/printers.def
-NTDRIVERSDIR = $(LIBDIR)/ntprinters
-FORMSFILE = $(NTDRIVERSDIR)/ntforms.def
PASSWD_PROGRAM = /bin/passwd
# This is where smbpasswd et al go
PRIVATEDIR = @privatedir@
@@ -149,8 +147,8 @@ RPC_CLIENT_OBJ = \
rpc_client/cli_wkssvc.o \
rpc_client/cli_srvsvc.o \
rpc_client/cli_samr.o \
- rpc_client/cli_reg.o
-
+ rpc_client/cli_reg.o \
+ rpc_client/cli_spoolss_notify.o
LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 0d163be3ba..f1183789f7 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1977,6 +1977,15 @@ uint32 spoolss_getprinterdriverdir(fstring srv_name, fstring env_name, uint32 le
uint32 *needed);
uint32 spoolss_addprinterdriver(const char *srv_name, uint32 level, PRINTER_DRIVER_CTR *info);
+/*The following definitions come from rpc_client/cli_spoolss_notify.c */
+
+BOOL spoolss_disconnect_from_client( struct cli_state *cli);
+BOOL spoolss_connect_to_client( struct cli_state *cli, char *remote_machine);
+BOOL cli_spoolss_reply_open_printer(struct cli_state *cli, char *printer, uint32 localprinter, uint32 type, uint32 *status, POLICY_HND *handle);
+BOOL cli_spoolss_reply_rrpcn(struct cli_state *cli, POLICY_HND *handle,
+ uint32 change_low, uint32 change_high, uint32 *status);
+BOOL cli_spoolss_reply_close_printer(struct cli_state *cli, POLICY_HND *handle, uint32 *status);
+
/*The following definitions come from rpc_client/cli_srvsvc.c */
BOOL do_srv_net_srv_conn_enum(struct cli_state *cli,
@@ -2935,10 +2944,17 @@ void free_print1_array(uint32 num_entries, PRINTER_INFO_1 **entries);
void free_job1_array(uint32 num_entries, JOB_INFO_1 **entries);
void free_job_info_2(JOB_INFO_2 *job);
void free_job2_array(uint32 num_entries, JOB_INFO_2 **entries);
+BOOL make_spoolss_q_replyopenprinter(SPOOL_Q_REPLYOPENPRINTER *q_u,
+ const fstring string, uint32 printer, uint32 type);
BOOL spoolss_io_q_replyopenprinter(char *desc, SPOOL_Q_REPLYOPENPRINTER *q_u, prs_struct *ps, int depth);
BOOL spoolss_io_r_replyopenprinter(char *desc, SPOOL_R_REPLYOPENPRINTER *r_u, prs_struct *ps, int depth);
+BOOL make_spoolss_q_reply_closeprinter(SPOOL_Q_REPLYCLOSEPRINTER *q_u, POLICY_HND *hnd);
BOOL spoolss_io_q_replycloseprinter(char *desc, SPOOL_Q_REPLYCLOSEPRINTER *q_u, prs_struct *ps, int depth);
BOOL spoolss_io_r_replycloseprinter(char *desc, SPOOL_R_REPLYCLOSEPRINTER *r_u, prs_struct *ps, int depth);
+BOOL make_spoolss_q_reply_rrpcn(SPOOL_Q_REPLY_RRPCN *q_u, POLICY_HND *hnd,
+ uint32 change_low, uint32 change_high);
+BOOL spoolss_io_q_reply_rrpcn(char *desc, SPOOL_Q_REPLY_RRPCN *q_u, prs_struct *ps, int depth);
+BOOL spoolss_io_r_reply_rrpcn(char *desc, SPOOL_R_REPLY_RRPCN *r_u, prs_struct *ps, int depth);
/*The following definitions come from rpc_parse/parse_srv.c */
@@ -3173,7 +3189,7 @@ uint32 _spoolss_schedulejob( POLICY_HND *handle, uint32 jobid);
uint32 _spoolss_setjob( POLICY_HND *handle,
uint32 jobid,
uint32 level,
- pipes_struct *p,
+ pipes_struct *p,
JOB_INFO *ctr,
uint32 command);
uint32 _spoolss_enumprinterdrivers( UNISTR2 *name, UNISTR2 *environment, uint32 level,
diff --git a/source3/include/rpc_spoolss.h b/source3/include/rpc_spoolss.h
index 61b20c36c8..94cfb45dfe 100755
--- a/source3/include/rpc_spoolss.h
+++ b/source3/include/rpc_spoolss.h
@@ -54,7 +54,6 @@
#define SPOOLSS_FINDNEXTPRINTERCHANGENOTIFICATION 0x37
#define SPOOLSS_ROUTERFINDFIRSTPRINTERNOTIFICATIONOLD 0x39
#define SPOOLSS_ROUTERREPLYPRINTER 0x3b
-#define SPOOLSS_REPLYCLOSEPRINTER 0x3c
#define SPOOLSS_ADDPORTEX 0x3d
#define SPOOLSS_REMOTEFINDFIRSTPRINTERCHANGENOTIFICATION0x3e
#define SPOOLSS_SPOOLERINIT 0x3f
@@ -99,8 +98,11 @@
/* find close printer notification */
#define SPOOLSS_FCPN 0x38
#define SPOOLSS_REPLYOPENPRINTER 0x3a
+#define SPOOLSS_REPLYCLOSEPRINTER 0x3c
/* remote find first printer change notifyEx */
#define SPOOLSS_RFFPCNEX 0x41
+/*SPOOLSS_ROUTERREFRESHPRINTERCHANGENOTIFICATION */
+#define SPOOLSS_RRPCN 0x42
/* remote find next printer change notifyEx */
#define SPOOLSS_RFNPCNEX 0x43
#define SPOOLSS_OPENPRINTEREX 0x45
@@ -299,6 +301,8 @@
PRINTER_CHANGE_PRINT_PROCESSOR | \
PRINTER_CHANGE_PRINTER_DRIVER )
+#define PRINTER_NOTIFY_INFO_DISCARDED 0x1
+
/*
* The printer attributes.
* I #defined all of them (grabbed form MSDN)
@@ -1773,7 +1777,8 @@ typedef struct spool_q_replyopenprinter
UNISTR2 string;
uint32 printer;
uint32 type;
- NEW_BUFFER *buffer;
+ uint32 unknown0;
+ uint32 unknown1;
}
SPOOL_Q_REPLYOPENPRINTER;
@@ -1797,6 +1802,25 @@ typedef struct spool_r_replycloseprinter
}
SPOOL_R_REPLYCLOSEPRINTER;
+typedef struct spool_q_rrpcn
+{
+ POLICY_HND handle;
+ uint32 change_low;
+ uint32 change_high;
+ uint32 unknown0;
+ uint32 unknown1;
+ uint32 info_ptr;
+ SPOOL_NOTIFY_INFO info;
+}
+SPOOL_Q_REPLY_RRPCN;
+
+typedef struct spool_r_rrpcn
+{
+ uint32 unknown0;
+ uint32 status;
+}
+SPOOL_R_REPLY_RRPCN;
+
#define PRINTER_DRIVER_VERSION 2
#define PRINTER_DRIVER_ARCHITECTURE "Windows NT x86"
diff --git a/source3/rpc_client/cli_spoolss_notify.c b/source3/rpc_client/cli_spoolss_notify.c
new file mode 100644
index 0000000000..acd53ced4c
--- /dev/null
+++ b/source3/rpc_client/cli_spoolss_notify.c
@@ -0,0 +1,295 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * Version 1.9.
+ * RPC Pipe client / server routines
+ * Copyright (C) Andrew Tridgell 1992-2000,
+ * Copyright (C) Jean Francois Micouleau 1998-2000,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+#include "rpc_parse.h"
+#include "rpc_client.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+extern pstring global_myname;
+
+/*********************************************************
+ Disconnect from the client machine.
+**********************************************************/
+BOOL spoolss_disconnect_from_client( struct cli_state *cli)
+{
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+
+ return True;
+}
+
+
+/*********************************************************
+ Connect to the client machine.
+**********************************************************/
+
+BOOL spoolss_connect_to_client( struct cli_state *cli, char *remote_machine)
+{
+ ZERO_STRUCTP(cli);
+ if(cli_initialise(cli) == False) {
+ DEBUG(0,("connect_to_client: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if(!resolve_name( remote_machine, &cli->dest_ip, 0x20)) {
+ DEBUG(0,("connect_to_client: Can't resolve address for %s\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (ismyip(cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!cli_connect(cli, remote_machine, &cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!attempt_netbios_session_request(cli, global_myname, remote_machine, &cli->dest_ip)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request. Error was %s\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ cli->protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(cli)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (cli->protocol != PROTOCOL_NT1) {
+ DEBUG(0,("connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(cli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!(cli->sec_mode & 1)) {
+ DEBUG(0,("connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ /*
+ * Ok - we have an anonymous connection to the IPC$ share.
+ * Now start the NT Domain stuff :-).
+ */
+
+ if(cli_nt_session_open(cli, PIPE_SPOOLSS) == False) {
+ DEBUG(0,("connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli)));
+ cli_nt_session_close(cli);
+ cli_ulogoff(cli);
+ cli_shutdown(cli);
+ return False;
+ }
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_open_printer(struct cli_state *cli, char *printer, uint32 localprinter, uint32 type, uint32 *status, POLICY_HND *handle)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLYOPENPRINTER q_s;
+ SPOOL_R_REPLYOPENPRINTER r_s;
+
+ prs_init(&buf , 1024, 4, cli->mem_ctx, False);
+ prs_init(&rbuf, 0, 4, cli->mem_ctx, True );
+
+ /* create and send a MSRPC command with api SPOOLSS_REPLYOPENPRINTER */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_replyopenprinter(&q_s, printer, localprinter, type);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_replyopenprinter("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_open_printer: Error : failed to marshall NET_Q_SRV_PWSET struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYOPENPRINTER, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_replyopenprinter("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ memcpy(handle, &r_s.handle, sizeof(r_s.handle));
+ *status=r_s.status;
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_rrpcn(struct cli_state *cli, POLICY_HND *handle,
+ uint32 change_low, uint32 change_high, uint32 *status)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLY_RRPCN q_s;
+ SPOOL_R_REPLY_RRPCN r_s;
+
+ prs_init(&buf , 1024, 4, cli->mem_ctx, False);
+ prs_init(&rbuf, 0, 4, cli->mem_ctx, True );
+
+ /* create and send a MSRPC command with api */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_reply_rrpcn(&q_s, handle, change_low, change_high);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_reply_rrpcn("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_rrpcn: Error : failed to marshall SPOOL_Q_REPLY_RRPCN struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_RRPCN, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_reply_rrpcn("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ *status=r_s.status;
+
+ return True;
+}
+
+/***************************************************************************
+ do a reply open printer
+****************************************************************************/
+
+BOOL cli_spoolss_reply_close_printer(struct cli_state *cli, POLICY_HND *handle, uint32 *status)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+
+ SPOOL_Q_REPLYCLOSEPRINTER q_s;
+ SPOOL_R_REPLYCLOSEPRINTER r_s;
+
+ prs_init(&buf , 1024, 4, cli->mem_ctx, False);
+ prs_init(&rbuf, 0, 4, cli->mem_ctx, True );
+
+ /* create and send a MSRPC command with api */
+/*
+ DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan_type, global_myname,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+*/
+ /* store the parameters */
+ make_spoolss_q_reply_closeprinter(&q_s, handle);
+
+ /* turn parameters into data stream */
+ if(!spoolss_io_q_replycloseprinter("", &q_s, &buf, 0)) {
+ DEBUG(0,("cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_Q_REPLY_CLOSEPRINTER struct.\n"));
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ /* send the data on \PIPE\ */
+ if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYCLOSEPRINTER, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&buf);
+
+ /* turn data stream into parameters*/
+ if(!spoolss_io_r_replycloseprinter("", &r_s, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return False;
+ }
+
+ prs_mem_free(&rbuf);
+
+ *status=r_s.status;
+
+ return True;
+}
+
diff --git a/source3/rpc_parse/parse_spoolss.c b/source3/rpc_parse/parse_spoolss.c
index 69d9c5bd83..6141c14446 100644
--- a/source3/rpc_parse/parse_spoolss.c
+++ b/source3/rpc_parse/parse_spoolss.c
@@ -5735,6 +5735,26 @@ JOB_INFO_2 *add_job2_to_array(uint32 *len, JOB_INFO_2 ***array,
}
/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+BOOL make_spoolss_q_replyopenprinter(SPOOL_Q_REPLYOPENPRINTER *q_u,
+ const fstring string, uint32 printer, uint32 type)
+{
+ if (q_u == NULL)
+ return False;
+
+ init_unistr2(&q_u->string, string, strlen(string)+1);
+
+ q_u->printer=printer;
+ q_u->type=type;
+
+ q_u->unknown0=0x0;
+ q_u->unknown1=0x0;
+
+ return True;
+}
+
+/*******************************************************************
Parse a SPOOL_Q_REPLYOPENPRINTER structure.
********************************************************************/
BOOL spoolss_io_q_replyopenprinter(char *desc, SPOOL_Q_REPLYOPENPRINTER *q_u, prs_struct *ps, int depth)
@@ -5756,7 +5776,9 @@ BOOL spoolss_io_q_replyopenprinter(char *desc, SPOOL_Q_REPLYOPENPRINTER *q_u, pr
if(!prs_uint32("type", ps, depth, &q_u->type))
return False;
- if(!new_spoolss_io_buffer("", ps, depth, q_u->buffer))
+ if(!prs_uint32("unknown0", ps, depth, &q_u->unknown0))
+ return False;
+ if(!prs_uint32("unknown1", ps, depth, &q_u->unknown1))
return False;
return True;
@@ -5783,6 +5805,19 @@ BOOL spoolss_io_r_replyopenprinter(char *desc, SPOOL_R_REPLYOPENPRINTER *r_u, pr
}
/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+BOOL make_spoolss_q_reply_closeprinter(SPOOL_Q_REPLYCLOSEPRINTER *q_u, POLICY_HND *hnd)
+{
+ if (q_u == NULL)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ return True;
+}
+
+/*******************************************************************
Parse a SPOOL_Q_REPLYCLOSEPRINTER structure.
********************************************************************/
BOOL spoolss_io_q_replycloseprinter(char *desc, SPOOL_Q_REPLYCLOSEPRINTER *q_u, prs_struct *ps, int depth)
@@ -5818,3 +5853,85 @@ BOOL spoolss_io_r_replycloseprinter(char *desc, SPOOL_R_REPLYCLOSEPRINTER *r_u,
return True;
}
+
+/*******************************************************************
+ * init a structure.
+ ********************************************************************/
+BOOL make_spoolss_q_reply_rrpcn(SPOOL_Q_REPLY_RRPCN *q_u, POLICY_HND *hnd,
+ uint32 change_low, uint32 change_high)
+{
+ if (q_u == NULL)
+ return False;
+
+ memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
+
+ q_u->change_low=change_low;
+ q_u->change_high=change_high;
+
+ q_u->unknown0=0x0;
+ q_u->unknown1=0x0;
+
+ q_u->info_ptr=1;
+
+ q_u->info.version=2;
+ q_u->info.flags=PRINTER_NOTIFY_INFO_DISCARDED;
+ q_u->info.count=0;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_Q_REPLY_RRPCN structure.
+********************************************************************/
+BOOL spoolss_io_q_reply_rrpcn(char *desc, SPOOL_Q_REPLY_RRPCN *q_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_q_replycloseprinter");
+ depth++;
+
+ if(!prs_align(ps))
+ return False;
+
+ if(!smb_io_pol_hnd("printer handle",&q_u->handle,ps,depth))
+ return False;
+
+ if (!prs_uint32("change_low", ps, depth, &q_u->change_low))
+ return False;
+
+ if (!prs_uint32("change_high", ps, depth, &q_u->change_high))
+ return False;
+
+ if (!prs_uint32("unknown0", ps, depth, &q_u->unknown0))
+ return False;
+
+ if (!prs_uint32("unknown1", ps, depth, &q_u->unknown1))
+ return False;
+
+ if (!prs_uint32("info_ptr", ps, depth, &q_u->info_ptr))
+ return False;
+
+ if(q_u->info_ptr!=0)
+ if(!smb_io_notify_info(desc, &q_u->info, ps, depth))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+ Parse a SPOOL_R_REPLY_RRPCN structure.
+********************************************************************/
+BOOL spoolss_io_r_reply_rrpcn(char *desc, SPOOL_R_REPLY_RRPCN *r_u, prs_struct *ps, int depth)
+{
+ prs_debug(ps, depth, desc, "spoolss_io_r_replycloseprinter");
+ depth++;
+
+ if (!prs_align(ps))
+ return False;
+
+ if (!prs_uint32("unknown0", ps, depth, &r_u->unknown0))
+ return False;
+
+ if (!prs_uint32("status", ps, depth, &r_u->status))
+ return False;
+
+ return True;
+}
diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c
index ca1b20522b..2a25f615d8 100644
--- a/source3/rpc_server/srv_spoolss_nt.c
+++ b/source3/rpc_server/srv_spoolss_nt.c
@@ -60,6 +60,8 @@ typedef struct _Printer{
fstring localmachine;
uint32 printerlocal;
SPOOL_NOTIFY_OPTION *option;
+ POLICY_HND client_hnd;
+ uint32 client_connected;
} notify;
struct {
fstring machine;
@@ -78,6 +80,8 @@ typedef struct _counter_printer_0 {
static ubi_dlList Printer_list;
static ubi_dlList counter_list;
+static struct cli_state cli;
+static uint32 smb_connections=0;
#define OPEN_HANDLE(pnum) ((pnum!=NULL) && (pnum->open!=False) && (IVAL(pnum->printer_hnd.data,16)==(uint32)sys_getpid()))
#define OUR_HANDLE(pnum) ((pnum==NULL)?"NULL":(IVAL(pnum->data,16)==sys_getpid()?"OURS":"OTHER"))
@@ -170,6 +174,30 @@ static void clear_handle(POLICY_HND *hnd)
ZERO_STRUCTP(hnd);
}
+/***************************************************************************
+ Disconnect from the client
+****************************************************************************/
+static BOOL srv_spoolss_replycloseprinter(POLICY_HND *handle)
+{
+ uint32 status;
+
+ /* weird if the test succeds !!! */
+ if (smb_connections==0) {
+ DEBUG(0,("srv_spoolss_replycloseprinter:Trying to close non-existant notify backchannel !\n"));
+ return False;
+ }
+
+ if(!cli_spoolss_reply_close_printer(&cli, handle, &status))
+ return False;
+
+ /* if it's the last connection, deconnect the IPC$ share */
+ if (smb_connections==1)
+ if(!spoolss_disconnect_from_client(&cli))
+ return False;
+
+ smb_connections--;
+}
+
/****************************************************************************
close printer index by handle
****************************************************************************/
@@ -182,6 +210,10 @@ static BOOL close_printer_handle(POLICY_HND *hnd)
return False;
}
+ if (Printer->notify.client_connected==True)
+ if(!srv_spoolss_replycloseprinter(&Printer->notify.client_hnd))
+ return ERROR_INVALID_HANDLE;
+
Printer->open=False;
Printer->notify.flags=0;
Printer->notify.options=0;
@@ -189,7 +221,8 @@ static BOOL close_printer_handle(POLICY_HND *hnd)
Printer->notify.printerlocal=0;
safe_free(Printer->notify.option);
Printer->notify.option=NULL;
-
+ Printer->notify.client_connected=False;
+
clear_handle(hnd);
ubi_dlRemThis(&Printer_list, Printer);
@@ -540,6 +573,57 @@ static BOOL alloc_buffer_size(NEW_BUFFER *buffer, uint32 buffer_size)
return True;
}
+/***************************************************************************
+ receive the notify message
+****************************************************************************/
+static BOOL srv_spoolss_receive_message(char *printer)
+{
+ uint32 status;
+ Printer_entry *find_printer;
+
+ find_printer = (Printer_entry *)ubi_dlFirst(&Printer_list);
+
+ /* Iterate the printer list. */
+ for(; find_printer; find_printer = (Printer_entry *)ubi_dlNext(find_printer)) {
+
+ /*
+ * if the entry is the given printer or if it's a printerserver
+ * we send the message
+ */
+
+ if (find_printer->printer_type==PRINTER_HANDLE_IS_PRINTER)
+ if (strcmp(find_printer->dev.handlename, printer))
+ continue;
+
+ if (find_printer->notify.client_connected==True)
+ if( !cli_spoolss_reply_rrpcn(&cli, &find_printer->notify.client_hnd, PRINTER_CHANGE_ALL, 0x0, &status))
+ return False;
+
+ }
+}
+
+/***************************************************************************
+ send a notify event
+****************************************************************************/
+static BOOL srv_spoolss_sendnotify(POLICY_HND *handle)
+{
+ fstring printer;
+
+ Printer_entry *Printer=find_printer_index_by_hnd(handle);
+
+ if (!OPEN_HANDLE(Printer)) {
+ DEBUG(0,("srv_spoolss_sendnotify: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+ return False;
+ }
+
+ if (Printer->printer_type==PRINTER_HANDLE_IS_PRINTER)
+ fstrcpy(printer, Printer->dev.handlename);
+ else
+ fstrcpy(printer, "");
+
+ srv_spoolss_receive_message(printer);
+}
+
/********************************************************************
* spoolss_open_printer
*
@@ -695,6 +779,8 @@ uint32 _spoolss_deleteprinter(POLICY_HND *handle)
if (!delete_printer_handle(handle))
return ERROR_INVALID_HANDLE;
+
+ srv_spoolss_sendnotify(handle);
return NT_STATUS_NO_PROBLEMO;
}
@@ -896,6 +982,27 @@ uint32 _spoolss_getprinterdata(POLICY_HND *handle, UNISTR2 *valuename,
return NT_STATUS_NO_PROBLEMO;
}
+/***************************************************************************
+ connect to the client
+****************************************************************************/
+static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uint32 type, POLICY_HND *handle)
+{
+ uint32 status;
+
+ /*
+ * If it's the first connection, contact the client
+ * and connect to the IPC$ share anonumously
+ */
+ if (smb_connections==0)
+ if(!spoolss_connect_to_client(&cli, printer+2)) /* the +2 is to strip the leading 2 backslashs */
+ return False;
+
+ smb_connections++;
+
+ if(!cli_spoolss_reply_open_printer(&cli, printer, localprinter, type, &status, handle))
+ return False;
+}
+
/********************************************************************
* _spoolss_rffpcnex
* ReplyFindFirstPrinterChangeNotifyEx
@@ -926,6 +1033,12 @@ uint32 _spoolss_rffpcnex(POLICY_HND *handle, uint32 flags, uint32 options,
Printer->notify.option=option;
unistr2_to_ascii(Printer->notify.localmachine, localmachine, sizeof(Printer->notify.localmachine)-1);
+ /* connect to the client machine and send a ReplyOpenPrinter */
+ if(srv_spoolss_replyopenprinter(Printer->notify.localmachine,
+ Printer->notify.printerlocal, 1,
+ &Printer->notify.client_hnd))
+ Printer->notify.client_connected=True;
+
return NT_STATUS_NO_PROBLEMO;
}
@@ -3112,6 +3225,7 @@ uint32 _spoolss_startdocprinter(POLICY_HND *handle, uint32 level,
Printer->document_started=True;
(*jobid) = Printer->jobid;
+ srv_spoolss_sendnotify(handle);
return 0x0;
}
@@ -3133,6 +3247,8 @@ uint32 _spoolss_enddocprinter(POLICY_HND *handle)
print_job_end(Printer->jobid);
/* error codes unhandled so far ... */
+ srv_spoolss_sendnotify(handle);
+
return 0x0;
}
@@ -3182,17 +3298,20 @@ static uint32 control_printer(POLICY_HND *handle, uint32 command,
switch (command) {
case PRINTER_CONTROL_PAUSE:
if (print_queue_pause(&user, snum, &errcode)) {
+ srv_spoolss_sendnotify(handle);
return 0;
}
break;
case PRINTER_CONTROL_RESUME:
case PRINTER_CONTROL_UNPAUSE:
if (print_queue_resume(&user, snum, &errcode)) {
+ srv_spoolss_sendnotify(handle);
return 0;
}
break;
case PRINTER_CONTROL_PURGE:
if (print_queue_purge(&user, snum, &errcode)) {
+ srv_spoolss_sendnotify(handle);
return 0;
}
break;
@@ -3449,6 +3568,8 @@ static uint32 update_printer(POLICY_HND *handle, uint32 level,
done:
free_a_printer(&printer, 2);
+ srv_spoolss_sendnotify(handle);
+
return result;
}
@@ -3495,7 +3616,11 @@ uint32 _spoolss_fcpn(POLICY_HND *handle)
DEBUG(0,("_spoolss_fcpn: Invalid handle (%s)\n", OUR_HANDLE(handle)));
return ERROR_INVALID_HANDLE;
}
-
+
+ if (Printer->notify.client_connected==True)
+ if(!srv_spoolss_replycloseprinter(&Printer->notify.client_hnd))
+ return ERROR_INVALID_HANDLE;
+
Printer->notify.flags=0;
Printer->notify.options=0;
Printer->notify.localmachine[0]='\0';
@@ -3504,7 +3629,8 @@ uint32 _spoolss_fcpn(POLICY_HND *handle)
safe_free(Printer->notify.option->ctr.type);
safe_free(Printer->notify.option);
Printer->notify.option=NULL;
-
+ Printer->notify.client_connected=False;
+
return NT_STATUS_NO_PROBLEMO;
}
@@ -3779,13 +3905,22 @@ uint32 _spoolss_setjob( POLICY_HND *handle,
switch (command) {
case JOB_CONTROL_CANCEL:
case JOB_CONTROL_DELETE:
- if (print_job_delete(&user, jobid)) return 0x0;
+ if (print_job_delete(&user, jobid)) {
+ srv_spoolss_sendnotify(handle);
+ return 0x0;
+ }
break;
case JOB_CONTROL_PAUSE:
- if (print_job_pause(&user, jobid)) return 0x0;
+ if (print_job_pause(&user, jobid)) {
+ srv_spoolss_sendnotify(handle);
+ return 0x0;
+ }
break;
case JOB_CONTROL_RESUME:
- if (print_job_resume(&user, jobid)) return 0x0;
+ if (print_job_resume(&user, jobid)) {
+ srv_spoolss_sendnotify(handle);
+ return 0x0;
+ }
break;
default:
return ERROR_INVALID_LEVEL;
@@ -4512,6 +4647,9 @@ static uint32 spoolss_addprinterex_level_2( const UNISTR2 *uni_srv_name,
}
free_a_printer(&printer,2);
+
+ srv_spoolss_sendnotify(handle);
+
return NT_STATUS_NO_PROBLEMO;
}