summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/printing/nt_printing.c159
-rw-r--r--source3/rpc_parse/parse_reg.c8
-rw-r--r--source3/rpc_server/srv_spoolss_nt.c91
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,11 +3366,11 @@ 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;
}
@@ -3378,6 +3378,151 @@ uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
}
/****************************************************************************
+ 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);