diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/proto.h | 2 | ||||
-rw-r--r-- | source3/rpc_server/srv_srvsvc_nt.c | 159 | ||||
-rw-r--r-- | source3/smbd/server.c | 4 | ||||
-rw-r--r-- | source3/smbd/service.c | 23 |
4 files changed, 170 insertions, 18 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 4d42664f25..a41c810816 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -3765,7 +3765,7 @@ BOOL api_srvsvc_rpc(pipes_struct *p); /*The following definitions come from rpc_server/srv_srvsvc_nt.c */ BOOL share_info_db_init(void); -SEC_DESC *get_share_security( TALLOC_CTX *ctx, int snum, size_t *psize); +BOOL share_access_check(int snum, uint16 vuid, uint32 desired_access); uint32 _srv_net_srv_get_info(pipes_struct *p, SRV_Q_NET_SRV_GET_INFO *q_u, SRV_R_NET_SRV_GET_INFO *r_u); uint32 _srv_net_file_enum(pipes_struct *p, SRV_Q_NET_FILE_ENUM *q_u, SRV_R_NET_FILE_ENUM *r_u); uint32 _srv_net_conn_enum(pipes_struct *p, SRV_Q_NET_CONN_ENUM *q_u, SRV_R_NET_CONN_ENUM *r_u); diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index 5c1c16c02a..4395a20e46 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -158,7 +158,7 @@ static SEC_DESC *get_share_security_default( TALLOC_CTX *ctx, int snum, size_t * Pull a security descriptor from the share tdb. ********************************************************************/ -SEC_DESC *get_share_security( TALLOC_CTX *ctx, int snum, size_t *psize) +static SEC_DESC *get_share_security( TALLOC_CTX *ctx, int snum, size_t *psize) { prs_struct ps; fstring key; @@ -184,7 +184,7 @@ SEC_DESC *get_share_security( TALLOC_CTX *ctx, int snum, size_t *psize) Store a security descriptor in the share db. ********************************************************************/ -static BOOL set_share_security(TALLOC_CTX *ctx, int snum, SEC_DESC *psd) +static BOOL set_share_security(TALLOC_CTX *ctx, const char *share_name, SEC_DESC *psd) { prs_struct ps; TALLOC_CTX *mem_ctx = NULL; @@ -201,13 +201,13 @@ static BOOL set_share_security(TALLOC_CTX *ctx, int snum, SEC_DESC *psd) goto out; } - slprintf(key, sizeof(key)-1, "SECDESC/%s", lp_servicename(snum)); + slprintf(key, sizeof(key)-1, "SECDESC/%s", share_name); if (tdb_prs_store(share_tdb, key, &ps)==0) { ret = True; - DEBUG(5,("set_share_security: stored secdesc for %s\n", lp_servicename(snum) )); + DEBUG(5,("set_share_security: stored secdesc for %s\n", share_name )); } else { - DEBUG(1,("set_share_security: Failed to store secdesc for %s\n", lp_servicename(snum) )); + DEBUG(1,("set_share_security: Failed to store secdesc for %s\n", share_name )); } /* Free malloc'ed memory */ @@ -243,6 +243,73 @@ static BOOL delete_share_security(int snum) } /******************************************************************* + Does this security descriptor map to a read only share ? +********************************************************************/ + +static BOOL read_only_share_sd(SEC_DESC *psd) +{ + int i; + SEC_ACL *ps_dacl = psd->dacl; + + if (!ps_dacl) + return True; + + for (i = 0; i < ps_dacl->num_aces; i++) { + SEC_ACE *psa = &ps_dacl->ace[i]; + + if (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED && + psa->info.mask & FILE_WRITE_DATA) + return False; + } + + return True; +} + +/******************************************************************* + Can this user access with share with the required permissions ? +********************************************************************/ + +BOOL share_access_check(int snum, uint16 vuid, uint32 desired_access) +{ + uint32 granted, status; + TALLOC_CTX *mem_ctx = NULL; + SEC_DESC *psd = NULL; + size_t sd_size; + struct current_user tmp_user; + struct current_user *puser = NULL; + user_struct *vuser = get_valid_user_struct(vuid); + BOOL ret = True; + + mem_ctx = talloc_init(); + if (mem_ctx == NULL) + return False; + + psd = get_share_security(mem_ctx, snum, &sd_size); + + if (!psd) + goto out; + + if (vuser) { + ZERO_STRUCT(tmp_user); + tmp_user.vuid = vuid; + tmp_user.uid = vuser->uid; + tmp_user.gid = vuser->gid; + tmp_user.ngroups = vuser->n_groups; + tmp_user.groups = vuser->groups; + tmp_user.nt_user_token = vuser->nt_user_token; + puser = &tmp_user; + } + + ret = se_access_check(psd, puser, desired_access, &granted, &status); + + out: + + talloc_destroy(mem_ctx); + + return ret; +} + +/******************************************************************* Fill in a share info level 502 structure. ********************************************************************/ @@ -1120,7 +1187,8 @@ uint32 _srv_net_share_set_info(pipes_struct *p, SRV_Q_NET_SHARE_SET_INFO *q_u, S int snum; int ret; char *ptr; - BOOL read_only; + SEC_DESC *psd = NULL; + BOOL read_only = False; DEBUG(5,("_srv_net_share_set_info: %d\n", __LINE__)); @@ -1139,27 +1207,76 @@ uint32 _srv_net_share_set_info(pipes_struct *p, SRV_Q_NET_SHARE_SET_INFO *q_u, S if (user.uid != 0) return ERROR_ACCESS_DENIED; - if (!lp_change_share_cmd()) - return ERROR_ACCESS_DENIED; - switch (q_u->info_level) { case 1: + /* Not enough info in a level 1 to do anything. */ return ERROR_ACCESS_DENIED; - break; case 2: - return ERROR_ACCESS_DENIED; + unistr2_to_ascii(comment, &q_u->info.share.info2.info_2_str.uni_remark, sizeof(share_name)); + unistr2_to_ascii(pathname, &q_u->info.share.info2.info_2_str.uni_path, sizeof(share_name)); + type = q_u->info.share.info2.info_2.type; + read_only = False; /* No SD means "Everyone full access. */ break; case 502: - /* we set sd's here. FIXME. JRA */ - return ERROR_ACCESS_DENIED; + unistr2_to_ascii(comment, &q_u->info.share.info502.info_502_str.uni_remark, sizeof(share_name)); + unistr2_to_ascii(pathname, &q_u->info.share.info502.info_502_str.uni_path, sizeof(share_name)); + type = q_u->info.share.info502.info_502.type; + psd = q_u->info.share.info502.info_502_str.sd; + read_only = read_only_share_sd(psd); break; case 1005: return ERROR_ACCESS_DENIED; - break; default: DEBUG(5,("_srv_net_share_set_info: unsupported switch value %d\n", q_u->info_level)); return NT_STATUS_INVALID_INFO_CLASS; - break; + } + + /* We can only modify disk shares. */ + if (type != STYPE_DISKTREE) + return ERROR_ACCESS_DENIED; + + /* Check if the pathname is valid. */ + if (!(ptr = valid_share_pathname( pathname ))) + return ERRbadpath; + + /* Ensure share name, pathname and comment don't contain '"' characters. */ + string_replace(share_name, '"', ' '); + string_replace(ptr, '"', ' '); + string_replace(comment, '"', ' '); + + /* Only call modify function if something changed. */ + + if (read_only != lp_readonly(snum) || strcmp(ptr, lp_pathname(snum)) || strcmp(comment, lp_comment(snum)) ) { + if (!lp_change_share_cmd()) + return ERROR_ACCESS_DENIED; + + slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\"", + lp_change_share_cmd(), share_name, ptr, comment, + read_only ? "read only = yes" : "read only = no" ); + dos_to_unix(command, True); /* Convert to unix-codepage */ + + DEBUG(10,("_srv_net_share_set_info: Running [%s]\n", command )); + if ((ret = smbrun(command, NULL, False)) != 0) { + DEBUG(0,("_srv_net_share_set_info: Running [%s] returned (%d)\n", command, ret )); + return ERROR_ACCESS_DENIED; + } + + /* Send SIGHUP to process group. */ + kill(0, SIGHUP); + } + + /* Replace SD if changed. */ + if (psd) { + SEC_DESC *old_sd; + size_t sd_size; + + old_sd = get_share_security(p->mem_ctx, snum, &sd_size); + + if (old_sd && !sec_desc_equal(old_sd, psd)) { + if (!set_share_security(p->mem_ctx, share_name, psd)) + DEBUG(0,("_srv_net_share_set_info: Failed to change security info in share %s.\n", + share_name )); + } } DEBUG(5,("_srv_net_share_set_info: %d\n", __LINE__)); @@ -1168,7 +1285,7 @@ uint32 _srv_net_share_set_info(pipes_struct *p, SRV_Q_NET_SHARE_SET_INFO *q_u, S } /******************************************************************* - Net share add. Call 'add_share_command "sharename" "pathname" "comment"' + Net share add. Call 'add_share_command "sharename" "pathname" "comment" "read only = xxx"' ********************************************************************/ uint32 _srv_net_share_add(pipes_struct *p, SRV_Q_NET_SHARE_ADD *q_u, SRV_R_NET_SHARE_ADD *r_u) @@ -1183,6 +1300,7 @@ uint32 _srv_net_share_add(pipes_struct *p, SRV_Q_NET_SHARE_ADD *q_u, SRV_R_NET_S int ret; char *ptr; BOOL read_only = False; + SEC_DESC *psd = NULL; DEBUG(5,("_srv_net_share_add: %d\n", __LINE__)); @@ -1208,11 +1326,12 @@ uint32 _srv_net_share_add(pipes_struct *p, SRV_Q_NET_SHARE_ADD *q_u, SRV_R_NET_S read_only = False; /* No SD means "Everyone full access. */ break; case 502: - /* we set sd's here. FIXME. JRA */ unistr2_to_ascii(share_name, &q_u->info.share.info502.info_502_str.uni_netname, sizeof(share_name)); unistr2_to_ascii(comment, &q_u->info.share.info502.info_502_str.uni_remark, sizeof(share_name)); unistr2_to_ascii(pathname, &q_u->info.share.info502.info_502_str.uni_path, sizeof(share_name)); type = q_u->info.share.info502.info_502.type; + psd = q_u->info.share.info502.info_502_str.sd; + read_only = read_only_share_sd(psd); break; case 1005: /* DFS only level. */ @@ -1252,6 +1371,12 @@ uint32 _srv_net_share_add(pipes_struct *p, SRV_Q_NET_SHARE_ADD *q_u, SRV_R_NET_S return ERROR_ACCESS_DENIED; } + if (psd) { + if (!set_share_security(p->mem_ctx, share_name, psd)) + DEBUG(0,("_srv_net_share_add: Failed to add security info to share %s.\n", + share_name )); + } + /* Send SIGHUP to process group. */ kill(0, SIGHUP); diff --git a/source3/smbd/server.c b/source3/smbd/server.c index adf57b3f55..84b7109294 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -765,6 +765,10 @@ static void usage(char *pname) exit(1); } + if (!share_info_db_init()) { + exit(1); + } + if(!initialize_password_db(False)) { exit(1); } diff --git a/source3/smbd/service.c b/source3/smbd/service.c index e20786595c..11ae11054a 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -343,6 +343,29 @@ connection_struct *make_connection(char *service,char *user,char *password, int conn->read_only = lp_readonly(snum); + /* + * New code to check if there's a share security descripter + * added from NT server manager. This is an additional check + * before the smb.conf checks are done. JRA. + */ + + { + BOOL can_write = share_access_check(snum, vuid, FILE_WRITE_DATA); + + if (!can_write) { + if (!share_access_check(snum, vuid, FILE_READ_DATA)) { + /* No access, read or write. */ + *ecode = ERRaccess; + DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n", + service )); + conn_free(conn); + return NULL; + } else { + conn->read_only = True; + } + } + } + { pstring list; StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1); |