The big character set handling changeover!
[samba.git] / source / printing / nt_printing.c
index eb4b243f2ee4690b189159f185f5a94ed3a641c5..d099c29cc194b35a393f3839bc5a4e87050fe0f5 100644 (file)
@@ -1,4 +1,3 @@
-#define OLD_NTDOMAIN 1
 /*
  *  Unix SMB/Netbios implementation.
  *  Version 1.9.
@@ -33,7 +32,7 @@ static TDB_CONTEXT *tdb; /* used for driver files */
 #define DRIVERS_PREFIX "DRIVERS/"
 #define PRINTERS_PREFIX "PRINTERS/"
 
-#define DATABASE_VERSION 1
+#define NTDRIVERS_DATABASE_VERSION 1
 
 /* Map generic permissions to printer object specific permissions */
 
@@ -50,6 +49,125 @@ array index). Letter is always first, so (for the current code) additions
 always put things in the correct order. */
 static nt_forms_struct default_forms[] = {
        {"Letter", 0x2, 0x34b5b, 0x44367, 0x0, 0x0, 0x34b5b, 0x44367},
+
+       {"Letter",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+       {"Letter Small",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+       {"Tabloid",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
+       {"Ledger",0x1,0x696b8,0x44368,0x0,0x0,0x696b8,0x44368},
+       {"Legal",0x1,0x34b5c,0x56d10,0x0,0x0,0x34b5c,0x56d10},
+       {"Statement",0x1,0x221b4,0x34b5c,0x0,0x0,0x221b4,0x34b5c},
+       {"Executive",0x1,0x2cf56,0x411cc,0x0,0x0,0x2cf56,0x411cc},
+       {"A3",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
+       {"A4",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+       {"A4 Small",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+       {"A5",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
+       {"B4 (JIS)",0x1,0x3ebe8,0x58de0,0x0,0x0,0x3ebe8,0x58de0},
+       {"B5 (JIS)",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
+       {"Folio",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
+       {"Quarto",0x1,0x347d8,0x43238,0x0,0x0,0x347d8,0x43238},
+       {"10x14",0x1,0x3e030,0x56d10,0x0,0x0,0x3e030,0x56d10},
+       {"11x17",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
+       {"Note",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+       {"Envelope #9",0x1,0x18079,0x37091,0x0,0x0,0x18079,0x37091},
+       {"Envelope #10",0x1,0x19947,0x3ae94,0x0,0x0,0x19947,0x3ae94},
+       {"Envelope #11",0x1,0x1be7c,0x40565,0x0,0x0,0x1be7c,0x40565},
+       {"Envelope #12",0x1,0x1d74a,0x44368,0x0,0x0,0x1d74a,0x44368},
+       {"Envelope #14",0x1,0x1f018,0x47504,0x0,0x0,0x1f018,0x47504},
+       {"C size sheet",0x1,0x696b8,0x886d0,0x0,0x0,0x696b8,0x886d0},
+       {"D size sheet",0x1,0x886d0,0xd2d70,0x0,0x0,0x886d0,0xd2d70},
+       {"E size sheet",0x1,0xd2d70,0x110da0,0x0,0x0,0xd2d70,0x110da0},
+       {"Envelope DL",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
+       {"Envelope C5",0x1,0x278d0,0x37e88,0x0,0x0,0x278d0,0x37e88},
+       {"Envelope C3",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
+       {"Envelope C4",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
+       {"Envelope C6",0x1,0x1bd50,0x278d0,0x0,0x0,0x1bd50,0x278d0},
+       {"Envelope C65",0x1,0x1bd50,0x37e88,0x0,0x0,0x1bd50,0x37e88},
+       {"Envelope B4",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
+       {"Envelope B5",0x1,0x2af80,0x3d090,0x0,0x0,0x2af80,0x3d090},
+       {"Envelope B6",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
+       {"Envelope",0x1,0x1adb0,0x38270,0x0,0x0,0x1adb0,0x38270},
+       {"Envelope Monarch",0x1,0x18079,0x2e824,0x0,0x0,0x18079,0x2e824},
+       {"6 3/4 Envelope",0x1,0x167ab,0x284ec,0x0,0x0,0x167ab,0x284ec},
+       {"US Std Fanfold",0x1,0x5c3e1,0x44368,0x0,0x0,0x5c3e1,0x44368},
+       {"German Std Fanfold",0x1,0x34b5c,0x4a6a0,0x0,0x0,0x34b5c,0x4a6a0},
+       {"German Legal Fanfold",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
+       {"B4 (ISO)",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
+       {"Japanese Postcard",0x1,0x186a0,0x24220,0x0,0x0,0x186a0,0x24220},
+       {"9x11",0x1,0x37cf8,0x44368,0x0,0x0,0x37cf8,0x44368},
+       {"10x11",0x1,0x3e030,0x44368,0x0,0x0,0x3e030,0x44368},
+       {"15x11",0x1,0x5d048,0x44368,0x0,0x0,0x5d048,0x44368},
+       {"Envelope Invite",0x1,0x35b60,0x35b60,0x0,0x0,0x35b60,0x35b60},
+       {"Reserved48",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
+       {"Reserved49",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
+       {"Letter Extra",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
+       {"Legal Extra",0x1,0x3ae94,0x5d048,0x0,0x0,0x3ae94,0x5d048},
+       {"Tabloid Extra",0x1,0x4a6a0,0x6f9f0,0x0,0x0,0x4a6a0,0x6f9f0},
+       {"A4 Extra",0x1,0x397c2,0x4eb16,0x0,0x0,0x397c2,0x4eb16},
+       {"Letter Transverse",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
+       {"A4 Transverse",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
+       {"Letter Extra Transverse",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
+       {"Super A",0x1,0x376b8,0x56ea0,0x0,0x0,0x376b8,0x56ea0},
+       {"Super B",0x1,0x4a768,0x76e58,0x0,0x0,0x4a768,0x76e58},
+       {"Letter Plus",0x1,0x34b5c,0x4eb16,0x0,0x0,0x34b5c,0x4eb16},
+       {"A4 Plus",0x1,0x33450,0x50910,0x0,0x0,0x33450,0x50910},
+       {"A5 Transverse",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
+       {"B5 (JIS) Transverse",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
+       {"A3 Extra",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
+       {"A5 Extra",0x1,0x2a7b0,0x395f8,0x0,0x0,0x2a7b0,0x395f8},
+       {"B5 (ISO) Extra",0x1,0x31128,0x43620,0x0,0x0,0x31128,0x43620},
+       {"A2",0x1,0x668a0,0x91050,0x0,0x0,0x668a0,0x91050},
+       {"A3 Transverse",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
+       {"A3 Extra Transverse",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
+       {"Japanese Double Postcard",0x1,0x30d40,0x24220,0x0,0x0,0x30d40,0x24220},
+       {"A6",0x1,0x19a28,0x24220,0x0,0x0,0x19a28,0x24220},
+       {"Japanese Envelope Kaku #2",0x1,0x3a980,0x510e0,0x0,0x0,0x3a980,0x510e0},
+       {"Japanese Envelope Kaku #3",0x1,0x34bc0,0x43a08,0x0,0x0,0x34bc0,0x43a08},
+       {"Japanese Envelope Chou #3",0x1,0x1d4c0,0x395f8,0x0,0x0,0x1d4c0,0x395f8},
+       {"Japanese Envelope Chou #4",0x1,0x15f90,0x320c8,0x0,0x0,0x15f90,0x320c8},
+       {"Letter Rotated",0x1,0x44368,0x34b5c,0x0,0x0,0x44368,0x34b5c},
+       {"A3 Rotated",0x1,0x668a0,0x48828,0x0,0x0,0x668a0,0x48828},
+       {"A4 Rotated",0x1,0x48828,0x33450,0x0,0x0,0x48828,0x33450},
+       {"A5 Rotated",0x1,0x33450,0x24220,0x0,0x0,0x33450,0x24220},
+       {"B4 (JIS) Rotated",0x1,0x58de0,0x3ebe8,0x0,0x0,0x58de0,0x3ebe8},
+       {"B5 (JIS) Rotated",0x1,0x3ebe8,0x2c6f0,0x0,0x0,0x3ebe8,0x2c6f0},
+       {"Japanese Postcard Rotated",0x1,0x24220,0x186a0,0x0,0x0,0x24220,0x186a0},
+       {"Double Japan Postcard Rotated",0x1,0x24220,0x30d40,0x0,0x0,0x24220,0x30d40},
+       {"A6 Rotated",0x1,0x24220,0x19a28,0x0,0x0,0x24220,0x19a28},
+       {"Japan Envelope Kaku #2 Rotated",0x1,0x510e0,0x3a980,0x0,0x0,0x510e0,0x3a980},
+       {"Japan Envelope Kaku #3 Rotated",0x1,0x43a08,0x34bc0,0x0,0x0,0x43a08, 0x34bc0},
+       {"Japan Envelope Chou #3 Rotated",0x1,0x395f8,0x1d4c0,0x0,0x0,0x395f8,0x1d4c0},
+       {"Japan Envelope Chou #4 Rotated",0x1,0x320c8,0x15f90,0x0,0x0,0x320c8,0x15f90},
+       {"B6 (JIS)",0x1,0x1f400,0x2c6f0,0x0,0x0,0x1f400,0x2c6f0},
+       {"B6 (JIS) Rotated",0x1,0x2c6f0,0x1f400,0x0,0x0,0x2c6f0,0x1f400},
+       {"12x11",0x1,0x4a724,0x443e1,0x0,0x0,0x4a724,0x443e1},
+       {"Japan Envelope You #4",0x1,0x19a28,0x395f8,0x0,0x0,0x19a28,0x395f8},
+       {"Japan Envelope You #4 Rotated",0x1,0x395f8,0x19a28,0x0,0x0,0x395f8,0x19a28},
+       {"PRC 16K",0x1,0x2de60,0x3f7a0,0x0,0x0,0x2de60,0x3f7a0},
+       {"PRC 32K",0x1,0x1fbd0,0x2cec0,0x0,0x0,0x1fbd0,0x2cec0},
+       {"PRC 32K(Big)",0x1,0x222e0,0x318f8,0x0,0x0,0x222e0,0x318f8},
+       {"PRC Envelope #1",0x1,0x18e70,0x28488,0x0,0x0,0x18e70,0x28488},
+       {"PRC Envelope #2",0x1,0x18e70,0x2af80,0x0,0x0,0x18e70,0x2af80},
+       {"PRC Envelope #3",0x1,0x1e848,0x2af80,0x0,0x0,0x1e848,0x2af80},
+       {"PRC Envelope #4",0x1,0x1adb0,0x32c80,0x0,0x0,0x1adb0,0x32c80},
+       {"PRC Envelope #5",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
+       {"PRC Envelope #6",0x1,0x1d4c0,0x38270,0x0,0x0,0x1d4c0,0x38270},
+       {"PRC Envelope #7",0x1,0x27100,0x38270,0x0,0x0,0x27100,0x38270},
+       {"PRC Envelope #8",0x1,0x1d4c0,0x4b708,0x0,0x0,0x1d4c0,0x4b708},
+       {"PRC Envelope #9",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
+       {"PRC Envelope #10",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
+       {"PRC 16K Rotated",0x1,0x3f7a0,0x2de60,0x0,0x0,0x3f7a0,0x2de60},
+       {"PRC 32K Rotated",0x1,0x2cec0,0x1fbd0,0x0,0x0,0x2cec0,0x1fbd0},
+       {"PRC 32K(Big) Rotated",0x1,0x318f8,0x222e0,0x0,0x0,0x318f8,0x222e0},
+       {"PRC Envelope #1 Rotated",0x1,0x28488,0x18e70,0x0,0x0,0x28488,0x18e70},
+       {"PRC Envelope #2 Rotated",0x1,0x2af80,0x18e70,0x0,0x0,0x2af80,0x18e70},
+       {"PRC Envelope #3 Rotated",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
+       {"PRC Envelope #4 Rotated",0x1,0x32c80,0x1adb0,0x0,0x0,0x32c80,0x1adb0},
+       {"PRC Envelope #5 Rotated",0x1,0x35b60,0x1adb0,0x0,0x0,0x35b60,0x1adb0},
+       {"PRC Envelope #6 Rotated",0x1,0x38270,0x1d4c0,0x0,0x0,0x38270,0x1d4c0},
+       {"PRC Envelope #7 Rotated",0x1,0x38270,0x27100,0x0,0x0,0x38270,0x27100},
+       {"PRC Envelope #8 Rotated",0x1,0x4b708,0x1d4c0,0x0,0x0,0x4b708,0x1d4c0},
+       {"PRC Envelope #9 Rotated",0x1,0x4f1a0,0x37e88,0x0,0x0,0x4f1a0,0x37e88},
+       {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
 };
 
 
@@ -62,9 +180,10 @@ BOOL nt_printing_init(void)
        char *vstring = "INFO/version";
 
        if (tdb && local_pid == sys_getpid()) return True;
-       tdb = tdb_open(lock_path("ntdrivers.tdb"), 0, 0, O_RDWR|O_CREAT, 0600);
+       tdb = tdb_open_log(lock_path("ntdrivers.tdb"), 0, 0, O_RDWR|O_CREAT, 0600);
        if (!tdb) {
-               DEBUG(0,("Failed to open nt drivers database\n"));
+               DEBUG(0,("Failed to open nt drivers database %s (%s)\n",
+                       lock_path("ntdrivers.tdb"), strerror(errno) ));
                return False;
        }
 
@@ -72,15 +191,45 @@ BOOL nt_printing_init(void)
 
        /* handle a Samba upgrade */
        tdb_lock_bystring(tdb, vstring);
-       if (tdb_fetch_int(tdb, vstring) != DATABASE_VERSION) {
+       if (tdb_fetch_int(tdb, vstring) != NTDRIVERS_DATABASE_VERSION) {
                tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
-               tdb_store_int(tdb, vstring, DATABASE_VERSION);
+               tdb_store_int(tdb, vstring, NTDRIVERS_DATABASE_VERSION);
        }
        tdb_unlock_bystring(tdb, vstring);
 
        return True;
 }
 
+/****************************************************************************
+ get builtin form struct list
+****************************************************************************/
+int get_builtin_ntforms(nt_forms_struct **list)
+{
+       *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
+       return sizeof(default_forms) / sizeof(default_forms[0]);
+}
+
+/****************************************************************************
+ get a builtin form struct
+****************************************************************************/
+
+BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
+{
+       int i,count;
+       fstring form_name;
+       unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
+       DEBUGADD(6,("Looking for builtin form %s \n", form_name));
+       count = sizeof(default_forms) / sizeof(default_forms[0]);
+       for (i=0;i<count;i++) {
+               if (strequal(form_name,default_forms[i].name)) {
+                       DEBUGADD(6,("Found builtin form %s \n", form_name));
+                       memcpy(form,&default_forms[i],sizeof(*form));
+                       break;
+               }
+       }
+
+       return (i !=count);
+}
 
 /****************************************************************************
 get a form struct list
@@ -108,18 +257,13 @@ int get_ntforms(nt_forms_struct **list)
                safe_free(dbuf.dptr);
                if (ret != dbuf.dsize) continue;
 
-               /* allocate space and populate the list in correct order */
-               if (i+1 > n) {
-                       *list = Realloc(*list, sizeof(nt_forms_struct)*(i+1));
-                       n = i+1;
+               *list = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
+               if (!*list) {
+                       DEBUG(0,("get_ntforms: Realloc fail.\n"));
+                       return 0;
                }
-               (*list)[i] = form;
-       }
-
-       /* we should never return a null forms list or NT gets unhappy */
-       if (n == 0) {
-               *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
-               n = sizeof(default_forms) / sizeof(default_forms[0]);
+               (*list)[n] = form;
+               n++;
        }
        
 
@@ -143,8 +287,7 @@ int write_ntforms(nt_forms_struct **list, int number)
                               (*list)[i].left, (*list)[i].top, (*list)[i].right,
                               (*list)[i].bottom);
                if (len > sizeof(buf)) break;
-               slprintf(key, sizeof(key), "%s%s", FORMS_PREFIX, (*list)[i].name);
-        dos_to_unix(key, True);            /* Convert key to unix-codepage */
+               slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
                kbuf.dsize = strlen(key)+1;
                kbuf.dptr = key;
                dbuf.dsize = len;
@@ -211,15 +354,6 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32
 
        *ret = 0;
 
-       if (*count == 1) {
-               /*
-                * Don't delete the last form (no empty lists).
-                * CHECKME ! Is this correct ? JRA.
-                */
-               *ret = ERROR_INVALID_PARAMETER;
-               return False;
-       }
-
        unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
 
        for (n=0; n<*count; n++) {
@@ -235,8 +369,7 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32
                return False;
        }
 
-       slprintf(key, sizeof(key), "%s%s", FORMS_PREFIX, (*list)[n].name);
-       dos_to_unix(key, True);                /* Convert key to unix-codepage */
+       slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
        kbuf.dsize = strlen(key)+1;
        kbuf.dptr = key;
        if (tdb_delete(tdb, kbuf) != 0) {
@@ -288,7 +421,7 @@ int get_ntdrivers(fstring **list, char *architecture, uint32 version)
        TDB_DATA kbuf, newkey;
 
        get_short_archi(short_archi, architecture);
-       slprintf(key, sizeof(key), "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
+       slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
 
        for (kbuf = tdb_firstkey(tdb);
             kbuf.dptr;
@@ -378,7 +511,7 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
        }
 
        become_root();
-       pass = getpwuid(user->uid);
+       pass = sys_getpwuid(user->uid);
        if(pass == NULL) {
                DEBUG(0,("get_correct_cversion: Unable to get passwd entry for uid %u\n",
                                (unsigned int)user->uid ));
@@ -415,7 +548,7 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
 
        /* Open the driver file (Portable Executable format) and determine the
         * deriver the cversion. */
-       slprintf(driverpath, sizeof(driverpath), "%s/%s", architecture, driverpath_in);
+       slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
 
        unix_convert(driverpath,conn,NULL,&bad_path,&st);
 
@@ -509,19 +642,15 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
        DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
                        driverpath, cversion));
 
-       fsp->conn->vfs_ops.close(fsp, fsp->fd);
-       file_free(fsp);
+       close_file(fsp, True);
        close_cnum(conn, user->vuid);
        pop_sec_ctx();
        return cversion;
 
 
        error_exit:
-               if(fsp) {
-                       if(fsp->fd != -1)
-                               fsp->conn->vfs_ops.close(fsp, fsp->fd);
-                       file_free(fsp);
-               }
+               if(fsp)
+                       close_file(fsp, True);
 
                close_cnum(conn, user->vuid);
                pop_sec_ctx();
@@ -1003,9 +1132,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file,
                        DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
                }
        }
-       fsp->conn->vfs_ops.close(fsp, fsp->fd);
-       file_free(fsp);
-
+       close_file(fsp, True);
 
        /* Get file version info (if available) for new file */
        pstrcpy(filepath, new_file);
@@ -1034,8 +1161,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file,
                        DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
                }
        }
-       fsp->conn->vfs_ops.close(fsp, fsp->fd);
-       file_free(fsp);
+       close_file(fsp, True);
 
        if (use_version) {
                /* Compare versions and choose the larger version number */
@@ -1063,11 +1189,8 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file,
        }
 
        error_exit:
-               if(fsp) {
-                       file_free(fsp);
-                       if(fsp->fd != -1)
-                               fsp->conn->vfs_ops.close(fsp, fsp->fd);
-               }
+               if(fsp)
+                       close_file(fsp, True);
                return -1;
 }
 
@@ -1089,7 +1212,6 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        struct passwd *pass;
        int ecode;
        int ver = 0;
-       int outsize = 0;
        int i;
 
        *perr = 0;
@@ -1109,7 +1231,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        get_short_archi(architecture, driver->environment);
 
        become_root();
-       pass = getpwuid(user->uid);
+       pass = sys_getpwuid(user->uid);
        if(pass == NULL) {
                DEBUG(0,("move_driver_to_download_area: Unable to get passwd entry for uid %u\n",
                                (unsigned int)user->uid ));
@@ -1149,7 +1271,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
         * under the architecture directory.
         */
        DEBUG(5,("Creating first directory\n"));
-       slprintf(new_dir, sizeof(new_dir), "%s/%d", architecture, driver->cversion);
+       slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
        mkdir_internal(conn, inbuf, outbuf, new_dir);
 
        /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
@@ -1172,10 +1294,10 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        DEBUG(5,("Moving files now !\n"));
 
        if (driver->driverpath && strlen(driver->driverpath)) {
-               slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->driverpath);        
-               slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->driverpath);     
+               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) {
-                       if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                       if (rename_internals(conn, inbuf, outbuf, new_name, old_name, True) != 0) {
                                DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                new_name, old_name));
                                *perr = (uint32)SVAL(outbuf,smb_err);
@@ -1189,10 +1311,10 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
 
        if (driver->datafile && strlen(driver->datafile)) {
                if (!strequal(driver->datafile, driver->driverpath)) {
-                       slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->datafile);  
-                       slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->datafile);       
+                       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) {
-                               if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                               if (rename_internals(conn, inbuf, outbuf, new_name, old_name, True) != 0) {
                                        DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                        new_name, old_name));
                                        *perr = (uint32)SVAL(outbuf,smb_err);
@@ -1208,10 +1330,10 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        if (driver->configfile && strlen(driver->configfile)) {
                if (!strequal(driver->configfile, driver->driverpath) &&
                        !strequal(driver->configfile, driver->datafile)) {
-                       slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->configfile);        
-                       slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->configfile);     
+                       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) {
-                               if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                               if (rename_internals(conn, inbuf, outbuf, new_name, old_name, True) != 0) {
                                        DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                        new_name, old_name));
                                        *perr = (uint32)SVAL(outbuf,smb_err);
@@ -1228,10 +1350,10 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                if (!strequal(driver->helpfile, driver->driverpath) &&
                        !strequal(driver->helpfile, driver->datafile) &&
                        !strequal(driver->helpfile, driver->configfile)) {
-                       slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->helpfile);  
-                       slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->helpfile);       
+                       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) {
-                               if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                               if (rename_internals(conn, inbuf, outbuf, new_name, old_name, True) != 0) {
                                        DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                        new_name, old_name));
                                        *perr = (uint32)SVAL(outbuf,smb_err);
@@ -1257,10 +1379,10 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                                        }
                                }
 
-                               slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->dependentfiles[i]); 
-                               slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->dependentfiles[i]);      
+                               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) {
-                                       if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                                       if (rename_internals(conn, inbuf, outbuf, new_name, old_name, True) != 0) {
                                                DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
                                                                new_name, old_name));
                                                *perr = (uint32)SVAL(outbuf,smb_err);
@@ -1301,7 +1423,7 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
         * It does make sense to NOT store the server's name in the printer TDB.
         */
 
-       slprintf(directory, sizeof(directory), "\\print$\\%s\\%d\\", architecture, driver->cversion);
+       slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
 
     /* .inf files do not always list a file for each of the four standard files. 
      * Don't prepend a path to a null filename, or client claims:
@@ -1311,33 +1433,32 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
      */
        if (strlen(driver->driverpath)) {
        fstrcpy(temp_name, driver->driverpath);
-       slprintf(driver->driverpath, sizeof(driver->driverpath), "%s%s", directory, temp_name);
+       slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
     }
 
        if (strlen(driver->datafile)) {
        fstrcpy(temp_name, driver->datafile);
-       slprintf(driver->datafile, sizeof(driver->datafile), "%s%s", directory, temp_name);
+       slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
     }
 
        if (strlen(driver->configfile)) {
        fstrcpy(temp_name, driver->configfile);
-       slprintf(driver->configfile, sizeof(driver->configfile), "%s%s", directory, temp_name);
+       slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
     }
 
        if (strlen(driver->helpfile)) {
        fstrcpy(temp_name, driver->helpfile);
-       slprintf(driver->helpfile, sizeof(driver->helpfile), "%s%s", directory, temp_name);
+       slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
     }
 
        if (driver->dependentfiles) {
                for (i=0; *driver->dependentfiles[i]; i++) {
             fstrcpy(temp_name, driver->dependentfiles[i]);
-            slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i]), "%s%s", directory, temp_name);
+            slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
                }
        }
 
-       slprintf(key, sizeof(key), "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
-       dos_to_unix(key, True);                /* Convert key to unix-codepage */
+       slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
 
        DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
 
@@ -1451,7 +1572,7 @@ static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
 
        DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, in_prt));
 
-       slprintf(key, sizeof(key), "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, in_prt);
+       slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, in_prt);
 
        kbuf.dptr = key;
        kbuf.dsize = strlen(key)+1;
@@ -1511,7 +1632,7 @@ uint32 get_a_printer_driver_9x_compatible(pstring line, fstring model)
        int i;
        line[0] = '\0';
 
-       slprintf(key, sizeof(key), "%s%s/%d/%s", DRIVERS_PREFIX, "WIN40", 0, model);
+       slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, "WIN40", 0, model);
        DEBUG(10,("driver key: [%s]\n", key));
        
        kbuf.dptr = key;
@@ -1701,8 +1822,7 @@ uint32 del_a_printer(char *sharename)
        pstring key;
        TDB_DATA kbuf;
 
-       slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, sharename);
-       dos_to_unix(key, True);                /* Convert key to unix-codepage */
+       slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
 
        kbuf.dptr=key;
        kbuf.dsize=strlen(key)+1;
@@ -1722,8 +1842,6 @@ static uint32 update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
        char *buf;
        int buflen, len, ret;
        TDB_DATA kbuf, dbuf;
-       NT_PRINTER_INFO_LEVEL_2 *old_printer = NULL;
-       NT_DEVICEMODE *devmode = NULL;
        
        /*
         * in addprinter: no servername and the printer is the name
@@ -1779,20 +1897,7 @@ static uint32 update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
                        info->datatype,
                        info->parameters);
 
-       /* do not write a NULL devicemode if there was previously
-          a valid one.  Windows 2000 likes to send setprinter calls
-          with NULL devicemodes (e.g. HP 4050 PCL6 driver)  --jerry
-          
-          We need to get the previously saved information for 
-          this printer if the devicemode is NULL */
-       devmode = info->devmode;
-       if (!devmode && info->sharename)
-       {
-               get_a_printer_2(&old_printer, info->sharename);
-               if (old_printer)
-                       devmode = old_printer->devmode;
-       }
-       len += pack_devicemode(devmode, buf+len, buflen-len);
+       len += pack_devicemode(info->devmode, buf+len, buflen-len);
        
        len += pack_specifics(info->specific, buf+len, buflen-len);
 
@@ -1803,8 +1908,7 @@ static uint32 update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
        }
        
 
-       slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, info->sharename);
-       dos_to_unix(key, True);                /* Convert key to unix-codepage */
+       slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename);
 
        kbuf.dptr = key;
        kbuf.dsize = strlen(key)+1;
@@ -1821,9 +1925,6 @@ static uint32 update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
        DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
                 info->sharename, info->drivername, info->portname, len));
 
-       if (old_printer)
-               free_nt_printer_info_level_2(&old_printer);
-       
        return ret;
 }
 
@@ -1977,8 +2078,7 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
        nt_devmode->panningwidth     = 0;
        nt_devmode->panningheight    = 0;
        
-       nt_devmode->private=NULL;
-
+       nt_devmode->private = NULL;
        return nt_devmode;
 }
 
@@ -2041,7 +2141,6 @@ static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
        DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
 
        free_nt_devicemode(&info->devmode);
-       free_sec_desc_buf(&info->secdesc_buf);
 
        for(param_ptr = info->specific; param_ptr; ) {
                NT_PRINTER_PARAM *tofree = param_ptr;
@@ -2110,7 +2209,7 @@ static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
        
        if (devmode.private) {
                /* the len in tdb_unpack is an int value and
-                * devmoce.driverextra is only a short
+                * devmode.driverextra is only a short
                 */
                len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
                devmode.driverextra=(uint16)extra_len;
@@ -2157,6 +2256,86 @@ static int unpack_specifics(NT_PRINTER_PARAM **list, char *buf, int buflen)
        return len;
 }
 
+static void map_to_os2_driver(fstring drivername)
+{
+       static BOOL initialised=False;
+       static fstring last_from,last_to;
+       char *mapfile = lp_os2_driver_map();
+       char **lines = NULL;
+       int numlines = 0;
+       int i;
+
+       if (!strlen(drivername))
+               return;
+
+       if (!*mapfile)
+               return;
+
+       if (!initialised) {
+               *last_from = *last_to = 0;
+               initialised = True;
+       }
+
+       if (strequal(drivername,last_from)) {
+               DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
+               fstrcpy(drivername,last_to);
+               return;
+       }
+
+       lines = file_lines_load(mapfile, &numlines);
+       if (numlines == 0) {
+               DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
+               return;
+       }
+
+       DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
+
+       for( i = 0; i < numlines; i++) {
+               char *nt_name = lines[i];
+               char *os2_name = strchr(nt_name,'=');
+
+               if (!os2_name)
+                       continue;
+
+               *os2_name++ = 0;
+
+               while (isspace(*nt_name))
+                       nt_name++;
+
+               if (!*nt_name || strchr("#;",*nt_name))
+                       continue;
+
+               {
+                       int l = strlen(nt_name);
+                       while (l && isspace(nt_name[l-1])) {
+                               nt_name[l-1] = 0;
+                               l--;
+                       }
+               }
+
+               while (isspace(*os2_name))
+                       os2_name++;
+
+               {
+                       int l = strlen(os2_name);
+                       while (l && isspace(os2_name[l-1])) {
+                               os2_name[l-1] = 0;
+                               l--;
+                       }
+               }
+
+               if (strequal(nt_name,drivername)) {
+                       DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
+                       fstrcpy(last_from,drivername);
+                       fstrcpy(last_to,os2_name);
+                       fstrcpy(drivername,os2_name);
+                       file_lines_free(lines);
+                       return;
+               }
+       }
+
+       file_lines_free(lines);
+}
 
 /****************************************************************************
 get a default printer info 2 struct
@@ -2171,15 +2350,25 @@ static uint32 get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
 
        snum = lp_servicenumber(sharename);
 
-       slprintf(info.servername, sizeof(info.servername), "\\\\%s", global_myname);
-       slprintf(info.printername, sizeof(info.printername), "\\\\%s\\%s", 
+       slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", global_myname);
+       slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s", 
                 global_myname, sharename);
        fstrcpy(info.sharename, sharename);
        fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
        fstrcpy(info.drivername, lp_printerdriver(snum));
 
+#if 0  /* JERRY */
        if (!*info.drivername)
                fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
+#else
+       /* by setting the driver name to an empty string, a local NT admin
+          can now run the **local** APW to install a local printer driver
+          for a Samba shared printer in 2.2.  Without this, drivers **must** be 
+          installed on the Samba server for NT clients --jerry */
+       if (!*info.drivername)
+               fstrcpy(info.drivername, "");
+#endif
+
 
        DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername));
 
@@ -2198,10 +2387,23 @@ static uint32 get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
        info.default_priority = 1;
        info.setuptime = (uint32)time(NULL);
 
+#if 1 /* JRA - NO NOT CHANGE ! */
+       info.devmode = NULL;
+#else
+       /*
+        * We should not return a default devicemode, as this causes
+        * Win2K to not send the correct one on PCL drivers. It needs to
+        * see a null devicemode so it can then overwrite the devicemode
+        * on OpenPrinterEx. Yes this *is* insane :-). JRA.
+        */
        if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL)
                goto fail;
+#endif
+
+       /* This will get the current RPC talloc context, but we should be
+          passing this as a parameter... fixme... JRA ! */
 
-       if (!nt_printing_getsec(sharename, &info.secdesc_buf))
+       if (!nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf))
                goto fail;
 
        *info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info));
@@ -2216,8 +2418,6 @@ static uint32 get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
 
        if (info.devmode)
                free_nt_devicemode(&info.devmode);
-       if (info.secdesc_buf)
-               free_sec_desc_buf(&info.secdesc_buf);
        return 2;
 }
 
