Merge from appliance head of JR's changes for driver versioning.
authorJeremy Allison <jra@samba.org>
Tue, 14 Nov 2000 21:56:32 +0000 (21:56 +0000)
committerJeremy Allison <jra@samba.org>
Tue, 14 Nov 2000 21:56:32 +0000 (21:56 +0000)
Jeremy.

source/include/nt_printing.h
source/include/proto.h
source/printing/nt_printing.c
source/printing/printing.c
source/rpc_server/srv_spoolss_nt.c
source/smbd/reply.c
source/smbd/sec_ctx.c
source/smbd/uid.c
source/smbd/vfs.c

index d3c4f4aefa06af6c0756fc86f5f5fdd11548c8c2..4c9265f09fa1429aa2cba5fd9277a434a23898b1 100644 (file)
@@ -1,20 +1,20 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    Version 1.9.
    SMB parameters and setup
    Copyright (C) Andrew Tridgell              1992-2000,
    Copyright (C) Jean Francois Micouleau      1998-2000.
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -222,7 +222,7 @@ typedef struct ntdevicemode
        uint32  panningwidth;
        uint32  panningheight;
        uint8   *private;
-} NT_DEVICEMODE; 
+} NT_DEVICEMODE;
 
 typedef struct nt_printer_info_level_2
 {
@@ -288,7 +288,7 @@ typedef struct _form
 
 #ifndef SAMBA_PRINTER_PORT_NAME
 #define SAMBA_PRINTER_PORT_NAME "Samba Printer Port"
-#endif 
+#endif
 
 /* DOS header format */
 #define DOS_HEADER_SIZE                 64
@@ -311,11 +311,25 @@ typedef struct _form
 #define PE_HEADER_SIGNATURE             0x00004550
 #define PE_HEADER_MACHINE_OFFSET        4
 #define PE_HEADER_MACHINE_I386          0x14c
+#define PE_HEADER_NUMBER_OF_SECTIONS    6
 #define PE_HEADER_MAJOR_OS_VER_OFFSET   64
 #define PE_HEADER_MINOR_OS_VER_OFFSET   66
 #define PE_HEADER_MAJOR_IMG_VER_OFFSET  68
 #define PE_HEADER_MINOR_IMG_VER_OFFSET  70
 #define PE_HEADER_MAJOR_SS_VER_OFFSET   72
 #define PE_HEADER_MINOR_SS_VER_OFFSET   74
+#define PE_HEADER_SECT_HEADER_SIZE      40
+#define PE_HEADER_SECT_NAME_OFFSET      0
+#define PE_HEADER_SECT_SIZE_DATA_OFFSET 16
+#define PE_HEADER_SECT_PTR_DATA_OFFSET  20
+
+/* Microsoft file version format */
+#define VS_SIGNATURE                    "VS_VERSION_INFO"
+#define VS_MAGIC_VALUE                  0xfeef04bd
+#define VS_MAJOR_OFFSET                                        8
+#define VS_MINOR_OFFSET                                        12
+#define VS_VERSION_INFO_UNICODE_SIZE    (sizeof(VS_SIGNATURE)*2+4+VS_MINOR_OFFSET+4) /* not true size! */
+#define VS_VERSION_INFO_SIZE            (sizeof(VS_SIGNATURE)+4+VS_MINOR_OFFSET+4)   /* not true size! */
+#define VS_NE_BUF_SIZE                  4096  /* Must be > 2*VS_VERSION_INFO_SIZE */
 
 #endif /* NT_PRINTING_H_ */
index 3bcf6e1e9004be9e28174c99ee8cffb5d21673e0..57d972cf364f69ff07f47ca0e4fa36afe7609605 100644 (file)
@@ -1747,9 +1747,9 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32
 void update_a_form(nt_forms_struct **list, const FORM *form, int count);
 int get_ntdrivers(fstring **list, char *architecture, uint32 version);
 BOOL get_short_archi(char *short_archi, char *long_archi);
-uint32 clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level);
-BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, 
-                                  uint32 level, struct current_user *user, uint32 *perr);
+uint32 clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
+                                                         uint32 level, struct current_user *user);
+BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, struct current_user *user, uint32 *perr);
 uint32 get_a_printer_driver_9x_compatible(pstring line, fstring model);
 uint32 del_a_printer(char *sharename);
 BOOL add_a_specific_param(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_PARAM *param);
@@ -1763,12 +1763,12 @@ uint32 add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level);
 uint32 get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring sharename);
 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level);
 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level);
-uint32 get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level, 
+uint32 get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
                             fstring printername, fstring architecture, uint32 version);
 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level);
 BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, uint32 param_index,
                                  fstring value, uint8 **data, uint32 *type, uint32 *len);
-BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level, 
+BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
                         fstring value, uint8 **data, uint32 *type, uint32 *len);
 uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr);
 BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr);
@@ -3703,6 +3703,8 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
 int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
 int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
+                                        int dirtype, char *name);
 int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize);
 int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz);
@@ -3880,8 +3882,9 @@ BOOL vfs_directory_exist(connection_struct *conn, char *dname, SMB_STRUCT_STAT *
 int vfs_mkdir(connection_struct *conn, char *fname, mode_t mode);
 char *vfs_getwd(connection_struct *conn, char *unix_path);
 BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf);
+ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count);
 ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N);
-SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp, 
+SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
                            int out_fd, files_struct *out_fsp,
                            SMB_OFF_T n, char *header, int headlen, int align);
 char *vfs_readdirname(connection_struct *conn, void *p);
index 1519faa5673a0e64357c7957d29276e78751f646..2c329c78a585c0cd0557819450cf328272add3ef 100644 (file)
@@ -1,21 +1,21 @@
 #define OLD_NTDOMAIN 1
-/* 
+/*
  *  Unix SMB/Netbios implementation.
  *  Version 1.9.
  *  RPC Pipe client / server routines
  *  Copyright (C) Andrew Tridgell              1992-2000,
  *  Copyright (C) Jean François Micouleau      1998-2000.
- *  
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
- *  
+ *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *  
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -25,7 +25,7 @@
 
 extern int DEBUGLEVEL;
 extern pstring global_myname;
-extern DOM_SID global_sid_World; 
+extern DOM_SID global_sid_World;
 
 static TDB_CONTEXT *tdb; /* used for driver files */
 
@@ -72,7 +72,7 @@ BOOL nt_printing_init(void)
        return True;
 }
 
-  
+
 /****************************************************************************
 get a form struct list
 ****************************************************************************/
@@ -84,8 +84,8 @@ int get_ntforms(nt_forms_struct **list)
        int i;
        int n = 0;
 
-       for (kbuf = tdb_firstkey(tdb); 
-            kbuf.dptr; 
+       for (kbuf = tdb_firstkey(tdb);
+            kbuf.dptr;
             newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
                if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0) continue;
                
@@ -131,7 +131,7 @@ int write_ntforms(nt_forms_struct **list, int number)
                /* save index, so list is rebuilt in correct order */
                len = tdb_pack(buf, sizeof(buf), "dddddddd",
                               i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
-                              (*list)[i].left, (*list)[i].top, (*list)[i].right, 
+                              (*list)[i].left, (*list)[i].top, (*list)[i].right,
                               (*list)[i].bottom);
                if (len > sizeof(buf)) break;
                slprintf(key, sizeof(key), "%s%s", FORMS_PREFIX, (*list)[i].name);
@@ -154,8 +154,8 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
        BOOL update;
        fstring form_name;
 
-       /* 
-        * NT tries to add forms even when 
+       /*
+        * NT tries to add forms even when
         * they are already in the base
         * only update the values if already present
         */
@@ -192,7 +192,7 @@ BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
 }
 
 /****************************************************************************
- delete a named form struct 
+ delete a named form struct
 ****************************************************************************/
 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32 *ret)
 {
@@ -239,7 +239,7 @@ BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, uint32
 }
 
 /****************************************************************************
-update a form struct 
+update a form struct
 ****************************************************************************/
 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
 {
@@ -265,7 +265,7 @@ void update_a_form(nt_forms_struct **list, const FORM *form, int count)
        (*list)[n].right=form->right;
        (*list)[n].bottom=form->bottom;
 }
+
 /****************************************************************************
 get the nt drivers list
 
@@ -281,8 +281,8 @@ int get_ntdrivers(fstring **list, char *architecture, uint32 version)
        get_short_archi(short_archi, architecture);
        slprintf(key, sizeof(key), "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
 
-       for (kbuf = tdb_firstkey(tdb); 
-            kbuf.dptr; 
+       for (kbuf = tdb_firstkey(tdb);
+            kbuf.dptr;
             newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
                if (strncmp(kbuf.dptr, key, strlen(key)) != 0) continue;
                
@@ -322,7 +322,7 @@ BOOL get_short_archi(char *short_archi, char *long_archi)
        DEBUG(107,("Getting architecture dependant directory\n"));
        do {
                i++;
-       } while ( (archi_table[i].long_archi!=NULL ) && 
+       } while ( (archi_table[i].long_archi!=NULL ) &&
                  StrCaseCmp(long_archi, archi_table[i].long_archi) );
 
        if (archi_table[i].long_archi==NULL) {
@@ -342,43 +342,84 @@ BOOL get_short_archi(char *short_archi, char *long_archi)
 /****************************************************************************
 Determine the correct cVersion associated with an architecture and driver
 ****************************************************************************/
