r8066: * had to modify the printer data storage slightly in ntprinters.tdb
[gd/samba/.git] / source / printing / nt_printing.c
index 908bd9c887fd13f275934c2c2fef5d491fd1dfbd..47e0af963344d7e7ed57e89f4206fbb85652cd50 100644 (file)
@@ -2,7 +2,7 @@
  *  Unix SMB/CIFS implementation.
  *  RPC Pipe client / server routines
  *  Copyright (C) Andrew Tridgell              1992-2000,
- *  Copyright (C) Jean François Micouleau      1998-2000.
+ *  Copyright (C) Jean François Micouleau      1998-2000.
  *  Copyright (C) Gerald Carter                2002-2003.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
 
 #include "includes.h"
 
-extern DOM_SID global_sid_World;
+extern struct current_user current_user;
 
 static TDB_CONTEXT *tdb_forms; /* used for forms files */
 static TDB_CONTEXT *tdb_drivers; /* used for driver files */
@@ -38,8 +38,9 @@ static TDB_CONTEXT *tdb_printers; /* used for printers files */
 #define NTDRIVERS_DATABASE_VERSION_1 1
 #define NTDRIVERS_DATABASE_VERSION_2 2
 #define NTDRIVERS_DATABASE_VERSION_3 3 /* little endian version of v2 */
+#define NTDRIVERS_DATABASE_VERSION_4 4 /* fix generic bits in security descriptors */
  
-#define NTDRIVERS_DATABASE_VERSION NTDRIVERS_DATABASE_VERSION_3
+#define NTDRIVERS_DATABASE_VERSION NTDRIVERS_DATABASE_VERSION_4
 
 /* Map generic permissions to printer object specific permissions */
 
@@ -209,6 +210,8 @@ struct table_node {
 #define SPL_ARCH_W32MIPS       "W32MIPS"
 #define SPL_ARCH_W32ALPHA      "W32ALPHA"
 #define SPL_ARCH_W32PPC                "W32PPC"
+#define SPL_ARCH_IA64          "IA64"
+#define SPL_ARCH_X64           "x64"
 
 static const struct table_node archi_table[]= {
 
@@ -217,6 +220,8 @@ static const struct table_node archi_table[]= {
        {"Windows NT R4000",     SPL_ARCH_W32MIPS,      2 },
        {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA,     2 },
        {"Windows NT PowerPC",   SPL_ARCH_W32PPC,       2 },
+       {"Windows IA64",         SPL_ARCH_IA64,         3 },
+       {"Windows x64",          SPL_ARCH_X64,          3 },
        {NULL,                   "",            -1 }
 };
 
@@ -279,16 +284,139 @@ static BOOL upgrade_to_version_3(void)
        return True;
 }
 
+/*******************************************************************
+ Fix an issue with security descriptors.  Printer sec_desc must 
+ use more than the generic bits that were previously used 
+ in <= 3.0.14a.  They must also have a owner and group SID assigned.
+ Otherwise, any printers than have been migrated to a Windows 
+ host using printmig.exe will not be accessible.
+*******************************************************************/
+
+static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
+                            TDB_DATA data, void *state )
+{
+       prs_struct ps;
+       SEC_DESC_BUF *sd_orig = NULL;
+       SEC_DESC_BUF *sd_new, *sd_store;
+       SEC_DESC *sec, *new_sec;
+       TALLOC_CTX *ctx = state;
+       int result, i;
+       uint32 sd_size, size_new_sec;
+       DOM_SID sid;
+
+       if (!data.dptr || data.dsize == 0)
+               return 0;
+
+       if ( strncmp( key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) != 0 )
+               return 0;
+
+       /* upgrade the security descriptor */
+
+       ZERO_STRUCT( ps );
+
+       prs_init( &ps, 0, ctx, UNMARSHALL );
+       prs_give_memory( &ps, data.dptr, data.dsize, True );
+
+       if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_orig, &ps, 1 ) ) {
+               /* delete bad entries */
+               DEBUG(0,("sec_desc_upg_fn: Failed to parse original sec_desc for %si.  Deleting....\n", key.dptr ));
+               tdb_delete( tdb_printers, key );
+               return 0;
+       }
+
+       sec = sd_orig->sec;
+               
+       /* is this even valid? */
+       
+       if ( !sec->dacl )
+               return 0;
+               
+       /* update access masks */
+       
+       for ( i=0; i<sec->dacl->num_aces; i++ ) {
+               switch ( sec->dacl->ace[i].info.mask ) {
+                       case (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS):
+                               sec->dacl->ace[i].info.mask = PRINTER_ACE_PRINT;
+                               break;
+                               
+                       case GENERIC_ALL_ACCESS:
+                               sec->dacl->ace[i].info.mask = PRINTER_ACE_FULL_CONTROL;
+                               break;
+                               
+                       case READ_CONTROL_ACCESS:
+                               sec->dacl->ace[i].info.mask = PRINTER_ACE_MANAGE_DOCUMENTS;
+                       
+                       default:        /* no change */
+                               break;
+               }
+       }
+
+       /* create a new SEC_DESC with the appropriate owner and group SIDs */
+
+       string_to_sid(&sid, "S-1-5-32-544" );
+       new_sec = make_sec_desc( ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+               &sid, &sid,
+               NULL, NULL, &size_new_sec );
+       sd_new = make_sec_desc_buf( ctx, size_new_sec, new_sec );
+
+       if ( !(sd_store = sec_desc_merge( ctx, sd_new, sd_orig )) ) {
+               DEBUG(0,("sec_desc_upg_fn: Failed to update sec_desc for %s\n", key.dptr ));
+               return 0;
+       }
+       
+       /* store it back */
+       
+       sd_size = sec_desc_size(sd_store->sec) + sizeof(SEC_DESC_BUF);
+       prs_init(&ps, sd_size, ctx, MARSHALL);
+
+       if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_store, &ps, 1 ) ) {
+               DEBUG(0,("sec_desc_upg_fn: Failed to parse new sec_desc for %s\n", key.dptr ));
+               return 0;
+       }
+
+       data.dptr = prs_data_p( &ps );
+       data.dsize = sd_size;
+       
+       result = tdb_store( tdb_printers, key, data, TDB_REPLACE );
+
+       prs_mem_free( &ps );
+       
+       /* 0 to continue and non-zero to stop traversal */
+
+       return (result == -1);
+}
+
+/*******************************************************************
+*******************************************************************/
+
+static BOOL upgrade_to_version_4(void)
+{
+       TALLOC_CTX *ctx;
+       int result;
+
+       DEBUG(0,("upgrade_to_version_4: upgrading printer security descriptors\n"));
+
+       if ( !(ctx = talloc_init( "upgrade_to_version_4" )) ) 
+               return False;
+
+       result = tdb_traverse( tdb_printers, sec_desc_upg_fn, ctx );
+
+       talloc_destroy( ctx );
+
+       return ( result != -1 );
+}
+
 /****************************************************************************
  Open the NT printing tdbs. Done once before fork().
 ****************************************************************************/
 
 BOOL nt_printing_init(void)
 {
-       static pid_t local_pid;
        const char *vstring = "INFO/version";
+       WERROR win_rc;
+       uint32 vers_id;
 
-       if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid())
+       if ( tdb_drivers && tdb_printers && tdb_forms )
                return True;
  
        if (tdb_drivers)
@@ -318,33 +446,43 @@ BOOL nt_printing_init(void)
                return False;
        }
  
-       local_pid = sys_getpid();
        /* handle a Samba upgrade */
        tdb_lock_bystring(tdb_drivers, vstring, 0);
-       {
-               int32 vers_id;
 
-               /* Cope with byte-reversed older versions of the db. */
-               vers_id = tdb_fetch_int32(tdb_drivers, vstring);
+       /* ---------------- Start Lock Region ---------------- */
+
+       /* Cope with byte-reversed older versions of the db. */
+       vers_id = tdb_fetch_int32(tdb_drivers, vstring);
+
+       if ( vers_id != NTDRIVERS_DATABASE_VERSION ) {
+
                if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) {
                        /* Written on a bigendian machine with old fetch_int code. Save as le. */
                        /* The only upgrade between V2 and V3 is to save the version in little-endian. */
-                       tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
-                       vers_id = NTDRIVERS_DATABASE_VERSION;
+                       tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
+                       vers_id = NTDRIVERS_DATABASE_VERSION_3;
                }
 
-               if (vers_id != NTDRIVERS_DATABASE_VERSION) {
-
+               if (vers_id != NTDRIVERS_DATABASE_VERSION_3 ) {
+       
                        if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) { 
                                if (!upgrade_to_version_3())
                                        return False;
                        } else
                                tdb_traverse(tdb_drivers, tdb_traverse_delete_fn, NULL);
                         
-                       tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
+                       tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
                }
+
+               /* at this point we know that the database is at version 3 so upgrade to v4 */
+
+               if ( !upgrade_to_version_4() )
+                       return False;
+               tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
        }