@@ -2233,8 +2433,7 @@ static uint32 get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
                
        ZERO_STRUCT(info);
 
-       slprintf(key, sizeof(key), "%s%s", PRINTERS_PREFIX, sharename);
-       dos_to_unix(key, True);                /* Convert key to unix-codepage */
+       slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
 
        kbuf.dptr = key;
        kbuf.dsize = strlen(key)+1;
@@ -2271,15 +2470,23 @@ static uint32 get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharen
        info.attributes |= (PRINTER_ATTRIBUTE_SHARED|PRINTER_ATTRIBUTE_RAW_ONLY);
 
        /* Restore the stripped strings. */
-       slprintf(info.servername, sizeof(info.servername), "\\\\%s", global_myname);
-       slprintf(printername, sizeof(printername), "\\\\%s\\%s", global_myname,
+       slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", global_myname);
+       slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", global_myname,
                        info.printername);
        fstrcpy(info.printername, printername);
 
        len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
        len += unpack_specifics(&info.specific,dbuf.dptr+len, dbuf.dsize-len);
 
-       nt_printing_getsec(sharename, &info.secdesc_buf);
+       /* This will get the current RPC talloc context, but we should be
+       passing this as a parameter... fixme... JRA ! */
+
+       nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf);
+
+       /* Fix for OS/2 drivers. */
+
+       if (get_remote_arch() == RA_OS2)
+               map_to_os2_driver(info.drivername);
 
        safe_free(dbuf.dptr);
        *info_ptr=memdup(&info, sizeof(info));
