Added John Reilly's enumports/addprinter/delprinter scripting code plus the
authorJeremy Allison <jra@samba.org>
Mon, 31 Jul 2000 20:41:51 +0000 (20:41 +0000)
committerJeremy Allison <jra@samba.org>
Mon, 31 Jul 2000 20:41:51 +0000 (20:41 +0000)
fix for the Win9x printer drivers.
Changed command names to add "command" string on the end for some consistancy
with the other scripting commands.
Added '%P' option to tdbpack/unpack to store long comment string.
Made port name be "Samba Printer Port" if no enum port script given.
Fixed prs_uint32_pre code to cope with null args.
Jeremy.

source/include/nt_printing.h
source/include/proto.h
source/param/loadparm.c
source/printing/load.c
source/printing/nt_printing.c
source/rpc_parse/parse_prs.c
source/rpc_parse/parse_spoolss.c
source/rpc_server/srv_spoolss_nt.c
source/smbd/lanman.c
source/tdb/tdbutil.c

index 58a4dec3a0681a98a20fa3c2ffe513cf1b1ea793..04d669f822dae168961174f1d073d6d92d33341a 100644 (file)
@@ -239,7 +239,7 @@ typedef struct nt_printer_info_level_2
        fstring sharename;
        fstring portname;
        fstring drivername;
-       fstring comment;
+       pstring comment;
        fstring location;
        NT_DEVICEMODE *devmode;
        fstring sepfile;
index af1c671e6240b70cdbc72be7e105ba3202dce060..9b526608f47b8d70d4dc55c523be92e5b8531fe6 100644 (file)
@@ -1302,6 +1302,9 @@ char *lp_configfile(void);
 char *lp_smb_passwd_file(void);
 char *lp_serverstring(void);
 char *lp_printcapname(void);
+char *lp_enumports_cmd(void);
+char *lp_addprinter_cmd(void);
+char *lp_deleteprinter_cmd(void);
 char *lp_lockdir(void);
 char *lp_utmpdir(void);
 char *lp_rootdir(void);
@@ -1530,6 +1533,7 @@ BOOL lp_snum_ok(int iService);
 void lp_add_one_printer(char *name, char *comment);
 BOOL lp_loaded(void);
 void lp_killunused(BOOL (*snumused) (int));
+void lp_killservice(int iServiceIn);
 BOOL lp_load(char *pszFname, BOOL global_only, BOOL save_defaults,
             BOOL add_ipc);
 void lp_resetnumservices(void);
@@ -1654,6 +1658,7 @@ BOOL trust_password_delete(char *domain);
 
 /*The following definitions come from  printing/load.c  */
 
+void add_all_printers(void);
 void load_printers(void);
 
 /*The following definitions come from  printing/lpq_parse.c  */
