diff options
Diffstat (limited to 'source/rpc_server/srv_spoolss_nt.c')
-rw-r--r-- | source/rpc_server/srv_spoolss_nt.c | 416 |
1 files changed, 184 insertions, 232 deletions
diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c index b5032536523..a3e96d03002 100644 --- a/source/rpc_server/srv_spoolss_nt.c +++ b/source/rpc_server/srv_spoolss_nt.c @@ -91,6 +91,10 @@ static ubi_dlList counter_list; static struct cli_state cli; static uint32 smb_connections=0; + +/* in printing/nt_printing.c */ +extern STANDARD_MAPPING printer_std_mapping; + #define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \ ((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid()) @@ -158,7 +162,7 @@ static void free_spool_notify_option(SPOOL_NOTIFY_OPTION **pp) static void srv_spoolss_replycloseprinter(POLICY_HND *handle) { - WERROR status; + NTSTATUS result; /* weird if the test succeds !!! */ if (smb_connections==0) { @@ -166,7 +170,9 @@ static void srv_spoolss_replycloseprinter(POLICY_HND *handle) return; } - if(!cli_spoolss_reply_close_printer(&cli, handle, &status)) + result = cli_spoolss_reply_close_printer(&cli, cli.mem_ctx, handle); + + if (!NT_STATUS_IS_OK(result)) DEBUG(0,("srv_spoolss_replycloseprinter: reply_close_printer failed.\n")); /* if it's the last connection, deconnect the IPC$ share */ @@ -529,160 +535,25 @@ static BOOL alloc_buffer_size(NEW_BUFFER *buffer, uint32 buffer_size) return True; } - -/********************************************************************************** - Build the SPOOL_NOTIFY_INFO_DATA entries based upon the flags which have been set - *********************************************************************************/ - -static int build_notify_data (TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printer, uint32 flags, - SPOOL_NOTIFY_INFO_DATA **notify_data) -{ - SPOOL_NOTIFY_INFO_DATA *data; - uint32 idx = 0; - - /* Changing the printer driver */ - - if (flags & PRINTER_MESSAGE_DRIVER) { - DEBUG(10,("build_notify_data: PRINTER_MESSAGE_DRIVER set on [%s][%d]\n", - printer->info_2->printername, idx)); - if ((data=Realloc(*notify_data, (idx+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) { - DEBUG(0,("build_notify_data: Realloc() failed with size [%d]!\n", - (idx+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))); - return -1; - } - *notify_data = data; - - /* clear memory */ - memset(*notify_data+idx, 0x0, sizeof(SPOOL_NOTIFY_INFO_DATA)); - - /* - * 'id' (last param here) is undefined when type == PRINTER_NOTIFY_TYPE - * See PRINTER_NOTIFY_INFO_DATA entries in MSDN - * --jerry - */ - construct_info_data(*notify_data+idx, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME, 0x00); - - spoolss_notify_driver_name(-1, *notify_data+idx, NULL, printer, ctx); - idx++; - } - - return idx; -} - /*************************************************************************** - Send a notify to the client. -****************************************************************************/ - -static BOOL cli_spoolss_reply_rrpcn(struct cli_state *pcli, POLICY_HND *handle, - PRINTER_MESSAGE_INFO *info, WERROR *status) + Always give preference Printer_entry.notify.option over + Printer_entry.notify.flags. Return True if we should send notification + events using SPOOLSS_RRPCN. False means that we should use + SPOOLSS_ROUTERREPLYPRINTER. + **************************************************************************/ +static BOOL valid_notify_options(Printer_entry *printer) { - prs_struct rbuf; - prs_struct buf; - - SPOOL_NOTIFY_INFO notify_info; - SPOOL_NOTIFY_INFO_DATA *notify_data = NULL; - uint32 data_len; - - WERROR result; - - NT_PRINTER_INFO_LEVEL *printer = NULL; - - SPOOL_Q_REPLY_RRPCN q_s; - SPOOL_R_REPLY_RRPCN r_s; - - if (!info) { - DEBUG(5,("cli_spoolss_reply_rrpcn: NULL printer message info pointer!\n")); + if (printer->notify.option == NULL) return False; - } - prs_init(&buf, 1024, pcli->mem_ctx, MARSHALL); - prs_init(&rbuf, 0, pcli->mem_ctx, UNMARSHALL ); - - ZERO_STRUCT(notify_info); - - /* lookup the printer if we have a name */ - - if (*(info->printer_name)) { - result = get_a_printer(&printer, 2, info->printer_name); - if (! W_ERROR_IS_OK(result)) { - *status = result; - goto done; - } - } - - /* - * See comments in _spoolss_setprinter() about PRINTER_CHANGE_XXX - * events. --jerry - */ - DEBUG(10,("cli_spoolss_reply_rrpcn: PRINTER_MESSAGE flags = 0x%8x\n", info->flags)); - - data_len = build_notify_data(pcli->mem_ctx, printer, info->flags, ¬ify_data); - if (info->flags && (data_len == -1)) { - DEBUG(0,("cli_spoolss_reply_rrpcn: Failed to build SPOOL_NOTIFY_INFO_DATA [flags == 0x%x] for printer [%s]\n", - info->flags, info->printer_name)); - *status = WERR_NOMEM; - goto done; - } - notify_info.version = 0x2; - notify_info.flags = 0x00020000; - notify_info.count = data_len; - notify_info.data = notify_data; - - -#if 0 /* JERRY -- do not delete */ - DEBUG(4,("cli_spoolss_reply_open_printer: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n", - pcli->srv_name_slash, pcli->mach_acct, sec_chan_type, global_myname, - credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time)); -#endif - - /* create and send a MSRPC command with api */ - /* store the parameters */ - - make_spoolss_q_reply_rrpcn(&q_s, handle, info->low, info->high, ¬ify_info); - - /* 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")); - *status = WERR_BADFUNC; - goto done; - } - - /* send the data on \PIPE\ */ - if (!rpc_api_pipe_req(pcli, SPOOLSS_RRPCN, &buf, &rbuf)) { - DEBUG(0,("cli_spoolss_reply_rrpcn: SPOOLSS_RRPCN failed!\n")); - *status = WERR_BADFUNC; - goto done; - } - - - /* turn data stream into parameters*/ - if(!spoolss_io_r_reply_rrpcn("", &r_s, &rbuf, 0)) { - DEBUG(0,("cli_spoolss_reply_rrpcn: Error : failed to unmarshall SPOOL_R_REPLY_RRPCN struct.\n")); - *status = WERR_BADFUNC; - goto done; - } - - *status = r_s.status; - -done: - prs_mem_free(&buf); - prs_mem_free(&rbuf); - free_a_printer(&printer, 2); - /* - * The memory allocated in this array is talloc'd so we only need - * free the array here. JRA. - */ - SAFE_FREE(notify_data); - - if (!W_ERROR_IS_OK(*status)) - DEBUG(5,("cli_spoolss_reply_rrpcn: %s\n", get_dos_error_msg(*status))); - - return W_ERROR_IS_OK(*status); + return True; } /*************************************************************************** Simple check to see if the client motify handle is set to watch for events represented by 'flags' + + FIXME!!!! only a stub right now --jerry **************************************************************************/ static BOOL is_client_monitoring_event(Printer_entry *p, uint32 flags) @@ -692,69 +563,177 @@ static BOOL is_client_monitoring_event(Printer_entry *p, uint32 flags) } /*************************************************************************** - Receive the notify message. -****************************************************************************/ - -static void srv_spoolss_receive_message(int msg_type, pid_t src, void *buf, size_t len) + Server wrapper for cli_spoolss_routerreplyprinter() since the client + function can only send a single change notification at a time. + + FIXME!!! only handles one change currently (PRINTER_CHANGE_SET_PRINTER_DRIVER) + --jerry + **************************************************************************/ + +static NTSTATUS srv_spoolss_routerreplyprinter (struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *pol, PRINTER_MESSAGE_INFO *info, + NT_PRINTER_INFO_LEVEL *printer) { - PRINTER_MESSAGE_INFO msg; - Printer_entry *find_printer; - WERROR status; + NTSTATUS result; + uint32 condition = 0x0; + + if (info->flags & PRINTER_MESSAGE_DRIVER) + condition = PRINTER_CHANGE_SET_PRINTER_DRIVER; + + result = cli_spoolss_routerreplyprinter(cli, mem_ctx, pol, condition, + printer->info_2->changeid); - if (len < sizeof(msg)) { - DEBUG(2,("srv_spoolss_receive_message: got incorrect message size (%u)!\n", (unsigned int)len)); - return; + return result; +} + +/*********************************************************************** + Wrapper around the decision of which RPC use to in the change + notification + **********************************************************************/ + +static NTSTATUS srv_spoolss_send_event_to_client(Printer_entry* Printer, + struct cli_state *cli, PRINTER_MESSAGE_INFO *msg, + NT_PRINTER_INFO_LEVEL *info) +{ + NTSTATUS result; + + if (valid_notify_options(Printer)) { + /* This is a single call that can send information about multiple changes */ + result = cli_spoolss_reply_rrpcn(cli, cli->mem_ctx, &Printer->notify.client_hnd, + msg, info); + } + else { + /* This requires that the server send an individual event notification for each change */ + result = srv_spoolss_routerreplyprinter(cli, cli->mem_ctx, &Printer->notify.client_hnd, + msg, info); } + + return result; +} - memcpy(&msg, buf, sizeof(PRINTER_MESSAGE_INFO)); - DEBUG(10,("srv_spoolss_receive_message: Got message printer change [queue = %s] low=0x%x high=0x%x flags=0x%x\n", - msg.printer_name, (unsigned int)msg.low, (unsigned int)msg.high, msg.flags )); +/*********************************************************************** + Send a change notication message on all handles which have a call + back registered + **********************************************************************/ - /* Iterate the printer list */ - for(find_printer = printers_list; find_printer; find_printer = find_printer->next) { +static void send_spoolss_event_notification(PRINTER_MESSAGE_INFO *msg) +{ + Printer_entry *find_printer; + NTSTATUS result; + WERROR wresult; + NT_PRINTER_INFO_LEVEL *printer = NULL; + + if (!msg) { + DEBUG(0,("send_spoolss_event_notification: NULL msg pointer!\n")); + return; + } + + for (find_printer = printers_list; find_printer; find_printer = find_printer->next) { /* - * If the entry has a connected client we send the message. + * If the entry has a connected client we send the message. There should + * only be one of these normally when dealing with the NT/2k spooler. + * However, iterate over all to make sure we deal with user applications + * in addition to spooler service. + * + * While we are only maintaining a single connection to the client, + * the FindFirstPrinterChangeNotification() call is made on a printer + * handle, so "client_connected" represents the whether or not the + * client asked for change notication on this handle. + * + * --jerry */ if (find_printer->notify.client_connected==True) { /* does the client care about what changed? */ - if (msg.flags && !is_client_monitoring_event(find_printer, msg.flags)) { - DEBUG(10,("srv_spoolss_receive_message: Client [%s] not monitoring these events\n", + if (msg->flags && !is_client_monitoring_event(find_printer, msg->flags)) { + DEBUG(10,("send_spoolss_event_notification: Client [%s] not monitoring these events\n", find_printer->client.machine)); continue; } if (find_printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) - DEBUG(10,("srv_spoolss_receive_message: printserver [%s]\n", find_printer->dev.printerservername )); + DEBUG(10,("send_spoolss_event_notification: printserver [%s]\n", find_printer->dev.printerservername )); else - DEBUG(10,("srv_spoolss_receive_message: printer [%s]\n", find_printer->dev.handlename)); + DEBUG(10,("send_spoolss_event_notification: printer [%s]\n", find_printer->dev.handlename)); /* * if handle is a printer, only send if the printer_name matches. * ...else if handle is a printerserver, send to all */ - if (*msg.printer_name && (find_printer->printer_type==PRINTER_HANDLE_IS_PRINTER) - && !strequal(msg.printer_name, find_printer->dev.handlename)) + if (*msg->printer_name && (find_printer->printer_type==PRINTER_HANDLE_IS_PRINTER) + && !strequal(msg->printer_name, find_printer->dev.handlename)) { - DEBUG(10,("srv_spoolss_receive_message: ignoring message sent to %s [%s]\n", - msg.printer_name, find_printer->dev.handlename )); + DEBUG(10,("send_spoolss_event_notification: ignoring message sent to %s [%s]\n", + msg->printer_name, find_printer->dev.handlename )); continue; } + + /* lookup the printer if we have a name if we don't already have a + valid NT_PRINTER_INFO_LEVEL structure. And yes I'm assuming we + will always have a non-empty msg.printer_name */ + + if (!printer || !printer->info_2 || strcmp(msg->printer_name, printer->info_2->printername)) + { + + if (printer) { + free_a_printer(&printer, 2); + printer = NULL; + } + + wresult = get_a_printer(&printer, 2, msg->printer_name); + if (! W_ERROR_IS_OK(wresult)) + continue; + } + /* issue the client call */ - if (cli_spoolss_reply_rrpcn(&cli, &find_printer->notify.client_hnd, &msg, &status)) - DEBUG(10,("srv_spoolss_receive_message: cli_spoolss_reply_rrpcn status = 0x%x\n", - (unsigned int)W_ERROR_V(status))); - else - DEBUG(10,("srv_spoolss_receive_message: cli_spoolss_reply_rrpcn failed\n")); + result = srv_spoolss_send_event_to_client(find_printer, &cli, msg, printer); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("send_spoolss_event_notification: Event notification failed [%s]\n", + get_nt_error_msg(result))); + } } } + + return; +} +/*************************************************************************** + Receive the notify message and decode the message. Do not send + notification if we sent this originally as that would result in + duplicates. +****************************************************************************/ + +static void srv_spoolss_receive_message(int msg_type, pid_t src, void *buf, size_t len) +{ + PRINTER_MESSAGE_INFO msg; + pid_t my_pid = sys_getpid(); + + if (len < sizeof(msg)) { + DEBUG(2,("srv_spoolss_receive_message: got incorrect message size (%u)!\n", (unsigned int)len)); + return; + } + + memcpy(&msg, buf, sizeof(PRINTER_MESSAGE_INFO)); + + if (my_pid == src) { + DEBUG(10,("srv_spoolss_receive_message: Skipping message to myself\n")); + return; + } + + DEBUG(10,("srv_spoolss_receive_message: Got message printer change [queue = %s] low=0x%x high=0x%x flags=0x%x\n", + msg.printer_name, (unsigned int)msg.low, (unsigned int)msg.high, msg.flags )); + + /* Iterate the printer list */ + + send_spoolss_event_notification(&msg); + } /*************************************************************************** @@ -772,7 +751,7 @@ static BOOL srv_spoolss_sendnotify(char* printer_name, uint32 high, uint32 low, info.high = high; info.flags = flags; fstrcpy(info.printer_name, printer_name); - + memcpy(msg, &info, sizeof(PRINTER_MESSAGE_INFO)); DEBUG(10,("srv_spoolss_sendnotify: printer change low=0x%x high=0x%x [%s], flags=0x%x\n", @@ -895,6 +874,8 @@ Can't find printer handle we created for priunter %s\n", name )); if (!get_printer_snum(p, handle, &snum)) return WERR_BADFID; + se_map_standard(&printer_default->access_required, &printer_std_mapping); + /* map an empty access mask to the minimum access mask */ if (printer_default->access_required == 0x0) printer_default->access_required = PRINTER_ACCESS_USE; @@ -1482,7 +1463,7 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uint32 type, POLICY_HND *handle) { - WERROR status; + NTSTATUS result; /* * If it's the first connection, contact the client @@ -1502,10 +1483,10 @@ static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uin smb_connections++; - if(!cli_spoolss_reply_open_printer(&cli, printer, localprinter, type, &status, handle)) - return False; + result = cli_spoolss_reply_open_printer(&cli, cli.mem_ctx, printer, localprinter, + type, handle); - return True; + return (NT_STATUS_IS_OK(result)); } /******************************************************************** @@ -1552,8 +1533,10 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE /* 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_hnd)) + { Printer->notify.client_connected=True; + } return WERR_OK; } @@ -2595,7 +2578,7 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY return WERR_BADFID; option=Printer->notify.option; - id=0xffffffff; + id = 0x0; info->version=2; info->data=NULL; info->count=0; @@ -4899,6 +4882,7 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level, int snum; NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL; Printer_entry *Printer = find_printer_index_by_hnd(p, handle); + PRINTER_MESSAGE_INFO msg; WERROR result; uint32 change_flag = 0x0; @@ -5024,13 +5008,13 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level, /* Update printer info */ result = mod_a_printer(*printer, 2); - + /* flag which changes actually occured. This is a small subset of all the possible changes */ if (!strequal(printer->info_2->comment, old_printer->info_2->comment)) change_flag |= PRINTER_MESSAGE_COMMENT; - + if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename)) change_flag |= PRINTER_MESSAGE_SHARENAME; @@ -5040,15 +5024,20 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level, if (!strequal(printer->info_2->location, old_printer->info_2->location)) change_flag |= PRINTER_MESSAGE_LOCATION; - /* - * It appears that if the PrinterName had changed, we should - * set this to PRINTER_CHANGE_ADD_PRINTER. This was observed - * between 2k -> 2k. Otherwise a PRINTER_CHANGE_SET_PRINTER - * event is ok. --jerry - */ - - srv_spoolss_sendnotify(printer->info_2->printername, 0, PRINTER_CHANGE_SET_PRINTER, - change_flag); + if (!(change_flag & PRINTER_MESSAGE_DRIVER)) + goto done; + + ZERO_STRUCT(msg); + + msg.low = PRINTER_CHANGE_ADD_PRINTER; + fstrcpy(msg.printer_name, printer->info_2->printername); + msg.flags = change_flag; + + /* send to myself before replying to SetPrinter() */ + send_spoolss_event_notification(&msg); + + /* send to other smbd's */ + srv_spoolss_sendnotify(printer->info_2->printername, 0, PRINTER_CHANGE_ADD_PRINTER, change_flag); done: free_a_printer(&printer, 2); @@ -6371,9 +6360,7 @@ static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environmen pstring long_archi; pstring short_archi; DRIVER_DIRECTORY_1 *info=NULL; -#if 0 - fstring asc_name, servername; -#endif + unistr2_to_ascii(long_archi, uni_environment, sizeof(long_archi)-1); if (get_short_archi(short_archi, long_archi)==False) @@ -6382,20 +6369,6 @@ static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environmen if((info=(DRIVER_DIRECTORY_1 *)malloc(sizeof(DRIVER_DIRECTORY_1))) == NULL) return WERR_NOMEM; -#if 0 /* JERRY */ - /* use the name the client sent us */ - - unistr2_to_ascii(asc_name, name, sizeof(asc_name)-1); - if (asc_name[0] == '\\' && asc_name[1] == '\\') - fstrcpy(servername, asc_name); - else { - fstrcpy(servername, "\\\\"); - fstrcat(servername, asc_name); - } - - slprintf(path, sizeof(path)-1, "%s\\print$\\%s", servername, short_archi); -#endif - slprintf(path, sizeof(path)-1, "\\\\%s\\print$\\%s", get_called_name(), short_archi); DEBUG(4,("printer driver directory: [%s]\n", path)); @@ -7582,27 +7555,6 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_ enum_values[num_entries].value_len = (strlen(value)+1) * 2; enum_values[num_entries].type = type; -#if 0 /* JERRY - I think think was a bad assumption based on bad - offset values when I first implemented it. Commented out. - We should not be adding an extra NULL to the end of a string - just send what the client set in the first place. */ - /* - * NULL terminate REG_SZ - * FIXME!!! We should not be correctly problems in the way - * we store PrinterData here. Need to investogate - * SetPrinterData[Ex] --jerry - */ - - if (type == REG_SZ) { - /* fix alignment if the string was stored - in a bizarre fashion */ - if ((data_len % 2) == 0) - add_len = 2; - else - add_len = data_len % 2; - } -#endif - if (!(enum_values[num_entries].data=talloc_zero(p->mem_ctx, data_len+add_len))) { DEBUG(0,("talloc_realloc failed to allocate more memory for data!\n")); result = WERR_NOMEM; |