@@ -2421,9 +2628,13 @@ uint32 add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
                        NTTIME time_nt;
                        time_t time_unix = time(NULL);
                        unix_to_nt_time(&time_nt, time_unix);
-                       printer.info_2->changeid=time_nt.low;
+                       if (printer.info_2->changeid==time_nt.low)
+                               printer.info_2->changeid++;
+                       else
+                               printer.info_2->changeid=time_nt.low;
 
                        printer.info_2->c_setprinter++;
+
                        result=update_a_printer_2(printer.info_2);
                        break;
                }
@@ -2617,6 +2828,113 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
        return result;
 }
 
+
+/****************************************************************************
+  Determine whether or not a particular driver is currently assigned
+  to a printer
+****************************************************************************/
+BOOL printer_driver_in_use (char *arch, char *driver)
+{
+       TDB_DATA kbuf, newkey, dbuf;
+       NT_PRINTER_INFO_LEVEL_2 info;
+       int ret;
+
+       if (!tdb)
+               nt_printing_init();     
+
+       DEBUG(5,("printer_driver_in_use: Beginning search through printers.tdb...\n"));
+       
+       /* loop through the printers.tdb and check for the drivername */
+       for (kbuf = tdb_firstkey(tdb); kbuf.dptr;
+            newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) 
+       {
+
+               dbuf = tdb_fetch(tdb, kbuf);
+               if (!dbuf.dptr) 
+                       continue;
+
+               if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) != 0) 
+                       continue;
+
+               ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddddddfffffPfffff",
+                       &info.attributes,
+                       &info.priority,
+                       &info.default_priority,
+                       &info.starttime,
+                       &info.untiltime,
+                       &info.status,
+                       &info.cjobs,
+                       &info.averageppm,
+                       &info.changeid,
+                       &info.c_setprinter,
+                       &info.setuptime,
+                       info.servername,
+                       info.printername,
+                       info.sharename,
+                       info.portname,
+                       info.drivername,
+                       info.comment,
+                       info.location,
+                       info.sepfile,
+                       info.printprocessor,
+                       info.datatype,
+                       info.parameters);
+
+               safe_free(dbuf.dptr);
+
+               if (ret == -1) {
+                       DEBUG (0,("printer_driver_in_use: tdb_unpack failed for printer %s\n",
+                                       info.printername));
+                       continue;
+               }
+               
+               DEBUG (10,("printer_driver_in_use: Printer - %s (%s)\n",
+                       info.printername, info.drivername));
+                       
+               if (strcmp(info.drivername, driver) == 0) 
+               {
+                       DEBUG(5,("printer_driver_in_use: Printer %s using %s\n",
+                               info.printername, driver));
+                       return True;
+               }       
+       }
+       DEBUG(5,("printer_driver_in_use: Completed search through printers.tdb...\n"));
+       
+       
+       
+       /* report that the driver is in use by default */
+       return False;
+}
+
+/****************************************************************************
+ Remove a printer driver from the TDB.  This assumes that the the driver was
+ previously looked up.
+ ***************************************************************************/
+uint32 delete_printer_driver (NT_PRINTER_DRIVER_INFO_LEVEL_3 *i)
+{
+       pstring         key;
+       fstring         arch;
+       TDB_DATA        kbuf;
+
+
+       get_short_archi(arch, i->environment);
+       slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
+               arch, i->cversion, i->name); 
+       DEBUG(5,("delete_printer_driver: key = [%s]\n", key));
+
+       kbuf.dptr=key;
+       kbuf.dsize=strlen(key)+1;
+
+       if (tdb_delete(tdb, kbuf) == -1) {
+               DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
+               return NT_STATUS_ACCESS_VIOLATION;
+       }
+       
+       DEBUG(5,("delete_printer_driver: [%s] driver delete successful.\n",
+               i->name));
+       
+       return NT_STATUS_NO_PROBLEMO;
+}
 /****************************************************************************
 ****************************************************************************/
 BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, uint32 param_index,
