[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha8-337-g73e9693

Bo Yang boyang at samba.org
Tue Jul 14 11:09:34 MDT 2009


The branch, master has been updated
       via  73e96935c3604d21552ba93dfd561eaf7606f52d (commit)
       via  2821f5abf5d60cf420877e92db5c615c83471e95 (commit)
       via  86865365ce487a8943370ea2f313000a6440ea9a (commit)
       via  9ef6af73b319048fc6f3891573f0e10066dffee6 (commit)
      from  99c7ee3c9145b6187113ff29500b55a32320a9bc (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 73e96935c3604d21552ba93dfd561eaf7606f52d
Author: Bo Yang <boyang at samba.org>
Date:   Wed Jul 15 17:03:04 2009 +0800

    s3: fix build of pdbedit and net_sam. Guenther, please check. Signed-off-by: Bo Yang <boyang at samba.org>

commit 2821f5abf5d60cf420877e92db5c615c83471e95
Author: Bo Yang <boyang at samba.org>
Date:   Wed Jul 15 15:37:04 2009 +0800

    s3: Fix double free in net usershare.
    
    Signed-off-by: Bo Yang <boyang at samba.org>

commit 86865365ce487a8943370ea2f313000a6440ea9a
Author: Bo Yang <boyang at samba.org>
Date:   Wed Jul 15 15:36:02 2009 +0800

    S3: Small fix to get rid of annoying log message.
    
    Signed-off-by: Bo Yang <boyang at samba.org>

commit 9ef6af73b319048fc6f3891573f0e10066dffee6
Author: Bo Yang <boyang at samba.org>
Date:   Wed Jul 15 15:34:10 2009 +0800

    s3: Make smbd aware of permission change of usershare. Since usershare are relatively volatile and non-previledge users must disconnect from smbd and reconnect to it to make share permission in effect.

-----------------------------------------------------------------------

Summary of changes:
 source3/include/proto.h            |    7 ++-
 source3/include/smb.h              |    6 ++
 source3/param/loadparm.c           |   14 +++++
 source3/rpc_server/srv_srvsvc_nt.c |    6 ++-
 source3/smbd/conn.c                |    1 +
 source3/smbd/notify_inotify.c      |    4 +-
 source3/smbd/process.c             |   58 +++++++++++++++++++++-
 source3/smbd/service.c             |   80 ++++++++++++++++++++++++++++++
 source3/smbd/uid.c                 |   96 +++++++++++++++++++++++++++---------
 source3/utils/net_sam.c            |    8 ++--
 source3/utils/net_usershare.c      |   32 ++----------
 source3/utils/pdbedit.c            |    2 +-
 12 files changed, 251 insertions(+), 63 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 0dd1e98..d141de4 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -4296,6 +4296,7 @@ enum usershare_err parse_usershare_file(TALLOC_CTX *ctx,
 			char **pp_comment,
 			SEC_DESC **ppsd,
 			bool *pallow_guest);
+bool am_usershare(int iService);
 int load_usershare_service(const char *servicename);
 int load_usershare_shares(void);
 void gfree_loadparm(void);
@@ -7063,7 +7064,8 @@ void reply_transs2(struct smb_request *req);
 
 bool change_to_guest(void);
 void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid);
-bool change_to_user(connection_struct *conn, uint16 vuid);
+bool change_to_user_force_recheck(connection_struct *conn, uint16 vuid,
+				  bool recheck, NTSTATUS *pstatus);
 bool change_to_root_user(void);
 bool become_authenticated_pipe_user(pipes_struct *p);
 bool unbecome_authenticated_pipe_user(void);
@@ -7072,6 +7074,9 @@ void unbecome_root(void);
 bool become_user(connection_struct *conn, uint16 vuid);
 bool unbecome_user(void);
 
+#define change_to_user(conn, vuid) \
+	change_to_user_force_recheck(conn, vuid, 0, NULL)
+
 /* The following definitions come from smbd/utmp.c  */
 
 void sys_utmp_claim(const char *username, const char *hostname,
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 2e9cf1b..44216f8 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -550,6 +550,7 @@ typedef struct connection_struct {
 	unsigned cnum; /* an index passed over the wire */
 	struct share_params *params;
 	bool force_user;
+	bool force_recheck_perm;
 	struct vuid_cache vuid_cache;
 	struct dptr_struct *dirptr;
 	bool printer;
@@ -1398,6 +1399,11 @@ struct bitmap {
 #define FILE_NOTIFY_CHANGE_STREAM_NAME	0x00000200
 #define FILE_NOTIFY_CHANGE_STREAM_SIZE	0x00000400
 #define FILE_NOTIFY_CHANGE_STREAM_WRITE	0x00000800
+#define FILE_NOTIFY_CHANGE_FILE_CONTENT \
+	(FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME \
+	| FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE \
+	| FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA \
+	| FILE_NOTIFY_CHANGE_SECURITY)
 
 #define FILE_NOTIFY_CHANGE_NAME \
 	(FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME)
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 7e4371b..4415804 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -5142,6 +5142,9 @@ static char *lp_string(const char *s)
 #if 0
 	DEBUG(10, ("lp_string(%s)\n", s));
 #endif
+	if (!s) {
+		return NULL;
+	}
 
 	ret = talloc_sub_basic(ctx,
 			get_current_username(),
@@ -8727,6 +8730,17 @@ static int process_usershare_file(const char *dir_name, const char *file_name, i
 }
 
 /***************************************************************************
+Am I a usershare service?
+***************************************************************************/
+bool am_usershare(int iService)
+{
+	if (iService >= 0) {
+		return (ServicePtrs[iService]->usershare == USERSHARE_VALID);
+	}
+	return false;
+}
+
+/***************************************************************************
  Checks if a usershare entry has been modified since last load.
 ***************************************************************************/
 
diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c
index 44acf4d..c58c08e 100644
--- a/source3/rpc_server/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srv_srvsvc_nt.c
@@ -540,11 +540,13 @@ static WERROR init_srv_share_info_ctr(pipes_struct *p,
                 if (lp_browseable(snum) && lp_snum_ok(snum) &&
                     is_enumeration_allowed(p, snum) &&
                     (all_shares || !is_hidden_share(snum)) ) {
-                        DEBUG(10, ("counting service %s\n", lp_servicename(snum)));
+                        DEBUG(10, ("counting service %s\n",
+				lp_servicename(snum) ? lp_servicename(snum) : "(null)"));
                         allowed[snum] = true;
                         num_entries++;
                 } else {
-                        DEBUG(10, ("NOT counting service %s\n", lp_servicename(snum)));
+                        DEBUG(10, ("NOT counting service %s\n",
+				lp_servicename(snum) ? lp_servicename(snum) : "(null)"));
                 }
         }
 
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
index af6e091..3ddb4c0 100644
--- a/source3/smbd/conn.c
+++ b/source3/smbd/conn.c
@@ -155,6 +155,7 @@ find_again:
 		return NULL;
 	}
 	conn->cnum = i;
+	conn->force_recheck_perm = false;
 	conn->force_group_gid = (gid_t)-1;
 
 	bitmap_set(sconn->smb1.tcons.bmap, i);
diff --git a/source3/smbd/notify_inotify.c b/source3/smbd/notify_inotify.c
index 26570a2..b6be69c 100644
--- a/source3/smbd/notify_inotify.c
+++ b/source3/smbd/notify_inotify.c
@@ -316,7 +316,9 @@ static const struct {
 	{FILE_NOTIFY_CHANGE_LAST_WRITE,  IN_ATTRIB},
 	{FILE_NOTIFY_CHANGE_LAST_ACCESS, IN_ATTRIB},
 	{FILE_NOTIFY_CHANGE_EA,          IN_ATTRIB},
-	{FILE_NOTIFY_CHANGE_SECURITY,    IN_ATTRIB}
+	{FILE_NOTIFY_CHANGE_SECURITY,    IN_ATTRIB},
+	{FILE_NOTIFY_CHANGE_FILE_CONTENT, IN_MODIFY|IN_DELETE|IN_CREATE|IN_DELETE_SELF
+					  |IN_MOVE_SELF|IN_MOVED_FROM|IN_MOVED_TO},
 };
 
 static uint32_t inotify_map(struct notify_entry *e)
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index b26bc15..5b8a325 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -1286,7 +1286,6 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
 			}
 		}
 	}
-
 	/* Does this call need to be run as the connected user? */
 	if (flags & AS_USER) {
 
@@ -1303,12 +1302,67 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
 			}
 			return NULL;
 		}
