Index: samba-3.0.24/source/auth/auth_compat.c
===================================================================
--- samba-3.0.24.orig/source/auth/auth_compat.c	2007-02-08 08:01:57.000000000 -0600
+++ samba-3.0.24/source/auth/auth_compat.c	2007-02-08 08:02:08.000000000 -0600
@@ -92,18 +92,25 @@
 check if a username/password pair is ok via the auth subsystem.
 return True if the password is correct, False otherwise
 ****************************************************************************/
+
 BOOL password_ok(char *smb_name, DATA_BLOB password_blob)
 {
 
 	DATA_BLOB null_password = data_blob(NULL, 0);
-	BOOL encrypted = (global_encrypted_passwords_negotiated && password_blob.length == 24);
+	BOOL encrypted = (global_encrypted_passwords_negotiated && (password_blob.length == 24 || password_blob.length > 46));
 	
 	if (encrypted) {
 		/* 
 		 * The password could be either NTLM or plain LM.  Try NTLM first, 
 		 * but fall-through as required.
-		 * NTLMv2 makes no sense here.
+		 * Vista sends NTLMv2 here - we need to try the client given workgroup.
 		 */
+		if (get_session_workgroup()) {
+			if (NT_STATUS_IS_OK(pass_check_smb(smb_name, get_session_workgroup(), null_password, password_blob, null_password, encrypted))) {
+				return True;
+			}
+		}
+
 		if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, encrypted))) {
 			return True;
 		}
@@ -119,5 +126,3 @@
 
 	return False;
 }
-
-
Index: samba-3.0.24/source/smbd/password.c
===================================================================
--- samba-3.0.24.orig/source/smbd/password.c	2007-02-08 08:01:42.000000000 -0600
+++ samba-3.0.24/source/smbd/password.c	2007-02-08 08:02:08.000000000 -0600
@@ -23,6 +23,8 @@
 /* users from session setup */
 static char *session_userlist = NULL;
 static int len_session_userlist = 0;
+/* workgroup from session setup. */
+static char *session_workgroup = NULL;
 
 /* this holds info on user ids that are already validated for this VC */
 static user_struct *validated_users;
@@ -406,6 +408,29 @@
 }
 
 /****************************************************************************
+ In security=share mode we need to store the client workgroup, as that's
+  what Vista uses for the NTLMv2 calculation.
+****************************************************************************/
+
+void add_session_workgroup(const char *workgroup)
+{
+	if (session_workgroup) {
+		SAFE_FREE(session_workgroup);
+	}
+	session_workgroup = smb_xstrdup(workgroup);
+}
+
+/****************************************************************************
+ In security=share mode we need to return the client workgroup, as that's
+  what Vista uses for the NTLMv2 calculation.
+****************************************************************************/
+
+const char *get_session_workgroup(void)
+{
+	return session_workgroup;
+}
+
+/****************************************************************************
  Check if a user is in a netgroup user list. If at first we don't succeed,
  try lower case.
 ****************************************************************************/
Index: samba-3.0.24/source/smbd/sesssetup.c
===================================================================
--- samba-3.0.24.orig/source/smbd/sesssetup.c	2007-02-08 08:01:38.000000000 -0600
+++ samba-3.0.24/source/smbd/sesssetup.c	2007-02-08 08:02:08.000000000 -0600
@@ -1035,6 +1035,7 @@
 
 		map_username(sub_user);
 		add_session_user(sub_user);
+		add_session_workgroup(domain);
 		/* Then force it to null for the benfit of the code below */
 		*user = 0;
 	}
Index: samba-3.0.24/source/rpc_server/srv_spoolss_nt.c
===================================================================
--- samba-3.0.24.orig/source/rpc_server/srv_spoolss_nt.c	2007-02-04 12:59:21.000000000 -0600
+++ samba-3.0.24/source/rpc_server/srv_spoolss_nt.c	2007-02-15 11:02:09.000000000 -0600
@@ -5848,6 +5848,12 @@
 		goto done;
 	}
 	
+	if (!secdesc_ctr) {
+		DEBUG(10,("update_printer_sec: secdesc_ctr is NULL !\n"));
+		result = WERR_INVALID_PARAM;
+		goto done;
+	}
+
 	/* Check the user has permissions to change the security
 	   descriptor.  By experimentation with two NT machines, the user
 	   requires Full Access to the printer to change security
@@ -9378,6 +9384,15 @@
 	
 	/* housekeeping information in the reply */
 	