@@ -2656,7 +2974,7 @@ BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
        /* right now that's enough ! */ 
        NT_PRINTER_PARAM *param;
        
-       DEBUG(105, ("get_specific_param\n"));
+       DEBUG(10, ("get_specific_param\n"));
        
        param=printer.info_2->specific;
                
@@ -2673,9 +2991,9 @@ BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
                param=param->next;
        }
        
-       DEBUG(106, ("found one param\n"));
        if (param != NULL)
        {
+        DEBUGADD(10, ("get_specific_param: found one param\n"));
                /* exited because it exist */
                *type=param->type;      
                
@@ -2685,10 +3003,10 @@ BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
                memcpy(*data, param->data, param->data_len);
                *len=param->data_len;
 
-               DEBUG(106, ("exit of get_specific_param:true\n"));
+               DEBUGADD(10, ("get_specific_param: exit true\n"));
                return (True);
        }
-       DEBUG(106, ("exit of get_specific_param:false\n"));
+       DEBUGADD(10, ("get_specific_param: exit false\n"));
        return (False);
 }
 
@@ -2720,7 +3038,7 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
                SEC_DESC *psd = NULL;
                size_t size;
 
-               nt_printing_getsec(printername, &old_secdesc_ctr);
+               nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr);
 
                /* Pick out correct owner and group sids */
 
