more debug classess activated
[ira/wip.git] / source3 / rpc_client / cli_spoolss_notify.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-2000,
5  *  Copyright (C) Jean Francois Micouleau      1998-2000,
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include "includes.h"
23 #if 0
24 #include "rpc_parse.h"
25 #include "nterr.h"
26 #endif
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_RPC_CLI
30
31 extern pstring global_myname;
32
33 struct msg_info_table {
34         uint32 msg;
35         uint32 field;
36         char*  name;
37         void (*construct_fn) (int snum, SPOOL_NOTIFY_INFO_DATA *data,
38                 print_queue_struct *queue,
39                 NT_PRINTER_INFO_LEVEL *printer, TALLOC_CTX *mem_ctx);
40 };
41
42 struct msg_info_table msg_table[] = {
43 { PRINTER_MESSAGE_DRIVER,      PRINTER_NOTIFY_DRIVER_NAME,    "PRINTER_MESSAGE_DRIVER",      spoolss_notify_driver_name  },
44 { PRINTER_MESSAGE_ATTRIBUTES,  PRINTER_NOTIFY_ATTRIBUTES,     "PRINTER_MESSAGE_ATTRIBUTES",  spoolss_notify_attributes   },
45 { PRINTER_MESSAGE_COMMENT,     PRINTER_NOTIFY_COMMENT,        "PRINTER_MESSAGE_COMMENT",     spoolss_notify_comment      },
46 { PRINTER_MESSAGE_LOCATION,    PRINTER_NOTIFY_LOCATION,       "PRINTER_MESSAGE_LOCATION",    spoolss_notify_location     },
47 { PRINTER_MESSAGE_PRINTERNAME, PRINTER_NOTIFY_PRINTER_NAME,   "PRINTER_MESSAGE_PRINTERNAME", spoolss_notify_printer_name },
48 { PRINTER_MESSAGE_SHARENAME,   PRINTER_NOTIFY_SHARE_NAME,     "PRINTER_MESSAGE_SHARENAME",   spoolss_notify_share_name   },
49 { PRINTER_MESSAGE_PORT,        PRINTER_NOTIFY_PORT_NAME,      "PRINTER_MESSAGE_PORT",        spoolss_notify_port_name    },
50 { PRINTER_MESSAGE_CJOBS,       PRINTER_NOTIFY_CJOBS,          "PRINTER_MESSAGE_CJOBS",       spoolss_notify_cjobs        },
51 { PRINTER_MESSAGE_SEPFILE,     PRINTER_NOTIFY_SEPFILE,        "PRINTER_MESSAGE_SEPFILE",     spoolss_notify_sepfile      },
52 { PRINTER_MESSAGE_PARAMS,      PRINTER_NOTIFY_PARAMETERS,     "PRINTER_MESSAGE_PARAMETERS",  spoolss_notify_parameters   },
53 { PRINTER_MESSAGE_DATATYPE,    PRINTER_NOTIFY_DATATYPE,       "PRINTER_MESSAGE_DATATYPE",    spoolss_notify_datatype     },
54 { PRINTER_MESSAGE_NULL,        0x0,                           "",                            NULL                        },
55 };
56
57 /*********************************************************
58  Disconnect from the client machine.
59 **********************************************************/
60 BOOL spoolss_disconnect_from_client( struct cli_state *cli)
61 {
62         cli_nt_session_close(cli);
63         cli_ulogoff(cli);
64         cli_shutdown(cli);
65
66         return True;
67 }
68
69
70 /*********************************************************
71  Connect to the client machine.
72 **********************************************************/
73
74 BOOL spoolss_connect_to_client( struct cli_state *cli, char *remote_machine)
75 {
76         ZERO_STRUCTP(cli);
77         if(cli_initialise(cli) == NULL) {
78                 DEBUG(0,("connect_to_client: unable to initialize client connection.\n"));
79                 return False;
80         }
81
82         if(!resolve_name( remote_machine, &cli->dest_ip, 0x20)) {
83                 DEBUG(0,("connect_to_client: Can't resolve address for %s\n", remote_machine));
84                 cli_shutdown(cli);
85         return False;
86         }
87
88         if (ismyip(cli->dest_ip)) {
89                 DEBUG(0,("connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
90                 cli_shutdown(cli);
91                 return False;
92         }
93
94         if (!cli_connect(cli, remote_machine, &cli->dest_ip)) {
95                 DEBUG(0,("connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
96                 cli_shutdown(cli);
97                 return False;
98         }
99   
100         if (!attempt_netbios_session_request(cli, global_myname, remote_machine, &cli->dest_ip)) {
101                 DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request.\n", 
102                         remote_machine));
103                 return False;
104         }
105
106         cli->protocol = PROTOCOL_NT1;
107     
108         if (!cli_negprot(cli)) {
109                 DEBUG(0,("connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
110                 cli_shutdown(cli);
111                 return False;
112         }
113
114         if (cli->protocol != PROTOCOL_NT1) {
115                 DEBUG(0,("connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
116                 cli_shutdown(cli);
117                 return False;
118         }
119     
120         /*
121          * Do an anonymous session setup.
122          */
123     
124         if (!cli_session_setup(cli, "", "", 0, "", 0, "")) {
125                 DEBUG(0,("connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
126                 cli_shutdown(cli);
127                 return False;
128         }
129     
130         if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
131                 DEBUG(0,("connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
132                 cli_shutdown(cli);
133                 return False;
134         }
135     
136         if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
137                 DEBUG(0,("connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
138                 cli_shutdown(cli);
139                 return False;
140         }
141
142         /*
143          * Ok - we have an anonymous connection to the IPC$ share.
144          * Now start the NT Domain stuff :-).
145          */
146
147         if(cli_nt_session_open(cli, PIPE_SPOOLSS) == False) {
148                 DEBUG(0,("connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli)));
149                 cli_nt_session_close(cli);
150                 cli_ulogoff(cli);
151                 cli_shutdown(cli);
152                 return False;
153         } 
154
155         return True;
156 }
157
158 /*
159  * SPOOLSS Client RPC's used by servers as the notification
160  * back channel
161  */
162
163 /***************************************************************************
164  do a reply open printer
165 ****************************************************************************/
166
167 WERROR cli_spoolss_reply_open_printer(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
168                                 char *printer, uint32 localprinter, uint32 type, 
169                                 POLICY_HND *handle)
170 {
171         WERROR result = W_ERROR(ERRgeneral);
172         
173         prs_struct rbuf;
174         prs_struct buf; 
175
176         SPOOL_Q_REPLYOPENPRINTER q_s;
177         SPOOL_R_REPLYOPENPRINTER r_s;
178
179         prs_init(&buf, 1024, mem_ctx, MARSHALL);
180         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL );
181
182         /* create and send a MSRPC command with api SPOOLSS_REPLYOPENPRINTER */
183         
184         /* store the parameters */
185         make_spoolss_q_replyopenprinter(&q_s, printer, localprinter, type);
186
187         /* turn parameters into data stream */
188         if(!spoolss_io_q_replyopenprinter("", &q_s,  &buf, 0)) {
189                 DEBUG(0,("cli_spoolss_reply_open_printer: Error : failed to marshall SPOOL_Q_REPLYOPENPRINTER struct.\n"));
190                 goto done;
191         }
192
193         /* send the data on \PIPE\ */
194         if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYOPENPRINTER, &buf, &rbuf)) 
195                 goto done;
196
197         /* turn data stream into parameters*/
198         if(!spoolss_io_r_replyopenprinter("", &r_s, &rbuf, 0)) {
199                 DEBUG(0,("cli_spoolss_reply_open_printer: Error : failed to unmarshall SPOOL_R_REPLYOPENPRINTER struct.\n"));
200                 goto done;
201         }
202         
203         memcpy(handle, &r_s.handle, sizeof(r_s.handle));
204         result = r_s.status;
205
206 done:
207         prs_mem_free(&buf);
208         prs_mem_free(&rbuf);
209
210         return result;
211 }
212
213 /***************************************************************************
214  do a reply open printer
215 ****************************************************************************/
216
217 WERROR cli_spoolss_reply_close_printer(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
218                                         POLICY_HND *handle)
219 {
220         WERROR result = W_ERROR(ERRgeneral);
221         prs_struct rbuf;
222         prs_struct buf; 
223
224         SPOOL_Q_REPLYCLOSEPRINTER q_s;
225         SPOOL_R_REPLYCLOSEPRINTER r_s;
226
227         prs_init(&buf, 1024, cli->mem_ctx, MARSHALL);
228         prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
229
230         /* create and send a MSRPC command with api  */
231         
232         /* store the parameters */
233         make_spoolss_q_reply_closeprinter(&q_s, handle);
234
235         /* turn parameters into data stream */
236         if(!spoolss_io_q_replycloseprinter("", &q_s,  &buf, 0)) {
237                 DEBUG(0,("cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_Q_REPLY_CLOSEPRINTER struct.\n"));
238                 goto done;
239         }
240
241         /* send the data on \PIPE\ */
242         if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYCLOSEPRINTER, &buf, &rbuf))
243                 goto done;
244
245         /* turn data stream into parameters*/
246         if(!spoolss_io_r_replycloseprinter("", &r_s, &rbuf, 0)) {
247                 DEBUG(0,("cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_R_REPLY_CLOSEPRINTER struct.\n"));
248                 goto done;
249         }
250         
251
252         result = r_s.status;
253         
254 done:
255                 prs_mem_free(&buf);
256                 prs_mem_free(&rbuf);
257
258         return result;
259 }
260
261  
262 /*********************************************************************
263  This SPOOLSS_ROUTERREPLYPRINTER function is used to send a change 
264  notification event when the registration **did not** use 
265  SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor.
266  Also see cli_spolss_reply_rrpcn()
267  *********************************************************************/
268  
269 WERROR cli_spoolss_routerreplyprinter (struct cli_state *cli, TALLOC_CTX *mem_ctx,
270                                         POLICY_HND *pol, uint32 condition, uint32 changd_id)
271 {
272         prs_struct qbuf, rbuf;
273         SPOOL_Q_ROUTERREPLYPRINTER q;
274         SPOOL_R_ROUTERREPLYPRINTER r;
275         WERROR result = W_ERROR(ERRgeneral);
276
277         ZERO_STRUCT(q);
278         ZERO_STRUCT(r);
279
280
281         /* Initialise input parameters */
282
283         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
284         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
285
286
287         /* write the request */
288         make_spoolss_q_routerreplyprinter(&q, pol, condition, changd_id);
289
290         /* Marshall data and send request */
291         if (!spoolss_io_q_routerreplyprinter ("", &q, &qbuf, 0)) {
292                 DEBUG(0,("cli_spoolss_routerreplyprinter: Unable to marshall SPOOL_Q_ROUTERREPLYPRINTER!\n"));
293                 goto done;
294         }
295                 
296                 
297         if (!rpc_api_pipe_req (cli, SPOOLSS_ROUTERREPLYPRINTER, &qbuf, &rbuf)) 
298                 goto done;
299
300         /* Unmarshall response */
301         if (!spoolss_io_r_routerreplyprinter ("", &r, &rbuf, 0)) {
302                 DEBUG(0,("cli_spoolss_routerreplyprinter: Unable to unmarshall SPOOL_R_ROUTERREPLYPRINTER!\n"));
303                 goto done;
304         }
305
306         /* Return output parameters */
307         result = r.status;
308         
309 done:
310         prs_mem_free(&qbuf);
311                 prs_mem_free(&rbuf);
312
313         return result;  
314 }
315
316
317 /**********************************************************************************
318  Build the SPOOL_NOTIFY_INFO_DATA entries based upon the flags which have been set
319  *********************************************************************************/
320
321 static int build_notify_data (TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printer, uint32 flags, 
322                         SPOOL_NOTIFY_INFO_DATA **notify_data)
323 {
324         SPOOL_NOTIFY_INFO_DATA *data;
325         uint32 idx = 0;
326         int i = 0;
327         
328         while ((msg_table[i].msg != PRINTER_MESSAGE_NULL) && flags)
329         {
330                 if (flags & msg_table[i].msg) 
331                 {
332                         DEBUG(10,("build_notify_data: %s set on [%s][%d]\n", msg_table[i].name,
333                                 printer->info_2->printername, idx));
334                         if ((data=Realloc(*notify_data, (idx+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) {
335                                 DEBUG(0,("build_notify_data: Realloc() failed with size [%d]!\n",
336                                         (idx+1)*sizeof(SPOOL_NOTIFY_INFO_DATA)));
337                                 return -1;
338         }
339                         *notify_data = data;
340
341                         /* clear memory */
342                         memset(*notify_data+idx, 0x0, sizeof(SPOOL_NOTIFY_INFO_DATA));
343         
344                         /*
345                          * 'id' (last param here) is undefined when type == PRINTER_NOTIFY_TYPE
346                          * See PRINTER_NOTIFY_INFO_DATA entries in MSDN
347                          * --jerry
348                          */
349                         construct_info_data(*notify_data+idx, PRINTER_NOTIFY_TYPE, msg_table[i].field, 0x00);
350
351                         msg_table[i].construct_fn(-1, *notify_data+idx, NULL, printer, ctx);
352                         idx++;
353                 }
354
355                 i++;
356         }
357         
358         return idx;
359 }
360
361 /*********************************************************************
362  This SPOOLSS_ROUTERREPLYPRINTER function is used to send a change 
363  notification event when the registration **did** use 
364  SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor
365  Also see cli_spoolss_routereplyprinter()
366  *********************************************************************/
367
368 WERROR cli_spoolss_reply_rrpcn(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
369                                         POLICY_HND *handle, PRINTER_MESSAGE_INFO *info,
370                                         NT_PRINTER_INFO_LEVEL *printer)
371 {
372         prs_struct rbuf;
373         prs_struct buf; 
374
375         SPOOL_NOTIFY_INFO       notify_info;
376         SPOOL_NOTIFY_INFO_DATA  *notify_data = NULL;
377         uint32                  data_len;
378
379         WERROR result = W_ERROR(ERRgeneral);
380
381         SPOOL_Q_REPLY_RRPCN q_s;
382         SPOOL_R_REPLY_RRPCN r_s;
383
384         if (!info) {
385                 DEBUG(5,("cli_spoolss_reply_rrpcn: NULL printer message info pointer!\n"));
386                 goto done;
387         }
388                 
389         prs_init(&buf, 1024, mem_ctx, MARSHALL);
390         prs_init(&rbuf, 0,   mem_ctx, UNMARSHALL );
391
392         ZERO_STRUCT(notify_info);
393
394 /*
395          * See comments in _spoolss_setprinter() about PRINTER_CHANGE_XXX
396          * events.  --jerry
397 */
398         DEBUG(10,("cli_spoolss_reply_rrpcn: PRINTER_MESSAGE flags = 0x%8x\n", info->flags));
399
400         data_len = build_notify_data(mem_ctx, printer, info->flags, &notify_data);
401         if (info->flags && (data_len == -1)) {
402                 DEBUG(0,("cli_spoolss_reply_rrpcn: Failed to build SPOOL_NOTIFY_INFO_DATA [flags == 0x%x] for printer [%s]\n",
403                         info->flags, info->printer_name));
404                 result = WERR_NOMEM;
405                 goto done;
406         }
407         notify_info.version = 0x2;
408         notify_info.flags   = 0x00020000;       /* ?? */
409         notify_info.count   = data_len;
410         notify_info.data    = notify_data;
411
412         /* create and send a MSRPC command with api  */
413         /* store the parameters */
414
415         make_spoolss_q_reply_rrpcn(&q_s, handle, info->low, info->high, &notify_info);
416
417         /* turn parameters into data stream */
418         if(!spoolss_io_q_reply_rrpcn("", &q_s,  &buf, 0)) {
419                 DEBUG(0,("cli_spoolss_reply_rrpcn: Error : failed to marshall SPOOL_Q_REPLY_RRPCN struct.\n"));
420                 goto done;
421         }
422
423         /* send the data on \PIPE\ */
424         if (!rpc_api_pipe_req(cli, SPOOLSS_RRPCN, &buf, &rbuf)) 
425                 goto done;
426
427         
428         /* turn data stream into parameters*/
429         if(!spoolss_io_r_reply_rrpcn("", &r_s, &rbuf, 0)) {
430                 DEBUG(0,("cli_spoolss_reply_rrpcn: Error : failed to unmarshall SPOOL_R_REPLY_RRPCN struct.\n"));
431                 goto done;
432         }
433
434         if (r_s.unknown0 == 0x00080000) {
435                 DEBUG(8,("cli_spoolss_reply_rrpcn: I think the spooler resonded that the notification was ignored.\n"));
436         }
437         
438         result = r_s.status;
439
440 done:
441         prs_mem_free(&buf);
442         prs_mem_free(&rbuf);
443         /*
444          * The memory allocated in this array is talloc'd so we only need
445          * free the array here. JRA.
446          */
447         SAFE_FREE(notify_data);
448
449         return result;
450 }
451