+
+       /* ---------------- End Lock Region ------------------ */
+
        tdb_unlock_bystring(tdb_drivers, vstring);
 
        update_c_setprinter(True);
@@ -363,10 +501,40 @@ BOOL nt_printing_init(void)
 
        message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata );
 
+       /*
+        * register callback to handle invalidating the printer cache 
+        * between smbd processes.
+        */
+
+       message_register( MSG_PRINTER_MOD, receive_printer_mod_msg);
+
+       /* of course, none of the message callbacks matter if you don't
+          tell messages.c that you interested in receiving PRINT_GENERAL 
+          msgs.  This is done in claim_connection() */
+
+
+       if ( lp_security() == SEC_ADS ) {
+               win_rc = check_published_printers();
+               if (!W_ERROR_IS_OK(win_rc))
+                       DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", dos_errstr(win_rc)));
+       }
 
        return True;
 }
 
+/*******************************************************************
+ Function to allow filename parsing "the old way".
+********************************************************************/
+
+static BOOL driver_unix_convert(char *name,connection_struct *conn,
+               char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst)
+{
+       unix_format(name);
+       unix_clean_name(name);
+       trim_string(name,"/","/");
+       return unix_convert(name, conn, saved_last_component, bad_path, pst);
+}
+
 /*******************************************************************
  tdb traversal function for counting printers.
 ********************************************************************/
@@ -496,7 +664,7 @@ int get_ntforms(nt_forms_struct **list)
                if (ret != dbuf.dsize) 
                        continue;
 
-               tl = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
+               tl = SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1);
                if (!tl) {
                        DEBUG(0,("get_ntforms: Realloc fail.\n"));
                        return 0;
@@ -558,15 +726,14 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
        
        unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
        for (n=0; n<*count; n++) {
-               if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
-                       DEBUG(103, ("NT workaround, [%s] already exists\n", form_name));
+               if ( strequal((*list)[n].name, form_name) ) {
                        update=True;
                        break;
                }
        }
 
        if (update==False) {
-               if((tl=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL) {
+               if((tl=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) {
                        DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
                        return False;
                }
@@ -583,6 +750,9 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
        (*list)[n].right=form->right;
        (*list)[n].bottom=form->bottom;
 
+       DEBUG(6,("add_a_form: Successfully %s form [%s]\n", 
+               update ? "updated" : "added", form_name));
+
        return True;
 }
 
@@ -675,7 +845,7 @@ int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
                if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
                        continue;
                
-               if((fl = Realloc(*list, sizeof(fstring)*(total+1))) == NULL) {
+               if((fl = SMB_REALLOC_ARRAY(*list, fstring, total+1)) == NULL) {
                        DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
                        return -1;
                }
@@ -731,7 +901,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
        char    *buf = NULL;
        ssize_t byte_count;
 
-       if ((buf=malloc(PE_HEADER_SIZE)) == NULL) {
+       if ((buf=SMB_MALLOC(PE_HEADER_SIZE)) == NULL) {
                DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
                                fname, PE_HEADER_SIZE));
                goto error_exit;
@@ -739,8 +909,8 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
 
        /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
        if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
-               DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %d\n",
-                               fname, byte_count));
+               DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
+                        fname, (unsigned long)byte_count));
                goto no_version_info;
        }
 
@@ -760,8 +930,8 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
        }
 
        if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
-               DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %d\n",
-                               fname, byte_count));
+               DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
+                        fname, (unsigned long)byte_count));
                /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
                goto no_version_info;
        }
@@ -787,15 +957,15 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
                        goto error_exit;
 
                SAFE_FREE(buf);
-               if ((buf=malloc(section_table_bytes)) == NULL) {
+               if ((buf=SMB_MALLOC(section_table_bytes)) == NULL) {
                        DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
                                        fname, section_table_bytes));
                        goto error_exit;
                }
 
                if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
-                       DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %d\n",
-                                       fname, byte_count));
+                       DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
+                                fname, (unsigned long)byte_count));
                        goto error_exit;
                }
 
@@ -811,7 +981,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
                                        goto error_exit;
 
                                SAFE_FREE(buf);
-                               if ((buf=malloc(section_bytes)) == NULL) {
+                               if ((buf=SMB_MALLOC(section_bytes)) == NULL) {
                                        DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
                                                        fname, section_bytes));
                                        goto error_exit;
@@ -825,8 +995,8 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
                                }
 
                                if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
-                                       DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %d\n",
-                                                       fname, byte_count));
+                                       DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
+                                                fname, (unsigned long)byte_count));
                                        goto error_exit;
                                }
 
@@ -871,7 +1041,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32
 
                /* Allocate a bit more space to speed up things */
                SAFE_FREE(buf);
-               if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) {
+               if ((buf=SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
                        DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes  = %d\n",
                                        fname, PE_HEADER_SIZE));
                        goto error_exit;
@@ -979,20 +1149,20 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
        SMB_STRUCT_STAT stat_buf;
        BOOL bad_path;
 
-       ZERO_STRUCT(st);
-       ZERO_STRUCT(stat_buf);
+       SET_STAT_INVALID(st);
+       SET_STAT_INVALID(stat_buf);
        new_create_time = (time_t)0;
        old_create_time = (time_t)0;
 
        /* Get file version info (if available) for previous file (if it exists) */
        pstrcpy(filepath, old_file);
 
-       unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
+       driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
 
        fsp = open_file_shared(conn, filepath, &stat_buf,
-                                                  SET_OPEN_MODE(DOS_OPEN_RDONLY),
+                                                  SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
                                                   (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
-                                                  0, 0, &access_mode, &action);
+                                                  FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
        if (!fsp) {
                /* Old file not found, so by definition new file is in fact newer */
                DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
@@ -1016,12 +1186,12 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
 
        /* Get file version info (if available) for new file */
        pstrcpy(filepath, new_file);
-       unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
+       driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
 
        fsp = open_file_shared(conn, filepath, &stat_buf,
-                                                  SET_OPEN_MODE(DOS_OPEN_RDONLY),
+                                                  SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
                                                   (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
-                                                  0, 0, &access_mode, &action);
+                                                  FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
        if (!fsp) {
                /* New file not found, this shouldn't occur if the caller did its job */
                DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
@@ -1092,7 +1262,7 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_
        SMB_STRUCT_STAT   st;
        connection_struct *conn;
 
-       ZERO_STRUCT(st);
+       SET_STAT_INVALID(st);
 
        *perr = WERR_INVALID_PARAM;
 
@@ -1132,12 +1302,18 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_
         * deriver the cversion. */
        slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
 
-       unix_convert(driverpath,conn,NULL,&bad_path,&st);
+       driver_unix_convert(driverpath,conn,NULL,&bad_path,&st);
+
+       if ( !vfs_file_exist( conn, driverpath, &st ) ) {
+               *perr = WERR_BADFILE;
+               goto error_exit;
+       }
 
        fsp = open_file_shared(conn, driverpath, &st,
-                                                  SET_OPEN_MODE(DOS_OPEN_RDONLY),
-                                                  (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
-                                                  0, 0, &access_mode, &action);
+               SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+               (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+               FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
+
        if (!fsp) {
                DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
                                driverpath, errno));
@@ -1178,8 +1354,8 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_
                                  driverpath, major, minor));
        }
 
-    DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
-                       driverpath, cversion));
+       DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
+               driverpath, cversion));
 
        close_file(fsp, True);
        close_cnum(conn, user->vuid);
@@ -1256,9 +1432,8 @@ static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri
         *      NT 4: cversion=2
         *      NT2K: cversion=3
         */
