summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h1
-rw-r--r--source3/printing/nt_printing.c101
-rwxr-xr-xsource3/rpc_server/srv_spoolss.c33
-rw-r--r--source3/rpc_server/srv_spoolss_nt.c82
-rw-r--r--source3/rpcclient/cmd_spoolss.c23
5 files changed, 232 insertions, 8 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 8b18ee5010..7881334df8 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -205,6 +205,7 @@ implemented */
#define ERROR_INVALID_PRINTER_NAME (1801)
#define ERROR_INVALID_DATATYPE (1804)
#define ERROR_INVALID_ENVIRONMENT (1805)
+#define ERROR_PRINTER_DRIVER_IN_USE (3001)
/* here's a special one from observing NT */
#define ERRnoipc 66 /* don't support ipc */
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index 164ad58742..a0031ae35a 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -2844,6 +2844,107 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
return result;
}
+
+/****************************************************************************
+ Determine whether or not a particular driver is currently assigned
+ to a printer
+****************************************************************************/
+BOOL printer_driver_in_use (char *arch, char *driver)
+{
+ TDB_DATA kbuf, newkey, dbuf;
+ NT_PRINTER_INFO_LEVEL_2 info;
+ int ret;
+
+ if (!tdb)
+ nt_printing_init();
+
+ DEBUG(5,("printer_driver_in_use: Beginning search through printers.tdb...\n"));
+
+ /* loop through the printers.tdb and check for the drivername */
+ for (kbuf = tdb_firstkey(tdb); kbuf.dptr;
+ newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
+ {
+
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr)
+ continue;
+
+ if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) != 0)
+ continue;
+
+ ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddddddfffffPfffff",
+ &info.attributes,
+ &info.priority,
+ &info.default_priority,
+ &info.starttime,
+ &info.untiltime,
+ &info.status,
+ &info.cjobs,
+ &info.averageppm,
+ &info.changeid,
+ &info.c_setprinter,
+ &info.setuptime,
+ info.servername,
+ info.printername,
+ info.sharename,
+ info.portname,
+ info.drivername,
+ info.comment,
+ info.location,
+ info.sepfile,
+ info.printprocessor,
+ info.datatype,
+ info.parameters);
+
+ safe_free(dbuf.dptr);
+
+ DEBUG (10,("printer_driver_in_use: Printer - %s (%s)\n",
+ info.printername, info.drivername));
+
+ if (strcmp(info.drivername, driver) == 0)
+ {
+ DEBUG(5,("printer_driver_in_use: Printer %s using %s\n",
+ info.printername, driver));
+ return True;
+ }
+ }
+ DEBUG(5,("printer_driver_in_use: Completed search through printers.tdb...\n"));
+
+
+
+ /* report that the driver is in use by default */
+ return False;
+}
+
+/****************************************************************************
+ Remove a printer driver from the TDB. This assumes that the the driver was
+ previously looked up.
+ ***************************************************************************/
+uint32 delete_printer_driver (NT_PRINTER_DRIVER_INFO_LEVEL_3 *i)
+{
+ pstring key;
+ fstring arch;
+ TDB_DATA kbuf;
+
+
+ get_short_archi(arch, i->environment);
+ slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
+ arch, i->cversion, i->name);
+ DEBUG(5,("delete_printer_driver: key = [%s]\n", key));
+
+ kbuf.dptr=key;
+ kbuf.dsize=strlen(key)+1;
+
+ if (tdb_delete(tdb, kbuf) == -1) {
+ DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
+ return NT_STATUS_ACCESS_VIOLATION;
+ }
+
+ DEBUG(5,("delete_printer_driver: [%s] driver delete successful.\n",
+ i->name));
+
+ return NT_STATUS_NO_PROBLEMO;
+}
/****************************************************************************
****************************************************************************/
BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, uint32 param_index,
diff --git a/source3/rpc_server/srv_spoolss.c b/source3/rpc_server/srv_spoolss.c
index ddd8255139..1adc783e24 100755
--- a/source3/rpc_server/srv_spoolss.c
+++ b/source3/rpc_server/srv_spoolss.c
@@ -214,6 +214,38 @@ static BOOL api_spoolss_deleteprinter(pipes_struct *p)
/********************************************************************
+ * api_spoolss_deleteprinterdriver
+ *
+ * called from the spoolss dispatcher
+ ********************************************************************/
+
+static BOOL api_spoolss_deleteprinterdriver(pipes_struct *p)
+{
+ SPOOL_Q_DELETEPRINTERDRIVER q_u;
+ SPOOL_R_DELETEPRINTERDRIVER r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if (!spoolss_io_q_deleteprinterdriver("", &q_u, data, 0)) {
+ DEBUG(0,("spoolss_io_q_deleteprinterdriver: unable to unmarshall SPOOL_Q_DELETEPRINTERDRIVER.\n"));
+ return False;
+ }
+
+ r_u.status = _spoolss_deleteprinterdriver(p, &q_u, &r_u);
+
+ if (!spoolss_io_r_deleteprinterdriver("",&r_u,rdata,0)) {
+ DEBUG(0,("spoolss_io_r_deleteprinter: unable to marshall SPOOL_R_DELETEPRINTER.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/********************************************************************
* api_spoolss_rffpcnex
* ReplyFindFirstPrinterChangeNotifyEx
********************************************************************/
@@ -1169,6 +1201,7 @@ struct api_struct api_spoolss_cmds[] =
{"SPOOLSS_ENUMPRINTERDRIVERS", SPOOLSS_ENUMPRINTERDRIVERS, api_spoolss_enumprinterdrivers },
{"SPOOLSS_ADDPRINTEREX", SPOOLSS_ADDPRINTEREX, api_spoolss_addprinterex },
{"SPOOLSS_ADDPRINTERDRIVER", SPOOLSS_ADDPRINTERDRIVER, api_spoolss_addprinterdriver },
+ {"SPOOLSS_DELETEPRINTERDRIVER", SPOOLSS_DELETEPRINTERDRIVER, api_spoolss_deleteprinterdriver },
{"SPOOLSS_GETPRINTERDRIVERDIRECTORY", SPOOLSS_GETPRINTERDRIVERDIRECTORY, api_spoolss_getprinterdriverdirectory },
{"SPOOLSS_ENUMPRINTERDATA", SPOOLSS_ENUMPRINTERDATA, api_spoolss_enumprinterdata },
{"SPOOLSS_SETPRINTERDATA", SPOOLSS_SETPRINTERDATA, api_spoolss_setprinterdata },
diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c
index d714972179..1d1eced2ea 100644
--- a/source3/rpc_server/srv_spoolss_nt.c
+++ b/source3/rpc_server/srv_spoolss_nt.c
@@ -34,6 +34,13 @@ extern pstring global_myname;
#define PRINTER_HANDLE_IS_PRINTER 0
#define PRINTER_HANDLE_IS_PRINTSERVER 1
+struct table_node {
+ char *long_archi;
+ char *short_archi;
+ int version;
+};
+
+
/* structure to store the printer handles */
/* and a reference to what it's pointing to */
/* and the notify info asked about */
@@ -1058,6 +1065,81 @@ uint32 _spoolss_deleteprinter(pipes_struct *p, SPOOL_Q_DELETEPRINTER *q_u, SPOOL
return result;
}
+/*******************************************************************
+ * static function to lookup the version id corresponding to an
+ * long architecture string
+ ******************************************************************/
+static int get_version_id (char * arch)
+{
+ int i;
+ struct table_node archi_table[]= {
+
+ {"Windows 4.0", "WIN40", 0 },
+ {"Windows NT x86", "W32X86", 2 },
+ {"Windows NT R4000", "W32MIPS", 2 },
+ {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
+ {"Windows NT PowerPC", "W32PPC", 2 },
+ {NULL, "", -1 }
+ };
+
+ for (i=0; archi_table[i].long_archi != NULL; i++)
+ {
+ if (strcmp(arch, archi_table[i].long_archi) == 0)
+ return (archi_table[i].version);
+ }
+
+ return -1;
+}
+
+/********************************************************************
+ * _spoolss_deleteprinterdriver
+ *
+ * We currently delete the driver for the architecture only.
+ * This can leave the driver for other archtectures. However,
+ * since every printer associates a "Windows NT x86" driver name
+ * and we cannot delete that one while it is in use, **and** since
+ * it is impossible to assign a driver to a Samba printer without
+ * having the "Windows NT x86" driver installed,...
+ *
+ * ....we should not get into trouble here.
+ *
+ * --jerry
+ ********************************************************************/
+
+uint32 _spoolss_deleteprinterdriver(pipes_struct *p, SPOOL_Q_DELETEPRINTERDRIVER *q_u,
+ SPOOL_R_DELETEPRINTERDRIVER *r_u)
+{
+ fstring driver;
+ fstring arch;
+ NT_PRINTER_DRIVER_INFO_LEVEL info;
+ int version;
+
+ unistr2_to_ascii(driver, &q_u->driver, sizeof(driver)-1 );
+ 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) {
+ /* this is what NT returns */
+ return ERROR_INVALID_ENVIRONMENT;
+ }
+
+ ZERO_STRUCT(info);
+ if (get_a_printer_driver (&info, 3, driver, arch, version) != 0) {
+ /* this is what NT returns */
+ return ERROR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+
+ if (printer_driver_in_use(arch, driver))
+ {
+ /* this is what NT returns */
+ return ERROR_PRINTER_DRIVER_IN_USE;
+ }
+
+ return delete_printer_driver(info.info_3);
+}
+
+
/********************************************************************
GetPrinterData on a printer server Handle.
********************************************************************/
diff --git a/source3/rpcclient/cmd_spoolss.c b/source3/rpcclient/cmd_spoolss.c
index fc1ac49430..32131ad780 100644
--- a/source3/rpcclient/cmd_spoolss.c
+++ b/source3/rpcclient/cmd_spoolss.c
@@ -1315,11 +1315,12 @@ static uint32 cmd_spoolss_deletedriver (struct cli_state *cli, int argc, char **
uint32 result = NT_STATUS_UNSUCCESSFUL;
fstring servername;
TALLOC_CTX *mem_ctx = NULL;
+ int i;
/* parse the command arguements */
- if (argc != 3)
+ if (argc != 2)
{
- printf ("Usage: %s <arch> <driver>\n", argv[0]);
+ printf ("Usage: %s <driver>\n", argv[0]);
return NT_STATUS_NOPROBLEMO;
}
@@ -1339,13 +1340,19 @@ static uint32 cmd_spoolss_deletedriver (struct cli_state *cli, int argc, char **
return NT_STATUS_UNSUCCESSFUL;
}
- /* make the call to remove the driver */
- if ((result = cli_spoolss_deleteprinterdriver(cli, mem_ctx, argv[1], argv[2])) != NT_STATUS_NO_PROBLEMO)
+ /* delete the driver for all architectures */
+ for (i=0; archi_table[i].long_archi; i++)
{
- printf ("Failed to remove %s driver %s!\n", argv[1], argv[2]);
- goto done;;
+ /* make the call to remove the driver */
+ if ((result = cli_spoolss_deleteprinterdriver(cli, mem_ctx,
+ archi_table[i].long_archi, argv[1])) != NT_STATUS_NO_PROBLEMO)
+ {
+ printf ("Failed to remove driver %s for arch [%s] - error %s!\n",
+ argv[1], archi_table[i].long_archi, get_nt_error_msg(result));
+ }
+ else
+ printf ("Driver %s removed for arch [%s].\n", argv[1], archi_table[i].long_archi);
}
- printf ("%s driver %s removed.\n", argv[1], argv[2]);
done:
@@ -1353,7 +1360,7 @@ done:
cli_nt_session_close (cli);
talloc_destroy(mem_ctx);
- return result;
+ return NT_STATUS_NO_PROBLEMO;
}