+	/* Fix from Martin Zielinski <mz@seh.de> - ensure
+	 * the hand marshalled container size is a multiple
+	 * of 4 bytes for RPC alignment.
+	 */
+
+	if (needed % 4) {
+		needed += 4-(needed % 4);
+	}
+
 	r_u->needed 	= needed;
 	r_u->returned 	= num_entries;
 
Index: samba-3.0.24/source/printing/nt_printing.c
===================================================================
--- samba-3.0.24.orig/source/printing/nt_printing.c	2007-02-04 13:09:01.000000000 -0600
+++ samba-3.0.24/source/printing/nt_printing.c	2007-02-15 11:02:09.000000000 -0600
@@ -2984,11 +2984,15 @@
 	return True;
 }
 
+/*****************************************************************
+ ****************************************************************/
+
 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, 
 			       struct uuid guid)
 {
 	int i;
 	REGVAL_CTR *ctr=NULL;
+	UNISTR2 unistr_guid;
 
 	/* find the DsSpooler key */
 	if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
@@ -2996,8 +3000,18 @@
 	ctr = info2->data->keys[i].values;
 
 	regval_ctr_delvalue(ctr, "objectGUID");
-	regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY, 
-			    (char *) &guid, sizeof(struct uuid));	
+
+	/* We used to store this as a REG_BINARY but that causes
+	   Vista to whine */
+
+	ZERO_STRUCT( unistr_guid );	
+	init_unistr2( &unistr_guid, smb_uuid_string_static(guid),
+		      UNI_STR_TERMINATE );
+
+	regval_ctr_addvalue(ctr, "objectGUID", REG_SZ, 
+			    (char *)unistr_guid.buffer, 
+			    unistr_guid.uni_max_len*2);
+	
 }
 
 static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
@@ -3254,6 +3268,7 @@
 	REGISTRY_VALUE *guid_val;
 	WERROR win_rc;
 	int i;
+	BOOL ret = False;
 
 	win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
 
@@ -3267,12 +3282,36 @@
 		return False;
 	}
 
-	/* fetching printer guids really ought to be a separate function.. */
-	if (guid && regval_size(guid_val) == sizeof(struct uuid))
-		memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid));
+	/* fetching printer guids really ought to be a separate function. */
+
+	if ( guid ) {	
+		fstring guid_str;
+		
+		/* We used to store the guid as REG_BINARY, then swapped 
+		   to REG_SZ for Vista compatibility so check for both */
+
+		switch ( regval_type(guid_val) ){
+		case REG_SZ:		
+			rpcstr_pull( guid_str, regval_data_p(guid_val), 
+				     sizeof(guid_str)-1, -1, STR_TERMINATE );
+			ret = smb_string_to_uuid( guid_str, guid );
+			break;			
+		case REG_BINARY:
+			if ( regval_size(guid_val) != sizeof(struct uuid) ) {
+				ret = False;
+				break;
+			}
+			memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid));
+			break;
+		default:
+			DEBUG(0,("is_printer_published: GUID value stored as "
+				 "invaluid type (%d)\n", regval_type(guid_val) ));			
+			break;
+		}
+	}
 
 	free_a_printer(&printer, 2);
-	return True;
+	return ret;
 }
 #else
 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
@@ -3539,13 +3578,43 @@
 			break;
 		}
 		
-		/* add the new value */
+		DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
+
+		/* Vista doesn't like unknown REG_BINARY values in DsSpooler.  
+		   Thanks to Martin Zielinski for the hint. */
+
+		if ( type == REG_BINARY && 
+		     strequal( keyname, SPOOL_DSSPOOLER_KEY ) && 
+		     strequal( valuename, "objectGUID" ) ) 
+		{
+			struct uuid guid;
+			UNISTR2 unistr_guid;
+
+			ZERO_STRUCT( unistr_guid );
+			
+			/* convert the GUID to a UNICODE string */
+			
+			memcpy( &guid, data_p, sizeof(struct uuid) );
+			
+			init_unistr2( &unistr_guid, smb_uuid_string_static(guid), 
+				      UNI_STR_TERMINATE );
+			
+			regval_ctr_addvalue( printer_data->keys[key_index].values, 
+					     valuename, REG_SZ, 
+					     (const char *)unistr_guid.buffer, 
+					     unistr_guid.uni_str_len*2 );
+
+		} else {
+			/* add the value */
+
+			regval_ctr_addvalue( printer_data->keys[key_index].values, 
+					     valuename, type, (const char *)data_p, 
+					     size );
+		}
 		