-       if ((driver->cversion = get_correct_cversion( architecture,
-                                                                       driver->driverpath, user, &err)) == -1)
-               return err;
+       if ((driver->cversion = get_correct_cversion( architecture, driver->driverpath, user, &err)) == -1)
+                       return err;
 
        return WERR_OK;
 }
@@ -1320,8 +1495,9 @@ static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *dri
         *      NT 4: cversion=2
         *      NT2K: cversion=3
         */
+
        if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
-               return err;
+                       return err;
 
        return WERR_OK;
 }
@@ -1388,7 +1564,7 @@ static char* ffmt(unsigned char *c){
 
 /****************************************************************************
 ****************************************************************************/
-BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, 
+WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, 
                                  struct current_user *user, WERROR *perr)
 {
        NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
@@ -1403,8 +1579,11 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        pstring inbuf;
        pstring outbuf;
        fstring res_type;
+       BOOL bad_path;
+       SMB_STRUCT_STAT st;
        int ver = 0;
        int i;
+       int err;
 
        memset(inbuf, '\0', sizeof(inbuf));
        memset(outbuf, '\0', sizeof(outbuf));
@@ -1417,7 +1596,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                driver = &converted_driver;
        } else {
                DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
-               return False;
+               return WERR_UNKNOWN_LEVEL;
        }
 
        architecture = get_short_archi(driver->environment);
@@ -1436,7 +1615,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        if (conn == NULL) {
                DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
                *perr = ntstatus_to_werror(nt_status);
-               return False;
+               return WERR_NO_SUCH_SHARE;
        }
 
        /*
@@ -1445,7 +1624,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
 
        if (!become_user(conn, conn->vuid)) {
                DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
-               return False;
+               return WERR_ACCESS_DENIED;
        }
 
        /*
@@ -1454,7 +1633,8 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
         */
        DEBUG(5,("Creating first directory\n"));
        slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
-       mkdir_internal(conn, new_dir);
+       driver_unix_convert(new_dir, conn, NULL, &bad_path, &st);
+       mkdir_internal(conn, new_dir, bad_path);
 
        /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
         * listed for this driver which has already been moved, skip it (note:
@@ -1479,18 +1659,14 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);      
                slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);   
                if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                       NTSTATUS status;
-                       status = rename_internals(conn, new_name, old_name, True);
-                       if (!NT_STATUS_IS_OK(status)) {
+                       driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
+                       if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
                                DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                new_name, old_name));
-                               *perr = ntstatus_to_werror(status);
-                               unlink_internals(conn, 0, new_name);
+                               *perr = WERR_ACCESS_DENIED;
                                ver = -1;
                        }
-               }
-               else
-                       unlink_internals(conn, 0, new_name);
+               } 
        }
 
        if (driver->datafile && strlen(driver->datafile)) {
@@ -1498,18 +1674,14 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                        slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);        
                        slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);     
                        if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                               NTSTATUS status;
-                               status = rename_internals(conn, new_name, old_name, True);
-                               if (!NT_STATUS_IS_OK(status)) {
+                               driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
+                               if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
                                        DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                        new_name, old_name));
-                                       *perr = ntstatus_to_werror(status);
-                                       unlink_internals(conn, 0, new_name);
+                                       *perr = WERR_ACCESS_DENIED;
                                        ver = -1;
                                }
                        }
-                       else
-                               unlink_internals(conn, 0, new_name);
                }
        }
 
@@ -1519,18 +1691,14 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                        slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);      
                        slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);   
                        if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                               NTSTATUS status;
-                               status = rename_internals(conn, new_name, old_name, True);
-                               if (!NT_STATUS_IS_OK(status)) {
+                               driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
+                               if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
                                        DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                        new_name, old_name));
-                                       *perr = ntstatus_to_werror(status);
-                                       unlink_internals(conn, 0, new_name);
+                                       *perr = WERR_ACCESS_DENIED;
                                        ver = -1;
                                }
                        }
-                       else
-                               unlink_internals(conn, 0, new_name);
                }
        }
 
@@ -1541,18 +1709,14 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                        slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);        
                        slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);     
                        if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                               NTSTATUS status;
-                               status = rename_internals(conn, new_name, old_name, True);
-                               if (!NT_STATUS_IS_OK(status)) {
+                               driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
+                               if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
                                        DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                        new_name, old_name));
-                                       *perr = ntstatus_to_werror(status);
-                                       unlink_internals(conn, 0, new_name);
+                                       *perr = WERR_ACCESS_DENIED;
                                        ver = -1;
                                }
                        }
-                       else
-                               unlink_internals(conn, 0, new_name);
                }
        }
 
@@ -1572,18 +1736,14 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                                slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);       
                                slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);    
                                if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                                       NTSTATUS status;
-                                       status = rename_internals(conn, new_name, old_name, True);
-                                       if (!NT_STATUS_IS_OK(status)) {
+                                       driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
+                                       if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
                                                DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                                new_name, old_name));
-                                               *perr = ntstatus_to_werror(status);
-                                               unlink_internals(conn, 0, new_name);
+                                               *perr = WERR_ACCESS_DENIED;
                                                ver = -1;
                                        }
                                }
-                               else
-                                       unlink_internals(conn, 0, new_name);
                        }
                NextDriver: ;
                }
@@ -1592,7 +1752,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        close_cnum(conn, user->vuid);
        unbecome_user();
 
-       return ver == -1 ? False : True;
+       return ver != -1 ? WERR_OK : WERR_UNKNOWN_PRINTER_DRIVER;
 }
 
 /****************************************************************************
@@ -1680,7 +1840,7 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
        if (len != buflen) {
                char *tb;
 
-               tb = (char *)Realloc(buf, len);
+               tb = (char *)SMB_REALLOC(buf, len);
                if (!tb) {
                        DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
                        ret = -1;
@@ -1745,7 +1905,7 @@ static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **in
        fstrcpy(info.configfile, "");
        fstrcpy(info.helpfile, "");
 
-       if ((info.dependentfiles=(fstring *)malloc(2*sizeof(fstring))) == NULL)
+       if ((info.dependentfiles= SMB_MALLOC_ARRAY(fstring, 2)) == NULL)
                return WERR_NOMEM;
 
        memset(info.dependentfiles, '\0', 2*sizeof(fstring));
@@ -1770,6 +1930,9 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
        ZERO_STRUCT(driver);
 
        architecture = get_short_archi(arch);
+
+       if ( !architecture )
+               return WERR_UNKNOWN_PRINTER_DRIVER;
        
        /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
        
@@ -1802,8 +1965,7 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
        while (len < dbuf.dsize) {
                fstring *tddfs;
 
-               tddfs = (fstring *)Realloc(driver.dependentfiles,
-                                                        sizeof(fstring)*(i+2));
+               tddfs = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2);
                if (tddfs == NULL) {
                        DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
                        break;
@@ -1928,13 +2090,13 @@ int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
                        nt_devmode->reserved2,
                        nt_devmode->panningwidth,
                        nt_devmode->panningheight,
-                       nt_devmode->private);
+                       nt_devmode->nt_dev_private);
 
        
-       if (nt_devmode->private) {
+       if (nt_devmode->nt_dev_private) {
                len += tdb_pack(buf+len, buflen-len, "B",
                                nt_devmode->driverextra,
-                               nt_devmode->private);
+                               nt_devmode->nt_dev_private);
        }
 
        DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
@@ -1963,8 +2125,17 @@ static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
        for ( i=0; i<data->num_keys; i++ ) {    
                val_ctr = &data->keys[i].values;
                num_values = regval_ctr_numvals( val_ctr );
+
+               /* pack the keyname followed by a empty value */
+
+               len += tdb_pack(buf+len, buflen-len, "pPdB", 
+                               &data->keys[i].name,
+                               data->keys[i].name, 
+                               REG_NONE,
+                               0,
+                               NULL);
                
