From de3d0310e2622c068d6ae6fb4698752128068924 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 30 Aug 2002 10:47:34 +0000 Subject: merge of phant0m key fix from APP_HEAD (This used to be commit cb13d334a53f27713665570d85607d57eb407f9f) --- source3/printing/nt_printing.c | 159 ++++++++++++++++++++++++++++++++++-- source3/rpc_parse/parse_reg.c | 8 +- source3/rpc_server/srv_spoolss_nt.c | 91 ++++++++------------- 3 files changed, 190 insertions(+), 68 deletions(-) diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 1761064584..a5b4c5106a 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -3208,16 +3208,17 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr ) * the initialization save. Change it to reflect the new printer. */ + if ( info.devmode ) { ZERO_STRUCT(info.devmode->devicename); fstrcpy(info.devmode->devicename, info_ptr->printername); - + } /* * NT/2k does not change out the entire DeviceMode of a printer * when changing the driver. Only the driverextra, private, & * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002) * - * Later e4xamination revealed that Windows NT/2k does reset the + * Later examination revealed that Windows NT/2k does reset the * the printer's device mode, bit **only** when you change a * property of the device mode such as the page orientation. * --jerry @@ -3229,9 +3230,8 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr ) free_nt_devicemode(&info_ptr->devmode); info_ptr->devmode = info.devmode; - - DEBUG(10,("set_driver_init_2: Set printer [%s] init DEVMODE for driver [%s]\n", - info_ptr->printername, info_ptr->drivername)); + DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n", + info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername)); /* Add the printer data 'values' to the new printer */ @@ -3366,17 +3366,162 @@ uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level) { case 2: { - result=update_driver_init_2(printer.info_2); + result = update_driver_init_2(printer.info_2); break; } default: - result=1; + result = 1; break; } return result; } +/**************************************************************************** + Convert the printer data value, a REG_BINARY array, into an initialization + DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc... + got to keep the endians happy :). +****************************************************************************/ + +static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len ) +{ + BOOL result = False; + prs_struct ps; + DEVICEMODE devmode; + + ZERO_STRUCT(devmode); + + prs_init(&ps, 0, ctx, UNMARSHALL); + ps.data_p = (char *)data; + ps.buffer_size = data_len; + + if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode)) + result = convert_devicemode("", &devmode, &nt_devmode); + else + DEBUG(10,("convert_driver_init: error parsing DEVMODE\n")); + + return result; +} + +/**************************************************************************** + Set the DRIVER_INIT info in the tdb. Requires Win32 client code that: + + 1. Use the driver's config DLL to this UNC printername and: + a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE + b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE + 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data. + + The last step triggers saving the "driver initialization" information for + this printer into the tdb. Later, new printers that use this driver will + have this initialization information bound to them. This simulates the + driver initialization, as if it had run on the Samba server (as it would + have done on NT). + + The Win32 client side code requirement sucks! But until we can run arbitrary + Win32 printer driver code on any Unix that Samba runs on, we are stuck with it. + + It would have been easier to use SetPrinter because all the UNMARSHALLING of + the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think + about it and you will realize why. JRR 010720 +****************************************************************************/ + +static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len ) +{ + WERROR status = WERR_OK; + TALLOC_CTX *ctx = NULL; + NT_DEVICEMODE *nt_devmode = NULL; + NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode; + + /* + * When the DEVMODE is already set on the printer, don't try to unpack it. + */ + DEBUG(8,("save_driver_init_2: Enter...\n")); + + if ( !printer->info_2->devmode && data_len ) + { + /* + * Set devmode on printer info, so entire printer initialization can be + * saved to tdb. + */ + + if ((ctx = talloc_init()) == NULL) + return WERR_NOMEM; + + if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) { + status = WERR_NOMEM; + goto done; + } + + ZERO_STRUCTP(nt_devmode); + + /* + * The DEVMODE is held in the 'data' component of the param in raw binary. + * Convert it to to a devmode structure + */ + if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) { + DEBUG(10,("save_driver_init_2: error converting DEVMODE\n")); + status = WERR_INVALID_PARAM; + goto done; + } + + printer->info_2->devmode = nt_devmode; + } + + /* + * Pack up and add (or update) the DEVMODE and any current printer data to + * a 'driver init' element in the tdb + * + */ + + if ( update_driver_init(*printer, 2) != 0 ) { + DEBUG(10,("save_driver_init_2: error updating DEVMODE\n")); + status = WERR_NOMEM; + goto done; + } + + /* + * If driver initialization info was successfully saved, set the current + * printer to match it. This allows initialization of the current printer + * as well as the driver. + */ + status = mod_a_printer(*printer, 2); + if (!W_ERROR_IS_OK(status)) { + DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n", + printer->info_2->printername)); + } + + done: + talloc_destroy(ctx); + free_nt_devicemode( &nt_devmode ); + + printer->info_2->devmode = tmp_devmode; + + return status; +} + +/**************************************************************************** + Update the driver init info (DEVMODE and specifics) for a printer +****************************************************************************/ + +WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len) +{ + WERROR status = WERR_OK; + + switch (level) + { + case 2: + { + status = save_driver_init_2( printer, data, data_len ); + break; + } + default: + status = WERR_UNKNOWN_LEVEL; + break; + } + + return status; +} + /**************************************************************************** Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory. ****************************************************************************/ diff --git a/source3/rpc_parse/parse_reg.c b/source3/rpc_parse/parse_reg.c index 365ad2dc70..1387aaf6ea 100644 --- a/source3/rpc_parse/parse_reg.c +++ b/source3/rpc_parse/parse_reg.c @@ -39,6 +39,7 @@ static uint32 reg_init_buffer2( BUFFER2 *buf2, REGISTRY_VALUE *val ) char *string; char *list = NULL; char *list2 = NULL; + int len = 0; if ( !buf2 || !val ) return 0; @@ -48,10 +49,13 @@ static uint32 reg_init_buffer2( BUFFER2 *buf2, REGISTRY_VALUE *val ) switch (val->type ) { case REG_SZ: - string = (char*)val->data_p; + string = (char*)regval_data_p( val ); DEBUG(10,("reg_init_buffer2: REG_SZ string => [%s]\n", string)); - init_unistr2( &unistr, (char*)val->data_p, strlen((char*)val->data_p)+1 ); + if ( string ) + len = strlen(string)+1; + + init_unistr2( &unistr, (char*)val->data_p, len ); init_buffer2( buf2, (char*)unistr.buffer, unistr.uni_str_len*2 ); real_size = unistr.uni_str_len*2; break; diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index de87954fea..d1f92aef13 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -5335,22 +5335,6 @@ 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) { @@ -5369,49 +5353,22 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level, } /* - * 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). + * 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 (printer->info_2->devmode && - printer->info_2->devmode->displayfrequency == MAGIC_DISPLAY_FREQUENCY) - { - - 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; - } - - /* we need to reset all driver init data for all printers - bound to this driver */ - - srv_spoolss_reset_printerdata( printer->info_2->drivername ); - - } - else + if (!strequal(printer->info_2->drivername, old_printer->info_2->drivername)) { - /* - * 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)) { - 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: changing driver [%s]! Sending event!\n", + 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 */ @@ -6614,8 +6571,11 @@ 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")); @@ -6625,8 +6585,6 @@ 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)) { @@ -6925,7 +6883,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; @@ -7145,10 +7103,25 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP 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 ); + 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); + } done: free_a_printer(&printer, 2); -- cgit