-		regval_ctr_addvalue( printer_data->keys[key_index].values, valuename, type, (const char *)data_p, size );
 
 		SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
 
-		DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
 	}
 
 	return len;
Index: samba-3.0.24/source/rpc_server/srv_spoolss.c
===================================================================
--- samba-3.0.24.orig/source/rpc_server/srv_spoolss.c	2006-04-19 21:29:27.000000000 -0500
+++ samba-3.0.24/source/rpc_server/srv_spoolss.c	2007-02-15 11:02:09.000000000 -0600
@@ -1477,6 +1477,15 @@
 	ZERO_STRUCT(r_u);
 	
 	if(!spoolss_io_q_addprinterdriverex("", &q_u, data, 0)) {
+		if (q_u.level != 3 && q_u.level != 6) {
+			/* Clever hack from Martin Zielinski <mz@seh.de>
+			 * to allow downgrade from level 8 (Vista).
+			 */
+			DEBUG(3,("api_spoolss_addprinterdriverex: unknown SPOOL_Q_ADDPRINTERDRIVEREX level %u.\n",
+				(unsigned int)q_u.level ));
+			setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_INVALID_TAG));
+			return True;
+		}
 		DEBUG(0,("spoolss_io_q_addprinterdriverex: unable to unmarshall SPOOL_Q_ADDPRINTERDRIVEREX.\n"));
 		return False;
 	}
Index: samba-3.0.24/source/rpc_parse/parse_spoolss.c
===================================================================
--- samba-3.0.24.orig/source/rpc_parse/parse_spoolss.c	2007-02-15 11:02:19.000000000 -0600
+++ samba-3.0.24/source/rpc_parse/parse_spoolss.c	2007-02-15 11:02:25.000000000 -0600
@@ -3893,7 +3893,16 @@
 		}
 		case 3:
 		{
-			ptr_sec_desc = q_u->info.info_3->secdesc_ptr;
+			/* FIXME ! Our parsing here is wrong I think,
+			 * but for a level3 it makes no sense for
+			 * ptr_sec_desc to be NULL. JRA. Based on
+			 * a Vista sniff from Martin Zielinski <mz@seh.de>.
+			 */
+			if (UNMARSHALLING(ps)) {
+				ptr_sec_desc = 1;
+			} else {
+				ptr_sec_desc = q_u->info.info_3->secdesc_ptr;
+			}
 			break;
 		}
 	}
Index: samba-3.0.24/source/smbd/posix_acls.c
===================================================================
--- samba-3.0.24.orig/source/smbd/posix_acls.c	2007-02-08 08:11:29.000000000 -0600
+++ samba-3.0.24/source/smbd/posix_acls.c	2007-02-08 08:12:02.000000000 -0600
@@ -655,6 +655,7 @@
 	}
 	return 0;
 }
+
 /****************************************************************************
  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
 ****************************************************************************/
@@ -666,6 +667,27 @@
 }
 
 /****************************************************************************
+ Is the identity in two ACEs equal ? Check both SID and uid/gid.
+****************************************************************************/
+
+static BOOL identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
+{
+	if (sid_equal(&ace1->trustee, &ace2->trustee)) {
+		return True;
+	}
+	if (ace1->owner_type == ace2->owner_type) {
+		if (ace1->owner_type == UID_ACE &&
+				ace1->unix_ug.uid == ace2->unix_ug.uid) {
+			return True;
+		} else if (ace1->owner_type == GID_ACE &&
+				ace1->unix_ug.gid == ace2->unix_ug.gid) {
+			return True;
+		}
+	}
+	return False;
+}
+
+/****************************************************************************
  Merge aces with a common sid - if both are allow or deny, OR the permissions together and
  delete the second one. If the first is deny, mask the permissions off and delete the allow
  if the permissions become zero, delete the deny if the permissions are non zero.
@@ -692,7 +714,7 @@
 
 			curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
 
-			if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+			if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
 				(curr_ace->attr == curr_ace_outer->attr)) {
 
 				if( DEBUGLVL( 10 )) {
@@ -732,7 +754,7 @@
 			 * we've put on the ACL, we know the deny must be the first one.
 			 */
 