-static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in)
+static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
+                                                                  struct current_user *user, uint32 *perr)
 {
-       int  fd = -1;
-       int  service;
-       int  cversion;
-       ssize_t  byte_count;
-       char buf[PE_HEADER_SIZE];
-       pstring driverpath;
+       int               cversion;
+       int               access_mode;
+       int               action;
+       int               ecode;
+       char              buf[PE_HEADER_SIZE];
+       ssize_t           byte_count;
+       pstring           driverpath;
+       fstring           user_name;
+       fstring           null_pw;
+       files_struct      *fsp = NULL;
+       SMB_STRUCT_STAT   st;
+       struct passwd *pass;
+       connection_struct *conn;
 
        /* If architecture is Windows 95/98, the version is always 0. */
        if (strcmp(architecture, "WIN40") == 0) {
                DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
                return 0;
        }
-       
-       /* Open the driver file (Portable Executable format) and determine the
-        * deriver the cversion.
-        */
-       if ((service = find_service("print$")) == -1) {
-               DEBUG(3,("get_correct_cversion: Can't find print$ service\n"));
-               goto error_exit;
+
+       become_root();
+       pass = getpwuid(user->uid);
+       if(pass == NULL) {
+               DEBUG(0,("get_correct_cversion: Unable to get passwd entry for uid %u\n",
+                               (unsigned int)user->uid ));
+               unbecome_root();
+               *perr = ERROR_ACCESS_DENIED;
+               return -1;
        }
+       unbecome_root();
 
-       slprintf(driverpath, sizeof(driverpath), "%s/%s/%s",
-                        lp_pathname(service), architecture, driverpath_in);
+       /* connect to the print$ share under the same account as the user connected
+        * to the rpc pipe */   
+       fstrcpy(user_name, pass->pw_name );
+       DEBUG(10,("get_correct_cversion: uid %d -> user %s\n", (int)user->uid, user_name));
 
-       dos_to_unix(driverpath, True);
+       /* Null password is ok - we are already an authenticated user... */
+       *null_pw = '\0';
+       conn = make_connection("print$", user_name, null_pw, 0, "A:", user->vuid, &ecode);
 
-       if ((fd = sys_open(driverpath, O_RDONLY, 0)) == -1) {
+       if (conn == NULL) {
+               DEBUG(0,("get_correct_cversion: Unable to connect\n"));
+               *perr = (uint32)ecode;
+               return -1;
+       }
+
+       /* Save who we are - we are temporarily becoming the connection user. */
+       push_sec_ctx();
+
+       if (!become_user(conn, conn->vuid)) {
+               DEBUG(0,("get_correct_cversion: Can't become user %s\n", user_name ));
+               *perr = ERROR_ACCESS_DENIED;
+               pop_sec_ctx();
+               return -1;
+       }
+
+       /* Open the driver file (Portable Executable format) and determine the
+        * deriver the cversion. */
+       slprintf(driverpath, sizeof(driverpath), "%s/%s", architecture, driverpath_in);
+       dos_to_unix(driverpath, True);
+       fsp = open_file_shared(conn, driverpath, &st,
+                                                  SET_OPEN_MODE(DOS_OPEN_RDONLY),
+                                                  (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+                                                  0, 0, &access_mode, &action);
+       if (!fsp) {
                DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
                                driverpath, errno));
+               *perr = ERROR_ACCESS_DENIED;
                goto error_exit;
        }
-        
-       if ((byte_count = read(fd, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
+
+       if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
                DEBUG(3,("get_correct_cversion: File [%s] DOS header too short, bytes read = %d\n",
                                driverpath, byte_count));
+               *perr = NT_STATUS_FILE_INVALID;
                goto error_exit;
        }
 
@@ -386,22 +427,24 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in)
        if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
                DEBUG(6,("get_correct_cversion: File [%s] bad DOS magic = 0x%x\n",
                                driverpath, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
+               *perr = NT_STATUS_FILE_INVALID;
                goto error_exit;
        }
 
        /* Skip OEM header (if any) and the DOS stub to start of Windows header */
-       if (sys_lseek(fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
+       if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
                DEBUG(3,("get_correct_cversion: File [%s] too short, errno = %d\n",
                                driverpath, errno));
+               *perr = NT_STATUS_FILE_INVALID;
                goto error_exit;
        }
 
-       if ((byte_count = read(fd, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
+       if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
                DEBUG(3,("get_correct_cversion: File [%s] Windows header too short, bytes read = %d\n",
                                driverpath, byte_count));
+               *perr = NT_STATUS_FILE_INVALID;
                goto error_exit;
        }
-       close(fd);
 
        /* The header may be a PE (Portable Executable) or an NE (New Executable) */
        if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
@@ -413,11 +456,13 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in)
                                default:
                                        DEBUG(6,("get_correct_cversion: PE formated file [%s] bad version = %d\n",
                                                        driverpath, SVAL(buf,PE_HEADER_MAJOR_OS_VER_OFFSET)));
+                                       *perr = NT_STATUS_FILE_INVALID;
                                        goto error_exit;
                        }
                } else {
                        DEBUG(6,("get_correct_cversion: PE formatted file [%s] wrong machine = 0x%x\n",
                                        driverpath, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
+                       *perr = NT_STATUS_FILE_INVALID;
                        goto error_exit;
                }
 
@@ -430,39 +475,55 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in)
                                default:
                                        DEBUG(6,("get_correct_cversion: NE formated file [%s] bad version = %d\n",
                                                        driverpath, CVAL(buf,NE_HEADER_MAJOR_VER_OFFSET)));
+                                       *perr = NT_STATUS_FILE_INVALID;
                                        goto error_exit;
                        }
                } else {
                        DEBUG(6,("get_correct_cversion: NE formatted file [%s] wrong target OS = 0x%x\n",
                                        driverpath, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
+                       *perr = NT_STATUS_FILE_INVALID;
                        goto error_exit;
                }
 
        } else {
                DEBUG(6,("get_correct_cversion: Unknown file format [%s], signature = 0x%x\n",
                                driverpath, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
+               *perr = NT_STATUS_FILE_INVALID;
                goto error_exit;
        }
 
        DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
                        driverpath, cversion));
+
+       fsp->conn->vfs_ops.close(fsp, fsp->fd);
+       file_free(fsp);
+       close_cnum(conn, user->vuid);
+       pop_sec_ctx();
        return cversion;
 
 
        error_exit:
-               if(fd != -1)
-                       close(fd);
+               if(fsp) {
+                       if(fsp->fd != -1)
+                               fsp->conn->vfs_ops.close(fsp, fsp->fd);
+                       file_free(fsp);
+               }
+
+               close_cnum(conn, user->vuid);
+               pop_sec_ctx();
                return -1;
 }
 
 /****************************************************************************
 ****************************************************************************/
-static uint32 clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
+static uint32 clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
+                                                                                        struct current_user *user)
 {
        fstring architecture;
        fstring new_name;
        char *p;
        int i;
+       uint32 err;
 
        /* clean up the driver name.
         * we can get .\driver.dll
@@ -511,21 +572,23 @@ static uint32 clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri
         *      NT 4: cversion=2
         *      NT2K: cversion=3
         */
-       if ((driver->cversion = get_correct_cversion(architecture,
-                                                                                       driver->driverpath)) == -1)
-               return NT_STATUS_FILE_INVALID;     /* Not the best error. Fix JRR */
+       if ((driver->cversion = get_correct_cversion( architecture,
+                                                                       driver->driverpath, user, &err)) == -1)
+               return err;
 
        return NT_STATUS_NO_PROBLEMO;
 }
-        
+       
 /****************************************************************************
 ****************************************************************************/
-static uint32 clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
+static uint32 clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver,
+                                                                                        struct current_user *user)
 {
        fstring architecture;
        fstring new_name;
        char *p;
        int i;
+       uint32 err;
 
        /* clean up the driver name.
         * we can get .\driver.dll
@@ -575,29 +638,30 @@ static uint32 clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *dri
         *      NT2K: cversion=3
         */
        if ((driver->version = get_correct_cversion(architecture,
-                                                                                       driver->driverpath)) == -1)
-               return NT_STATUS_FILE_INVALID;     /* Not the best error. Fix JRR */
+                                                                       driver->driverpath, user, &err)) == -1)
+               return err;
 
        return NT_STATUS_NO_PROBLEMO;
 }
 
 /****************************************************************************
 ****************************************************************************/
