printing/nt_printing.c

説明を見る。
00001 /*
00002  *  Unix SMB/CIFS implementation.
00003  *  RPC Pipe client / server routines
00004  *  Copyright (C) Andrew Tridgell              1992-2000,
00005  *  Copyright (C) Jean Fran巽ois Micouleau      1998-2000.
00006  *  Copyright (C) Gerald Carter                2002-2005.
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program; if not, write to the Free Software
00020  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021  */
00022 
00023 #include "includes.h"
00024 
00025 extern struct current_user current_user;
00026 
00027 static TDB_CONTEXT *tdb_forms; /* used for forms files */
00028 static TDB_CONTEXT *tdb_drivers; /* used for driver files */
00029 static TDB_CONTEXT *tdb_printers; /* used for printers files */
00030 
00031 #define FORMS_PREFIX "FORMS/"
00032 #define DRIVERS_PREFIX "DRIVERS/"
00033 #define DRIVER_INIT_PREFIX "DRIVER_INIT/"
00034 #define PRINTERS_PREFIX "PRINTERS/"
00035 #define SECDESC_PREFIX "SECDESC/"
00036 #define GLOBAL_C_SETPRINTER "GLOBALS/c_setprinter"
00037  
00038 #define NTDRIVERS_DATABASE_VERSION_1 1
00039 #define NTDRIVERS_DATABASE_VERSION_2 2
00040 #define NTDRIVERS_DATABASE_VERSION_3 3 /* little endian version of v2 */
00041 #define NTDRIVERS_DATABASE_VERSION_4 4 /* fix generic bits in security descriptors */
00042 #define NTDRIVERS_DATABASE_VERSION_5 5 /* normalize keys in ntprinters.tdb */
00043 
00044 /* Map generic permissions to printer object specific permissions */
00045 
00046 GENERIC_MAPPING printer_generic_mapping = {
00047         PRINTER_READ,
00048         PRINTER_WRITE,
00049         PRINTER_EXECUTE,
00050         PRINTER_ALL_ACCESS
00051 };
00052 
00053 STANDARD_MAPPING printer_std_mapping = {
00054         PRINTER_READ,
00055         PRINTER_WRITE,
00056         PRINTER_EXECUTE,
00057         PRINTER_ALL_ACCESS
00058 };
00059 
00060 /* Map generic permissions to print server object specific permissions */
00061 
00062 GENERIC_MAPPING printserver_generic_mapping = {
00063         SERVER_READ,
00064         SERVER_WRITE,
00065         SERVER_EXECUTE,
00066         SERVER_ALL_ACCESS
00067 };
00068 
00069 STANDARD_MAPPING printserver_std_mapping = {
00070         SERVER_READ,
00071         SERVER_WRITE,
00072         SERVER_EXECUTE,
00073         SERVER_ALL_ACCESS
00074 };
00075 
00076 /* Map generic permissions to job object specific permissions */
00077 
00078 GENERIC_MAPPING job_generic_mapping = {
00079         JOB_READ,
00080         JOB_WRITE,
00081         JOB_EXECUTE,
00082         JOB_ALL_ACCESS
00083 };
00084 
00085 /* We need one default form to support our default printer. Msoft adds the
00086 forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
00087 array index). Letter is always first, so (for the current code) additions
00088 always put things in the correct order. */
00089 static const nt_forms_struct default_forms[] = {
00090         {"Letter",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
00091         {"Letter Small",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
00092         {"Tabloid",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
00093         {"Ledger",0x1,0x696b8,0x44368,0x0,0x0,0x696b8,0x44368},
00094         {"Legal",0x1,0x34b5c,0x56d10,0x0,0x0,0x34b5c,0x56d10},
00095         {"Statement",0x1,0x221b4,0x34b5c,0x0,0x0,0x221b4,0x34b5c},
00096         {"Executive",0x1,0x2cf56,0x411cc,0x0,0x0,0x2cf56,0x411cc},
00097         {"A3",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
00098         {"A4",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
00099         {"A4 Small",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
00100         {"A5",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
00101         {"B4 (JIS)",0x1,0x3ebe8,0x58de0,0x0,0x0,0x3ebe8,0x58de0},
00102         {"B5 (JIS)",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
00103         {"Folio",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
00104         {"Quarto",0x1,0x347d8,0x43238,0x0,0x0,0x347d8,0x43238},
00105         {"10x14",0x1,0x3e030,0x56d10,0x0,0x0,0x3e030,0x56d10},
00106         {"11x17",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
00107         {"Note",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
00108         {"Envelope #9",0x1,0x18079,0x37091,0x0,0x0,0x18079,0x37091},
00109         {"Envelope #10",0x1,0x19947,0x3ae94,0x0,0x0,0x19947,0x3ae94},
00110         {"Envelope #11",0x1,0x1be7c,0x40565,0x0,0x0,0x1be7c,0x40565},
00111         {"Envelope #12",0x1,0x1d74a,0x44368,0x0,0x0,0x1d74a,0x44368},
00112         {"Envelope #14",0x1,0x1f018,0x47504,0x0,0x0,0x1f018,0x47504},
00113         {"C size sheet",0x1,0x696b8,0x886d0,0x0,0x0,0x696b8,0x886d0},
00114         {"D size sheet",0x1,0x886d0,0xd2d70,0x0,0x0,0x886d0,0xd2d70},
00115         {"E size sheet",0x1,0xd2d70,0x110da0,0x0,0x0,0xd2d70,0x110da0},
00116         {"Envelope DL",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
00117         {"Envelope C5",0x1,0x278d0,0x37e88,0x0,0x0,0x278d0,0x37e88},
00118         {"Envelope C3",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
00119         {"Envelope C4",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
00120         {"Envelope C6",0x1,0x1bd50,0x278d0,0x0,0x0,0x1bd50,0x278d0},
00121         {"Envelope C65",0x1,0x1bd50,0x37e88,0x0,0x0,0x1bd50,0x37e88},
00122         {"Envelope B4",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
00123         {"Envelope B5",0x1,0x2af80,0x3d090,0x0,0x0,0x2af80,0x3d090},
00124         {"Envelope B6",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
00125         {"Envelope",0x1,0x1adb0,0x38270,0x0,0x0,0x1adb0,0x38270},
00126         {"Envelope Monarch",0x1,0x18079,0x2e824,0x0,0x0,0x18079,0x2e824},
00127         {"6 3/4 Envelope",0x1,0x167ab,0x284ec,0x0,0x0,0x167ab,0x284ec},
00128         {"US Std Fanfold",0x1,0x5c3e1,0x44368,0x0,0x0,0x5c3e1,0x44368},
00129         {"German Std Fanfold",0x1,0x34b5c,0x4a6a0,0x0,0x0,0x34b5c,0x4a6a0},
00130         {"German Legal Fanfold",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
00131         {"B4 (ISO)",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
00132         {"Japanese Postcard",0x1,0x186a0,0x24220,0x0,0x0,0x186a0,0x24220},
00133         {"9x11",0x1,0x37cf8,0x44368,0x0,0x0,0x37cf8,0x44368},
00134         {"10x11",0x1,0x3e030,0x44368,0x0,0x0,0x3e030,0x44368},
00135         {"15x11",0x1,0x5d048,0x44368,0x0,0x0,0x5d048,0x44368},
00136         {"Envelope Invite",0x1,0x35b60,0x35b60,0x0,0x0,0x35b60,0x35b60},
00137         {"Reserved48",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
00138         {"Reserved49",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
00139         {"Letter Extra",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
00140         {"Legal Extra",0x1,0x3ae94,0x5d048,0x0,0x0,0x3ae94,0x5d048},
00141         {"Tabloid Extra",0x1,0x4a6a0,0x6f9f0,0x0,0x0,0x4a6a0,0x6f9f0},
00142         {"A4 Extra",0x1,0x397c2,0x4eb16,0x0,0x0,0x397c2,0x4eb16},
00143         {"Letter Transverse",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
00144         {"A4 Transverse",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
00145         {"Letter Extra Transverse",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
00146         {"Super A",0x1,0x376b8,0x56ea0,0x0,0x0,0x376b8,0x56ea0},
00147         {"Super B",0x1,0x4a768,0x76e58,0x0,0x0,0x4a768,0x76e58},
00148         {"Letter Plus",0x1,0x34b5c,0x4eb16,0x0,0x0,0x34b5c,0x4eb16},
00149         {"A4 Plus",0x1,0x33450,0x50910,0x0,0x0,0x33450,0x50910},
00150         {"A5 Transverse",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
00151         {"B5 (JIS) Transverse",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
00152         {"A3 Extra",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
00153         {"A5 Extra",0x1,0x2a7b0,0x395f8,0x0,0x0,0x2a7b0,0x395f8},
00154         {"B5 (ISO) Extra",0x1,0x31128,0x43620,0x0,0x0,0x31128,0x43620},
00155         {"A2",0x1,0x668a0,0x91050,0x0,0x0,0x668a0,0x91050},
00156         {"A3 Transverse",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
00157         {"A3 Extra Transverse",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
00158         {"Japanese Double Postcard",0x1,0x30d40,0x24220,0x0,0x0,0x30d40,0x24220},
00159         {"A6",0x1,0x19a28,0x24220,0x0,0x0,0x19a28,0x24220},
00160         {"Japanese Envelope Kaku #2",0x1,0x3a980,0x510e0,0x0,0x0,0x3a980,0x510e0},
00161         {"Japanese Envelope Kaku #3",0x1,0x34bc0,0x43a08,0x0,0x0,0x34bc0,0x43a08},
00162         {"Japanese Envelope Chou #3",0x1,0x1d4c0,0x395f8,0x0,0x0,0x1d4c0,0x395f8},
00163         {"Japanese Envelope Chou #4",0x1,0x15f90,0x320c8,0x0,0x0,0x15f90,0x320c8},
00164         {"Letter Rotated",0x1,0x44368,0x34b5c,0x0,0x0,0x44368,0x34b5c},
00165         {"A3 Rotated",0x1,0x668a0,0x48828,0x0,0x0,0x668a0,0x48828},
00166         {"A4 Rotated",0x1,0x48828,0x33450,0x0,0x0,0x48828,0x33450},
00167         {"A5 Rotated",0x1,0x33450,0x24220,0x0,0x0,0x33450,0x24220},
00168         {"B4 (JIS) Rotated",0x1,0x58de0,0x3ebe8,0x0,0x0,0x58de0,0x3ebe8},
00169         {"B5 (JIS) Rotated",0x1,0x3ebe8,0x2c6f0,0x0,0x0,0x3ebe8,0x2c6f0},
00170         {"Japanese Postcard Rotated",0x1,0x24220,0x186a0,0x0,0x0,0x24220,0x186a0},
00171         {"Double Japan Postcard Rotated",0x1,0x24220,0x30d40,0x0,0x0,0x24220,0x30d40},
00172         {"A6 Rotated",0x1,0x24220,0x19a28,0x0,0x0,0x24220,0x19a28},
00173         {"Japan Envelope Kaku #2 Rotated",0x1,0x510e0,0x3a980,0x0,0x0,0x510e0,0x3a980},
00174         {"Japan Envelope Kaku #3 Rotated",0x1,0x43a08,0x34bc0,0x0,0x0,0x43a08, 0x34bc0},
00175         {"Japan Envelope Chou #3 Rotated",0x1,0x395f8,0x1d4c0,0x0,0x0,0x395f8,0x1d4c0},
00176         {"Japan Envelope Chou #4 Rotated",0x1,0x320c8,0x15f90,0x0,0x0,0x320c8,0x15f90},
00177         {"B6 (JIS)",0x1,0x1f400,0x2c6f0,0x0,0x0,0x1f400,0x2c6f0},
00178         {"B6 (JIS) Rotated",0x1,0x2c6f0,0x1f400,0x0,0x0,0x2c6f0,0x1f400},
00179         {"12x11",0x1,0x4a724,0x443e1,0x0,0x0,0x4a724,0x443e1},
00180         {"Japan Envelope You #4",0x1,0x19a28,0x395f8,0x0,0x0,0x19a28,0x395f8},
00181         {"Japan Envelope You #4 Rotated",0x1,0x395f8,0x19a28,0x0,0x0,0x395f8,0x19a28},
00182         {"PRC 16K",0x1,0x2de60,0x3f7a0,0x0,0x0,0x2de60,0x3f7a0},
00183         {"PRC 32K",0x1,0x1fbd0,0x2cec0,0x0,0x0,0x1fbd0,0x2cec0},
00184         {"PRC 32K(Big)",0x1,0x222e0,0x318f8,0x0,0x0,0x222e0,0x318f8},
00185         {"PRC Envelope #1",0x1,0x18e70,0x28488,0x0,0x0,0x18e70,0x28488},
00186         {"PRC Envelope #2",0x1,0x18e70,0x2af80,0x0,0x0,0x18e70,0x2af80},
00187         {"PRC Envelope #3",0x1,0x1e848,0x2af80,0x0,0x0,0x1e848,0x2af80},
00188         {"PRC Envelope #4",0x1,0x1adb0,0x32c80,0x0,0x0,0x1adb0,0x32c80},
00189         {"PRC Envelope #5",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
00190         {"PRC Envelope #6",0x1,0x1d4c0,0x38270,0x0,0x0,0x1d4c0,0x38270},
00191         {"PRC Envelope #7",0x1,0x27100,0x38270,0x0,0x0,0x27100,0x38270},
00192         {"PRC Envelope #8",0x1,0x1d4c0,0x4b708,0x0,0x0,0x1d4c0,0x4b708},
00193         {"PRC Envelope #9",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
00194         {"PRC Envelope #10",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
00195         {"PRC 16K Rotated",0x1,0x3f7a0,0x2de60,0x0,0x0,0x3f7a0,0x2de60},
00196         {"PRC 32K Rotated",0x1,0x2cec0,0x1fbd0,0x0,0x0,0x2cec0,0x1fbd0},
00197         {"PRC 32K(Big) Rotated",0x1,0x318f8,0x222e0,0x0,0x0,0x318f8,0x222e0},
00198         {"PRC Envelope #1 Rotated",0x1,0x28488,0x18e70,0x0,0x0,0x28488,0x18e70},
00199         {"PRC Envelope #2 Rotated",0x1,0x2af80,0x18e70,0x0,0x0,0x2af80,0x18e70},
00200         {"PRC Envelope #3 Rotated",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
00201         {"PRC Envelope #4 Rotated",0x1,0x32c80,0x1adb0,0x0,0x0,0x32c80,0x1adb0},
00202         {"PRC Envelope #5 Rotated",0x1,0x35b60,0x1adb0,0x0,0x0,0x35b60,0x1adb0},
00203         {"PRC Envelope #6 Rotated",0x1,0x38270,0x1d4c0,0x0,0x0,0x38270,0x1d4c0},
00204         {"PRC Envelope #7 Rotated",0x1,0x38270,0x27100,0x0,0x0,0x38270,0x27100},
00205         {"PRC Envelope #8 Rotated",0x1,0x4b708,0x1d4c0,0x0,0x0,0x4b708,0x1d4c0},
00206         {"PRC Envelope #9 Rotated",0x1,0x4f1a0,0x37e88,0x0,0x0,0x4f1a0,0x37e88},
00207         {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
00208 };
00209 
00210 struct table_node {
00211         const char      *long_archi;
00212         const char      *short_archi;
00213         int     version;
00214 };
00215  
00216 #define SPL_ARCH_WIN40          "WIN40"
00217 #define SPL_ARCH_W32X86         "W32X86"
00218 #define SPL_ARCH_W32MIPS        "W32MIPS"
00219 #define SPL_ARCH_W32ALPHA       "W32ALPHA"
00220 #define SPL_ARCH_W32PPC         "W32PPC"
00221 #define SPL_ARCH_IA64           "IA64"
00222 #define SPL_ARCH_X64            "x64"
00223 
00224 static const struct table_node archi_table[]= {
00225 
00226         {"Windows 4.0",          SPL_ARCH_WIN40,        0 },
00227         {"Windows NT x86",       SPL_ARCH_W32X86,       2 },
00228         {"Windows NT R4000",     SPL_ARCH_W32MIPS,      2 },
00229         {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA,     2 },
00230         {"Windows NT PowerPC",   SPL_ARCH_W32PPC,       2 },
00231         {"Windows IA64",         SPL_ARCH_IA64,         3 },
00232         {"Windows x64",          SPL_ARCH_X64,          3 },
00233         {NULL,                   "",            -1 }
00234 };
00235 
00236 
00237 /****************************************************************************
00238  generate a new TDB_DATA key for storing a printer
00239 ****************************************************************************/
00240 
00241 static TDB_DATA make_printer_tdbkey( const char *sharename )
00242 {
00243         fstring share;
00244         static pstring keystr;
00245         TDB_DATA key;
00246         
00247         fstrcpy( share, sharename );
00248         strlower_m( share );
00249         
00250         pstr_sprintf( keystr, "%s%s", PRINTERS_PREFIX, share );
00251         
00252         key.dptr = keystr;
00253         key.dsize = strlen(keystr)+1;
00254 
00255         return key;
00256 }
00257 
00258 /****************************************************************************
00259  generate a new TDB_DATA key for storing a printer security descriptor
00260 ****************************************************************************/
00261 
00262 static char *make_printers_secdesc_tdbkey( const char* sharename  )
00263 {
00264         fstring share;
00265         static pstring keystr;
00266         
00267         fstrcpy( share, sharename );
00268         strlower_m( share );
00269         
00270         pstr_sprintf( keystr, "%s%s", SECDESC_PREFIX, share );
00271 
00272         return keystr;
00273 }
00274 
00275 /****************************************************************************
00276 ****************************************************************************/
00277 
00278 static BOOL upgrade_to_version_3(void)
00279 {
00280         TDB_DATA kbuf, newkey, dbuf;
00281  
00282         DEBUG(0,("upgrade_to_version_3: upgrading print tdb's to version 3\n"));
00283  
00284         for (kbuf = tdb_firstkey(tdb_drivers); kbuf.dptr;
00285                         newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
00286 
00287                 dbuf = tdb_fetch(tdb_drivers, kbuf);
00288 
00289                 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
00290                         DEBUG(0,("upgrade_to_version_3:moving form\n"));
00291                         if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
00292                                 SAFE_FREE(dbuf.dptr);
00293                                 DEBUG(0,("upgrade_to_version_3: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
00294                                 return False;
00295                         }
00296                         if (tdb_delete(tdb_drivers, kbuf) != 0) {
00297                                 SAFE_FREE(dbuf.dptr);
00298                                 DEBUG(0,("upgrade_to_version_3: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
00299                                 return False;
00300                         }
00301                 }
00302  
00303                 if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
00304                         DEBUG(0,("upgrade_to_version_3:moving printer\n"));
00305                         if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
00306                                 SAFE_FREE(dbuf.dptr);
00307                                 DEBUG(0,("upgrade_to_version_3: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
00308                                 return False;
00309                         }
00310                         if (tdb_delete(tdb_drivers, kbuf) != 0) {
00311                                 SAFE_FREE(dbuf.dptr);
00312                                 DEBUG(0,("upgrade_to_version_3: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
00313                                 return False;
00314                         }
00315                 }
00316  
00317                 if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
00318                         DEBUG(0,("upgrade_to_version_3:moving secdesc\n"));
00319                         if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
00320                                 SAFE_FREE(dbuf.dptr);
00321                                 DEBUG(0,("upgrade_to_version_3: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
00322                                 return False;
00323                         }
00324                         if (tdb_delete(tdb_drivers, kbuf) != 0) {
00325                                 SAFE_FREE(dbuf.dptr);
00326                                 DEBUG(0,("upgrade_to_version_3: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
00327                                 return False;
00328                         }
00329                 }
00330  
00331                 SAFE_FREE(dbuf.dptr);
00332         }
00333 
00334         return True;
00335 }
00336 
00337 /*******************************************************************
00338  Fix an issue with security descriptors.  Printer sec_desc must 
00339  use more than the generic bits that were previously used 
00340  in <= 3.0.14a.  They must also have a owner and group SID assigned.
00341  Otherwise, any printers than have been migrated to a Windows 
00342  host using printmig.exe will not be accessible.
00343 *******************************************************************/
00344 
00345 static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
00346                             TDB_DATA data, void *state )
00347 {
00348         prs_struct ps;
00349         SEC_DESC_BUF *sd_orig = NULL;
00350         SEC_DESC_BUF *sd_new, *sd_store;
00351         SEC_DESC *sec, *new_sec;
00352         TALLOC_CTX *ctx = state;
00353         int result, i;
00354         uint32 sd_size;
00355         size_t size_new_sec;
00356         DOM_SID sid;
00357 
00358         if (!data.dptr || data.dsize == 0) {
00359                 return 0;
00360         }
00361 
00362         if ( strncmp( key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) != 0 ) {
00363                 return 0;
00364         }
00365 
00366         /* upgrade the security descriptor */
00367 
00368         ZERO_STRUCT( ps );
00369 
00370         prs_init( &ps, 0, ctx, UNMARSHALL );
00371         prs_give_memory( &ps, data.dptr, data.dsize, False );
00372 
00373         if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_orig, &ps, 1 ) ) {
00374                 /* delete bad entries */
00375                 DEBUG(0,("sec_desc_upg_fn: Failed to parse original sec_desc for %si.  Deleting....\n", key.dptr ));
00376                 tdb_delete( tdb_printers, key );
00377                 prs_mem_free( &ps );
00378                 return 0;
00379         }
00380 
00381         if (!sd_orig) {
00382                 prs_mem_free( &ps );
00383                 return 0;
00384         }
00385         sec = sd_orig->sec;
00386                 
00387         /* is this even valid? */
00388         
00389         if ( !sec->dacl ) {
00390                 prs_mem_free( &ps );
00391                 return 0;
00392         }
00393                 
00394         /* update access masks */
00395         
00396         for ( i=0; i<sec->dacl->num_aces; i++ ) {
00397                 switch ( sec->dacl->aces[i].access_mask ) {
00398                         case (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS):
00399                                 sec->dacl->aces[i].access_mask = PRINTER_ACE_PRINT;
00400                                 break;
00401                                 
00402                         case GENERIC_ALL_ACCESS:
00403                                 sec->dacl->aces[i].access_mask = PRINTER_ACE_FULL_CONTROL;
00404                                 break;
00405                                 
00406                         case READ_CONTROL_ACCESS:
00407                                 sec->dacl->aces[i].access_mask = PRINTER_ACE_MANAGE_DOCUMENTS;
00408                         
00409                         default:        /* no change */
00410                                 break;
00411                 }
00412         }
00413 
00414         /* create a new SEC_DESC with the appropriate owner and group SIDs */
00415 
00416         string_to_sid(&sid, "S-1-5-32-544" );
00417         new_sec = make_sec_desc( ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
00418                 &sid, &sid,
00419                 NULL, NULL, &size_new_sec );
00420         if (!new_sec) {
00421                 prs_mem_free( &ps );
00422                 return 0;
00423         }
00424         sd_new = make_sec_desc_buf( ctx, size_new_sec, new_sec );
00425         if (!sd_new) {
00426                 prs_mem_free( &ps );
00427                 return 0;
00428         }
00429 
00430         if ( !(sd_store = sec_desc_merge( ctx, sd_new, sd_orig )) ) {
00431                 DEBUG(0,("sec_desc_upg_fn: Failed to update sec_desc for %s\n", key.dptr ));
00432                 prs_mem_free( &ps );
00433                 return 0;
00434         }
00435         
00436         prs_mem_free( &ps );
00437 
00438         /* store it back */
00439         
00440         sd_size = sec_desc_size(sd_store->sec) + sizeof(SEC_DESC_BUF);
00441         prs_init(&ps, sd_size, ctx, MARSHALL);
00442 
00443         if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_store, &ps, 1 ) ) {
00444                 DEBUG(0,("sec_desc_upg_fn: Failed to parse new sec_desc for %s\n", key.dptr ));
00445                 prs_mem_free( &ps );
00446                 return 0;
00447         }
00448 
00449         data.dptr = prs_data_p( &ps );
00450         data.dsize = sd_size;
00451         
00452         result = tdb_store( tdb_printers, key, data, TDB_REPLACE );
00453 
00454         prs_mem_free( &ps );
00455         
00456         /* 0 to continue and non-zero to stop traversal */
00457 
00458         return (result == -1);
00459 }
00460 
00461 /*******************************************************************
00462 *******************************************************************/
00463 
00464 static BOOL upgrade_to_version_4(void)
00465 {
00466         TALLOC_CTX *ctx;
00467         int result;
00468 
00469         DEBUG(0,("upgrade_to_version_4: upgrading printer security descriptors\n"));
00470 
00471         if ( !(ctx = talloc_init( "upgrade_to_version_4" )) ) 
00472                 return False;
00473 
00474         result = tdb_traverse( tdb_printers, sec_desc_upg_fn, ctx );
00475 
00476         talloc_destroy( ctx );
00477 
00478         return ( result != -1 );
00479 }
00480 
00481 /*******************************************************************
00482  Fix an issue with security descriptors.  Printer sec_desc must 
00483  use more than the generic bits that were previously used 
00484  in <= 3.0.14a.  They must also have a owner and group SID assigned.
00485  Otherwise, any printers than have been migrated to a Windows 
00486  host using printmig.exe will not be accessible.
00487 *******************************************************************/
00488 
00489 static int normalize_printers_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
00490                                   TDB_DATA data, void *state )
00491 {
00492         TDB_DATA new_key;
00493         
00494         if (!data.dptr || data.dsize == 0)
00495                 return 0;
00496 
00497         /* upgrade printer records and security descriptors */
00498         
00499         if ( strncmp( key.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX) ) == 0 ) {
00500                 new_key = make_printer_tdbkey( key.dptr+strlen(PRINTERS_PREFIX) );
00501         }
00502         else if ( strncmp( key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) == 0 ) {
00503                 new_key.dptr = make_printers_secdesc_tdbkey( key.dptr+strlen(SECDESC_PREFIX) );
00504                 new_key.dsize = strlen( new_key.dptr ) + 1;
00505         }
00506         else {
00507                 /* ignore this record */
00508                 return 0;
00509         }
00510                 
00511         /* delete the original record and store under the normalized key */
00512         
00513         if ( tdb_delete( the_tdb, key ) != 0 ) {
00514                 DEBUG(0,("normalize_printers_fn: tdb_delete for [%s] failed!\n", 
00515                         key.dptr));
00516                 return 1;
00517         }
00518         
00519         if ( tdb_store( the_tdb, new_key, data, TDB_REPLACE) != 0 ) {
00520                 DEBUG(0,("normalize_printers_fn: failed to store new record for [%s]!\n",
00521                         key.dptr));
00522                 return 1;
00523         }
00524         
00525         return 0;
00526 }
00527 
00528 /*******************************************************************
00529 *******************************************************************/
00530 
00531 static BOOL upgrade_to_version_5(void)
00532 {
00533         TALLOC_CTX *ctx;
00534         int result;
00535 
00536         DEBUG(0,("upgrade_to_version_5: normalizing printer keys\n"));
00537 
00538         if ( !(ctx = talloc_init( "upgrade_to_version_5" )) ) 
00539                 return False;
00540 
00541         result = tdb_traverse( tdb_printers, normalize_printers_fn, NULL );
00542 
00543         talloc_destroy( ctx );
00544 
00545         return ( result != -1 );
00546 }
00547 
00548 /****************************************************************************
00549  Open the NT printing tdbs. Done once before fork().
00550 ****************************************************************************/
00551 
00552 BOOL nt_printing_init(void)
00553 {
00554         const char *vstring = "INFO/version";
00555         WERROR win_rc;
00556         int32 vers_id;
00557 
00558         if ( tdb_drivers && tdb_printers && tdb_forms )
00559                 return True;
00560  
00561         if (tdb_drivers)
00562                 tdb_close(tdb_drivers);
00563         tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
00564         if (!tdb_drivers) {
00565                 DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
00566                         lock_path("ntdrivers.tdb"), strerror(errno) ));
00567                 return False;
00568         }
00569  
00570         if (tdb_printers)
00571                 tdb_close(tdb_printers);
00572         tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
00573         if (!tdb_printers) {
00574                 DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
00575                         lock_path("ntprinters.tdb"), strerror(errno) ));
00576                 return False;
00577         }
00578  
00579         if (tdb_forms)
00580                 tdb_close(tdb_forms);
00581         tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
00582         if (!tdb_forms) {
00583                 DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
00584                         lock_path("ntforms.tdb"), strerror(errno) ));
00585                 return False;
00586         }
00587  
00588         /* handle a Samba upgrade */
00589         
00590         vers_id = tdb_fetch_int32(tdb_drivers, vstring);
00591         if (vers_id == -1) {
00592                 DEBUG(10, ("Fresh database\n"));
00593                 tdb_store_int32( tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5 );
00594                 vers_id = NTDRIVERS_DATABASE_VERSION_5;
00595         }
00596 
00597         if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) {
00598 
00599                 if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) { 
00600                         if (!upgrade_to_version_3())
00601                                 return False;
00602                         tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
00603                         vers_id = NTDRIVERS_DATABASE_VERSION_3;
00604                 } 
00605                 
00606                 if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) {
00607                         /* Written on a bigendian machine with old fetch_int code. Save as le. */
00608                         /* The only upgrade between V2 and V3 is to save the version in little-endian. */
00609                         tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
00610                         vers_id = NTDRIVERS_DATABASE_VERSION_3;
00611                 }
00612 
00613                 if (vers_id == NTDRIVERS_DATABASE_VERSION_3 ) {
00614                         if ( !upgrade_to_version_4() )
00615                                 return False;
00616                         tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_4);
00617                         vers_id = NTDRIVERS_DATABASE_VERSION_4;
00618                 }
00619 
00620                 if (vers_id == NTDRIVERS_DATABASE_VERSION_4 ) {
00621                         if ( !upgrade_to_version_5() )
00622                                 return False;
00623                         tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5);
00624                         vers_id = NTDRIVERS_DATABASE_VERSION_5;
00625                 }
00626 
00627 
00628                 if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) {
00629                         DEBUG(0,("nt_printing_init: Unknown printer database version [%d]\n", vers_id));
00630                         return False;
00631                 }
00632         }
00633         
00634         update_c_setprinter(True);
00635 
00636         /*
00637          * register callback to handle updating printers as new
00638          * drivers are installed
00639          */
00640 
00641         message_register(MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer, NULL);
00642 
00643         /*
00644          * register callback to handle updating printer data
00645          * when a driver is initialized
00646          */
00647 
00648         message_register(MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata,
00649                          NULL);
00650 
00651         /* of course, none of the message callbacks matter if you don't
00652            tell messages.c that you interested in receiving PRINT_GENERAL 
00653            msgs.  This is done in claim_connection() */
00654 
00655 
00656         if ( lp_security() == SEC_ADS ) {
00657                 win_rc = check_published_printers();
00658                 if (!W_ERROR_IS_OK(win_rc))
00659                         DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", dos_errstr(win_rc)));
00660         }
00661 
00662         return True;
00663 }
00664 
00665 /*******************************************************************
00666  Function to allow filename parsing "the old way".
00667 ********************************************************************/
00668 
00669 static void driver_unix_convert(char *name,connection_struct *conn,
00670                 char *saved_last_component, SMB_STRUCT_STAT *pst)
00671 {
00672         unix_format(name);
00673         unix_clean_name(name);
00674         trim_string(name,"/","/");
00675         unix_convert(conn, name, False, saved_last_component, pst);
00676 }
00677 
00678 /*******************************************************************
00679  tdb traversal function for counting printers.
00680 ********************************************************************/
00681 
00682 static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
00683                                       TDB_DATA data, void *context)
00684 {
00685         int *printer_count = (int*)context;
00686  
00687         if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
00688                 (*printer_count)++;
00689                 DEBUG(10,("traverse_counting_printers: printer = [%s]  printer_count = %d\n", key.dptr, *printer_count));
00690         }
00691  
00692         return 0;
00693 }
00694  
00695 /*******************************************************************
00696  Update the spooler global c_setprinter. This variable is initialized
00697  when the parent smbd starts with the number of existing printers. It
00698  is monotonically increased by the current number of printers *after*
00699  each add or delete printer RPC. Only Microsoft knows why... JRR020119
00700 ********************************************************************/
00701 
00702 uint32 update_c_setprinter(BOOL initialize)
00703 {
00704         int32 c_setprinter;
00705         int32 printer_count = 0;
00706  
00707         tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
00708  
00709         /* Traverse the tdb, counting the printers */
00710         tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
00711  
00712         /* If initializing, set c_setprinter to current printers count
00713          * otherwise, bump it by the current printer count
00714          */
00715         if (!initialize)
00716                 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
00717         else
00718                 c_setprinter = printer_count;
00719  
00720         DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
00721         tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
00722  
00723         tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
00724  
00725         return (uint32)c_setprinter;
00726 }
00727 
00728 /*******************************************************************
00729  Get the spooler global c_setprinter, accounting for initialization.
00730 ********************************************************************/
00731 
00732 uint32 get_c_setprinter(void)
00733 {
00734         int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
00735  
00736         if (c_setprinter == (int32)-1)
00737                 c_setprinter = update_c_setprinter(True);
00738  
00739         DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
00740  
00741         return (uint32)c_setprinter;
00742 }
00743 
00744 /****************************************************************************
00745  Get builtin form struct list.
00746 ****************************************************************************/
00747 
00748 int get_builtin_ntforms(nt_forms_struct **list)
00749 {
00750         *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
00751         if (!*list) {
00752                 return 0;
00753         }
00754         return sizeof(default_forms) / sizeof(default_forms[0]);
00755 }
00756 
00757 /****************************************************************************
00758  get a builtin form struct
00759 ****************************************************************************/
00760 
00761 BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
00762 {
00763         int i,count;
00764         fstring form_name;
00765         unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
00766         DEBUGADD(6,("Looking for builtin form %s \n", form_name));
00767         count = sizeof(default_forms) / sizeof(default_forms[0]);
00768         for (i=0;i<count;i++) {
00769                 if (strequal(form_name,default_forms[i].name)) {
00770                         DEBUGADD(6,("Found builtin form %s \n", form_name));
00771                         memcpy(form,&default_forms[i],sizeof(*form));
00772                         break;
00773                 }
00774         }
00775 
00776         return (i !=count);
00777 }
00778 
00779 /****************************************************************************
00780  get a form struct list.
00781 ****************************************************************************/
00782 
00783 int get_ntforms(nt_forms_struct **list)
00784 {
00785         TDB_DATA kbuf, newkey, dbuf;
00786         nt_forms_struct form;
00787         int ret;
00788         int i;
00789         int n = 0;
00790 
00791         *list = NULL;
00792 
00793         for (kbuf = tdb_firstkey(tdb_forms);
00794              kbuf.dptr;
00795              newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey) 
00796         {
00797                 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0) 
00798                         continue;
00799                 
00800                 dbuf = tdb_fetch(tdb_forms, kbuf);
00801                 if (!dbuf.dptr) 
00802                         continue;
00803 
00804                 fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
00805                 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
00806                                  &i, &form.flag, &form.width, &form.length, &form.left,
00807                                  &form.top, &form.right, &form.bottom);
00808                 SAFE_FREE(dbuf.dptr);
00809                 if (ret != dbuf.dsize) 
00810                         continue;
00811 
00812                 *list = SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1);
00813                 if (!*list) {
00814                         DEBUG(0,("get_ntforms: Realloc fail.\n"));
00815                         return 0;
00816                 }
00817                 (*list)[n] = form;
00818                 n++;
00819         }
00820         
00821 
00822         return n;
00823 }
00824 
00825 /****************************************************************************
00826 write a form struct list
00827 ****************************************************************************/
00828 int write_ntforms(nt_forms_struct **list, int number)
00829 {
00830         pstring buf, key;
00831         int len;
00832         TDB_DATA kbuf,dbuf;
00833         int i;
00834 
00835         for (i=0;i<number;i++) {
00836                 /* save index, so list is rebuilt in correct order */
00837                 len = tdb_pack(buf, sizeof(buf), "dddddddd",
00838                                i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
00839                                (*list)[i].left, (*list)[i].top, (*list)[i].right,
00840                                (*list)[i].bottom);
00841                 if (len > sizeof(buf)) break;
00842                 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
00843                 kbuf.dsize = strlen(key)+1;
00844                 kbuf.dptr = key;
00845                 dbuf.dsize = len;
00846                 dbuf.dptr = buf;
00847                 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break;
00848        }
00849 
00850        return i;
00851 }
00852 
00853 /****************************************************************************
00854 add a form struct at the end of the list
00855 ****************************************************************************/
00856 BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
00857 {
00858         int n=0;
00859         BOOL update;
00860         fstring form_name;
00861 
00862         /*
00863          * NT tries to add forms even when
00864          * they are already in the base
00865          * only update the values if already present
00866          */
00867 
00868         update=False;
00869         
00870         unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
00871         for (n=0; n<*count; n++) {
00872                 if ( strequal((*list)[n].name, form_name) ) {
00873                         update=True;
00874                         break;
00875                 }
00876         }
00877 
00878         if (update==False) {
00879                 if((*list=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) {
00880                         DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
00881                         return False;
00882                 }
00883                 unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
00884                 (*count)++;
00885         }
00886         
00887         (*list)[n].flag=form->flags;
00888         (*list)[n].width=form->size_x;
00889         (*list)[n].length=form->size_y;
00890         (*list)[n].left=form->left;
00891         (*list)[n].top=form->top;
00892         (*list)[n].right=form->right;
00893         (*list)[n].bottom=form->bottom;
00894 
00895         DEBUG(6,("add_a_form: Successfully %s form [%s]\n", 
00896                 update ? "updated" : "added", form_name));
00897 
00898         return True;
00899 }
00900 
00901 /****************************************************************************
00902  Delete a named form struct.
00903 ****************************************************************************/
00904 
00905 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
00906 {
00907         pstring key;
00908         TDB_DATA kbuf;
00909         int n=0;
00910         fstring form_name;
00911 
00912         *ret = WERR_OK;
00913 
00914         unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
00915 
00916         for (n=0; n<*count; n++) {
00917                 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
00918                         DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
00919                         break;
00920                 }
00921         }
00922 
00923         if (n == *count) {
00924                 DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
00925                 *ret = WERR_INVALID_PARAM;
00926                 return False;
00927         }
00928 
00929         slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
00930         kbuf.dsize = strlen(key)+1;
00931         kbuf.dptr = key;
00932         if (tdb_delete(tdb_forms, kbuf) != 0) {
00933                 *ret = WERR_NOMEM;
00934                 return False;
00935         }
00936 
00937         return True;
00938 }
00939 
00940 /****************************************************************************
00941  Update a form struct.
00942 ****************************************************************************/
00943 
00944 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
00945 {
00946         int n=0;
00947         fstring form_name;
00948         unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
00949 
00950         DEBUG(106, ("[%s]\n", form_name));
00951         for (n=0; n<count; n++) {
00952                 DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
00953                 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
00954                         break;
00955         }
00956 
00957         if (n==count) return;
00958 
00959         (*list)[n].flag=form->flags;
00960         (*list)[n].width=form->size_x;
00961         (*list)[n].length=form->size_y;
00962         (*list)[n].left=form->left;
00963         (*list)[n].top=form->top;
00964         (*list)[n].right=form->right;
00965         (*list)[n].bottom=form->bottom;
00966 }
00967 
00968 /****************************************************************************
00969  Get the nt drivers list.
00970  Traverse the database and look-up the matching names.
00971 ****************************************************************************/
00972 int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
00973 {
00974         int total=0;
00975         const char *short_archi;
00976         pstring key;
00977         TDB_DATA kbuf, newkey;
00978 
00979         short_archi = get_short_archi(architecture);
00980         if (!short_archi) {
00981                 return 0;
00982         }
00983 
00984         slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
00985 
00986         for (kbuf = tdb_firstkey(tdb_drivers);
00987              kbuf.dptr;
00988              newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
00989 
00990                 if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
00991                         continue;
00992                 
00993                 if((*list = SMB_REALLOC_ARRAY(*list, fstring, total+1)) == NULL) {
00994                         DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
00995                         return -1;
00996                 }
00997 
00998                 fstrcpy((*list)[total], kbuf.dptr+strlen(key));
00999                 total++;
01000         }
01001 
01002         return(total);
01003 }
01004 
01005 /****************************************************************************
01006  Function to do the mapping between the long architecture name and
01007  the short one.
01008 ****************************************************************************/
01009 
01010 const char *get_short_archi(const char *long_archi)
01011 {
01012         int i=-1;
01013 
01014         DEBUG(107,("Getting architecture dependant directory\n"));
01015         do {
01016                 i++;
01017         } while ( (archi_table[i].long_archi!=NULL ) &&
01018                   StrCaseCmp(long_archi, archi_table[i].long_archi) );
01019 
01020         if (archi_table[i].long_archi==NULL) {
01021                 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
01022                 return NULL;
01023         }
01024 
01025         /* this might be client code - but shouldn't this be an fstrcpy etc? */
01026 
01027         DEBUGADD(108,("index: [%d]\n", i));
01028         DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
01029         DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
01030 
01031         return archi_table[i].short_archi;
01032 }
01033 
01034 /****************************************************************************
01035  Version information in Microsoft files is held in a VS_VERSION_INFO structure.
01036  There are two case to be covered here: PE (Portable Executable) and NE (New
01037  Executable) files. Both files support the same INFO structure, but PE files
01038  store the signature in unicode, and NE files store it as !unicode.
01039  returns -1 on error, 1 on version info found, and 0 on no version info found.
01040 ****************************************************************************/
01041 
01042 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
01043 {
01044         int     i;
01045         char    *buf = NULL;
01046         ssize_t byte_count;
01047 
01048         if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
01049                 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
01050                                 fname, DOS_HEADER_SIZE));
01051                 goto error_exit;
01052         }
01053 
01054         if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
01055                 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
01056                          fname, (unsigned long)byte_count));
01057                 goto no_version_info;
01058         }
01059 
01060         /* Is this really a DOS header? */
01061         if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
01062                 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
01063                                 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
01064                 goto no_version_info;
01065         }
01066 
01067         /* Skip OEM header (if any) and the DOS stub to start of Windows header */
01068         if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
01069                 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
01070                                 fname, errno));
01071                 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
01072                 goto no_version_info;
01073         }
01074 
01075         /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
01076         if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
01077                 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
01078                          fname, (unsigned long)byte_count));
01079                 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
01080                 goto no_version_info;
01081         }
01082 
01083         /* The header may be a PE (Portable Executable) or an NE (New Executable) */
01084         if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
01085                 unsigned int num_sections;
01086                 unsigned int section_table_bytes;
01087 
01088                 /* Just skip over optional header to get to section table */
01089                 if (SMB_VFS_LSEEK(fsp, fsp->fh->fd,
01090                                 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
01091                                 SEEK_CUR) == (SMB_OFF_T)-1) {
01092                         DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
01093                                 fname, errno));
01094                         goto error_exit;
01095                 }
01096 
01097                 /* get the section table */
01098                 num_sections        = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
01099                 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
01100                 if (section_table_bytes == 0)
01101                         goto error_exit;
01102 
01103                 SAFE_FREE(buf);
01104                 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
01105                         DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
01106                                         fname, section_table_bytes));
01107                         goto error_exit;
01108                 }
01109 
01110                 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
01111                         DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
01112                                  fname, (unsigned long)byte_count));
01113                         goto error_exit;
01114                 }
01115 
01116                 /* Iterate the section table looking for the resource section ".rsrc" */
01117                 for (i = 0; i < num_sections; i++) {
01118                         int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
01119 
01120                         if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
01121                                 unsigned int section_pos   = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
01122                                 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
01123 
01124                                 if (section_bytes == 0)
01125                                         goto error_exit;
01126 
01127                                 SAFE_FREE(buf);
01128                                 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
01129                                         DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
01130                                                         fname, section_bytes));
01131                                         goto error_exit;
01132                                 }
01133 
01134                                 /* Seek to the start of the .rsrc section info */
01135                                 if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
01136                                         DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
01137                                                         fname, errno));
01138                                         goto error_exit;
01139                                 }
01140 
01141                                 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
01142                                         DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
01143                                                  fname, (unsigned long)byte_count));
01144                                         goto error_exit;
01145                                 }
01146 
01147                                 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
01148                                         goto error_exit;
01149 
01150                                 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
01151                                         /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
01152                                         if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
01153                                                 /* Align to next long address */
01154                                                 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
01155 
01156                                                 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
01157                                                         *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
01158                                                         *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
01159                                                         
01160                                                         DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
01161                                                                           fname, *major, *minor,
01162                                                                           (*major>>16)&0xffff, *major&0xffff,
01163                                                                           (*minor>>16)&0xffff, *minor&0xffff));
01164                                                         SAFE_FREE(buf);
01165                                                         return 1;
01166                                                 }
01167                                         }
01168                                 }
01169                         }
01170                 }
01171 
01172                 /* Version info not found, fall back to origin date/time */
01173                 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
01174                 SAFE_FREE(buf);
01175                 return 0;
01176 
01177         } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
01178                 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
01179                         DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
01180                                         fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
01181                         /* At this point, we assume the file is in error. It still could be somthing
01182                          * else besides a NE file, but it unlikely at this point. */
01183                         goto error_exit;
01184                 }
01185 
01186                 /* Allocate a bit more space to speed up things */
01187                 SAFE_FREE(buf);
01188                 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
01189                         DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes  = %d\n",
01190                                         fname, PE_HEADER_SIZE));
01191                         goto error_exit;
01192                 }
01193 
01194                 /* This is a HACK! I got tired of trying to sort through the messy
01195                  * 'NE' file format. If anyone wants to clean this up please have at
01196                  * it, but this works. 'NE' files will eventually fade away. JRR */
01197                 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
01198                         /* Cover case that should not occur in a well formed 'NE' .dll file */
01199                         if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
01200 
01201                         for(i=0; i<byte_count; i++) {
01202                                 /* Fast skip past data that can't possibly match */
01203                                 if (buf[i] != 'V') continue;
01204 
01205                                 /* Potential match data crosses buf boundry, move it to beginning
01206                                  * of buf, and fill the buf with as much as it will hold. */
01207                                 if (i>byte_count-VS_VERSION_INFO_SIZE) {
01208                                         int bc;
01209 
01210                                         memcpy(buf, &buf[i], byte_count-i);
01211                                         if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
01212                                                                    (byte_count-i))) < 0) {
01213 
01214                                                 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
01215                                                                  fname, errno));
01216                                                 goto error_exit;
01217                                         }
01218 
01219                                         byte_count = bc + (byte_count - i);
01220                                         if (byte_count<VS_VERSION_INFO_SIZE) break;
01221 
01222                                         i = 0;
01223                                 }
01224 
01225                                 /* Check that the full signature string and the magic number that
01226                                  * follows exist (not a perfect solution, but the chances that this
01227                                  * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
01228                                  * twice, as it is simpler to read the code. */
01229                                 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
01230                                         /* Compute skip alignment to next long address */
01231                                         int skip = -(SMB_VFS_LSEEK(fsp, fsp->fh->fd, 0, SEEK_CUR) - (byte_count - i) +
01232                                                                  sizeof(VS_SIGNATURE)) & 3;
01233                                         if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
01234 
01235                                         *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
01236                                         *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
01237                                         DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
01238                                                           fname, *major, *minor,
01239                                                           (*major>>16)&0xffff, *major&0xffff,
01240                                                           (*minor>>16)&0xffff, *minor&0xffff));
01241                                         SAFE_FREE(buf);
01242                                         return 1;
01243                                 }
01244                         }
01245                 }
01246 
01247                 /* Version info not found, fall back to origin date/time */
01248                 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
01249                 SAFE_FREE(buf);
01250                 return 0;
01251 
01252         } else
01253                 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
01254                 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
01255                                 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
01256 
01257         no_version_info:
01258                 SAFE_FREE(buf);
01259                 return 0;
01260 
01261         error_exit:
01262                 SAFE_FREE(buf);
01263                 return -1;
01264 }
01265 
01266 /****************************************************************************
01267 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
01268 share one or more files. During the MS installation process files are checked
01269 to insure that only a newer version of a shared file is installed over an
01270 older version. There are several possibilities for this comparison. If there
01271 is no previous version, the new one is newer (obviously). If either file is
01272 missing the version info structure, compare the creation date (on Unix use
01273 the modification date). Otherwise chose the numerically larger version number.
01274 ****************************************************************************/
01275 
01276 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
01277 {
01278         BOOL   use_version = True;
01279         pstring filepath;
01280 
01281         uint32 new_major;
01282         uint32 new_minor;
01283         time_t new_create_time;
01284 
01285         uint32 old_major;
01286         uint32 old_minor;
01287         time_t old_create_time;
01288 
01289         files_struct    *fsp = NULL;
01290         SMB_STRUCT_STAT st;
01291         SMB_STRUCT_STAT stat_buf;
01292 
01293         NTSTATUS status;
01294 
01295         SET_STAT_INVALID(st);
01296         SET_STAT_INVALID(stat_buf);
01297         new_create_time = (time_t)0;
01298         old_create_time = (time_t)0;
01299 
01300         /* Get file version info (if available) for previous file (if it exists) */
01301         pstrcpy(filepath, old_file);
01302 
01303         driver_unix_convert(filepath,conn,NULL,&stat_buf);
01304 
01305         status = open_file_ntcreate(conn, filepath, &stat_buf,
01306                                 FILE_GENERIC_READ,
01307                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
01308                                 FILE_OPEN,
01309                                 0,
01310                                 FILE_ATTRIBUTE_NORMAL,
01311                                 INTERNAL_OPEN_ONLY,
01312                                 NULL, &fsp);
01313 
01314         if (!NT_STATUS_IS_OK(status)) {
01315                 /* Old file not found, so by definition new file is in fact newer */
01316                 DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
01317                                 filepath, errno));
01318                 return True;
01319 
01320         } else {
01321                 int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
01322                 if (ret == -1) {
01323                         goto error_exit;
01324                 }
01325 
01326                 if (!ret) {
01327                         DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
01328                                          old_file));
01329                         use_version = False;
01330                         if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &st) == -1) goto error_exit;
01331                         old_create_time = st.st_mtime;
01332                         DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
01333                 }
01334         }
01335         close_file(fsp, NORMAL_CLOSE);
01336 
01337         /* Get file version info (if available) for new file */
01338         pstrcpy(filepath, new_file);
01339         driver_unix_convert(filepath,conn,NULL,&stat_buf);
01340 
01341         status = open_file_ntcreate(conn, filepath, &stat_buf,
01342                                 FILE_GENERIC_READ,
01343                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
01344                                 FILE_OPEN,
01345                                 0,
01346                                 FILE_ATTRIBUTE_NORMAL,
01347                                 INTERNAL_OPEN_ONLY,
01348                                 NULL, &fsp);
01349 
01350         if (!NT_STATUS_IS_OK(status)) {
01351                 /* New file not found, this shouldn't occur if the caller did its job */
01352                 DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
01353                                 filepath, errno));
01354                 goto error_exit;
01355 
01356         } else {
01357                 int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
01358                 if (ret == -1) {
01359                         goto error_exit;
01360                 }
01361 
01362                 if (!ret) {
01363                         DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
01364                                          new_file));
01365                         use_version = False;
01366                         if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &st) == -1) goto error_exit;
01367                         new_create_time = st.st_mtime;
01368                         DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
01369                 }
01370         }
01371         close_file(fsp, NORMAL_CLOSE);
01372 
01373         if (use_version && (new_major != old_major || new_minor != old_minor)) {
01374                 /* Compare versions and choose the larger version number */
01375                 if (new_major > old_major ||
01376                         (new_major == old_major && new_minor > old_minor)) {
01377                         
01378                         DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
01379                         return True;
01380                 }
01381                 else {
01382                         DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
01383                         return False;
01384                 }
01385 
01386         } else {
01387                 /* Compare modification time/dates and choose the newest time/date */
01388                 if (new_create_time > old_create_time) {
01389                         DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
01390                         return True;
01391                 }
01392                 else {
01393                         DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
01394                         return False;
01395                 }
01396         }
01397 
01398         error_exit:
01399                 if(fsp)
01400                         close_file(fsp, NORMAL_CLOSE);
01401                 return -1;
01402 }
01403 
01404 /****************************************************************************
01405 Determine the correct cVersion associated with an architecture and driver
01406 ****************************************************************************/
01407 static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
01408                                    struct current_user *user, WERROR *perr)
01409 {
01410         int               cversion;
01411         NTSTATUS          nt_status;
01412         pstring           driverpath;
01413         DATA_BLOB         null_pw;
01414         fstring           res_type;
01415         files_struct      *fsp = NULL;
01416         SMB_STRUCT_STAT   st;
01417         connection_struct *conn;
01418         NTSTATUS status;
01419 
01420         SET_STAT_INVALID(st);
01421 
01422         *perr = WERR_INVALID_PARAM;
01423 
01424         /* If architecture is Windows 95/98/ME, the version is always 0. */
01425         if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
01426                 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
01427                 *perr = WERR_OK;
01428                 return 0;
01429         }
01430 
01431         /* If architecture is Windows x64, the version is always 3. */
01432         if (strcmp(architecture, SPL_ARCH_X64) == 0) {
01433                 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
01434                 *perr = WERR_OK;
01435                 return 3;
01436         }
01437 
01438         /*
01439          * Connect to the print$ share under the same account as the user connected
01440          * to the rpc pipe. Note we must still be root to do this.
01441          */
01442 
01443         /* Null password is ok - we are already an authenticated user... */
01444         null_pw = data_blob(NULL, 0);
01445         fstrcpy(res_type, "A:");
01446         become_root();
01447         conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
01448         unbecome_root();
01449 
01450         if (conn == NULL) {
01451                 DEBUG(0,("get_correct_cversion: Unable to connect\n"));
01452                 *perr = ntstatus_to_werror(nt_status);
01453                 return -1;
01454         }
01455 
01456         /* We are temporarily becoming the connection user. */
01457         if (!become_user(conn, user->vuid)) {
01458                 DEBUG(0,("get_correct_cversion: Can't become user!\n"));
01459                 *perr = WERR_ACCESS_DENIED;
01460                 return -1;
01461         }
01462 
01463         /* Open the driver file (Portable Executable format) and determine the
01464          * deriver the cversion. */
01465         slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
01466 
01467         driver_unix_convert(driverpath,conn,NULL,&st);
01468 
01469         if ( !vfs_file_exist( conn, driverpath, &st ) ) {
01470                 *perr = WERR_BADFILE;
01471                 goto error_exit;
01472         }
01473 
01474         status = open_file_ntcreate(conn, driverpath, &st,
01475                                 FILE_GENERIC_READ,
01476                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
01477                                 FILE_OPEN,
01478                                 0,
01479                                 FILE_ATTRIBUTE_NORMAL,
01480                                 INTERNAL_OPEN_ONLY,
01481                                 NULL, &fsp);
01482 
01483         if (!NT_STATUS_IS_OK(status)) {
01484                 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
01485                                 driverpath, errno));
01486                 *perr = WERR_ACCESS_DENIED;
01487                 goto error_exit;
01488         } else {
01489                 uint32 major;
01490                 uint32 minor;
01491                 int    ret = get_file_version(fsp, driverpath, &major, &minor);
01492                 if (ret == -1) goto error_exit;
01493 
01494                 if (!ret) {
01495                         DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
01496                         goto error_exit;
01497                 }
01498 
01499                 /*
01500                  * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
01501                  * for more details. Version in this case is not just the version of the 
01502                  * file, but the version in the sense of kernal mode (2) vs. user mode
01503                  * (3) drivers. Other bits of the version fields are the version info. 
01504                  * JRR 010716
01505                 */
01506                 cversion = major & 0x0000ffff;
01507                 switch (cversion) {
01508                         case 2: /* WinNT drivers */
01509                         case 3: /* Win2K drivers */
01510                                 break;
01511                         
01512                         default:
01513                                 DEBUG(6,("get_correct_cversion: cversion invalid [%s]  cversion = %d\n", 
01514                                         driverpath, cversion));
01515                                 goto error_exit;
01516                 }
01517 
01518                 DEBUG(10,("get_correct_cversion: Version info found [%s]  major = 0x%x  minor = 0x%x\n",
01519                                   driverpath, major, minor));
01520         }
01521 
01522         DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
01523                 driverpath, cversion));
01524 
01525         close_file(fsp, NORMAL_CLOSE);
01526         close_cnum(conn, user->vuid);
01527         unbecome_user();
01528         *perr = WERR_OK;
01529         return cversion;
01530 
01531 
01532   error_exit:
01533 
01534         if(fsp)
01535                 close_file(fsp, NORMAL_CLOSE);
01536 
01537         close_cnum(conn, user->vuid);
01538         unbecome_user();
01539         return -1;
01540 }
01541 
01542 /****************************************************************************
01543 ****************************************************************************/
01544 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
01545                                                                                          struct current_user *user)
01546 {
01547         const char *architecture;
01548         fstring new_name;
01549         char *p;
01550         int i;
01551         WERROR err;
01552 
01553         /* clean up the driver name.
01554          * we can get .\driver.dll
01555          * or worse c:\windows\system\driver.dll !
01556          */
01557         /* using an intermediate string to not have overlaping memcpy()'s */
01558         if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
01559                 fstrcpy(new_name, p+1);
01560                 fstrcpy(driver->driverpath, new_name);
01561         }
01562 
01563         if ((p = strrchr(driver->datafile,'\\')) != NULL) {
01564                 fstrcpy(new_name, p+1);
01565                 fstrcpy(driver->datafile, new_name);
01566         }
01567 
01568         if ((p = strrchr(driver->configfile,'\\')) != NULL) {
01569                 fstrcpy(new_name, p+1);
01570                 fstrcpy(driver->configfile, new_name);
01571         }
01572 
01573         if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
01574                 fstrcpy(new_name, p+1);
01575                 fstrcpy(driver->helpfile, new_name);
01576         }
01577 
01578         if (driver->dependentfiles) {
01579                 for (i=0; *driver->dependentfiles[i]; i++) {
01580                         if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
01581                                 fstrcpy(new_name, p+1);
01582                                 fstrcpy(driver->dependentfiles[i], new_name);
01583                         }
01584                 }
01585         }
01586 
01587         architecture = get_short_archi(driver->environment);
01588         if (!architecture) {
01589                 return WERR_UNKNOWN_PRINTER_DRIVER;
01590         }
01591         
01592         /* jfm:7/16/2000 the client always sends the cversion=0.
01593          * The server should check which version the driver is by reading
01594          * the PE header of driver->driverpath.
01595          *
01596          * For Windows 95/98 the version is 0 (so the value sent is correct)
01597          * For Windows NT (the architecture doesn't matter)
01598          *      NT 3.1: cversion=0
01599          *      NT 3.5/3.51: cversion=1
01600          *      NT 4: cversion=2
01601          *      NT2K: cversion=3
01602          */
01603         if ((driver->cversion = get_correct_cversion( architecture, driver->driverpath, user, &err)) == -1)
01604                 return err;
01605 
01606         return WERR_OK;
01607 }
01608         
01609 /****************************************************************************
01610 ****************************************************************************/
01611 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
01612 {
01613         const char *architecture;
01614         fstring new_name;
01615         char *p;
01616         int i;
01617         WERROR err;
01618 
01619         /* clean up the driver name.
01620          * we can get .\driver.dll
01621          * or worse c:\windows\system\driver.dll !
01622          */
01623         /* using an intermediate string to not have overlaping memcpy()'s */
01624         if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
01625                 fstrcpy(new_name, p+1);
01626                 fstrcpy(driver->driverpath, new_name);
01627         }
01628 
01629         if ((p = strrchr(driver->datafile,'\\')) != NULL) {
01630                 fstrcpy(new_name, p+1);
01631                 fstrcpy(driver->datafile, new_name);
01632         }
01633 
01634         if ((p = strrchr(driver->configfile,'\\')) != NULL) {
01635                 fstrcpy(new_name, p+1);
01636                 fstrcpy(driver->configfile, new_name);
01637         }
01638 
01639         if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
01640                 fstrcpy(new_name, p+1);
01641                 fstrcpy(driver->helpfile, new_name);
01642         }
01643 
01644         if (driver->dependentfiles) {
01645                 for (i=0; *driver->dependentfiles[i]; i++) {
01646                         if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
01647                                 fstrcpy(new_name, p+1);
01648                                 fstrcpy(driver->dependentfiles[i], new_name);
01649                         }
01650                 }
01651         }
01652 
01653         architecture = get_short_archi(driver->environment);
01654         if (!architecture) {
01655                 return WERR_UNKNOWN_PRINTER_DRIVER;
01656         }
01657 
01658         /* jfm:7/16/2000 the client always sends the cversion=0.
01659          * The server should check which version the driver is by reading
01660          * the PE header of driver->driverpath.
01661          *
01662          * For Windows 95/98 the version is 0 (so the value sent is correct)
01663          * For Windows NT (the architecture doesn't matter)
01664          *      NT 3.1: cversion=0
01665          *      NT 3.5/3.51: cversion=1
01666          *      NT 4: cversion=2
01667          *      NT2K: cversion=3
01668          */
01669 
01670         if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
01671                         return err;
01672 
01673         return WERR_OK;
01674 }
01675 
01676 /****************************************************************************
01677 ****************************************************************************/
01678 WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
01679                                                           uint32 level, struct current_user *user)
01680 {
01681         switch (level) {
01682                 case 3:
01683                 {
01684                         NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
01685                         driver=driver_abstract.info_3;
01686                         return clean_up_driver_struct_level_3(driver, user);
01687                 }
01688                 case 6:
01689                 {
01690                         NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
01691                         driver=driver_abstract.info_6;
01692                         return clean_up_driver_struct_level_6(driver, user);
01693                 }
01694                 default:
01695                         return WERR_INVALID_PARAM;
01696         }
01697 }
01698 
01699 /****************************************************************************
01700  This function sucks and should be replaced. JRA.
01701 ****************************************************************************/
01702 
01703 static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
01704 {
01705     dst->cversion  = src->version;
01706 
01707     fstrcpy( dst->name, src->name);
01708     fstrcpy( dst->environment, src->environment);
01709     fstrcpy( dst->driverpath, src->driverpath);
01710     fstrcpy( dst->datafile, src->datafile);
01711     fstrcpy( dst->configfile, src->configfile);
01712     fstrcpy( dst->helpfile, src->helpfile);
01713     fstrcpy( dst->monitorname, src->monitorname);
01714     fstrcpy( dst->defaultdatatype, src->defaultdatatype);
01715     dst->dependentfiles = src->dependentfiles;
01716 }
01717 
01718 #if 0 /* Debugging function */
01719 
01720 static char* ffmt(unsigned char *c){
01721         int i;
01722         static char ffmt_str[17];
01723 
01724         for (i=0; i<16; i++) {
01725                 if ((c[i] < ' ') || (c[i] > '~'))
01726                         ffmt_str[i]='.';
01727                 else
01728                         ffmt_str[i]=c[i];
01729         }
01730     ffmt_str[16]='\0';
01731         return ffmt_str;
01732 }
01733 
01734 #endif
01735 
01736 /****************************************************************************
01737 ****************************************************************************/
01738 WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, 
01739                                   struct current_user *user, WERROR *perr)
01740 {
01741         NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
01742         NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
01743         const char *architecture;
01744         pstring new_dir;
01745         pstring old_name;
01746         pstring new_name;
01747         DATA_BLOB null_pw;
01748         connection_struct *conn;
01749         NTSTATUS nt_status;
01750         pstring inbuf;
01751         pstring outbuf;
01752         fstring res_type;
01753         SMB_STRUCT_STAT st;
01754         int ver = 0;
01755         int i;
01756 
01757         memset(inbuf, '\0', sizeof(inbuf));
01758         memset(outbuf, '\0', sizeof(outbuf));
01759         *perr = WERR_OK;
01760 
01761         if (level==3)
01762                 driver=driver_abstract.info_3;
01763         else if (level==6) {
01764                 convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
01765                 driver = &converted_driver;
01766         } else {
01767                 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
01768                 return WERR_UNKNOWN_LEVEL;
01769         }
01770 
01771         architecture = get_short_archi(driver->environment);
01772         if (!architecture) {
01773                 return WERR_UNKNOWN_PRINTER_DRIVER;
01774         }
01775 
01776         /*
01777          * Connect to the print$ share under the same account as the user connected to the rpc pipe.
01778          * Note we must be root to do this.
01779          */
01780 
01781         null_pw = data_blob(NULL, 0);
01782         fstrcpy(res_type, "A:");
01783         become_root();
01784         conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
01785         unbecome_root();
01786 
01787         if (conn == NULL) {
01788                 DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
01789                 *perr = ntstatus_to_werror(nt_status);
01790                 return WERR_NO_SUCH_SHARE;
01791         }
01792 
01793         /*
01794          * Save who we are - we are temporarily becoming the connection user.
01795          */
01796 
01797         if (!become_user(conn, conn->vuid)) {
01798                 DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
01799                 return WERR_ACCESS_DENIED;
01800         }
01801 
01802         /*
01803          * make the directories version and version\driver_name
01804          * under the architecture directory.
01805          */
01806         DEBUG(5,("Creating first directory\n"));
01807         slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
01808         driver_unix_convert(new_dir, conn, NULL, &st);
01809         create_directory(conn, new_dir);
01810 
01811         /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
01812          * listed for this driver which has already been moved, skip it (note:
01813          * drivers may list the same file name several times. Then check if the
01814          * file already exists in archi\cversion\, if so, check that the version
01815          * info (or time stamps if version info is unavailable) is newer (or the
01816          * date is later). If it is, move it to archi\cversion\filexxx.yyy.
01817          * Otherwise, delete the file.
01818          *
01819          * If a file is not moved to archi\cversion\ because of an error, all the
01820          * rest of the 'unmoved' driver files are removed from archi\. If one or
01821          * more of the driver's files was already moved to archi\cversion\, it
01822          * potentially leaves the driver in a partially updated state. Version
01823          * trauma will most likely occur if an client attempts to use any printer
01824          * bound to the driver. Perhaps a rewrite to make sure the moves can be
01825          * done is appropriate... later JRR
01826          */
01827 
01828         DEBUG(5,("Moving files now !\n"));
01829 
01830         if (driver->driverpath && strlen(driver->driverpath)) {
01831                 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);      
01832                 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);   
01833                 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
01834                         driver_unix_convert(new_name, conn, NULL, &st);
01835                         if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
01836                                                 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
01837                                 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
01838                                                 new_name, old_name));
01839                                 *perr = WERR_ACCESS_DENIED;
01840                                 ver = -1;
01841                         }
01842                 } 
01843         }
01844 
01845         if (driver->datafile && strlen(driver->datafile)) {
01846                 if (!strequal(driver->datafile, driver->driverpath)) {
01847                         slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);        
01848                         slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);     
01849                         if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
01850                                 driver_unix_convert(new_name, conn, NULL, &st);
01851                                 if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
01852                                                 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
01853                                         DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
01854                                                         new_name, old_name));
01855                                         *perr = WERR_ACCESS_DENIED;
01856                                         ver = -1;
01857                                 }
01858                         }
01859                 }
01860         }
01861 
01862         if (driver->configfile && strlen(driver->configfile)) {
01863                 if (!strequal(driver->configfile, driver->driverpath) &&
01864                         !strequal(driver->configfile, driver->datafile)) {
01865                         slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);      
01866                         slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);   
01867                         if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
01868                                 driver_unix_convert(new_name, conn, NULL, &st);
01869                                 if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
01870                                                 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
01871                                         DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
01872                                                         new_name, old_name));
01873                                         *perr = WERR_ACCESS_DENIED;
01874                                         ver = -1;
01875                                 }
01876                         }
01877                 }
01878         }
01879 
01880         if (driver->helpfile && strlen(driver->helpfile)) {
01881                 if (!strequal(driver->helpfile, driver->driverpath) &&
01882                         !strequal(driver->helpfile, driver->datafile) &&
01883                         !strequal(driver->helpfile, driver->configfile)) {
01884                         slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);        
01885                         slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);     
01886                         if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
01887                                 driver_unix_convert(new_name, conn, NULL, &st);
01888                                 if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
01889                                                 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
01890                                         DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
01891                                                         new_name, old_name));
01892                                         *perr = WERR_ACCESS_DENIED;
01893                                         ver = -1;
01894                                 }
01895                         }
01896                 }
01897         }
01898 
01899         if (driver->dependentfiles) {
01900                 for (i=0; *driver->dependentfiles[i]; i++) {
01901                         if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
01902                                 !strequal(driver->dependentfiles[i], driver->datafile) &&
01903                                 !strequal(driver->dependentfiles[i], driver->configfile) &&
01904                                 !strequal(driver->dependentfiles[i], driver->helpfile)) {
01905                                 int j;
01906                                 for (j=0; j < i; j++) {
01907                                         if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
01908                                                 goto NextDriver;
01909                                         }
01910                                 }
01911 
01912                                 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);       
01913                                 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);    
01914                                 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
01915                                         driver_unix_convert(new_name, conn, NULL, &st);
01916                                         if ( !NT_STATUS_IS_OK(copy_file(conn, new_name, old_name,
01917                                                         OPENX_FILE_EXISTS_TRUNCATE|
01918                                                         OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
01919                                                 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
01920                                                                 new_name, old_name));
01921                                                 *perr = WERR_ACCESS_DENIED;
01922                                                 ver = -1;
01923                                         }
01924                                 }
01925                         }
01926                 NextDriver: ;
01927                 }
01928         }
01929 
01930         close_cnum(conn, user->vuid);
01931         unbecome_user();
01932 
01933         return ver != -1 ? WERR_OK : WERR_UNKNOWN_PRINTER_DRIVER;
01934 }
01935 
01936 /****************************************************************************
01937 ****************************************************************************/
01938 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
01939 {
01940         int len, buflen;
01941         const char *architecture;
01942         pstring directory;
01943         fstring temp_name;
01944         pstring key;
01945         char *buf;
01946         int i, ret;
01947         TDB_DATA kbuf, dbuf;
01948 
01949         architecture = get_short_archi(driver->environment);
01950         if (!architecture) {
01951                 return (uint32)-1;
01952         }
01953 
01954         /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
01955          * \\server is added in the rpc server layer.
01956          * It does make sense to NOT store the server's name in the printer TDB.
01957          */
01958 
01959         slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
01960 
01961         /* .inf files do not always list a file for each of the four standard files. 
01962          * Don't prepend a path to a null filename, or client claims:
01963          *   "The server on which the printer resides does not have a suitable 
01964          *   <printer driver name> printer driver installed. Click OK if you 
01965          *   wish to install the driver on your local machine."
01966          */
01967         if (strlen(driver->driverpath)) {
01968                 fstrcpy(temp_name, driver->driverpath);
01969                 slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
01970         }
01971 
01972         if (strlen(driver->datafile)) {
01973                 fstrcpy(temp_name, driver->datafile);
01974                 slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
01975         }
01976 
01977         if (strlen(driver->configfile)) {
01978                 fstrcpy(temp_name, driver->configfile);
01979                 slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
01980         }
01981 
01982         if (strlen(driver->helpfile)) {
01983                 fstrcpy(temp_name, driver->helpfile);
01984                 slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
01985         }
01986 
01987         if (driver->dependentfiles) {
01988                 for (i=0; *driver->dependentfiles[i]; i++) {
01989                         fstrcpy(temp_name, driver->dependentfiles[i]);
01990                         slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
01991                 }
01992         }
01993 
01994         slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
01995 
01996         DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
01997 
01998         buf = NULL;
01999         len = buflen = 0;
02000 
02001  again:
02002         len = 0;
02003         len += tdb_pack(buf+len, buflen-len, "dffffffff",
02004                         driver->cversion,
02005                         driver->name,
02006                         driver->environment,
02007                         driver->driverpath,
02008                         driver->datafile,
02009                         driver->configfile,
02010                         driver->helpfile,
02011                         driver->monitorname,
02012                         driver->defaultdatatype);
02013 
02014         if (driver->dependentfiles) {
02015                 for (i=0; *driver->dependentfiles[i]; i++) {
02016                         len += tdb_pack(buf+len, buflen-len, "f",
02017                                         driver->dependentfiles[i]);
02018                 }
02019         }
02020 
02021         if (len != buflen) {
02022                 buf = (char *)SMB_REALLOC(buf, len);
02023                 if (!buf) {
02024                         DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
02025                         ret = -1;
02026                         goto done;
02027                 }
02028                 buflen = len;
02029                 goto again;
02030         }
02031 
02032 
02033         kbuf.dptr = key;
02034         kbuf.dsize = strlen(key)+1;
02035         dbuf.dptr = buf;
02036         dbuf.dsize = len;
02037         
02038         ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
02039 
02040 done:
02041         if (ret)
02042                 DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
02043 
02044         SAFE_FREE(buf);
02045         return ret;
02046 }
02047 
02048 /****************************************************************************
02049 ****************************************************************************/
02050 static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
02051 {
02052         NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
02053 
02054         ZERO_STRUCT(info3);
02055         info3.cversion = driver->version;
02056         fstrcpy(info3.name,driver->name);
02057         fstrcpy(info3.environment,driver->environment);
02058         fstrcpy(info3.driverpath,driver->driverpath);
02059         fstrcpy(info3.datafile,driver->datafile);
02060         fstrcpy(info3.configfile,driver->configfile);
02061         fstrcpy(info3.helpfile,driver->helpfile);
02062         fstrcpy(info3.monitorname,driver->monitorname);
02063         fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
02064         info3.dependentfiles = driver->dependentfiles;
02065 
02066         return add_a_printer_driver_3(&info3);
02067 }
02068 
02069 
02070 /****************************************************************************
02071 ****************************************************************************/
02072 static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
02073 {
02074         NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
02075 
02076         ZERO_STRUCT(info);
02077 
02078         fstrcpy(info.name, driver);
02079         fstrcpy(info.defaultdatatype, "RAW");
02080         
02081         fstrcpy(info.driverpath, "");
02082         fstrcpy(info.datafile, "");
02083         fstrcpy(info.configfile, "");
02084         fstrcpy(info.helpfile, "");
02085 
02086         if ((info.dependentfiles= SMB_MALLOC_ARRAY(fstring, 2)) == NULL)
02087                 return WERR_NOMEM;
02088 
02089         memset(info.dependentfiles, '\0', 2*sizeof(fstring));
02090         fstrcpy(info.dependentfiles[0], "");
02091 
02092         *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&info, sizeof(info));
02093         if (!*info_ptr) {
02094                 SAFE_FREE(info.dependentfiles);
02095                 return WERR_NOMEM;
02096         }
02097         
02098         return WERR_OK;
02099 }
02100 
02101 /****************************************************************************
02102 ****************************************************************************/
02103 static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
02104 {
02105         NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
02106         TDB_DATA kbuf, dbuf;
02107         const char *architecture;
02108         int len = 0;
02109         int i;
02110         pstring key;
02111 
02112         ZERO_STRUCT(driver);
02113 
02114         architecture = get_short_archi(arch);
02115         if ( !architecture ) {
02116                 return WERR_UNKNOWN_PRINTER_DRIVER;
02117         }
02118         
02119         /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
02120         
02121         if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 )
02122                 version = 0;
02123 
02124         DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
02125 
02126         slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername);
02127 
02128         kbuf.dptr = key;
02129         kbuf.dsize = strlen(key)+1;
02130         
02131         dbuf = tdb_fetch(tdb_drivers, kbuf);
02132         if (!dbuf.dptr) 
02133                 return WERR_UNKNOWN_PRINTER_DRIVER;
02134 
02135         len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
02136                           &driver.cversion,
02137                           driver.name,
02138                           driver.environment,
02139                           driver.driverpath,
02140                           driver.datafile,
02141                           driver.configfile,
02142                           driver.helpfile,
02143                           driver.monitorname,
02144                           driver.defaultdatatype);
02145 
02146         i=0;
02147         while (len < dbuf.dsize) {
02148                 driver.dependentfiles = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2);
02149                 if ( !driver.dependentfiles ) {
02150                         DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
02151                         break;
02152                 }
02153 
02154                 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
02155                                   &driver.dependentfiles[i]);
02156                 i++;
02157         }
02158         
02159         if ( driver.dependentfiles )
02160                 fstrcpy( driver.dependentfiles[i], "" );
02161 
02162         SAFE_FREE(dbuf.dptr);
02163 
02164         if (len != dbuf.dsize) {
02165                 SAFE_FREE(driver.dependentfiles);
02166 
02167                 return get_a_printer_driver_3_default(info_ptr, drivername, arch);
02168         }
02169 
02170         *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
02171         if (!*info_ptr) {
02172                 SAFE_FREE(driver.dependentfiles);
02173                 return WERR_NOMEM;
02174         }
02175 
02176         return WERR_OK;
02177 }
02178 
02179 /****************************************************************************
02180  Debugging function, dump at level 6 the struct in the logs.
02181 ****************************************************************************/
02182 
02183 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
02184 {
02185         uint32 result;
02186         NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
02187         int i;
02188         
02189         DEBUG(20,("Dumping printer driver at level [%d]\n", level));
02190         
02191         switch (level)
02192         {
02193                 case 3:
02194                 {
02195                         if (driver.info_3 == NULL)
02196                                 result=5;
02197                         else {
02198                                 info3=driver.info_3;
02199                         
02200                                 DEBUGADD(20,("version:[%d]\n",         info3->cversion));
02201                                 DEBUGADD(20,("name:[%s]\n",            info3->name));
02202                                 DEBUGADD(20,("environment:[%s]\n",     info3->environment));
02203                                 DEBUGADD(20,("driverpath:[%s]\n",      info3->driverpath));
02204                                 DEBUGADD(20,("datafile:[%s]\n",        info3->datafile));
02205                                 DEBUGADD(20,("configfile:[%s]\n",      info3->configfile));
02206                                 DEBUGADD(20,("helpfile:[%s]\n",        info3->helpfile));
02207                                 DEBUGADD(20,("monitorname:[%s]\n",     info3->monitorname));
02208                                 DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
02209                                 
02210                                 for (i=0; info3->dependentfiles &&
02211                                           *info3->dependentfiles[i]; i++) {
02212                                         DEBUGADD(20,("dependentfile:[%s]\n",
02213                                                       info3->dependentfiles[i]));
02214                                 }
02215                                 result=0;
02216                         }
02217                         break;
02218                 }
02219                 default:
02220                         DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
02221                         result=1;
02222                         break;
02223         }
02224         
02225         return result;
02226 }
02227 
02228 /****************************************************************************
02229 ****************************************************************************/
02230 int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
02231 {
02232         int len = 0;
02233 
02234         len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
02235 
02236         if (!nt_devmode)
02237                 return len;
02238 
02239         len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
02240                         nt_devmode->devicename,
02241                         nt_devmode->formname,
02242 
02243                         nt_devmode->specversion,
02244                         nt_devmode->driverversion,
02245                         nt_devmode->size,
02246                         nt_devmode->driverextra,
02247                         nt_devmode->orientation,
02248                         nt_devmode->papersize,
02249                         nt_devmode->paperlength,
02250                         nt_devmode->paperwidth,
02251                         nt_devmode->scale,
02252                         nt_devmode->copies,
02253                         nt_devmode->defaultsource,
02254                         nt_devmode->printquality,
02255                         nt_devmode->color,
02256                         nt_devmode->duplex,
02257                         nt_devmode->yresolution,
02258                         nt_devmode->ttoption,
02259                         nt_devmode->collate,
02260                         nt_devmode->logpixels,
02261                         
02262                         nt_devmode->fields,
02263                         nt_devmode->bitsperpel,
02264                         nt_devmode->pelswidth,
02265                         nt_devmode->pelsheight,
02266                         nt_devmode->displayflags,
02267                         nt_devmode->displayfrequency,
02268                         nt_devmode->icmmethod,
02269                         nt_devmode->icmintent,
02270                         nt_devmode->mediatype,
02271                         nt_devmode->dithertype,
02272                         nt_devmode->reserved1,
02273                         nt_devmode->reserved2,
02274                         nt_devmode->panningwidth,
02275                         nt_devmode->panningheight,
02276                         nt_devmode->nt_dev_private);
02277 
02278         
02279         if (nt_devmode->nt_dev_private) {
02280                 len += tdb_pack(buf+len, buflen-len, "B",
02281                                 nt_devmode->driverextra,
02282                                 nt_devmode->nt_dev_private);
02283         }
02284 
02285         DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
02286 
02287         return len;
02288 }
02289 
02290 /****************************************************************************
02291  Pack all values in all printer keys
02292  ***************************************************************************/
02293  
02294 static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
02295 {
02296         int             len = 0;
02297         int             i, j;
02298         REGISTRY_VALUE  *val;
02299         REGVAL_CTR      *val_ctr;
02300         pstring         path;
02301         int             num_values;
02302 
02303         if ( !data )
02304                 return 0;
02305 
02306         /* loop over all keys */
02307                 
02308         for ( i=0; i<data->num_keys; i++ ) {    
02309                 val_ctr = data->keys[i].values;
02310                 num_values = regval_ctr_numvals( val_ctr );
02311 
02312                 /* pack the keyname followed by a empty value */
02313 
02314                 len += tdb_pack(buf+len, buflen-len, "pPdB", 
02315                                 &data->keys[i].name,
02316                                 data->keys[i].name, 
02317                                 REG_NONE,
02318                                 0,
02319                                 NULL);
02320                 
02321                 /* now loop over all values */
02322                 
02323                 for ( j=0; j<num_values; j++ ) {
02324                         /* pathname should be stored as <key><value> */
02325                         
02326                         val = regval_ctr_specific_value( val_ctr, j );
02327                         pstrcpy( path, data->keys[i].name );
02328                         pstrcat( path, "\\" );
02329                         pstrcat( path, regval_name(val) );
02330                         
02331                         len += tdb_pack(buf+len, buflen-len, "pPdB",
02332                                         val,
02333                                         path,
02334                                         regval_type(val),
02335                                         regval_size(val),
02336                                         regval_data_p(val) );
02337 
02338                         DEBUG(8,("specific: [%s], len: %d\n", regval_name(val), regval_size(val)));
02339                 }
02340         
02341         }
02342 
02343         /* terminator */
02344         
02345         len += tdb_pack(buf+len, buflen-len, "p", NULL);
02346 
02347         return len;
02348 }
02349 
02350 
02351 /****************************************************************************
02352  Delete a printer - this just deletes the printer info file, any open
02353  handles are not affected.
02354 ****************************************************************************/
02355 
02356 uint32 del_a_printer(const char *sharename)
02357 {
02358         TDB_DATA kbuf;
02359         pstring printdb_path;
02360 
02361         kbuf = make_printer_tdbkey( sharename );
02362         tdb_delete(tdb_printers, kbuf);
02363 
02364         kbuf.dptr = make_printers_secdesc_tdbkey( sharename );
02365         kbuf.dsize = strlen(kbuf.dptr) + 1;
02366         tdb_delete(tdb_printers, kbuf);
02367 
02368         close_all_print_db();
02369 
02370         if (geteuid() == 0) {
02371                 pstrcpy(printdb_path, lock_path("printing/"));
02372                 pstrcat(printdb_path, sharename);
02373                 pstrcat(printdb_path, ".tdb");
02374 
02375                 unlink(printdb_path);
02376         }
02377 
02378         return 0;
02379 }
02380 
02381 /****************************************************************************
02382 ****************************************************************************/
02383 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
02384 {
02385         char *buf;
02386         int buflen, len;
02387         WERROR ret;
02388         TDB_DATA kbuf, dbuf;
02389         
02390         /*
02391          * in addprinter: no servername and the printer is the name
02392          * in setprinter: servername is \\server
02393          *                and printer is \\server\\printer
02394          *
02395          * Samba manages only local printers.
02396          * we currently don't support things like i
02397          * path=\\other_server\printer
02398          *
02399          * We only store the printername, not \\server\printername
02400          */
02401 
02402         if ( info->servername[0] != '\0' ) {
02403                 trim_string(info->printername, info->servername, NULL);
02404                 trim_char(info->printername, '\\', '\0');
02405                 info->servername[0]='\0';
02406         }
02407 
02408         /*
02409          * JFM: one day I'll forget.
02410          * below that's info->portname because that's the SAMBA sharename
02411          * and I made NT 'thinks' it's the portname
02412          * the info->sharename is the thing you can name when you add a printer
02413          * that's the short-name when you create shared printer for 95/98
02414          * So I've made a limitation in SAMBA: you can only have 1 printer model
02415          * behind a SAMBA share.
02416          */
02417 
02418         buf = NULL;
02419         buflen = 0;
02420 
02421  again: 
02422         len = 0;
02423         len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
02424                         info->attributes,
02425                         info->priority,
02426                         info->default_priority,
02427                         info->starttime,
02428                         info->untiltime,
02429                         info->status,
02430                         info->cjobs,
02431                         info->averageppm,
02432                         info->changeid,
02433                         info->c_setprinter,
02434                         info->setuptime,
02435                         info->servername,
02436                         info->printername,
02437                         info->sharename,
02438                         info->portname,
02439                         info->drivername,
02440                         info->comment,
02441                         info->location,
02442                         info->sepfile,
02443                         info->printprocessor,
02444                         info->datatype,
02445                         info->parameters);
02446 
02447         len += pack_devicemode(info->devmode, buf+len, buflen-len);
02448         
02449         len += pack_values( info->data, buf+len, buflen-len );
02450 
02451         if (buflen != len) {
02452                 buf = (char *)SMB_REALLOC(buf, len);
02453                 if (!buf) {
02454                         DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
02455                         ret = WERR_NOMEM;
02456                         goto done;
02457                 }
02458                 buflen = len;
02459                 goto again;
02460         }
02461         
02462 
02463         kbuf = make_printer_tdbkey( info->sharename );
02464 
02465         dbuf.dptr = buf;
02466         dbuf.dsize = len;
02467 
02468         ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
02469 
02470 done:
02471         if (!W_ERROR_IS_OK(ret))
02472                 DEBUG(8, ("error updating printer to tdb on disk\n"));
02473 
02474         SAFE_FREE(buf);
02475 
02476         DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
02477                  info->sharename, info->drivername, info->portname, len));
02478 
02479         return ret;
02480 }
02481 
02482 
02483 /****************************************************************************
02484  Malloc and return an NT devicemode.
02485 ****************************************************************************/
02486 
02487 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
02488 {
02489 
02490         char adevice[MAXDEVICENAME];
02491         NT_DEVICEMODE *nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE);
02492 
02493         if (nt_devmode == NULL) {
02494                 DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
02495                 return NULL;
02496         }
02497 
02498         ZERO_STRUCTP(nt_devmode);
02499 
02500         slprintf(adevice, sizeof(adevice), "%s", default_devicename);
02501         fstrcpy(nt_devmode->devicename, adevice);       
02502         
02503         fstrcpy(nt_devmode->formname, "Letter");
02504 
02505         nt_devmode->specversion      = 0x0401;
02506         nt_devmode->driverversion    = 0x0400;
02507         nt_devmode->size             = 0x00DC;
02508         nt_devmode->driverextra      = 0x0000;
02509         nt_devmode->fields           = FORMNAME | TTOPTION | PRINTQUALITY |
02510                                        DEFAULTSOURCE | COPIES | SCALE |
02511                                        PAPERSIZE | ORIENTATION;
02512         nt_devmode->orientation      = 1;
02513         nt_devmode->papersize        = PAPER_LETTER;
02514         nt_devmode->paperlength      = 0;
02515         nt_devmode->paperwidth       = 0;
02516         nt_devmode->scale            = 0x64;
02517         nt_devmode->copies           = 1;
02518         nt_devmode->defaultsource    = BIN_FORMSOURCE;
02519         nt_devmode->printquality     = RES_HIGH;           /* 0x0258 */
02520         nt_devmode->color            = COLOR_MONOCHROME;
02521         nt_devmode->duplex           = DUP_SIMPLEX;
02522         nt_devmode->yresolution      = 0;
02523         nt_devmode->ttoption         = TT_SUBDEV;
02524         nt_devmode->collate          = COLLATE_FALSE;
02525         nt_devmode->icmmethod        = 0;
02526         nt_devmode->icmintent        = 0;
02527         nt_devmode->mediatype        = 0;
02528         nt_devmode->dithertype       = 0;
02529 
02530         /* non utilis辿s par un driver d'imprimante */
02531         nt_devmode->logpixels        = 0;
02532         nt_devmode->bitsperpel       = 0;
02533         nt_devmode->pelswidth        = 0;
02534         nt_devmode->pelsheight       = 0;
02535         nt_devmode->displayflags     = 0;
02536         nt_devmode->displayfrequency = 0;
02537         nt_devmode->reserved1        = 0;
02538         nt_devmode->reserved2        = 0;
02539         nt_devmode->panningwidth     = 0;
02540         nt_devmode->panningheight    = 0;
02541         
02542         nt_devmode->nt_dev_private = NULL;
02543         return nt_devmode;
02544 }
02545 
02546 /****************************************************************************
02547  Deepcopy an NT devicemode.
02548 ****************************************************************************/
02549 
02550 NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
02551 {
02552         NT_DEVICEMODE *new_nt_devicemode = NULL;
02553 
02554         if ( !nt_devicemode )
02555                 return NULL;
02556 
02557         if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
02558                 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
02559                 return NULL;
02560         }
02561 
02562         new_nt_devicemode->nt_dev_private = NULL;
02563         if (nt_devicemode->nt_dev_private != NULL) {
02564                 if ((new_nt_devicemode->nt_dev_private = (uint8 *)memdup(nt_devicemode->nt_dev_private, nt_devicemode->driverextra)) == NULL) {
02565                         SAFE_FREE(new_nt_devicemode);
02566                         DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
02567                         return NULL;
02568         }
02569         }
02570 
02571         return new_nt_devicemode;
02572 }
02573 
02574 /****************************************************************************
02575  Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
02576 ****************************************************************************/
02577 
02578 void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
02579 {
02580         NT_DEVICEMODE *nt_devmode = *devmode_ptr;
02581 
02582         if(nt_devmode == NULL)
02583                 return;
02584 
02585         DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
02586 
02587         SAFE_FREE(nt_devmode->nt_dev_private);
02588         SAFE_FREE(*devmode_ptr);
02589 }
02590 
02591 /****************************************************************************
02592  Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
02593 ****************************************************************************/
02594 
02595 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
02596 {
02597         NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
02598 
02599         if ( !info )
02600                 return;
02601 
02602         free_nt_devicemode(&info->devmode);
02603 
02604         TALLOC_FREE( *info_ptr );
02605 }
02606 
02607 
02608 /****************************************************************************
02609 ****************************************************************************/
02610 int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
02611 {
02612         int len = 0;
02613         int extra_len = 0;
02614         NT_DEVICEMODE devmode;
02615         
02616         ZERO_STRUCT(devmode);
02617 
02618         len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
02619 
02620         if (!*nt_devmode) return len;
02621 
02622         len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
02623                           devmode.devicename,
02624                           devmode.formname,
02625 
02626                           &devmode.specversion,
02627                           &devmode.driverversion,
02628                           &devmode.size,
02629                           &devmode.driverextra,
02630                           &devmode.orientation,
02631                           &devmode.papersize,
02632                           &devmode.paperlength,
02633                           &devmode.paperwidth,
02634                           &devmode.scale,
02635                           &devmode.copies,
02636                           &devmode.defaultsource,
02637                           &devmode.printquality,
02638                           &devmode.color,
02639                           &devmode.duplex,
02640                           &devmode.yresolution,
02641                           &devmode.ttoption,
02642                           &devmode.collate,
02643                           &devmode.logpixels,
02644                         
02645                           &devmode.fields,
02646                           &devmode.bitsperpel,
02647                           &devmode.pelswidth,
02648                           &devmode.pelsheight,
02649                           &devmode.displayflags,
02650                           &devmode.displayfrequency,
02651                           &devmode.icmmethod,
02652                           &devmode.icmintent,
02653                           &devmode.mediatype,
02654                           &devmode.dithertype,
02655                           &devmode.reserved1,
02656                           &devmode.reserved2,
02657                           &devmode.panningwidth,
02658                           &devmode.panningheight,
02659                           &devmode.nt_dev_private);
02660         
02661         if (devmode.nt_dev_private) {
02662                 /* the len in tdb_unpack is an int value and
02663                  * devmode.driverextra is only a short
02664                  */
02665                 len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.nt_dev_private);
02666                 devmode.driverextra=(uint16)extra_len;
02667                 
02668                 /* check to catch an invalid TDB entry so we don't segfault */
02669                 if (devmode.driverextra == 0) {
02670                         devmode.nt_dev_private = NULL;
02671                 }
02672         }
02673 
02674         *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
02675         if (!*nt_devmode) {
02676                 SAFE_FREE(devmode.nt_dev_private);
02677                 return -1;
02678         }
02679 
02680         DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
02681         if (devmode.nt_dev_private)
02682                 DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
02683 
02684         return len;
02685 }
02686 
02687 /****************************************************************************
02688  Allocate and initialize a new slot.
02689 ***************************************************************************/
02690  
02691 int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
02692 {
02693         NT_PRINTER_KEY  *d;
02694         int             key_index;
02695         
02696         if ( !name || !data )
02697                 return -1;
02698 
02699         /* allocate another slot in the NT_PRINTER_KEY array */
02700         
02701         if ( !(d = TALLOC_REALLOC_ARRAY( data, data->keys, NT_PRINTER_KEY, data->num_keys+1)) ) {
02702                 DEBUG(0,("add_new_printer_key: Realloc() failed!\n"));
02703                 return -1;
02704         }
02705 
02706         data->keys = d;
02707         
02708         key_index = data->num_keys;
02709         
02710         /* initialze new key */
02711         
02712         data->keys[key_index].name = talloc_strdup( data, name );
02713         
02714         if ( !(data->keys[key_index].values = TALLOC_ZERO_P( data, REGVAL_CTR )) ) 
02715                 return -1;
02716         
02717         data->num_keys++;
02718 
02719         DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
02720         
02721         return key_index;
02722 }
02723 
02724 /****************************************************************************
02725  search for a registry key name in the existing printer data
02726  ***************************************************************************/
02727 
02728 int delete_printer_key( NT_PRINTER_DATA *data, const char *name )
02729 {
02730         int i;
02731         
02732         for ( i=0; i<data->num_keys; i++ ) {
02733                 if ( strequal( data->keys[i].name, name ) ) {
02734                 
02735                         /* cleanup memory */
02736                         
02737                         TALLOC_FREE( data->keys[i].name );
02738                         TALLOC_FREE( data->keys[i].values );
02739                         
02740                         /* if not the end of the array, move remaining elements down one slot */
02741                         
02742                         data->num_keys--;
02743                         if ( data->num_keys && (i < data->num_keys) )
02744                                 memmove( &data->keys[i], &data->keys[i+1], sizeof(NT_PRINTER_KEY)*(data->num_keys-i) );
02745                                 
02746                         break;
02747                 }
02748         }
02749         
02750 
02751         return data->num_keys;
02752 }
02753 
02754 /****************************************************************************
02755  search for a registry key name in the existing printer data
02756  ***************************************************************************/
02757  
02758 int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
02759 {
02760         int             key_index = -1;
02761         int             i;
02762         
02763         if ( !data || !name )
02764                 return -1;
02765 
02766         DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
02767 
02768         /* loop over all existing keys */
02769         
02770         for ( i=0; i<data->num_keys; i++ ) {
02771                 if ( strequal(data->keys[i].name, name) ) {
02772                         DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
02773                         key_index = i;
02774                         break;
02775                 
02776                 }
02777         }
02778         
02779         return key_index;
02780 }
02781 
02782 /****************************************************************************
02783  ***************************************************************************/
02784 
02785 int get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
02786 {
02787         int     i, j;
02788         int     key_len;
02789         int     num_subkeys = 0;
02790         char    *p;
02791         fstring *subkeys_ptr = NULL;
02792         fstring subkeyname;
02793         
02794         *subkeys = NULL;
02795 
02796         if ( !data )
02797                 return 0;
02798 
02799         if ( !key )
02800                 return -1;
02801 
02802         /* special case of asking for the top level printer data registry key names */
02803 
02804         if ( strlen(key) == 0 ) {
02805                 for ( i=0; i<data->num_keys; i++ ) {
02806                 
02807                         /* found a match, so allocate space and copy the name */
02808                         
02809                         if ( !(subkeys_ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
02810                                 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n", 
02811                                         num_subkeys+1));
02812                                 return -1;
02813                         }
02814                         
02815                         fstrcpy( subkeys_ptr[num_subkeys], data->keys[i].name );
02816                         num_subkeys++;
02817                 }
02818 
02819                 goto done;
02820         }
02821                 
02822         /* asking for the subkeys of some key */
02823         /* subkey paths are stored in the key name using '\' as the delimiter */
02824 
02825         for ( i=0; i<data->num_keys; i++ ) {
02826                 if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
02827                         
02828                         /* if we found the exact key, then break */
02829                         key_len = strlen( key );
02830                         if ( strlen(data->keys[i].name) == key_len )
02831                                 break;
02832                         
02833                         /* get subkey path */
02834 
02835                         p = data->keys[i].name + key_len;
02836                         if ( *p == '\\' )
02837                                 p++;
02838                         fstrcpy( subkeyname, p );
02839                         if ( (p = strchr( subkeyname, '\\' )) )
02840                                 *p = '\0';
02841                         
02842                         /* don't add a key more than once */
02843                         
02844                         for ( j=0; j<num_subkeys; j++ ) {
02845                                 if ( strequal( subkeys_ptr[j], subkeyname ) )
02846                                         break;
02847                         }
02848                         
02849                         if ( j != num_subkeys )
02850                                 continue;
02851 
02852                         /* found a match, so allocate space and copy the name */
02853                         
02854                         if ( !(subkeys_ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
02855                                 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n", 
02856                                         num_subkeys+1));
02857                                 return 0;
02858                         }
02859                         
02860                         fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
02861                         num_subkeys++;
02862                 }
02863                 
02864         }
02865         
02866         /* return error if the key was not found */
02867         
02868         if ( i == data->num_keys ) {
02869                 SAFE_FREE(subkeys_ptr);
02870                 return -1;
02871         }
02872         
02873 done:
02874         /* tag off the end */
02875         
02876         if (num_subkeys)
02877                 fstrcpy(subkeys_ptr[num_subkeys], "" );
02878         
02879         *subkeys = subkeys_ptr;
02880 
02881         return num_subkeys;
02882 }
02883 
02884 #ifdef HAVE_ADS
02885 static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name, 
02886                             const char *sz)
02887 {
02888         smb_ucs2_t conv_str[1024];
02889         size_t str_size;
02890 
02891         regval_ctr_delvalue(ctr, val_name);
02892         str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
02893                              STR_TERMINATE | STR_NOALIGN);
02894         regval_ctr_addvalue(ctr, val_name, REG_SZ, 
02895                             (char *) conv_str, str_size);
02896 }
02897 
02898 static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name, 
02899                                uint32 dword)
02900 {
02901         regval_ctr_delvalue(ctr, val_name);
02902         regval_ctr_addvalue(ctr, val_name, REG_DWORD,
02903                             (char *) &dword, sizeof(dword));
02904 }
02905 
02906 static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
02907                               BOOL b)
02908 {
02909         uint8 bin_bool = (b ? 1 : 0);
02910         regval_ctr_delvalue(ctr, val_name);
02911         regval_ctr_addvalue(ctr, val_name, REG_BINARY, 
02912                             (char *) &bin_bool, sizeof(bin_bool));
02913 }
02914 
02915 static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
02916                                          const char *multi_sz)
02917 {
02918         smb_ucs2_t *conv_strs = NULL;
02919         size_t str_size;
02920 
02921         /* a multi-sz has to have a null string terminator, i.e., the last
02922            string must be followed by two nulls */
02923         str_size = strlen(multi_sz) + 2;
02924         conv_strs = SMB_CALLOC_ARRAY(smb_ucs2_t, str_size);
02925         if (!conv_strs) {
02926                 return;
02927         }
02928 
02929         /* Change to byte units. */
02930         str_size *= sizeof(smb_ucs2_t);
02931         push_ucs2(NULL, conv_strs, multi_sz, str_size, 
02932                   STR_TERMINATE | STR_NOALIGN);
02933 
02934         regval_ctr_delvalue(ctr, val_name);
02935         regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ, 
02936                             (char *) conv_strs, str_size);      
02937         safe_free(conv_strs);
02938         
02939 }
02940 
02941 /****************************************************************************
02942  * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
02943  *
02944  * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
02945  * @return BOOL indicating success or failure
02946  ***************************************************************************/
02947 
02948 static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
02949 {
02950         REGVAL_CTR *ctr = NULL;
02951         fstring longname;
02952         fstring dnssuffix;
02953         char *allocated_string = NULL;
02954         const char *ascii_str;
02955         int i;
02956 
02957         if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
02958                 i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY);
02959         ctr = info2->data->keys[i].values;
02960 
02961         map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
02962         map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
02963 
02964         /* we make the assumption that the netbios name is the same 
02965            as the DNS name sinc ethe former will be what we used to 
02966            join the domain */
02967 
02968         if ( get_mydnsdomname( dnssuffix ) )
02969                 fstr_sprintf( longname, "%s.%s", global_myname(), dnssuffix );
02970         else
02971                 fstrcpy( longname, global_myname() );
02972                 
02973         map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
02974 
02975         asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
02976         map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
02977         SAFE_FREE(allocated_string);
02978 
02979         map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
02980         map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
02981         map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
02982         map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
02983         map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
02984         map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
02985         map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
02986         map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
02987         map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
02988 
02989         map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
02990                           (info2->attributes & 
02991                            PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
02992 
02993         switch (info2->attributes & 0x3) {
02994         case 0:
02995                 ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
02996                 break;
02997         case 1:
02998                 ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
02999                 break;
03000         case 2:
03001                 ascii_str = SPOOL_REGVAL_PRINTDIRECT;
03002                 break;
03003         default:
03004                 ascii_str = "unknown";
03005         }
03006         map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
03007 
03008         return True;
03009 }
03010 
03011 /*****************************************************************
03012  ****************************************************************/
03013 
03014 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, 
03015                                struct GUID guid)
03016 {
03017         int i;
03018         REGVAL_CTR *ctr=NULL;
03019         UNISTR2 unistr_guid;
03020 
03021         /* find the DsSpooler key */
03022         if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
03023                 i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY);
03024         ctr = info2->data->keys[i].values;
03025 
03026         regval_ctr_delvalue(ctr, "objectGUID");
03027 
03028         /* We used to store this as a REG_BINARY but that causes
03029            Vista to whine */
03030 
03031         ZERO_STRUCT( unistr_guid );     
03032         init_unistr2( &unistr_guid, smb_uuid_string_static(guid),
03033                       UNI_STR_TERMINATE );
03034 
03035         regval_ctr_addvalue(ctr, "objectGUID", REG_SZ, 
03036                             (char *)unistr_guid.buffer, 
03037                             unistr_guid.uni_max_len*2);
03038         
03039 }
03040 
03041 static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
03042                                      NT_PRINTER_INFO_LEVEL *printer)
03043 {
03044         ADS_STATUS ads_rc;
03045         LDAPMessage *res;
03046         char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
03047         char *srv_dn_utf8, **srv_cn_utf8;
03048         TALLOC_CTX *ctx;
03049         ADS_MODLIST mods;
03050         const char *attrs[] = {"objectGUID", NULL};
03051         struct GUID guid;
03052         WERROR win_rc = WERR_OK;
03053 
03054         DEBUG(5, ("publishing printer %s\n", printer->info_2->printername));
03055 
03056         /* figure out where to publish */
03057         ads_find_machine_acct(ads, &res, global_myname());
03058 
03059         /* We use ldap_get_dn here as we need the answer
03060          * in utf8 to call ldap_explode_dn(). JRA. */
03061 
03062         srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
03063         if (!srv_dn_utf8) {
03064                 ads_destroy(&ads);
03065                 return WERR_SERVER_UNAVAILABLE;
03066         }
03067         ads_msgfree(ads, res);
03068         srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
03069         if (!srv_cn_utf8) {
03070                 ldap_memfree(srv_dn_utf8);
03071                 ads_destroy(&ads);
03072                 return WERR_SERVER_UNAVAILABLE;
03073         }
03074         /* Now convert to CH_UNIX. */
03075         if (pull_utf8_allocate(&srv_dn, srv_dn_utf8) == (size_t)-1) {
03076                 ldap_memfree(srv_dn_utf8);
03077                 ldap_memfree(srv_cn_utf8);
03078                 ads_destroy(&ads);
03079                 return WERR_SERVER_UNAVAILABLE;
03080         }
03081         if (pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0]) == (size_t)-1) {
03082                 ldap_memfree(srv_dn_utf8);
03083                 ldap_memfree(srv_cn_utf8);
03084                 ads_destroy(&ads);
03085                 SAFE_FREE(srv_dn);
03086                 return WERR_SERVER_UNAVAILABLE;
03087         }
03088 
03089         ldap_memfree(srv_dn_utf8);
03090         ldap_memfree(srv_cn_utf8);
03091 
03092         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
03093         if (!srv_cn_escaped) {
03094                 SAFE_FREE(srv_cn_0);
03095                 ldap_memfree(srv_dn_utf8);
03096                 ads_destroy(&ads);
03097                 return WERR_SERVER_UNAVAILABLE;
03098         }
03099         sharename_escaped = escape_rdn_val_string_alloc(printer->info_2->sharename);
03100         if (!sharename_escaped) {
03101                 SAFE_FREE(srv_cn_escaped);
03102                 SAFE_FREE(srv_cn_0);
03103                 ldap_memfree(srv_dn_utf8);
03104                 ads_destroy(&ads);
03105                 return WERR_SERVER_UNAVAILABLE;
03106         }
03107 
03108 
03109         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
03110 
03111         SAFE_FREE(srv_dn);
03112         SAFE_FREE(srv_cn_0);
03113         SAFE_FREE(srv_cn_escaped);
03114         SAFE_FREE(sharename_escaped);
03115 
03116         /* build the ads mods */
03117         ctx = talloc_init("nt_printer_publish_ads");
03118         if (ctx == NULL) {
03119                 SAFE_FREE(prt_dn);
03120                 return WERR_NOMEM;
03121         }
03122 
03123         mods = ads_init_mods(ctx);
03124 
03125         if (mods == NULL) {
03126                 SAFE_FREE(prt_dn);
03127                 talloc_destroy(ctx);
03128                 return WERR_NOMEM;
03129         }
03130 
03131         get_local_printer_publishing_data(ctx, &mods, printer->info_2->data);
03132         ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, 
03133                     printer->info_2->sharename);
03134 
03135         /* publish it */
03136         ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
03137         if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT)
03138                 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
03139 
03140         if (!ADS_ERR_OK(ads_rc))
03141                 DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc)));
03142         
03143         talloc_destroy(ctx);
03144 
03145         /* retreive the guid and store it locally */
03146         if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
03147                 ZERO_STRUCT(guid);
03148                 ads_pull_guid(ads, res, &guid);
03149                 ads_msgfree(ads, res);
03150                 store_printer_guid(printer->info_2, guid);
03151                 win_rc = mod_a_printer(printer, 2);
03152         } 
03153 
03154         SAFE_FREE(prt_dn);
03155         return win_rc;
03156 }
03157 
03158 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
03159                                        NT_PRINTER_INFO_LEVEL *printer)
03160 {
03161         ADS_STATUS ads_rc;
03162         LDAPMessage *res;
03163         char *prt_dn = NULL;
03164 
03165         DEBUG(5, ("unpublishing printer %s\n", printer->info_2->printername));
03166 
03167         /* remove the printer from the directory */
03168         ads_rc = ads_find_printer_on_server(ads, &res, 
03169                             printer->info_2->sharename, global_myname());
03170 
03171         if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
03172                 prt_dn = ads_get_dn(ads, res);
03173                 if (!prt_dn) {
03174                         ads_msgfree(ads, res);
03175                         return WERR_NOMEM;
03176                 }
03177                 ads_rc = ads_del_dn(ads, prt_dn);
03178                 ads_memfree(ads, prt_dn);
03179         }
03180 
03181         ads_msgfree(ads, res);
03182         return WERR_OK;
03183 }
03184 
03185 /****************************************************************************
03186  * Publish a printer in the directory
03187  *
03188  * @param snum describing printer service
03189  * @return WERROR indicating status of publishing
03190  ***************************************************************************/
03191 
03192 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
03193 {
03194         ADS_STATUS ads_rc;
03195         ADS_STRUCT *ads = NULL;
03196         NT_PRINTER_INFO_LEVEL *printer = NULL;
03197         WERROR win_rc;
03198 
03199         win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
03200         if (!W_ERROR_IS_OK(win_rc))
03201                 goto done;
03202 
03203         switch (action) {
03204         case SPOOL_DS_PUBLISH:
03205         case SPOOL_DS_UPDATE:
03206                 /* set the DsSpooler info and attributes */
03207                 if (!(map_nt_printer_info2_to_dsspooler(printer->info_2))) {
03208                         win_rc = WERR_NOMEM;
03209                         goto done;
03210                 }
03211 
03212                 printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
03213                 break;
03214         case SPOOL_DS_UNPUBLISH:
03215                 printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
03216                 break;
03217         default:
03218                 win_rc = WERR_NOT_SUPPORTED;
03219                 goto done;
03220         }
03221 
03222         win_rc = mod_a_printer(printer, 2);
03223         if (!W_ERROR_IS_OK(win_rc)) {
03224                 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
03225                 goto done;
03226         }
03227 
03228         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
03229         if (!ads) {
03230                 DEBUG(3, ("ads_init() failed\n"));
03231                 win_rc = WERR_SERVER_UNAVAILABLE;
03232                 goto done;
03233         }
03234         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
03235         SAFE_FREE(ads->auth.password);
03236         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
03237                 NULL, NULL);
03238 
03239         /* ads_connect() will find the DC for us */                                         
03240         ads_rc = ads_connect(ads);
03241         if (!ADS_ERR_OK(ads_rc)) {
03242                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
03243                 win_rc = WERR_ACCESS_DENIED;
03244                 goto done;
03245         }
03246 
03247         switch (action) {
03248         case SPOOL_DS_PUBLISH:
03249         case SPOOL_DS_UPDATE:
03250                 win_rc = nt_printer_publish_ads(ads, printer);
03251                 break;
03252         case SPOOL_DS_UNPUBLISH:
03253                 win_rc = nt_printer_unpublish_ads(ads, printer);
03254                 break;
03255         }
03256 
03257 done:
03258         free_a_printer(&printer, 2);
03259         ads_destroy(&ads);
03260         return win_rc;
03261 }
03262 
03263 WERROR check_published_printers(void)
03264 {
03265         ADS_STATUS ads_rc;
03266         ADS_STRUCT *ads = NULL;
03267         int snum;
03268         int n_services = lp_numservices();
03269         NT_PRINTER_INFO_LEVEL *printer = NULL;
03270 
03271         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
03272         if (!ads) {
03273                 DEBUG(3, ("ads_init() failed\n"));
03274                 return WERR_SERVER_UNAVAILABLE;
03275         }
03276         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
03277         SAFE_FREE(ads->auth.password);
03278         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
03279                 NULL, NULL);
03280 
03281         /* ads_connect() will find the DC for us */                                         
03282         ads_rc = ads_connect(ads);
03283         if (!ADS_ERR_OK(ads_rc)) {
03284                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
03285                 ads_destroy(&ads);
03286                 ads_kdestroy("MEMORY:prtpub_cache");
03287                 return WERR_ACCESS_DENIED;
03288         }
03289 
03290         for (snum = 0; snum < n_services; snum++) {
03291                 if (!(lp_snum_ok(snum) && lp_print_ok(snum)))
03292                         continue;
03293 
03294                 if (W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2,
03295                                                 lp_servicename(snum))) &&
03296                     (printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
03297                         nt_printer_publish_ads(ads, printer);
03298 
03299                 free_a_printer(&printer, 2);
03300         }
03301 
03302         ads_destroy(&ads);
03303         ads_kdestroy("MEMORY:prtpub_cache");
03304         return WERR_OK;
03305 }
03306 
03307 BOOL is_printer_published(Printer_entry *print_hnd, int snum, 
03308                           struct GUID *guid)
03309 {
03310         NT_PRINTER_INFO_LEVEL *printer = NULL;
03311         REGVAL_CTR *ctr;
03312         REGISTRY_VALUE *guid_val;
03313         WERROR win_rc;
03314         int i;
03315         BOOL ret = False;
03316 
03317         win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
03318 
03319         if (!W_ERROR_IS_OK(win_rc) ||
03320             !(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) ||
03321             ((i = lookup_printerkey(printer->info_2->data, SPOOL_DSSPOOLER_KEY)) < 0) ||
03322             !(ctr = printer->info_2->data->keys[i].values) ||
03323             !(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) 
03324         {
03325                 free_a_printer(&printer, 2);
03326                 return False;
03327         }
03328 
03329         /* fetching printer guids really ought to be a separate function. */
03330 
03331         if ( guid ) {   
03332                 fstring guid_str;
03333                 
03334                 /* We used to store the guid as REG_BINARY, then swapped 
03335                    to REG_SZ for Vista compatibility so check for both */
03336 
03337                 switch ( regval_type(guid_val) ){
03338                 case REG_SZ:            
03339                         rpcstr_pull( guid_str, regval_data_p(guid_val), 
03340                                      sizeof(guid_str)-1, -1, STR_TERMINATE );
03341                         ret = smb_string_to_uuid( guid_str, guid );
03342                         break;                  
03343                 case REG_BINARY:
03344                         if ( regval_size(guid_val) != sizeof(struct GUID) ) {
03345                                 ret = False;
03346                                 break;
03347                         }
03348                         memcpy(guid, regval_data_p(guid_val), sizeof(struct GUID));
03349                         break;
03350                 default:
03351                         DEBUG(0,("is_printer_published: GUID value stored as "
03352                                  "invaluid type (%d)\n", regval_type(guid_val) ));                      
03353                         break;
03354                 }
03355         }
03356 
03357         free_a_printer(&printer, 2);
03358         return ret;
03359 }
03360 #else
03361 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
03362 {
03363         return WERR_OK;
03364 }
03365 
03366 WERROR check_published_printers(void)
03367 {
03368         return WERR_OK;
03369 }
03370 
03371 BOOL is_printer_published(Printer_entry *print_hnd, int snum, 
03372                           struct GUID *guid)
03373 {
03374         return False;
03375 }
03376 #endif /* HAVE_ADS */
03377 
03378 /****************************************************************************
03379  ***************************************************************************/
03380  
03381 WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
03382 {
03383         NT_PRINTER_DATA *data;
03384         int             i;
03385         int             removed_keys = 0;
03386         int             empty_slot;
03387         
03388         data = p2->data;
03389         empty_slot = data->num_keys;
03390 
03391         if ( !key )
03392                 return WERR_INVALID_PARAM;
03393         
03394         /* remove all keys */
03395 
03396         if ( !strlen(key) ) {
03397         
03398                 TALLOC_FREE( data );
03399 
03400                 p2->data = NULL;
03401 
03402                 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
03403                         p2->printername ));
03404         
03405                 return WERR_OK;
03406         }
03407 
03408         /* remove a specific key (and all subkeys) */
03409         
03410         for ( i=0; i<data->num_keys; i++ ) {
03411                 if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
03412                         DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
03413                                 data->keys[i].name));
03414                 
03415                         TALLOC_FREE( data->keys[i].name );
03416                         TALLOC_FREE( data->keys[i].values );
03417 
03418                         /* mark the slot as empty */
03419 
03420                         ZERO_STRUCTP( &data->keys[i] );
03421                 }
03422         }
03423 
03424         /* find the first empty slot */
03425 
03426         for ( i=0; i<data->num_keys; i++ ) {
03427                 if ( !data->keys[i].name ) {
03428                         empty_slot = i;
03429                         removed_keys++;
03430                         break;
03431                 }
03432         }
03433 
03434         if ( i == data->num_keys )
03435                 /* nothing was removed */
03436                 return WERR_INVALID_PARAM;
03437 
03438         /* move everything down */
03439         
03440         for ( i=empty_slot+1; i<data->num_keys; i++ ) {
03441                 if ( data->keys[i].name ) {
03442                         memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) ); 
03443                         ZERO_STRUCTP( &data->keys[i] );
03444                         empty_slot++;
03445                         removed_keys++;
03446                 }
03447         }
03448 
03449         /* update count */
03450                 
03451         data->num_keys -= removed_keys;
03452 
03453         /* sanity check to see if anything is left */
03454 
03455         if ( !data->num_keys ) {
03456                 DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
03457 
03458                 SAFE_FREE( data->keys );
03459                 ZERO_STRUCTP( data );
03460         }
03461 
03462         return WERR_OK;
03463 }
03464 
03465 /****************************************************************************
03466  ***************************************************************************/
03467  
03468 WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
03469 {
03470         WERROR          result = WERR_OK;
03471         int             key_index;
03472         
03473         /* we must have names on non-zero length */
03474         
03475         if ( !key || !*key|| !value || !*value )
03476                 return WERR_INVALID_NAME;
03477                 
03478         /* find the printer key first */
03479 
03480         key_index = lookup_printerkey( p2->data, key );
03481         if ( key_index == -1 )
03482                 return WERR_OK;
03483         
03484         /* make sure the value exists so we can return the correct error code */
03485         
03486         if ( !regval_ctr_getvalue( p2->data->keys[key_index].values, value ) )
03487                 return WERR_BADFILE;
03488                 
03489         regval_ctr_delvalue( p2->data->keys[key_index].values, value );
03490         
03491         DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
03492                 key, value ));
03493         
03494         return result;
03495 }
03496 
03497 /****************************************************************************
03498  ***************************************************************************/
03499  
03500 WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value, 
03501                            uint32 type, uint8 *data, int real_len )
03502 {
03503         WERROR          result = WERR_OK;
03504         int             key_index;
03505 
03506         /* we must have names on non-zero length */
03507         
03508         if ( !key || !*key|| !value || !*value )
03509                 return WERR_INVALID_NAME;
03510                 
03511         /* find the printer key first */
03512         
03513         key_index = lookup_printerkey( p2->data, key );
03514         if ( key_index == -1 )
03515                 key_index = add_new_printer_key( p2->data, key );
03516                 
03517         if ( key_index == -1 )
03518                 return WERR_NOMEM;
03519         
03520         regval_ctr_addvalue( p2->data->keys[key_index].values, value,
03521                 type, (const char *)data, real_len );
03522         
03523         DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
03524                 key, value, type, real_len  ));
03525         
03526         return result;
03527 }
03528 
03529 /****************************************************************************
03530  ***************************************************************************/
03531  
03532 REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
03533 {
03534         int             key_index;
03535 
03536         if ( (key_index = lookup_printerkey( p2->data, key )) == -1 )
03537                 return NULL;
03538 
03539         DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
03540                 key, value ));
03541 
03542         return regval_ctr_getvalue( p2->data->keys[key_index].values, value );
03543 }
03544 
03545 /****************************************************************************
03546  Unpack a list of registry values frem the TDB
03547  ***************************************************************************/
03548  
03549 static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
03550 {
03551         int             len = 0;
03552         uint32          type;
03553         pstring         string, valuename, keyname;
03554         char            *str;
03555         int             size;
03556         uint8           *data_p;
03557         REGISTRY_VALUE  *regval_p;
03558         int             key_index;
03559 
03560         /* add the "PrinterDriverData" key first for performance reasons */
03561         
03562         add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
03563 
03564         /* loop and unpack the rest of the registry values */
03565         
03566         while ( True ) {
03567         
03568                 /* check to see if there are any more registry values */
03569                 
03570                 regval_p = NULL;
03571                 len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);         
03572                 if ( !regval_p ) 
03573                         break;
03574 
03575                 /* unpack the next regval */
03576                 
03577                 len += tdb_unpack(buf+len, buflen-len, "fdB",
03578                                   string,
03579                                   &type,
03580                                   &size,
03581                                   &data_p);
03582 
03583                 /* lookup for subkey names which have a type of REG_NONE */
03584                 /* there's no data with this entry */
03585 
03586                 if ( type == REG_NONE ) {
03587                         if ( (key_index=lookup_printerkey( printer_data, string)) == -1 )
03588                                 add_new_printer_key( printer_data, string );
03589                         continue;
03590                 }
03591         
03592                 /*
03593                  * break of the keyname from the value name.  
03594                  * Valuenames can have embedded '\'s so be careful.
03595                  * only support one level of keys.  See the 
03596                  * "Konica Fiery S300 50C-K v1.1. enu" 2k driver.
03597                  * -- jerry
03598                  */     
03599                  
03600                 str = strchr_m( string, '\\');
03601                 
03602                 /* Put in "PrinterDriverData" is no key specified */
03603                 
03604                 if ( !str ) {
03605                         pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
03606                         pstrcpy( valuename, string );
03607                 }
03608                 else {
03609                         *str = '\0';
03610                         pstrcpy( keyname, string );
03611                         pstrcpy( valuename, str+1 );
03612                 }
03613                         
03614                 /* see if we need a new key */
03615                 
03616                 if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
03617                         key_index = add_new_printer_key( printer_data, keyname );
03618                         
03619                 if ( key_index == -1 ) {
03620                         DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
03621                                 keyname));
03622                         break;
03623                 }
03624                 
03625                 DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
03626 
03627                 /* Vista doesn't like unknown REG_BINARY values in DsSpooler.  
03628                    Thanks to Martin Zielinski for the hint. */
03629 
03630                 if ( type == REG_BINARY && 
03631                      strequal( keyname, SPOOL_DSSPOOLER_KEY ) && 
03632                      strequal( valuename, "objectGUID" ) ) 
03633                 {
03634                         struct GUID guid;
03635                         UNISTR2 unistr_guid;
03636 
03637                         ZERO_STRUCT( unistr_guid );
03638                         
03639                         /* convert the GUID to a UNICODE string */
03640                         
03641                         memcpy( &guid, data_p, sizeof(struct GUID) );
03642                         
03643                         init_unistr2( &unistr_guid, smb_uuid_string_static(guid), 
03644                                       UNI_STR_TERMINATE );
03645                         
03646                         regval_ctr_addvalue( printer_data->keys[key_index].values, 
03647                                              valuename, REG_SZ, 
03648                                              (const char *)unistr_guid.buffer, 
03649                                              unistr_guid.uni_str_len*2 );
03650 
03651                 } else {
03652                         /* add the value */
03653 
03654                         regval_ctr_addvalue( printer_data->keys[key_index].values, 
03655                                              valuename, type, (const char *)data_p, 
03656                                              size );
03657                 }
03658                 
03659 
03660                 SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
03661 
03662         }
03663 
03664         return len;
03665 }
03666 
03667 /****************************************************************************
03668  ***************************************************************************/
03669 
03670 static void map_to_os2_driver(fstring drivername)
03671 {
03672         static BOOL initialised=False;
03673         static fstring last_from,last_to;
03674         char *mapfile = lp_os2_driver_map();
03675         char **lines = NULL;
03676         int numlines = 0;
03677         int i;
03678 
03679         if (!strlen(drivername))
03680                 return;
03681 
03682         if (!*mapfile)
03683                 return;
03684 
03685         if (!initialised) {
03686                 *last_from = *last_to = 0;
03687                 initialised = True;
03688         }
03689 
03690         if (strequal(drivername,last_from)) {
03691                 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
03692                 fstrcpy(drivername,last_to);
03693                 return;
03694         }
03695 
03696         lines = file_lines_load(mapfile, &numlines,0);
03697         if (numlines == 0 || lines == NULL) {
03698                 DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
03699                 SAFE_FREE(lines);
03700                 return;
03701         }
03702 
03703         DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
03704 
03705         for( i = 0; i < numlines; i++) {
03706                 char *nt_name = lines[i];
03707                 char *os2_name = strchr(nt_name,'=');
03708 
03709                 if (!os2_name)
03710                         continue;
03711 
03712                 *os2_name++ = 0;
03713 
03714                 while (isspace(*nt_name))
03715                         nt_name++;
03716 
03717                 if (!*nt_name || strchr("#;",*nt_name))
03718                         continue;
03719 
03720                 {
03721                         int l = strlen(nt_name);
03722                         while (l && isspace(nt_name[l-1])) {
03723                                 nt_name[l-1] = 0;
03724                                 l--;
03725                         }
03726                 }
03727 
03728                 while (isspace(*os2_name))
03729                         os2_name++;
03730 
03731                 {
03732                         int l = strlen(os2_name);
03733                         while (l && isspace(os2_name[l-1])) {
03734                                 os2_name[l-1] = 0;
03735                                 l--;
03736                         }
03737                 }
03738 
03739                 if (strequal(nt_name,drivername)) {
03740                         DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
03741                         fstrcpy(last_from,drivername);
03742                         fstrcpy(last_to,os2_name);
03743                         fstrcpy(drivername,os2_name);
03744                         file_lines_free(lines);
03745                         return;
03746                 }
03747         }
03748 
03749         file_lines_free(lines);
03750 }
03751 
03752 /****************************************************************************
03753  Get a default printer info 2 struct.
03754 ****************************************************************************/
03755 
03756 static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info,
03757                                         const char *servername,
03758                                         const char* sharename,
03759                                         BOOL get_loc_com)
03760 {
03761         int snum = lp_servicenumber(sharename);
03762 
03763         slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername);
03764         slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s", 
03765                 servername, sharename);
03766         fstrcpy(info->sharename, sharename);
03767         fstrcpy(info->portname, SAMBA_PRINTER_PORT_NAME);
03768 
03769         /* by setting the driver name to an empty string, a local NT admin
03770            can now run the **local** APW to install a local printer driver
03771            for a Samba shared printer in 2.2.  Without this, drivers **must** be 
03772            installed on the Samba server for NT clients --jerry */
03773 #if 0   /* JERRY --do not uncomment-- */
03774         if (!*info->drivername)
03775                 fstrcpy(info->drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
03776 #endif
03777 
03778 
03779         DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info->drivername));
03780 
03781         pstrcpy(info->comment, "");
03782         fstrcpy(info->printprocessor, "winprint");
03783         fstrcpy(info->datatype, "RAW");
03784 
03785 #ifdef HAVE_CUPS
03786         if (get_loc_com && (enum printing_types)lp_printing(snum) == PRINT_CUPS ) {             
03787                 /* Pull the location and comment strings from cups if we don't
03788                    already have one */
03789                 if ( !strlen(info->location) || !strlen(info->comment) )
03790                         cups_pull_comment_location( info );
03791         }
03792 #endif
03793 
03794         info->attributes = PRINTER_ATTRIBUTE_SAMBA;
03795 
03796         info->starttime = 0; /* Minutes since 12:00am GMT */
03797         info->untiltime = 0; /* Minutes since 12:00am GMT */
03798         info->priority = 1;
03799         info->default_priority = 1;
03800         info->setuptime = (uint32)time(NULL);
03801 
03802         /*
03803          * I changed this as I think it is better to have a generic
03804          * DEVMODE than to crash Win2k explorer.exe   --jerry
03805          * See the HP Deskjet 990c Win2k drivers for an example.
03806          *
03807          * However the default devmode appears to cause problems
03808          * with the HP CLJ 8500 PCL driver.  Hence the addition of
03809          * the "default devmode" parameter   --jerry 22/01/2002
03810          */
03811 
03812         if (lp_default_devmode(snum)) {
03813                 if ((info->devmode = construct_nt_devicemode(info->printername)) == NULL) {
03814                         goto fail;
03815                 }
03816         } else {
03817                 info->devmode = NULL;
03818         }
03819 
03820         if (!nt_printing_getsec(info, sharename, &info->secdesc_buf)) {
03821                 goto fail;
03822         }
03823 
03824         return WERR_OK;
03825 
03826 fail:
03827         if (info->devmode)
03828                 free_nt_devicemode(&info->devmode);
03829 
03830         return WERR_ACCESS_DENIED;
03831 }
03832 
03833 /****************************************************************************
03834 ****************************************************************************/
03835 
03836 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info,
03837                                 const char *servername,
03838                                 const char *sharename,
03839                                 BOOL get_loc_com)
03840 {
03841         int len = 0;
03842         int snum = lp_servicenumber(sharename);
03843         TDB_DATA kbuf, dbuf;
03844         fstring printername;
03845         char adevice[MAXDEVICENAME];
03846                 
03847         kbuf = make_printer_tdbkey( sharename );
03848 
03849         dbuf = tdb_fetch(tdb_printers, kbuf);
03850         if (!dbuf.dptr) {
03851                 return get_a_printer_2_default(info, servername,
03852                                 sharename, get_loc_com);
03853         }
03854 
03855         len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
03856                         &info->attributes,
03857                         &info->priority,
03858                         &info->default_priority,
03859                         &info->starttime,
03860                         &info->untiltime,
03861                         &info->status,
03862                         &info->cjobs,
03863                         &info->averageppm,
03864                         &info->changeid,
03865                         &info->c_setprinter,
03866                         &info->setuptime,
03867                         info->servername,
03868                         info->printername,
03869                         info->sharename,
03870                         info->portname,
03871                         info->drivername,
03872                         info->comment,
03873                         info->location,
03874                         info->sepfile,
03875                         info->printprocessor,
03876                         info->datatype,
03877                         info->parameters);
03878 
03879         /* Samba has to have shared raw drivers. */
03880         info->attributes |= PRINTER_ATTRIBUTE_SAMBA;
03881         info->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA;
03882 
03883         /* Restore the stripped strings. */
03884         slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername);
03885 
03886         if ( lp_force_printername(snum) ) {
03887                 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, sharename );
03888         } else {
03889                 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info->printername);
03890         }
03891 
03892         fstrcpy(info->printername, printername);
03893 
03894 #ifdef HAVE_CUPS
03895         if (get_loc_com && (enum printing_types)lp_printing(snum) == PRINT_CUPS ) {             
03896                 /* Pull the location and comment strings from cups if we don't
03897                    already have one */
03898                 if ( !strlen(info->location) || !strlen(info->comment) )
03899                         cups_pull_comment_location( info );
03900         }
03901 #endif
03902 
03903         len += unpack_devicemode(&info->devmode,dbuf.dptr+len, dbuf.dsize-len);
03904 
03905         /*
03906          * Some client drivers freak out if there is a NULL devmode
03907          * (probably the driver is not checking before accessing 
03908          * the devmode pointer)   --jerry
03909          *
03910          * See comments in get_a_printer_2_default()
03911          */
03912 
03913         if (lp_default_devmode(snum) && !info->devmode) {
03914                 DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
03915                         printername));
03916                 info->devmode = construct_nt_devicemode(printername);
03917         }
03918 
03919         slprintf( adevice, sizeof(adevice), "%s", info->printername );
03920         if (info->devmode) {
03921                 fstrcpy(info->devmode->devicename, adevice);    
03922         }
03923 
03924         if ( !(info->data = TALLOC_ZERO_P( info, NT_PRINTER_DATA )) ) {
03925                 DEBUG(0,("unpack_values: talloc() failed!\n"));
03926                 SAFE_FREE(dbuf.dptr);
03927                 return WERR_NOMEM;
03928         }
03929         len += unpack_values( info->data, dbuf.dptr+len, dbuf.dsize-len );
03930 
03931         /* This will get the current RPC talloc context, but we should be
03932            passing this as a parameter... fixme... JRA ! */
03933 
03934         if (!nt_printing_getsec(info, sharename, &info->secdesc_buf)) {
03935                 SAFE_FREE(dbuf.dptr);
03936                 return WERR_NOMEM;
03937         }
03938 
03939         /* Fix for OS/2 drivers. */
03940 
03941         if (get_remote_arch() == RA_OS2) {
03942                 map_to_os2_driver(info->drivername);
03943         }
03944 
03945         SAFE_FREE(dbuf.dptr);
03946 
03947         DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
03948                  sharename, info->printername, info->drivername));
03949 
03950         return WERR_OK; 
03951 }
03952 
03953 /****************************************************************************
03954  Debugging function, dump at level 6 the struct in the logs.
03955 ****************************************************************************/
03956 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
03957 {
03958         uint32 result;
03959         NT_PRINTER_INFO_LEVEL_2 *info2;
03960         
03961         DEBUG(106,("Dumping printer at level [%d]\n", level));
03962         
03963         switch (level) {
03964                 case 2:
03965                 {
03966                         if (printer->info_2 == NULL)
03967                                 result=5;
03968                         else
03969                         {
03970                                 info2=printer->info_2;
03971                         
03972                                 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
03973                                 DEBUGADD(106,("priority:[%d]\n", info2->priority));
03974                                 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
03975                                 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
03976                                 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
03977                                 DEBUGADD(106,("status:[%d]\n", info2->status));
03978                                 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
03979                                 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
03980                                 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
03981                                 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
03982                                 DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
03983 
03984                                 DEBUGADD(106,("servername:[%s]\n", info2->servername));
03985                                 DEBUGADD(106,("printername:[%s]\n", info2->printername));
03986                                 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
03987                                 DEBUGADD(106,("portname:[%s]\n", info2->portname));
03988                                 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
03989                                 DEBUGADD(106,("comment:[%s]\n", info2->comment));
03990                                 DEBUGADD(106,("location:[%s]\n", info2->location));
03991                                 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
03992                                 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
03993                                 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
03994                                 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
03995                                 result=0;
03996                         }
03997                         break;
03998                 }
03999                 default:
04000                         DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
04001                         result=1;
04002                         break;
04003         }
04004         
04005         return result;
04006 }
04007 
04008 /****************************************************************************
04009  Update the changeid time.
04010  This is SO NASTY as some drivers need this to change, others need it
04011  static. This value will change every second, and I must hope that this
04012  is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
04013  UTAH ! JRA.
04014 ****************************************************************************/
04015 
04016 static uint32 rev_changeid(void)
04017 {
04018         struct timeval tv;
04019 
04020         get_process_uptime(&tv);
04021 
04022 #if 1   /* JERRY */
04023         /* Return changeid as msec since spooler restart */
04024         return tv.tv_sec * 1000 + tv.tv_usec / 1000;
04025 #else
04026         /*
04027          * This setting seems to work well but is too untested
04028          * to replace the above calculation.  Left in for experiementation
04029          * of the reader            --jerry (Tue Mar 12 09:15:05 CST 2002)
04030          */
04031         return tv.tv_sec * 10 + tv.tv_usec / 100000;
04032 #endif
04033 }
04034 
04035 
04036 /*
04037  * The function below are the high level ones.
04038  * only those ones must be called from the spoolss code.
04039  * JFM.
04040  */
04041 
04042 /****************************************************************************
04043  Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
04044 ****************************************************************************/
04045 
04046 WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
04047 {
04048         WERROR result;
04049         
04050         dump_a_printer(printer, level); 
04051         
04052         switch (level) {
04053                 case 2:
04054                 {
04055                         /*
04056                          * Update the changestamp.  Emperical tests show that the
04057                          * ChangeID is always updated,but c_setprinter is  
04058                          *  global spooler variable (not per printer).
04059                          */
04060 
04061                         /* ChangeID **must** be increasing over the lifetime
04062                            of client's spoolss service in order for the
04063                            client's cache to show updates */
04064 
04065                         printer->info_2->changeid = rev_changeid();
04066 
04067                         /*
04068                          * Because one day someone will ask:
04069                          * NT->NT       An admin connection to a remote
04070                          *              printer show changes imeediately in
04071                          *              the properities dialog
04072                          *      
04073                          *              A non-admin connection will only show the
04074                          *              changes after viewing the properites page
04075                          *              2 times.  Seems to be related to a
04076                          *              race condition in the client between the spooler
04077                          *              updating the local cache and the Explorer.exe GUI
04078                          *              actually displaying the properties.
04079                          *
04080                          *              This is fixed in Win2k.  admin/non-admin
04081                          *              connections both display changes immediately.
04082                          *
04083                          * 14/12/01     --jerry
04084                          */
04085 
04086                         result=update_a_printer_2(printer->info_2);
04087                         
04088                         break;
04089                 }
04090                 default:
04091                         result=WERR_UNKNOWN_LEVEL;
04092                         break;
04093         }
04094         
04095         return result;
04096 }
04097 
04098 /****************************************************************************
04099  Initialize printer devmode & data with previously saved driver init values.
04100 ****************************************************************************/
04101 
04102 static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
04103 {
04104         int                     len = 0;
04105         pstring                 key;
04106         TDB_DATA                kbuf, dbuf;
04107         NT_PRINTER_INFO_LEVEL_2 info;
04108 
04109 
04110         ZERO_STRUCT(info);
04111 
04112         /*
04113          * Delete any printer data 'values' already set. When called for driver
04114          * replace, there will generally be some, but during an add printer, there
04115          * should not be any (if there are delete them).
04116          */
04117          
04118         if ( info_ptr->data )
04119                 delete_all_printer_data( info_ptr, "" );
04120         
04121         slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
04122 
04123         kbuf.dptr = key;
04124         kbuf.dsize = strlen(key)+1;
04125 
04126         dbuf = tdb_fetch(tdb_drivers, kbuf);
04127         if (!dbuf.dptr) {
04128                 /*
04129                  * When changing to a driver that has no init info in the tdb, remove
04130                  * the previous drivers init info and leave the new on blank.
04131                  */
04132                 free_nt_devicemode(&info_ptr->devmode);
04133                 return False;
04134         }
04135         
04136         /*
04137          * Get the saved DEVMODE..
04138          */
04139          
04140         len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
04141 
04142         /*
04143          * The saved DEVMODE contains the devicename from the printer used during
04144          * the initialization save. Change it to reflect the new printer.
04145          */
04146          
04147         if ( info.devmode ) {
04148                 ZERO_STRUCT(info.devmode->devicename);
04149                 fstrcpy(info.devmode->devicename, info_ptr->printername);
04150         }
04151 
04152         /*
04153          * NT/2k does not change out the entire DeviceMode of a printer
04154          * when changing the driver.  Only the driverextra, private, & 
04155          * driverversion fields.   --jerry  (Thu Mar 14 08:58:43 CST 2002)
04156          *
04157          * Later examination revealed that Windows NT/2k does reset the
04158          * the printer's device mode, bit **only** when you change a 
04159          * property of the device mode such as the page orientation.
04160          * --jerry
04161          */
04162 
04163 
04164         /* Bind the saved DEVMODE to the new the printer */
04165          
04166         free_nt_devicemode(&info_ptr->devmode);
04167         info_ptr->devmode = info.devmode;
04168 
04169         DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
04170                 info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
04171 
04172         /* Add the printer data 'values' to the new printer */
04173 
04174         if ( !(info_ptr->data = TALLOC_ZERO_P( info_ptr, NT_PRINTER_DATA )) ) {
04175                 DEBUG(0,("set_driver_init_2: talloc() failed!\n"));
04176                 return False;
04177         }
04178          
04179         len += unpack_values( info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
04180         
04181 
04182         SAFE_FREE(dbuf.dptr);
04183 
04184         return True;    
04185 }
04186 
04187 /****************************************************************************
04188  Initialize printer devmode & data with previously saved driver init values.
04189  When a printer is created using AddPrinter, the drivername bound to the
04190  printer is used to lookup previously saved driver initialization info, which
04191  is bound to the new printer.
04192 ****************************************************************************/
04193 
04194 BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
04195 {
04196         BOOL result = False;
04197         
04198         switch (level) {
04199                 case 2:
04200                         result = set_driver_init_2(printer->info_2);
04201                         break;
04202                         
04203                 default:
04204                         DEBUG(0,("set_driver_init: Programmer's error!  Unknown driver_init level [%d]\n",
04205                                 level));
04206                         break;
04207         }
04208         
04209         return result;
04210 }
04211 
04212 /****************************************************************************
04213  Delete driver init data stored for a specified driver
04214 ****************************************************************************/
04215 
04216 BOOL del_driver_init(char *drivername)
04217 {
04218         pstring key;
04219         TDB_DATA kbuf;
04220 
04221         if (!drivername || !*drivername) {
04222                 DEBUG(3,("del_driver_init: No drivername specified!\n"));
04223                 return False;
04224         }
04225 
04226         slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername);
04227 
04228         kbuf.dptr = key;
04229         kbuf.dsize = strlen(key)+1;
04230 
04231         DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername));
04232 
04233         return (tdb_delete(tdb_drivers, kbuf) == 0);
04234 }
04235 
04236 /****************************************************************************
04237  Pack up the DEVMODE and values for a printer into a 'driver init' entry 
04238  in the tdb. Note: this is different from the driver entry and the printer
04239  entry. There should be a single driver init entry for each driver regardless
04240  of whether it was installed from NT or 2K. Technically, they should be
04241  different, but they work out to the same struct.
04242 ****************************************************************************/
04243 
04244 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
04245 {
04246         pstring key;
04247         char *buf;
04248         int buflen, len, ret;
04249         TDB_DATA kbuf, dbuf;
04250 
04251         buf = NULL;
04252         buflen = 0;
04253 
04254  again: 
04255         len = 0;
04256         len += pack_devicemode(info->devmode, buf+len, buflen-len);
04257 
04258         len += pack_values( info->data, buf+len, buflen-len );
04259 
04260         if (buflen < len) {
04261                 buf = (char *)SMB_REALLOC(buf, len);
04262                 if (!buf) {
04263                         DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
04264                         ret = -1;
04265                         goto done;
04266                 }
04267                 buflen = len;
04268                 goto again;
04269         }
04270 
04271         slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
04272 
04273         kbuf.dptr = key;
04274         kbuf.dsize = strlen(key)+1;
04275         dbuf.dptr = buf;
04276         dbuf.dsize = len;
04277 
04278         ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
04279 
04280 done:
04281         if (ret == -1)
04282                 DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
04283 
04284         SAFE_FREE(buf);
04285 
04286         DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
04287                  info->sharename, info->drivername));
04288 
04289         return ret;
04290 }
04291 
04292 /****************************************************************************
04293  Update (i.e. save) the driver init info (DEVMODE and values) for a printer
04294 ****************************************************************************/
04295 
04296 static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
04297 {
04298         uint32 result;
04299         
04300         dump_a_printer(printer, level); 
04301         
04302         switch (level) {
04303                 case 2:
04304                         result = update_driver_init_2(printer->info_2);
04305                         break;
04306                 default:
04307                         result = 1;
04308                         break;
04309         }
04310         
04311         return result;
04312 }
04313 
04314 /****************************************************************************
04315  Convert the printer data value, a REG_BINARY array, into an initialization 
04316  DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
04317  got to keep the endians happy :).
04318 ****************************************************************************/
04319 
04320 static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
04321 {
04322         BOOL       result = False;
04323         prs_struct ps;
04324         DEVICEMODE devmode;
04325 
04326         ZERO_STRUCT(devmode);
04327 
04328         prs_init(&ps, 0, ctx, UNMARSHALL);
04329         ps.data_p      = (char *)data;
04330         ps.buffer_size = data_len;
04331 
04332         if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
04333                 result = convert_devicemode("", &devmode, &nt_devmode);
04334         else
04335                 DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
04336 
04337         return result;
04338 }
04339 
04340 /****************************************************************************
04341  Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
04342 
04343  1. Use the driver's config DLL to this UNC printername and:
04344     a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
04345     b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
04346  2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
04347 
04348  The last step triggers saving the "driver initialization" information for
04349  this printer into the tdb. Later, new printers that use this driver will
04350  have this initialization information bound to them. This simulates the
04351  driver initialization, as if it had run on the Samba server (as it would
04352  have done on NT).
04353 
04354  The Win32 client side code requirement sucks! But until we can run arbitrary
04355  Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
04356  
04357  It would have been easier to use SetPrinter because all the UNMARSHALLING of
04358  the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
04359  about it and you will realize why.  JRR 010720
04360 ****************************************************************************/
04361 
04362 static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
04363 {
04364         WERROR        status       = WERR_OK;
04365         TALLOC_CTX    *ctx         = NULL;
04366         NT_DEVICEMODE *nt_devmode  = NULL;
04367         NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
04368         
04369         /*
04370          * When the DEVMODE is already set on the printer, don't try to unpack it.
04371          */
04372         DEBUG(8,("save_driver_init_2: Enter...\n"));
04373         
04374         if ( !printer->info_2->devmode && data_len ) {
04375                 /*
04376                  * Set devmode on printer info, so entire printer initialization can be
04377                  * saved to tdb.
04378                  */
04379 
04380                 if ((ctx = talloc_init("save_driver_init_2")) == NULL)
04381                         return WERR_NOMEM;
04382 
04383                 if ((nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE)) == NULL) {
04384                         status = WERR_NOMEM;
04385                         goto done;
04386                 }
04387         
04388                 ZERO_STRUCTP(nt_devmode);
04389 
04390                 /*
04391                  * The DEVMODE is held in the 'data' component of the param in raw binary.
04392                  * Convert it to to a devmode structure
04393                  */
04394                 if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
04395                         DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
04396                         status = WERR_INVALID_PARAM;
04397                         goto done;
04398                 }
04399 
04400                 printer->info_2->devmode = nt_devmode;
04401         }
04402 
04403         /*
04404          * Pack up and add (or update) the DEVMODE and any current printer data to
04405          * a 'driver init' element in the tdb
04406          * 
04407          */
04408 
04409         if ( update_driver_init(printer, 2) != 0 ) {
04410                 DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
04411                 status = WERR_NOMEM;
04412                 goto done;
04413         }
04414         
04415         /*
04416          * If driver initialization info was successfully saved, set the current 
04417          * printer to match it. This allows initialization of the current printer 
04418          * as well as the driver.
04419          */
04420         status = mod_a_printer(printer, 2);
04421         if (!W_ERROR_IS_OK(status)) {
04422                 DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
04423                                   printer->info_2->printername));
04424         }
04425         
04426   done:
04427         talloc_destroy(ctx);
04428         free_nt_devicemode( &nt_devmode );
04429         
04430         printer->info_2->devmode = tmp_devmode;
04431 
04432         return status;
04433 }
04434 
04435 /****************************************************************************
04436  Update the driver init info (DEVMODE and specifics) for a printer
04437 ****************************************************************************/
04438 
04439 WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
04440 {
04441         WERROR status = WERR_OK;
04442         
04443         switch (level) {
04444                 case 2:
04445                         status = save_driver_init_2( printer, data, data_len );
04446                         break;
04447                 default:
04448                         status = WERR_UNKNOWN_LEVEL;
04449                         break;
04450         }
04451         
04452         return status;
04453 }
04454 
04455 /****************************************************************************
04456  Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
04457 
04458  Previously the code had a memory allocation problem because it always
04459  used the TALLOC_CTX from the Printer_entry*.   This context lasts 
04460  as a long as the original handle is open.  So if the client made a lot 
04461  of getprinter[data]() calls, the memory usage would climb.  Now we use
04462  a short lived TALLOC_CTX for printer_info_2 objects returned.  We 
04463  still use the Printer_entry->ctx for maintaining the cache copy though
04464  since that object must live as long as the handle by definition.  
04465                                                     --jerry
04466 
04467 ****************************************************************************/
04468 
04469 static WERROR get_a_printer_internal( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, 
04470                         const char *sharename, BOOL get_loc_com)
04471 {
04472         WERROR result;
04473         fstring servername;
04474         
04475         DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
04476 
04477         if ( !(*pp_printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) {
04478                 DEBUG(0,("get_a_printer: talloc() fail.\n"));
04479                 return WERR_NOMEM;
04480         }
04481 
04482         switch (level) {
04483                 case 2:
04484                         if ( !((*pp_printer)->info_2 = TALLOC_ZERO_P(*pp_printer, NT_PRINTER_INFO_LEVEL_2)) ) {
04485                                 DEBUG(0,("get_a_printer: talloc() fail.\n"));
04486                                 TALLOC_FREE( *pp_printer );
04487                                 return WERR_NOMEM;
04488                         }
04489 
04490                         if ( print_hnd ) 
04491                                 fstrcpy( servername, print_hnd->servername );
04492                         else {
04493                                 fstrcpy( servername, "%L" );
04494                                 standard_sub_basic( "", "", servername,
04495                                                     sizeof(servername)-1 );
04496                         }
04497 
04498                         result = get_a_printer_2( (*pp_printer)->info_2,
04499                                         servername,
04500                                         sharename,
04501                                         get_loc_com);
04502         
04503                         
04504                         /* we have a new printer now.  Save it with this handle */
04505                         
04506                         if ( !W_ERROR_IS_OK(result) ) {
04507                                 TALLOC_FREE( *pp_printer );
04508                                 DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", 
04509                                         sharename, (unsigned int)level, dos_errstr(result)));
04510                                 return result;
04511                         }
04512 
04513                         dump_a_printer( *pp_printer, level);
04514                         
04515                         break;
04516                         
04517                 default:
04518                         TALLOC_FREE( *pp_printer );
04519                         return WERR_UNKNOWN_LEVEL;
04520         }
04521         
04522         return WERR_OK;
04523 }
04524 
04525 WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, 
04526                         const char *sharename)
04527 {
04528         return get_a_printer_internal(print_hnd, pp_printer, level,
04529                                         sharename, True);
04530 }
04531 
04532 WERROR get_a_printer_search( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, 
04533                         const char *sharename)
04534 {
04535         return get_a_printer_internal(print_hnd, pp_printer, level,
04536                                         sharename, False);
04537 }
04538 
04539 /****************************************************************************
04540  Deletes a NT_PRINTER_INFO_LEVEL struct.
04541 ****************************************************************************/
04542 
04543 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
04544 {
04545         NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
04546 
04547         if ( !printer )
04548                 return 0;
04549         
04550         switch (level) {
04551                 case 2:
04552                         if ( printer->info_2 ) 
04553                                 free_nt_printer_info_level_2(&printer->info_2);
04554                         break;
04555 
04556                 default:
04557                         DEBUG(0,("free_a_printer: unknown level! [%d]\n", level ));
04558                         return 1;
04559         }
04560 
04561         TALLOC_FREE(*pp_printer);
04562 
04563         return 0;
04564 }
04565 
04566 /****************************************************************************
04567 ****************************************************************************/
04568 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
04569 {
04570         uint32 result;
04571         DEBUG(104,("adding a printer at level [%d]\n", level));
04572         dump_a_printer_driver(driver, level);
04573         
04574         switch (level) {
04575                 case 3:
04576                         result=add_a_printer_driver_3(driver.info_3);
04577                         break;
04578 
04579                 case 6:
04580                         result=add_a_printer_driver_6(driver.info_6);
04581                         break;
04582 
04583                 default:
04584                         result=1;
04585                         break;
04586         }
04587         
04588         return result;
04589 }
04590 /****************************************************************************
04591 ****************************************************************************/
04592 
04593 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
04594                             fstring drivername, const char *architecture, uint32 version)
04595 {
04596         WERROR result;
04597         
04598         switch (level) {
04599                 case 3:
04600                         /* Sometime we just want any version of the driver */
04601                         
04602                         if ( version == DRIVER_ANY_VERSION ) {
04603                                 /* look for Win2k first and then for NT4 */
04604                                 result = get_a_printer_driver_3(&driver->info_3, drivername, 
04605                                                 architecture, 3);
04606                                                 
04607                                 if ( !W_ERROR_IS_OK(result) ) {
04608                                         result = get_a_printer_driver_3( &driver->info_3, 
04609                                                         drivername, architecture, 2 );
04610                                 }
04611                         } else {
04612                                 result = get_a_printer_driver_3(&driver->info_3, drivername, 
04613                                         architecture, version);                         
04614                         }
04615                         break;
04616                         
04617                 default:
04618                         result=W_ERROR(1);
04619                         break;
04620         }
04621         
04622         if (W_ERROR_IS_OK(result))
04623                 dump_a_printer_driver(*driver, level);
04624                 
04625         return result;
04626 }
04627 
04628 /****************************************************************************
04629 ****************************************************************************/
04630 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
04631 {
04632         uint32 result;
04633         
04634         switch (level) {
04635                 case 3:
04636                 {
04637                         NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
04638                         if (driver.info_3 != NULL)
04639                         {
04640                                 info3=driver.info_3;
04641                                 SAFE_FREE(info3->dependentfiles);
04642                                 ZERO_STRUCTP(info3);
04643                                 SAFE_FREE(info3);
04644                                 result=0;
04645                         } else {
04646                                 result=4;
04647                         }
04648                         break;
04649                 }
04650                 case 6:
04651                 {
04652                         NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
04653                         if (driver.info_6 != NULL) {
04654                                 info6=driver.info_6;
04655                                 SAFE_FREE(info6->dependentfiles);
04656                                 SAFE_FREE(info6->previousnames);
04657                                 ZERO_STRUCTP(info6);
04658                                 SAFE_FREE(info6);
04659                                 result=0;
04660                         } else {
04661                                 result=4;
04662                         }
04663                         break;
04664                 }
04665                 default:
04666                         result=1;
04667                         break;
04668         }
04669         return result;
04670 }
04671 
04672 
04673 /****************************************************************************
04674   Determine whether or not a particular driver is currently assigned
04675   to a printer
04676 ****************************************************************************/
04677 
04678 BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
04679 {
04680         int snum;
04681         int n_services = lp_numservices();
04682         NT_PRINTER_INFO_LEVEL *printer = NULL;
04683         BOOL in_use = False;
04684 
04685         if ( !info_3 ) 
04686                 return False;
04687 
04688         DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
04689         
04690         /* loop through the printers.tdb and check for the drivername */
04691         
04692         for (snum=0; snum<n_services && !in_use; snum++) {
04693                 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
04694                         continue;
04695                 
04696                 if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
04697                         continue;
04698                 
04699                 if ( strequal(info_3->name, printer->info_2->drivername) ) 
04700                         in_use = True;
04701                 
04702                 free_a_printer( &printer, 2 );
04703         }
04704         
04705         DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
04706         
04707         if ( in_use ) {
04708                 NT_PRINTER_DRIVER_INFO_LEVEL d;
04709                 WERROR werr;
04710                 
04711                 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", info_3->name));
04712                 
04713                 /* we can still remove the driver if there is one of 
04714                    "Windows NT x86" version 2 or 3 left */
04715                    
04716                 if ( !strequal( "Windows NT x86", info_3->environment ) ) {
04717                         werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", DRIVER_ANY_VERSION );                       
04718                 }
04719                 else {
04720                         switch ( info_3->cversion ) {
04721                         case 2:
04722                                 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 3 );
04723                                 break;
04724                         case 3: 
04725                                 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 2 );
04726                                 break;
04727                         default:
04728                                 DEBUG(0,("printer_driver_in_use: ERROR! unknown driver version (%d)\n", 
04729                                         info_3->cversion));
04730                                 werr = WERR_UNKNOWN_PRINTER_DRIVER;
04731                                 break;
04732                         }
04733                 }
04734 
04735                 /* now check the error code */
04736                                 
04737                 if ( W_ERROR_IS_OK(werr) ) {
04738                         /* it's ok to remove the driver, we have other architctures left */
04739                         in_use = False;
04740                         free_a_printer_driver( d, 3 );
04741                 }
04742         }
04743         
04744         /* report that the driver is not in use by default */
04745         
04746         return in_use;
04747 }
04748 
04749 
04750 /**********************************************************************
04751  Check to see if a ogiven file is in use by *info
04752  *********************************************************************/
04753  
04754 static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
04755 {
04756         int i = 0;
04757 
04758         if ( !info )
04759                 return False;
04760 
04761         /* mz: skip files that are in the list but already deleted */
04762         if (!file || !file[0]) {
04763                 return false;
04764         }
04765 
04766         if ( strequal(file, info->driverpath) )
04767                 return True;
04768 
04769         if ( strequal(file, info->datafile) )
04770                 return True;
04771 
04772         if ( strequal(file, info->configfile) )
04773                 return True;
04774 
04775         if ( strequal(file, info->helpfile) )
04776                 return True;
04777         
04778         /* see of there are any dependent files to examine */
04779         
04780         if ( !info->dependentfiles )
04781                 return False;
04782         
04783         while ( *info->dependentfiles[i] ) {
04784                 if ( strequal(file, info->dependentfiles[i]) )
04785                         return True;
04786                 i++;
04787         }
04788         
04789         return False;
04790 
04791 }
04792 
04793 /**********************************************************************
04794  Utility function to remove the dependent file pointed to by the 
04795  input parameter from the list 
04796  *********************************************************************/
04797 
04798 static void trim_dependent_file( fstring files[], int idx )
04799 {
04800         
04801         /* bump everything down a slot */
04802 
04803         while( *files[idx+1] ) {
04804                 fstrcpy( files[idx], files[idx+1] );
04805                 idx++;
04806         }
04807         
04808         *files[idx] = '\0';
04809 
04810         return; 
04811 }
04812 
04813 /**********************************************************************
04814  Check if any of the files used by src are also used by drv 
04815  *********************************************************************/
04816 
04817 static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src, 
04818                                        NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
04819 {
04820         BOOL    in_use = False;
04821         int     i = 0;
04822         
04823         if ( !src || !drv )
04824                 return False;
04825                 
04826         /* check each file.  Remove it from the src structure if it overlaps */
04827         
04828         if ( drv_file_in_use(src->driverpath, drv) ) {
04829                 in_use = True;
04830                 DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
04831                 fstrcpy( src->driverpath, "" );
04832         }
04833                 
04834         if ( drv_file_in_use(src->datafile, drv) ) {
04835                 in_use = True;
04836                 DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
04837                 fstrcpy( src->datafile, "" );
04838         }
04839                 
04840         if ( drv_file_in_use(src->configfile, drv) ) {
04841                 in_use = True;
04842                 DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
04843                 fstrcpy( src->configfile, "" );
04844         }
04845                 
04846         if ( drv_file_in_use(src->helpfile, drv) ) {
04847                 in_use = True;
04848                 DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
04849                 fstrcpy( src->helpfile, "" );
04850         }
04851         
04852         /* are there any dependentfiles to examine? */
04853         
04854         if ( !src->dependentfiles )
04855                 return in_use;
04856                 
04857         while ( *src->dependentfiles[i] ) {
04858                 if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
04859                         in_use = True;
04860                         DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
04861                         trim_dependent_file( src->dependentfiles, i );
04862                 } else
04863                         i++;
04864         }               
04865                 
04866         return in_use;
04867 }
04868 
04869 /****************************************************************************
04870   Determine whether or not a particular driver files are currently being 
04871   used by any other driver.  
04872   
04873   Return value is True if any files were in use by other drivers
04874   and False otherwise.
04875   
04876   Upon return, *info has been modified to only contain the driver files
04877   which are not in use
04878 
04879   Fix from mz:
04880 
04881   This needs to check all drivers to ensure that all files in use
04882   have been removed from *info, not just the ones in the first
04883   match.
04884 ****************************************************************************/
04885 
04886 BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
04887 {
04888         int                             i;
04889         int                             ndrivers;
04890         uint32                          version;
04891         fstring                         *list = NULL;
04892         NT_PRINTER_DRIVER_INFO_LEVEL    driver;
04893         BOOL in_use = False;
04894 
04895         if ( !info )
04896                 return False;
04897         
04898         version = info->cversion;
04899         
04900         /* loop over all driver versions */
04901         
04902         DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
04903         
04904         /* get the list of drivers */
04905                 
04906         list = NULL;
04907         ndrivers = get_ntdrivers(&list, info->environment, version);
04908                 
04909         DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n", 
04910                 ndrivers, info->environment, version));
04911 
04912         /* check each driver for overlap in files */
04913                 
04914         for (i=0; i<ndrivers; i++) {
04915                 DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
04916                         
04917                 ZERO_STRUCT(driver);
04918                         
04919                 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
04920                         SAFE_FREE(list);
04921                         return True;
04922                 }
04923                         
04924                 /* check if d2 uses any files from d1 */
04925                 /* only if this is a different driver than the one being deleted */
04926                         
04927                 if ( !strequal(info->name, driver.info_3->name) ) {
04928                         if ( trim_overlap_drv_files(info, driver.info_3) ) {
04929                                 /* mz: Do not instantly return -
04930                                  * we need to ensure this file isn't
04931                                  * also in use by other drivers. */
04932                                 in_use = True;
04933                         }
04934                 }
04935         
04936                 free_a_printer_driver(driver, 3);
04937         }       
04938         
04939         SAFE_FREE(list);
04940         
04941         DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
04942         
04943         driver.info_3 = info;
04944         
04945         if ( DEBUGLEVEL >= 20 )
04946                 dump_a_printer_driver( driver, 3 );
04947         
04948         return in_use;
04949 }
04950 
04951 /****************************************************************************
04952   Actually delete the driver files.  Make sure that 
04953   printer_driver_files_in_use() return False before calling 
04954   this.
04955 ****************************************************************************/
04956 
04957 static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
04958 {
04959         int i = 0;
04960         char *s;
04961         pstring file;
04962         connection_struct *conn;
04963         DATA_BLOB null_pw;
04964         NTSTATUS nt_status;
04965         fstring res_type;
04966         SMB_STRUCT_STAT  st;
04967 
04968         if ( !info_3 )
04969                 return False;
04970                 
04971         DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
04972         
04973         /*
04974          * Connect to the print$ share under the same account as the 
04975          * user connected to the rpc pipe. Note we must be root to 
04976          * do this.
04977          */
04978          
04979         null_pw = data_blob( NULL, 0 );
04980         fstrcpy(res_type, "A:");
04981         become_root();
04982         conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
04983         unbecome_root();
04984         
04985         if ( !conn ) {
04986                 DEBUG(0,("delete_driver_files: Unable to connect\n"));
04987                 return False;
04988         }
04989 
04990         if ( !CAN_WRITE(conn) ) {
04991                 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
04992                 return False;
04993         }
04994 
04995         /* Save who we are - we are temporarily becoming the connection user. */
04996 
04997         if ( !become_user(conn, conn->vuid) ) {
04998                 DEBUG(0,("delete_driver_files: Can't become user!\n"));
04999                 return False;
05000         }
05001 
05002         /* now delete the files; must strip the '\print$' string from 
05003            fron of path                                                */
05004         
05005         if ( *info_3->driverpath ) {
05006                 if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
05007                         pstrcpy( file, s );
05008                         driver_unix_convert(file, conn, NULL, &st);
05009                         DEBUG(10,("deleting driverfile [%s]\n", s));
05010                         unlink_internals(conn, 0, file, False, False);
05011                 }
05012         }
05013                 
05014         if ( *info_3->configfile ) {
05015                 if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
05016                         pstrcpy( file, s );
05017                         driver_unix_convert(file, conn, NULL, &st);
05018                         DEBUG(10,("deleting configfile [%s]\n", s));
05019                         unlink_internals(conn, 0, file, False, False);
05020                 }
05021         }
05022         
05023         if ( *info_3->datafile ) {
05024                 if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
05025                         pstrcpy( file, s );
05026                         driver_unix_convert(file, conn, NULL, &st);
05027                         DEBUG(10,("deleting datafile [%s]\n", s));
05028                         unlink_internals(conn, 0, file, False, False);
05029                 }
05030         }
05031         
05032         if ( *info_3->helpfile ) {
05033                 if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
05034                         pstrcpy( file, s );
05035                         driver_unix_convert(file, conn, NULL, &st);
05036                         DEBUG(10,("deleting helpfile [%s]\n", s));
05037                         unlink_internals(conn, 0, file, False, False);
05038                 }
05039         }
05040         
05041         /* check if we are done removing files */
05042         
05043         if ( info_3->dependentfiles ) {
05044                 while ( info_3->dependentfiles[i][0] ) {
05045                         char *p;
05046 
05047                         /* bypass the "\print$" portion of the path */
05048                         
05049                         if ( (p = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
05050                                 pstrcpy( file, p );
05051                                 driver_unix_convert(file, conn, NULL, &st);
05052                                 DEBUG(10,("deleting dependent file [%s]\n", file));
05053                                 unlink_internals(conn, 0, file, False, False);
05054                         }
05055                         
05056                         i++;
05057                 }
05058         }
05059 
05060         unbecome_user();
05061         
05062         return True;
05063 }
05064 
05065 /****************************************************************************
05066  Remove a printer driver from the TDB.  This assumes that the the driver was
05067  previously looked up.
05068  ***************************************************************************/
05069 
05070 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
05071                               uint32 version, BOOL delete_files )
05072 {
05073         pstring         key;
05074         const char     *arch;
05075         TDB_DATA        kbuf, dbuf;
05076         NT_PRINTER_DRIVER_INFO_LEVEL    ctr;
05077 
05078         /* delete the tdb data first */
05079 
05080         arch = get_short_archi(info_3->environment);
05081         if (!arch) {
05082                 return WERR_UNKNOWN_PRINTER_DRIVER;
05083         }
05084         slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
05085                 arch, version, info_3->name);
05086 
05087         DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
05088                 key, delete_files ? "TRUE" : "FALSE" ));
05089 
05090         ctr.info_3 = info_3;
05091         dump_a_printer_driver( ctr, 3 );
05092 
05093         kbuf.dptr=key;
05094         kbuf.dsize=strlen(key)+1;
05095 
05096         /* check if the driver actually exists for this environment */
05097         
05098         dbuf = tdb_fetch( tdb_drivers, kbuf );
05099         if ( !dbuf.dptr ) {
05100                 DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
05101                 return WERR_UNKNOWN_PRINTER_DRIVER;
05102         }
05103                 
05104         SAFE_FREE( dbuf.dptr );
05105         
05106         /* ok... the driver exists so the delete should return success */
05107                 
05108         if (tdb_delete(tdb_drivers, kbuf) == -1) {
05109                 DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
05110                 return WERR_ACCESS_DENIED;
05111         }
05112 
05113         /*
05114          * now delete any associated files if delete_files == True
05115          * even if this part failes, we return succes because the
05116          * driver doesn not exist any more
05117          */
05118 
05119         if ( delete_files )
05120                 delete_driver_files( info_3, user );
05121                         
05122                 
05123         DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
05124 
05125         return WERR_OK;
05126         }
05127         
05128 /****************************************************************************
05129  Store a security desc for a printer.
05130 ****************************************************************************/
05131 
05132 WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr)
05133 {
05134         SEC_DESC_BUF *new_secdesc_ctr = NULL;
05135         SEC_DESC_BUF *old_secdesc_ctr = NULL;
05136         prs_struct ps;
05137         TALLOC_CTX *mem_ctx = NULL;
05138         char *key;
05139         WERROR status;
05140 
05141         mem_ctx = talloc_init("nt_printing_setsec");
05142         if (mem_ctx == NULL)
05143                 return WERR_NOMEM;
05144 
05145         /* The old owner and group sids of the security descriptor are not
05146            present when new ACEs are added or removed by changing printer
05147            permissions through NT.  If they are NULL in the new security
05148            descriptor then copy them over from the old one. */
05149 
05150         if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->group_sid) {
05151                 DOM_SID *owner_sid, *group_sid;
05152                 SEC_ACL *dacl, *sacl;
05153                 SEC_DESC *psd = NULL;
05154                 size_t size;
05155 
05156                 if (!nt_printing_getsec(mem_ctx, sharename, &old_secdesc_ctr)) {
05157                         status = WERR_NOMEM;
05158                         goto out;
05159                 }
05160 
05161                 /* Pick out correct owner and group sids */
05162 
05163                 owner_sid = secdesc_ctr->sec->owner_sid ?
05164                         secdesc_ctr->sec->owner_sid :
05165                         old_secdesc_ctr->sec->owner_sid;
05166 
05167                 group_sid = secdesc_ctr->sec->group_sid ?
05168                         secdesc_ctr->sec->group_sid :
05169                         old_secdesc_ctr->sec->group_sid;
05170 
05171                 dacl = secdesc_ctr->sec->dacl ?
05172                         secdesc_ctr->sec->dacl :
05173                         old_secdesc_ctr->sec->dacl;
05174 
05175                 sacl = secdesc_ctr->sec->sacl ?
05176                         secdesc_ctr->sec->sacl :
05177                         old_secdesc_ctr->sec->sacl;
05178 
05179                 /* Make a deep copy of the security descriptor */
05180 
05181                 psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision, secdesc_ctr->sec->type,
05182                                     owner_sid, group_sid,
05183                                     sacl,
05184                                     dacl,
05185                                     &size);
05186 
05187                 if (!psd) {
05188                         status = WERR_NOMEM;
05189                         goto out;
05190                 }
05191 
05192                 new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
05193         }
05194 
05195         if (!new_secdesc_ctr) {
05196                 new_secdesc_ctr = secdesc_ctr;
05197         }
05198 
05199         /* Store the security descriptor in a tdb */
05200 
05201         prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
05202                  sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
05203 
05204         if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
05205                              &ps, 1)) {
05206                 status = WERR_BADFUNC;
05207                 goto out;
05208         }
05209 
05210         key = make_printers_secdesc_tdbkey( sharename );
05211 
05212         if (tdb_prs_store(tdb_printers, key, &ps)==0) {
05213                 status = WERR_OK;
05214         } else {
05215                 DEBUG(1,("Failed to store secdesc for %s\n", sharename));
05216                 status = WERR_BADFUNC;
05217         }
05218 
05219         /* Free malloc'ed memory */
05220 
05221  out:
05222 
05223         prs_mem_free(&ps);
05224         if (mem_ctx)
05225                 talloc_destroy(mem_ctx);
05226         return status;
05227 }
05228 
05229 /****************************************************************************
05230  Construct a default security descriptor buffer for a printer.
05231 ****************************************************************************/
05232 
05233 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
05234 {
05235         SEC_ACE ace[5]; /* max number of ace entries */
05236         int i = 0;
05237         SEC_ACCESS sa;
05238         SEC_ACL *psa = NULL;
05239         SEC_DESC_BUF *sdb = NULL;
05240         SEC_DESC *psd = NULL;
05241         DOM_SID adm_sid;
05242         size_t sd_size;
05243 
05244         /* Create an ACE where Everyone is allowed to print */
05245 
05246         init_sec_access(&sa, PRINTER_ACE_PRINT);
05247         init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
05248                      sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
05249 
05250         /* Add the domain admins group if we are a DC */
05251         
05252         if ( IS_DC ) {
05253                 DOM_SID domadmins_sid;
05254                 
05255                 sid_copy(&domadmins_sid, get_global_sam_sid());
05256                 sid_append_rid(&domadmins_sid, DOMAIN_GROUP_RID_ADMINS);
05257                 
05258                 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
05259                 init_sec_ace(&ace[i++], &domadmins_sid, 
05260                         SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 
05261                         SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
05262                 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
05263                         sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
05264         }
05265         else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
05266                 sid_append_rid(&adm_sid, DOMAIN_USER_RID_ADMIN);
05267 
05268                 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
05269                 init_sec_ace(&ace[i++], &adm_sid, 
05270                         SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 
05271                         SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
05272                 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
05273                         sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
05274         }
05275 
05276         /* add BUILTIN\Administrators as FULL CONTROL */
05277 
05278         init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
05279         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, 
05280                 SEC_ACE_TYPE_ACCESS_ALLOWED, sa, 
05281                 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
05282         init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, 
05283                 SEC_ACE_TYPE_ACCESS_ALLOWED,
05284                 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
05285 
05286         /* Make the security descriptor owned by the BUILTIN\Administrators */
05287 
05288         /* The ACL revision number in rpc_secdesc.h differs from the one
05289            created by NT when setting ACE entries in printer
05290            descriptors.  NT4 complains about the property being edited by a
05291            NT5 machine. */
05292 
05293         if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
05294                 psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
05295                         &global_sid_Builtin_Administrators, 
05296                         &global_sid_Builtin_Administrators,
05297                         NULL, psa, &sd_size);
05298         }
05299 
05300         if (!psd) {
05301                 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
05302                 return NULL;
05303         }
05304 
05305         sdb = make_sec_desc_buf(ctx, sd_size, psd);
05306 
05307         DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
05308                  (unsigned int)sd_size));
05309 
05310         return sdb;
05311 }
05312 
05313 /****************************************************************************
05314  Get a security desc for a printer.
05315 ****************************************************************************/
05316 
05317 BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **secdesc_ctr)
05318 {
05319         prs_struct ps;
05320         char *key;
05321         char *temp;
05322 
05323         if (strlen(sharename) > 2 && (temp = strchr(sharename + 2, '\\'))) {
05324                 sharename = temp + 1;
05325         }
05326 
05327         ZERO_STRUCT(ps);
05328 
05329         /* Fetch security descriptor from tdb */
05330 
05331         key = make_printers_secdesc_tdbkey( sharename  );
05332 
05333         if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
05334             !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
05335 
05336                 prs_mem_free(&ps);
05337 
05338                 DEBUG(4,("using default secdesc for %s\n", sharename));
05339 
05340                 if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
05341                         return False;
05342                 }
05343 
05344                 /* Save default security descriptor for later */
05345 
05346                 prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
05347                                 sizeof(SEC_DESC_BUF), ctx, MARSHALL);
05348 
05349                 if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
05350                         tdb_prs_store(tdb_printers, key, &ps);
05351                 }
05352 
05353                 prs_mem_free(&ps);
05354 
05355                 return True;
05356         }
05357 
05358         prs_mem_free(&ps);
05359 
05360         /* If security descriptor is owned by S-1-1-0 and winbindd is up,
05361            this security descriptor has been created when winbindd was
05362            down.  Take ownership of security descriptor. */
05363 
05364         if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
05365                 DOM_SID owner_sid;
05366 
05367                 /* Change sd owner to workgroup administrator */
05368 
05369                 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
05370                         SEC_DESC_BUF *new_secdesc_ctr = NULL;
05371                         SEC_DESC *psd = NULL;
05372                         size_t size;
05373 
05374                         /* Create new sd */
05375 
05376                         sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
05377 
05378                         psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision, (*secdesc_ctr)->sec->type,
05379                                             &owner_sid,
05380                                             (*secdesc_ctr)->sec->group_sid,
05381                                             (*secdesc_ctr)->sec->sacl,
05382                                             (*secdesc_ctr)->sec->dacl,
05383                                             &size);
05384 
05385                         if (!psd) {
05386                                 return False;
05387                         }
05388 
05389                         new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
05390                         if (!new_secdesc_ctr) {
05391                                 return False;
05392                         }
05393 
05394                         /* Swap with other one */
05395 
05396                         *secdesc_ctr = new_secdesc_ctr;
05397 
05398                         /* Set it */
05399 
05400                         nt_printing_setsec(sharename, *secdesc_ctr);
05401                 }
05402         }
05403 
05404         if (DEBUGLEVEL >= 10) {
05405                 SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
05406                 int i;
05407 
05408                 DEBUG(10, ("secdesc_ctr for %s has %d aces:\n", 
05409                            sharename, the_acl->num_aces));
05410 
05411                 for (i = 0; i < the_acl->num_aces; i++) {
05412                         fstring sid_str;
05413 
05414                         sid_to_string(sid_str, &the_acl->aces[i].trustee);
05415 
05416                         DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
05417                                    the_acl->aces[i].type, the_acl->aces[i].flags, 
05418                                    the_acl->aces[i].access_mask)); 
05419                 }
05420         }
05421 
05422         return True;
05423 }
05424 
05425 /* error code:
05426         0: everything OK
05427         1: level not implemented
05428         2: file doesn't exist
05429         3: can't allocate memory
05430         4: can't free memory
05431         5: non existant struct
05432 */
05433 
05434 /*
05435         A printer and a printer driver are 2 different things.
05436         NT manages them separatelly, Samba does the same.
05437         Why ? Simply because it's easier and it makes sense !
05438         
05439         Now explanation: You have 3 printers behind your samba server,
05440         2 of them are the same make and model (laser A and B). But laser B
05441         has an 3000 sheet feeder and laser A doesn't such an option.
05442         Your third printer is an old dot-matrix model for the accounting :-).
05443         
05444         If the /usr/local/samba/lib directory (default dir), you will have
05445         5 files to describe all of this.
05446         
05447         3 files for the printers (1 by printer):
05448                 NTprinter_laser A
05449                 NTprinter_laser B
05450                 NTprinter_accounting
05451         2 files for the drivers (1 for the laser and 1 for the dot matrix)
05452                 NTdriver_printer model X
05453                 NTdriver_printer model Y
05454 
05455 jfm: I should use this comment for the text file to explain
05456         same thing for the forms BTW.
05457         Je devrais mettre mes commentaires en francais, ca serait mieux :-)
05458 
05459 */
05460 
05461 /* Convert generic access rights to printer object specific access rights.
05462    It turns out that NT4 security descriptors use generic access rights and
05463    NT5 the object specific ones. */
05464 
05465 void map_printer_permissions(SEC_DESC *sd)
05466 {
05467         int i;
05468 
05469         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
05470                 se_map_generic(&sd->dacl->aces[i].access_mask,
05471                                &printer_generic_mapping);
05472         }
05473 }
05474 
05475 void map_job_permissions(SEC_DESC *sd)
05476 {
05477         int i;
05478 
05479         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
05480                 se_map_generic(&sd->dacl->aces[i].access_mask,
05481                                &job_generic_mapping);
05482         }
05483 }
05484 
05485 
05486 /****************************************************************************
05487  Check a user has permissions to perform the given operation.  We use the
05488  permission constants defined in include/rpc_spoolss.h to check the various
05489  actions we perform when checking printer access.
05490 
05491    PRINTER_ACCESS_ADMINISTER:
05492        print_queue_pause, print_queue_resume, update_printer_sec,
05493        update_printer, spoolss_addprinterex_level_2,
05494        _spoolss_setprinterdata
05495 
05496    PRINTER_ACCESS_USE:
05497        print_job_start
05498 
05499    JOB_ACCESS_ADMINISTER:
05500        print_job_delete, print_job_pause, print_job_resume,
05501        print_queue_purge
05502 
05503   Try access control in the following order (for performance reasons):
05504     1)  root ans SE_PRINT_OPERATOR can do anything (easy check) 
05505     2)  check security descriptor (bit comparisons in memory)
05506     3)  "printer admins" (may result in numerous calls to winbind)
05507 
05508  ****************************************************************************/
05509 BOOL print_access_check(struct current_user *user, int snum, int access_type)
05510 {
05511         SEC_DESC_BUF *secdesc = NULL;
05512         uint32 access_granted;
05513         NTSTATUS status;
05514         BOOL result;
05515         const char *pname;
05516         TALLOC_CTX *mem_ctx = NULL;
05517         SE_PRIV se_printop = SE_PRINT_OPERATOR;
05518         
05519         /* If user is NULL then use the current_user structure */
05520 
05521         if (!user)
05522                 user = &current_user;
05523 
05524         /* Always allow root or SE_PRINT_OPERATROR to do anything */
05525 
05526         if ( user->ut.uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) {
05527                 return True;
05528         }
05529 
05530         /* Get printer name */
05531 
05532         pname = PRINTERNAME(snum);
05533 
05534         if (!pname || !*pname) {
05535                 errno = EACCES;
05536                 return False;
05537         }
05538 
05539         /* Get printer security descriptor */
05540 
05541         if(!(mem_ctx = talloc_init("print_access_check"))) {
05542                 errno = ENOMEM;
05543                 return False;
05544         }
05545 
05546         if (!nt_printing_getsec(mem_ctx, pname, &secdesc)) {
05547                 talloc_destroy(mem_ctx);
05548                 errno = ENOMEM;
05549                 return False;
05550         }
05551 
05552         if (access_type == JOB_ACCESS_ADMINISTER) {
05553                 SEC_DESC_BUF *parent_secdesc = secdesc;
05554 
05555                 /* Create a child security descriptor to check permissions
05556                    against.  This is because print jobs are child objects
05557                    objects of a printer. */
05558 
05559                 secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
05560 
05561                 if (!secdesc) {
05562                         talloc_destroy(mem_ctx);
05563                         errno = ENOMEM;
05564                         return False;
05565                 }
05566 
05567                 map_job_permissions(secdesc->sec);
05568         } else {
05569                 map_printer_permissions(secdesc->sec);
05570         }
05571 
05572         /* Check access */
05573         result = se_access_check(secdesc->sec, user->nt_user_token, access_type,
05574                                  &access_granted, &status);
05575 
05576         DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
05577 
05578         /* see if we need to try the printer admin list */
05579 
05580         if ((access_granted == 0) &&
05581             (token_contains_name_in_list(uidtoname(user->ut.uid), NULL,
05582                                          user->nt_user_token,
05583                                          lp_printer_admin(snum)))) {
05584                 talloc_destroy(mem_ctx);
05585                 return True;
05586         }
05587 
05588         talloc_destroy(mem_ctx);
05589         
05590         if (!result) {
05591                 errno = EACCES;
05592         }
05593 
05594         return result;
05595 }
05596 
05597 /****************************************************************************
05598  Check the time parameters allow a print operation.
05599 *****************************************************************************/
05600 
05601 BOOL print_time_access_check(const char *servicename)
05602 {
05603         NT_PRINTER_INFO_LEVEL *printer = NULL;
05604         BOOL ok = False;
05605         time_t now = time(NULL);
05606         struct tm *t;
05607         uint32 mins;
05608 
05609         if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename)))
05610                 return False;
05611 
05612         if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
05613                 ok = True;
05614 
05615         t = gmtime(&now);
05616         mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
05617 
05618         if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
05619                 ok = True;
05620 
05621         free_a_printer(&printer, 2);
05622 
05623         if (!ok)
05624                 errno = EACCES;
05625 
05626         return ok;
05627 }
05628 
05629 /****************************************************************************
05630  Fill in the servername sent in the _spoolss_open_printer_ex() call
05631 ****************************************************************************/
05632 
05633 char* get_server_name( Printer_entry *printer )
05634 {
05635         return printer->servername;
05636 }
05637 
05638 

Sambaに対してSat Aug 29 21:23:13 2009に生成されました。  doxygen 1.4.7