From 233bc000209cf5759e0e49ad83da70b280d51dae Mon Sep 17 00:00:00 2001 From: Jean-François Micouleau Date: Mon, 25 Sep 2000 21:05:18 +0000 Subject: printer notify code. It only sends notifies to one client. The broadcasting notify code will code soon. J.F. (This used to be commit 4c63c9185887c64e57d901e82a4a16a83522c898) --- source3/Makefile.in | 6 +- source3/include/proto.h | 18 +- source3/include/rpc_spoolss.h | 28 ++- source3/rpc_client/cli_spoolss_notify.c | 295 ++++++++++++++++++++++++++++++++ source3/rpc_parse/parse_spoolss.c | 119 ++++++++++++- source3/rpc_server/srv_spoolss_nt.c | 150 +++++++++++++++- 6 files changed, 602 insertions(+), 14 deletions(-) create mode 100644 source3/rpc_client/cli_spoolss_notify.c 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 @@ -5734,6 +5734,26 @@ JOB_INFO_2 *add_job2_to_array(uint32 *len, JOB_INFO_2 ***array, (void***)array, (const void*)job, *fn, True); } +/******************************************************************* + * 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. ********************************************************************/ @@ -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; @@ -5782,6 +5804,19 @@ BOOL spoolss_io_r_replyopenprinter(char *desc, SPOOL_R_REPLYOPENPRINTER *r_u, pr return True; } +/******************************************************************* + * 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. ********************************************************************/ @@ -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; } -- cgit