-uint32 clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level)
+uint32 clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
+                                                         uint32 level, struct current_user *user)
 {
        switch (level) {
                case 3:
                {
                        NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
                        driver=driver_abstract.info_3;
-                       return clean_up_driver_struct_level_3(driver);
+                       return clean_up_driver_struct_level_3(driver, user);
                        break;
                }
                case 6:
                {
                        NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
                        driver=driver_abstract.info_6;
-                       return clean_up_driver_struct_level_6(driver);
+                       return clean_up_driver_struct_level_6(driver, user);
                        break;
                }
                default:
@@ -624,11 +688,373 @@ static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PR
     dst->dependentfiles = src->dependentfiles;
 }
 
+#if 0 /* Debugging function */
+
+static char* ffmt(unsigned char *c){
+       int i;
+       static char ffmt_str[17];
+
+       for (i=0; i<16; i++) {
+               if ((c[i] < ' ') || (c[i] > '~'))
+                       ffmt_str[i]='.';
+               else
+                       ffmt_str[i]=c[i];
+       }
+    ffmt_str[16]='\0';
+       return ffmt_str;
+}
+
+#endif
+
+/****************************************************************************
+Version information in Microsoft files is held in a VS_VERSION_INFO structure.
+There are two case to be covered here: PE (Portable Executable) and NE (New
+Executable) files. Both files support the same INFO structure, but PE files
+store the signature in unicode, and NE files store it as !unicode.
+****************************************************************************/
+//static BOOL get_file_version(connection_struct *conn, int fd, char *fname,
+static BOOL get_file_version(files_struct *fsp, char *fname,uint32 *major,
+                                                        uint32 *minor)
+{
+       int     i;
+       char    *buf;
+       ssize_t byte_count;
+
+       if ((buf=malloc(PE_HEADER_SIZE)) == NULL) {
+               DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
+                               fname, PE_HEADER_SIZE));
+               goto error_exit;
+       }
+
+       /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
+       if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
+               DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %d\n",
+                               fname, byte_count));
+               goto no_version_info;
+       }
+
+       /* Is this really a DOS header? */
+       if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
+               DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
+                               fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
+               goto no_version_info;
+       }
+
+       /* Skip OEM header (if any) and the DOS stub to start of Windows header */
+       if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
+               DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
+                               fname, errno));
+               /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+               goto no_version_info;
+       }
+
+       if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
+               DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %d\n",
+                               fname, byte_count));
+               /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+               goto no_version_info;
+       }
+
+       /* The header may be a PE (Portable Executable) or an NE (New Executable) */
+       if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
+               int num_sections;
+               int section_table_bytes;
+               
+               if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) {
+                       DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n",
+                                       fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
+                       /* At this point, we assume the file is in error. It still could be somthing
+                        * else besides a PE file, but it unlikely at this point.
+                        */
+                       goto error_exit;
+               }
+
+               /* get the section table */
+               num_sections        = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
+               section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
+               free(buf);
+               if ((buf=malloc(section_table_bytes)) == NULL) {
+                       DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
+                                       fname, section_table_bytes));
+                       goto error_exit;
+               }
+
+               if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
+                       DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %d\n",
+                                       fname, byte_count));
+                       goto error_exit;
+               }
+
+               /* Iterate the section table looking for the resource section ".rsrc" */
+               for (i = 0; i < num_sections; i++) {
+                       int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
+
+                       if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
+                               int section_pos   = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
+                               int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
+
+                               free(buf);
+                               if ((buf=malloc(section_bytes)) == NULL) {
+                                       DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
+                                                       fname, section_bytes));
+                                       goto error_exit;
+                               }
+
+                               /* Seek to the start of the .rsrc section info */
+                               if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
+                                       DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
+                                                       fname, errno));
+                                       goto error_exit;
+                               }
+
+                               if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
+                                       DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %d\n",
+                                                       fname, byte_count));
+                                       goto error_exit;
+                               }
+
+                               for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
+                                       /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
+                                       if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
+                                               /* Align to next long address */
+                                               int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
+
+                                               if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
+                                                       *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
+                                                       *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
+                                                       
+                                                       DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
+                                                                         fname, *major, *minor,
+                                                                         (*major>>16)&0xffff, *major&0xffff,
+                                                                         (*minor>>16)&0xffff, *minor&0xffff));
+                                                       free(buf);
+                                                       return True;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               /* Version info not found, fall back to origin date/time */
+               DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
+               free(buf);
+               return False;
+
+       } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
+               if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
+                       DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
+                                       fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
+                       /* At this point, we assume the file is in error. It still could be somthing
+                        * else besides a NE file, but it unlikely at this point. */
+                       goto error_exit;
+               }
+
+               /* Allocate a bit more space to speed up things */
+               free(buf);
+               if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) {
+                       DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes  = %d\n",
+                                       fname, PE_HEADER_SIZE));
+                       goto error_exit;
+               }
+
+               /* This is a HACK! I got tired of trying to sort through the messy
+                * 'NE' file format. If anyone wants to clean this up please have at
+                * it, but this works. 'NE' files will eventually fade away. JRR */
+               while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
+                       /* Cover case that should not occur in a well formed 'NE' .dll file */
+                       if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
+
+                       for(i=0; i<byte_count; i++) {
+                               /* Fast skip past data that can't possibly match */
+                               if (buf[i] != 'V') continue;
+
+                               /* Potential match data crosses buf boundry, move it to beginning
+                                * of buf, and fill the buf with as much as it will hold. */
+                               if (i>byte_count-VS_VERSION_INFO_SIZE) {
+                                       int bc;
+
+                                       memcpy(buf, &buf[i], byte_count-i);
+                                       if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
+                                                                  (byte_count-i))) < 0) {
+
+                                               DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
+                                                                fname, errno));
+                                               goto error_exit;
+                                       }
+
+                                       byte_count = bc + (byte_count - i);
+                                       if (byte_count<VS_VERSION_INFO_SIZE) break;
+
+                                       i = 0;
+                               }
+
+                               /* Check that the full signature string and the magic number that
+                                * follows exist (not a perfect solution, but the chances that this
+                                * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
+                                * twice, as it is simpler to read the code. */
+                               if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
+                                       /* Compute skip alignment to next long address */
+                                       int skip = -(fsp->conn->vfs_ops.lseek(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
+                                                                sizeof(VS_SIGNATURE)) & 3;
+                                       if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
+
+                                       *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
+                                       *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
+                                       DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
+                                                         fname, *major, *minor,
+                                                         (*major>>16)&0xffff, *major&0xffff,
+                                                         (*minor>>16)&0xffff, *minor&0xffff));
+                                       free(buf);
+                                       return True;
+                               }
+                       }
+               }
+
+               /* Version info not found, fall back to origin date/time */
+               DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
+               free(buf);
+               return False;
+
+       } else
+               /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
+               DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
+                               fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
+
+       no_version_info:
+               free(buf);
+               return False;
+
+       error_exit:
+               free(buf);
+               return -1;
+}
+
+/****************************************************************************
+Drivers for Microsoft systems contain multiple files. Often, multiple drivers
+share one or more files. During the MS installation process files are checked
+to insure that only a newer version of a shared file is installed over an
+older version. There are several possibilities for this comparison. If there
+is no previous version, the new one is newer (obviously). If either file is
+missing the version info structure, compare the creation date (on Unix use
+the modification date). Otherwise chose the numerically larger version number.
+****************************************************************************/
+static int file_version_is_newer(connection_struct *conn, fstring new_file,
+                                                               fstring old_file)
+{
+       BOOL   use_version = True;
+       pstring filepath;
+
+       uint32 new_major;
+       uint32 new_minor;
+       time_t new_create_time;
+
+       uint32 old_major;
+       uint32 old_minor;
+       time_t old_create_time;
+
+       int access_mode;
+       int action;
+       files_struct    *fsp = NULL;
+       SMB_STRUCT_STAT st;
+       SMB_STRUCT_STAT stat_buf;
+       
+       /* Get file version info (if available) for previous file (if it exists) */
+       pstrcpy(filepath, old_file);
+       dos_to_unix(filepath, True);
+
+       fsp = open_file_shared(conn, filepath, &stat_buf,
+                                                  SET_OPEN_MODE(DOS_OPEN_RDONLY),
+                                                  (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+                                                  0, 0, &access_mode, &action);
+       if (!fsp) {
+               /* Old file not found, so by definition new file is in fact newer */
+               DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
+                               filepath, errno));
+               return True;
+
+       } else {
+               int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
+               if (ret == -1) goto error_exit;
+
+               if (!ret) {
+                       DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
+                                        old_file));
+                       use_version = False;
+                       if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit;
+                       old_create_time = st.st_mtime;
+                       DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
+               }
+       }
+       fsp->conn->vfs_ops.close(fsp, fsp->fd);
+       file_free(fsp);
+
+
+       /* Get file version info (if available) for new file */
+       pstrcpy(filepath, new_file);
+       dos_to_unix(filepath, True);
+       fsp = open_file_shared(conn, filepath, &stat_buf,
+                                                  SET_OPEN_MODE(DOS_OPEN_RDONLY),
+                                                  (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+                                                  0, 0, &access_mode, &action);
+       if (!fsp) {
+               /* New file not found, this shouldn't occur if the caller did its job */
+               DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
+                               filepath, errno));
+               goto error_exit;
+
+       } else {
+               int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
+               if (ret == -1) goto error_exit;
+
+               if (!ret) {
+                       DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
+                                        new_file));
+                       use_version = False;
+                       if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit;
+                       new_create_time = st.st_mtime;
+                       DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
+               }
+       }
+       fsp->conn->vfs_ops.close(fsp, fsp->fd);
+       file_free(fsp);
+
+       if (use_version) {
+               /* Compare versions and choose the larger version number */
+               if (new_major > old_major ||
+                       (new_major == old_major && new_minor > old_minor)) {
+                       
+                       DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
+                       return True;
+               }
+               else {
+                       DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
+                       return False;
+               }
+
+       } else {
+               /* Compare modification time/dates and choose the newest time/date */
+               if (new_create_time > old_create_time) {
+                       DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
+                       return True;
+               }
+               else {
+                       DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
+                       return False;
+               }
+       }
+
+       error_exit:
+               if(fsp) {
+                       file_free(fsp);
+                       if(fsp->fd != -1)
+                               fsp->conn->vfs_ops.close(fsp, fsp->fd);
+               }
+               return -1;
+}
 
 /****************************************************************************
 ****************************************************************************/
-BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, 
-                                  uint32 level, struct current_user *user, uint32 *perr)
+BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level, struct current_user *user, uint32 *perr)
 {
        NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
        NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
@@ -643,6 +1069,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        pstring outbuf;
        struct passwd *pass;
        int ecode;
+       int ver = 0;
        int outsize = 0;
        int i;
 
@@ -698,95 +1125,112 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                return False;
        }
 
-       /* 
-        * make the directories version and version\driver_name 
+       /*
+        * make the directories version and version\driver_name
         * under the architecture directory.
         */
        DEBUG(5,("Creating first directory\n"));
-       slprintf(new_dir, sizeof(new_dir), "%s\\%d", architecture, driver->cversion);
+       slprintf(new_dir, sizeof(new_dir), "%s/%d", architecture, driver->cversion);
        mkdir_internal(conn, inbuf, outbuf, new_dir);
 
-       /* move all the files, one by one, 
-        * from archi\filexxx.yyy to
-        * archi\version\filexxx.yyy
-        *
-        * Note: drivers may list the same file name in several places. This
-        * causes problems on a second attempt to move the file. JRR
+       /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
+        * listed for this driver which has already been moved, skip it (note:
+        * drivers may list the same file name several times. Then check if the
+        * file already exists in archi\cversion\, if so, check that the version
+        * info (or time stamps if version info is unavailable) is newer (or the
+        * date is later). If it is, move it to archi\cversion\filexxx.yyy.
+        * Otherwise, delete the file.
         *
-        * Note: use the replace flag on rename_internals() call, otherwise it
-        * is very difficult to change previously installed drivers... the Windows
-        * GUI offers the user the choice to replace or keep exisitng driver. JRR
+        * If a file is not moved to archi\cversion\ because of an error, all the
+        * rest of the 'unmoved' driver files are removed from archi\. If one or
+        * more of the driver's files was already moved to archi\cversion\, it
+        * potentially leaves the driver in a partially updated state. Version
+        * trauma will most likely occur if an client attempts to use any printer
+        * bound to the driver. Perhaps a rewrite to make sure the moves can be
+        * done is appropriate... later JRR
         */
 
-       DEBUG(5,("Moving file now !\n"));
+       DEBUG(5,("Moving files now !\n"));
 
        if (driver->driverpath && strlen(driver->driverpath)) {
-       slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->driverpath);       
-       slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->driverpath);    
-       if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
-               DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
-                               old_name, new_name ));
-               close_cnum(conn, user->vuid);
-               pop_sec_ctx();
-               *perr = (uint32)SVAL(outbuf,smb_err);
-               return False;
-       }
+               slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->driverpath);        
+               slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->driverpath);     
+               if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+                       if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                               DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+                                               new_name, old_name));
+                               *perr = (uint32)SVAL(outbuf,smb_err);
+                               unlink_internals(conn, inbuf, outbuf, 0, new_name);
+                               ver = -1;
+                       }
+               }
+               else
+                       unlink_internals(conn, inbuf, outbuf, 0, new_name);
        }
 
        if (driver->datafile && strlen(driver->datafile)) {
-       if (!strequal(driver->datafile, driver->driverpath)) {
-               slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->datafile); 
-               slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->datafile);      
-               if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
-                       DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
-                                       old_name, new_name ));
-                       close_cnum(conn, user->vuid);
-                       pop_sec_ctx();
-                       *perr = (uint32)SVAL(outbuf,smb_err);
-                       return False;
+               if (!strequal(driver->datafile, driver->driverpath)) {
+                       slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->datafile);  
+                       slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->datafile);       
+                       if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+                               if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                                       DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+                                                       new_name, old_name));
+                                       *perr = (uint32)SVAL(outbuf,smb_err);
+                                       unlink_internals(conn, inbuf, outbuf, 0, new_name);
+                                       ver = -1;
+                               }
+                       }
+                       else
+                               unlink_internals(conn, inbuf, outbuf, 0, new_name);
                }
        }
-       }
 
        if (driver->configfile && strlen(driver->configfile)) {
-       if (!strequal(driver->configfile, driver->driverpath) &&
-               !strequal(driver->configfile, driver->datafile)) {
-               slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->configfile);       
-               slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->configfile);    
-               if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
-                       DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
-                               old_name, new_name ));
-                       close_cnum(conn, user->vuid);
-                       pop_sec_ctx();
-                       *perr = (uint32)SVAL(outbuf,smb_err);
-                       return False;
+               if (!strequal(driver->configfile, driver->driverpath) &&
+                       !strequal(driver->configfile, driver->datafile)) {
+                       slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->configfile);        
+                       slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->configfile);     
+                       if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+                               if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                                       DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+                                                       new_name, old_name));
+                                       *perr = (uint32)SVAL(outbuf,smb_err);
+                                       unlink_internals(conn, inbuf, outbuf, 0, new_name);
+                                       ver = -1;
+                               }
+                       }
+                       else
+                               unlink_internals(conn, inbuf, outbuf, 0, new_name);
                }
        }
-       }
 
        if (driver->helpfile && strlen(driver->helpfile)) {
-       if (!strequal(driver->helpfile, driver->driverpath) &&
+               if (!strequal(driver->helpfile, driver->driverpath) &&
                        !strequal(driver->helpfile, driver->datafile) &&
                        !strequal(driver->helpfile, driver->configfile)) {
-               slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->helpfile); 
-               slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->helpfile);      
-               if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
-                       DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
-                               old_name, new_name ));
-                       close_cnum(conn, user->vuid);
-                       pop_sec_ctx();
-                       *perr = (uint32)SVAL(outbuf,smb_err);
-                       return False;
+                       slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->helpfile);  
+                       slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->helpfile);       
+                       if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+                               if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                                       DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+                                                       new_name, old_name));
+                                       *perr = (uint32)SVAL(outbuf,smb_err);
+                                       unlink_internals(conn, inbuf, outbuf, 0, new_name);
+                                       ver = -1;
+                               }
+                       }
+                       else
+                               unlink_internals(conn, inbuf, outbuf, 0, new_name);
                }
        }
