The Samba-Bugzilla – Attachment 4415 Details for
Bug 6550
Samba needs to dynamically track user/registry share permission changes
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Initial patch from Boyang to add this functionality.
look (text/plain), 15.56 KB, created by
Jeremy Allison
on 2009-07-14 13:29:29 UTC
(
hide
)
Description:
Initial patch from Boyang to add this functionality.
Filename:
MIME Type:
Creator:
Jeremy Allison
Created:
2009-07-14 13:29:29 UTC
Size:
15.56 KB
patch
obsolete
>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..7b4e363 100644 >--- a/source3/param/loadparm.c >+++ b/source3/param/loadparm.c >@@ -8727,6 +8727,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/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); >+ } > return False; > } > >@@ -353,6 +398,9 @@ bool change_to_user(connection_struct *conn, uint16 vuid) > DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n", > (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid())); > >+ if (pstatus) { >+ *pstatus = NT_STATUS_OK; >+ } > return(True); > } >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 6550
: 4415 |
4419
|
4433