index 61e38bea602d42cd064ac91c21ba26d26be7508a..318c1ea53472379e9a64303533f2349ae6103f99 100644 (file)
@@ -104,6 +104,9 @@ static BOOL defaults_saved = False;
 typedef struct
 {
        char *szPrintcapname;
+       char *szEnumPortsCommand;
+       char *szAddPrinterCommand;
+       char *szDeletePrinterCommand;
        char *szLockDir;
        char *szRootdir;
        char *szDefaultService;
@@ -793,6 +796,10 @@ static struct parm_struct parm_table[] = {
        {"queuepause command", P_STRING, P_LOCAL, &sDefault.szQueuepausecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
        {"queueresume command", P_STRING, P_LOCAL, &sDefault.szQueueresumecommand, NULL, NULL, FLAG_PRINT | FLAG_GLOBAL},
 
+       {"enumports command", P_STRING, P_GLOBAL, &Globals.szEnumPortsCommand, NULL, NULL, 0},
+       {"addprinter command", P_STRING, P_GLOBAL, &Globals.szAddPrinterCommand, NULL, NULL, 0},
+       {"deleteprinter command", P_STRING, P_GLOBAL, &Globals.szDeletePrinterCommand, NULL, NULL, 0},
+       
        {"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, FLAG_PRINT},
        {"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, 0},
        {"printer driver", P_STRING, P_LOCAL, &sDefault.szPrinterDriver, NULL, NULL, FLAG_PRINT},
@@ -1317,6 +1324,9 @@ FN_GLOBAL_STRING(lp_configfile, &Globals.szConfigFile)
 FN_GLOBAL_STRING(lp_smb_passwd_file, &Globals.szSMBPasswdFile)
 FN_GLOBAL_STRING(lp_serverstring, &Globals.szServerString)
 FN_GLOBAL_STRING(lp_printcapname, &Globals.szPrintcapname)
+FN_GLOBAL_STRING(lp_enumports_cmd, &Globals.szEnumPortsCommand)
+FN_GLOBAL_STRING(lp_addprinter_cmd, &Globals.szAddPrinterCommand)
+FN_GLOBAL_STRING(lp_deleteprinter_cmd, &Globals.szDeletePrinterCommand)
 FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir)
 #ifdef WITH_UTMP
 FN_GLOBAL_STRING(lp_utmpdir, &Globals.szUtmpDir)
@@ -3007,6 +3017,18 @@ void lp_killunused(BOOL (*snumused) (int))
 }
 
 
+/***************************************************************************
+unload a service
+***************************************************************************/
+void lp_killservice(int iServiceIn)
+{
+       if (VALID(iServiceIn))
+       {
+               iSERVICE(iServiceIn).valid = False;
+               free_service(pSERVICE(iServiceIn));
+       }
+}
+
 /***************************************************************************
 save the curent values of all global and sDefault parameters into the 
 defaults union. This allows swat and testparm to show only the
index 3d50f6d42a8cf831de66fcd61fdfa1018708b669..fbf10d22b87f81680410ca936ddcf97ba8c84930 100644 (file)
@@ -25,7 +25,7 @@
 /***************************************************************************
 auto-load printer services
 ***************************************************************************/
-static void add_all_printers(void)
+void add_all_printers(void)
 {
        int printers = lp_servicenumber(PRINTERS_NAME);
 
index 2fb1cbc998196b6df3494f24bc2e11668aa2ff0c..1b9fe8b15fee2eed799fb8434036c385c043c087 100644 (file)
@@ -387,7 +387,6 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
 {
        NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
        fstring architecture;
-       fstring clean_driver_name;
        pstring new_dir;
        pstring old_name;
        pstring new_name;
@@ -406,10 +405,6 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        
        get_short_archi(architecture, driver->environment);
 
-       /* clean up the driver's name */
-       fstrcpy(clean_driver_name, driver->name);
-       all_string_sub(clean_driver_name, "/", "#", 0);
-       
        /* connect to the print$ share under the same account as the user connected to the rpc pipe */  
        fstrcpy(user_name, uidtoname(user->uid));
        DEBUG(10,("move_driver_to_download_area: uid %d -> user %s\n", (int)user->uid, user_name));
@@ -447,18 +442,22 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        slprintf(new_dir, sizeof(new_dir), "%s\\%d", architecture, driver->cversion);
        mkdir_internal(conn, inbuf, outbuf, new_dir);
 
-       slprintf(new_dir, sizeof(new_dir), "%s\\%d\\%s", architecture, driver->cversion, clean_driver_name);
-       mkdir_internal(conn, inbuf, outbuf, new_dir);
-
        /* move all the files, one by one, 
         * from archi\filexxx.yyy to
-        * archi\version\driver name\filexxx.yyy 
+        * archi\version\filexxx.yyy
+        *
+        * Note: drivers may list the same file name in several places. This
+        * causes problems on a second attempt to move the file. JRR
+        *
+        * Note: use the replace flag on rename_internals() call, otherwise it
+        * is very difficult to change previously installed drivers... the Windows
+        * GUI offers the user the choice to replace or keep exisitng driver. JRR
         */
 
        DEBUG(5,("Moving file now !\n"));
        slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->driverpath);       
        slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->driverpath);    
-       if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, False)) != 0) {
+       if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
                DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
                                old_name, new_name ));
                close_cnum(conn, user->vuid);
@@ -466,45 +465,61 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                return False;
        }
 
+       if (!strequal(driver->datafile, driver->driverpath)) {
        slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->datafile); 
        slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->datafile);      
-       if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, False)) != 0) {
+               if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
                DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
                                old_name, new_name ));
                close_cnum(conn, user->vuid);
                unbecome_root();
                return False;
        }
+       }
 
+       if (!strequal(driver->configfile, driver->driverpath) &&
+               !strequal(driver->configfile, driver->datafile)) {
        slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->configfile);       
        slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->configfile);    
-       if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, False)) != 0) {
+               if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
                DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
                        old_name, new_name ));
                close_cnum(conn, user->vuid);
                unbecome_root();
                return False;
        }
+       }
 
+       if (!strequal(driver->helpfile, driver->driverpath) &&
+               !strequal(driver->helpfile, driver->datafile) &&
+               !strequal(driver->helpfile, driver->configfile)) {
        slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->helpfile); 
        slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->helpfile);      
-       if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, False)) != 0) {
+               if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
                DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
                        old_name, new_name ));
                close_cnum(conn, user->vuid);
                unbecome_root();
                return False;
        }