-
+#ifdef HAVE_INOTIFY
+		if (conn->force_recheck_perm) {
+			int old;
+			int iService = -1;
+			const char *service = NULL;
+			NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+			conn->force_recheck_perm = false;
+			DEBUG(5, ("switch_message: rechecking permission for connection %x\n",
+				 (unsigned int)conn));
+			old = SNUM(conn);
+			service = lp_servicename(old);
+			conn->read_only = False;
+			if (lp_snum_ok(old) && am_usershare(old)) {
+				iService = load_usershare_service(service);
+				if (iService < 0 || old != iService) {
+					/* non-exist service */
+					DEBUG(5, ("switch_message: deleting connection %x\n",
+						 (unsigned int)conn));
+					DEBUG(5, ("snum %d, sname %s\n",
+						 old, service ? service : "NULL"));
+					delete_share_security(service);
+					set_current_service(NULL, 0, True);
+					close_cnum(smbd_server_conn, conn, conn->vuid);
+					lp_killservice(old);
+					reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
+					return NULL;
+				}
+
+				/*
+				 * Don't have to reauthentication here, but
+				 * need to check share permissions.....
+				 * the vuid cache is a problem..
+				 */
+
+				if (!change_to_root_user()) {
+					smb_panic("cann't change to root user!\n");
+				}
+
+				if (!change_to_user_force_recheck(conn, session_tag,
+								True, &status)) {
+					reply_nterror(req, status);
+					remove_deferred_open_smb_message(req->mid);
+					return conn;
+				}
+			}
+		} else {
+			NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+			if (!change_to_user_force_recheck(conn, session_tag,
+							False, &status)) {
+				reply_nterror(req, status);
+				remove_deferred_open_smb_message(req->mid);
+				return conn;
+			}
+		}
+#else
 		if (!change_to_user(conn,session_tag)) {
 			reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
 			remove_deferred_open_smb_message(req->mid);
 			return conn;
 		}
