The Samba-Bugzilla – Attachment 4433 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]
new patch
net_usershare_permission.diff (text/x-patch), 15.41 KB, created by
boyang
on 2009-07-16 13:44:04 UTC
(
hide
)
Description:
new patch
Filename:
MIME Type:
Creator:
boyang
Created:
2009-07-16 13:44:04 UTC
Size:
15.41 KB
patch
obsolete
>diff --git a/source3/include/proto.h b/source3/include/proto.h >index d68aa4b..7a81a84 100644 >--- a/source3/include/proto.h >+++ b/source3/include/proto.h >@@ -4317,7 +4317,7 @@ enum usershare_err parse_usershare_file(TALLOC_CTX *ctx, > SEC_DESC **ppsd, > bool *pallow_guest); > int load_usershare_service(const char *servicename); >-int load_usershare_shares(void); >+int load_usershare_shares(bool reload); > void gfree_loadparm(void); > void lp_set_in_client(bool b); > bool lp_is_in_client(void); >@@ -6130,6 +6130,8 @@ NTSTATUS delete_all_streams(connection_struct *conn, const char *fname); > void conn_init(struct smbd_server_connection *sconn); > int conn_num_open(struct smbd_server_connection *sconn); > bool conn_snum_used(int snum); >+void recheck_share_security(int snum); >+void conn_disconnect_snum(int snum); > connection_struct *conn_find(struct smbd_server_connection *sconn, > unsigned cnum); > connection_struct *conn_new(struct smbd_server_connection *sconn); >@@ -7067,6 +7069,7 @@ 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_root_user(void); >+void recheck_current_user(connection_struct *conn); > bool become_authenticated_pipe_user(pipes_struct *p); > bool unbecome_authenticated_pipe_user(void); > void become_root(void); >diff --git a/source3/lib/dummysmbd.c b/source3/lib/dummysmbd.c >index a41e6dc..a100187 100644 >--- a/source3/lib/dummysmbd.c >+++ b/source3/lib/dummysmbd.c >@@ -38,6 +38,16 @@ bool conn_snum_used(int snum) > return False; > } > >+void recheck_share_security(int snum) >+{ >+ return; >+} >+ >+void conn_disconnect_snum(int snum) >+{ >+ return; >+} >+ > void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck) > { > } >diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c >index dbbd6e3..16a2be4 100644 >--- a/source3/param/loadparm.c >+++ b/source3/param/loadparm.c >@@ -364,6 +364,7 @@ struct service { > bool autoloaded; > int usershare; > struct timespec usershare_last_mod; >+ struct timespec usershare_last_mod2; /* only updated when reload from main loop. */ > char *szService; > char *szPath; > char *szUsername; >@@ -507,6 +508,7 @@ static struct service sDefault = { > False, /* not autoloaded */ > 0, /* not a usershare */ > {0, }, /* No last mod time */ >+ {0, }, /* No last mod time2 */ > NULL, /* szService */ > NULL, /* szPath */ > NULL, /* szUsername */ >@@ -8533,6 +8535,9 @@ enum usershare_err parse_usershare_file(TALLOC_CTX *ctx, > return USERSHARE_OK; > } > >+/* initialized to invalid */ >+static SMB_STRUCT_STAT dir_sbuf = { .st_ex_nlink = 0 }; >+ > /*************************************************************************** > Deal with a usershare file. > Returns: >@@ -8542,7 +8547,7 @@ enum usershare_err parse_usershare_file(TALLOC_CTX *ctx, > with permissions to share directory etc. > ***************************************************************************/ > >-static int process_usershare_file(const char *dir_name, const char *file_name, int snum_template) >+static int process_usershare_file(const char *dir_name, const char *file_name, int snum_template, bool reload) > { > SMB_STRUCT_STAT sbuf; > SMB_STRUCT_STAT lsbuf; >@@ -8569,6 +8574,9 @@ static int process_usershare_file(const char *dir_name, const char *file_name, i > fstrcpy(service_name, file_name); > > if (asprintf(&fname, "%s/%s", dir_name, file_name) < 0) { >+ DEBUG(0, ("process_usershare_file: Allocate memory failed when " >+ "loading usershare!\n")); >+ return -2; > } > > /* Minimize the race condition by doing an lstat before we >@@ -8601,9 +8609,31 @@ static int process_usershare_file(const char *dir_name, const char *file_name, i > TALLOC_FREE(canon_name); > } > >- if (iService != -1 && >- timespec_compare(&ServicePtrs[iService]->usershare_last_mod, >- &lsbuf.st_ex_mtime) == 0) { >+ if (reload && iService == -1) { >+ /* not loaded, ignore this share. */ >+ SAFE_FREE(fname); >+ return -2; >+ } >+ >+ /* >+ * This looks a little weird.... >+ * load_usershare_service() and lp_servicenumber()(calls load_usershare_service()) >+ * are invoked everywhere, each time they are called, usershare_last_mod is updated >+ * but the access check is not reforced. access check is only checked when we >+ * reload usershare in the main loop of the child. see, if we depend on >+ * usershare_last_mod, we are risking missing access check. >+ * usershare_last_mod2 is only update when access check is performed. >+ * use another list to keep it is possible, but if we want to use >+ * load_usershare_shares() and process_usershare_file() here, it is the same >+ * else we might copy duplicate code to handle usershare reload alone. >+ */ >+ >+ if ((!reload && iService != -1 && >+ timespec_compare(&ServicePtrs[iService]->usershare_last_mod, >+ &lsbuf.st_ex_mtime) == 0) >+ || (reload && iService != -1 && >+ timespec_compare(&ServicePtrs[iService]->usershare_last_mod2, >+ &lsbuf.st_ex_mtime) == 0)) { > /* Nothing changed - Mark valid and return. */ > DEBUG(10,("process_usershare_file: service %s not changed.\n", > service_name )); >@@ -8612,6 +8642,15 @@ static int process_usershare_file(const char *dir_name, const char *file_name, i > return iService; > } > >+ if (reload && iService != -1 && >+ timespec_compare(&ServicePtrs[iService]->usershare_last_mod, >+ &lsbuf.st_ex_mtime) == 0 && >+ timespec_compare(&ServicePtrs[iService]->usershare_last_mod2, >+ &lsbuf.st_ex_mtime) != 0) { >+ /* the share is update, only need to recheck accesses */ >+ goto check_access; >+ } >+ > /* Try and open the file read only - no symlinks allowed. */ > #ifdef O_NOFOLLOW > fd = sys_open(fname, O_RDONLY|O_NOFOLLOW, 0); >@@ -8725,6 +8764,20 @@ static int process_usershare_file(const char *dir_name, const char *file_name, i > string_set(&ServicePtrs[iService]->comment, comment); > > talloc_destroy(ctx); >+check_access: >+ if (reload) { >+ /* trying to adjust share access for connections. */ >+ if (conn_snum_used(iService)) { >+ /* rechecking share security */ >+ DEBUG(0, ("[boyang] process_usershare_file: " >+ "rechecking permission for share %s\n", >+ lp_servicename(iService))); >+ recheck_share_security(iService); >+ } >+ /* update time stamp when finish the access check. */ >+ ServicePtrs[iService]->usershare_last_mod2 = >+ ServicePtrs[iService]->usershare_last_mod; >+ } > > return iService; > } >@@ -8781,6 +8834,11 @@ int load_usershare_service(const char *servicename) > return -1; > } > >+ if (dir_sbuf.st_ex_nlink == 0) { >+ /* first time to load, update stat buffer. */ >+ memcpy(&dir_sbuf, &sbuf, sizeof(SMB_STRUCT_STAT)); >+ } >+ > if (!S_ISDIR(sbuf.st_ex_mode)) { > DEBUG(0,("load_usershare_service: %s is not a directory.\n", > usersharepath )); >@@ -8823,7 +8881,34 @@ int load_usershare_service(const char *servicename) > } > } > >- return process_usershare_file(usersharepath, servicename, snum_template); >+ return process_usershare_file(usersharepath, servicename, snum_template, false); >+} >+ >+static bool usershare_dir_changed(void) >+{ >+ SMB_STRUCT_STAT sbuf; >+ const char *usersharepath = lp_usershare_path(); >+ /* not even loaded, so there is no change. :-) */ >+ if (dir_sbuf.st_ex_nlink == 0) { >+ return false; >+ } >+ /* usershare is not enabled. */ >+ if (lp_usershare_max_shares() == 0 || !usersharepath || !*usersharepath) { >+ return false; >+ } >+ if (sys_stat(usersharepath, &sbuf) != 0) { >+ DEBUG(0, ("usershare_dir_changed: stat usershare path %s failed. %s\n", >+ usersharepath, strerror(errno))); >+ /* not sure if it is changed. return false? */ >+ return false; >+ } >+ if (dir_sbuf.st_ex_dev != sbuf.st_ex_dev >+ || dir_sbuf.st_ex_ino != sbuf.st_ex_ino >+ || timespec_compare(&dir_sbuf.st_ex_mtime, &sbuf.st_ex_mtime) != 0) { >+ memcpy(&dir_sbuf, &sbuf, sizeof(SMB_STRUCT_STAT)); >+ return true; >+ } >+ return false; > } > > /*************************************************************************** >@@ -8833,7 +8918,7 @@ int load_usershare_service(const char *servicename) > been removed. > ***************************************************************************/ > >-int load_usershare_shares(void) >+int load_usershare_shares(bool reload) > { > SMB_STRUCT_DIR *dp; > SMB_STRUCT_STAT sbuf; >@@ -8848,6 +8933,14 @@ int load_usershare_shares(void) > const char *usersharepath = Globals.szUsersharePath; > int ret = lp_numservices(); > >+ if (reload && !usershare_dir_changed()) { >+ return lp_numservices(); >+ } >+ >+ if (reload) { >+ DEBUG(0, ("[boyang] load_usershare_shares: trying to reload usershare!!\n")); >+ } >+ > if (max_user_shares == 0 || *usersharepath == '\0') { > return lp_numservices(); > } >@@ -8858,6 +8951,11 @@ int load_usershare_shares(void) > return ret; > } > >+ if (reload || dir_sbuf.st_ex_nlink == 0) { >+ /* first time to load usershare or reload, update stat buffer. */ >+ memcpy(&dir_sbuf, &sbuf, sizeof(SMB_STRUCT_STAT)); >+ } >+ > /* > * This directory must be owned by root, and have the 't' bit set. > * It also must not be writable by "other". >@@ -8934,8 +9032,8 @@ int load_usershare_shares(void) > break; > } > >- r = process_usershare_file(usersharepath, n, snum_template); >- if (r == 0) { >+ r = process_usershare_file(usersharepath, n, snum_template, reload); >+ if (r >= 0) { > /* Update the services count. */ > num_usershares++; > if (num_usershares >= max_user_shares) { >@@ -8972,6 +9070,13 @@ int load_usershare_shares(void) > for (iService = iNumServices - 1; iService >= 0; iService--) { > if (VALID(iService) && (ServicePtrs[iService]->usershare == USERSHARE_PENDING_DELETE)) { > if (conn_snum_used(iService)) { >+ /* should we disconnect the tconxs if we are reloading? */ >+ if (reload) { >+ DEBUG(10, ("[boyang] removing non-exist shares.\n")); >+ delete_share_security(lp_servicename(iService)); >+ conn_disconnect_snum(iService); >+ free_service_byindex(iService); >+ } > continue; > } > /* Remove from the share ACL db. */ >diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c >index c58c08e..41304a5 100644 >--- a/source3/rpc_server/srv_srvsvc_nt.c >+++ b/source3/rpc_server/srv_srvsvc_nt.c >@@ -527,7 +527,7 @@ static WERROR init_srv_share_info_ctr(pipes_struct *p, > > /* Ensure all the usershares are loaded. */ > become_root(); >- load_usershare_shares(); >+ load_usershare_shares(false); > load_registry_shares(); > num_services = lp_numservices(); > unbecome_root(); >diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c >index af6e091..b6183e5 100644 >--- a/source3/smbd/conn.c >+++ b/source3/smbd/conn.c >@@ -61,6 +61,61 @@ bool conn_snum_used(int snum) > return(False); > } > >+/*************************************************************************** >+ Recheck share access for existing connections, which is used for usershare >+ now. This cannot be used for other shares now, because this cannot handle >+ force user parameters. At present, usershare has no force user parameter. >+***************************************************************************/ >+void recheck_share_security(int snum) >+{ >+ struct smbd_server_connection *sconn = smbd_server_conn; >+ int i; >+ struct vuid_cache_entry *ent; >+ connection_struct *conn; >+ for (conn = sconn->smb1.tcons.Connections; conn; conn=conn->next) { >+ if (conn->params->service == snum) { >+ conn->read_only = false; >+ conn->admin_user = false; >+ for (i = 0; i < VUID_CACHE_SIZE; i++) { >+ ent = &conn->vuid_cache.array[i]; >+ if (ent->vuid != UID_FIELD_INVALID) { >+ ent->vuid = UID_FIELD_INVALID; >+ if (conn->server_info == ent->server_info) { >+ ent->server_info = NULL; >+ } else { >+ TALLOC_FREE(ent->server_info); >+ } >+ ent->read_only = false; >+ ent->admin_user = false; >+ } >+ } >+ /* handle current user if he is on this tree. */ >+ recheck_current_user(conn); >+ /* need to handle fsp too? */ >+ /* leave the tree connect here, but close open fsps. */ >+ file_close_conn(conn); >+ } >+ } >+ return; >+} >+ >+/*************************************************************************** >+ Given a service number to disconnect all tconx connected to the share. >+***************************************************************************/ >+void conn_disconnect_snum(int snum) >+{ >+ struct smbd_server_connection *sconn = smbd_server_conn; >+ connection_struct *conn, *next; >+ for (conn = sconn->smb1.tcons.Connections; conn; conn=next) { >+ next = conn->next; >+ if (SNUM(conn) == snum) { >+ set_current_service(NULL, 0, true); >+ close_cnum(sconn, conn, conn->vuid); >+ } >+ } >+ return; >+} >+ > /**************************************************************************** > Find a conn given a cnum. > ****************************************************************************/ >diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c >index 6fc72c2..55d69c2 100644 >--- a/source3/smbd/lanman.c >+++ b/source3/smbd/lanman.c >@@ -1806,7 +1806,7 @@ static bool api_RNetShareEnum( connection_struct *conn, uint16 vuid, > /* Ensure all the usershares are loaded. */ > become_root(); > load_registry_shares(); >- count = load_usershare_shares(); >+ count = load_usershare_shares(false); > unbecome_root(); > > data_len = fixed_len = string_len = 0; >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index d40b8a8..7139470 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -1681,7 +1681,7 @@ struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn) > /* Ensure all the usershares are loaded. */ > become_root(); > load_registry_shares(); >- sharecount = load_usershare_shares(); >+ sharecount = load_usershare_shares(false); > unbecome_root(); > > for(i=0;i < sharecount;i++) { >diff --git a/source3/smbd/process.c b/source3/smbd/process.c >index b26bc15..20aae81 100644 >--- a/source3/smbd/process.c >+++ b/source3/smbd/process.c >@@ -762,6 +762,15 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection * > struct timeval to; > int maxfd = 0; > >+ /* >+ * Watch on usershare service changes. Only load usershare >+ * that were loaded by the child already. The change of unloaded >+ * shares won't affect current connection. The purpose here is to >+ * detect user share change on fly, which is the case in windows. >+ * We don't want to reload all services when only usershare service >+ * changed. we don't add the directory to lp_file_lists_changed(). >+ */ >+ > to.tv_sec = SMBD_SELECT_TIMEOUT; > to.tv_usec = 0; > >@@ -800,6 +809,8 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection * > END_PROFILE(smbd_idle); > errno = sav; > } >+ >+ load_usershare_shares(true); > > if (run_events(smbd_event_context(), selrtn, &r_fds, &w_fds)) { > return NT_STATUS_RETRY; >diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c >index 2ec50cd..ef620bd 100644 >--- a/source3/smbd/uid.c >+++ b/source3/smbd/uid.c >@@ -505,3 +505,26 @@ bool unbecome_user(void) > pop_conn_ctx(); > return True; > } >+ >+void recheck_current_user(connection_struct *conn) >+{ >+ struct auth_serversupplied_info *server_info; >+ user_struct *vuser = get_valid_user_struct(smbd_server_conn, current_user.vuid); >+ if ((current_user.conn == conn) >+ && (current_user.vuid != UID_FIELD_INVALID)) { >+ server_info = vuser ? vuser->server_info : conn->server_info; >+ if (!check_user_ok(conn, current_user.vuid, server_info, SNUM(conn))) { >+ DEBUG(10, ("[boyang] recheck_share_security: rechecking for " >+ "current user, access denied!")); >+ /* >+ * change to root user. which will force >+ * check at next request. >+ */ >+ change_to_root_user(); >+ } else { >+ DEBUG(0, ("[boyang] current user access %s\n", conn->read_only ? >+ "read" : "read/write")); >+ } >+ } >+ return; >+}
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