-               /* loop over all values */
+               /* now loop over all values */
                
                for ( j=0; j<num_values; j++ ) {
                        /* pathname should be stored as <key>\<value> */
@@ -1997,28 +2168,41 @@ static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
  handles are not affected.
 ****************************************************************************/
 
-uint32 del_a_printer(char *sharename)
+uint32 del_a_printer(const char *sharename)
 {
        pstring key;
        TDB_DATA kbuf;
+       pstring printdb_path;
 
        slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
-
        kbuf.dptr=key;
        kbuf.dsize=strlen(key)+1;
+       tdb_delete(tdb_printers, kbuf);
 
+       slprintf(key, sizeof(key)-1, "%s%s", SECDESC_PREFIX, sharename);
+       kbuf.dptr=key;
+       kbuf.dsize=strlen(key)+1;
        tdb_delete(tdb_printers, kbuf);
+
+       close_all_print_db();
+
+       if (geteuid() == 0) {
+               pstrcpy(printdb_path, lock_path("printing/"));
+               pstrcat(printdb_path, sharename);
+               pstrcat(printdb_path, ".tdb");
+
+               unlink(printdb_path);
+       }
+
        return 0;
 }
 
-/* FIXME!!!  Reorder so this forward declaration is not necessary --jerry */
-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 **);
 /****************************************************************************
 ****************************************************************************/
 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
 {
        pstring key;
+       fstring norm_sharename;
        char *buf;
        int buflen, len;
        WERROR ret;
@@ -2030,10 +2214,13 @@ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
         *                and printer is \\server\\printer
         *
         * Samba manages only local printers.
-        * we currently don't support things like path=\\other_server\printer
+        * we currently don't support things like i
+        * path=\\other_server\printer
+        *
+        * We only store the printername, not \\server\printername
         */
 
-       if (info->servername[0]!='\0') {
+       if ( info->servername[0] != '\0' ) {
                trim_string(info->printername, info->servername, NULL);
                trim_char(info->printername, '\\', '\0');
                info->servername[0]='\0';
@@ -2085,7 +2272,7 @@ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
        if (buflen != len) {
                char *tb;
 
-               tb = (char *)Realloc(buf, len);
+               tb = (char *)SMB_REALLOC(buf, len);
                if (!tb) {
                        DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
                        ret = WERR_NOMEM;
@@ -2097,6 +2284,11 @@ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
        }
        
 
+       /* normalize the key */
+
+       fstrcpy( norm_sharename, info->sharename );
+       strlower_m( norm_sharename );
+
        slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename);
 
        kbuf.dptr = key;
@@ -2127,7 +2319,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
 {
 
        char adevice[MAXDEVICENAME];
-       NT_DEVICEMODE *nt_devmode = (NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE));
+       NT_DEVICEMODE *nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE);
 
        if (nt_devmode == NULL) {
                DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
@@ -2136,7 +2328,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
 
        ZERO_STRUCTP(nt_devmode);
 
-       safe_strcpy(adevice, default_devicename, sizeof(adevice)-1);
+       slprintf(adevice, sizeof(adevice), "%s", default_devicename);
        fstrcpy(nt_devmode->devicename, adevice);       
        
        fstrcpy(nt_devmode->formname, "Letter");
@@ -2166,7 +2358,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
        nt_devmode->mediatype        = 0;
        nt_devmode->dithertype       = 0;
 
-       /* non utilisés par un driver d'imprimante */
+       /* non utilisés par un driver d'imprimante */
        nt_devmode->logpixels        = 0;
        nt_devmode->bitsperpel       = 0;
        nt_devmode->pelswidth        = 0;
@@ -2178,7 +2370,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
        nt_devmode->panningwidth     = 0;
        nt_devmode->panningheight    = 0;
        
-       nt_devmode->private = NULL;
+       nt_devmode->nt_dev_private = NULL;
        return nt_devmode;
 }
 
@@ -2198,9 +2390,9 @@ NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
                return NULL;
        }
 
-       new_nt_devicemode->private = NULL;
-       if (nt_devicemode->private != NULL) {
-               if ((new_nt_devicemode->private = memdup(nt_devicemode->private, nt_devicemode->driverextra)) == NULL) {
+       new_nt_devicemode->nt_dev_private = NULL;
+       if (nt_devicemode->nt_dev_private != NULL) {
+               if ((new_nt_devicemode->nt_dev_private = memdup(nt_devicemode->nt_dev_private, nt_devicemode->driverextra)) == NULL) {
                        SAFE_FREE(new_nt_devicemode);
                        DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
                        return NULL;
@@ -2223,7 +2415,7 @@ void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
 
        DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
 
-       SAFE_FREE(nt_devmode->private);
+       SAFE_FREE(nt_devmode->nt_dev_private);
        SAFE_FREE(*devmode_ptr);
 }
 
@@ -2309,25 +2501,25 @@ int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
                          &devmode.reserved2,
                          &devmode.panningwidth,
                          &devmode.panningheight,
-                         &devmode.private);
+                         &devmode.nt_dev_private);
        
-       if (devmode.private) {
+       if (devmode.nt_dev_private) {
                /* the len in tdb_unpack is an int value and
                 * devmode.driverextra is only a short
                 */
-               len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
+               len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.nt_dev_private);
                devmode.driverextra=(uint16)extra_len;
                
                /* check to catch an invalid TDB entry so we don't segfault */
                if (devmode.driverextra == 0) {
-                       devmode.private = NULL;
+                       devmode.nt_dev_private = NULL;
                }
        }
 
        *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
 
        DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
-       if (devmode.private)
+       if (devmode.nt_dev_private)
                DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
 
        return len;
@@ -2337,7 +2529,7 @@ int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
  Allocate and initialize a new slot.
 ***************************************************************************/
  
-static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
+int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
 {
        NT_PRINTER_KEY  *d;
        int             key_index;
@@ -2347,18 +2539,19 @@ static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
        
        /* allocate another slot in the NT_PRINTER_KEY array */
        
-       d = Realloc( data->keys, sizeof(NT_PRINTER_KEY)*(data->num_keys+1) );
-       if ( d )
-               data->keys = d;
+       if ( !(d = SMB_REALLOC_ARRAY( data->keys, NT_PRINTER_KEY, data->num_keys+1)) ) {
+               DEBUG(0,("add_new_printer_key: Realloc() failed!\n"));
+               return -1;
+       }
+
+       data->keys = d;
        
        key_index = data->num_keys;
        
        /* initialze new key */
        
        data->num_keys++;
-       data->keys[key_index].name = strdup( name );
-       
-       ZERO_STRUCTP( &data->keys[key_index].values );
+       data->keys[key_index].name = SMB_STRDUP( name );
        
        regval_ctr_init( &data->keys[key_index].values );
        
@@ -2398,7 +2591,7 @@ int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
 /****************************************************************************
  ***************************************************************************/
 
-uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
+int get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
 {
        int     i, j;
        int     key_len;
@@ -2409,14 +2602,42 @@ uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **su
        
        if ( !data )
                return 0;
+
+       if ( !key )
+               return -1;
+
+       /* special case of asking for the top level printer data registry key names */
+
+       if ( strlen(key) == 0 ) {
+               for ( i=0; i<data->num_keys; i++ ) {
                
+                       /* found a match, so allocate space and copy the name */
+                       
+                       if ( !(ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
+                               DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n", 
+                                       num_subkeys+1));
+                               SAFE_FREE( subkeys );
+                               return -1;
+                       }
+                       
+                       subkeys_ptr = ptr;
+                       fstrcpy( subkeys_ptr[num_subkeys], data->keys[i].name );
+                       num_subkeys++;
+               }
+
+               goto done;
+       }
+               
+       /* asking for the subkeys of some key */
+       /* subkey paths are stored in the key name using '\' as the delimiter */
+
        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 */
                        
+                       /* if we found the exact key, then break */
                        key_len = strlen( key );
                        if ( strlen(data->keys[i].name) == key_len )
-                               continue;
+                               break;
                        
                        /* get subkey path */
 
@@ -2439,7 +2660,7 @@ uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **su
 
                        /* found a match, so allocate space and copy the name */
                        
-                       if ( !(ptr = Realloc( subkeys_ptr, (num_subkeys+2)*sizeof(fstring))) ) {
+                       if ( !(ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
                                DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n", 
                                        num_subkeys+1));
                                SAFE_FREE( subkeys );
@@ -2453,7 +2674,13 @@ uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **su
                
        }
        
-       /* tag of the end */
+       /* return error if the key was not found */
+       
+       if ( i == data->num_keys )
+               return -1;
+       
+done:
+       /* tag off the end */
        
        if (num_subkeys)
                fstrcpy(subkeys_ptr[num_subkeys], "" );
@@ -2502,9 +2729,14 @@ static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
 
        /* 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);
+       str_size = strlen(multi_sz) + 2;
+       conv_strs = SMB_CALLOC_ARRAY(smb_ucs2_t, str_size);
+       if (!conv_strs) {
+               return;
+       }
 
+       /* Change to byte units. */
+       str_size *= sizeof(smb_ucs2_t);
        push_ucs2(NULL, conv_strs, multi_sz, str_size, 
                  STR_TERMINATE | STR_NOALIGN);
 
@@ -2526,6 +2758,7 @@ static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
 {
        REGVAL_CTR *ctr = NULL;
        fstring longname;
+       fstring dnssuffix;
        char *allocated_string = NULL;
         const char *ascii_str;
        int i;
@@ -2537,7 +2770,15 @@ static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
        map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
        map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
 
-       get_myfullname(longname);
+       /* we make the assumption that the netbios name is the same 
+          as the DNS name sinc ethe former will be what we used to 
+          join the domain */
+
+       if ( get_mydnsdomname( dnssuffix ) )
+               fstr_sprintf( longname, "%s.%s", global_myname(), dnssuffix );
+       else
+               fstrcpy( longname, global_myname() );
+               
        map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
 
        asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
@@ -2576,7 +2817,8 @@ static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
        return True;
 }
 
-static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, GUID guid)
+static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, 
+                              struct uuid guid)
 {
        int i;
        REGVAL_CTR *ctr=NULL;
@@ -2588,59 +2830,23 @@ static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, GUID guid)
 
        regval_ctr_delvalue(ctr, "objectGUID");
        regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY, 
-                           (char *) &guid, sizeof(GUID));      
+                           (char *) &guid, sizeof(struct uuid));       
 }
 
