/*
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 .
*/
#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 .
*/
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;
}