@@ -2742,18 +3060,13 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
 
                /* Make a deep copy of the security descriptor */
 
-               psd = make_sec_desc(secdesc_ctr->sec->revision,
+               psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision,
                                    owner_sid, group_sid,
                                    sacl,
                                    dacl,
                                    &size);
 
-               new_secdesc_ctr = make_sec_desc_buf(size, psd);
-
-               /* Free up memory */
-
-               free_sec_desc(&psd);
-               free_sec_desc_buf(&old_secdesc_ctr);
+               new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
        }
 
        if (!new_secdesc_ctr) {
@@ -2763,7 +3076,7 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
        /* Store the security descriptor in a tdb */
 
        prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
-                sizeof(SEC_DESC_BUF), 4, mem_ctx, MARSHALL);
+                sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
 
        if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
                             &ps, 1)) {
@@ -2771,7 +3084,7 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
                goto out;
        }
 
-       slprintf(key, sizeof(key), "SECDESC/%s", printername);
+       slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
 
        if (tdb_prs_store(tdb, key, &ps)==0) {
                status = 0;
@@ -2780,14 +3093,9 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
                status = ERROR_INVALID_FUNCTION;
        }
 
-       /* Free mallocated memory */
+       /* Free malloc'ed memory */
 
  out:
-       free_sec_desc_buf(&old_secdesc_ctr);
-
-       if (new_secdesc_ctr != secdesc_ctr) {
-               free_sec_desc_buf(&new_secdesc_ctr);
-       }
 
        prs_mem_free(&ps);
        if (mem_ctx)
@@ -2799,7 +3107,7 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
  Construct a default security descriptor buffer for a printer.
 ****************************************************************************/
 
-static SEC_DESC_BUF *construct_default_printer_sdb(void)
+static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
 {
        SEC_ACE ace[3];
        SEC_ACCESS sa;
@@ -2822,16 +3130,19 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
        if (winbind_lookup_name(lp_workgroup(), &owner_sid, &name_type)) {
                sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
        } else {
+               uint32 owner_rid;
+
+               /* Backup plan - make printer owned by admins or root.
+                  This should emulate a lanman printer as security
+                  settings can't be changed. */
 
-               /* Backup plan - make printer owned by admins or root.  This should
-                  emulate a lanman printer as security settings can't be
-                  changed. */
+               sid_peek_rid(&owner_sid, &owner_rid);
 
-               if (!lookup_name( "Printer Administrators", &owner_sid, &name_type) &&
-                       !lookup_name( "Administrators", &owner_sid, &name_type) &&
-                       !lookup_name( "Administrator", &owner_sid, &name_type) &&
-                       !lookup_name("root", &owner_sid, &name_type)) {
-                                               sid_copy(&owner_sid, &global_sid_World);
+               if (owner_rid != BUILTIN_ALIAS_RID_PRINT_OPS &&
+                   owner_rid != BUILTIN_ALIAS_RID_ADMINS &&
+                   owner_rid != DOMAIN_USER_RID_ADMIN &&
+                   !lookup_name("root", &owner_sid, &name_type)) {
+                       sid_copy(&owner_sid, &global_sid_World);
                }
        }
 
@@ -2849,13 +3160,10 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
           descriptors.  NT4 complains about the property being edited by a
           NT5 machine. */
 
-#define NT4_ACL_REVISION 0x2
-
-       if ((psa = make_sec_acl(NT4_ACL_REVISION, 3, ace)) != NULL) {
-               psd = make_sec_desc(SEC_DESC_REVISION,
+       if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) != NULL) {
+               psd = make_sec_desc(ctx, SEC_DESC_REVISION,
                                    &owner_sid, NULL,
                                    NULL, psa, &sd_size);
-               free_sec_acl(&psa);
        }
 
        if (!psd) {
@@ -2863,12 +3171,11 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
                return NULL;
        }
 
-       sdb = make_sec_desc_buf(sd_size, psd);
+       sdb = make_sec_desc_buf(ctx, sd_size, psd);
 
        DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
                 (unsigned int)sd_size));
 
