diff options
Diffstat (limited to 'source3/param/service.c')
-rw-r--r-- | source3/param/service.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/source3/param/service.c b/source3/param/service.c new file mode 100644 index 0000000..b06a2fb --- /dev/null +++ b/source3/param/service.c @@ -0,0 +1,335 @@ +/* + Unix SMB/CIFS implementation. + service (connection) opening and closing + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/filesys.h" +#include "../lib/tsocket/tsocket.h" +#include "smbd/smbd.h" +#include "smbd/globals.h" +#include "../librpc/gen_ndr/netlogon.h" +#include "../libcli/security/security.h" +#include "printing/pcap.h" +#include "printing/printer_list.h" +#include "passdb/lookup_sid.h" +#include "auth.h" +#include "lib/param/loadparm.h" + +static int load_registry_service(const char *servicename) +{ + if (!lp_registry_shares()) { + return -1; + } + + if ((servicename == NULL) || (*servicename == '\0')) { + return -1; + } + + if (strequal(servicename, GLOBAL_NAME)) { + return -2; + } + + if (!process_registry_service(servicename)) { + return -1; + } + + return lp_servicenumber(servicename); +} + +void load_registry_shares(void) +{ + DEBUG(8, ("load_registry_shares()\n")); + if (!lp_registry_shares()) { + return; + } + + process_registry_shares(); + + return; +} + +/**************************************************************************** + Add a home service. Returns the new service number or -1 if fail. +****************************************************************************/ + +int add_home_service(const char *service, const char *username, const char *homedir) +{ + int iHomeService; + + if (!service || !homedir || homedir[0] == '\0') + return -1; + + if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0) { + if ((iHomeService = load_registry_service(HOMES_NAME)) < 0) { + return -1; + } + } + + /* + * If this is a winbindd provided username, remove + * the domain component before adding the service. + * Log a warning if the "path=" parameter does not + * include any macros. + */ + + { + const char *p = strchr(service,*lp_winbind_separator()); + + /* We only want the 'user' part of the string */ + if (p) { + service = p + 1; + } + } + + if (!lp_add_home(service, iHomeService, username, homedir)) { + return -1; + } + + return lp_servicenumber(service); + +} + +/** + * Find a service entry. + * + * @param service is modified (to canonical form??) + **/ + +int find_service(TALLOC_CTX *ctx, const char *service_in, char **p_service_out) +{ + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); + int iService; + + if (!service_in) { + return -1; + } + + /* First make a copy. */ + *p_service_out = talloc_strdup(ctx, service_in); + if (!*p_service_out) { + return -1; + } + + all_string_sub(*p_service_out,"\\","/",0); + + iService = lp_servicenumber(*p_service_out); + + /* + * check for whether the service is a registry share before + * handling home directories. This is to ensure that + * that in the case service name is identical to a user's + * home directory, the explicit service is preferred. + */ + if (iService < 0) { + iService = load_registry_service(*p_service_out); + } + + /* now handle the special case of a home directory */ + if (iService < 0) { + char *phome_dir = get_user_home_dir(ctx, *p_service_out); + + if(!phome_dir) { + /* + * Try mapping the servicename, it may + * be a Windows to unix mapped user name. + */ + if(map_username(ctx, *p_service_out, p_service_out)) { + if (*p_service_out == NULL) { + /* Out of memory. */ + return -1; + } + phome_dir = get_user_home_dir( + ctx, *p_service_out); + } + } + + DEBUG(3,("checking for home directory %s gave %s\n",*p_service_out, + phome_dir?phome_dir:"(NULL)")); + + if (!strequal(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. */ + if (iService < 0) { + int iPrinterService; + + if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) < 0) { + iPrinterService = load_registry_service(PRINTERS_NAME); + } + if (iPrinterService >= 0) { + DEBUG(3,("checking whether %s is a valid printer name...\n", + *p_service_out)); + if (printer_list_printername_exists(*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", + *p_service_out)); + } + } else { + DEBUG(3,("%s is not a valid printer name\n", + *p_service_out)); + } + } + } + + /* Is it a usershare service ? */ + if (iService < 0 && *lp_usershare_path(talloc_tos(), lp_sub)) { + /* Ensure the name is canonicalized. */ + if (!strlower_m(*p_service_out)) { + goto fail; + } + iService = load_usershare_service(*p_service_out); + } + + /* just possibly it's a default service? */ + if (iService < 0) { + char *pdefservice = lp_defaultservice(talloc_tos(), lp_sub); + 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 <joehtg@joehtg.co.at>. + */ + char *defservice = talloc_strdup(ctx, pdefservice); + + if (!defservice) { + goto fail; + } + + /* Disallow anything except explicit share names. */ + if (strequal(defservice,HOMES_NAME) || + strequal(defservice, PRINTERS_NAME) || + strequal(defservice, "IPC$")) { + TALLOC_FREE(defservice); + goto fail; + } + + 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(*p_service_out, "_","/",0); + iService = lp_add_service(*p_service_out, iService); + } + TALLOC_FREE(defservice); + } + } + + if (iService >= 0) { + if (!VALID_SNUM(iService)) { + 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", + *p_service_out)); + } + + return (iService); +} + +bool lp_allow_local_address( + int snum, const struct tsocket_address *local_address) +{ + bool is_inet = tsocket_address_is_inet(local_address, "ip"); + const char **server_addresses = lp_server_addresses(snum); + char *local = NULL; + ssize_t i; + + if (!is_inet) { + return false; + } + + if (server_addresses == NULL) { + return true; + } + + local = tsocket_address_inet_addr_string(local_address, talloc_tos()); + if (local == NULL) { + return false; + } + + for (i=0; server_addresses[i] != NULL; i++) { + struct tsocket_address *server_addr = NULL; + char *server_addr_string = NULL; + bool equal; + int ret; + + /* + * Go through struct tsocket_address to normalize the + * string representation + */ + + ret = tsocket_address_inet_from_strings( + talloc_tos(), + "ip", + server_addresses[i], + 0, + &server_addr); + if (ret == -1) { + DBG_WARNING("tsocket_address_inet_from_strings " + "failed for %s: %s, ignoring\n", + server_addresses[i], + strerror(errno)); + continue; + } + + server_addr_string = tsocket_address_inet_addr_string( + server_addr, talloc_tos()); + TALLOC_FREE(server_addr); + if (server_addr_string == NULL) { + DBG_ERR("tsocket_address_inet_addr_string failed " + "for %s, ignoring\n", + server_addresses[i]); + continue; + } + + equal = strequal(local, server_addr_string); + TALLOC_FREE(server_addr_string); + + if (equal) { + TALLOC_FREE(local); + return true; + } + } + + TALLOC_FREE(local); + return false; +} |