+       }
 
        if (driver->dependentfiles) {
                for (i=0; *driver->dependentfiles[i]; i++) {
+                       if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
+                               !strequal(driver->dependentfiles[i], driver->datafile) &&
+                               !strequal(driver->dependentfiles[i], driver->configfile) &&
+                               !strequal(driver->dependentfiles[i], driver->helpfile)) {
                        slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->dependentfiles[i]);        
                        slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->dependentfiles[i]);     
-                       /*
-                        * We don't check the error returns here as several of these
-                        * files may have already been moved in the list above...
-                        */
-                       rename_internals(conn, inbuf, outbuf, old_name, new_name, False);
+                               if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
+                                       DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
+                                               old_name, new_name ));
+                                       close_cnum(conn, user->vuid);
+                                       unbecome_root();
+                                       return False;
+                               }
+                       }
                }
        }
 
@@ -521,7 +536,6 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
        int len, buflen;
        fstring architecture;
        pstring directory;
-       fstring clean_driver_name;
        pstring temp_name;
        pstring key;
        char *buf;
@@ -530,16 +544,12 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
 
        get_short_archi(architecture, driver->environment);
 
-       /* The names are relative. We store them in the form: \print$\arch\version\printer-name\driver.xxx
+       /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
         * \\server is added in the rpc server layer.
         * It does make sense to NOT store the server's name in the printer TDB.
         */
 
-       /* clean up the driver's name */
-       fstrcpy(clean_driver_name, driver->name);
-       all_string_sub(clean_driver_name, "/", "#", 0);
-       
-       slprintf(directory, sizeof(directory), "\\print$\\%s\\%d\\%s\\", architecture, driver->cversion, clean_driver_name);
+       slprintf(directory, sizeof(directory), "\\print$\\%s\\%d\\", architecture, driver->cversion);
 
        
        fstrcpy(temp_name, driver->driverpath);
@@ -752,12 +762,16 @@ uint32 get_a_printer_driver_9x_compatible(pstring line, fstring model)
     DEBUGADD(10,("info3->configfile      [%s]\n", info3->configfile));
 
        /*pstrcat(line, info3->name);             pstrcat(line, ":");*/
+       trim_string(info3->configfile, "\\print$\\WIN40\\0\\", 0);
        pstrcat(line, info3->configfile);
     pstrcat(line, ":");
+       trim_string(info3->datafile, "\\print$\\WIN40\\0\\", 0);
        pstrcat(line, info3->datafile);
     pstrcat(line, ":");
+       trim_string(info3->helpfile, "\\print$\\WIN40\\0\\", 0);
        pstrcat(line, info3->helpfile);
     pstrcat(line, ":");
+       trim_string(info3->monitorname, "\\print$\\WIN40\\0\\", 0);
        pstrcat(line, info3->monitorname);
     pstrcat(line, ":");
        pstrcat(line, "RAW");                /*info3->defaultdatatype);*/