-static WERROR publish_it(NT_PRINTER_INFO_LEVEL *printer)
+static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
+                                     NT_PRINTER_INFO_LEVEL *printer)
 {
        ADS_STATUS ads_rc;
-       TALLOC_CTX *ctx = talloc_init("publish_it");
-       ADS_MODLIST mods = ads_init_mods(ctx);
+       void *res;
        char *prt_dn = NULL, *srv_dn, *srv_cn_0;
        char *srv_dn_utf8, **srv_cn_utf8;
-       void *res = NULL;
-       ADS_STRUCT *ads;
+       TALLOC_CTX *ctx;
+       ADS_MODLIST mods;
        const char *attrs[] = {"objectGUID", NULL};
-       GUID guid;
+       struct uuid 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);
-
-       /* initial ads structure */
-       
-       ads = ads_init(NULL, NULL, NULL);
-       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_connect() will find the DC for us */                                         
-       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;
-       }
+       DEBUG(5, ("publishing printer %s\n", printer->info_2->printername));
 
        /* figure out where to publish */
        ads_find_machine_acct(ads, &res, global_myname());
@@ -2661,13 +2867,13 @@ static WERROR publish_it(NT_PRINTER_INFO_LEVEL *printer)
                return WERR_SERVER_UNAVAILABLE;
        }
        /* Now convert to CH_UNIX. */
-       if (pull_utf8_allocate((void **) &srv_dn, srv_dn_utf8) == (size_t)-1) {
+       if (pull_utf8_allocate(&srv_dn, srv_dn_utf8) == (size_t)-1) {
                ldap_memfree(srv_dn_utf8);
                ldap_memfree(srv_cn_utf8);
                ads_destroy(&ads);
                return WERR_SERVER_UNAVAILABLE;
        }
-       if (pull_utf8_allocate((void **) &srv_cn_0, srv_cn_utf8[0]) == (size_t)-1) {
+       if (pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0]) == (size_t)-1) {
                ldap_memfree(srv_dn_utf8);
                ldap_memfree(srv_cn_utf8);
                ads_destroy(&ads);
@@ -2684,71 +2890,58 @@ static WERROR publish_it(NT_PRINTER_INFO_LEVEL *printer)
        SAFE_FREE(srv_dn);
        SAFE_FREE(srv_cn_0);
 
+       /* build the ads mods */
+       ctx = talloc_init("nt_printer_publish_ads");
+       mods = ads_init_mods(ctx);
+
+       get_local_printer_publishing_data(ctx, &mods, 
+                                         &printer->info_2->data);
+       ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, 
+                   printer->info_2->sharename);
+
        /* 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);
+       ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
+       if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT)
+               ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
+
+       if (!ADS_ERR_OK(ads_rc))
+               DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc)));
        
+       talloc_destroy(ctx);
+
        /* retreive the guid and store it locally */
        if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
-               ads_memfree(ads, prt_dn);
+               ZERO_STRUCT(guid);
                ads_pull_guid(ads, res, &guid);
                ads_msgfree(ads, res);
                store_printer_guid(printer->info_2, guid);
-               win_rc = mod_a_printer(*printer, 2);
+               win_rc = mod_a_printer(printer, 2);
        } 
 
-       safe_free(prt_dn);
-       ads_destroy(&ads);
-
-       return WERR_OK;
+       SAFE_FREE(prt_dn);
+       return win_rc;
 }
 
-WERROR unpublish_it(NT_PRINTER_INFO_LEVEL *printer)
+static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
+                                       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, NULL);
-       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);
+       DEBUG(5, ("unpublishing printer %s\n", printer->info_2->printername));
 
-       /* ads_connect() will find the DC for us */                                         
-       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);
+       ads_msgfree(ads, res);
        return WERR_OK;
 }
 
@@ -2761,74 +2954,163 @@ WERROR unpublish_it(NT_PRINTER_INFO_LEVEL *printer)
 
 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
 {
+       ADS_STATUS ads_rc;
+       ADS_STRUCT *ads = NULL;
        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;
+               goto done;
 
-       switch(action) {
+       switch (action) {
        case SPOOL_DS_PUBLISH:
        case SPOOL_DS_UPDATE:
-               win_rc = publish_it(printer);
+               /* set the DsSpooler info and attributes */
+               if (!(map_nt_printer_info2_to_dsspooler(printer->info_2))) {
+                       win_rc = WERR_NOMEM;
+                       goto done;
+               }
+
+               printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
                break;
        case SPOOL_DS_UNPUBLISH:
-               win_rc = unpublish_it(printer);
+               printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
                break;
        default:
                win_rc = WERR_NOT_SUPPORTED;
+               goto done;
        }
-       
 
+       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)));
+               goto done;
+       }
+
+       ads = ads_init(NULL, NULL, NULL);
+       if (!ads) {
+               DEBUG(3, ("ads_init() failed\n"));
+               win_rc = WERR_SERVER_UNAVAILABLE;
+               goto done;
+       }
+       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_connect() will find the DC for us */                                         
+       ads_rc = ads_connect(ads);
+       if (!ADS_ERR_OK(ads_rc)) {
+               DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
+               win_rc = WERR_ACCESS_DENIED;
+               goto done;
+       }
+
+       switch (action) {
+       case SPOOL_DS_PUBLISH:
+       case SPOOL_DS_UPDATE:
+               win_rc = nt_printer_publish_ads(ads, printer);
+               break;
+       case SPOOL_DS_UNPUBLISH:
+               win_rc = nt_printer_unpublish_ads(ads, printer);
+               break;
+       }
+
+done:
        free_a_printer(&printer, 2);
+       ads_destroy(&ads);
        return win_rc;
 }
 
-BOOL is_printer_published(Printer_entry *print_hnd, int snum, GUID *guid)
+WERROR check_published_printers(void)
 {
+       ADS_STATUS ads_rc;
+       ADS_STRUCT *ads = NULL;
+       int snum;
+       int n_services = lp_numservices();
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       REGVAL_CTR *ctr;
-       REGISTRY_VALUE *guid_val;
-       WERROR win_rc;
-       int i;
 
+       ads = ads_init(NULL, NULL, NULL);
+       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);
 
-       win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
-       if (!W_ERROR_IS_OK(win_rc))
-               return False;
+       /* ads_connect() will find the DC for us */                                         
+       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;
+       }
 