+#endif
 
 		/* All NEED_WRITE and CAN_IPC flags must also have AS_USER. */
 
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index 0124b2b..8ae13b1 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -630,6 +630,33 @@ static NTSTATUS create_connection_server_info(struct smbd_server_connection *sco
 	return NT_STATUS_ACCESS_DENIED;
 }
 
+#ifdef HAVE_INOTIFY
+static void share_perm_changed(struct sys_notify_context *ctx,
+				   void *ptr, struct notify_event *ev)
+{
+	connection_struct *conn = talloc_get_type_abort(ptr, connection_struct);
+	const char *service = NULL;
+	service = lp_servicename(SNUM(conn));
+	if (strequal(ev->path, service)) {
+		conn->force_recheck_perm = true;
+		DEBUG(0, ("share_perm_changed: set recheck flag for connection %x\n",
+		(unsigned int)conn));
+	}
+}
+
+struct notify_context {
+	struct db_context *db_recursive;
+	struct db_context *db_onelevel;
+	struct server_id server;
+	struct messaging_context *messaging_ctx;
+	struct notify_list *list;
+	struct notify_array *array;
+	int seqnum;
+	struct sys_notify_context *sys_notify_ctx;
+	TDB_DATA key;
+};
+#endif
+
 
 /****************************************************************************
   Make a connection, given the snum to connect to, and the vuser of the
@@ -867,11 +894,64 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
 	}
 
 	if ((!conn->printer) && (!conn->ipc)) {
+#ifdef HAVE_INOTIFY
+		struct sys_notify_context *sys_ctx = NULL;
+		struct notify_entry e;
+		struct inotify_watch_context *w = NULL;
+#endif
 		conn->notify_ctx = notify_init(conn, server_id_self(),
 					       smbd_messaging_context(),
 					       smbd_event_context(),
 					       conn);
+#ifdef HAVE_INOTIFY
+		/*
+		 * here is the start of monitoring share permissions change.
+		 * For usershares, we have to watch on both
+		 * get_dyn_STATDIR()/servicename and get_dyn_STATDIR()/share_info.tdb.
+		 * For shares in smb.conf, we just watch on
+		 * get_dyn_STATDIR()/share_info.tdb
+		 */
+		if (!conn->notify_ctx) {
+			DEBUG(1, ("change notify is not enabled??\n"));
+			goto nonotify;
+		}
+		sys_ctx = conn->notify_ctx->sys_notify_ctx;
+		if (!sys_ctx) {
+			DEBUG(1, ("change notify: out of memory!!\n"));
+			*pstatus = NT_STATUS_NO_MEMORY;
+			conn_free(sconn, conn);
+			return NULL;
+		}
+		ZERO_STRUCT(e);
+		if (am_usershare(SNUM(conn))) {
+			const char *usershare_path = lp_usershare_path();
+			/* This is usershare service. */
+			e.path = talloc_strdup(conn, usershare_path);
+		} else {
+			goto nonotify;
+			/* watch normal shares' permission? */
+		}
+		if (!e.path) {
+			DEBUG(1, ("setting up usershare notify: out of memory!\n"));
+			*pstatus = status;
+			conn_free(sconn, conn);
+			return NULL;
+		}
+		e.path_len = strlen(e.path);
+		e.filter = FILE_NOTIFY_CHANGE_FILE_CONTENT;
+		status = inotify_watch(sys_ctx, &e, share_perm_changed,
+			(void *)conn, (void *)&w);
+		if (NT_STATUS_IS_ERR(status)) {
+			DEBUG(1, ("add inotify for usershare permission failed!\n"));
+			*pstatus = status;
+			conn_free(sconn, conn);
+			return NULL;
+		}
+#endif
 	}