-       }
 
        if (driver->dependentfiles) {
                for (i=0; *driver->dependentfiles[i]; i++) {
                        if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
-                                       !strequal(driver->dependentfiles[i], driver->datafile) &&
-                                       !strequal(driver->dependentfiles[i], driver->configfile) &&
-                                       !strequal(driver->dependentfiles[i], driver->helpfile)) {
+                               !strequal(driver->dependentfiles[i], driver->datafile) &&
+                               !strequal(driver->dependentfiles[i], driver->configfile) &&
+                               !strequal(driver->dependentfiles[i], driver->helpfile)) {
                                int j;
                                for (j=0; j < i; j++) {
                                        if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
@@ -794,16 +1238,19 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
                                        }
                                }
 
-                               slprintf(old_name, sizeof(old_name), "%s\\%s", architecture, driver->dependentfiles[i]);        
-                               slprintf(new_name, sizeof(new_name), "%s\\%s", new_dir, driver->dependentfiles[i]);     
-                               if ((outsize = rename_internals(conn, inbuf, outbuf, old_name, new_name, True)) != 0) {
-                                       DEBUG(0,("move_driver_to_download_area: Unable to rename %s to %s\n",
-                                               old_name, new_name ));
-                                       close_cnum(conn, user->vuid);
-                                       pop_sec_ctx();
-                                       *perr = (uint32)SVAL(outbuf,smb_err);
-                                       return False;
+                               slprintf(new_name, sizeof(new_name), "%s/%s", architecture, driver->dependentfiles[i]); 
+                               slprintf(old_name, sizeof(old_name), "%s/%s", new_dir, driver->dependentfiles[i]);      
+                               if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
+                                       if ((outsize = rename_internals(conn, inbuf, outbuf, new_name, old_name, True)) != 0) {
+                                               DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
+                                                               new_name, old_name));
+                                               *perr = (uint32)SVAL(outbuf,smb_err);
+                                               unlink_internals(conn, inbuf, outbuf, 0, new_name);
+                                               ver = -1;
+                                       }
                                }
+                               else
+                                       unlink_internals(conn, inbuf, outbuf, 0, new_name);
                        }
                NextDriver: ;
                }
@@ -812,7 +1259,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        close_cnum(conn, user->vuid);
        pop_sec_ctx();
 
-       return True;
+       return ver == -1 ? False : True;
 }
 
 /****************************************************************************
@@ -866,7 +1313,7 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
 
  again:
        len = 0;
-       len += tdb_pack(buf+len, buflen-len, "dffffffff", 
+       len += tdb_pack(buf+len, buflen-len, "dffffffff",
                        driver->cversion,
                        driver->name,
                        driver->environment,
@@ -879,7 +1326,7 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
 
        if (driver->dependentfiles) {
                for (i=0; *driver->dependentfiles[i]; i++) {
-                       len += tdb_pack(buf+len, buflen-len, "f", 
+                       len += tdb_pack(buf+len, buflen-len, "f",
                                        driver->dependentfiles[i]);
                }
        }
@@ -982,7 +1429,7 @@ static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
 #else
        if (!dbuf.dptr) return 5;
 #endif
-       len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff", 
+       len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
                          &driver.cversion,
                          driver.name,
                          driver.environment,
@@ -1000,7 +1447,7 @@ static uint32 get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
                if (driver.dependentfiles == NULL)
                        break;
 
-               len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f", 
+               len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
                                  &driver.dependentfiles[i]);
                i++;
        }
@@ -1094,7 +1541,7 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32
        
        switch (level)
        {
-               case 3: 
+               case 3:
                {
                        if (driver.info_3 == NULL)
                                success=5;
@@ -1113,7 +1560,7 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32
                                
                                for (i=0; info3->dependentfiles &&
                                          *info3->dependentfiles[i]; i++) {
-                                       DEBUGADD(106,("dependentfile:[%s]\n", 
+                                       DEBUGADD(106,("dependentfile:[%s]\n",
                                                      info3->dependentfiles[i]));
                                }
                                success=0;
@@ -1199,8 +1646,8 @@ static int pack_specifics(NT_PRINTER_PARAM *param, char *buf, int buflen)
        while (param != NULL) {
                len += tdb_pack(buf+len, buflen-len, "pfdB",
                                param,
-                               param->value, 
-                               param->type, 
+                               param->value,
+                               param->type,
                                param->data_len,
                                param->data);
                param=param->next;      
@@ -1240,7 +1687,7 @@ static uint32 update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
        int buflen, len, ret;
        TDB_DATA kbuf, dbuf;
        
-       /* 
+       /*
         * in addprinter: no servername and the printer is the name
         * in setprinter: servername is \\server
         *                and printer is \\server\\printer
@@ -1319,7 +1766,7 @@ static uint32 update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
 
        safe_free(buf);
 
-       DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n", 
+       DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
                 info->sharename, info->drivername, info->portname, len));
 
        return ret;
@@ -1363,7 +1810,7 @@ BOOL unlink_specific_param_if_exist(NT_PRINTER_INFO_LEVEL_2 *info_2, NT_PRINTER_
        
        if (current==NULL) return (False);
        
-       if ( !strcmp(current->value, param->value) && 
+       if ( !strcmp(current->value, param->value) &&
            (strlen(current->value)==strlen(param->value)) ) {
                DEBUG(109,("deleting first value\n"));
                info_2->specific=current->next;
@@ -1441,8 +1888,8 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
        nt_devmode->driverversion    = 0x0400;
        nt_devmode->size             = 0x00DC;
        nt_devmode->driverextra      = 0x0000;
-       nt_devmode->fields           = FORMNAME | TTOPTION | PRINTQUALITY | 
-                                      DEFAULTSOURCE | COPIES | SCALE | 
+       nt_devmode->fields           = FORMNAME | TTOPTION | PRINTQUALITY |
+                                      DEFAULTSOURCE | COPIES | SCALE |
                                       PAPERSIZE | ORIENTATION;
        nt_devmode->orientation      = 1;
        nt_devmode->papersize        = PAPER_LETTER;
@@ -1588,7 +2035,7 @@ static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
                          &devmode.ttoption,
                          &devmode.collate,
                          &devmode.logpixels,
-                         
+                       
                          &devmode.fields,
                          &devmode.bitsperpel,
                          &devmode.pelswidth,
@@ -1636,8 +2083,8 @@ static int unpack_specifics(NT_PRINTER_PARAM **list, char *buf, int buflen)
                if (!p) break;
 
                len += tdb_unpack(buf+len, buflen-len, "fdB",
-                                 param.value, 
-                                 &param.type, 
+                                 param.value,
+                                 &param.type,
                                  &param.data_len,
                                  &param.data);
                param.next = *list;
@@ -1664,13 +2111,17 @@ static uint32 get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
        snum = lp_servicenumber(sharename);
 
        slprintf(info.servername, sizeof(info.servername), "\\\\%s", global_myname);
+       slprintf(info.printername, sizeof(info.printername), "\\\\%s\\%s", 
+                global_myname, sharename);
        fstrcpy(info.sharename, sharename);
        fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
        fstrcpy(info.drivername, lp_printerdriver(snum));
-       if (*info.drivername == '\0')
-               fstrcpy(info.drivername, "NO DRIVER AVAILABLE");
 
-       slprintf(info.printername, sizeof(info.printername), "\\\\%s\\%s", global_myname, sharename);
+       if (!*info.drivername)
+               fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
+
+       DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername));
+
        pstrcpy(info.comment, "");
        fstrcpy(info.printprocessor, "winprint");
        fstrcpy(info.datatype, "RAW");
@@ -1790,7 +2241,7 @@ static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        
        switch (level)
        {
-               case 2: 
+               case 2:
                {
                        if (printer.info_2 == NULL)
                                success=5;
@@ -1899,7 +2350,7 @@ uint32 add_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
        
        switch (level)
        {
-               case 2: 
+               case 2:
                {
                        /*
                         * Update the changestamp.
@@ -1937,7 +2388,7 @@ uint32 get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring s
 
        switch (level)
        {
-               case 2: 
+               case 2:
                {
                        if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
                                DEBUG(0,("get_a_printer: malloc fail.\n"));
@@ -1979,7 +2430,7 @@ uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
        
        switch (level)
        {
-               case 2: 
+               case 2:
                {
                        if (printer->info_2 != NULL)
                        {
@@ -2012,13 +2463,13 @@ uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
        
        switch (level)
        {
-               case 3: 
+               case 3:
                {
                        success=add_a_printer_driver_3(driver.info_3);
                        break;
                }
 
-               case 6: 
+               case 6:
                {
                        success=add_a_printer_driver_6(driver.info_6);
                        break;
@@ -2032,14 +2483,14 @@ uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
 }
 /****************************************************************************
 ****************************************************************************/