-       if (!(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
-               return False;
+       for (snum = 0; snum < n_services; snum++) {
+               if (!(lp_snum_ok(snum) && lp_print_ok(snum)))
+                       continue;
 
-       if ((i = lookup_printerkey(&printer->info_2->data, 
-                                  SPOOL_DSSPOOLER_KEY)) < 0)
-               return False;
+               if (W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2,
+                                               lp_servicename(snum))) &&
+                   (printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
+                       nt_printer_publish_ads(ads, printer);
 
-       if (!(ctr = &printer->info_2->data.keys[i].values)) {
-               return False;
+               free_a_printer(&printer, 2);
        }
 
-       if (!(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) {
+       ads_destroy(&ads);
+       return WERR_OK;
+}
+
+BOOL is_printer_published(Printer_entry *print_hnd, int snum, 
+                         struct uuid *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) ||
+           !(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) ||
+           ((i = lookup_printerkey(&printer->info_2->data, 
+                                   SPOOL_DSSPOOLER_KEY)) < 0) ||
+           !(ctr = &printer->info_2->data.keys[i].values) ||
+           !(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) {
+               free_a_printer(&printer, 2);
                return False;
        }
 
-       if (regval_size(guid_val) == sizeof(GUID))
-               memcpy(guid, regval_data_p(guid_val), sizeof(GUID));
+       /* fetching printer guids really ought to be a separate function.. */
+       if (guid && regval_size(guid_val) == sizeof(struct uuid))
+               memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid));
 
+       free_a_printer(&printer, 2);
        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)
+
+WERROR check_published_printers(void)
+{
+       return WERR_OK;
+}
+
+BOOL is_printer_published(Printer_entry *print_hnd, int snum, 
+                         struct uuid *guid)
 {
        return False;
 }
-#endif
+#endif /* HAVE_ADS */
+
 /****************************************************************************
  ***************************************************************************/
  
@@ -3027,6 +3309,7 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
        
                /* check to see if there are any more registry values */
                
+               regval_p = NULL;
                len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);         
                if ( !regval_p ) 
                        break;
@@ -3038,13 +3321,25 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
                                  &type,
                                  &size,
                                  &data_p);
+
+               /* lookup for subkey names which have a type of REG_NONE */
+               /* there's no data with this entry */
+
+               if ( type == REG_NONE ) {
+                       if ( (key_index=lookup_printerkey( printer_data, string)) == -1 )
+                               add_new_printer_key( printer_data, string );
+                       continue;
+               }
        
                /*
                 * break of the keyname from the value name.  
-                * Should only be one '\' in the string returned.
+                * Valuenames can have embedded '\'s so be careful.
+                * only support one level of keys.  See the 
+                * "Konica Fiery S300 50C-K v1.1. enu" 2k driver.
+                * -- jerry
                 */     
                 
-               str = strrchr( string, '\\');
+               str = strchr_m( string, '\\');
                
                /* Put in "PrinterDriverData" is no key specified */
                
@@ -3168,7 +3463,7 @@ static void map_to_os2_driver(fstring drivername)
 /****************************************************************************
  Get a default printer info 2 struct.
 ****************************************************************************/
-static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
+static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *servername, const char* sharename)
 {
        int snum;
        NT_PRINTER_INFO_LEVEL_2 info;
@@ -3177,9 +3472,9 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const
 
        snum = lp_servicenumber(sharename);
 
-       slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
+       slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", servername);
        slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s", 
-                get_called_name(), sharename);
+               servername, sharename);
        fstrcpy(info.sharename, sharename);
        fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
 
@@ -3247,25 +3542,31 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const
 
 /****************************************************************************
 ****************************************************************************/
-static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
+static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *servername, const char *sharename)
 {
        pstring key;
        NT_PRINTER_INFO_LEVEL_2 info;
-       int             len = 0;
+       int len = 0;
+       int snum = lp_servicenumber(sharename);
        TDB_DATA kbuf, dbuf;
        fstring printername;
        char adevice[MAXDEVICENAME];
+       fstring norm_sharename;
                
        ZERO_STRUCT(info);
 
-       slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
+       /* normalize case */
+       fstrcpy( norm_sharename, sharename );
+       strlower_m( norm_sharename );
+
+       slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, norm_sharename);
 
        kbuf.dptr = key;
        kbuf.dsize = strlen(key)+1;
 
        dbuf = tdb_fetch(tdb_printers, kbuf);
        if (!dbuf.dptr)
-               return get_a_printer_2_default(info_ptr, sharename);
+               return get_a_printer_2_default(info_ptr, servername, norm_sharename);
 
        len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
                        &info.attributes,
@@ -3293,11 +3594,16 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sh
 
        /* Samba has to have shared raw drivers. */
        info.attributes |= PRINTER_ATTRIBUTE_SAMBA;
+       info.attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA;
 
        /* Restore the stripped strings. */
-       slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
-       slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", get_called_name(),
-                       info.printername);
+       slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", servername);
+
+       if ( lp_force_printername(snum) )
+               slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, norm_sharename );
+       else 
+               slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info.printername);
+
        fstrcpy(info.printername, printername);
 
        len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
@@ -3310,13 +3616,13 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sh
         * See comments in get_a_printer_2_default()
         */
 
-       if (lp_default_devmode(lp_servicenumber(sharename)) && !info.devmode) {
+       if (lp_default_devmode(snum) && !info.devmode) {
                DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
                        printername));
                info.devmode = construct_nt_devicemode(printername);
        }
 
-       safe_strcpy(adevice, info.printername, sizeof(adevice)-1);
+       slprintf( adevice, sizeof(adevice), "%s", info.printername );
        if (info.devmode) {
                fstrcpy(info.devmode->devicename, adevice);     
        }
@@ -3345,7 +3651,7 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sh
 /****************************************************************************
  Debugging function, dump at level 6 the struct in the logs.
 ****************************************************************************/