-       free_sec_desc(&psd);
        return sdb;
 }
 
@@ -2876,36 +3183,29 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
  Get a security desc for a printer.
 ****************************************************************************/
 
-BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr)
+BOOL nt_printing_getsec(TALLOC_CTX *ctx, char *printername, SEC_DESC_BUF **secdesc_ctr)
 {
        prs_struct ps;
-       TALLOC_CTX *mem_ctx = NULL;
        fstring key;
        char *temp;
 
-       mem_ctx = talloc_init();
-       if (mem_ctx == NULL)
-               return False;
-
        if ((temp = strchr(printername + 2, '\\'))) {
                printername = temp + 1;
        }
 
        /* Fetch security descriptor from tdb */
 
-       slprintf(key, sizeof(key), "SECDESC/%s", printername);
+       slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
 
-       if (tdb_prs_fetch(tdb, key, &ps, mem_ctx)!=0 ||
+       if (tdb_prs_fetch(tdb, key, &ps, ctx)!=0 ||
            !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
 
                DEBUG(4,("using default secdesc for %s\n", printername));
 
-               if (!(*secdesc_ctr = construct_default_printer_sdb())) {
-                       talloc_destroy(mem_ctx);
+               if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
                        return False;
                }
 
-               talloc_destroy(mem_ctx);
                return True;
        }
 
@@ -2929,20 +3229,17 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr)
 
                        sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
 
-                       psd = make_sec_desc((*secdesc_ctr)->sec->revision,
+                       psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision,
                                            &owner_sid,
                                            (*secdesc_ctr)->sec->grp_sid,
                                            (*secdesc_ctr)->sec->sacl,
                                            (*secdesc_ctr)->sec->dacl,
                                            &size);
 
-                       new_secdesc_ctr = make_sec_desc_buf(size, psd);
-
-                       free_sec_desc(&psd);
+                       new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
 
                        /* Swap with other one */
 
-                       free_sec_desc_buf(secdesc_ctr);
                        *secdesc_ctr = new_secdesc_ctr;
 
                        /* Set it */
@@ -2952,25 +3249,24 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr)
        }
 
        if (DEBUGLEVEL >= 10) {
-               SEC_ACL *acl = (*secdesc_ctr)->sec->dacl;
+               SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
                int i;
 
                DEBUG(10, ("secdesc_ctr for %s has %d aces:\n", 
-                          printername, acl->num_aces));
+                          printername, the_acl->num_aces));
 