-uint32 get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level, 
+uint32 get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
                             fstring printername, fstring architecture, uint32 version)
 {
        uint32 success;
        
        switch (level)
        {
-               case 3: 
+               case 3:
                {
                        success=get_a_printer_driver_3(&driver->info_3, printername, architecture, version);
                        break;
@@ -2062,7 +2513,7 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
        
        switch (level)
        {
-               case 3: 
+               case 3:
                {
                        NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
                        if (driver.info_3 != NULL)
@@ -2079,7 +2530,7 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
                        }
                        break;
                }
-               case 6: 
+               case 6:
                {
                        NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
                        if (driver.info_6 != NULL)
@@ -2137,7 +2588,7 @@ BOOL get_specific_param_by_index(NT_PRINTER_INFO_LEVEL printer, uint32 level, ui
 
 /****************************************************************************
 ****************************************************************************/
-BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level, 
+BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
                         fstring value, uint8 **data, uint32 *type, uint32 *len)
 {
        /* right now that's enough ! */ 
@@ -2150,9 +2601,9 @@ BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
        while (param != NULL)
        {
 #if 1 /* JRA - I think this should be case insensitive.... */
-               if ( strequal(value, param->value) 
+               if ( strequal(value, param->value)
 #else
-               if ( !strcmp(value, param->value) 
+               if ( !strcmp(value, param->value)
 #endif
                    && strlen(value)==strlen(param->value))
                        break;
@@ -2185,22 +2636,78 @@ BOOL get_specific_param(NT_PRINTER_INFO_LEVEL printer, uint32 level,
 
 uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
 {
+       SEC_DESC_BUF *new_secdesc_ctr = NULL;
+       SEC_DESC_BUF *old_secdesc_ctr = NULL;
        prs_struct ps;
        TALLOC_CTX *mem_ctx = NULL;
        fstring key;
        uint32 status;
 
        mem_ctx = talloc_init();
-       if (mem_ctx == NULL) return False;
+       if (mem_ctx == NULL)
+               return False;
+
+        /* The old owner and group sids of the security descriptor are not
+          present when new ACEs are added or removed by changing printer
+          permissions through NT.  If they are NULL in the new security
+          descriptor then copy them over from the old one. */
+
+       if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
+               DOM_SID *owner_sid, *group_sid;
+               SEC_ACL *dacl, *sacl;
+               SEC_DESC *psd = NULL;
+               size_t size;
+
+               nt_printing_getsec(printername, &old_secdesc_ctr);
+
+               /* Pick out correct owner and group sids */
+
+               owner_sid = secdesc_ctr->sec->owner_sid ?
+                       secdesc_ctr->sec->owner_sid :
+                       old_secdesc_ctr->sec->owner_sid;
+
+               group_sid = secdesc_ctr->sec->grp_sid ?
+                       secdesc_ctr->sec->grp_sid :
+                       old_secdesc_ctr->sec->grp_sid;
+
+               dacl = secdesc_ctr->sec->dacl ?
+                       secdesc_ctr->sec->dacl :
+                       old_secdesc_ctr->sec->dacl;
+
+               sacl = secdesc_ctr->sec->sacl ?
+                       secdesc_ctr->sec->sacl :
+                       old_secdesc_ctr->sec->sacl;
+
+               /* Make a deep copy of the security descriptor */
+
+               psd = make_sec_desc(secdesc_ctr->sec->revision,
+                                   secdesc_ctr->sec->type,
+                                   owner_sid, group_sid,
+                                   sacl,
+                                   dacl,
+                                   &size);
+
+               new_secdesc_ctr = make_sec_desc_buf(size, psd);
+
+               /* Free up memory */
+
+               free_sec_desc(&psd);
+               free_sec_desc_buf(&old_secdesc_ctr);
+       }
+
+       if (!new_secdesc_ctr) {
+               new_secdesc_ctr = secdesc_ctr;
+       }
 
        /* Store the security descriptor in a tdb */
 
-       prs_init(&ps, (uint32)sec_desc_size(secdesc_ctr->sec) + 
+       prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
                 sizeof(SEC_DESC_BUF), 4, mem_ctx, MARSHALL);
 
-       if (!sec_io_desc_buf("nt_printing_setsec", &secdesc_ctr, &ps, 1)) {
+       if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
+                            &ps, 1)) {
                status = ERROR_INVALID_FUNCTION;
-               goto done;
+               goto out;
        }
 
        slprintf(key, sizeof(key), "SECDESC/%s", printername);
@@ -2214,11 +2721,16 @@ uint32 nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
 
        /* Free mallocated memory */
 
done:
-       prs_mem_free(&ps);
out:
+       free_sec_desc_buf(&old_secdesc_ctr);
 
-       if (mem_ctx) talloc_destroy(mem_ctx);
+       if (new_secdesc_ctr != secdesc_ctr) {
+               free_sec_desc_buf(&new_secdesc_ctr);
+       }
 
+       prs_mem_free(&ps);
+       if (mem_ctx)
+               talloc_destroy(mem_ctx);
        return status;
 }
 
@@ -2275,8 +2787,8 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
 #define NT4_ACL_REVISION 0x2
 
        if ((psa = make_sec_acl(NT4_ACL_REVISION, 2, ace)) != NULL) {
-               psd = make_sec_desc(SEC_DESC_REVISION, 
-                                   SEC_DESC_SELF_RELATIVE | 
+               psd = make_sec_desc(SEC_DESC_REVISION,
+                                   SEC_DESC_SELF_RELATIVE |
                                    SEC_DESC_DACL_PRESENT,
                                    &owner_sid, NULL,
                                    NULL, psa, &sd_size);
@@ -2290,7 +2802,7 @@ static SEC_DESC_BUF *construct_default_printer_sdb(void)
 
        sdb = make_sec_desc_buf(sd_size, psd);
 
-       DEBUG(4,("construct_default_printer_sdb: size = %u.\n", 
+       DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
                 (unsigned int)sd_size));
 
        free_sec_desc(&psd);
@@ -2392,7 +2904,7 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr)
        Why ? Simply because it's easier and it makes sense !
        
        Now explanation: You have 3 printers behind your samba server,
-       2 of them are the same make and model (laser A and B). But laser B 
+       2 of them are the same make and model (laser A and B). But laser B
        has an 3000 sheet feeder and laser A doesn't such an option.
        Your third printer is an old dot-matrix model for the accounting :-).
        
@@ -2407,7 +2919,7 @@ BOOL nt_printing_getsec(char *printername, SEC_DESC_BUF **secdesc_ctr)
                NTdriver_printer model X
                NTdriver_printer model Y
 
-jfm: I should use this comment for the text file to explain 
+jfm: I should use this comment for the text file to explain
        same thing for the forms BTW.
        Je devrais mettre mes commentaires en francais, ca serait mieux :-)
 
@@ -2422,7 +2934,7 @@ jfm: I should use this comment for the text file to explain
        print_queue_pause, print_queue_resume, update_printer_sec,
        update_printer, spoolss_addprinterex_level_2,
        _spoolss_setprinterdata
-        
+
    PRINTER_ACCESS_USE:
        print_job_start
 
@@ -2482,7 +2994,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
                required_access = PRINTER_ACE_PRINT;
                break;
        case PRINTER_ACCESS_ADMINISTER:
-               required_access = PRINTER_ACE_MANAGE_DOCUMENTS | 
+               required_access = PRINTER_ACE_MANAGE_DOCUMENTS |
                        PRINTER_ACE_PRINT;
                break;
        case JOB_ACCESS_ADMINISTER:
@@ -2500,7 +3012,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
           values, i.e PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT.
           This would cause the access check to simply fall out when we
           check against any subset of these bits.  To get things to work,
-          change every ACE mask of PRINTER_ACE_FULL_CONTROL to 
+          change every ACE mask of PRINTER_ACE_FULL_CONTROL to
           PRINTER_ACE_MANAGE_DOCUMENTS | PRINTER_ACE_PRINT before
           performing the access check.  I'm sure there is a better way to
           do this! */
@@ -2511,13 +3023,13 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
                        if (secdesc->sec->dacl->ace[i].info.mask ==
                            PRINTER_ACE_FULL_CONTROL) {
                                secdesc->sec->dacl->ace[i].info.mask =
-                                       PRINTER_ACE_MANAGE_DOCUMENTS | 
+                                       PRINTER_ACE_MANAGE_DOCUMENTS |
                                        PRINTER_ACE_PRINT;
                        }
                }
        }
 
-       if ((result = se_access_check(secdesc->sec, user, required_access, 
+       if ((result = se_access_check(secdesc->sec, user, required_access,
                                      &access_granted, &status))) {
                goto done;
        }
@@ -2547,7 +3059,7 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
                break;
        }       
 
-       result = se_access_check(secdesc->sec, user, required_access, 
+       result = se_access_check(secdesc->sec, user, required_access,
                                 &access_granted, &status);
 
        /* Check access */
index 95bcf2a2762471acdc499460137394a74ab4a712..8b17e8d5f2bb5ab899de100b19f218cbf5505868 100644 (file)
@@ -305,15 +305,17 @@ static void print_queue_update(int snum)
        print_status_struct status;
        struct printjob *pjob;
        struct traverse_struct tstruct;
-       fstring keystr;
+       fstring keystr, printer_name;
        TDB_DATA data, key;
  
+       fstrcpy(printer_name, lp_servicename(snum));
+       
        /*
         * Update the cache time FIRST ! Stops others doing this
         * if the lpq takes a long time.
         */
 
-       slprintf(keystr, sizeof(keystr), "CACHE/%s", lp_servicename(snum));
+       slprintf(keystr, sizeof(keystr), "CACHE/%s", printer_name);
        tdb_store_int(tdb, keystr, (int)time(NULL));
 
        slprintf(tmp_file, sizeof(tmp_file), "%s/smblpq.%d", path, local_pid);
@@ -343,11 +345,11 @@ static void print_queue_update(int snum)
        file_lines_free(qlines);
 
        DEBUG(3, ("%d job%s in queue for %s\n", qcount, (qcount != 1) ?
-               "s" : "", lp_servicename(snum)));
+               "s" : "", printer_name));
 
        /* Lock the queue for the database update */
 
-       slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", lp_servicename(snum));
+       slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", printer_name);
        tdb_lock_bystring(tdb, keystr);
 
        /*
@@ -397,7 +399,7 @@ static void print_queue_update(int snum)
 
        /* store the queue status structure */
        status.qcount = qcount;
-       slprintf(keystr, sizeof(keystr), "STATUS/%s", lp_servicename(snum));
+       slprintf(keystr, sizeof(keystr), "STATUS/%s", printer_name);
        data.dptr = (void *)&status;
        data.dsize = sizeof(status);
        key.dptr = keystr;
@@ -406,7 +408,7 @@ static void print_queue_update(int snum)
 
        /* Unlock for database update */
 
-       slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", lp_servicename(snum));
+       slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", printer_name);
        tdb_unlock_bystring(tdb, keystr);
 
        /*
@@ -414,7 +416,7 @@ static void print_queue_update(int snum)
         * as little as possible...
         */
 
-       slprintf(keystr, sizeof(keystr), "CACHE/%s", lp_servicename(snum));
+       slprintf(keystr, sizeof(keystr), "CACHE/%s", printer_name);
        tdb_store_int(tdb, keystr, (int)time(NULL));
 }
 
@@ -1032,7 +1034,8 @@ int print_queue_status(int snum,
                return 0;
 
        /* Allocate the queue size. */
-       if (( tstruct.queue = (print_queue_struct *)malloc(sizeof(print_queue_struct)*tsc.count))
+       if ((tstruct.queue = (print_queue_struct *)
+            malloc(sizeof(print_queue_struct)*tsc.count))
                                == NULL)
                return 0;
 
index cd2b4c4e3db9173d2d2440c0bcfb6f522c557045..6a3b72ffa71d1a5f5d7aaa517fb8a8df681601b7 100644 (file)
@@ -4891,7 +4891,7 @@ uint32 _spoolss_addprinterdriver(pipes_struct *p, const UNISTR2 *server_name,
        convert_printer_driver_info(info, &driver, level);
 
        DEBUG(5,("Cleaning driver's information\n"));
-       if ((err = clean_up_driver_struct(driver, level)) != NT_STATUS_NO_PROBLEMO )
+       if ((err = clean_up_driver_struct(driver, level, &user)) != NT_STATUS_NO_PROBLEMO )
                goto done;
 
        DEBUG(5,("Moving driver to final destination\n"));
index fa8aa112776ad71dcd18c0498316a402cee33903..0b3b5bbe276d8fa73d8dec8acc3ced40541a966b 100644 (file)
@@ -1882,14 +1882,13 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
 }
 
 /****************************************************************************
- Reply to a unlink
+ The guts of the unlink command, split out so it may be called by the NT SMB
+ code.
 ****************************************************************************/
 
-int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
+                                        int dirtype, char *name)
 {
-  int outsize = 0;
-  pstring name;
-  int dirtype;
   pstring directory;
   pstring mask;
   char *p;
@@ -1900,18 +1899,9 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   BOOL bad_path = False;
   BOOL rc = True;
   SMB_STRUCT_STAT sbuf;
-  START_PROFILE(SMBunlink);
 
   *directory = *mask = 0;
 
-  dirtype = SVAL(inbuf,smb_vwv0);
-  
-  pstrcpy(name,smb_buf(inbuf) + 1);
-   
-  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
-
-  DEBUG(3,("reply_unlink : %s\n",name));
-   
   rc = unix_convert(name,conn,0,&bad_path,&sbuf);
 
   p = strrchr(name,'/');
@@ -1975,29 +1965,58 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
            slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
            if (!can_delete(fname,conn,dirtype)) continue;
            if (!vfs_unlink(conn,fname)) count++;
-           DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
+           DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
          }
        CloseDir(dirptr);
       }
   }
   
   if (count == 0) {
-    if (exists) {
-      END_PROFILE(SMBunlink);
+    if (exists)
       return(ERROR(ERRDOS,error));
-    } else
-    {
-      if((errno == ENOENT) && bad_path)
-      {
+    else {
+      if((errno == ENOENT) && bad_path) {
         unix_ERR_class = ERRDOS;
         unix_ERR_code = ERRbadpath;
       }
-      END_PROFILE(SMBunlink);
       return(UNIXERROR(ERRDOS,error));
     }
   }
   
+  return 0;
+}
+
+/****************************************************************************
+ Reply to a unlink
+****************************************************************************/
+
+int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+{
+  int outsize = 0;
+  pstring name;
+  int dirtype;
+  START_PROFILE(SMBunlink);
+
+  dirtype = SVAL(inbuf,smb_vwv0);
+
+  pstrcpy(name,smb_buf(inbuf) + 1);
+
+  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
+  DEBUG(3,("reply_unlink : %s\n",name));
+
+  outsize = unlink_internals(conn, inbuf, outbuf, dirtype, name);
+  if(outsize == 0) {
+
+    /*
+     * Win2k needs a changenotify request response before it will
+     * update after a rename..
+     */
+
+    process_pending_change_notify_queue((time_t)0);
+
   outsize = set_message(outbuf,0,0,True);
+  }
   
   END_PROFILE(SMBunlink);
   return(outsize);
@@ -3589,7 +3608,6 @@ static BOOL can_rename(char *fname,connection_struct *conn)
 
   if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False);
   if (!check_file_sharing(conn,fname,True)) return(False);
-
   return(True);
 }
 
@@ -3718,6 +3736,7 @@ int rename_internals(connection_struct *conn,
                         * file with the same name so don't check for
                         * vfs_file_exist().
                         */
+
                        if(resolve_wildcards(directory,newname) &&
                           can_rename(directory,conn) &&
                           !conn->vfs_ops.rename(conn,zdirectory,
index ef446ed759a262937de8cbf795c01cbea3b5f243..f3adcfce8fb3ef9dc72489cf19bc375e67545d2a 100644 (file)
@@ -221,7 +221,7 @@ BOOL initialise_groups(char *user, uid_t uid, gid_t gid)
 
        /* Call initgroups() to get user groups */
 
-       if (initgroups(user,gid) == -1) {
+       if (winbind_initgroups(user,gid) == -1) {
                DEBUG(0,("Unable to initgroups. Error was %s\n", strerror(errno) ));
                if (getuid() == 0) {
                        if (gid < 0 || gid > 32767 || uid < 0 || uid > 32767) {
index d82edcbfae097a220173ed208ea7016c64c618fd..008765cde1363c0c0090eba0c27bd1bc6bfd82c6 100644 (file)
@@ -243,8 +243,8 @@ BOOL unbecome_authenticated_pipe_user(pipes_struct *p)
        return pop_sec_ctx();
 }
 
-
 /* Temporarily become a root user.  Must match with unbecome_root(). */
+
 void become_root(void)
 {
        push_sec_ctx();
@@ -267,25 +267,49 @@ BOOL lookup_name(char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
 {
        extern pstring global_myname;
        fstring sid;
+       char *sep = lp_winbind_separator();
 
        if (!winbind_lookup_name(name, psid, name_type)) {
                BOOL ret;
 
-               DEBUG(10,("lookup_name: winbind lookup for %s failed - trying local\n", name ));
+               DEBUG(10, ("lookup_name: winbind lookup for %s failed - trying local\n", name));
+
+               /* If we are looking up a domain user, make sure it is
+                  for the local machine only */
+
+               if (strchr(name, sep[0]) || strchr(name, '\\')) {
+                       fstring domain, username;
+
+                       split_domain_name(name, domain, username);
+
+                       if (strcasecmp(global_myname, domain) != 0) {
+                               DEBUG(5, ("domain %s is not local\n", domain));
+                               return False;
+                       }
+
+                       ret = local_lookup_name(domain, username, psid, 
+                                               name_type);
+               } else {
+
+                       ret = local_lookup_name(global_myname, name, psid, 
+                                               name_type);
+               }
+
+               if (ret) {
+                       DEBUG(10,
+                             ("lookup_name: (local) %s -> SID %s (type %u)\n",
+                              name, sid_to_string(sid,psid),
+                              (unsigned int)*name_type ));
+               } else {
+                       DEBUG(10,("lookup name: (local) %s failed.\n", name));
+               }
 
-               ret = local_lookup_name(global_myname, name, psid, name_type);
-               if (ret)
-                       DEBUG(10,("lookup_name : (local) %s -> SID %s (type %u)\n",
-                               name, sid_to_string(sid,psid),
-                               (unsigned int)*name_type ));
-               else
-                       DEBUG(10,("lookup name : (local) %s failed.\n",
-                                       name ));
                return ret;
        }
 
-       DEBUG(10,("lookup_name (winbindd): %s -> SID %s (type %u)\n",
-               name, sid_to_string(sid,psid), (unsigned int)*name_type ));
+               DEBUG(10,("lookup_name (winbindd): %s -> SID %s (type %u)\n",
+                         name, sid_to_string(sid, psid), 
+                         (unsigned int)*name_type));
        return True;
 }
 
@@ -300,7 +324,7 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE
                return False;
 
        /* Check if this is our own sid.  This should perhaps be done by
-               winbind?  For the moment handle it here. */
+          winbind?  For the moment handle it here. */
 
        if (sid->num_auths == 5) {
                DOM_SID tmp_sid;
index 99c8e26fa85a40f379af6da2554248f9e664762f..77b42361ed280b4060bc1cb772dbae117d55499c 100644 (file)
@@ -1,19 +1,19 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    Version 1.9.
    VFS initialisation and support functions
    Copyright (C) Tim Potter 1999
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -36,7 +36,7 @@ struct vfs_syminfo {
 
 struct vfs_ops default_vfs_ops = {
 
-       /* Disk operations */        
+       /* Disk operations */
 
        vfswrap_dummy_connect,
        vfswrap_dummy_disconnect,
@@ -112,7 +112,7 @@ BOOL vfs_init_custom(connection_struct *conn)
     init_fptr = (struct vfs_ops *(*)(int *))dlsym(conn->dl_handle, "vfs_init");
 
     if (init_fptr == NULL) {
-               DEBUG(0, ("No vfs_init() symbol found in %s\n", 
+               DEBUG(0, ("No vfs_init() symbol found in %s\n",
                  lp_vfsobj(SNUM(conn))));
                return False;
     }
@@ -132,10 +132,10 @@ BOOL vfs_init_custom(connection_struct *conn)
 
     /* Fill in unused operations with default (disk based) ones.
        There's probably a neater way to do this then a whole bunch of
-       if statements. */ 
+       if statements. */
 
     memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
-    
+
     if (conn->vfs_ops.connect == NULL) {
        conn->vfs_ops.connect = default_vfs_ops.connect;
     }
@@ -179,47 +179,47 @@ BOOL vfs_init_custom(connection_struct *conn)
     if (conn->vfs_ops.read == NULL) {
        conn->vfs_ops.read = default_vfs_ops.read;
     }
-    
+
     if (conn->vfs_ops.write == NULL) {
        conn->vfs_ops.write = default_vfs_ops.write;
     }
-    
+
     if (conn->vfs_ops.lseek == NULL) {
        conn->vfs_ops.lseek = default_vfs_ops.lseek;
     }
-    
+
     if (conn->vfs_ops.rename == NULL) {
        conn->vfs_ops.rename = default_vfs_ops.rename;
     }
-    
+
     if (conn->vfs_ops.fsync == NULL) {
        conn->vfs_ops.fsync = default_vfs_ops.fsync;
     }
-    
+
     if (conn->vfs_ops.stat == NULL) {
        conn->vfs_ops.stat = default_vfs_ops.stat;
     }
-    
+
     if (conn->vfs_ops.fstat == NULL) {
        conn->vfs_ops.fstat = default_vfs_ops.fstat;
     }
-    
+
     if (conn->vfs_ops.lstat == NULL) {
        conn->vfs_ops.lstat = default_vfs_ops.lstat;
     }
-    
+
     if (conn->vfs_ops.unlink == NULL) {
        conn->vfs_ops.unlink = default_vfs_ops.unlink;
     }
-    
+
     if (conn->vfs_ops.chmod == NULL) {
        conn->vfs_ops.chmod = default_vfs_ops.chmod;
     }
-    
+
     if (conn->vfs_ops.chown == NULL) {
        conn->vfs_ops.chown = default_vfs_ops.chown;
     }
-    
+
     if (conn->vfs_ops.chdir == NULL) {
        conn->vfs_ops.chdir = default_vfs_ops.chdir;
     }
@@ -227,15 +227,15 @@ BOOL vfs_init_custom(connection_struct *conn)
     if (conn->vfs_ops.getwd == NULL) {
        conn->vfs_ops.getwd = default_vfs_ops.getwd;
     }
-    
+
     if (conn->vfs_ops.utime == NULL) {
        conn->vfs_ops.utime = default_vfs_ops.utime;
     }
-    
+
     if (conn->vfs_ops.ftruncate == NULL) {
        conn->vfs_ops.ftruncate = default_vfs_ops.ftruncate;
     }
-    
+
     if (conn->vfs_ops.lock == NULL) {
        conn->vfs_ops.lock = default_vfs_ops.lock;
     }
@@ -255,7 +255,7 @@ BOOL vfs_init_custom(connection_struct *conn)
     if (conn->vfs_ops.set_nt_acl == NULL) {
        conn->vfs_ops.set_nt_acl = default_vfs_ops.set_nt_acl;
     }
-    
+
     return True;
 }
 #endif
@@ -272,7 +272,7 @@ BOOL vfs_directory_exist(connection_struct *conn, char *dname, SMB_STRUCT_STAT *
        if (!st)
                st = &st2;
 
-       if (vfs_stat(conn,dname,st) != 0) 
+       if (vfs_stat(conn,dname,st) != 0)
                return(False);
 
        ret = S_ISDIR(st->st_mode);
@@ -294,7 +294,7 @@ int vfs_mkdir(connection_struct *conn, char *fname, mode_t mode)
 
        pstrcpy(name,dos_to_unix(fname,False)); /* paranoia copy */
        if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
-               /* 
+               /*
                 * Check if high bits should have been set,
                 * then (if bits are missing): add them.
                 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
@@ -331,13 +331,38 @@ BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
                sbuf = &st;
 
        ZERO_STRUCTP(sbuf);
-       if (vfs_stat(conn,fname,sbuf) != 0) 
+
+       if (vfs_stat(conn,fname,sbuf) != 0)
                return(False);
 
        return(S_ISREG(sbuf->st_mode));
 }
 
+/****************************************************************************
+ Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
+****************************************************************************/
+
+ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
+{
+       size_t total=0;
+
+       while (total < byte_count)
+       {
+               ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
+                                                                                         byte_count - total);
+
+               if (ret == 0) return total;
+               if (ret == -1) {
+                       if (errno == EINTR)
+                               continue;
+                       else
+                               return -1;
+               }
+               total += ret;
+       }
+       return (ssize_t)total;
+}
+
 /****************************************************************************
  Write data to a fd on the vfs.
 ****************************************************************************/
@@ -363,11 +388,11 @@ ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N)
  Transfer some data between two file_struct's.
 ****************************************************************************/
 
-SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp, 
+SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
                            int out_fd, files_struct *out_fsp,
                            SMB_OFF_T n, char *header, int headlen, int align)
 {
-  static char *buf=NULL;  
+  static char *buf=NULL;
   static int size=0;
   char *buf1,*abuf;
   SMB_OFF_T total = 0;
@@ -425,7 +450,7 @@ SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
     }
 
     if (s > ret) {
-      ret += in_fsp ? 
+      ret += in_fsp ?
          in_fsp->conn->vfs_ops.read(in_fsp,in_fsp->fd,buf1+ret,s-ret) : read(in_fd,buf1+ret,s-ret);
     }
 
@@ -459,7 +484,7 @@ char *vfs_readdirname(connection_struct *conn, void *p)
 
        if (!p)
                return(NULL);
-  
+
        ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
        if (!ptr)
                return(NULL);
@@ -497,7 +522,7 @@ static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
 {
     struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
     int i;
-    
+
     /* Create new vfs option */
 
     new_option = (struct vfs_options *)malloc(sizeof(*new_option));
@@ -508,7 +533,7 @@ static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
     ZERO_STRUCTP(new_option);
 
     /* Get name and value */
-    
+
     new_option->name = strtok(pszParmValue, "=");
 
     if (new_option->name == NULL) {
@@ -714,7 +739,7 @@ char *vfs_GetWd(connection_struct *conn, char *path)
 }
 
 /*******************************************************************
- Reduce a file name, removing .. elements and checking that 
+ Reduce a file name, removing .. elements and checking that
  it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
  on the system that has the referenced file system.
  Widelinks are allowed if widelinks is true.
@@ -749,7 +774,7 @@ BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
 
     return(True);
   }
-  
+
   DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
 
   /* remove any double slashes */
@@ -810,7 +835,7 @@ BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
   }
 
   {
-    size_t l = strlen(dir2);    
+    size_t l = strlen(dir2);
     if (dir2[l-1] == '/')
       l--;