-static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
 {
        uint32 result;
        NT_PRINTER_INFO_LEVEL_2 *info2;
@@ -3355,11 +3661,11 @@ static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        switch (level) {
                case 2:
                {
-                       if (printer.info_2 == NULL)
+                       if (printer->info_2 == NULL)
                                result=5;
                        else
                        {
-                               info2=printer.info_2;
+                               info2=printer->info_2;
                        
                                DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
                                DEBUGADD(106,("priority:[%d]\n", info2->priority));
@@ -3424,6 +3730,27 @@ static uint32 rev_changeid(void)
 #endif
 }
 
+/********************************************************************
+ Send a message to all smbds about the printer that just changed
+ ********************************************************************/
+static BOOL send_printer_mod_msg( char* printername )
+{
+       int len = strlen(printername);
+       
+       if (!len)
+               return False;
+
+       DEBUG(10,("send_printer_mod_msg: Sending message about printer change [%s]\n",
+               printername));
+               
+       /* spam everyone that we just changed this printer */
+       
+       message_send_all( conn_tdb_ctx(), MSG_PRINTER_MOD, printername, len+1, False, NULL );
+
+       return True;
+}
+
 /*
  * The function below are the high level ones.
  * only those ones must be called from the spoolss code.
@@ -3434,7 +3761,7 @@ static uint32 rev_changeid(void)
  Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
 ****************************************************************************/
 
-WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
 {
        WERROR result;
        
@@ -3446,7 +3773,8 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
         * get_a_printer() 
         */
         
-       invalidate_printer_hnd_cache( printer.info_2->sharename );
+       invalidate_printer_hnd_cache( printer->info_2->sharename );
+       send_printer_mod_msg( printer->info_2->sharename );
        
        switch (level) {
                case 2:
@@ -3461,7 +3789,7 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
                           of client's spoolss service in order for the
                           client's cache to show updates */
 
-                       printer.info_2->changeid = rev_changeid();
+                       printer->info_2->changeid = rev_changeid();
 
                        /*
                         * Because one day someone will ask:
@@ -3482,7 +3810,7 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
                         * 14/12/01     --jerry
                         */
 
-                       result=update_a_printer_2(printer.info_2);
+                       result=update_a_printer_2(printer->info_2);
                        
                        break;
                }
@@ -3650,10 +3978,10 @@ static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
 
        len += pack_values( &info->data, buf+len, buflen-len );
 
-       if (buflen != len) {
+       if (buflen < len) {
                char *tb;
 
-               tb = (char *)Realloc(buf, len);
+               tb = (char *)SMB_REALLOC(buf, len);
                if (!tb) {
                        DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
                        ret = -1;
@@ -3690,7 +4018,7 @@ done:
  Update (i.e. save) the driver init info (DEVMODE and values) for a printer
 ****************************************************************************/
 
-uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
 {
        uint32 result;
        
@@ -3698,7 +4026,7 @@ uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        
        switch (level) {
                case 2:
-                       result = update_driver_init_2(printer.info_2);
+                       result = update_driver_init_2(printer->info_2);
                        break;
                default:
                        result = 1;
@@ -3777,7 +4105,7 @@ static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, ui
                if ((ctx = talloc_init("save_driver_init_2")) == NULL)
                        return WERR_NOMEM;
 
-               if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
+               if ((nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE)) == NULL) {
                        status = WERR_NOMEM;
                        goto done;
                }
@@ -3803,7 +4131,7 @@ static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, ui
         * 
         */
 
-       if ( update_driver_init(*printer, 2) != 0 ) {
+       if ( update_driver_init(printer, 2) != 0 ) {
                DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
                status = WERR_NOMEM;
                goto done;
@@ -3814,7 +4142,7 @@ static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, ui
         * printer to match it. This allows initialization of the current printer 
         * as well as the driver.
         */
-       status = mod_a_printer(*printer, 2);
+       status = mod_a_printer(printer, 2);
        if (!W_ERROR_IS_OK(status)) {
                DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
                                  printer->info_2->printername));
@@ -3894,7 +4222,7 @@ NT_PRINTER_INFO_LEVEL_2* dup_printer_2( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2
        if ( !printer )
                return NULL;
        
-       if ( !(copy = (NT_PRINTER_INFO_LEVEL_2 *)malloc(sizeof(NT_PRINTER_INFO_LEVEL_2))) )
+       if ( !(copy = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL_2)) )
                return NULL;
                
        memcpy( copy, printer, sizeof(NT_PRINTER_INFO_LEVEL_2) );
@@ -3917,6 +4245,16 @@ NT_PRINTER_INFO_LEVEL_2* dup_printer_2( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2
 
 /****************************************************************************
  Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
+
+ Previously the code had a memory allocation problem because it always
+ used the TALLOC_CTX from the Printer_entry*.   This context lasts 
+ as a long as the original handle is open.  So if the client made a lot 
+ of getprinter[data]() calls, the memory usage would climb.  Now we use
+ a short lived TALLOC_CTX for printer_info_2 objects returned.  We 
+ still use the Printer_entry->ctx for maintaining the cache copy though
+ since that object must live as long as the handle by definition.  
+                                                    --jerry
+
 ****************************************************************************/
 
 WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, 
@@ -3924,6 +4262,7 @@ WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_print
 {
        WERROR result;
        NT_PRINTER_INFO_LEVEL *printer = NULL;
+       fstring servername;
        
        *pp_printer = NULL;
 
@@ -3931,11 +4270,18 @@ WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_print
 
        switch (level) {
                case 2:
-                       if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
+                       if ((printer = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL)) == NULL) {
                                DEBUG(0,("get_a_printer: malloc fail.\n"));
                                return WERR_NOMEM;
                        }
                        ZERO_STRUCTP(printer);
+
+                       if ( print_hnd ) 
+                               fstrcpy( servername, print_hnd->servername );
+                       else {
+                               fstrcpy( servername, "%L" );
+                               standard_sub_basic( "", servername, sizeof(servername)-1 );
+                       }
                        
                        /* 
                         * check for cache first.  A Printer handle cannot changed
@@ -3947,7 +4293,11 @@ WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_print
                                && (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)) ) {
+                               /* get_talloc_ctx() works here because we need a short 
+                                  lived talloc context */
+
+                               if ( !(printer->info_2 = dup_printer_2(get_talloc_ctx(), print_hnd->printer_info->info_2)) ) 
+                               {
                                        DEBUG(0,("get_a_printer: unable to copy cached printer info!\n"));
                                        
                                        SAFE_FREE(printer);
@@ -3962,27 +4312,31 @@ WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_print
                                break;
                        }
 
-                       /* no cache for this handle; see if we can match one from another handle */
-                       
+                       /* no cache for this handle; see if we can match one from another handle.
+                          Make sure to use a short lived talloc ctx */
+
                        if ( print_hnd )
-                               result = find_printer_in_print_hnd_cache(print_hnd->ctx, &printer->info_2, sharename);
+                               result = find_printer_in_print_hnd_cache(get_talloc_ctx(), &printer->info_2, servername, sharename);
                        
                        /* fail to disk if we don't have it with any open handle */
 
                        if ( !print_hnd || !W_ERROR_IS_OK(result) )
-                               result = get_a_printer_2(&printer->info_2, sharename);                          
+                               result = get_a_printer_2(&printer->info_2, servername, sharename );
                        
                        /* we have a new printer now.  Save it with this handle */
                        
                        if ( W_ERROR_IS_OK(result) ) {
-                               dump_a_printer(*printer, level);
+                               dump_a_printer(printer, level);
                                        
                                /* 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));
+                                               print_hnd->printer_info = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL);
 
                                        if ( print_hnd->printer_info ) {
+                                               /* make sure to use the handle's talloc ctx here since 
+                                                  the printer_2 object must last until the handle is closed */
+
                                                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 */
@@ -4156,34 +4510,70 @@ BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
        int snum;
        int n_services = lp_numservices();
        NT_PRINTER_INFO_LEVEL *printer = NULL;
+       BOOL in_use = False;
 
        if ( !info_3 ) 
                return False;
 
-       DEBUG(5,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
+       DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
        
        /* loop through the printers.tdb and check for the drivername */
        
-       for (snum=0; snum<n_services; snum++) {
+       for (snum=0; snum<n_services && !in_use; snum++) {
                if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
                        continue;
                
                if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
                        continue;
                
-               if ( !StrCaseCmp(info_3->name, printer->info_2->drivername) ) {
-                       free_a_printer( &printer, 2 );
-                       return True;
-               }
+               if ( strequal(info_3->name, printer->info_2->drivername) ) 
+                       in_use = True;
                
                free_a_printer( &printer, 2 );
        }
        
-       DEBUG(5,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
+       DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
+       
+       if ( in_use ) {
+               NT_PRINTER_DRIVER_INFO_LEVEL d;
+               WERROR werr;
+               
+               DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", info_3->name));
+               
+               /* we can still remove the driver if there is one of 
+                  "Windows NT x86" version 2 or 3 left */
+                  
+               if ( !strequal( "Windows NT x86", info_3->environment ) ) {
+                       werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", DRIVER_ANY_VERSION );                       
+               }
+               else {
+                       switch ( info_3->cversion ) {
+                       case 2:
+                               werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 3 );
+                               break;
+                       case 3: 
+                               werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 2 );
+                               break;
+                       default:
+                               DEBUG(0,("printer_driver_in_use: ERROR! unknown driver version (%d)\n", 
+                                       info_3->cversion));
+                               werr = WERR_UNKNOWN_PRINTER_DRIVER;
+                               break;
+                       }
+               }
+
+               /* now check the error code */
+                               
+               if ( W_ERROR_IS_OK(werr) ) {
+                       /* it's ok to remove the driver, we have other architctures left */
+                       in_use = False;
+                       free_a_printer_driver( d, 3 );
+               }
+       }
        
        /* report that the driver is not in use by default */
        
-       return False;
+       return in_use;
 }
 
 
@@ -4389,6 +4779,8 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
        DATA_BLOB null_pw;
        NTSTATUS nt_status;
        fstring res_type;
+       BOOL bad_path;
+       SMB_STRUCT_STAT  st;
 
        if ( !info_3 )
                return False;
@@ -4424,6 +4816,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
        
        if ( *info_3->driverpath ) {
                if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
+                       driver_unix_convert(s, conn, NULL, &bad_path, &st);
                        DEBUG(10,("deleting driverfile [%s]\n", s));
                        unlink_internals(conn, 0, s);
                }
@@ -4431,6 +4824,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
                
        if ( *info_3->configfile ) {
                if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
+                       driver_unix_convert(s, conn, NULL, &bad_path, &st);
                        DEBUG(10,("deleting configfile [%s]\n", s));
                        unlink_internals(conn, 0, s);
                }
@@ -4438,6 +4832,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
        
        if ( *info_3->datafile ) {
                if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
+                       driver_unix_convert(s, conn, NULL, &bad_path, &st);
                        DEBUG(10,("deleting datafile [%s]\n", s));
                        unlink_internals(conn, 0, s);
                }
@@ -4445,6 +4840,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
        
        if ( *info_3->helpfile ) {
                if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
+                       driver_unix_convert(s, conn, NULL, &bad_path, &st);
                        DEBUG(10,("deleting helpfile [%s]\n", s));
                        unlink_internals(conn, 0, s);
                }
@@ -4459,6 +4855,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct
                        /* bypass the "\print$" portion of the path */
                        
                        if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
+                               driver_unix_convert(file, conn, NULL, &bad_path, &st);
                                DEBUG(10,("deleting dependent file [%s]\n", file));
                                unlink_internals(conn, 0, file );
                        }
@@ -4536,7 +4933,7 @@ WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct cur
  Store a security desc for a printer.
 ****************************************************************************/
 
-WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
+WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr)
 {
        SEC_DESC_BUF *new_secdesc_ctr = NULL;
        SEC_DESC_BUF *old_secdesc_ctr = NULL;
@@ -4544,6 +4941,10 @@ WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
        TALLOC_CTX *mem_ctx = NULL;
        fstring key;
        WERROR status;
+       fstring norm_sharename;
+
+       fstrcpy( norm_sharename, sharename );
+       strlower_m( norm_sharename );
 
        mem_ctx = talloc_init("nt_printing_setsec");
        if (mem_ctx == NULL)
@@ -4560,7 +4961,7 @@ WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
                SEC_DESC *psd = NULL;
                size_t size;
 
-               nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr);
+               nt_printing_getsec(mem_ctx, norm_sharename, &old_secdesc_ctr);
 
                /* Pick out correct owner and group sids */
 
@@ -4606,12 +5007,12 @@ WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
                goto out;
        }
 
-       slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
+       slprintf(key, sizeof(key)-1, "SECDESC/%s", norm_sharename);
 
        if (tdb_prs_store(tdb_printers, key, &ps)==0) {
                status = WERR_OK;
        } else {
-               DEBUG(1,("Failed to store secdesc for %s\n", printername));
+               DEBUG(1,("Failed to store secdesc for %s\n", norm_sharename));
                status = WERR_BADFUNC;
        }
 
@@ -4631,53 +5032,69 @@ WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
 
 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
 {
-       SEC_ACE ace[3];
+       SEC_ACE ace[5]; /* max number of ace entries */
+       int i = 0;
        SEC_ACCESS sa;
        SEC_ACL *psa = NULL;
        SEC_DESC_BUF *sdb = NULL;
        SEC_DESC *psd = NULL;
-       DOM_SID owner_sid;
+       DOM_SID adm_sid;
        size_t sd_size;
 
        /* Create an ACE where Everyone is allowed to print */
 
        init_sec_access(&sa, PRINTER_ACE_PRINT);
-       init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
+       init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
                     sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
 
-       /* Make the security descriptor owned by the Administrators group
-          on the PDC of the domain. */
-
-       if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
-               sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
-       } else {
-
-               /* Backup plan - make printer owned by admins.
-                  This should emulate a lanman printer as security
-                  settings can't be changed. */
+       /* Add the domain admins group if we are a DC */
+       
+       if ( IS_DC ) {
+               DOM_SID domadmins_sid;
+               
+               sid_copy(&domadmins_sid, get_global_sam_sid());
+               sid_append_rid(&domadmins_sid, DOMAIN_GROUP_RID_ADMINS);
+               
+               init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
+               init_sec_ace(&ace[i++], &domadmins_sid, 
+                       SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 
+                       SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+               init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+       }
+       else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
+               sid_append_rid(&adm_sid, DOMAIN_USER_RID_ADMIN);
 
-               sid_copy(&owner_sid, get_global_sam_sid());
-               sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
+               init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
+               init_sec_ace(&ace[i++], &adm_sid, 
+                       SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 
+                       SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+               init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
        }
 
-       init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
-       init_sec_ace(&ace[1], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
-                    sa, SEC_ACE_FLAG_OBJECT_INHERIT |
-                    SEC_ACE_FLAG_INHERIT_ONLY);
+       /* add BUILTIN\Administrators as FULL CONTROL */
 
        init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
-       init_sec_ace(&ace[2], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
-                    sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+       init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, 
+               SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 
+               SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+       init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, 
+               SEC_ACE_TYPE_ACCESS_ALLOWED,
+               sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+       /* Make the security descriptor owned by the BUILTIN\Administrators */
 
        /* The ACL revision number in rpc_secdesc.h differs from the one
           created by NT when setting ACE entries in printer
           descriptors.  NT4 complains about the property being edited by a
           NT5 machine. */
 
-       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) != NULL) {
+       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
                psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
-                                   &owner_sid, NULL,
-                                   NULL, psa, &sd_size);
+                       &global_sid_Builtin_Administrators, 
+                       &global_sid_Builtin_Administrators,
+                       NULL, psa, &sd_size);
        }
 
        if (!psd) {
@@ -4697,24 +5114,28 @@ static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
  Get a security desc for a printer.
 ****************************************************************************/
 
-BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF **secdesc_ctr)
+BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **secdesc_ctr)
 {
        prs_struct ps;
        fstring key;
        char *temp;
+       fstring norm_sharename;
 
-       if (strlen(printername) > 2 && (temp = strchr(printername + 2, '\\'))) {
-               printername = temp + 1;
+       if (strlen(sharename) > 2 && (temp = strchr(sharename + 2, '\\'))) {
+               sharename = temp + 1;
        }
 
        /* Fetch security descriptor from tdb */
 
-       slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
+       fstrcpy( norm_sharename, sharename );
+       strlower_m( norm_sharename );
+
+       slprintf(key, sizeof(key)-1, "SECDESC/%s", norm_sharename);
 
        if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
            !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
 
-               DEBUG(4,("using default secdesc for %s\n", printername));
+               DEBUG(4,("using default secdesc for %s\n", norm_sharename));
 
                if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
                        return False;
@@ -4766,7 +5187,7 @@ BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF *
 
                        /* Set it */
 
-                       nt_printing_setsec(printername, *secdesc_ctr);
+                       nt_printing_setsec(norm_sharename, *secdesc_ctr);
                }
        }
 
@@ -4775,7 +5196,7 @@ BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF *
                int i;
 
                DEBUG(10, ("secdesc_ctr for %s has %d aces:\n", 
-                          printername, the_acl->num_aces));
+                          norm_sharename, the_acl->num_aces));
 
                for (i = 0; i < the_acl->num_aces; i++) {
                        fstring sid_str;
@@ -4859,6 +5280,11 @@ void map_printer_permissions(SEC_DESC *sd)
        print_job_delete, print_job_pause, print_job_resume,
        print_queue_purge
 
+  Try access control in the following order (for performance reasons):
+    1)  root ans SE_PRINT_OPERATOR can do anything (easy check) 
+    2)  check security descriptor (bit comparisons in memory)
+    3)  "printer admins" (may result in numerous calls to winbind)
+
  ****************************************************************************/
 BOOL print_access_check(struct current_user *user, int snum, int access_type)
 {
@@ -4868,17 +5294,16 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
        BOOL result;
        const char *pname;
        TALLOC_CTX *mem_ctx = NULL;
-       extern struct current_user current_user;
+       SE_PRIV se_printop = SE_PRINT_OPERATOR;
        
        /* If user is NULL then use the current_user structure */
 
        if (!user)
                user = &current_user;
 
-       /* Always allow root or printer admins to do anything */
+       /* Always allow root or SE_PRINT_OPERATROR to do anything */
 
-       if (user->uid == 0 ||
-           user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups)) {
+       if ( user->uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) {
                return True;
        }
 
@@ -4927,6 +5352,13 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
 
        DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
 
+        /* see if we need to try the printer admin list */
+
+        if ( access_granted == 0 ) {
+                if ( user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups) )
+                        return True;
+        }
+
        talloc_destroy(mem_ctx);
        
        if (!result)
@@ -4967,3 +5399,10 @@ BOOL print_time_access_check(int snum)
        return ok;
 }
 
+/****************************************************************************
+ Fill in the servername sent in the _spoolss_open_printer_ex() call
+****************************************************************************/
+char* get_server_name( Printer_entry *printer )
+{
+       return printer->servername;
+}