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