@@ -766,6 +780,7 @@ uint32 get_a_printer_driver_9x_compatible(pstring line, fstring model)
        for (i=0; info3->dependentfiles &&
                 *info3->dependentfiles[i]; i++) {
                if (i) pstrcat(line, ",");               /* don't end in a "," */
+               trim_string(info3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
                pstrcat(line, info3->dependentfiles[i]);
        }
        
@@ -969,7 +984,7 @@ static uint32 add_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
 
  again:        
        len = 0;
-       len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffffffff",
+       len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
                        info->attributes,
                        info->priority,
                        info->default_priority,
@@ -1367,7 +1382,7 @@ static uint32 get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
        fstrcpy(info.printername, sharename);
        fstrcpy(info.portname, sharename);
        fstrcpy(info.drivername, lp_printerdriver(snum));
-       fstrcpy(info.comment, "");
+       pstrcpy(info.comment, "");
        fstrcpy(info.printprocessor, "winprint");
        fstrcpy(info.datatype, "RAW");
 
@@ -1428,7 +1443,7 @@ static uint32 get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
        if (!dbuf.dptr) return 1;
 #endif
 
-       len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffffffff",
+       len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
                        &info.attributes,
                        &info.priority,
                        &info.default_priority,
index bf36b5b3467bba42b20cd2764a99795014390f49..71806e422e200f587fe18d74faac4176b94cb882 100644 (file)
@@ -867,7 +867,7 @@ BOOL prs_uint16_post(char *name, prs_struct *ps, int depth, uint16 *data16,
 BOOL prs_uint32_pre(char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
 {
        *offset = ps->data_offset;
-       if (UNMARSHALLING(ps)) {
+       if (UNMARSHALLING(ps) && (data32 != NULL)) {
                /* reading. */
                return prs_uint32(name, ps, depth, data32);
        } else {
index 2adfc65eeb8a973336354dcca762a96c77c77d75..d0a745d095ddf35c1b5a89b87d2f169a6c1d468a 100644 (file)
@@ -1778,7 +1778,7 @@ BOOL new_smb_io_printer_info_2(char *desc, NEW_BUFFER *buffer, PRINTER_INFO_2 *i
 {
        uint32 sec_offset;
        prs_struct *ps=&buffer->prs;
-       int i = 0;
+       uint32 dummy = 0;
 
        prs_debug(ps, depth, desc, "new_smb_io_printer_info_2");
        depth++;        
@@ -1814,7 +1814,7 @@ BOOL new_smb_io_printer_info_2(char *desc, NEW_BUFFER *buffer, PRINTER_INFO_2 *i
                return False;
 
 #if 1 /* JFMTEST */
-       if (!prs_uint32_pre("secdesc_ptr ", ps, depth, &i, &sec_offset))
+       if (!prs_uint32_pre("secdesc_ptr ", ps, depth, &dummy, &sec_offset))
                return False;
 #else
        if (!new_smb_io_relsecdesc("secdesc", buffer, depth, &info->secdesc))
index c9d81e1cba4356250c9c8c6a6a1ddb3db3bf7dd2..b675175544a8fbc76a6adb0866041660b072e7ca 100644 (file)
 extern int DEBUGLEVEL;
 extern pstring global_myname;
 
+#ifndef SAMBA_PRINTER_PORT_NAME
+#define SAMBA_PRINTER_PORT_NAME "Samba Printer Port"
+#endif
+
 #ifndef MAX_OPEN_PRINTER_EXS
 #define MAX_OPEN_PRINTER_EXS 50
 #endif
@@ -217,6 +221,45 @@ static BOOL delete_printer_handle(POLICY_HND *hnd)
                return False;
        }
 
+       if (*lp_deleteprinter_cmd()) {
+
+               pid_t local_pid = sys_getpid();
+               char *cmd = lp_deleteprinter_cmd();
+               char *path;
+               pstring tmp_file;
+               pstring command;
+               int ret;
+               int i;
+
+               if (*lp_pathname(lp_servicenumber(PRINTERS_NAME)))
+                       path = lp_pathname(lp_servicenumber(PRINTERS_NAME));
+               else
+                       path = tmpdir();
+               
+               /* Printer->dev.handlename equals portname equals sharename */
+               slprintf(command, sizeof(command), "%s \"%s\"", cmd,
+                                       Printer->dev.handlename);
+               slprintf(tmp_file, sizeof(tmp_file), "%s/smbcmd.%d", path, local_pid);
+
+               unlink(tmp_file);
+               DEBUG(10,("Running [%s > %s]\n", command,tmp_file));
+               ret = smbrun(command, tmp_file, False);
+               if (ret != 0) {
+                       unlink(tmp_file);
+                       return False;
+               }
+               DEBUGADD(10,("returned [%d]\n", ret));
+               DEBUGADD(10,("Unlinking output file [%s]\n", tmp_file));
+               unlink(tmp_file);
+
+               if ( ( i = lp_servicenumber( Printer->dev.handlename ) ) >= 0 ) {
+                       lp_remove_service( i );
+                       lp_killservice( i );
+                       return True;
+               } else
+                       return False;
+       }
+
        return True;
 }      
 
@@ -3204,7 +3247,7 @@ static uint32 update_printer(POLICY_HND *handle, uint32 level,
         */
 
        if (!check_printer_ok(printer->info_2, snum)) {
-               result = ERROR_ACCESS_DENIED;
+               result = ERROR_INVALID_PARAMETER;
                goto done;
        }
 
@@ -3914,46 +3957,71 @@ static void fill_port_2(PORT_INFO_2 *port, char *name)
 ****************************************************************************/
 static uint32 enumports_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
-       int n_services=lp_numservices();
-       int snum;
-       int i=0;
-       
        PORT_INFO_1 *ports=NULL;
+       int i=0;
 
-       for (snum=0; snum<n_services; snum++)
-               if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
-                       (*returned)++;
+       if (*lp_enumports_cmd()) {
+               pid_t local_pid = sys_getpid();
+               char *cmd = lp_enumports_cmd();
+               char *path;
+               char **qlines;
+               pstring tmp_file;
+               pstring command;
+               int numlines;
+               int ret;
+
+               if (*lp_pathname(lp_servicenumber(PRINTERS_NAME)))
+                       path = lp_pathname(lp_servicenumber(PRINTERS_NAME));
+               else
+                       path = tmpdir();
+
+               slprintf(tmp_file, sizeof(tmp_file), "%s/smbcmd.%d", path, local_pid);
+               slprintf(command, sizeof(command), "%s \"%d\"", cmd, 1);
+
+               unlink(tmp_file);
+               DEBUG(10,("Running [%s > %s]\n", command,tmp_file));
+               ret = smbrun(command, tmp_file, False);
+               DEBUG(10,("Returned [%d]\n", ret));
+               if (ret != 0) {
+                       unlink(tmp_file);
+                       // Is this the best error to return here?
+                       return ERROR_ACCESS_DENIED;
+               }
 
-       if((ports=(PORT_INFO_1 *)malloc( (*returned+1) * sizeof(PORT_INFO_1) )) == NULL)
-               return ERROR_NOT_ENOUGH_MEMORY;
-       
-       for (snum=0; snum<n_services; snum++) {
-               if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
-                       /*
-                        * Ensure this port name is unique.
-                        */
-                       int j;
+               numlines = 0;
+               qlines = file_lines_load(tmp_file, &numlines);
+               DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+               DEBUGADD(10,("Line[0] = [%s]\n", qlines[0]));
+               DEBUGADD(10,("Unlinking port file [%s]\n", tmp_file));
+               unlink(tmp_file);
+
+               if(numlines) {
+                       if((ports=(PORT_INFO_1 *)malloc( numlines * sizeof(PORT_INFO_1) )) == NULL) {
+                               DEBUG(10,("Returning ERROR_NOT_ENOUGH_MEMORY [%x]\n", ERROR_NOT_ENOUGH_MEMORY));
+                               file_lines_free(qlines);
+                               return ERROR_NOT_ENOUGH_MEMORY;
+                       }
 
-                       DEBUG(10,("enumports_level_1: port name %s\n", PRINTERNAME(snum)));
+                       for (i=0; i<numlines; i++) {
+                               DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
+                               fill_port_1(&ports[i], qlines[i]);
+                       }
 
-                       for(j = 0; j < i; j++) {
-                               fstring port_name;
-                               unistr_to_dos(port_name, (const char *)&ports[j].port_name.buffer[0], sizeof(port_name));
+                       file_lines_free(qlines);
+               }
 
-                               if (strequal(port_name, PRINTERNAME(snum)))
-                                       break;
-                       }
+               *returned = numlines;
 
-                       if (j < i)
-                               continue;
+       } else {
+               *returned = 1; /* Sole Samba port returned. */
 
-                       DEBUGADD(6,("Filling port number [%d]\n", i));
-                       fill_port_1(&ports[i], PRINTERNAME(snum));
-                       i++;
-               }
-       }
+               if((ports=(PORT_INFO_1 *)malloc( sizeof(PORT_INFO_1) )) == NULL)
+                       return ERROR_NOT_ENOUGH_MEMORY;
+       
+               DEBUG(10,("enumports_level_1: port name %s\n", SAMBA_PRINTER_PORT_NAME));
 
-       *returned = i;
+               fill_port_1(&ports[0], SAMBA_PRINTER_PORT_NAME);
+       }
 
        /* check the required size. */
        for (i=0; i<*returned; i++) {
@@ -3988,46 +4056,72 @@ static uint32 enumports_level_1(NEW_BUFFER *buffer, uint32 offered, uint32 *need
 
 static uint32 enumports_level_2(NEW_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
 {
-       int n_services=lp_numservices();
-       int snum;
-       int i=0;
-       
        PORT_INFO_2 *ports=NULL;
+       int i=0;
 
-       for (snum=0; snum<n_services; snum++)
-               if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
-                       (*returned)++;
+       if (*lp_enumports_cmd()) {
+               pid_t local_pid = sys_getpid();
+               char *cmd = lp_enumports_cmd();
+               char *path;
+               char **qlines;
+               pstring tmp_file;
+               pstring command;
+               int numlines;
+               int ret;
+
+               if (*lp_pathname(lp_servicenumber(PRINTERS_NAME)))
+                       path = lp_pathname(lp_servicenumber(PRINTERS_NAME));
+               else
+                       path = tmpdir();
+
+               slprintf(tmp_file, sizeof(tmp_file), "%s/smbcmd.%d", path, local_pid);
+               slprintf(command, sizeof(command), "%s \"%d\"", cmd, 2);
+
+               unlink(tmp_file);
+               DEBUG(10,("Running [%s > %s]\n", command,tmp_file));
+               ret = smbrun(command, tmp_file, False);
+               DEBUGADD(10,("returned [%d]\n", ret));
+               if (ret != 0) {
+                       unlink(tmp_file);
+                       // Is this the best error to return here?
+                       return ERROR_ACCESS_DENIED;
+               }
 
-       if((ports=(PORT_INFO_2 *)malloc( (*returned+1) * sizeof(PORT_INFO_2) )) == NULL)
-               return ERROR_NOT_ENOUGH_MEMORY;
-       
-       for (snum=0; snum<n_services; snum++) {
-               if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
-                       /*
-                        * Ensure this port name is unique.
-                        */
-                       int j;
+               numlines = 0;
+               qlines = file_lines_load(tmp_file, &numlines);
+               DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+               DEBUGADD(10,("Line[0] = [%s]\n", qlines[0]));
+               DEBUGADD(10,("Unlinking port file [%s]\n", tmp_file));
+               unlink(tmp_file);
+
+               if(numlines) {
+                       if((ports=(PORT_INFO_2 *)malloc( numlines * sizeof(PORT_INFO_2) )) == NULL) {
+                               DEBUG(10,("Returning ERROR_NOT_ENOUGH_MEMORY [%x]\n", ERROR_NOT_ENOUGH_MEMORY));
+                               file_lines_free(qlines);
+                               return ERROR_NOT_ENOUGH_MEMORY;
+                       }
 
-                       DEBUG(10,("enumports_level_2: port name %s\n", PRINTERNAME(snum)));
+                       for (i=0; i<numlines; i++) {
+                               DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
+                               fill_port_2(&(ports[i]), qlines[i]);
+                       }
 
-                       for(j = 0; j < i; j++) {
-                               fstring port_name;
-                               unistr_to_dos(port_name, (const char *)&ports[j].port_name.buffer[0], sizeof(port_name));
+                       file_lines_free(qlines);
+               }
 
-                               if (strequal(port_name, PRINTERNAME(snum)))
-                                       break;
-                       }
+               *returned = numlines;
 
-                       if (j < i)
-                               continue;
+       } else {
 
-                       DEBUGADD(6,("Filling port number [%d]\n", i));
-                       fill_port_2(&ports[i], PRINTERNAME(snum));
-                       i++;
-               }
-       }
+               *returned = 1;
+
+               if((ports=(PORT_INFO_2 *)malloc( sizeof(PORT_INFO_2) )) == NULL)
+                       return ERROR_NOT_ENOUGH_MEMORY;
+       
+               DEBUG(10,("enumports_level_2: port name %s\n", SAMBA_PRINTER_PORT_NAME));
 
-       *returned = i;
+               fill_port_2(&ports[0], SAMBA_PRINTER_PORT_NAME);
+       }
 
        /* check the required size. */
        for (i=0; i<*returned; i++) {
@@ -4081,6 +4175,68 @@ uint32 _spoolss_enumports( UNISTR2 *name, uint32 level,
        }
 }
 
+/****************************************************************************
+****************************************************************************/
+static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
+{
+       pid_t local_pid = sys_getpid();
+       char *cmd = lp_addprinter_cmd();
+       char *path;
+       char **qlines;
+       pstring tmp_file;
+       pstring command;
+       pstring driverlocation;
+       int numlines;
+       int ret;
+
+       if (*lp_pathname(lp_servicenumber(PRINTERS_NAME)))
+               path = lp_pathname(lp_servicenumber(PRINTERS_NAME));
+       else
+               path = tmpdir();
+
+       /* build driver path... only 9X architecture is needed for legacy reasons */
+       slprintf(driverlocation, sizeof(driverlocation)-1, "\\\\%s\\print$\\WIN40\\0",
+                       global_myname);
+       /* change \ to \\ for the shell */
+       all_string_sub(driverlocation,"\\","\\\\",sizeof(pstring));
+       
+       slprintf(tmp_file, sizeof(tmp_file), "%s/smbcmd.%d", path, local_pid);
+       slprintf(command, sizeof(command), "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
+                       cmd, printer->info_2->printername, printer->info_2->sharename,
+                       printer->info_2->portname, printer->info_2->drivername,
+                       printer->info_2->location, driverlocation);
+
+       unlink(tmp_file);
+       DEBUG(10,("Running [%s > %s]\n", command,tmp_file));
+       ret = smbrun(command, tmp_file, False);
+       DEBUGADD(10,("returned [%d]\n", ret));
+
+       if ( ret != 0 ) {
+               unlink(tmp_file);
+               free_a_printer(&printer,2);
+               return False;
+       }
+
+       numlines = 0;
+       qlines = file_lines_load(tmp_file, &numlines);
+       DEBUGADD(10,("Lines returned = [%d]\n", numlines));
+       DEBUGADD(10,("Line[0] = [%s]\n", qlines[0]));
+       DEBUGADD(10,("Unlinking port file [%s]\n", tmp_file));
+       unlink(tmp_file);
+
+       if(numlines) {
+               // Set the portname to what the script says the portname should be
+               strncpy(printer->info_2->portname, qlines[0], sizeof(printer->info_2->portname));
+
+               // Send SIGHUP to process group... is there a better way?
+               kill(0, SIGHUP);
+               add_all_printers();
+       }
+
+       file_lines_free(qlines);
+       return True;
+}
+
 /****************************************************************************
 ****************************************************************************/
 static uint32 spoolss_addprinterex_level_2( const UNISTR2 *uni_srv_name,
@@ -4091,7 +4247,6 @@ static uint32 spoolss_addprinterex_level_2( const UNISTR2 *uni_srv_name,
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        fstring name;
-       fstring share_name;
        int snum;
 
        if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
@@ -4104,11 +4259,14 @@ static uint32 spoolss_addprinterex_level_2( const UNISTR2 *uni_srv_name,
        /* convert from UNICODE to ASCII - this allocates the info_2 struct inside *printer.*/
        convert_printer_info(info, printer, 2);
 
-       unistr2_to_ascii(share_name, &info->info_2->sharename, sizeof(share_name)-1);
+       if (*lp_addprinter_cmd() )
+               if ( !add_printer_hook(printer) )
+                       return ERROR_ACCESS_DENIED;
        
-       slprintf(name, sizeof(name)-1, "\\\\%s\\%s", global_myname, share_name);
+       slprintf(name, sizeof(name)-1, "\\\\%s\\%s", global_myname,
+             printer->info_2->sharename);
 
-       if ((snum = print_queue_snum(share_name)) == -1) {
+       if ((snum = print_queue_snum(printer->info_2->sharename)) == -1) {
                free_a_printer(&printer,2);
                return ERROR_ACCESS_DENIED;
        }
@@ -4119,7 +4277,7 @@ static uint32 spoolss_addprinterex_level_2( const UNISTR2 *uni_srv_name,
 
        if (!check_printer_ok(printer->info_2, snum)) {
                free_a_printer(&printer,2);
-               return ERROR_ACCESS_DENIED;
+               return ERROR_INVALID_PARAMETER;
        }
 
        /* write the ASCII on disk */
@@ -4130,7 +4288,7 @@ static uint32 spoolss_addprinterex_level_2( const UNISTR2 *uni_srv_name,
 
        if (!open_printer_hnd(handle, name)) {
                /* Handle open failed - remove addition. */
-               del_a_printer(share_name);
+               del_a_printer(printer->info_2->sharename);
                free_a_printer(&printer,2);
                return ERROR_ACCESS_DENIED;
        }
index 6cb63f18f77c2d2aad9b025a58e8610a2e081d49..ab2fd4d55ddeb6883f3a1ae66bbfc08c1313c9db 100644 (file)
@@ -495,11 +495,10 @@ static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
                                print_status_struct* status)
 {
        int i;
-       BOOL ok = False;
+       BOOL ok;
        pstring tok,driver,datafile,langmon,helpfile,datatype;
        char *p;
-       char **lines;
-       char *line = NULL;
+       char **lines = NULL;
        pstring gen_line;
        
        /*
@@ -512,23 +511,18 @@ static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
         p = gen_line;
                DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", lp_printerdriver(snum), gen_line));
     } else {
-               /* didn't find driver in tdb either... oh well */
-               DEBUG(10,("9x driver not found in tdb\n"));
-       }
+               /* didn't find driver in tdb */
 
        DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n",
                          snum, lp_printerdriver(snum), lp_driverfile(snum)));
 
        lines = file_lines_load(lp_driverfile(snum),NULL);
-
        if (!lines) {
-               DEBUG(3,("fill_printq_info: Can't open %s - %s\n",
-                        lp_driverfile(snum),strerror(errno)));
+                       DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
                desc->errcode=NERR_notsupported;
                return;
        } else {
-               /* lookup the long printer driver name in the file
-                       description */
+                       /* lookup the long printer driver name in the file description */
                for (i=0;lines[i] && !ok;i++) {
                        p = lines[i];
                        if (next_token(&p,tok,":",sizeof(tok)) &&
@@ -537,16 +531,10 @@ static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
                                ok = True;
                }
        }
+       }
 
-       if (!ok)
-               goto err;
-
-       if ((line = strdup(p)) == NULL)
-               goto err;
-
-       p = line;
-       file_lines_free(lines);
-       
+       if (ok)
+       {
        /* driver file name */
        if (!next_token(&p,driver,":",sizeof(driver)))
                goto err;
@@ -588,9 +576,11 @@ static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
        PACKS(desc,"z",datatype);                        /* default data type */
        PACKS(desc,"z",helpfile);                  /* helpfile name */
        PACKS(desc,"z",driver);                    /* driver name */
+               DEBUG(3,("lp_printerdriver:%s:\n",lp_printerdriver(snum)));
        DEBUG(3,("Driver:%s:\n",driver));
        DEBUG(3,("Data File:%s:\n",datafile));
        DEBUG(3,("Language Monitor:%s:\n",langmon));
+               DEBUG(3,("lp_driverlocation:%s:\n",lp_driverlocation(snum)));
        DEBUG(3,("Data Type:%s:\n",datatype));
        DEBUG(3,("Help File:%s:\n",helpfile));
        PACKI(desc,"N",count);                     /* number of files to copy */
@@ -607,15 +597,16 @@ static void fill_printq_info_52(connection_struct *conn, int snum, int uLevel,
        DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",
                 SERVICE(snum),count));
 
-       free(line);
+        desc->errcode=NERR_Success;
+               file_lines_free(lines);
        return;
+       }
 
   err:
 
        DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
        desc->errcode=NERR_notsupported;
-       if (line)
-               free(line);
+       file_lines_free(lines); 
 }
 
 
@@ -697,64 +688,67 @@ static void fill_printq_info(connection_struct *conn, int snum, int uLevel,
 /* This function returns the number of files for a given driver */
 static int get_printerdrivernumber(int snum)
 {
-       int i=0,ok=0;
+       int i;
+       BOOL ok;
        pstring tok;
        char *p;
-       char **lines, *line;
+       char **lines = NULL;
        pstring gen_line;
 
+       /*
+        * Check in the tdb *first* before checking the legacy
+        * files. This allows an NT upload to take precedence over
+        * the existing fileset. JRA.
+        */
+       
+       if ((ok = get_a_printer_driver_9x_compatible(gen_line, lp_printerdriver(snum))) == True ) {
+               p = gen_line;
+               DEBUG(10,("9x compatable driver line for [%s]: [%s]\n", lp_printerdriver(snum), gen_line));
+       } else {
+               /* didn't find driver in tdb */
+       
        DEBUG(10,("snum: %d\nlp_printerdriver: [%s]\nlp_driverfile: [%s]\n",
                          snum, lp_printerdriver(snum), lp_driverfile(snum)));
+               
        lines = file_lines_load(lp_driverfile(snum), NULL);
        if (!lines) {
-               DEBUG(3,("get_printerdrivernumber: Can't open %s - %s\n",
-                        lp_driverfile(snum),strerror(errno)));
+                       DEBUG(3,("Can't open %s - %s\n", lp_driverfile(snum),strerror(errno)));
        }
        else
        {
-               /* lookup the long printer driver name in the file
-                  description */
+                       /* lookup the long printer driver name in the file description */
                for (i=0;lines[i] && !ok;i++) {
                p = lines[i];
                if (next_token(&p,tok,":",sizeof(tok)) &&
                                (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
                    (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum))))) 
-                       ok=1;
+                                       ok = True;
        }
-       }
-
-       if( !ok ) {
-               /* no printers.def, or driver not found, check the NT driver tdb */
-               if ((ok = get_a_printer_driver_9x_compatible(gen_line, lp_printerdriver(snum)))==True ) {
-               p = gen_line;
-                       DEBUG(10,("9x compatable driver line for [%s]: [%s]\n",
-                                         lp_printerdriver(snum), gen_line));
-           } else {
-                       /* didn't find driver in tdb either... oh well */
-                       DEBUG(10,("9x driver not found in tdb\n"));
-                   return (0);
                }
        }
-       line = strdup(p);
-       p = line;
-       file_lines_free(lines);
        
-       if (ok) {
+       if( ok ) {
                /* skip 5 fields */
                i = 5;
                while (*p && i) {
                        if (*p++ == ':') i--;
                }
                if (!*p || i)
-                       return(0);
+                       goto err;
                
                /* count the number of files */
                while (next_token(&p,tok,",",sizeof(tok)))
                        i++;
-       }
-       free(line);
        
+               file_lines_free(lines);
        return(i);
+       }
+
+  err:
+
+       DEBUG(3,("Can't determine number of printer driver files\n"));
+       file_lines_free(lines);
+       return (0);
 }
 
 static BOOL api_DosPrintQGetInfo(connection_struct *conn,
index 3e973337b9c72b6eefbd2ac505a9bf01c140a61e..e426aa51cd958acd5709753e55bdf3a9dd99d045 100644 (file)
@@ -136,6 +136,14 @@ size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
                                SIVAL(buf, 0, d);
                        }
                        break;
+               case 'P':
+                       s = va_arg(ap,char *);
+                       w = strlen(s);
+                       len = w + 1;
+                       if (bufsize >= len) {
+                               memcpy(buf, s, len);
+                       }
+                       break;
                case 'f':
                        s = va_arg(ap,char *);
                        w = strlen(s);
@@ -211,6 +219,12 @@ int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
                        if (bufsize < len) goto no_space;
                        *p = (void *)IVAL(buf, 0);
                        break;
+               case 'P':
+                       s = va_arg(ap,char *);
+                       len = strlen(buf) + 1;
+                       if (bufsize < len || len > sizeof(pstring)) goto no_space;
+                       memcpy(s, buf, len);
+                       break;
                case 'f':
                        s = va_arg(ap,char *);
                        len = strlen(buf) + 1;