Prefix VFS API macros with SMB_ for consistency and to avoid problems with VFS_ macro...
[tprouty/samba.git] / source / printing / nt_printing.c
index 222619032332e2ce612ff9ace62eca3fb84c165c..389628fd86f8deb79e2dfc0e056bd4f368426b44 100644 (file)
@@ -3,7 +3,7 @@
  *  RPC Pipe client / server routines
  *  Copyright (C) Andrew Tridgell              1992-2000,
  *  Copyright (C) Jean François Micouleau      1998-2000.
- *  Copyright (C) Gerald Carter                     2002.
+ *  Copyright (C) Gerald Carter                2002-2003.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -77,7 +77,7 @@ STANDARD_MAPPING printserver_std_mapping = {
 forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
 array index). Letter is always first, so (for the current code) additions
 always put things in the correct order. */
-static nt_forms_struct default_forms[] = {
+static const nt_forms_struct default_forms[] = {
        {"Letter",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
        {"Letter Small",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
        {"Tabloid",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
@@ -198,6 +198,22 @@ static nt_forms_struct default_forms[] = {
        {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
 };
 
+struct table_node {
+       const char      *long_archi;
+       const char      *short_archi;
+       int     version;
+};
+static const 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 }
+};
+
 static BOOL upgrade_to_version_3(void)
 {
        TDB_DATA kbuf, newkey, dbuf;
@@ -212,10 +228,12 @@ static BOOL upgrade_to_version_3(void)
                if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
                        DEBUG(0,("upgrade_to_version_3:moving form\n"));
                        if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
+                               SAFE_FREE(dbuf.dptr);
                                DEBUG(0,("upgrade_to_version_3: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
                                return False;
                        }
                        if (tdb_delete(tdb_drivers, kbuf) != 0) {
+                               SAFE_FREE(dbuf.dptr);
                                DEBUG(0,("upgrade_to_version_3: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
                                return False;
                        }
@@ -224,10 +242,12 @@ static BOOL upgrade_to_version_3(void)
                if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
                        DEBUG(0,("upgrade_to_version_3:moving printer\n"));
                        if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
+                               SAFE_FREE(dbuf.dptr);
                                DEBUG(0,("upgrade_to_version_3: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
                                return False;
                        }
                        if (tdb_delete(tdb_drivers, kbuf) != 0) {
+                               SAFE_FREE(dbuf.dptr);
                                DEBUG(0,("upgrade_to_version_3: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
                                return False;
                        }
@@ -236,10 +256,12 @@ static BOOL upgrade_to_version_3(void)
                if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
                        DEBUG(0,("upgrade_to_version_3:moving secdesc\n"));
                        if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
+                               SAFE_FREE(dbuf.dptr);
                                DEBUG(0,("upgrade_to_version_3: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
                                return False;
                        }
                        if (tdb_delete(tdb_drivers, kbuf) != 0) {
+                               SAFE_FREE(dbuf.dptr);
                                DEBUG(0,("upgrade_to_version_3: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
                                return False;
                        }
@@ -252,17 +274,19 @@ static BOOL upgrade_to_version_3(void)
 }
 
 /****************************************************************************
- Open the NT printing tdb.
+ Open the NT printing tdbs. Done once before fork().
 ****************************************************************************/
 
 BOOL nt_printing_init(void)
 {
        static pid_t local_pid;
-       char *vstring = "INFO/version";
+       const char *vstring = "INFO/version";
 
        if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid())
                return True;
  
+       if (tdb_drivers)
+               tdb_close(tdb_drivers);
        tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
        if (!tdb_drivers) {
                DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
@@ -270,6 +294,8 @@ BOOL nt_printing_init(void)
                return False;
        }
  
+       if (tdb_printers)
+               tdb_close(tdb_printers);
        tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
        if (!tdb_printers) {
                DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
@@ -277,6 +303,8 @@ BOOL nt_printing_init(void)
                return False;
        }
  
+       if (tdb_forms)
+               tdb_close(tdb_forms);
        tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
        if (!tdb_forms) {
                DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
@@ -553,8 +581,9 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
 }
 
 /****************************************************************************
- delete a named form struct
+ Delete a named form struct.
 ****************************************************************************/
+
 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
 {
        pstring key;
@@ -591,8 +620,9 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR
 }
 
 /****************************************************************************
-update a form struct
+ Update a form struct.
 ****************************************************************************/
+
 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
 {
        int n=0;
@@ -600,8 +630,7 @@ void update_a_form(nt_forms_struct **list, const FORM *form, int count)
        unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
 
        DEBUG(106, ("[%s]\n", form_name));
-       for (n=0; n<count; n++)
-       {
+       for (n=0; n<count; n++) {
                DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
                if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
                        break;
@@ -619,25 +648,26 @@ void update_a_form(nt_forms_struct **list, const FORM *form, int count)
 }
 
 /****************************************************************************
-get the nt drivers list
-
-traverse the database and look-up the matching names
+ Get the nt drivers list.
+ Traverse the database and look-up the matching names.
 ****************************************************************************/
-int get_ntdrivers(fstring **list, char *architecture, uint32 version)
+int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
 {
        int total=0;
-       fstring short_archi;
+       const char *short_archi;
        fstring *fl;
        pstring key;
        TDB_DATA kbuf, newkey;
 
-       get_short_archi(short_archi, architecture);
+       short_archi = get_short_archi(architecture);
        slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
 
        for (kbuf = tdb_firstkey(tdb_drivers);
             kbuf.dptr;
             newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
-               if (strncmp(kbuf.dptr, key, strlen(key)) != 0) continue;
+
+               if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
+                       continue;
                
                if((fl = Realloc(*list, sizeof(fstring)*(total+1))) == NULL) {
                        DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
@@ -656,43 +686,29 @@ int get_ntdrivers(fstring **list, char *architecture, uint32 version)
 function to do the mapping between the long architecture name and
 the short one.
 ****************************************************************************/
-BOOL get_short_archi(char *short_archi, char *long_archi)
+const char *get_short_archi(const char *long_archi)
 {
-       struct table {
-               char *long_archi;
-               char *short_archi;
-       };
-       
-       struct table archi_table[]=
-       {
-               {"Windows 4.0",          "WIN40"    },
-               {"Windows NT x86",       "W32X86"   },
-               {"Windows NT R4000",     "W32MIPS"  },
-               {"Windows NT Alpha_AXP", "W32ALPHA" },
-               {"Windows NT PowerPC",   "W32PPC"   },
-               {NULL,                   ""         }
-       };
-       
-       int i=-1;
-
-       DEBUG(107,("Getting architecture dependant directory\n"));
-       do {
-               i++;
-       } while ( (archi_table[i].long_archi!=NULL ) &&
-                 StrCaseCmp(long_archi, archi_table[i].long_archi) );
+        int i=-1;
 
-       if (archi_table[i].long_archi==NULL) {
-               DEBUGADD(107,("Unknown architecture [%s] !\n", long_archi));
-               return False;
-       }
+        DEBUG(107,("Getting architecture dependant directory\n"));
+        do {
+                i++;
+        } while ( (archi_table[i].long_archi!=NULL ) &&
+                  StrCaseCmp(long_archi, archi_table[i].long_archi) );
 
-       StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
+        if (archi_table[i].long_archi==NULL) {
+                DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
+                return NULL;
+        }
 
-       DEBUGADD(108,("index: [%d]\n", i));
-       DEBUGADD(108,("long architecture: [%s]\n", long_archi));
-       DEBUGADD(108,("short architecture: [%s]\n", short_archi));
-       
-       return True;
+       /* this might be client code - but shouldn't this be an fstrcpy etc? */
+
+
+        DEBUGADD(108,("index: [%d]\n", i));
+        DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
+        DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
+
+       return archi_table[i].short_archi;
 }
 
 /****************************************************************************
@@ -730,7 +746,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
        }
 
        /* Skip OEM header (if any) and the DOS stub to start of Windows header */
-       if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
+       if (SMB_VFS_LSEEK(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
                DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
                                fname, errno));
                /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
@@ -790,7 +806,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
                                }
 
                                /* Seek to the start of the .rsrc section info */
-                               if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
+                               if (SMB_VFS_LSEEK(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
                                        DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
                                                        fname, errno));
                                        goto error_exit;
@@ -883,7 +899,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
                                 * twice, as it is simpler to read the code. */
                                if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
                                        /* Compute skip alignment to next long address */
-                                       int skip = -(fsp->conn->vfs_ops.lseek(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
+                                       int skip = -(SMB_VFS_LSEEK(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
                                                                 sizeof(VS_SIGNATURE)) & 3;
                                        if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
 
@@ -927,8 +943,8 @@ is no previous version, the new one is newer (obviously). If either file is
 missing the version info structure, compare the creation date (on Unix use
 the modification date). Otherwise chose the numerically larger version number.
 ****************************************************************************/
-static int file_version_is_newer(connection_struct *conn, fstring new_file,
-                                                               fstring old_file)
+
+static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
 {
        BOOL   use_version = True;
        pstring filepath;
@@ -976,7 +992,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file,
                        DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
                                         old_file));
                        use_version = False;
-                       if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit;
+                       if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
                        old_create_time = st.st_mtime;
                        DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
                }
@@ -1005,7 +1021,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file,
                        DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
                                         new_file));
                        use_version = False;
-                       if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit;
+                       if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
                        new_create_time = st.st_mtime;
                        DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
                }
@@ -1046,7 +1062,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file,
 /****************************************************************************
 Determine the correct cVersion associated with an architecture and driver
 ****************************************************************************/
-static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
+static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
                                   struct current_user *user, WERROR *perr)
 {
        int               cversion;
@@ -1055,6 +1071,7 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
        NTSTATUS          nt_status;
        pstring           driverpath;
        DATA_BLOB         null_pw;
+       fstring           res_type;
        files_struct      *fsp = NULL;
        BOOL              bad_path;
        SMB_STRUCT_STAT   st;
@@ -1078,8 +1095,9 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
 
        /* Null password is ok - we are already an authenticated user... */
        null_pw = data_blob(NULL, 0);
+       fstrcpy(res_type, "A:");
        become_root();
-       conn = make_connection_with_chdir("print$", null_pw, "A:", user->vuid, &nt_status);
+       conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
        unbecome_root();
 
        if (conn == NULL) {
@@ -1089,7 +1107,7 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
        }
 
        /* We are temporarily becoming the connection user. */
-       if (!become_user(conn, conn->vuid)) {
+       if (!become_user(conn, user->vuid)) {
                DEBUG(0,("get_correct_cversion: Can't become user!\n"));
                *perr = WERR_ACCESS_DENIED;
                return -1;
@@ -1170,7 +1188,7 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
                                                                                         struct current_user *user)
 {
-       fstring architecture;
+       const char *architecture;
        fstring new_name;
        char *p;
        int i;
@@ -1210,7 +1228,7 @@ static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri
                }
        }
 
-       get_short_archi(architecture, driver->environment);
+       architecture = get_short_archi(driver->environment);
        
        /* jfm:7/16/2000 the client always sends the cversion=0.
         * The server should check which version the driver is by reading
@@ -1234,7 +1252,7 @@ static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri
 ****************************************************************************/
 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
 {
-       fstring architecture;
+       const char *architecture;
        fstring new_name;
        char *p;
        int i;
@@ -1274,7 +1292,7 @@ static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *dri
                }
        }
 
-       get_short_archi(architecture, driver->environment);
+       architecture = get_short_archi(driver->environment);
 
        /* jfm:7/16/2000 the client always sends the cversion=0.
         * The server should check which version the driver is by reading
@@ -1360,7 +1378,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
 {
        NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
        NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
-       fstring architecture;
+       const char *architecture;
        pstring new_dir;
        pstring old_name;
        pstring new_name;
@@ -1369,6 +1387,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        NTSTATUS nt_status;
        pstring inbuf;
        pstring outbuf;
+       fstring res_type;
        int ver = 0;
        int i;
 
@@ -1386,16 +1405,17 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                return False;
        }
 
-       get_short_archi(architecture, driver->environment);
+       architecture = get_short_archi(driver->environment);
 
        /*
         * Connect to the print$ share under the same account as the user connected to the rpc pipe.
         * Note we must be root to do this.
         */
 
-       become_root();
        null_pw = data_blob(NULL, 0);
-       conn = make_connection_with_chdir("print$", null_pw, "A:", user->vuid, &nt_status);
+       fstrcpy(res_type, "A:");
+       become_root();
+       conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
        unbecome_root();
 
        if (conn == NULL) {
@@ -1565,15 +1585,15 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
 {
        int len, buflen;
-       fstring architecture;
+       const char *architecture;
        pstring directory;
-       pstring temp_name;
+       fstring temp_name;
        pstring key;
        char *buf;
        int i, ret;
        TDB_DATA kbuf, dbuf;
 
-       get_short_archi(architecture, driver->environment);
+       architecture = get_short_archi(driver->environment);
 
        /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
         * \\server is added in the rpc server layer.
@@ -1696,7 +1716,7 @@ static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
 
 /****************************************************************************
 ****************************************************************************/
-static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring driver, fstring arch)
+static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
 {
        NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
 
@@ -1723,18 +1743,18 @@ static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **in
 
 /****************************************************************************
 ****************************************************************************/
-static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, fstring arch, uint32 version)
+static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
 {
        NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
        TDB_DATA kbuf, dbuf;
-       fstring architecture;
+       const char *architecture;
        int len = 0;
        int i;
        pstring key;
 
        ZERO_STRUCT(driver);
 
-       get_short_archi(architecture, arch);
+       architecture = get_short_archi(arch);
 
        DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
 
@@ -1759,8 +1779,7 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
                          driver.defaultdatatype);
 
        i=0;
-       while (len < dbuf.dsize) 
-       {
+       while (len < dbuf.dsize) {
                fstring *tddfs;
 
                tddfs = (fstring *)Realloc(driver.dependentfiles,
@@ -1781,8 +1800,7 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
 
        SAFE_FREE(dbuf.dptr);
 
-       if (len != dbuf.dsize) 
-       {
+       if (len != dbuf.dsize) {
                SAFE_FREE(driver.dependentfiles);
 
                return get_a_printer_driver_3_default(info_ptr, drivername, arch);
@@ -1850,7 +1868,8 @@ int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
 
        len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
 
-       if (!nt_devmode) return len;
+       if (!nt_devmode)
+               return len;
 
        len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
                        nt_devmode->devicename,
@@ -1921,15 +1940,13 @@ static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
 
        /* loop over all keys */
                
-       for ( i=0; i<data->num_keys; i++ )
-       {       
+       for ( i=0; i<data->num_keys; i++ ) {    
                val_ctr = &data->keys[i].values;
                num_values = regval_ctr_numvals( val_ctr );
                
                /* loop over all values */
                
-               for ( j=0; j<num_values; j++ )
-               {
+               for ( j=0; j<num_values; j++ ) {
                        /* pathname should be stored as <key>\<value> */
                        
                        val = regval_ctr_specific_value( val_ctr, j );
@@ -1975,7 +1992,7 @@ uint32 del_a_printer(char *sharename)
 }
 
 /* FIXME!!!  Reorder so this forward declaration is not necessary --jerry */
-static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **, fstring);
+static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **, const char* sharename);
 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **);
 /****************************************************************************
 ****************************************************************************/
@@ -2089,7 +2106,7 @@ done:
 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
 {
 
-       char adevice[32];
+       char adevice[MAXDEVICENAME];
        NT_DEVICEMODE *nt_devmode = (NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE));
 
        if (nt_devmode == NULL) {
@@ -2099,7 +2116,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
 
        ZERO_STRUCTP(nt_devmode);
 
-       safe_strcpy(adevice, default_devicename, sizeof(adevice));
+       safe_strcpy(adevice, default_devicename, sizeof(adevice)-1);
        fstrcpy(nt_devmode->devicename, adevice);       
        
        fstrcpy(nt_devmode->formname, "Letter");
@@ -2153,6 +2170,9 @@ NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
 {
        NT_DEVICEMODE *new_nt_devicemode = NULL;
 
+       if ( !nt_devicemode )
+               return NULL;
+
        if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
                DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
                return NULL;
@@ -2206,8 +2226,7 @@ static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
        /* clean up all registry keys */
        
        data = &info->data;
-       for ( i=0; i<data->num_keys; i++ ) 
-       {
+       for ( i=0; i<data->num_keys; i++ ) {
                SAFE_FREE( data->keys[i].name );
                regval_ctr_destroy( &data->keys[i].values );
        }
@@ -2295,10 +2314,10 @@ int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
 }
 
 /****************************************************************************
- allocate and initialize a new slot in 
- ***************************************************************************/
+ Allocate and initialize a new slot.
+***************************************************************************/
  
-static int add_new_printer_key( NT_PRINTER_DATA *data, char *name )
+static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
 {
        NT_PRINTER_KEY  *d;
        int             key_index;
@@ -2332,7 +2351,7 @@ static int add_new_printer_key( NT_PRINTER_DATA *data, char *name )
  search for a registry key name in the existing printer data
  ***************************************************************************/
  
-int lookup_printerkey( NT_PRINTER_DATA *data, char *name )
+int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
 {
        int             key_index = -1;
        int             i;
@@ -2344,8 +2363,7 @@ int lookup_printerkey( NT_PRINTER_DATA *data, char *name )
 
        /* loop over all existing keys */
        
-       for ( i=0; i<data->num_keys; i++ ) 
-       {
+       for ( i=0; i<data->num_keys; i++ ) {
                if ( strequal(data->keys[i].name, name) ) {
                        DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
                        key_index = i;
@@ -2360,7 +2378,7 @@ int lookup_printerkey( NT_PRINTER_DATA *data, char *name )
 /****************************************************************************
  ***************************************************************************/
 
-uint32 get_printer_subkeys( NT_PRINTER_DATA *data, char* key, fstring **subkeys )
+uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
 {
        int     i, j;
        int     key_len;
@@ -2372,10 +2390,8 @@ uint32 get_printer_subkeys( NT_PRINTER_DATA *data, char* key, fstring **subkeys
        if ( !data )
                return 0;
                
-       for ( i=0; i<data->num_keys; i++ ) 
-       {
-               if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 )
-               {
+       for ( i=0; i<data->num_keys; i++ ) {
+               if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
                        /* match sure it is a subkey and not the key itself */
                        
                        key_len = strlen( key );
@@ -2419,17 +2435,345 @@ uint32 get_printer_subkeys( NT_PRINTER_DATA *data, char* key, fstring **subkeys
        
        /* tag of the end */
        
-       fstrcpy( subkeys_ptr[num_subkeys], "" );
+       if (num_subkeys)
+               fstrcpy(subkeys_ptr[num_subkeys], "" );
        
        *subkeys = subkeys_ptr;
 
        return num_subkeys;
 }
+
+static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name, 
+                           const char *sz)
+{
+       smb_ucs2_t conv_str[1024];
+       size_t str_size;
+
+       regval_ctr_delvalue(ctr, val_name);
+       str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
+                            STR_TERMINATE | STR_NOALIGN);
+       regval_ctr_addvalue(ctr, val_name, REG_SZ, 
+                           (char *) conv_str, str_size);
+}
+
+static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name, 
+                              uint32 dword)
+{
+       regval_ctr_delvalue(ctr, val_name);
+       regval_ctr_addvalue(ctr, val_name, REG_DWORD,
+                           (char *) &dword, sizeof(dword));
+}
+
+static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+                             BOOL bool)
+{
+       uint8 bin_bool = (bool ? 1 : 0);
+       regval_ctr_delvalue(ctr, val_name);
+       regval_ctr_addvalue(ctr, val_name, REG_BINARY, 
+                           (char *) &bin_bool, sizeof(bin_bool));
+}
+
+static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+                                        const char *multi_sz)
+{
+       smb_ucs2_t *conv_strs = NULL;
+       size_t str_size;
+
+       /* a multi-sz has to have a null string terminator, i.e., the last
+          string must be followed by two nulls */
+       str_size = (strlen(multi_sz) + 2) * sizeof(smb_ucs2_t);
+       conv_strs = calloc(str_size, 1);
+
+       push_ucs2(NULL, conv_strs, multi_sz, str_size, 
+                 STR_TERMINATE | STR_NOALIGN);
+
+       regval_ctr_delvalue(ctr, val_name);
+       regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ, 
+                           (char *) conv_strs, str_size);      
+       safe_free(conv_strs);
+       
+}
+
+/****************************************************************************
+ * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
+ *
+ * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
+ * @return BOOL indicating success or failure
+ ***************************************************************************/
+
+static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
+{
+       REGVAL_CTR *ctr = NULL;
+       fstring longname;
+       char *allocated_string = NULL;
+        const char *ascii_str;
+       int i;
+
+       if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
+               i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
+       ctr = &info2->data.keys[i].values;
+
+       map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
+       map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
+
+       get_myfullname(longname);
+       map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
+
+       asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
+       map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
+       SAFE_FREE(allocated_string);
+
+       map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
+       map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
+       map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
+       map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
+       map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
+       map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
+       map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
+       map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
+       map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
+
+       map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
+                         (info2->attributes & 
+                          PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
+
+       switch (info2->attributes & 0x3) {
+       case 0:
+               ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
+               break;
+       case 1:
+               ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
+               break;
+       case 2:
+               ascii_str = SPOOL_REGVAL_PRINTDIRECT;
+               break;
+       default:
+               ascii_str = "unknown";
+       }
+       map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
+
+       return True;
+}
+
+#ifdef HAVE_ADS
+static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, GUID guid)
+{
+       int i;
+       REGVAL_CTR *ctr=NULL;
+
+       /* find the DsSpooler key */
+       if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
+               i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
+       ctr = &info2->data.keys[i].values;
+
+       regval_ctr_delvalue(ctr, "objectGUID");
+       regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY, 
+                           (char *) &guid, sizeof(GUID));      
+}
+
+static WERROR publish_it(NT_PRINTER_INFO_LEVEL *printer)
+{
+       ADS_STATUS ads_rc;
+       TALLOC_CTX *ctx = talloc_init("publish_it");
+       ADS_MODLIST mods = ads_init_mods(ctx);
+       char *prt_dn = NULL, *srv_dn, **srv_cn;
+       void *res = NULL;
+       ADS_STRUCT *ads;
+       const char *attrs[] = {"objectGUID", NULL};
+       GUID guid;
+       WERROR win_rc = WERR_OK;
+
+       ZERO_STRUCT(guid);
+       /* set the DsSpooler info and attributes */
+       if (!(map_nt_printer_info2_to_dsspooler(printer->info_2)))
+                       return WERR_NOMEM;
+       printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
+       win_rc = mod_a_printer(*printer, 2);
+       if (!W_ERROR_IS_OK(win_rc)) {
+               DEBUG(3, ("err %d saving data\n",
+                                 W_ERROR_V(win_rc)));
+               return win_rc;
+       }
+
+       /* Build the ads mods */
+       get_local_printer_publishing_data(ctx, &mods, 
+                                         &printer->info_2->data);
+       ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, 
+                   printer->info_2->sharename);
+
+       /* connect to the ADS server */
+       ads = ads_init(NULL, NULL, lp_ads_server());
+       if (!ads) {
+               DEBUG(3, ("ads_init() failed\n"));
+               return WERR_SERVER_UNAVAILABLE;
+       }
+       setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
+       SAFE_FREE(ads->auth.password);
+       ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
+                                                           NULL, NULL);
+       ads_rc = ads_connect(ads);
+       if (!ADS_ERR_OK(ads_rc)) {
+               DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
+               ads_destroy(&ads);
+               return WERR_ACCESS_DENIED;
+       }
+
+       /* figure out where to publish */
+       ads_find_machine_acct(ads, &res, global_myname());
+       srv_dn = ldap_get_dn(ads->ld, res);
+       ads_msgfree(ads, res);
+       srv_cn = ldap_explode_dn(srv_dn, 1);
+       asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], 
+                printer->info_2->sharename, srv_dn);
+       ads_memfree(ads, srv_dn);
+
+       /* publish it */
+       ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
+       if (LDAP_ALREADY_EXISTS == ads_rc.err.rc)
+               ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx,&mods);
+       
+       /* retreive the guid and store it locally */
+       if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
+               ads_memfree(ads, prt_dn);
+               ads_pull_guid(ads, res, &guid);
+               ads_msgfree(ads, res);
+               store_printer_guid(printer->info_2, guid);
+               win_rc = mod_a_printer(*printer, 2);
+       } 
+
+       safe_free(prt_dn);
+       ads_destroy(&ads);
+
+       return WERR_OK;
+}
+
+WERROR unpublish_it(NT_PRINTER_INFO_LEVEL *printer)
+{
+       ADS_STATUS ads_rc;
+       ADS_STRUCT *ads;
+       void *res;
+       char *prt_dn = NULL;
+       WERROR win_rc;
+
+       printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
+       win_rc = mod_a_printer(*printer, 2);
+       if (!W_ERROR_IS_OK(win_rc)) {
+               DEBUG(3, ("err %d saving data\n",
+                                 W_ERROR_V(win_rc)));
+               return win_rc;
+       }
+       
+       ads = ads_init(NULL, NULL, lp_ads_server());
+       if (!ads) {
+               DEBUG(3, ("ads_init() failed\n"));
+               return WERR_SERVER_UNAVAILABLE;
+       }
+       setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
+       SAFE_FREE(ads->auth.password);
+       ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
+                                                           NULL, NULL);
+       ads_rc = ads_connect(ads);
+       if (!ADS_ERR_OK(ads_rc)) {
+               DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
+               ads_destroy(&ads);
+               return WERR_ACCESS_DENIED;
+       }
+       
+       /* remove the printer from the directory */
+       ads_rc = ads_find_printer_on_server(ads, &res, 
+                           printer->info_2->sharename, global_myname());
+       if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
+               prt_dn = ads_get_dn(ads, res);
+               ads_msgfree(ads, res);
+               ads_rc = ads_del_dn(ads, prt_dn);
+               ads_memfree(ads, prt_dn);
+       }
+
+       ads_destroy(&ads);
+       return WERR_OK;
+}
+
+/****************************************************************************
+ * Publish a printer in the directory
+ *
+ * @param snum describing printer service
+ * @return WERROR indicating status of publishing
+ ***************************************************************************/
+
+WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
+{
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+       WERROR win_rc;
+
+       win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
+       if (!W_ERROR_IS_OK(win_rc))
+               return win_rc;
+
+       switch(action) {
+       case SPOOL_DS_PUBLISH:
+       case SPOOL_DS_UPDATE:
+               win_rc = publish_it(printer);
+               break;
+       case SPOOL_DS_UNPUBLISH:
+               win_rc = unpublish_it(printer);
+               break;
+       default:
+               win_rc = WERR_NOT_SUPPORTED;
+       }
+       
+
+       free_a_printer(&printer, 2);
+       return win_rc;
+}
+
+BOOL is_printer_published(Printer_entry *print_hnd, int snum, GUID *guid)
+{
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+       REGVAL_CTR *ctr;
+       REGISTRY_VALUE *guid_val;
+       WERROR win_rc;
+       int i;
+
+
+       win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
+       if (!W_ERROR_IS_OK(win_rc))
+               return False;
+
+       if (!(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
+               return False;
+
+       if ((i = lookup_printerkey(&printer->info_2->data, 
+                                  SPOOL_DSSPOOLER_KEY)) < 0)
+               return False;
+
+       if (!(ctr = &printer->info_2->data.keys[i].values)) {
+               return False;
+       }
+
+       if (!(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) {
+               return False;
+       }
+
+       if (regval_size(guid_val) == sizeof(GUID))
+               memcpy(guid, regval_data_p(guid_val), sizeof(GUID));
+
+       return True;
+}
+       
+#else
+WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
+{
+       return WERR_OK;
+}
+BOOL is_printer_published(Printer_entry *print_hnd, int snum, GUID *guid)
+{
+       return False;
+}
+#endif
 /****************************************************************************
  ***************************************************************************/
  
-WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key )
+WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
 {
        NT_PRINTER_DATA *data;
        int             i;
@@ -2444,10 +2788,8 @@ WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key )
        
        /* remove all keys */
 
-       if ( !strlen(key) ) 
-       {
-               for ( i=0; i<data->num_keys; i++ ) 
-               {
+       if ( !strlen(key) ) {
+               for ( i=0; i<data->num_keys; i++ ) {
                        DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
                                data->keys[i].name));
                
@@ -2466,10 +2808,8 @@ WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key )
 
        /* remove a specific key (and all subkeys) */
        
-       for ( i=0; i<data->num_keys; i++ ) 
-       {
-               if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 )
-               {
+       for ( i=0; i<data->num_keys; i++ ) {
+               if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
                        DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
                                data->keys[i].name));
                
@@ -2513,8 +2853,7 @@ WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key )
 
        /* sanity check to see if anything is left */
 
-       if ( !data->num_keys )
-       {
+       if ( !data->num_keys ) {
                DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
 
                SAFE_FREE( data->keys );
@@ -2527,7 +2866,7 @@ WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key )
 /****************************************************************************
  ***************************************************************************/
  
-WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value )
+WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
 {
        WERROR          result = WERR_OK;
        int             key_index;
@@ -2554,7 +2893,7 @@ WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value
 /****************************************************************************
  ***************************************************************************/
  
-WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value, 
+WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value, 
                            uint32 type, uint8 *data, int real_len )
 {
        WERROR          result = WERR_OK;
@@ -2586,7 +2925,7 @@ WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value,
 /****************************************************************************
  ***************************************************************************/
  
-REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value )
+REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
 {
        int             key_index;
 
@@ -2620,8 +2959,7 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
 
        /* loop and unpack the rest of the registry values */
        
-       while ( True ) 
-       {
+       while ( True ) {
        
                /* check to see if there are any more registry values */
                
@@ -2671,6 +3009,8 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
                
                regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, data_p, size );
 
+               SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
+
                DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
        }
 
@@ -2762,9 +3102,9 @@ static void map_to_os2_driver(fstring drivername)
 }
 
 /****************************************************************************
-get a default printer info 2 struct
+ Get a default printer info 2 struct.
 ****************************************************************************/
-static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
+static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
 {
        int snum;
        NT_PRINTER_INFO_LEVEL_2 info;
@@ -2795,7 +3135,7 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
        fstrcpy(info.printprocessor, "winprint");
        fstrcpy(info.datatype, "RAW");
 
-       info.attributes = PRINTER_ATTRIBUTE_SHARED | PRINTER_ATTRIBUTE_NETWORK;      /* attributes */
+       info.attributes = PRINTER_ATTRIBUTE_SAMBA;
 
        info.starttime = 0; /* Minutes since 12:00am GMT */
        info.untiltime = 0; /* Minutes since 12:00am GMT */
@@ -2843,7 +3183,7 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
 
 /****************************************************************************
 ****************************************************************************/
-static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
+static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
 {
        pstring key;
        NT_PRINTER_INFO_LEVEL_2 info;
@@ -2887,7 +3227,7 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
                        info.parameters);
 
        /* Samba has to have shared raw drivers. */
-       info.attributes |= (PRINTER_ATTRIBUTE_SHARED | PRINTER_ATTRIBUTE_NETWORK); 
+       info.attributes |= PRINTER_ATTRIBUTE_SAMBA;
 
        /* Restore the stripped strings. */
        slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
@@ -2905,8 +3245,7 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
         * See comments in get_a_printer_2_default()
         */
 
-       if (lp_default_devmode(lp_servicenumber(sharename)) && !info.devmode)
-       {
+       if (lp_default_devmode(lp_servicenumber(sharename)) && !info.devmode) {
                DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
                        printername));
                info.devmode = construct_nt_devicemode(printername);
@@ -2934,7 +3273,7 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
 }
 
 /****************************************************************************
-debugging function, dump at level 6 the struct in the logs
+ Debugging function, dump at level 6 the struct in the logs.
 ****************************************************************************/
 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
 {
@@ -2943,8 +3282,7 @@ static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        
        DEBUG(106,("Dumping printer at level [%d]\n", level));
        
-       switch (level)
-       {
+       switch (level) {
                case 2:
                {
                        if (printer.info_2 == NULL)
@@ -2989,26 +3327,6 @@ static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        return result;
 }
 
-/****************************************************************************
- Get the parameters we can substitute in an NT print job.
-****************************************************************************/
-
-void get_printer_subst_params(int snum, fstring *printername, fstring *sharename, fstring *portname)
-{
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-
-       **printername = **sharename = **portname = '\0';
-
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
-               return;
-
-       fstrcpy(*printername, printer->info_2->printername);
-       fstrcpy(*sharename, printer->info_2->sharename);
-       fstrcpy(*portname, printer->info_2->portname);
-
-       free_a_printer(&printer, 2);
-}
-
 /****************************************************************************
  Update the changeid time.
  This is SO NASTY as some drivers need this to change, others need it
@@ -3052,8 +3370,15 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        
        dump_a_printer(printer, level); 
        
-       switch (level)
-       {
+       /* 
+        * invalidate cache for all open handles to this printer.
+        * cache for a given handle will be updated on the next 
+        * get_a_printer() 
+        */
+        
+       invalidate_printer_hnd_cache( printer.info_2->sharename );
+       
+       switch (level) {
                case 2:
                {
                        /*
@@ -3088,6 +3413,7 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
                         */
 
                        result=update_a_printer_2(printer.info_2);
+                       
                        break;
                }
                default:
@@ -3147,8 +3473,8 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
         */
         
        if ( info.devmode ) {
-       ZERO_STRUCT(info.devmode->devicename);
-       fstrcpy(info.devmode->devicename, info_ptr->printername);
+               ZERO_STRUCT(info.devmode->devicename);
+               fstrcpy(info.devmode->devicename, info_ptr->printername);
        }
 
        /*
@@ -3192,8 +3518,7 @@ BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
 {
        BOOL result = False;
        
-       switch (level)
-       {
+       switch (level) {
                case 2:
                        result = set_driver_init_2(printer->info_2);
                        break;
@@ -3264,7 +3589,8 @@ static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
                        ret = -1;
                        goto done;
                }
-               else buf = tb;
+               else
+                       buf = tb;
                buflen = len;
                goto again;
        }
@@ -3300,13 +3626,10 @@ uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        
        dump_a_printer(printer, level); 
        
-       switch (level)
-       {
+       switch (level) {
                case 2:
-               {
                        result = update_driver_init_2(printer.info_2);
                        break;
-               }
                default:
                        result = 1;
                        break;
@@ -3375,14 +3698,13 @@ static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, ui
         */
        DEBUG(8,("save_driver_init_2: Enter...\n"));
        
-       if ( !printer->info_2->devmode && data_len ) 
-       {
+       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)
+               if ((ctx = talloc_init("save_driver_init_2")) == NULL)
                        return WERR_NOMEM;
 
                if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
@@ -3445,13 +3767,10 @@ WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *dat
 {
        WERROR status = WERR_OK;
        
-       switch (level)
-       {
+       switch (level) {
                case 2:
-               {
                        status = save_driver_init_2( printer, data, data_len );
                        break;
-               }
                default:
                        status = WERR_UNKNOWN_LEVEL;
                        break;
@@ -3460,11 +3779,80 @@ WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *dat
        return status;
 }
 
+/****************************************************************************
+ Deep copy a NT_PRINTER_DATA
+****************************************************************************/
+
+static NTSTATUS copy_printer_data( NT_PRINTER_DATA *dst, NT_PRINTER_DATA *src )
+{
+       int i, j, num_vals, new_key_index;
+       REGVAL_CTR *src_key, *dst_key;
+       
+       if ( !dst || !src )
+               return NT_STATUS_NO_MEMORY;
+       
+       for ( i=0; i<src->num_keys; i++ ) {
+                          
+               /* create a new instance of the printerkey in the destination 
+                  printer_data object */
+                  
+               new_key_index = add_new_printer_key( dst, src->keys[i].name );
+               dst_key = &dst->keys[new_key_index].values;
+
+               src_key = &src->keys[i].values;
+               num_vals = regval_ctr_numvals( src_key );
+               
+               /* dup the printer entire printer key */
+               
+               for ( j=0; j<num_vals; j++ ) {
+                       regval_ctr_copyvalue( dst_key, regval_ctr_specific_value(src_key, j) );
+               }
+       }
+               
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Deep copy a NT_PRINTER_INFO_LEVEL_2 structure using malloc()'d memeory
+ Caller must free.
+****************************************************************************/
+
+static NT_PRINTER_INFO_LEVEL_2* dup_printer_2( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2 *printer )
+{
+       NT_PRINTER_INFO_LEVEL_2 *copy;
+       
+       if ( !printer )
+               return NULL;
+       
+       if ( !(copy = (NT_PRINTER_INFO_LEVEL_2 *)malloc(sizeof(NT_PRINTER_INFO_LEVEL_2))) )
+               return NULL;
+               
+       memcpy( copy, printer, sizeof(NT_PRINTER_INFO_LEVEL_2) );
+       
+       /* malloc()'d members copied here */
+       
+       copy->devmode = dup_nt_devicemode( printer->devmode );  
+
+       ZERO_STRUCT( copy->data );
+       copy_printer_data( &copy->data, &printer->data );
+       
+       /* this is talloc()'d; very ugly that we have a structure that 
+          is half malloc()'d and half talloc()'d but that is the way 
+          that the PRINTER_INFO stuff is written right now.  --jerry  */
+          
+       copy->secdesc_buf = dup_sec_desc_buf( ctx, printer->secdesc_buf );
+               
+       return copy;
+}
+
 /****************************************************************************
  Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
 ****************************************************************************/
 
-WERROR get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring sharename)
+#define ENABLE_PRINT_HND_CACHE 1
+
+WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, 
+                       const char *sharename)
 {
        WERROR result;
        NT_PRINTER_INFO_LEVEL *printer = NULL;
@@ -3473,24 +3861,70 @@ WERROR get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring s
 
        DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
 
-       switch (level)
-       {
+       switch (level) {
                case 2:
-               {
                        if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
                                DEBUG(0,("get_a_printer: malloc fail.\n"));
                                return WERR_NOMEM;
                        }
                        ZERO_STRUCTP(printer);
+                       
+                       /* 
+                        * check for cache first.  A Printer handle cannot changed
+                        * to another printer object so we only check that the printer 
+                        * is actually for a printer and that the printer_info pointer 
+                        * is valid
+                        */
+#ifdef ENABLE_PRINT_HND_CACHE  /* JERRY */
+                       if ( print_hnd 
+                               && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER) 
+                               && print_hnd->printer_info )
+                       {
+                               if ( !(printer->info_2 = dup_printer_2(print_hnd->ctx, print_hnd->printer_info->info_2)) ) {
+                                       DEBUG(0,("get_a_printer: unable to copy cached printer info!\n"));
+                                       
+                                       SAFE_FREE(printer);
+                                       return WERR_NOMEM;
+                               }
+                               
+                               DEBUG(10,("get_a_printer: using cached copy of printer_info_2\n"));
+                               
+                               *pp_printer = printer;                          
+                               result = WERR_OK;
+                               
+                               break;
+                       }
+#endif 
+
+                       /* no cache; look it up on disk */
+                       
                        result=get_a_printer_2(&printer->info_2, sharename);
                        if (W_ERROR_IS_OK(result)) {
                                dump_a_printer(*printer, level);
+
+#if ENABLE_PRINT_HND_CACHE     /* JERRY */                                                             
+                               /* save a copy in cache */
+                               if ( print_hnd && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)) {
+                                       if ( !print_hnd->printer_info )
+                                               print_hnd->printer_info = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL));
+                                       
+                                       if ( print_hnd->printer_info ) {
+                                               print_hnd->printer_info->info_2 = dup_printer_2(print_hnd->ctx, printer->info_2);
+                                               
+                                               /* don't fail the lookup just because the cache update failed */
+                                               if ( !print_hnd->printer_info->info_2 )
+                                                       DEBUG(0,("get_a_printer: unable to copy new printer info!\n"));
+                                       }
+                                       
+                               }
+#endif
                                *pp_printer = printer;
-                       } else {
-                               SAFE_FREE(printer);
                        }
+                       else 
+                               SAFE_FREE(printer);
+       
+
                        break;
-               }
                default:
                        result=WERR_UNKNOWN_LEVEL;
                        break;
@@ -3515,21 +3949,15 @@ uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
        if (printer == NULL)
                return 0;
        
-       switch (level)
-       {
+       switch (level) {
                case 2:
-               {
-                       if (printer->info_2 != NULL)
-                       {
+                       if (printer->info_2 != NULL) {
                                free_nt_printer_info_level_2(&printer->info_2);
                                result=0;
-                       }
-                       else
-                       {
+                       } else
                                result=4;
-                       }
                        break;
-               }
+
                default:
                        result=1;
                        break;
@@ -3547,19 +3975,15 @@ uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
        DEBUG(104,("adding a printer at level [%d]\n", level));
        dump_a_printer_driver(driver, level);
        
-       switch (level)
-       {
+       switch (level) {
                case 3:
-               {
                        result=add_a_printer_driver_3(driver.info_3);
                        break;
-               }
 
                case 6:
-               {
                        result=add_a_printer_driver_6(driver.info_6);
                        break;
-               }
+
                default:
                        result=1;
                        break;
@@ -3569,13 +3993,13 @@ uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
 }
 /****************************************************************************
 ****************************************************************************/
+
 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
-                            fstring drivername, fstring architecture, uint32 version)
+                            fstring drivername, const char *architecture, uint32 version)
 {
        WERROR result;
        
-       switch (level)
-       {
+       switch (level) {
                case 3:
                        /* Sometime we just want any version of the driver */
                        
@@ -3588,8 +4012,7 @@ WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
                                        result = get_a_printer_driver_3( &driver->info_3, 
                                                        drivername, architecture, 2 );
                                }
-                       }
-                       else {
+                       } else {
                                result = get_a_printer_driver_3(&driver->info_3, drivername, 
                                        architecture, version);                         
                        }
@@ -3612,8 +4035,7 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
 {
        uint32 result;
        
-       switch (level)
-       {
+       switch (level) {
                case 3:
                {
                        NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
@@ -3624,9 +4046,7 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
                                ZERO_STRUCTP(info3);
                                SAFE_FREE(info3);
                                result=0;
-                       }
-                       else
-                       {
+                       } else {
                                result=4;
                        }
                        break;
@@ -3634,17 +4054,14 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
                case 6:
                {
                        NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
-                       if (driver.info_6 != NULL)
-                       {
+                       if (driver.info_6 != NULL) {
                                info6=driver.info_6;
                                SAFE_FREE(info6->dependentfiles);
                                SAFE_FREE(info6->previousnames);
                                ZERO_STRUCTP(info6);
                                SAFE_FREE(info6);
                                result=0;
-                       }
-                       else
-                       {
+                       } else {
                                result=4;
                        }
                        break;
@@ -3675,12 +4092,11 @@ BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
        
        /* loop through the printers.tdb and check for the drivername */
        
-       for (snum=0; snum<n_services; snum++) 
-       {
+       for (snum=0; snum<n_services; snum++) {
                if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
                        continue;
                
-               if ( !W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))) )
+               if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
                        continue;
                
                if ( !StrCaseCmp(info_3->name, printer->info_2->drivername) ) {
@@ -3727,11 +4143,9 @@ static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
        if ( !info->dependentfiles )
                return False;
        
-       while ( *info->dependentfiles[i] ) 
-       {
+       while ( *info->dependentfiles[i] ) {
                if ( strequal(file, info->dependentfiles[i]) )
                        return True;
-                       
                i++;
        }
        
@@ -3749,8 +4163,7 @@ static void trim_dependent_file( fstring files[], int idx )
        
        /* bump everything down a slot */
 
-       while( *files[idx+1] ) 
-       {
+       while( *files[idx+1] ) {
                fstrcpy( files[idx], files[idx+1] );
                idx++;
        }
@@ -3804,14 +4217,12 @@ static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
        if ( !src->dependentfiles )
                return in_use;
                
-       while ( *src->dependentfiles[i] ) 
-       {
+       while ( *src->dependentfiles[i] ) {
                if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
                        in_use = True;
                        DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
                        trim_dependent_file( src->dependentfiles, i );
-               }
-               else
+               } else
                        i++;
        }               
                
@@ -3856,15 +4267,12 @@ BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
 
        /* check each driver for overlap in files */
                
-       for (i=0; i<ndrivers; i++) 
-       {
+       for (i=0; i<ndrivers; i++) {
                DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        
                ZERO_STRUCT(driver);
                        
-               if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], 
-                       info->environment, version)) )
-               {
+               if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
                        SAFE_FREE(list);
                        return True;
                }
@@ -3872,8 +4280,7 @@ BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
                /* check if d2 uses any files from d1 */
                /* only if this is a different driver than the one being deleted */
                        
-               if ( !strequal(info->name, driver.info_3->name) )
-               {
+               if ( !strequal(info->name, driver.info_3->name) ) {
                        if ( trim_overlap_drv_files(info, driver.info_3) ) {
                                free_a_printer_driver(driver, 3);
                                SAFE_FREE( list );
@@ -3909,7 +4316,8 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
        connection_struct *conn;
        DATA_BLOB null_pw;
        NTSTATUS nt_status;
-       
+       fstring res_type;
+
        if ( !info_3 )
                return False;
                
@@ -3921,9 +4329,10 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
         * do this.
         */
         
-       become_root();
        null_pw = data_blob( NULL, 0 );
-        conn = make_connection_with_chdir( "print$", null_pw, "A:", user->vuid, &nt_status );
+       fstrcpy(res_type, "A:");
+       become_root();
+        conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
        unbecome_root();
        
        if ( !conn ) {
@@ -3971,15 +4380,13 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
        
        /* check if we are done removing files */
        
-       if ( info_3->dependentfiles )
-       {
+       if ( info_3->dependentfiles ) {
                while ( *info_3->dependentfiles[i] ) {
                        char *file;
 
                        /* bypass the "\print$" portion of the path */
                        
-                       if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL )
-                       {
+                       if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
                                DEBUG(10,("deleting dependent file [%s]\n", file));
                                unlink_internals(conn, 0, file );
                        }
@@ -4002,13 +4409,13 @@ WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct cur
                               uint32 version, BOOL delete_files )
 {
        pstring         key;
-       fstring         arch;
+       const char     *arch;
        TDB_DATA        kbuf, dbuf;
        NT_PRINTER_DRIVER_INFO_LEVEL    ctr;
 
        /* delete the tdb data first */
 
-       get_short_archi(arch, info_3->environment);
+       arch = get_short_archi(info_3->environment);
        slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
                arch, version, info_3->name);
 
@@ -4066,7 +4473,7 @@ WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
        fstring key;
        WERROR status;
 
-       mem_ctx = talloc_init();
+       mem_ctx = talloc_init("nt_printing_setsec");
        if (mem_ctx == NULL)
                return WERR_NOMEM;
 
@@ -4224,7 +4631,7 @@ BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF *
        fstring key;
        char *temp;
 
-       if ((temp = strchr(printername + 2, '\\'))) {
+       if (strlen(printername) > 2 && (temp = strchr(printername + 2, '\\'))) {
                printername = temp + 1;
        }
 
@@ -4399,7 +4806,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
        /* Always allow root or printer admins to do anything */
 
        if (user->uid == 0 ||
-           user_in_list(uidtoname(user->uid), lp_printer_admin(snum))) {
+           user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups)) {
                return True;
        }
 
@@ -4414,7 +4821,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
 
        /* Get printer security descriptor */
 
-       if(!(mem_ctx = talloc_init())) {
+       if(!(mem_ctx = talloc_init("print_access_check"))) {
                errno = ENOMEM;
                return False;
        }
@@ -4468,7 +4875,7 @@ BOOL print_time_access_check(int snum)
        struct tm *t;
        uint32 mins;
 
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
+       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))))
                return False;
 
        if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)