From f0dcc90f726e1232a4e0b74a03784281ea9a7cdc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Nov 2010 15:07:49 -0800 Subject: Fix bug 7781 - Samba transforms ShareName to lowercase (sharename) when adding new share via MMC Change the find_service() interface to not depend on fstring, and create a useable talloc-based interface. Jeremy. --- source3/include/proto.h | 2 +- source3/lib/dummysmbd.c | 2 +- source3/lib/util_str.c | 4 ++ source3/modules/vfs_xattr_tdb.c | 7 +-- source3/param/loadparm.c | 12 +--- source3/printing/nt_printing.c | 29 ++++++---- source3/rpc_server/srv_spoolss_nt.c | 9 +-- source3/rpc_server/srv_srvsvc_nt.c | 103 ++++++++++++++++++++++----------- source3/smbd/lanman.c | 7 ++- source3/smbd/msdfs.c | 8 ++- source3/smbd/service.c | 110 ++++++++++++++++++++++++------------ source3/smbd/smb2_tcon.c | 12 +++- 12 files changed, 195 insertions(+), 110 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index 3cae5ec94b..38c5a6d8fa 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -5356,7 +5356,7 @@ bool set_conn_connectpath(connection_struct *conn, const char *connectpath); bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir); void load_registry_shares(void); int add_home_service(const char *service, const char *username, const char *homedir); -int find_service(fstring service); +int find_service(TALLOC_CTX *ctx, const char *service, char **p_service_out); connection_struct *make_connection_snum(struct smbd_server_connection *sconn, int snum, user_struct *vuser, DATA_BLOB password, diff --git a/source3/lib/dummysmbd.c b/source3/lib/dummysmbd.c index 2ab0ed559d..2465e6552b 100644 --- a/source3/lib/dummysmbd.c +++ b/source3/lib/dummysmbd.c @@ -23,7 +23,7 @@ #include "includes.h" -int find_service(fstring service) +int find_service(TALLOC_CTX *ctx, const char *service_in, char **p_service_out) { return -1; } diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c index 508050d892..61b46edc5d 100644 --- a/source3/lib/util_str.c +++ b/source3/lib/util_str.c @@ -2307,6 +2307,10 @@ bool validate_net_name( const char *name, { int i; + if (!name) { + return false; + } + for ( i=0; idriver_name, r->version)); - fstrcpy(printdollar, "print$"); - - printdollar_snum = find_service(printdollar); + printdollar_snum = find_service(talloc_tos(), "print$", &printdollar); + if (!printdollar) { + return false; + } if (printdollar_snum == -1) { return false; } diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 62725ee95a..aafba01ef4 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -9629,7 +9629,7 @@ WERROR _spoolss_GetPrintProcessorDirectory(struct pipes_struct *p, struct spoolss_GetPrintProcessorDirectory *r) { WERROR result; - fstring prnproc_share; + char *prnproc_share = NULL; bool prnproc_share_exists = false; int snum; @@ -9650,9 +9650,10 @@ WERROR _spoolss_GetPrintProcessorDirectory(struct pipes_struct *p, * users are not forced to have a [prnproc$] share on the Samba spoolss * server, if users decide to do so, lets announce it though - Guenther */ - fstrcpy(prnproc_share, "prnproc$"); - - snum = find_service(prnproc_share); + snum = find_service(talloc_tos(), "prnproc$", &prnproc_share); + if (!prnproc_share) { + return WERR_NOMEM; + } if (snum != -1) { prnproc_share_exists = true; } diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index f59b972861..82b89390db 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -1412,15 +1412,20 @@ WERROR _srvsvc_NetShareGetInfo(struct pipes_struct *p, struct srvsvc_NetShareGetInfo *r) { WERROR status = WERR_OK; - fstring share_name; + char *share_name = NULL; int snum; union srvsvc_NetShareInfo *info = r->out.info; DEBUG(5,("_srvsvc_NetShareGetInfo: %d\n", __LINE__)); - fstrcpy(share_name, r->in.share_name); + if (!r->in.share_name) { + return WERR_INVALID_NAME; + } - snum = find_service(share_name); + snum = find_service(talloc_tos(), r->in.share_name, &share_name); + if (!share_name) { + return WERR_NOMEM; + } if (snum < 0) { return WERR_INVALID_NAME; } @@ -1543,26 +1548,28 @@ WERROR _srvsvc_NetShareSetInfo(struct pipes_struct *p, DEBUG(5,("_srvsvc_NetShareSetInfo: %d\n", __LINE__)); - share_name = talloc_strdup(p->mem_ctx, r->in.share_name); - if (!share_name) { - return WERR_NOMEM; + if (!r->in.share_name) { + return WERR_INVALID_NAME; } if (r->out.parm_error) { *r->out.parm_error = 0; } - if ( strequal(share_name,"IPC$") - || ( lp_enable_asu_support() && strequal(share_name,"ADMIN$") ) - || strequal(share_name,"global") ) + if ( strequal(r->in.share_name,"IPC$") + || ( lp_enable_asu_support() && strequal(r->in.share_name,"ADMIN$") ) + || strequal(r->in.share_name,"global") ) { DEBUG(5,("_srvsvc_NetShareSetInfo: share %s cannot be " "modified by a remote user.\n", - share_name )); + r->in.share_name )); return WERR_ACCESS_DENIED; } - snum = find_service(share_name); + snum = find_service(talloc_tos(), r->in.share_name, &share_name); + if (!share_name) { + return WERR_NOMEM; + } /* Does this share exist ? */ if (snum < 0) @@ -1756,6 +1763,7 @@ WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, struct srvsvc_NetShareAdd *r) { char *command = NULL; + char *share_name_in = NULL; char *share_name = NULL; char *comment = NULL; char *pathname = NULL; @@ -1792,7 +1800,7 @@ WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, /* Not enough info in a level 1 to do anything. */ return WERR_ACCESS_DENIED; case 2: - share_name = talloc_strdup(ctx, r->in.info->info2->name); + share_name_in = talloc_strdup(ctx, r->in.info->info2->name); comment = talloc_strdup(ctx, r->in.info->info2->comment); pathname = talloc_strdup(ctx, r->in.info->info2->path); max_connections = (r->in.info->info2->max_users == (uint32_t)-1) ? @@ -1803,7 +1811,7 @@ WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, /* No path. Not enough info in a level 501 to do anything. */ return WERR_ACCESS_DENIED; case 502: - share_name = talloc_strdup(ctx, r->in.info->info502->name); + share_name_in = talloc_strdup(ctx, r->in.info->info502->name); comment = talloc_strdup(ctx, r->in.info->info502->comment); pathname = talloc_strdup(ctx, r->in.info->info502->path); max_connections = (r->in.info->info502->max_users == (uint32_t)-1) ? @@ -1831,21 +1839,24 @@ WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, /* check for invalid share names */ - if (!share_name || !validate_net_name(share_name, + if (!share_name_in || !validate_net_name(share_name_in, INVALID_SHARENAME_CHARS, - strlen(share_name))) { + strlen(share_name_in))) { DEBUG(5,("_srvsvc_NetShareAdd: Bad sharename \"%s\"\n", - share_name ? share_name : "")); + share_name_in ? share_name_in : "")); return WERR_INVALID_NAME; } - if (strequal(share_name,"IPC$") || strequal(share_name,"global") + if (strequal(share_name_in,"IPC$") || strequal(share_name_in,"global") || (lp_enable_asu_support() && - strequal(share_name,"ADMIN$"))) { + strequal(share_name_in,"ADMIN$"))) { return WERR_ACCESS_DENIED; } - snum = find_service(share_name); + snum = find_service(ctx, share_name_in, &share_name); + if (!share_name) { + return WERR_NOMEM; + } /* Share already exists. */ if (snum >= 0) { @@ -1863,6 +1874,7 @@ WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, } /* Ensure share name, pathname and comment don't contain '"' characters. */ + string_replace(share_name_in, '"', ' '); string_replace(share_name, '"', ' '); string_replace(path, '"', ' '); if (comment) { @@ -1873,7 +1885,7 @@ WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, "%s \"%s\" \"%s\" \"%s\" \"%s\" %d", lp_add_share_cmd(), get_dyn_CONFIGFILE(), - share_name, + share_name_in, path, comment ? comment : "", max_connections); @@ -1910,6 +1922,8 @@ WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, return WERR_ACCESS_DENIED; if (psd) { + /* Note we use share_name here, not share_name_in as + we need a canonicalized name for setting security. */ if (!set_share_security(share_name, psd)) { DEBUG(0,("_srvsvc_NetShareAdd: Failed to add security info to share %s.\n", share_name )); @@ -1946,22 +1960,29 @@ WERROR _srvsvc_NetShareDel(struct pipes_struct *p, DEBUG(5,("_srvsvc_NetShareDel: %d\n", __LINE__)); - share_name = talloc_strdup(p->mem_ctx, r->in.share_name); - if (!share_name) { + if (!r->in.share_name) { return WERR_NET_NAME_NOT_FOUND; } - if ( strequal(share_name,"IPC$") - || ( lp_enable_asu_support() && strequal(share_name,"ADMIN$") ) - || strequal(share_name,"global") ) + + if ( strequal(r->in.share_name,"IPC$") + || ( lp_enable_asu_support() && strequal(r->in.share_name,"ADMIN$") ) + || strequal(r->in.share_name,"global") ) { return WERR_ACCESS_DENIED; } - if (!(params = get_share_params(p->mem_ctx, share_name))) { + snum = find_service(talloc_tos(), r->in.share_name, &share_name); + if (!share_name) { + return WERR_NOMEM; + } + + if (snum < 0) { return WERR_NO_SUCH_SHARE; } - snum = find_service(share_name); + if (!(params = get_share_params(p->mem_ctx, share_name))) { + return WERR_NO_SUCH_SHARE; + } /* No change to printer shares. */ if (lp_print_ok(snum)) @@ -2092,7 +2113,7 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p, struct smb_filename *smb_fname = NULL; struct security_descriptor *psd = NULL; size_t sd_size; - fstring servicename; + char *servicename = NULL; SMB_STRUCT_STAT st; NTSTATUS nt_status; WERROR werr; @@ -2104,9 +2125,15 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p, ZERO_STRUCT(st); - fstrcpy(servicename, r->in.share); - - snum = find_service(servicename); + if (!r->in.share) { + werr = WERR_NET_NAME_NOT_FOUND; + goto error_exit; + } + snum = find_service(talloc_tos(), r->in.share, &servicename); + if (!servicename) { + werr = WERR_NOMEM; + goto error_exit; + } if (snum == -1) { DEBUG(10, ("Could not find service %s\n", servicename)); werr = WERR_NET_NAME_NOT_FOUND; @@ -2222,7 +2249,7 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p, struct srvsvc_NetSetFileSecurity *r) { struct smb_filename *smb_fname = NULL; - fstring servicename; + char *servicename = NULL; files_struct *fsp = NULL; SMB_STRUCT_STAT st; NTSTATUS nt_status; @@ -2235,9 +2262,17 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p, ZERO_STRUCT(st); - fstrcpy(servicename, r->in.share); + if (!r->in.share) { + werr = WERR_NET_NAME_NOT_FOUND; + goto error_exit; + } + + snum = find_service(talloc_tos(), r->in.share, &servicename); + if (!servicename) { + werr = WERR_NOMEM; + goto error_exit; + } - snum = find_service(servicename); if (snum == -1) { DEBUG(10, ("Could not find service %s\n", servicename)); werr = WERR_NET_NAME_NOT_FOUND; diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index e5527a5812..fd8b0c7928 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -1994,7 +1994,8 @@ static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn, { char *str1 = get_safe_str_ptr(param,tpscnt,param,2); char *str2 = skip_string(param,tpscnt,str1); - char *netname = skip_string(param,tpscnt,str2); + char *netname_in = skip_string(param,tpscnt,str2); + char *netname = NULL; char *p = skip_string(param,tpscnt,netname); int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); int snum; @@ -2003,8 +2004,8 @@ static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn, return False; } - snum = find_service(netname); - if (snum < 0) { + snum = find_service(talloc_tos(), netname_in, &netname); + if (snum < 0 || !netname) { return False; } diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index c005a2f3ab..165e802a82 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -833,11 +833,13 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, /* Verify the share is a dfs root */ snum = lp_servicenumber(jucn->service_name); if(snum < 0) { - fstring service_name; - fstrcpy(service_name, jucn->service_name); - if ((snum = find_service(service_name)) < 0) { + char *service_name = NULL; + if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) { return NT_STATUS_NOT_FOUND; } + if (!service_name) { + return NT_STATUS_NO_MEMORY; + } TALLOC_FREE(jucn->service_name); jucn->service_name = talloc_strdup(ctx, service_name); if (!jucn->service_name) { diff --git a/source3/smbd/service.c b/source3/smbd/service.c index efe68d7c3f..5b6d9087a3 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -305,39 +305,47 @@ int add_home_service(const char *service, const char *username, const char *home * @param service is modified (to canonical form??) **/ -int find_service(fstring service) +int find_service(TALLOC_CTX *ctx, const char *service_in, char **p_service_out) { int iService; - all_string_sub(service,"\\","/",0); + if (!service_in) { + return -1; + } + + /* First make a copy. */ + *p_service_out = talloc_strdup(ctx, service_in); + if (!*p_service_out) { + return -1; + } - iService = lp_servicenumber(service); + all_string_sub(*p_service_out,"\\","/",0); + + iService = lp_servicenumber(*p_service_out); /* now handle the special case of a home directory */ if (iService < 0) { - char *phome_dir = get_user_home_dir(talloc_tos(), service); + char *phome_dir = get_user_home_dir(ctx, *p_service_out); if(!phome_dir) { - char *service_out = NULL; /* * Try mapping the servicename, it may * be a Windows to unix mapped user name. */ - if(map_username(talloc_tos(), service, &service_out)) { - if (service_out == NULL) { + if(map_username(ctx, *p_service_out, p_service_out)) { + if (*p_service_out == NULL) { /* Out of memory. */ return -1; } - fstrcpy(service, service_out); phome_dir = get_user_home_dir( - talloc_tos(), service); + ctx, *p_service_out); } } - DEBUG(3,("checking for home directory %s gave %s\n",service, + DEBUG(3,("checking for home directory %s gave %s\n",*p_service_out, phome_dir?phome_dir:"(NULL)")); - iService = add_home_service(service,service /* 'username' */, phome_dir); + iService = add_home_service(*p_service_out,*p_service_out /* 'username' */, phome_dir); } /* If we still don't have a service, attempt to add it as a printer. */ @@ -348,17 +356,22 @@ int find_service(fstring service) iPrinterService = load_registry_service(PRINTERS_NAME); } if (iPrinterService >= 0) { - DEBUG(3,("checking whether %s is a valid printer name...\n", service)); - if (pcap_printername_ok(service)) { - DEBUG(3,("%s is a valid printer name\n", service)); - DEBUG(3,("adding %s as a printer service\n", service)); - lp_add_printer(service, iPrinterService); - iService = lp_servicenumber(service); + DEBUG(3,("checking whether %s is a valid printer name...\n", + *p_service_out)); + if (pcap_printername_ok(*p_service_out)) { + DEBUG(3,("%s is a valid printer name\n", + *p_service_out)); + DEBUG(3,("adding %s as a printer service\n", + *p_service_out)); + lp_add_printer(*p_service_out, iPrinterService); + iService = lp_servicenumber(*p_service_out); if (iService < 0) { - DEBUG(0,("failed to add %s as a printer service!\n", service)); + DEBUG(0,("failed to add %s as a printer service!\n", + *p_service_out)); } } else { - DEBUG(3,("%s is not a valid printer name\n", service)); + DEBUG(3,("%s is not a valid printer name\n", + *p_service_out)); } } } @@ -368,27 +381,30 @@ int find_service(fstring service) } if (iService < 0) { - iService = load_registry_service(service); + iService = load_registry_service(*p_service_out); } /* Is it a usershare service ? */ if (iService < 0 && *lp_usershare_path()) { /* Ensure the name is canonicalized. */ - strlower_m(service); - iService = load_usershare_service(service); + strlower_m(*p_service_out); + iService = load_usershare_service(*p_service_out); } /* just possibly it's a default service? */ if (iService < 0) { char *pdefservice = lp_defaultservice(); - if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) { + if (pdefservice && + *pdefservice && + !strequal(pdefservice, *p_service_out) + && !strstr_m(*p_service_out,"..")) { /* * We need to do a local copy here as lp_defaultservice() * returns one of the rotating lp_string buffers that * could get overwritten by the recursive find_service() call * below. Fix from Josef Hinteregger . */ - char *defservice = SMB_STRDUP(pdefservice); + char *defservice = talloc_strdup(ctx, pdefservice); if (!defservice) { goto fail; @@ -398,30 +414,38 @@ int find_service(fstring service) if (strequal(defservice,HOMES_NAME) || strequal(defservice, PRINTERS_NAME) || strequal(defservice, "IPC$")) { - SAFE_FREE(defservice); + TALLOC_FREE(defservice); goto fail; } - iService = find_service(defservice); + iService = find_service(ctx, defservice, p_service_out); + if (!*p_service_out) { + TALLOC_FREE(defservice); + iService = -1; + goto fail; + } if (iService >= 0) { - all_string_sub(service, "_","/",0); - iService = lp_add_service(service, iService); + all_string_sub(*p_service_out, "_","/",0); + iService = lp_add_service(*p_service_out, iService); } - SAFE_FREE(defservice); + TALLOC_FREE(defservice); } } if (iService >= 0) { if (!VALID_SNUM(iService)) { - DEBUG(0,("Invalid snum %d for %s\n",iService, service)); + DEBUG(0,("Invalid snum %d for %s\n",iService, + *p_service_out)); iService = -1; } } fail: - if (iService < 0) - DEBUG(3,("find_service() failed to find service %s\n", service)); + if (iService < 0) { + DEBUG(3,("find_service() failed to find service %s\n", + *p_service_out)); + } return (iService); } @@ -1101,7 +1125,7 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, { uid_t euid; user_struct *vuser = NULL; - fstring service; + char *service = NULL; fstring dev; int snum = -1; @@ -1164,7 +1188,13 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, (void)map_username(talloc_tos(), current_user_info.smb_name, &unix_username); - snum = find_service(unix_username); + snum = find_service(talloc_tos(), + unix_username, + &unix_username); + if (!unix_username) { + *status = NT_STATUS_NO_MEMORY; + } + return NULL; } if (snum != -1) { DEBUG(5, ("making a connection to 'homes' " @@ -1188,11 +1218,19 @@ connection_struct *make_connection(struct smbd_server_connection *sconn, dev, status); } - fstrcpy(service, service_in); + service = talloc_strdup(talloc_tos(), service_in); + if (!service) { + *status = NT_STATUS_NO_MEMORY; + return NULL; + } strlower_m(service); - snum = find_service(service); + snum = find_service(talloc_tos(), service, &service); + if (!service) { + *status = NT_STATUS_NO_MEMORY; + return NULL; + } if (snum < 0) { if (strequal(service,"IPC$") || diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c index 203325e71a..82d9a28084 100644 --- a/source3/smbd/smb2_tcon.c +++ b/source3/smbd/smb2_tcon.c @@ -151,7 +151,7 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, uint32_t *out_tree_id) { const char *share = in_path; - fstring service; + char *service = NULL; int snum = -1; struct smbd_smb2_tcon *tcon; connection_struct *compat_conn = NULL; @@ -169,7 +169,10 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n", in_path, share)); - fstrcpy(service, share); + service = talloc_strdup(talloc_tos(), share); + if(!service) { + return NT_STATUS_NO_MEMORY; + } strlower_m(service); @@ -189,7 +192,10 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, lp_servicename(compat_vuser->homes_snum))) { snum = compat_vuser->homes_snum; } else { - snum = find_service(service); + snum = find_service(talloc_tos(), service, &service); + if (!service) { + return NT_STATUS_NO_MEMORY; + } } if (snum < 0) { -- cgit