diff options
-rw-r--r-- | source3/include/smb.h | 1 | ||||
-rw-r--r-- | source3/printing/nt_printing.c | 101 | ||||
-rwxr-xr-x | source3/rpc_server/srv_spoolss.c | 33 | ||||
-rw-r--r-- | source3/rpc_server/srv_spoolss_nt.c | 82 | ||||
-rw-r--r-- | source3/rpcclient/cmd_spoolss.c | 23 |
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; } |