+#ifdef HAVE_INOTIFY
+nonotify:
+#endif
 
 /* ROOT Activities: */	
 	/*
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 2ec50cd..8e5a386 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -82,12 +82,17 @@ static void free_conn_server_info_if_unused(connection_struct *conn)
 static bool check_user_ok(connection_struct *conn,
 			uint16_t vuid,
 			const struct auth_serversupplied_info *server_info,
-			int snum)
+			int snum, bool recheck, NTSTATUS *pstatus)
 {
 	bool valid_vuid = (vuid != UID_FIELD_INVALID);
 	unsigned int i;
 	bool readonly_share;
 	bool admin_user;
+	struct vuid_cache_entry *ent0;
+
+	if (pstatus) {
+		*pstatus = NT_STATUS_OK;
+	}
 
 	if (valid_vuid) {
 		struct vuid_cache_entry *ent;
@@ -96,18 +101,27 @@ static bool check_user_ok(connection_struct *conn,
 			ent = &conn->vuid_cache.array[i];
 			if (ent->vuid == vuid) {
 				free_conn_server_info_if_unused(conn);
-				conn->server_info = ent->server_info;
-				conn->read_only = ent->read_only;
-				conn->admin_user = ent->admin_user;
-				return(True);
+				ent0 = ent;
+				if (!recheck) {
+					conn->server_info = ent->server_info;
+					conn->read_only = ent->read_only;
+					conn->admin_user = ent->admin_user;
+					return(True);
+				} else {
+					break;
+				}
 			}
 		}
 	}
 
 	if (!user_ok_token(server_info->unix_name,
 			   pdb_get_domain(server_info->sam_account),
-			   server_info->ptok, snum))
+			   server_info->ptok, snum)) {
+		if (pstatus) {
+			*pstatus = NT_STATUS_ACCESS_DENIED;
+		}
 		return(False);
+	}
 
 	readonly_share = is_share_read_only_for_token(
 		server_info->unix_name,
@@ -128,6 +142,9 @@ static bool check_user_ok(connection_struct *conn,
 	if (!share_access_check(server_info->ptok, lp_servicename(snum),
 				readonly_share ?
 				FILE_READ_DATA : FILE_WRITE_DATA)) {
+		if (pstatus) {
+			*pstatus = NT_STATUS_ACCESS_DENIED;
+		}
 		return False;
 	}
 
@@ -137,13 +154,26 @@ static bool check_user_ok(connection_struct *conn,
 		NULL, server_info->ptok, lp_admin_users(snum));
 
 	if (valid_vuid) {
-		struct vuid_cache_entry *ent =
-			&conn->vuid_cache.array[conn->vuid_cache.next_entry];
+		struct vuid_cache_entry *ent = NULL;
+
+		if (!recheck || i == VUID_CACHE_SIZE) {
+			/* find a new entry and fill it. */
+			ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry];
 
