diff options
Diffstat (limited to 'source3/rpc_server/srv_spoolss_nt.c')
-rw-r--r-- | source3/rpc_server/srv_spoolss_nt.c | 1898 |
1 files changed, 687 insertions, 1211 deletions
diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 2190215107..7aceaa548f 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -4,7 +4,7 @@ * Copyright (C) Andrew Tridgell 1992-2000, * Copyright (C) Luke Kenneth Casson Leighton 1996-2000, * Copyright (C) Jean François Micouleau 1998-2000, - * Copyright (C) Jeremy Allison 2001-2002, + * Copyright (C) Jeremy Allison 2001, * Copyright (C) Gerald Carter 2000-2002, * Copyright (C) Tim Potter 2001-2002. * @@ -87,10 +87,6 @@ typedef struct _Printer{ fstring machine; fstring user; } client; - - /* devmode sent in the OpenPrinter() call */ - NT_DEVICEMODE *nt_devmode; - } Printer_entry; static Printer_entry *printers_list; @@ -200,11 +196,6 @@ static void srv_spoolss_replycloseprinter(POLICY_HND *handle) cli_ulogoff(¬ify_cli); cli_shutdown(¬ify_cli); message_deregister(MSG_PRINTER_NOTIFY2); - - /* Tell the connections db we're no longer interested in - * printer notify messages. */ - - register_message_flags( False, FLAG_MSG_PRINTING ); } smb_connections--; @@ -228,8 +219,6 @@ static void free_printer_entry(void *ptr) free_spool_notify_option(&Printer->notify.option); Printer->notify.option=NULL; Printer->notify.client_connected=False; - - free_nt_devicemode( &Printer->nt_devmode ); /* Remove from the internal list. */ DLIST_REMOVE(printers_list, Printer); @@ -577,14 +566,7 @@ static BOOL is_monitoring_event(Printer_entry *p, uint16 notify_type, { SPOOL_NOTIFY_OPTION *option = p->notify.option; uint32 i, j; - - /* - * Flags should always be zero when the change notify - * is registered by the cliebnt's spooler. A user Win32 app - * might use the flags though instead of the NOTIFY_OPTION_INFO - * --jerry - */ - + if (p->notify.flags) return is_monitoring_event_flags( p->notify.flags, notify_type, notify_field); @@ -734,177 +716,26 @@ static struct notify2_message_table job_notify_table[] = { /* 0x17 */ { "JOB_NOTIFY_BYTES_PRINTED", NULL }, }; - -/*********************************************************************** - Allocate talloc context for container object - **********************************************************************/ - -static void notify_msg_ctr_init( SPOOLSS_NOTIFY_MSG_CTR *ctr ) -{ - if ( !ctr ) - return; - - ctr->ctx = talloc_init(); - - return; -} - -/*********************************************************************** - release all allocated memory and zero out structure - **********************************************************************/ - -static void notify_msg_ctr_destroy( SPOOLSS_NOTIFY_MSG_CTR *ctr ) -{ - if ( !ctr ) - return; - - if ( ctr->ctx ) - talloc_destroy(ctr->ctx); - - ZERO_STRUCTP(ctr); - - return; -} - -/*********************************************************************** - **********************************************************************/ - -static TALLOC_CTX* notify_ctr_getctx( SPOOLSS_NOTIFY_MSG_CTR *ctr ) -{ - if ( !ctr ) - return NULL; - - return ctr->ctx; -} - -/*********************************************************************** - **********************************************************************/ - -static SPOOLSS_NOTIFY_MSG_GROUP* notify_ctr_getgroup( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx ) -{ - if ( !ctr || !ctr->msg_groups ) - return NULL; - - if ( idx >= ctr->num_groups ) - return NULL; - - return &ctr->msg_groups[idx]; - -} - -/*********************************************************************** - How many groups of change messages do we have ? - **********************************************************************/ - -static int notify_msg_ctr_numgroups( SPOOLSS_NOTIFY_MSG_CTR *ctr ) -{ - if ( !ctr ) - return 0; - - return ctr->num_groups; -} - -/*********************************************************************** - Add a SPOOLSS_NOTIFY_MSG_CTR to the correct group - **********************************************************************/ - -static int notify_msg_ctr_addmsg( SPOOLSS_NOTIFY_MSG_CTR *ctr, SPOOLSS_NOTIFY_MSG *msg ) -{ - SPOOLSS_NOTIFY_MSG_GROUP *groups = NULL; - SPOOLSS_NOTIFY_MSG_GROUP *msg_grp = NULL; - SPOOLSS_NOTIFY_MSG *msg_list = NULL; - int i, new_slot; - - if ( !ctr || !msg ) - return 0; - - /* loop over all groups looking for a matching printer name */ - - for ( i=0; i<ctr->num_groups; i++ ) { - if ( strcmp(ctr->msg_groups[i].printername, msg->printer) == 0 ) - break; - } - - /* add a new group? */ - - if ( i == ctr->num_groups ) - { - ctr->num_groups++; - - if ( !(groups = talloc_realloc( ctr->ctx, ctr->msg_groups, sizeof(SPOOLSS_NOTIFY_MSG_GROUP)*ctr->num_groups)) ) { - DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed!\n")); - return 0; - } - ctr->msg_groups = groups; - - /* clear the new entry and set the printer name */ - - ZERO_STRUCT( ctr->msg_groups[ctr->num_groups-1] ); - fstrcpy( ctr->msg_groups[ctr->num_groups-1].printername, msg->printer ); - } - - /* add the change messages; 'i' is the correct index now regardless */ - - msg_grp = &ctr->msg_groups[i]; - - msg_grp->num_msgs++; - - if ( !(msg_list = talloc_realloc( ctr->ctx, msg_grp->msgs, sizeof(SPOOLSS_NOTIFY_MSG)*msg_grp->num_msgs )) ) { - DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed for new message [%d]!\n", msg_grp->num_msgs)); - return 0; - } - msg_grp->msgs = msg_list; - - new_slot = msg_grp->num_msgs-1; - memcpy( &msg_grp->msgs[new_slot], msg, sizeof(SPOOLSS_NOTIFY_MSG) ); - - /* need to allocate own copy of data */ - - if ( msg->len != 0 ) - msg_grp->msgs[new_slot].notify.data = talloc_memdup( ctr->ctx, msg->notify.data, msg->len ); - - return ctr->num_groups; -} - /*********************************************************************** Send a change notication message on all handles which have a call back registered **********************************************************************/ -static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx ) +static void process_notify2_message(struct spoolss_notify_msg *msg, + TALLOC_CTX *mem_ctx) { - Printer_entry *p; - TALLOC_CTX *mem_ctx = notify_ctr_getctx( ctr ); - SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, idx ); - SPOOLSS_NOTIFY_MSG *messages; - - - if ( !msg_group ) { - DEBUG(5,("send_notify2_changes() called with no msg group!\n")); - return; - } - - messages = msg_group->msgs; - - if ( !messages ) { - DEBUG(5,("send_notify2_changes() called with no messages!\n")); - return; - } - - DEBUG(8,("send_notify2_changes: Enter...[%s]\n", msg_group->printername)); - - /* loop over all printers */ + Printer_entry *p; + + DEBUG(8,("process_notify2_message: Enter...[%s]\n", msg->printer)); - for (p = printers_list; p; p = p->next) - { + for (p = printers_list; p; p = p->next) { SPOOL_NOTIFY_INFO_DATA *data; - uint32 data_len = 0; - uint32 id; - int i; + uint32 data_len = 1; + uint32 id; /* Is there notification on this handle? */ - if ( !p->notify.client_connected ) + if (!p->notify.client_connected) continue; DEBUG(10,("Client connected! [%s]\n", p->dev.handlename)); @@ -913,31 +744,25 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx ) notifications. */ if ( ( p->printer_type == PRINTER_HANDLE_IS_PRINTER ) && - ( !strequal(msg_group->printername, p->dev.handlename) ) ) + ( !strequal(msg->printer, p->dev.handlename) ) ) continue; DEBUG(10,("Our printer\n")); - /* allocate the max entries possible */ - - data = talloc( mem_ctx, msg_group->num_msgs*sizeof(SPOOL_NOTIFY_INFO_DATA) ); - ZERO_STRUCTP(data); - - /* build the array of change notifications */ - - for ( i=0; i<msg_group->num_msgs; i++ ) - { - SPOOLSS_NOTIFY_MSG *msg = &messages[i]; - /* Are we monitoring this event? */ if (!is_monitoring_event(p, msg->type, msg->field)) continue; - DEBUG(10,("process_notify2_message: Sending message type [%x] field [%x] for printer [%s]\n", msg->type, msg->field, p->dev.handlename)); + /* OK - send the event to the client */ + + data = talloc(mem_ctx, sizeof(SPOOL_NOTIFY_INFO_DATA)); + + ZERO_STRUCTP(data); + /* * if the is a printer notification handle and not a job notification * type, then set the id to 0. Other wise just use what was specified @@ -959,8 +784,8 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx ) /* Convert unix jobid to smb jobid */ - if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) - { + if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) { + id = sysjob_to_jobid(msg->id); if (id == -1) { @@ -969,20 +794,22 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx ) } } - construct_info_data( &data[data_len], msg->type, msg->field, id ); + construct_info_data(data, msg->type, msg->field, id); switch(msg->type) { case PRINTER_NOTIFY_TYPE: if ( !printer_notify_table[msg->field].fn ) goto done; - printer_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx); + + printer_notify_table[msg->field].fn(msg, data, mem_ctx); break; case JOB_NOTIFY_TYPE: if ( !job_notify_table[msg->field].fn ) goto done; - job_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx); + + job_notify_table[msg->field].fn(msg, data, mem_ctx); break; @@ -991,139 +818,59 @@ static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 idx ) goto done; } - data_len++; - } - cli_spoolss_rrpcn( ¬ify_cli, mem_ctx, &p->notify.client_hnd, data_len, data, p->notify.change, 0 ); } - done: - DEBUG(8,("send_notify2_changes: Exit...\n")); + DEBUG(8,("process_notify2_message: Exit...\n")); return; } -/*********************************************************************** - **********************************************************************/ +/* Receive a notify2 message */ -static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, void *buf, size_t len ) +static void receive_notify2_message(int msg_type, pid_t src, void *buf, + size_t len) { - + struct spoolss_notify_msg msg; int offset = 0; + TALLOC_CTX *mem_ctx = talloc_init(); /* Unpack message */ + ZERO_STRUCT(msg); + offset += tdb_unpack((char *)buf + offset, len - offset, "f", - msg->printer); + msg.printer); offset += tdb_unpack((char *)buf + offset, len - offset, "ddddd", - &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags); + &msg.type, &msg.field, &msg.id, &msg.len, &msg.flags); - if (msg->len == 0) + if (msg.len == 0) tdb_unpack((char *)buf + offset, len - offset, "dd", - &msg->notify.value[0], &msg->notify.value[1]); + &msg.notify.value[0], &msg.notify.value[1]); else tdb_unpack((char *)buf + offset, len - offset, "B", - &msg->len, &msg->notify.data); + &msg.len, &msg.notify.data); - DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message, type %d, field 0x%02x, flags 0x%04x\n", - msg->type, msg->field, msg->flags)); + DEBUG(3, ("got NOTIFY2 message, type %d, field 0x%02x, flags 0x%04x\n", + msg.type, msg.field, msg.flags)); - if (msg->len == 0) - DEBUG(3, ("notify2_unpack_msg: value1 = %d, value2 = %d\n", msg->notify.value[0], - msg->notify.value[1])); + if (msg.len == 0) + DEBUG(3, ("value1 = %d, value2 = %d\n", msg.notify.value[0], + msg.notify.value[1])); else - dump_data(3, msg->notify.data, msg->len); - - return True; -} - -/******************************************************************** - Receive a notify2 message list - ********************************************************************/ - -static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, size_t len) -{ - size_t msg_count, i; - char *buf = (char *)msg; - char *msg_ptr; - size_t msg_len; - SPOOLSS_NOTIFY_MSG notify; - SPOOLSS_NOTIFY_MSG_CTR messages; - int num_groups; - - if (len < 4) { - DEBUG(0,("receive_notify2_message_list: bad message format (len < 4)!\n")); - return; - } - - msg_count = IVAL(buf, 0); - msg_ptr = buf + 4; + dump_data(3, msg.notify.data, msg.len); - DEBUG(5, ("receive_notify2_message_list: got %d messages in list\n", msg_count)); + /* Process message */ - if (msg_count == 0) { - DEBUG(0,("receive_notify2_message_list: bad message format (msg_count == 0) !\n")); - return; - } + process_notify2_message(&msg, mem_ctx); - /* initialize the container */ - - ZERO_STRUCT( messages ); - notify_msg_ctr_init( &messages ); - - /* - * build message groups for each printer identified - * in a change_notify msg. Remember that a PCN message - * includes the handle returned for the srv_spoolss_replyopenprinter() - * call. Therefore messages are grouped according to printer handle. - */ - - for ( i=0; i<msg_count; i++ ) - { - if (msg_ptr + 4 - buf > len) { - DEBUG(0,("receive_notify2_message_list: bad message format (len > buf_size) !\n")); - return; - } + /* Free message */ - msg_len = IVAL(msg_ptr,0); - msg_ptr += 4; + if (msg.len > 0) + free(msg.notify.data); - if (msg_ptr + msg_len - buf > len) { - DEBUG(0,("receive_notify2_message_list: bad message format (bad len) !\n")); - return; - } - - /* unpack messages */ - - ZERO_STRUCT( notify ); - notify2_unpack_msg( ¬ify, msg_ptr, msg_len ); - msg_ptr += msg_len; - - /* add to correct list in container */ - - notify_msg_ctr_addmsg( &messages, ¬ify ); - - /* free memory that might have been allocated by notify2_unpack_msg() */ - - if ( notify.len != 0 ) - SAFE_FREE( notify.notify.data ); - } - - /* process each group of messages */ - - num_groups = notify_msg_ctr_numgroups( &messages ); - for ( i=0; i<num_groups; i++ ) - send_notify2_changes( &messages, i ); - - - /* cleanup */ - - DEBUG(10,("receive_notify2_message_list: processed %u messages\n", (uint32)msg_count )); - - notify_msg_ctr_destroy( &messages ); - - return; + talloc_destroy(mem_ctx); } /******************************************************************** @@ -1396,65 +1143,14 @@ WERROR _spoolss_open_printer(pipes_struct *p, SPOOL_Q_OPEN_PRINTER *q_u, SPOOL_R /******************************************************************** * spoolss_open_printer * - * If the openprinterex rpc call contains a devmode, - * it's a per-user one. This per-user devmode is derivated - * from the global devmode. Openprinterex() contains a per-user - * devmode for when you do EMF printing and spooling. - * In the EMF case, the NT workstation is only doing half the job - * of rendering the page. The other half is done by running the printer - * driver on the server. - * The EMF file doesn't contain the page description (paper size, orientation, ...). - * The EMF file only contains what is to be printed on the page. - * So in order for the server to know how to print, the NT client sends - * a devicemode attached to the openprinterex call. - * But this devicemode is short lived, it's only valid for the current print job. - * - * If Samba would have supported EMF spooling, this devicemode would - * have been attached to the handle, to sent it to the driver to correctly - * rasterize the EMF file. - * - * As Samba only supports RAW spooling, we only receive a ready-to-print file, - * we just act as a pass-thru between windows and the printer. - * - * In order to know that Samba supports only RAW spooling, NT has to call - * getprinter() at level 2 (attribute field) or NT has to call startdoc() - * and until NT sends a RAW job, we refuse it. - * - * But to call getprinter() or startdoc(), you first need a valid handle, - * and to get an handle you have to call openprintex(). Hence why you have - * a devicemode in the openprinterex() call. - * - * - * Differences between NT4 and NT 2000. - * NT4: - * --- - * On NT4, you only have a global devicemode. This global devicemode can be changed - * by the administrator (or by a user with enough privs). Everytime a user - * wants to print, the devicemode is resetted to the default. In Word, everytime - * you print, the printer's characteristics are always reset to the global devicemode. - * - * NT 2000: - * ------- - * In W2K, there is the notion of per-user devicemode. The first time you use - * a printer, a per-user devicemode is build from the global devicemode. - * If you change your per-user devicemode, it is saved in the registry, under the - * H_KEY_CURRENT_KEY sub_tree. So that everytime you print, you have your default - * printer preferences available. - * - * To change the per-user devicemode: it's the "Printing Preferences ..." button - * on the General Tab of the printer properties windows. - * - * To change the global devicemode: it's the "Printing Defaults..." button - * on the Advanced Tab of the printer properties window. - * - * JFM. + * called from the spoolss dispatcher ********************************************************************/ WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u) { - UNISTR2 *printername = NULL; - PRINTER_DEFAULT *printer_default = &q_u->printer_default; - POLICY_HND *handle = &r_u->handle; + UNISTR2 *printername = NULL; + PRINTER_DEFAULT *printer_default = &q_u->printer_default; + POLICY_HND *handle = &r_u->handle; fstring name; int snum; @@ -1484,36 +1180,39 @@ Can't find printer handle we created for printer %s\n", name )); return WERR_INVALID_PRINTER_NAME; } + /* + First case: the user is opening the print server: + + Disallow MS AddPrinterWizard if parameter disables it. A Win2k + client 1st tries an OpenPrinterEx with access==0, MUST be allowed. + + Then both Win2k and WinNT clients try an OpenPrinterEx with + SERVER_ALL_ACCESS, which we allow only if the user is root (uid=0) + or if the user is listed in the smb.conf printer admin parameter. + + Then they try OpenPrinterEx with SERVER_READ which we allow. This lets the + client view printer folder, but does not show the MSAPW. + + Note: this test needs code to check access rights here too. Jeremy + could you look at this? + + + Second case: the user is opening a printer: + NT doesn't let us connect to a printer if the connecting user + doesn't have print permission. + + */ + get_current_user(&user, p); - /* - * First case: the user is opening the print server: - * - * Disallow MS AddPrinterWizard if parameter disables it. A Win2k - * client 1st tries an OpenPrinterEx with access==0, MUST be allowed. - * - * Then both Win2k and WinNT clients try an OpenPrinterEx with - * SERVER_ALL_ACCESS, which we allow only if the user is root (uid=0) - * or if the user is listed in the smb.conf printer admin parameter. - * - * Then they try OpenPrinterEx with SERVER_READ which we allow. This lets the - * client view printer folder, but does not show the MSAPW. - * - * Note: this test needs code to check access rights here too. Jeremy - * could you look at this? - * - * Second case: the user is opening a printer: - * NT doesn't let us connect to a printer if the connecting user - * doesn't have print permission. - */ + if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) { - if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) - { /* Printserver handles use global struct... */ snum = -1; - /* Map standard access rights to object specific access rights */ + /* Map standard access rights to object specific access + rights */ se_map_standard(&printer_default->access_required, &printserver_std_mapping); @@ -1532,32 +1231,23 @@ Can't find printer handle we created for printer %s\n", name )); /* Allow admin access */ - if ( printer_default->access_required & SERVER_ACCESS_ADMINISTER ) - { + if (printer_default->access_required & + SERVER_ACCESS_ADMINISTER) { + if (!lp_ms_add_printer_wizard()) { close_printer_handle(p, handle); return WERR_ACCESS_DENIED; } - /* if the user is not root and not a printer admin, then fail */ - - if ( user.uid != 0 - && !user_in_list(uidtoname(user.uid), lp_printer_admin(snum)) ) - { - close_printer_handle(p, handle); - return WERR_ACCESS_DENIED; - } + if (user.uid == 0 || + user_in_list(uidtoname(user.uid), + lp_printer_admin(snum))) + return WERR_OK; - printer_default->access_required = SERVER_ACCESS_ADMINISTER; - } - else - { - printer_default->access_required = SERVER_ACCESS_ENUMERATE; + close_printer_handle(p, handle); + return WERR_ACCESS_DENIED; } - DEBUG(4,("Setting print server access = %s\n", (printer_default->access_required == SERVER_ACCESS_ADMINISTER) - ? "SERVER_ACCESS_ADMINISTER" : "SERVER_ACCESS_ENUMERATE" )); - /* We fall through to return WERR_OK */ } @@ -1606,24 +1296,84 @@ Can't find printer handle we created for printer %s\n", name )); else printer_default->access_required = PRINTER_ACCESS_USE; - DEBUG(4,("Setting printer access = %s\n", (printer_default->access_required == PRINTER_ACCESS_ADMINISTER) - ? "PRINTER_ACCESS_ADMINISTER" : "PRINTER_ACCESS_USE" )); + DEBUG(4,("Setting printer access=%x\n", printer_default->access_required)); + Printer->access_granted = printer_default->access_required; + + /* + * If we have a default device pointer in the + * printer_default struct, then we need to get + * the printer info from the tdb and if there is + * no default devicemode there then we do a *SET* + * here ! This is insanity.... JRA. + */ + /* + * If the openprinterex rpc call contains a devmode, + * it's a per-user one. This per-user devmode is derivated + * from the global devmode. Openprinterex() contains a per-user + * devmode for when you do EMF printing and spooling. + * In the EMF case, the NT workstation is only doing half the job + * of rendering the page. The other half is done by running the printer + * driver on the server. + * The EMF file doesn't contain the page description (paper size, orientation, ...). + * The EMF file only contains what is to be printed on the page. + * So in order for the server to know how to print, the NT client sends + * a devicemode attached to the openprinterex call. + * But this devicemode is short lived, it's only valid for the current print job. + * + * If Samba would have supported EMF spooling, this devicemode would + * have been attached to the handle, to sent it to the driver to correctly + * rasterize the EMF file. + * + * As Samba only supports RAW spooling, we only receive a ready-to-print file, + * we just act as a pass-thru between windows and the printer. + * + * In order to know that Samba supports only RAW spooling, NT has to call + * getprinter() at level 2 (attribute field) or NT has to call startdoc() + * and until NT sends a RAW job, we refuse it. + * + * But to call getprinter() or startdoc(), you first need a valid handle, + * and to get an handle you have to call openprintex(). Hence why you have + * a devicemode in the openprinterex() call. + * + * + * Differences between NT4 and NT 2000. + * NT4: + * --- + * On NT4, you only have a global devicemode. This global devicemode can be changed + * by the administrator (or by a user with enough privs). Everytime a user + * wants to print, the devicemode is resetted to the default. In Word, everytime + * you print, the printer's characteristics are always reset to the global devicemode. + * + * NT 2000: + * ------- + * In W2K, there is the notion of per-user devicemode. The first time you use + * a printer, a per-user devicemode is build from the global devicemode. + * If you change your per-user devicemode, it is saved in the registry, under the + * H_KEY_CURRENT_KEY sub_tree. So that everytime you print, you have your default + * printer preferences available. + * + * To change the per-user devicemode: it's the "Printing Preferences ..." button + * on the General Tab of the printer properties windows. + * + * To change the global devicemode: it's the "Printing Defaults..." button + * on the Advanced Tab of the printer properties window. + * + * JFM. + */ + + + +#if 0 + if (printer_default->devmode_cont.devmode != NULL) { + result = printer_write_default_dev( snum, printer_default); + if (result != 0) { + close_printer_handle(p, handle); + return result; + } + } +#endif } - - Printer->access_granted = printer_default->access_required; - - /* - * If the client sent a devmode in the OpenPrinter() call, then - * save it here in case we get a job submission on this handle - */ - - if ( (Printer->printer_type != PRINTER_HANDLE_IS_PRINTSERVER) - && q_u->printer_default.devmode_cont.devmode_ptr ) - { - convert_devicemode( Printer->dev.handlename, q_u->printer_default.devmode_cont.devmode, - &Printer->nt_devmode ); - } return WERR_OK; } @@ -1849,11 +1599,8 @@ WERROR _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER fstring driver; fstring arch; NT_PRINTER_DRIVER_INFO_LEVEL info; - NT_PRINTER_DRIVER_INFO_LEVEL info_win2k; int version; struct current_user user; - WERROR status; - WERROR status_win2k = WERR_ACCESS_DENIED; get_current_user(&user, p); @@ -1861,58 +1608,25 @@ WERROR _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER unistr2_to_ascii(arch, &q_u->arch, sizeof(arch)-1 ); /* check that we have a valid driver name first */ - - if ((version=get_version_id(arch)) == -1) + if ((version=get_version_id(arch)) == -1) { + /* this is what NT returns */ return WERR_INVALID_ENVIRONMENT; - - ZERO_STRUCT(info); - ZERO_STRUCT(info_win2k); - - if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) - { - /* try for Win2k driver if "Windows NT x86" */ - - if ( version == 2 ) { - version = 3; - if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) { - status = WERR_UNKNOWN_PRINTER_DRIVER; - goto done; - } - } } - if (printer_driver_in_use(info.info_3)) { - status = WERR_PRINTER_DRIVER_IN_USE; - goto done; - } + /* if they said "Windows NT x86", then try for version 2 & 3 */ if ( version == 2 ) - { - if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3, driver, arch, 3))) - { - /* if we get to here, we now have 2 driver info structures to remove */ - /* remove the Win2k driver first*/ - - status_win2k = delete_printer_driver(info_win2k.info_3, &user, 3, False ); - free_a_printer_driver( info_win2k, 3 ); + version = DRIVER_ANY_VERSION; - /* this should not have failed---if it did, report to client */ - if ( !W_ERROR_IS_OK(status_win2k) ) - goto done; - } - } - - status = delete_printer_driver(info.info_3, &user, version, False); - - /* if at least one of the deletes succeeded return OK */ + ZERO_STRUCT(info); - if ( W_ERROR_IS_OK(status) || W_ERROR_IS_OK(status_win2k) ) - status = WERR_OK; + if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) + return WERR_UNKNOWN_PRINTER_DRIVER; -done: - free_a_printer_driver( info, 3 ); + if (printer_driver_in_use(info.info_3)) + return WERR_PRINTER_DRIVER_IN_USE; - return status; + return delete_printer_driver(info.info_3, &user, DRIVER_ANY_VERSION, False); } /******************************************************************** @@ -1924,13 +1638,10 @@ WERROR _spoolss_deleteprinterdriverex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIV fstring driver; fstring arch; NT_PRINTER_DRIVER_INFO_LEVEL info; - NT_PRINTER_DRIVER_INFO_LEVEL info_win2k; int version; uint32 flags = q_u->delete_flags; BOOL delete_files; struct current_user user; - WERROR status; - WERROR status_win2k = WERR_ACCESS_DENIED; get_current_user(&user, p); @@ -1945,36 +1656,17 @@ WERROR _spoolss_deleteprinterdriverex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIV if ( flags & DPD_DELETE_SPECIFIC_VERSION ) version = q_u->version; + else if ( version == 2 ) + /* if they said "Windows NT x86", then try for version 2 & 3 */ + version = DRIVER_ANY_VERSION; ZERO_STRUCT(info); - ZERO_STRUCT(info_win2k); - - status = get_a_printer_driver(&info, 3, driver, arch, version); - if ( !W_ERROR_IS_OK(status) ) - { - /* - * if the client asked for a specific version, - * or this is something other than Windows NT x86, - * then we've failed - */ - - if ( (flags&DPD_DELETE_SPECIFIC_VERSION) || (version !=2) ) - goto done; - - /* try for Win2k driver if "Windows NT x86" */ - - version = 3; - if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) { - status = WERR_UNKNOWN_PRINTER_DRIVER; - goto done; - } - } + if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, driver, arch, version))) + return WERR_UNKNOWN_PRINTER_DRIVER; - if ( printer_driver_in_use(info.info_3) ) { - status = WERR_PRINTER_DRIVER_IN_USE; - goto done; - } + if ( printer_driver_in_use(info.info_3) ) + return WERR_PRINTER_DRIVER_IN_USE; /* * we have a couple of cases to consider. @@ -1990,119 +1682,24 @@ WERROR _spoolss_deleteprinterdriverex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIV delete_files = flags & (DPD_DELETE_ALL_FILES|DPD_DELETE_UNUSED_FILES); - /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */ - - if ( delete_files && printer_driver_files_in_use(info.info_3) & (flags&DPD_DELETE_ALL_FILES) ) { - /* no idea of the correct error here */ - status = WERR_ACCESS_DENIED; - goto done; - } - - - /* also check for W32X86/3 if necessary; maybe we already have? */ - - if ( (version == 2) && ((flags&DPD_DELETE_SPECIFIC_VERSION) != DPD_DELETE_SPECIFIC_VERSION) ) { - if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3, driver, arch, 3))) - { - - if ( delete_files && printer_driver_files_in_use(info_win2k.info_3) & (flags&DPD_DELETE_ALL_FILES) ) { - /* no idea of the correct error here */ - free_a_printer_driver( info_win2k, 3 ); - status = WERR_ACCESS_DENIED; - goto done; - } - - /* if we get to here, we now have 2 driver info structures to remove */ - /* remove the Win2k driver first*/ + if ( delete_files ) + { + /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */ - status_win2k = delete_printer_driver(info_win2k.info_3, &user, 3, delete_files); - free_a_printer_driver( info_win2k, 3 ); - - /* this should not have failed---if it did, report to client */ - - if ( !W_ERROR_IS_OK(status_win2k) ) - goto done; - } - } - - status = delete_printer_driver(info.info_3, &user, version, delete_files); - - if ( W_ERROR_IS_OK(status) || W_ERROR_IS_OK(status_win2k) ) - status = WERR_OK; -done: - free_a_printer_driver( info, 3 ); - - return status; -} - - -/**************************************************************************** - Internal routine for retreiving printerdata - ***************************************************************************/ - -static WERROR get_printer_dataex( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printer, - char *key, char *value, uint32 *type, uint8 **data, - uint32 *needed, uint32 in_size ) -{ - REGISTRY_VALUE *val; - int size, data_len; - - if ( !(val = get_printer_data( printer->info_2, key, value)) ) - return WERR_BADFILE; - - *type = regval_type( val ); - - DEBUG(5,("get_printer_dataex: allocating %d\n", in_size)); - - size = regval_size( val ); - - /* copy the min(in_size, len) */ - - if ( in_size ) { - data_len = (size > in_size) ? in_size : size*sizeof(uint8); - if ( (*data = (uint8 *)talloc_memdup(ctx, regval_data_p(val), data_len)) == NULL ) - return WERR_NOMEM; + if ( printer_driver_files_in_use(info.info_3) & (flags&DPD_DELETE_ALL_FILES) ) + /* no idea of the correct error here */ + return WERR_ACCESS_DENIED; } - else - *data = NULL; - *needed = size; - - DEBUG(5,("get_printer_dataex: copy done\n")); - - return WERR_OK; + return delete_printer_driver(info.info_3, &user, version, delete_files); } -/**************************************************************************** - Internal routine for removing printerdata - ***************************************************************************/ - -static WERROR delete_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, char *key, char *value ) -{ - delete_printer_data( printer->info_2, key, value ); - - return mod_a_printer(*printer, 2); -} - -/**************************************************************************** - Internal routine for storing printerdata - ***************************************************************************/ - -static WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, char *key, char *value, - uint32 type, uint8 *data, int real_len ) -{ - delete_printer_data( printer->info_2, key, value ); - - add_printer_data( printer->info_2, key, value, type, data, real_len ); - - return mod_a_printer(*printer, 2); -} /******************************************************************** GetPrinterData on a printer server Handle. ********************************************************************/ -static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint32 *type, uint8 **data, uint32 *needed, uint32 in_size) +static BOOL getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint32 *type, uint8 **data, uint32 *needed, uint32 in_size) { int i; @@ -2111,50 +1708,50 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint if (!strcmp(value, "W3SvcInstalled")) { *type = 0x4; if((*data = (uint8 *)talloc_zero(ctx, 4*sizeof(uint8) )) == NULL) - return WERR_NOMEM; - *needed = 0x4; - return WERR_OK; + return False; + *needed = 0x4; + return True; } if (!strcmp(value, "BeepEnabled")) { *type = 0x4; if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL) - return WERR_NOMEM; + return False; SIVAL(*data, 0, 0x00); *needed = 0x4; - return WERR_OK; + return True; } if (!strcmp(value, "EventLog")) { *type = 0x4; if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL) - return WERR_NOMEM; + return False; /* formally was 0x1b */ SIVAL(*data, 0, 0x0); *needed = 0x4; - return WERR_OK; + return True; } if (!strcmp(value, "NetPopup")) { *type = 0x4; if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL) - return WERR_NOMEM; + return False; SIVAL(*data, 0, 0x00); *needed = 0x4; - return WERR_OK; + return True; } if (!strcmp(value, "MajorVersion")) { *type = 0x4; if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL) - return WERR_NOMEM; + return False; #ifndef EMULATE_WIN2K_HACK /* JERRY */ SIVAL(*data, 0, 2); #else SIVAL(*data, 0, 3); #endif *needed = 0x4; - return WERR_OK; + return True; } if (!strcmp(value, "DefaultSpoolDirectory")) { @@ -2164,7 +1761,7 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint *type = 0x1; *needed = 2*(strlen(string)+1); if((*data = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL) - return WERR_NOMEM; + return False; memset(*data, 0, (*needed > in_size) ? *needed:in_size); /* it's done by hand ready to go on the wire */ @@ -2172,7 +1769,7 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint (*data)[2*i]=string[i]; (*data)[2*i+1]='\0'; } - return WERR_OK; + return True; } if (!strcmp(value, "Architecture")) { @@ -2180,36 +1777,97 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint *type = 0x1; *needed = 2*(strlen(string)+1); if((*data = (uint8 *)talloc(ctx, ((*needed > in_size) ? *needed:in_size) *sizeof(uint8))) == NULL) - return WERR_NOMEM; + return False; memset(*data, 0, (*needed > in_size) ? *needed:in_size); for (i=0; i<strlen(string); i++) { (*data)[2*i]=string[i]; (*data)[2*i+1]='\0'; } - return WERR_OK; + return True; } - return WERR_INVALID_PARAM; + return False; } /******************************************************************** + GetPrinterData on a printer Handle. +********************************************************************/ + +static BOOL getprinterdata_printer(pipes_struct *p, TALLOC_CTX *ctx, POLICY_HND *handle, + fstring value, uint32 *type, + uint8 **data, uint32 *needed, uint32 in_size ) +{ + NT_PRINTER_INFO_LEVEL *printer = NULL; + int snum=0; + Printer_entry *Printer = find_printer_index_by_hnd(p, handle); + REGISTRY_VALUE *val; + int size = 0; + + DEBUG(5,("getprinterdata_printer\n")); + + if ( !Printer ) { + DEBUG(2,("getprinterdata_printer: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); + return False; + } + + if ( !get_printer_snum(p, handle, &snum) ) + return False; + + if ( !W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))) ) + return False; + + if ( !(val = get_printer_data( printer->info_2, SPOOL_PRINTERDATA_KEY, value)) ) + { + free_a_printer(&printer, 2); + return False; + } + + *type = regval_type( val ); + + + DEBUG(5,("getprinterdata_printer:allocating %d\n", in_size)); + + if (in_size) + { + if ( (*data = (uint8 *)talloc(ctx, in_size * sizeof(uint8))) == NULL ) + return False; + + memset( *data, 0, in_size *sizeof(uint8) ); + + /* copy the min(in_size, len) */ + + size = regval_size( val ); + memcpy( *data, regval_data_p(val), (size > in_size) ? in_size : size*sizeof(uint8) ); + } + else + *data = NULL; + + *needed = size; + + DEBUG(5,("getprinterdata_printer:copy done\n")); + + + free_a_printer(&printer, 2); + return True; +} + +/******************************************************************** * spoolss_getprinterdata ********************************************************************/ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPOOL_R_GETPRINTERDATA *r_u) { - POLICY_HND *handle = &q_u->handle; - UNISTR2 *valuename = &q_u->valuename; - uint32 in_size = q_u->size; - uint32 *type = &r_u->type; - uint32 *out_size = &r_u->size; - uint8 **data = &r_u->data; - uint32 *needed = &r_u->needed; - WERROR status; - fstring value; - Printer_entry *Printer = find_printer_index_by_hnd(p, handle); - NT_PRINTER_INFO_LEVEL *printer = NULL; - int snum = 0; + POLICY_HND *handle = &q_u->handle; + UNISTR2 *valuename = &q_u->valuename; + uint32 in_size = q_u->size; + uint32 *type = &r_u->type; + uint32 *out_size = &r_u->size; + uint8 **data = &r_u->data; + uint32 *needed = &r_u->needed; + + fstring value; + BOOL found=False; + Printer_entry *Printer = find_printer_index_by_hnd(p, handle); /* * Reminder: when it's a string, the length is in BYTES @@ -2227,58 +1885,45 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO DEBUG(4,("_spoolss_getprinterdata\n")); - if ( !Printer ) { + if (!Printer) { + if((*data=(uint8 *)talloc_zero(p->mem_ctx, 4*sizeof(uint8))) == NULL) + return WERR_NOMEM; DEBUG(2,("_spoolss_getprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); - status = WERR_BADFID; - goto done; + return WERR_BADFID; } unistr2_to_ascii(value, valuename, sizeof(value)-1); - if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER ) - status = getprinterdata_printer_server( p->mem_ctx, value, type, data, needed, *out_size ); + if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) + found = getprinterdata_printer_server(p->mem_ctx, value, type, data, needed, *out_size); else - { - if ( !get_printer_snum(p,handle, &snum) ) { - status = WERR_BADFID; - goto done; - } + found = getprinterdata_printer(p, p->mem_ctx, handle, value, type, data, needed, *out_size); - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if ( !W_ERROR_IS_OK(status) ) - goto done; - - status = get_printer_dataex( p->mem_ctx, printer, SPOOL_PRINTERDATA_KEY, value, type, data, needed, *out_size ); - } - - if (*needed > *out_size) - status = WERR_MORE_DATA; - -done: - if ( !W_ERROR_IS_OK(status) ) + if ( !found ) { - DEBUG(5, ("error: allocating %d\n", *out_size)); + DEBUG(5, ("value not found, allocating %d\n", *out_size)); /* reply this param doesn't exist */ - if ( *out_size ) { - if((*data=(uint8 *)talloc_zero(p->mem_ctx, *out_size*sizeof(uint8))) == NULL) { - if ( printer ) - free_a_printer( &printer, 2 ); + if (*out_size) { + if((*data=(uint8 *)talloc_zero(p->mem_ctx, *out_size*sizeof(uint8))) == NULL) return WERR_NOMEM; - } - } - else { + } else { *data = NULL; } - } - - /* cleanup & exit */ - if ( printer ) - free_a_printer( &printer, 2 ); + /* error depends on handle type */ + + if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) + return WERR_INVALID_PARAM; + else + return WERR_BADFILE; + } - return status; + if (*needed > *out_size) + return WERR_MORE_DATA; + else + return WERR_OK; } /********************************************************* @@ -2316,7 +1961,6 @@ static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_ma if (!attempt_netbios_session_request(the_cli, global_myname, remote_machine, &the_cli->dest_ip)) { DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request.\n", remote_machine)); - cli_shutdown(the_cli); return False; } @@ -2392,10 +2036,7 @@ static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uin if(!spoolss_connect_to_client(¬ify_cli, unix_printer)) return False; - message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message_list); - /* Tell the connections db we're now interested in printer - * notify messages. */ - register_message_flags( True, FLAG_MSG_PRINTING ); + message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message); } smb_connections++; @@ -2795,8 +2436,8 @@ static void spoolss_notify_security_desc(int snum, NT_PRINTER_INFO_LEVEL *printer, TALLOC_CTX *mem_ctx) { - data->notify_data.sd.size = printer->info_2->secdesc_buf->len; - data->notify_data.sd.desc = dup_sec_desc( mem_ctx, printer->info_2->secdesc_buf->sec ) ; + data->notify_data.data.length=0; + data->notify_data.data.string = NULL; } /******************************************************************* @@ -3802,20 +3443,47 @@ static void free_dev_mode(DEVICEMODE *dev) SAFE_FREE(dev); } - /**************************************************************************** - Convert an NT_DEVICEMODE to a DEVICEMODE structure. Both pointers - should be valid upon entry + Create a DEVMODE struct. Returns malloced memory. ****************************************************************************/ -static BOOL convert_nt_devicemode( DEVICEMODE *devmode, NT_DEVICEMODE *ntdevmode ) +DEVICEMODE *construct_dev_mode(int snum) { - if ( !devmode || !ntdevmode ) - return False; - - init_unistr(&devmode->devicename, ntdevmode->devicename); + char adevice[32]; + char aform[32]; + NT_PRINTER_INFO_LEVEL *printer = NULL; + NT_DEVICEMODE *ntdevmode = NULL; + DEVICEMODE *devmode = NULL; - init_unistr(&devmode->formname, ntdevmode->formname); + DEBUG(7,("construct_dev_mode\n")); + + DEBUGADD(8,("getting printer characteristics\n")); + + if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) == NULL) { + DEBUG(2,("construct_dev_mode: malloc fail.\n")); + return NULL; + } + + ZERO_STRUCTP(devmode); + + if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum)))) + goto fail; + + if (printer->info_2->devmode) + ntdevmode = dup_nt_devicemode(printer->info_2->devmode); + + if (ntdevmode == NULL) { + DEBUG(5, ("BONG! There was no device mode!\n")); + goto fail; + } + + DEBUGADD(8,("loading DEVICEMODE\n")); + + slprintf(adevice, sizeof(adevice)-1, printer->info_2->printername); + init_unistr(&devmode->devicename, adevice); + + slprintf(aform, sizeof(aform)-1, ntdevmode->formname); + init_unistr(&devmode->formname, aform); devmode->specversion = ntdevmode->specversion; devmode->driverversion = ntdevmode->driverversion; @@ -3843,51 +3511,23 @@ static BOOL convert_nt_devicemode( DEVICEMODE *devmode, NT_DEVICEMODE *ntdevmode if (ntdevmode->private != NULL) { if ((devmode->private=(uint8 *)memdup(ntdevmode->private, ntdevmode->driverextra)) == NULL) - return False; + goto fail; } - - return True; -} - -/**************************************************************************** - Create a DEVMODE struct. Returns malloced memory. -****************************************************************************/ - -DEVICEMODE *construct_dev_mode(int snum) -{ - NT_PRINTER_INFO_LEVEL *printer = NULL; - DEVICEMODE *devmode = NULL; - - DEBUG(7,("construct_dev_mode\n")); - - DEBUGADD(8,("getting printer characteristics\n")); - - if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum)))) - return NULL; - if ( !printer->info_2->devmode ) { - DEBUG(5, ("BONG! There was no device mode!\n")); - goto done; - } - - if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) == NULL) { - DEBUG(2,("construct_dev_mode: malloc fail.\n")); - goto done; - } + free_nt_devicemode(&ntdevmode); + free_a_printer(&printer,2); - ZERO_STRUCTP(devmode); - - DEBUGADD(8,("loading DEVICEMODE\n")); + return devmode; - if ( !convert_nt_devicemode( devmode, printer->info_2->devmode ) ) { - free_dev_mode( devmode ); - devmode = NULL; - } + fail: -done: - free_a_printer(&printer,2); + if (ntdevmode) + free_nt_devicemode(&ntdevmode); + if (printer) + free_a_printer(&printer,2); + free_dev_mode(devmode); - return devmode; + return NULL; } /******************************************************************** @@ -4744,7 +4384,7 @@ static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, fst * convert an array of ascii string to a UNICODE string ********************************************************************/ -static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, char *servername) +static void init_unistr_array(uint16 **uni_array, fstring *char_array, char *servername) { int i=0; int j=0; @@ -4757,34 +4397,26 @@ static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, char *s while (True) { - if ( !char_array ) + if (char_array == NULL) v = ""; - else - { + else { v = char_array[i]; - if (!v) - v = ""; /* hack to handle null lists */ + if (!v) v = ""; /* hack to handle null lists */ } - /* hack to allow this to be used in places other than when generating - the list of dependent files */ - - if ( servername ) - slprintf( line, sizeof(line)-1, "\\\\%s%s", servername, v ); - else - pstrcpy( line, v ); + if ( !strlen(v) ) + break; + slprintf(line, sizeof(line)-1, "\\\\%s%s", servername, v); + DEBUGADD(6,("%d:%s:%d\n", i, line, strlen(line))); - if ( (tuary=Realloc(*uni_array, (j+strlen(line)+2)*sizeof(uint16))) == NULL ) { + if((tuary=Realloc(*uni_array, (j+strlen(line)+2)*sizeof(uint16))) == NULL) { DEBUG(2,("init_unistr_array: Realloc error\n" )); - return 0; + return; } else *uni_array = tuary; - if ( !strlen(v) ) - break; - j += (rpcstr_push((*uni_array+j), line, sizeof(uint16)*strlen(line)+2, STR_TERMINATE) / sizeof(uint16)); i++; } @@ -4794,10 +4426,6 @@ static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, char *s } DEBUGADD(6,("last one:done\n")); - - /* return size of array in uint16's */ - - return j+1; } /******************************************************************** @@ -4816,29 +4444,29 @@ static void fill_printer_driver_info_3(DRIVER_INFO_3 *info, NT_PRINTER_DRIVER_IN init_unistr( &info->name, driver.info_3->name ); init_unistr( &info->architecture, driver.info_3->environment ); - if (strlen(driver.info_3->driverpath)) { - slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->driverpath); - init_unistr( &info->driverpath, temp ); - } else - init_unistr( &info->driverpath, "" ); + if (strlen(driver.info_3->driverpath)) { + slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->driverpath); + init_unistr( &info->driverpath, temp ); + } else + init_unistr( &info->driverpath, "" ); - if (strlen(driver.info_3->datafile)) { - slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->datafile); - init_unistr( &info->datafile, temp ); - } else - init_unistr( &info->datafile, "" ); + if (strlen(driver.info_3->datafile)) { + slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->datafile); + init_unistr( &info->datafile, temp ); + } else + init_unistr( &info->datafile, "" ); - if (strlen(driver.info_3->configfile)) { - slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->configfile); - init_unistr( &info->configfile, temp ); - } else - init_unistr( &info->configfile, "" ); + if (strlen(driver.info_3->configfile)) { + slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->configfile); + init_unistr( &info->configfile, temp ); + } else + init_unistr( &info->configfile, "" ); - if (strlen(driver.info_3->helpfile)) { - slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->helpfile); - init_unistr( &info->helpfile, temp ); - } else - init_unistr( &info->helpfile, "" ); + if (strlen(driver.info_3->helpfile)) { + slprintf(temp, sizeof(temp)-1, "\\\\%s%s", servername, driver.info_3->helpfile); + init_unistr( &info->helpfile, temp ); + } else + init_unistr( &info->helpfile, "" ); init_unistr( &info->monitorname, driver.info_3->monitorname ); init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype ); @@ -5305,6 +4933,10 @@ WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, S * in EMF format. * * So I add checks like in NT Server ... + * + * lkclXXXX jean-francois, i love this kind of thing. oh, well, + * there's a bug in NT client-side code, so we'll fix it in the + * server-side code. *nnnnnggggh!* */ if (info_1->p_datatype != 0) { @@ -5322,7 +4954,7 @@ WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, S unistr2_to_ascii(jobname, &info_1->docname, sizeof(jobname)); - Printer->jobid = print_job_start(&user, snum, jobname, Printer->nt_devmode); + Printer->jobid = print_job_start(&user, snum, jobname); /* An error occured in print_job_start() so return an appropriate NT error code. */ @@ -5372,13 +5004,6 @@ WERROR _spoolss_writeprinter(pipes_struct *p, SPOOL_Q_WRITEPRINTER *q_u, SPOOL_R return WERR_BADFID; (*buffer_written) = print_job_write(snum, Printer->jobid, (char *)buffer, buffer_size); - if (*buffer_written == -1) { - r_u->buffer_written = 0; - if (errno == ENOSPC) - return WERR_NO_SPOOL_SPACE; - else - return WERR_ACCESS_DENIED; - } r_u->buffer_written = q_u->buffer_size2; @@ -5421,13 +5046,11 @@ static WERROR control_printer(POLICY_HND *handle, uint32 command, errcode = WERR_OK; } break; -#if 0 /* JERRY - Never called */ case PRINTER_CONTROL_PURGE: if (print_queue_purge(&user, snum, &errcode)) { errcode = WERR_OK; } break; -#endif default: return WERR_UNKNOWN_LEVEL; } @@ -5437,31 +5060,13 @@ static WERROR control_printer(POLICY_HND *handle, uint32 command, /******************************************************************** * api_spoolss_abortprinter - * From MSDN: "Deletes printer's spool file if printer is configured - * for spooling" ********************************************************************/ WERROR _spoolss_abortprinter(pipes_struct *p, SPOOL_Q_ABORTPRINTER *q_u, SPOOL_R_ABORTPRINTER *r_u) { - POLICY_HND *handle = &q_u->handle; - Printer_entry *Printer = find_printer_index_by_hnd(p, handle); - int snum; - struct current_user user; - WERROR errcode = WERR_OK; - - if (!Printer) { - DEBUG(2,("_spoolss_abortprinter: Invalid handle (%s:%u:%u)\n",OUR_HANDLE(handle))); - return WERR_BADFID; - } - - if (!get_printer_snum(p, handle, &snum)) - return WERR_BADFID; - - get_current_user( &user, p ); - - print_job_delete( &user, snum, Printer->jobid, &errcode ); - - return errcode; + POLICY_HND *handle = &q_u->handle; + + return control_printer(handle, PRINTER_CONTROL_PURGE, p); } /******************************************************************** @@ -5710,6 +5315,22 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level, goto done; } +#if 0 /* JERRY */ + + /* + * Another one of those historical misunderstandings... + * This is reminisent of a similar call we had in _spoolss_setprinterdata() + * I'm leaving it here as a reminder. --jerry + */ + + if (nt_printer_info_level_equal(printer, old_printer)) { + DEBUG(3, ("update_printer: printer info has not changed\n")); + result = WERR_OK; + goto done; + } + +#endif + /* Check calling user has permission to update printer description */ if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { @@ -5728,22 +5349,49 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level, } /* - * When a *new* driver is bound to a printer, the drivername is used to - * lookup previously saved driver initialization info, which is then - * bound to the printer, simulating what happens in the Windows arch. + * Set the DRIVER_INIT info in the tdb; trigger on magic value for the + * DEVMODE.displayfrequency, which is not used for printer drivers. This + * requires Win32 client code (see other notes elsewhere in the code). */ - if (!strequal(printer->info_2->drivername, old_printer->info_2->drivername)) + if (printer->info_2->devmode && + printer->info_2->devmode->displayfrequency == MAGIC_DISPLAY_FREQUENCY) { - if (!set_driver_init(printer, 2)) - { - DEBUG(5,("update_printer: Error restoring driver initialization data for driver [%s]!\n", - printer->info_2->drivername)); + + DEBUG(10,("update_printer: Save printer driver init data\n")); + printer->info_2->devmode->displayfrequency = 0; + + if (update_driver_init(*printer, 2)!=0) { + DEBUG(10,("update_printer: error updating printer driver init DEVMODE\n")); + result = WERR_ACCESS_DENIED; + goto done; } - DEBUG(10,("update_printer: changing driver [%s]! Sending event!\n", - printer->info_2->drivername)); + /* we need to reset all driver init data for all printers + bound to this driver */ + + srv_spoolss_reset_printerdata( printer->info_2->drivername ); + + } + else + { + /* + * When a *new* driver is bound to a printer, the drivername is used to + * lookup previously saved driver initialization info, which is then + * bound to the printer, simulating what happens in the Windows arch. + */ + if (!strequal(printer->info_2->drivername, old_printer->info_2->drivername)) + { + if (!set_driver_init(printer, 2)) + { + DEBUG(5,("update_printer: Error restoring driver initialization data for driver [%s]!\n", + printer->info_2->drivername)); + } - notify_printer_driver(snum, printer->info_2->drivername); + DEBUG(10,("update_printer: changing driver [%s]! Sending event!\n", + printer->info_2->drivername)); + + notify_printer_driver(snum, printer->info_2->drivername); + } } /* Update printer info */ @@ -6946,11 +6594,8 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_ */ if (!devmode) - { set_driver_init(printer, 2); - } - else - { + else { /* A valid devmode was included, convert and link it */ DEBUGADD(10, ("spoolss_addprinterex_level_2: devmode included, converting\n")); @@ -6960,6 +6605,8 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_ return WERR_NOMEM; } + set_driver_init(printer, 2); + /* write the ASCII on disk */ err = mod_a_printer(*printer, 2); if (!W_ERROR_IS_OK(err)) { @@ -7258,7 +6905,7 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S uint32 idx = q_u->index; uint32 in_value_len = q_u->valuesize; uint32 in_data_len = q_u->datasize; - uint32 *out_max_value_len = &r_u->valuesize; + uint32 *out_max_value_len= &r_u->valuesize; uint16 **out_value = &r_u->value; uint32 *out_value_len = &r_u->realvaluesize; uint32 *out_type = &r_u->type; @@ -7465,8 +7112,7 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP * when connecting to a printer --jerry */ - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) - { + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { DEBUG(3, ("_spoolss_setprinterdata: change denied by handle access permissions\n")); status = WERR_ACCESS_DENIED; goto done; @@ -7476,27 +7122,15 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP if (!W_ERROR_IS_OK(status)) return status; - unistr2_to_ascii( valuename, value, sizeof(valuename)-1 ); + /* save the registry data */ - /* - * When client side code sets a magic printer data key, detect it and save - * the current printer data and the magic key's data (its the DEVMODE) for - * future printer/driver initializations. - */ - if ( (type == REG_BINARY) && strequal( valuename, PHANTOM_DEVMODE_KEY)) - { - /* Set devmode and printer initialization info */ - status = save_driver_init( printer, 2, data, real_len ); + unistr2_to_ascii( valuename, value, sizeof(valuename)-1 ); + delete_printer_data( printer->info_2, SPOOL_PRINTERDATA_KEY, valuename ); + add_printer_data( printer->info_2, SPOOL_PRINTERDATA_KEY, valuename, type, data, real_len ); + + /* write the **entire** printer out to disk.... :-( */ - srv_spoolss_reset_printerdata( printer->info_2->drivername ); - } - else - { - status = set_printer_dataex( printer, SPOOL_PRINTERDATA_KEY, valuename, - type, data, real_len ); - if ( W_ERROR_IS_OK(status) ) - status = mod_a_printer(*printer, 2); - } + status = mod_a_printer(*printer, 2); done: free_a_printer(&printer, 2); @@ -7570,7 +7204,9 @@ WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_ unistr2_to_ascii( valuename, value, sizeof(valuename)-1 ); - status = delete_printer_dataex( printer, SPOOL_PRINTERDATA_KEY, valuename ); + status = delete_printer_data( printer->info_2, SPOOL_PRINTERDATA_KEY, valuename ); + if ( NT_STATUS_IS_OK(status) ) + status = mod_a_printer(*printer, 2); free_a_printer(&printer, 2); @@ -7599,52 +7235,40 @@ WERROR _spoolss_addform( pipes_struct *p, SPOOL_Q_ADDFORM *q_u, SPOOL_R_ADDFORM DEBUG(2,("_spoolss_addform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); return WERR_BADFID; } - - - /* forms can be added on printer of on the print server handle */ - - if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTER ) - { - if (!get_printer_snum(p,handle, &snum)) - return WERR_BADFID; - - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if (!W_ERROR_IS_OK(status)) - goto done; - } - if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) { + if (!get_printer_snum(p,handle, &snum)) + return WERR_BADFID; + + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { DEBUG(2,("_spoolss_addform: denied by handle permissions.\n")); status = WERR_ACCESS_DENIED; goto done; } - + /* can't add if builtin */ - if (get_a_builtin_ntform(&form->name,&tmpForm)) { - status = WERR_ALREADY_EXISTS; - goto done; + return WERR_ALREADY_EXISTS; } - count = get_ntforms(&list); - - if(!add_a_form(&list, form, &count)) { - status = WERR_NOMEM; - goto done; - } - + count=get_ntforms(&list); + if(!add_a_form(&list, form, &count)) + return WERR_NOMEM; write_ntforms(&list, count); /* - * ChangeID must always be set if this is a printer + * ChangeID must always be set */ - if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTER ) - status = mod_a_printer(*printer, 2); + status = get_a_printer(&printer, 2, lp_servicename(snum)); + if (!W_ERROR_IS_OK(status)) + goto done; + + status = mod_a_printer(*printer, 2); + if (!W_ERROR_IS_OK(status)) + goto done; done: - if ( printer ) - free_a_printer(&printer, 2); + free_a_printer(&printer, 2); SAFE_FREE(list); return status; @@ -7659,6 +7283,7 @@ WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DE UNISTR2 *form_name = &q_u->name; nt_forms_struct tmpForm; int count=0; + WERROR ret = WERR_OK; nt_forms_struct *list=NULL; Printer_entry *Printer = find_printer_index_by_hnd(p, handle); int snum; @@ -7672,49 +7297,40 @@ WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DE return WERR_BADFID; } - /* forms can be deleted on printer of on the print server handle */ - - if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTER ) - { - if (!get_printer_snum(p,handle, &snum)) - return WERR_BADFID; - - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if (!W_ERROR_IS_OK(status)) - goto done; - } + if (!get_printer_snum(p, handle, &snum)) + return WERR_BADFID; - if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) { - DEBUG(2,("_spoolss_deleteform: denied by handle permissions.\n")); - status = WERR_ACCESS_DENIED; - goto done; + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { + DEBUG(2,("_spoolss_deleteform: denied by handle permissions\n")); + return WERR_ACCESS_DENIED; } /* can't delete if builtin */ - if (get_a_builtin_ntform(form_name,&tmpForm)) { - status = WERR_INVALID_PARAM; - goto done; + return WERR_INVALID_PARAM; } count = get_ntforms(&list); - - if ( !delete_a_form(&list, form_name, &count, &status )) - goto done; + if(!delete_a_form(&list, form_name, &count, &ret)) + return WERR_INVALID_PARAM; /* - * ChangeID must always be set if this is a printer + * ChangeID must always be set */ - if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTER ) - status = mod_a_printer(*printer, 2); + status = get_a_printer(&printer, 2, lp_servicename(snum)); + if (!W_ERROR_IS_OK(status)) + goto done; + + status = mod_a_printer(*printer, 2); + if (!W_ERROR_IS_OK(status)) + goto done; done: - if ( printer ) - free_a_printer(&printer, 2); + free_a_printer(&printer, 2); SAFE_FREE(list); - return status; + return ret; } /**************************************************************************** @@ -7740,48 +7356,40 @@ WERROR _spoolss_setform(pipes_struct *p, SPOOL_Q_SETFORM *q_u, SPOOL_R_SETFORM * return WERR_BADFID; } - /* forms can be modified on printer of on the print server handle */ - - if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTER ) - { - if (!get_printer_snum(p,handle, &snum)) - return WERR_BADFID; - - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if (!W_ERROR_IS_OK(status)) - goto done; - } + if (!get_printer_snum(p, handle, &snum)) + return WERR_BADFID; - if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) { + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { DEBUG(2,("_spoolss_setform: denied by handle permissions\n")); - status = WERR_ACCESS_DENIED; - goto done; + return WERR_ACCESS_DENIED; } /* can't set if builtin */ if (get_a_builtin_ntform(&form->name,&tmpForm)) { - status = WERR_INVALID_PARAM; - goto done; + return WERR_INVALID_PARAM; } - count = get_ntforms(&list); + count=get_ntforms(&list); update_a_form(&list, form, count); write_ntforms(&list, count); /* - * ChangeID must always be set if this is a printer + * ChangeID must always be set */ - if ( Printer->printer_type == PRINTER_HANDLE_IS_PRINTER ) - status = mod_a_printer(*printer, 2); + status = get_a_printer(&printer, 2, lp_servicename(snum)); + if (!W_ERROR_IS_OK(status)) + goto done; + status = mod_a_printer(*printer, 2); + if (!W_ERROR_IS_OK(status)) + goto done; done: - if ( printer ) - free_a_printer(&printer, 2); + free_a_printer(&printer, 2); SAFE_FREE(list); - return status; + return WERR_OK; } /**************************************************************************** @@ -8030,7 +7638,7 @@ static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uin return WERR_NOMEM; } - for (i=0; i<count && found==False; i++) { + for (i=0; i<count && found==False; i++) { if (queue[i].job==(int)jobid) found=True; } @@ -8044,6 +7652,8 @@ static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uin fill_job_info_1(info_1, &(queue[i-1]), i, snum); + SAFE_FREE(queue); + *needed += spoolss_size_job_info_1(info_1); if (!alloc_buffer_size(buffer, *needed)) { @@ -8066,13 +7676,12 @@ static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uin static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed) { - int i = 0; - BOOL found = False; - JOB_INFO_2 *info_2; + int i=0; + BOOL found=False; + JOB_INFO_2 *info_2; NT_PRINTER_INFO_LEVEL *ntprinter = NULL; - WERROR ret; - DEVICEMODE *devmode = NULL; - NT_DEVICEMODE *nt_devmode = NULL; + WERROR ret; + DEVICEMODE *devmode = NULL; info_2=(JOB_INFO_2 *)malloc(sizeof(JOB_INFO_2)); @@ -8083,14 +7692,12 @@ static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uin goto done; } - for ( i=0; i<count && found==False; i++ ) - { - if (queue[i].job == (int)jobid) - found = True; + for (i=0; i<count && found==False; i++) { + if (queue[i].job==(int)jobid) + found=True; } - if ( !found ) - { + if (found==False) { /* NT treats not found as bad param... yet another bad choice */ ret = WERR_INVALID_PARAM; @@ -8100,22 +7707,7 @@ static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uin ret = get_a_printer(&ntprinter, 2, lp_servicename(snum)); if (!W_ERROR_IS_OK(ret)) goto done; - - /* - * if the print job does not have a DEVMODE associated with it, - * just use the one for the printer - */ - - if ( !(nt_devmode=print_job_devmode( snum, jobid )) ) - devmode = construct_dev_mode(snum); - else { - if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) != NULL) { - ZERO_STRUCTP( devmode ); - convert_nt_devicemode( devmode, nt_devmode ); - } - } - - if ( !devmode ) { + if (construct_dev_mode(snum) == NULL) { ret = WERR_NOMEM; goto done; } @@ -8141,6 +7733,7 @@ static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uin done: /* Cleanup allocated memory */ + SAFE_FREE(queue); free_job_info_2(info_2); /* Also frees devmode */ SAFE_FREE(info_2); free_a_printer(&ntprinter, 2); @@ -8159,11 +7752,10 @@ WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_ NEW_BUFFER *buffer = NULL; uint32 offered = q_u->offered; uint32 *needed = &r_u->needed; - WERROR wstatus = WERR_OK; int snum; int count; - print_queue_struct *queue = NULL; + print_queue_struct *queue=NULL; print_status_struct prt_status; /* that's an [in out] buffer */ @@ -8172,7 +7764,7 @@ WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_ DEBUG(5,("spoolss_getjob\n")); - *needed = 0; + *needed=0; if (!get_printer_snum(p, handle, &snum)) return WERR_BADFID; @@ -8182,29 +7774,19 @@ WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_ DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n", count, prt_status.status, prt_status.message)); - switch ( level ) { + switch (level) { case 1: - wstatus = getjob_level_1(queue, count, snum, jobid, - buffer, offered, needed); - break; + return getjob_level_1(queue, count, snum, jobid, buffer, offered, needed); case 2: - wstatus = getjob_level_2(queue, count, snum, jobid, - buffer, offered, needed); - break; + return getjob_level_2(queue, count, snum, jobid, buffer, offered, needed); default: - wstatus = WERR_UNKNOWN_LEVEL; - break; + SAFE_FREE(queue); + return WERR_UNKNOWN_LEVEL; } - - SAFE_FREE(queue); - return wstatus; } /******************************************************************** - spoolss_getprinterdataex - - From MSDN documentation of GetPrinterDataEx: pass request - to GetPrinterData if key is "PrinterDriverData". + * spoolss_getprinterdataex ********************************************************************/ WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u, SPOOL_R_GETPRINTERDATAEX *r_u) @@ -8215,181 +7797,112 @@ WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u, uint32 *out_size = &r_u->size; uint8 **data = &r_u->data; uint32 *needed = &r_u->needed; - fstring keyname, valuename; - + + fstring key, value; Printer_entry *Printer = find_printer_index_by_hnd(p, handle); - - NT_PRINTER_INFO_LEVEL *printer = NULL; - int snum = 0; - WERROR status = WERR_OK; + BOOL found = False; DEBUG(4,("_spoolss_getprinterdataex\n")); - unistr2_to_ascii(keyname, &q_u->keyname, sizeof(keyname) - 1); - unistr2_to_ascii(valuename, &q_u->valuename, sizeof(valuename) - 1); - - DEBUG(10, ("_spoolss_getprinterdataex: key => [%s], value => [%s]\n", - keyname, valuename)); + unistr2_to_ascii(key, &q_u->keyname, sizeof(key) - 1); + unistr2_to_ascii(value, &q_u->valuename, sizeof(value) - 1); /* in case of problem, return some default values */ - - *needed = 0; - *type = 0; - *out_size = in_size; + *needed=0; + *type=0; + *out_size=0; + if (!Printer) { - DEBUG(2,("_spoolss_getprinterdataex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); - status = WERR_BADFID; - goto done; + if((*data=(uint8 *)talloc_zero(p->mem_ctx, 4*sizeof(uint8))) == NULL) + return WERR_NOMEM; + DEBUG(2,("_spoolss_getprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); + return WERR_BADFID; } + /* Is the handle to a printer or to the server? */ - if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) { + if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER) + { DEBUG(10,("_spoolss_getprinterdatex: Not implemented for server handles yet\n")); - status = WERR_INVALID_PARAM; - goto done; + return WERR_INVALID_PARAM; } - - if ( !get_printer_snum(p,handle, &snum) ) - return WERR_BADFID; - - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if ( !W_ERROR_IS_OK(status) ) - goto done; + else + { + /* + * From MSDN documentation of GetPrinterDataEx: pass request + * to GetPrinterData if key is "PrinterDriverData". This is + * the only key we really support. Other keys to implement: + * (a) DsDriver + * (b) DsSpooler + * (c) PnPData + * (d) DsUser + */ + + if (strcmp(key, SPOOL_PRINTERDATA_KEY) != 0) + return WERR_BADFILE; - /* check to see if the keyname is valid */ - if ( !strlen(keyname) ) { - status = WERR_INVALID_PARAM; - goto done; - } - - if ( lookup_printerkey( &printer->info_2->data, keyname ) == -1 ) { - DEBUG(4,("_spoolss_getprinterdataex: Invalid keyname [%s]\n", keyname )); - free_a_printer( &printer, 2 ); - status = WERR_BADFILE; - goto done; + DEBUG(10, ("_spoolss_getprinterdataex: pass me to getprinterdata\n")); + found = getprinterdata_printer(p, p->mem_ctx, handle, value, + type, data, needed, in_size); + } - - /* When given a new keyname, we should just create it */ - - status = get_printer_dataex( p->mem_ctx, printer, keyname, valuename, type, data, needed, in_size ); - - if (*needed > *out_size) - status = WERR_MORE_DATA; - -done: - if ( !W_ERROR_IS_OK(status) ) - { - DEBUG(5, ("error: allocating %d\n", *out_size)); + + if (!found) { + DEBUG(5, ("value not found, allocating %d\n", *out_size)); /* reply this param doesn't exist */ - - if ( *out_size ) - { - if( (*data=(uint8 *)talloc_zero(p->mem_ctx, *out_size*sizeof(uint8))) == NULL ) { - status = WERR_NOMEM; - goto done; - } - } - else { + if (*out_size) { + if((*data=(uint8 *)talloc_zero(p->mem_ctx, *out_size*sizeof(uint8))) == NULL) + return WERR_NOMEM; + } else { *data = NULL; + } + + return WERR_INVALID_PARAM; } - } - - if ( printer ) - free_a_printer( &printer, 2 ); - return status; + if (*needed > *out_size) + return WERR_MORE_DATA; + else + return WERR_OK; } /******************************************************************** - * spoolss_setprinterdataex + * spoolss_setprinterdata ********************************************************************/ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u, SPOOL_R_SETPRINTERDATAEX *r_u) { - POLICY_HND *handle = &q_u->handle; - uint32 type = q_u->type; - uint8 *data = q_u->data; - uint32 real_len = q_u->real_len; + SPOOL_Q_SETPRINTERDATA q_u_local; + SPOOL_R_SETPRINTERDATA r_u_local; + fstring key; - NT_PRINTER_INFO_LEVEL *printer = NULL; - int snum = 0; - WERROR status = WERR_OK; - Printer_entry *Printer = find_printer_index_by_hnd(p, handle); - fstring valuename; - fstring keyname; - char *oid_string; - DEBUG(4,("_spoolss_setprinterdataex\n")); /* From MSDN documentation of SetPrinterDataEx: pass request to SetPrinterData if key is "PrinterDriverData" */ - if (!Printer) { - DEBUG(2,("_spoolss_setprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); - return WERR_BADFID; - } + unistr2_to_ascii(key, &q_u->key, sizeof(key) - 1); - if ( !get_printer_snum(p,handle, &snum) ) - return WERR_BADFID; - - /* - * Access check : NT returns "access denied" if you make a - * SetPrinterData call without the necessary privildge. - * we were originally returning OK if nothing changed - * which made Win2k issue **a lot** of SetPrinterData - * when connecting to a printer --jerry - */ - - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) - { - DEBUG(3, ("_spoolss_setprinterdataex: change denied by handle access permissions\n")); - return WERR_ACCESS_DENIED; - } - - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if (!W_ERROR_IS_OK(status)) - return status; - - unistr2_to_ascii( valuename, &q_u->value, sizeof(valuename) - 1); - unistr2_to_ascii( keyname, &q_u->key, sizeof(keyname) - 1); - - /* check for OID in valuename */ - - if ( (oid_string = strchr( valuename, ',' )) != NULL ) - { - *oid_string = '\0'; - oid_string++; - } - - /* save the registry data */ - - status = set_printer_dataex( printer, keyname, valuename, type, data, real_len ); - - /* save the OID if one was specified and the previous set call succeeded */ - - if ( W_ERROR_IS_OK(status) && oid_string ) - { - - fstrcat( keyname, "\\" ); - fstrcat( keyname, SPOOL_OID_KEY ); + if (strcmp(key, SPOOL_PRINTERDATA_KEY) != 0) + return WERR_INVALID_PARAM; - /* - * I'm not checking the status here on purpose. Don't know - * if this is right, but I'm returning the status from the - * previous set_printer_dataex() call. I have no idea if - * this is right. --jerry - */ - - set_printer_dataex( printer, keyname, valuename, - REG_SZ, (void*)oid_string, strlen(oid_string)+1 ); - } - - free_a_printer(&printer, 2); - - return status; + ZERO_STRUCT(q_u_local); + ZERO_STRUCT(r_u_local); + + /* make a copy to call _spoolss_setprinterdata() */ + + memcpy(&q_u_local.handle, &q_u->handle, sizeof(POLICY_HND)); + copy_unistr2(&q_u_local.value, &q_u->value); + q_u_local.type = q_u->type; + q_u_local.max_len = q_u->max_len; + q_u_local.data = q_u->data; + q_u_local.real_len = q_u->real_len; + q_u_local.numeric_data = q_u->numeric_data; + + return _spoolss_setprinterdata(p, &q_u_local, &r_u_local); } @@ -8399,44 +7912,26 @@ WERROR _spoolss_setprinterdataex(pipes_struct *p, SPOOL_Q_SETPRINTERDATAEX *q_u, WERROR _spoolss_deleteprinterdataex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATAEX *q_u, SPOOL_R_DELETEPRINTERDATAEX *r_u) { - POLICY_HND *handle = &q_u->handle; - UNISTR2 *value = &q_u->valuename; - UNISTR2 *key = &q_u->keyname; - - NT_PRINTER_INFO_LEVEL *printer = NULL; - int snum=0; - WERROR status = WERR_OK; - Printer_entry *Printer=find_printer_index_by_hnd(p, handle); - pstring valuename, keyname; + SPOOL_Q_DELETEPRINTERDATA q_u_local; + SPOOL_R_DELETEPRINTERDATA r_u_local; + fstring key; - DEBUG(5,("spoolss_deleteprinterdataex\n")); - - if (!Printer) { - DEBUG(2,("_spoolss_deleteprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); - return WERR_BADFID; - } - - if (!get_printer_snum(p, handle, &snum)) - return WERR_BADFID; - - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { - DEBUG(3, ("_spoolss_deleteprinterdataex: printer properties change denied by handle\n")); - return WERR_ACCESS_DENIED; - } + /* From MSDN documentation of SetPrinterDataEx: pass request to + SetPrinterData if key is "PrinterDriverData" */ - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if (!W_ERROR_IS_OK(status)) - return status; + unistr2_to_ascii(key, &q_u->keyname, sizeof(key) - 1); - unistr2_to_ascii( valuename, value, sizeof(valuename)-1 ); - unistr2_to_ascii( keyname, key, sizeof(keyname)-1 ); + if (strcmp(key, SPOOL_PRINTERDATA_KEY) != 0) + return WERR_INVALID_PARAM; + + memcpy(&q_u_local.handle, &q_u->handle, sizeof(POLICY_HND)); + copy_unistr2(&q_u_local.valuename, &q_u->valuename); + + return _spoolss_deleteprinterdata( p, &q_u_local, &r_u_local ); +} - status = delete_printer_dataex( printer, keyname, valuename ); - free_a_printer(&printer, 2); - return status; -} /******************************************************************** * spoolss_enumprinterkey @@ -8445,69 +7940,73 @@ WERROR _spoolss_deleteprinterdataex(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATAEX WERROR _spoolss_enumprinterkey(pipes_struct *p, SPOOL_Q_ENUMPRINTERKEY *q_u, SPOOL_R_ENUMPRINTERKEY *r_u) { - fstring key; - fstring *keynames = NULL; - uint16 *enumkeys = NULL; - int num_keys; - int printerkey_len; - POLICY_HND *handle = &q_u->handle; - Printer_entry *Printer = find_printer_index_by_hnd(p, handle); - NT_PRINTER_DATA *data; - NT_PRINTER_INFO_LEVEL *printer = NULL; - int snum = 0; - WERROR status = WERR_BADFILE; - - + fstring key; + uint16 *enumkeys = NULL; + char* ptr = NULL; + int i; + int printerkey_len = strlen(SPOOL_PRINTERDATA_KEY)+1; + DEBUG(4,("_spoolss_enumprinterkey\n")); - if (!Printer) { - DEBUG(2,("_spoolss_enumprinterkey: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); - return WERR_BADFID; - } + unistr2_to_ascii( key, &q_u->key, sizeof(key)-1 ); - if ( !get_printer_snum(p,handle, &snum) ) - return WERR_BADFID; + /* + * we only support enumating all keys (key == "") + * Of course, the only key we support is the "PrinterDriverData" + * key + */ - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if (!W_ERROR_IS_OK(status)) - return status; + if ( !strlen( key ) ) + { + r_u->needed = printerkey_len*2; - /* get the list of subkey names */ + if ( q_u->size < r_u->needed ) + return WERR_MORE_DATA; - unistr2_to_ascii( key, &q_u->key, sizeof(key)-1 ); - data = &printer->info_2->data; - - num_keys = get_printer_subkeys( data, key, &keynames ); - - if ( num_keys == -1 ) { - status = WERR_BADFILE; - goto done; - } - - printerkey_len = init_unistr_array( &enumkeys, keynames, NULL ); - - r_u->needed = printerkey_len*2; - - if ( q_u->size < r_u->needed ) { - status = WERR_MORE_DATA; - goto done; - } + if ( !(enumkeys = talloc( p->mem_ctx, printerkey_len*2 )) ) { + DEBUG(0,("_spoolss_enumprinterkey: talloc() failed for [%d] bytes!\n", + printerkey_len)); + return WERR_NOMEM; + } + + ptr = SPOOL_PRINTERDATA_KEY; + for ( i=0; i<(printerkey_len-1); i++ ) + { + enumkeys[i] = (uint16)(*ptr); + ptr++; + } - if (!make_spoolss_buffer5(p->mem_ctx, &r_u->keys, printerkey_len, enumkeys)) { - status = WERR_NOMEM; - goto done; + /* tag of '\0's */ + + enumkeys[i] = 0x0; + + if (!make_spoolss_buffer5(p->mem_ctx, &r_u->keys, printerkey_len, enumkeys)) + return WERR_BADFILE; + + return WERR_OK; } + + /* The "PrinterDriverData" key should have no subkeys */ + if ( strcmp(key, SPOOL_PRINTERDATA_KEY) == 0 ) + { + uint16 dummy_key = 0; + + r_u->needed = 2; + + if (q_u->size < r_u->needed) + return WERR_MORE_DATA; - status = WERR_OK; - - if ( q_u->size < r_u->needed ) - status = WERR_MORE_DATA; - -done: - free_a_printer( &printer, 2 ); - SAFE_FREE( keynames ); + if ( !make_spoolss_buffer5(p->mem_ctx, &r_u->keys, 1, &dummy_key ) ) + return WERR_BADFILE; + + return WERR_OK; + } - return status; + + /* The return value for an unknown key is documented in MSDN + EnumPrinterKey description */ + + return WERR_BADFILE; } /******************************************************************** @@ -8516,49 +8015,25 @@ done: WERROR _spoolss_deleteprinterkey(pipes_struct *p, SPOOL_Q_DELETEPRINTERKEY *q_u, SPOOL_R_DELETEPRINTERKEY *r_u) { - POLICY_HND *handle = &q_u->handle; - Printer_entry *Printer = find_printer_index_by_hnd(p, &q_u->handle); - fstring key; - NT_PRINTER_INFO_LEVEL *printer = NULL; - int snum=0; - WERROR status; - - DEBUG(5,("spoolss_deleteprinterkey\n")); + Printer_entry *Printer = find_printer_index_by_hnd(p, &q_u->handle); + fstring key; if (!Printer) { - DEBUG(2,("_spoolss_deleteprinterkey: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle))); + DEBUG(2,("_spoolss_deleteprinterkey: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(&q_u->handle))); return WERR_BADFID; } - - /* if keyname == NULL, return error */ - - if ( !q_u->keyname.buffer ) - return WERR_INVALID_PARAM; - - if (!get_printer_snum(p, handle, &snum)) - return WERR_BADFID; - - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { - DEBUG(3, ("_spoolss_deleteprinterkey: printer properties change denied by handle\n")); - return WERR_ACCESS_DENIED; - } - - status = get_a_printer(&printer, 2, lp_servicename(snum)); - if (!W_ERROR_IS_OK(status)) - return status; - - /* delete the key and all subneys */ unistr2_to_ascii(key, &q_u->keyname, sizeof(key) - 1); - - status = delete_all_printer_data( printer->info_2, key ); - if ( W_ERROR_IS_OK(status) ) - status = mod_a_printer(*printer, 2); - - free_a_printer( &printer, 2 ); - - return status; + if (strcmp(key, SPOOL_PRINTERDATA_KEY) != 0) + return WERR_INVALID_PARAM; + + /* + * this is what 2k returns when you try to delete the "PrinterDriverData" + * key + */ + + return WERR_ACCESS_DENIED; } @@ -8593,6 +8068,7 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_ return WERR_BADFID; } + /* first get the printer off of disk */ if (!get_printer_snum(p,handle, &snum)) |