-			if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+			if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
 				(curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
 
 				if( DEBUGLVL( 10 )) {
Index: samba-3.0.24/source/include/smb.h
===================================================================
--- samba-3.0.24.orig/source/include/smb.h	2007-02-08 15:27:50.000000000 -0600
+++ samba-3.0.24/source/include/smb.h	2007-02-08 15:31:14.000000000 -0600
@@ -1436,6 +1436,7 @@
 #define FLAGS2_LONG_PATH_COMPONENTS    0x0001
 #define FLAGS2_EXTENDED_ATTRIBUTES     0x0002
 #define FLAGS2_SMB_SECURITY_SIGNATURES 0x0004
+#define FLAGS2_UNKNOWN_BIT4            0x0010
 #define FLAGS2_IS_LONG_NAME            0x0040
 #define FLAGS2_EXTENDED_SECURITY       0x0800 
 #define FLAGS2_DFS_PATHNAMES           0x1000
@@ -1499,7 +1500,8 @@
 
 /* Remote architectures we know about. */
 enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT,
-			RA_WIN2K, RA_WINXP, RA_WIN2K3, RA_SAMBA, RA_CIFSFS};
+			RA_WIN2K, RA_WINXP, RA_WIN2K3, RA_VISTA,
+			RA_SAMBA, RA_CIFSFS};
 
 /* case handling */
 enum case_handling {CASE_LOWER,CASE_UPPER};
Index: samba-3.0.24/source/smbd/negprot.c
===================================================================
--- samba-3.0.24.orig/source/smbd/negprot.c	2007-02-08 15:27:50.000000000 -0600
+++ samba-3.0.24/source/smbd/negprot.c	2007-02-08 15:42:10.000000000 -0600
@@ -263,6 +263,16 @@
 
 	global_encrypted_passwords_negotiated = lp_encrypted_passwords();
 
+	/* Check the flags field to see if this is Vista.
+	   WinXP sets it and Vista does not. But we have to 
+	   distinguish from NT which doesn't set it either. */
+
+	if ( (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY) &&
+		((SVAL(inbuf, smb_flg2) & FLAGS2_UNKNOWN_BIT4) == 0) ) 
+	{
+		set_remote_arch( RA_VISTA );		
+	}
+
 	/* do spnego in user level security if the client
 	   supports it and we can do encrypted passwords */
 	
@@ -393,6 +403,15 @@
 protocol [LANMAN2.1]
 protocol [NT LM 0.12]
 
+Vista:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+protocol [SMB 2.001]
+
 OS/2:
 protocol [PC NETWORK PROGRAM 1.0]
 protocol [XENIX CORE]
@@ -406,18 +425,19 @@
   *
   * This appears to be the matrix of which protocol is used by which
   * MS product.
-       Protocol                       WfWg    Win95   WinNT  Win2K  OS/2
-       PC NETWORK PROGRAM 1.0          1       1       1      1      1
+       Protocol                       WfWg    Win95   WinNT  Win2K  OS/2 Vista
+       PC NETWORK PROGRAM 1.0          1       1       1      1      1     1
        XENIX CORE                                      2             2
        MICROSOFT NETWORKS 3.0          2       2       
        DOS LM1.2X002                   3       3       
        MICROSOFT NETWORKS 1.03                         3
        DOS LANMAN2.1                   4       4       
-       LANMAN1.0                                       4      2      3
-       Windows for Workgroups 3.1a     5       5       5      3
-       LM1.2X002                                       6      4      4
-       LANMAN2.1                                       7      5      5
-       NT LM 0.12                              6       8      6
+       LANMAN1.0                                       4      2      3     2
+       Windows for Workgroups 3.1a     5       5       5      3            3
+       LM1.2X002                                       6      4      4     4
+       LANMAN2.1                                       7      5      5     5
+       NT LM 0.12                              6       8      6            6
+       SMB 2.001                                                           7
   *
   *  tim@fsg.com 09/29/95
   *  Win2K added by matty 17/7/99
@@ -430,6 +450,7 @@
 #define ARCH_OS2      0x14     /* Again OS/2 is like NT */
 #define ARCH_SAMBA    0x20
 #define ARCH_CIFSFS   0x40
+#define ARCH_VISTA    0x8C     /* Vista is like XP/2K */
  
 #define ARCH_ALL      0x7F
  
@@ -493,6 +514,8 @@
 			arch &= ( ARCH_WFWG | ARCH_WIN95 );
 		else if (strcsequal(p,"NT LM 0.12"))
 			arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS);
+		else if (strcsequal(p,"SMB 2.001"))
+			arch = ARCH_VISTA;		
 		else if (strcsequal(p,"LANMAN2.1"))
 			arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
 		else if (strcsequal(p,"LM1.2X002"))
@@ -537,7 +560,13 @@
 				set_remote_arch(RA_WINNT);
 			break;
 		case ARCH_WIN2K:
-			set_remote_arch(RA_WIN2K);
+			/* Vista may have been set in the negprot so don't 
+			   override it here */
+			if ( get_remote_arch() != RA_VISTA )
+				set_remote_arch(RA_WIN2K);
+			break;
+		case ARCH_VISTA:
+			set_remote_arch(RA_VISTA);
 			break;
 		case ARCH_OS2:
 			set_remote_arch(RA_OS2);
Index: samba-3.0.24/source/lib/util.c
===================================================================
--- samba-3.0.24.orig/source/lib/util.c	2007-02-08 15:27:50.000000000 -0600
+++ samba-3.0.24/source/lib/util.c	2007-02-08 15:31:14.000000000 -0600
@@ -2182,6 +2182,9 @@
 	case RA_WIN2K3:
 		fstrcpy(remote_arch, "Win2K3");
 		break;
+	case RA_VISTA:
+		fstrcpy(remote_arch, "Vista");
+		break;
 	case RA_SAMBA:
 		fstrcpy(remote_arch,"Samba");
 		break;
Index: samba-3.0.24/source/smbd/msdfs.c
===================================================================
--- samba-3.0.24.orig/source/smbd/msdfs.c	2007-02-04 12:59:13.000000000 -0600
+++ samba-3.0.24/source/smbd/msdfs.c	2007-02-08 15:54:49.000000000 -0600
@@ -832,9 +832,13 @@
 
 	/* create the referral depeding on version */
 	DEBUG(10,("max_referral_level :%d\n",max_referral_level));
-	if(max_referral_level<2 || max_referral_level>3) {
+
+	if (max_referral_level < 2) {
 		max_referral_level = 2;
 	}
+	if (max_referral_level > 3) {
+		max_referral_level = 3;
+	}
 
 	switch(max_referral_level) {
 	case 2:
Index: samba-3.0.24/source/lib/dummysmbd.c
===================================================================
--- samba-3.0.24.orig/source/lib/dummysmbd.c	2006-04-19 21:29:23.000000000 -0500
+++ samba-3.0.24/source/lib/dummysmbd.c	2007-02-08 20:15:04.000000000 -0600
@@ -38,3 +38,9 @@
 {
 	return False;
 }
+
+NTSTATUS can_delete_directory(struct connection_struct *conn,
+                                const char *dirname)
+{
+	return NT_STATUS_OK;
+}
Index: samba-3.0.24/source/locking/locking.c
===================================================================
--- samba-3.0.24.orig/source/locking/locking.c	2007-02-04 12:59:23.000000000 -0600
+++ samba-3.0.24/source/locking/locking.c	2007-02-08 20:15:04.000000000 -0600
@@ -1166,6 +1166,11 @@
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
+	/* Don't allow delete on close for non-empty directories. */
+	if (fsp->is_directory) {
+		return can_delete_directory(fsp->conn, fsp->fsp_name);
+	}
+
 	return NT_STATUS_OK;
 }
 
Index: samba-3.0.24/source/smbd/dir.c
===================================================================
--- samba-3.0.24.orig/source/smbd/dir.c	2007-02-04 12:59:13.000000000 -0600
+++ samba-3.0.24/source/smbd/dir.c	2007-02-08 20:15:04.000000000 -0600
@@ -1255,3 +1255,42 @@
 	}
 	return False;
 }
+
+/*****************************************************************
+ Is this directory empty ?
+*****************************************************************/
+
+NTSTATUS can_delete_directory(struct connection_struct *conn,
+				const char *dirname)
+{
+	NTSTATUS status = NT_STATUS_OK;
+	long dirpos = 0;
+	const char *dname;
+	struct smb_Dir *dir_hnd = OpenDir(conn, dirname, NULL, 0);
+
+	if (!dir_hnd) {
+		return map_nt_error_from_unix(errno);
+	}
+
+	while ((dname = ReadDirName(dir_hnd,&dirpos))) {
+		SMB_STRUCT_STAT st;
+
+		/* Quick check for "." and ".." */
+		if (dname[0] == '.') {
+			if (!dname[1] || (dname[1] == '.' && !dname[2])) {
+				continue;
+			}
+		}
+
+		if (!is_visible_file(conn, dirname, dname, &st, True)) {
+			continue;
+		}
+
+		DEBUG(10,("can_delete_directory: got name %s - can't delete\n", dname ));
+		status = NT_STATUS_DIRECTORY_NOT_EMPTY;
+		break;
+	}
+	CloseDir(dir_hnd);
+
+	return status;
+}