-		conn->vuid_cache.next_entry =
-			(conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
+			conn->vuid_cache.next_entry =
+				(conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
 
-		TALLOC_FREE(ent->server_info);
+			TALLOC_FREE(ent->server_info);
+		} else if (recheck && (i < VUID_CACHE_SIZE) && (ent0->vuid == vuid)) {
+			/* she perform forced recheck, replace the old one. */
+			ent = ent0;
+		} else {
+			/* must not happen */
+			DEBUG(0, ("check_user_ok: recheck %s\n", recheck ? "true" : "false"));
+			DEBUG(0, ("check_user_ok: vuid cache %d -- %d\n", i, VUID_CACHE_SIZE));
+			DEBUG(0, ("check_user_ok: vuid %d -- %d\n", ent0->vuid, vuid));
+			smb_panic("should not happen");
+		}
 
 		/*
 		 * If force_user was set, all server_info's are based on the same
@@ -155,6 +185,9 @@ static bool check_user_ok(connection_struct *conn,
 
 		if (ent->server_info == NULL) {
 			ent->vuid = UID_FIELD_INVALID;
+			if (pstatus) {
+				*pstatus = NT_STATUS_NO_MEMORY;
+			}
 			return false;
 		}
 
@@ -221,7 +254,8 @@ void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid)
  stack, but modify the current_user entries.
 ****************************************************************************/
 
-bool change_to_user(connection_struct *conn, uint16 vuid)
+bool change_to_user_force_recheck(connection_struct *conn, uint16 vuid,
+				  bool recheck, NTSTATUS *pstatus)
 {
 	const struct auth_serversupplied_info *server_info = NULL;
 	struct smbd_server_connection *sconn = smbd_server_conn;
@@ -235,6 +269,9 @@ bool change_to_user(connection_struct *conn, uint16 vuid)
 
 	if (!conn) {
 		DEBUG(2,("change_to_user: Connection not open\n"));
+		if (pstatus) {
+			*pstatus = NT_STATUS_INVALID_HANDLE;
+		}
 		return(False);
 	}
 
@@ -245,17 +282,19 @@ bool change_to_user(connection_struct *conn, uint16 vuid)
 	 * SMB's - this hurts performance - Badly.
 	 */
 
-	if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
-	   (current_user.ut.uid == conn->server_info->utok.uid)) {
-		DEBUG(4,("change_to_user: Skipping user change - already "
-			 "user\n"));
-		return(True);
-	} else if ((current_user.conn == conn) && 
-		   (vuser != NULL) && (current_user.vuid == vuid) &&
-		   (current_user.ut.uid == vuser->server_info->utok.uid)) {
-		DEBUG(4,("change_to_user: Skipping user change - already "
-			 "user\n"));
-		return(True);
+	if (!recheck) {
+		if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
+		   (current_user.ut.uid == conn->server_info->utok.uid)) {
+			DEBUG(4,("change_to_user: Skipping user change - already "
+				 "user\n"));
+			return(True);
+		} else if ((current_user.conn == conn) &&
+			   (vuser != NULL) && (current_user.vuid == vuid) &&
+			   (current_user.ut.uid == vuser->server_info->utok.uid)) {
+			DEBUG(4,("change_to_user: Skipping user change - already "
+				 "user\n"));
+			return(True);
+		}
 	}
 
 	snum = SNUM(conn);
@@ -266,10 +305,13 @@ bool change_to_user(connection_struct *conn, uint16 vuid)
 		/* Invalid vuid sent - even with security = share. */
 		DEBUG(2,("change_to_user: Invalid vuid %d used on "
 			 "share %s.\n",vuid, lp_servicename(snum) ));
+		if (pstatus) {
+			*pstatus = NT_STATUS_ACCESS_VIOLATION;
+		}
 		return false;
 	}
 
-	if (!check_user_ok(conn, vuid, server_info, snum)) {
+	if (!check_user_ok(conn, vuid, server_info, snum, recheck, pstatus)) {
 		DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
 			 "not permitted access to share %s.\n",
 			 server_info->sanitized_username,
@@ -296,6 +338,9 @@ bool change_to_user(connection_struct *conn, uint16 vuid)
 	} else {
 		DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
 			 "share %s.\n",vuid, lp_servicename(snum) ));
+		if (pstatus) {
+			*pstatus = NT_STATUS_DOS(ERRSRV, ERRbaduid);
+		}


-- 
Samba Shared Repository


More information about the samba-cvs mailing list