-               for (i = 0; i < acl->num_aces; i++) {
+               for (i = 0; i < the_acl->num_aces; i++) {
                        fstring sid_str;
 
-                       sid_to_string(sid_str, &acl->ace[i].sid);
+                       sid_to_string(sid_str, &the_acl->ace[i].sid);
 
                        DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
-                                  acl->ace[i].type, acl->ace[i].flags, 
-                                  acl->ace[i].info.mask)); 
+                                  the_acl->ace[i].type, the_acl->ace[i].flags, 
+                                  the_acl->ace[i].info.mask)); 
                }
        }
 
        prs_mem_free(&ps);
-       talloc_destroy(mem_ctx);
        return True;
 }
 
@@ -3048,6 +3344,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
        uint32 access_granted, status;
        BOOL result;
        char *pname;
+       TALLOC_CTX *mem_ctx = NULL;
        extern struct current_user current_user;
        
        /* If user is NULL then use the current_user structure */
@@ -3072,7 +3369,12 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
 
        /* Get printer security descriptor */
 
-       nt_printing_getsec(pname, &secdesc);
+       if(!(mem_ctx = talloc_init())) {
+               errno = ENOMEM;
+               return False;
+       }
+
+       nt_printing_getsec(mem_ctx, pname, &secdesc);
 
        if (access_type == JOB_ACCESS_ADMINISTER) {
                SEC_DESC_BUF *parent_secdesc = secdesc;
@@ -3081,9 +3383,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
                   against.  This is because print jobs are child objects
                   objects of a printer. */
 
-               secdesc = se_create_child_secdesc(parent_secdesc->sec, False);
-
-               free_sec_desc_buf(&parent_secdesc);
+               secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
 
                /* Now this is the bit that really confuses me.  The access
                   type needs to be changed from JOB_ACCESS_ADMINISTER to
@@ -3102,11 +3402,9 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
                                 &access_granted, &status);
 
        DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
-       
-       /* Free mallocated memory */
-
-       free_sec_desc_buf(&secdesc);
 
+       talloc_destroy(mem_ctx);
+       
        if (!result)
                errno = EACCES;
 
@@ -3145,5 +3443,78 @@ BOOL print_time_access_check(int snum)
        return ok;
 }
 
+/****************************************************************************
+ Attempt to write a default device.
+*****************************************************************************/
+
+uint32 printer_write_default_dev(int snum, const PRINTER_DEFAULT *printer_default)
+{
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
 
-#undef OLD_NTDOMAIN
+       uint32 result = 0;
+
+       /*
+        * Don't bother if no default devicemode was sent.
+        */
+
+       if (printer_default->devmode_cont.devmode == NULL)
+               return 0;
+
+       if (get_a_printer(&printer, 2, lp_servicename(snum))!=0)
+               return ERROR_ACCESS_DENIED;
+
+       /*
+        * Just ignore it if we already have a devmode.
+        */
+#if 0
+       if (printer->info_2->devmode != NULL)
+               goto done;
+#endif
+       /*
+        * We don't have a devicemode and we're trying to write
+        * one. Check we have the access needed.
+        */
+       DEBUG(5,("printer_write_default_dev: access: %x\n", printer_default->access_required));
+
+       if ( (printer_default->access_required & PRINTER_ACCESS_ADMINISTER) != 
+             PRINTER_ACCESS_ADMINISTER) {
+               DEBUG(5,("printer_write_default_dev: invalid request access to update: %x\n", printer_default->access_required));
+               result = ERROR_ACCESS_DENIED;
+               goto done;
+       }
+
+       if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+               DEBUG(5,("printer_write_default_dev: Access denied for printer %s\n",
+                       lp_servicename(snum) ));
+               result = ERROR_ACCESS_DENIED;
+               /*result = NT_STATUS_NO_PROBLEMO;*/
+               goto done;
+       }
+
+       DEBUG(5,("printer_write_default_dev: updating, check OK.\n"));
+
+       /*
+        * Convert the on the wire devicemode format to the internal one.
+        */
+
+       if (!convert_devicemode(printer->info_2->printername,
+                               printer_default->devmode_cont.devmode,
+                               &printer->info_2->devmode)) {
+               result = ERROR_NOT_ENOUGH_MEMORY;
+               goto done;
+       }
+
+       /*
+        * Finally write back to the tdb.
+        */
+
+       if (add_a_printer(*printer, 2)!=0) {
+               result = ERROR_ACCESS_DENIED;
+               goto done;
+       }
+
+  done:
+
+       free_a_printer(&printer, 2);
+       return result;
+}