/* This hardcoded value should go into a ldb database! */ enum srvsvc_ShareType dcesrv_common_get_share_type(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg) { /* for disk share 0x00000000 * for print share 0x00000001 * for IPC$ share 0x00000003 * * administrative shares: * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000 * this ones are hidden in NetShareEnum, but shown in NetShareEnumAll */ enum srvsvc_ShareType share_type = 0; const char *sharetype; if (!share_bool_option(scfg, SHARE_BROWSEABLE, SHARE_BROWSEABLE_DEFAULT)) { share_type |= STYPE_HIDDEN; } sharetype = share_string_option(scfg, SHARE_TYPE, SHARE_TYPE_DEFAULT); if (sharetype && strcasecmp(sharetype, "IPC") == 0) { share_type |= STYPE_IPC; return share_type; } if (sharetype && strcasecmp(sharetype, "PRINTER") == 0) { share_type |= STYPE_PRINTQ; return share_type; } share_type |= STYPE_DISKTREE; return share_type; }
/* connect to a share - used when a tree_connect operation comes in. For a disk based backend we needs to ensure that the base directory exists (tho it doesn't need to be accessible by the user, that comes later) */ static NTSTATUS svfs_connect(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, const char *sharename) { struct stat st; struct svfs_private *p; struct share_config *scfg = ntvfs->ctx->config; p = talloc(ntvfs, struct svfs_private); NT_STATUS_HAVE_NO_MEMORY(p); p->ntvfs = ntvfs; p->next_search_handle = 0; p->connectpath = talloc_strdup(p, share_string_option(scfg, SHARE_PATH, "")); p->open_files = NULL; p->search = NULL; /* the directory must exist */ if (stat(p->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", p->connectpath, sharename)); return NT_STATUS_BAD_NETWORK_NAME; } ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type); ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); ntvfs->private_data = p; return NT_STATUS_OK; }
/* connect to a share - used when a tree_connect operation comes in. For a disk based backend we needs to ensure that the base directory exists (tho it doesn't need to be accessible by the user, that comes later) */ static NTSTATUS svfs_connect(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_tcon* tcon) { struct stat st; struct svfs_private *p; struct share_config *scfg = ntvfs->ctx->config; const char *sharename; switch (tcon->generic.level) { case RAW_TCON_TCON: sharename = tcon->tcon.in.service; break; case RAW_TCON_TCONX: sharename = tcon->tconx.in.path; break; case RAW_TCON_SMB2: sharename = tcon->smb2.in.path; break; default: return NT_STATUS_INVALID_LEVEL; } if (strncmp(sharename, "\\\\", 2) == 0) { char *p2 = strchr(sharename+2, '\\'); if (p2) { sharename = p2 + 1; } } p = talloc(ntvfs, struct svfs_private); NT_STATUS_HAVE_NO_MEMORY(p); p->ntvfs = ntvfs; p->next_search_handle = 0; p->connectpath = talloc_strdup(p, share_string_option(scfg, SHARE_PATH, "")); p->open_files = NULL; p->search = NULL; /* the directory must exist */ if (stat(p->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", p->connectpath, sharename)); return NT_STATUS_BAD_NETWORK_NAME; } ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type); ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); if (tcon->generic.level == RAW_TCON_TCONX) { tcon->tconx.out.fs_type = ntvfs->ctx->fs_type; tcon->tconx.out.dev_type = ntvfs->ctx->dev_type; } ntvfs->private_data = p; return NT_STATUS_OK; }
/* initialise a system change notify backend */ _PUBLIC_ struct sys_notify_context *sys_notify_context_create(struct share_config *scfg, TALLOC_CTX *mem_ctx, struct tevent_context *ev) { struct sys_notify_context *ctx; const char *bname; int i; if (num_backends == 0) { return NULL; } if (ev == NULL) { return NULL; } ctx = talloc_zero(mem_ctx, struct sys_notify_context); if (ctx == NULL) { return NULL; } ctx->ev = ev; bname = share_string_option(scfg, NOTIFY_BACKEND, NULL); if (!bname) { if (num_backends) { bname = backends[0].name; } else { bname = "__unknown__"; } } for (i=0; i<num_backends; i++) { char *enable_opt_name; bool enabled; enable_opt_name = talloc_asprintf(mem_ctx, "notify:%s", backends[i].name); enabled = share_bool_option(scfg, enable_opt_name, true); talloc_free(enable_opt_name); if (!enabled) continue; if (strcasecmp(backends[i].name, bname) == 0) { bname = backends[i].name; break; } } ctx->name = bname; ctx->notify_watch = NULL; if (i < num_backends) { ctx->notify_watch = backends[i].notify_watch; } return ctx; }
/* initialise a system change notify backend */ _PUBLIC_ struct sys_lease_context *sys_lease_context_create(struct share_config *scfg, TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct messaging_context *msg, sys_lease_send_break_fn break_send) { struct sys_lease_context *ctx; const char *bname; int i; NTSTATUS status; if (num_backends == 0) { return NULL; } if (ev == NULL) { return NULL; } ctx = talloc_zero(mem_ctx, struct sys_lease_context); if (ctx == NULL) { return NULL; } ctx->event_ctx = ev; ctx->msg_ctx = msg; ctx->break_send = break_send; bname = share_string_option(scfg, LEASE_BACKEND, NULL); if (!bname) { talloc_free(ctx); return NULL; } for (i=0;i<num_backends;i++) { if (strcasecmp(backends[i].name, bname) == 0) { ctx->ops = &backends[i]; break; } } if (!ctx->ops) { talloc_free(ctx); return NULL; } status = ctx->ops->init(ctx); if (!NT_STATUS_IS_OK(status)) { talloc_free(ctx); return NULL; } return ctx; }
/**************************************************************************** Make a connection to a service. * * @param service ****************************************************************************/ static NTSTATUS make_connection(struct smbsrv_request *req, const char *service, DATA_BLOB password, const char *dev) { NTSTATUS status; enum ntvfs_type type; const char *type_str; struct share_config *scfg; const char *sharetype; /* the service might be of the form \\SERVER\SHARE. Should we put the server name we get from this somewhere? */ if (strncmp(service, "\\\\", 2) == 0) { char *p = strchr(service+2, '\\'); if (p) { service = p + 1; } } status = share_get_config(req, req->smb_conn->share_context, service, &scfg); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("make_connection: couldn't find service %s\n", service)); return NT_STATUS_BAD_NETWORK_NAME; } /* TODO: check the password, when it's share level security! */ if (!socket_check_access(req->smb_conn->connection->socket, scfg->name, share_string_list_option(req, scfg, SHARE_HOSTS_ALLOW), share_string_list_option(req, scfg, SHARE_HOSTS_DENY))) { return NT_STATUS_ACCESS_DENIED; } /* work out what sort of connection this is */ sharetype = share_string_option(scfg, "type", "DISK"); if (sharetype && strcmp(sharetype, "IPC") == 0) { type = NTVFS_IPC; type_str = "IPC"; } else if (sharetype && strcmp(sharetype, "PRINTER") == 0) { type = NTVFS_PRINT; type_str = "LPT:"; } else { type = NTVFS_DISK; type_str = "A:"; } if (strcmp(dev, "?????") != 0 && strcasecmp(type_str, dev) != 0) { /* the client gave us the wrong device type */ return NT_STATUS_BAD_DEVICE_TYPE; } return make_connection_scfg(req, scfg, type, password, dev); }
/* This hardcoded value should go into a ldb database! */ const char *dcesrv_common_get_share_path(TALLOC_CTX *mem_ctx, struct dcesrv_context *dce_ctx, struct share_config *scfg) { const char *sharetype; char *p; sharetype = share_string_option(scfg, SHARE_TYPE, SHARE_TYPE_DEFAULT); if (sharetype && strcasecmp(sharetype, "IPC") == 0) { return talloc_strdup(mem_ctx, ""); } p = talloc_strdup(mem_ctx, share_string_option(scfg, SHARE_PATH, "")); if (!p) { return NULL; } if (p[0] == '\0') { return p; } all_string_sub(p, "/", "\\", 0); return talloc_asprintf(mem_ctx, "C:%s", p); }
/* initialise a system change notify backend */ _PUBLIC_ struct sys_notify_context *sys_notify_context_create(struct share_config *scfg, TALLOC_CTX *mem_ctx, struct event_context *ev) { struct sys_notify_context *ctx; const char *bname; int i; if (num_backends == 0) { return NULL; } if (ev == NULL) { ev = event_context_find(mem_ctx); } ctx = talloc_zero(mem_ctx, struct sys_notify_context); if (ctx == NULL) { return NULL; } ctx->ev = ev; bname = share_string_option(scfg, NOTIFY_BACKEND, NULL); if (!bname) { if (num_backends) { bname = backends[0].name; } else { bname = "__unknown__"; } } for (i=0; i<num_backends; i++) { if (strcasecmp(backends[i].name, bname) == 0) { bname = backends[i].name; break; } } ctx->name = bname; ctx->notify_watch = NULL; if (i < num_backends) { ctx->notify_watch = backends[i].notify_watch; } return ctx; }
NTSTATUS rap_netshareenum(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, struct rap_NetShareEnum *r) { NTSTATUS nterr; const char **snames; struct share_context *sctx; struct share_config *scfg; int i, j, count; r->out.status = 0; r->out.available = 0; r->out.info = NULL; nterr = share_get_context_by_name(mem_ctx, lp_share_backend(lp_ctx), event_ctx, lp_ctx, &sctx); if (!NT_STATUS_IS_OK(nterr)) { return nterr; } nterr = share_list_all(mem_ctx, sctx, &count, &snames); if (!NT_STATUS_IS_OK(nterr)) { return nterr; } r->out.available = count; r->out.info = talloc_array(mem_ctx, union rap_shareenum_info, r->out.available); for (i = 0, j = 0; i < r->out.available; i++) { if (!NT_STATUS_IS_OK(share_get_config(mem_ctx, sctx, snames[i], &scfg))) { DEBUG(3, ("WARNING: Service [%s] disappeared after enumeration!\n", snames[i])); continue; } strncpy(r->out.info[j].info1.name, snames[i], sizeof(r->out.info[0].info1.name)); r->out.info[i].info1.pad = 0; r->out.info[i].info1.type = dcesrv_common_get_share_type(mem_ctx, NULL, scfg); r->out.info[i].info1.comment = talloc_strdup(mem_ctx, share_string_option(scfg, SHARE_COMMENT, "")); talloc_free(scfg); j++; } r->out.available = j; return NT_STATUS_OK; }
/* connect to a share - used when a tree_connect operation comes in. */ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_tcon *tcon) { NTSTATUS status; struct cvfs_private *p; const char *host, *user, *pass, *domain, *remote_share; struct smb_composite_connect io; struct composite_context *creq; struct share_config *scfg = ntvfs->ctx->config; struct cli_credentials *credentials; bool machine_account; bool s4u2proxy; const char* sharename; switch (tcon->generic.level) { case RAW_TCON_TCON: sharename = tcon->tcon.in.service; break; case RAW_TCON_TCONX: sharename = tcon->tconx.in.path; break; case RAW_TCON_SMB2: sharename = tcon->smb2.in.path; break; default: return NT_STATUS_INVALID_LEVEL; } if (strncmp(sharename, "\\\\", 2) == 0) { char *str = strchr(sharename+2, '\\'); if (str) { sharename = str + 1; } } /* Here we need to determine which server to connect to. * For now we use parametric options, type cifs. * Later we will use security=server and auth_server.c. */ host = share_string_option(scfg, CIFS_SERVER, NULL); user = share_string_option(scfg, CIFS_USER, NULL); pass = share_string_option(scfg, CIFS_PASSWORD, NULL); domain = share_string_option(scfg, CIFS_DOMAIN, NULL); remote_share = share_string_option(scfg, CIFS_SHARE, NULL); if (!remote_share) { remote_share = sharename; } machine_account = share_bool_option(scfg, CIFS_USE_MACHINE_ACCT, CIFS_USE_MACHINE_ACCT_DEFAULT); s4u2proxy = share_bool_option(scfg, CIFS_USE_S4U2PROXY, CIFS_USE_S4U2PROXY_DEFAULT); p = talloc_zero(ntvfs, struct cvfs_private); if (!p) { return NT_STATUS_NO_MEMORY; } ntvfs->private_data = p; if (!host) { DEBUG(1,("CIFS backend: You must supply server\n")); return NT_STATUS_INVALID_PARAMETER; } if (user && pass) { DEBUG(5, ("CIFS backend: Using specified password\n")); credentials = cli_credentials_init(p); if (!credentials) { return NT_STATUS_NO_MEMORY; } cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx); cli_credentials_set_username(credentials, user, CRED_SPECIFIED); if (domain) { cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); } cli_credentials_set_password(credentials, pass, CRED_SPECIFIED); } else if (machine_account) { DEBUG(5, ("CIFS backend: Using machine account\n")); credentials = cli_credentials_init(p); cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx); if (domain) { cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); } status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { return status; } } else if (req->session_info->credentials) { DEBUG(5, ("CIFS backend: Using delegated credentials\n")); credentials = req->session_info->credentials; } else if (s4u2proxy) { struct ccache_container *ccc = NULL; const char *err_str = NULL; int ret; char *impersonate_principal; char *self_service; char *target_service; impersonate_principal = talloc_asprintf(req, "%s@%s", req->session_info->info->account_name, req->session_info->info->domain_name); self_service = talloc_asprintf(req, "cifs/%s", lpcfg_netbios_name(ntvfs->ctx->lp_ctx)); target_service = talloc_asprintf(req, "cifs/%s", host); DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n")); credentials = cli_credentials_init(p); cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx); if (domain) { cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); } status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { return status; } cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); cli_credentials_set_impersonate_principal(credentials, impersonate_principal, self_service); cli_credentials_set_target_service(credentials, target_service); ret = cli_credentials_get_ccache(credentials, ntvfs->ctx->event_ctx, ntvfs->ctx->lp_ctx, &ccc, &err_str); if (ret != 0) { status = NT_STATUS_CROSSREALM_DELEGATION_FAILURE; DEBUG(1,("S4U2Proxy: cli_credentials_get_ccache() gave: ret[%d] str[%s] - %s\n", ret, err_str, nt_errstr(status))); return status; } } else { DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n")); return NT_STATUS_INTERNAL_ERROR; } /* connect to the server, using the smbd event context */ io.in.dest_host = host; io.in.dest_ports = lpcfg_smb_ports(ntvfs->ctx->lp_ctx); io.in.socket_options = lpcfg_socket_options(ntvfs->ctx->lp_ctx); io.in.called_name = host; io.in.credentials = credentials; io.in.fallback_to_anonymous = false; io.in.workgroup = lpcfg_workgroup(ntvfs->ctx->lp_ctx); io.in.service = remote_share; io.in.service_type = "?????"; io.in.gensec_settings = lpcfg_gensec_settings(p, ntvfs->ctx->lp_ctx); lpcfg_smbcli_options(ntvfs->ctx->lp_ctx, &io.in.options); lpcfg_smbcli_session_options(ntvfs->ctx->lp_ctx, &io.in.session_options); if (!(ntvfs->ctx->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS)) { io.in.options.use_level2_oplocks = false; } creq = smb_composite_connect_send(&io, p, lpcfg_resolve_context(ntvfs->ctx->lp_ctx), ntvfs->ctx->event_ctx); status = smb_composite_connect_recv(creq, p); NT_STATUS_NOT_OK_RETURN(status); p->tree = io.out.tree; p->transport = p->tree->session->transport; SETUP_PID; p->ntvfs = ntvfs; ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type); ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); if (tcon->generic.level == RAW_TCON_TCONX) { tcon->tconx.out.fs_type = ntvfs->ctx->fs_type; tcon->tconx.out.dev_type = ntvfs->ctx->dev_type; } /* we need to receive oplock break requests from the server */ smbcli_oplock_handler(p->transport, oplock_handler, p); p->map_generic = share_bool_option(scfg, CIFS_MAP_GENERIC, CIFS_MAP_GENERIC_DEFAULT); p->map_trans2 = share_bool_option(scfg, CIFS_MAP_TRANS2, CIFS_MAP_TRANS2_DEFAULT); return NT_STATUS_OK; }
/* setup config options for a posix share */ static void pvfs_setup_options(struct pvfs_state *pvfs) { struct share_config *scfg = pvfs->ntvfs->ctx->config; const char *eadb; bool def_perm_override = false; if (share_bool_option(scfg, SHARE_MAP_HIDDEN, SHARE_MAP_HIDDEN_DEFAULT)) pvfs->flags |= PVFS_FLAG_MAP_HIDDEN; if (share_bool_option(scfg, SHARE_MAP_ARCHIVE, SHARE_MAP_ARCHIVE_DEFAULT)) pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE; if (share_bool_option(scfg, SHARE_MAP_SYSTEM, SHARE_MAP_SYSTEM_DEFAULT)) pvfs->flags |= PVFS_FLAG_MAP_SYSTEM; if (share_bool_option(scfg, SHARE_READONLY, SHARE_READONLY_DEFAULT)) pvfs->flags |= PVFS_FLAG_READONLY; if (share_bool_option(scfg, SHARE_STRICT_SYNC, SHARE_STRICT_SYNC_DEFAULT)) pvfs->flags |= PVFS_FLAG_STRICT_SYNC; if (share_bool_option(scfg, SHARE_STRICT_LOCKING, SHARE_STRICT_LOCKING_DEFAULT)) pvfs->flags |= PVFS_FLAG_STRICT_LOCKING; if (share_bool_option(scfg, SHARE_CI_FILESYSTEM, SHARE_CI_FILESYSTEM_DEFAULT)) pvfs->flags |= PVFS_FLAG_CI_FILESYSTEM; if (share_bool_option(scfg, PVFS_FAKE_OPLOCKS, PVFS_FAKE_OPLOCKS_DEFAULT)) pvfs->flags |= PVFS_FLAG_FAKE_OPLOCKS; if (share_bool_option(scfg, PVFS_AIO, false)) pvfs->flags |= PVFS_FLAG_LINUX_AIO; #if defined(O_DIRECTORY) && defined(O_NOFOLLOW) /* set PVFS_PERM_OVERRIDE by default only if the system * supports the necessary capabilities to make it secure */ def_perm_override = true; #endif if (share_bool_option(scfg, PVFS_PERM_OVERRIDE, def_perm_override)) pvfs->flags |= PVFS_FLAG_PERM_OVERRIDE; /* file perm options */ pvfs->options.create_mask = share_int_option(scfg, SHARE_CREATE_MASK, SHARE_CREATE_MASK_DEFAULT); pvfs->options.dir_mask = share_int_option(scfg, SHARE_DIR_MASK, SHARE_DIR_MASK_DEFAULT); pvfs->options.force_dir_mode = share_int_option(scfg, SHARE_FORCE_DIR_MODE, SHARE_FORCE_DIR_MODE_DEFAULT); pvfs->options.force_create_mode = share_int_option(scfg, SHARE_FORCE_CREATE_MODE, SHARE_FORCE_CREATE_MODE_DEFAULT); /* this must be a power of 2 */ pvfs->alloc_size_rounding = share_int_option(scfg, PVFS_ALLOCATION_ROUNDING, PVFS_ALLOCATION_ROUNDING_DEFAULT); pvfs->search.inactivity_time = share_int_option(scfg, PVFS_SEARCH_INACTIVITY, PVFS_SEARCH_INACTIVITY_DEFAULT); #if HAVE_XATTR_SUPPORT if (share_bool_option(scfg, PVFS_XATTR, PVFS_XATTR_DEFAULT)) pvfs->flags |= PVFS_FLAG_XATTR_ENABLE; #endif pvfs->sharing_violation_delay = share_int_option(scfg, PVFS_SHARE_DELAY, PVFS_SHARE_DELAY_DEFAULT); pvfs->oplock_break_timeout = share_int_option(scfg, PVFS_OPLOCK_TIMEOUT, PVFS_OPLOCK_TIMEOUT_DEFAULT); pvfs->writetime_delay = share_int_option(scfg, PVFS_WRITETIME_DELAY, PVFS_WRITETIME_DELAY_DEFAULT); pvfs->share_name = talloc_strdup(pvfs, scfg->name); pvfs->fs_attribs = FS_ATTR_CASE_SENSITIVE_SEARCH | FS_ATTR_CASE_PRESERVED_NAMES | FS_ATTR_UNICODE_ON_DISK | FS_ATTR_SPARSE_FILES; /* allow xattrs to be stored in a external tdb */ eadb = share_string_option(scfg, PVFS_EADB, NULL); if (eadb != NULL) { pvfs->ea_db = tdb_wrap_open(pvfs, eadb, 50000, TDB_DEFAULT, O_RDWR|O_CREAT, 0600, pvfs->ntvfs->ctx->lp_ctx); if (pvfs->ea_db != NULL) { pvfs->flags |= PVFS_FLAG_XATTR_ENABLE; } else { DEBUG(0,("Failed to open eadb '%s' - %s\n", eadb, strerror(errno))); pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE; } } if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS; } if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { pvfs->fs_attribs |= FS_ATTR_PERSISTANT_ACLS; } pvfs->sid_cache.creator_owner = dom_sid_parse_talloc(pvfs, SID_CREATOR_OWNER); pvfs->sid_cache.creator_group = dom_sid_parse_talloc(pvfs, SID_CREATOR_GROUP); /* check if the system really supports xattrs */ if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { pvfs_xattr_probe(pvfs); } /* enable an ACL backend */ pvfs->acl_ops = pvfs_acl_backend_byname(share_string_option(scfg, PVFS_ACL, "xattr")); }
/* connect to a share - used when a tree_connect operation comes in. For a disk based backend we needs to ensure that the base directory exists (tho it doesn't need to be accessible by the user, that comes later) */ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_tcon* tcon) { struct pvfs_state *pvfs; struct stat st; char *base_directory; NTSTATUS status; const char *sharename; switch (tcon->generic.level) { case RAW_TCON_TCON: sharename = tcon->tcon.in.service; break; case RAW_TCON_TCONX: sharename = tcon->tconx.in.path; break; case RAW_TCON_SMB2: sharename = tcon->smb2.in.path; break; default: return NT_STATUS_INVALID_LEVEL; } if (strncmp(sharename, "\\\\", 2) == 0) { char *p = strchr(sharename+2, '\\'); if (p) { sharename = p + 1; } } /* * TODO: call this from ntvfs_posix_init() * but currently we don't have a lp_ctx there */ status = pvfs_acl_init(); NT_STATUS_NOT_OK_RETURN(status); pvfs = talloc_zero(ntvfs, struct pvfs_state); NT_STATUS_HAVE_NO_MEMORY(pvfs); /* for simplicity of path construction, remove any trailing slash now */ base_directory = talloc_strdup(pvfs, share_string_option(ntvfs->ctx->config, SHARE_PATH, "")); NT_STATUS_HAVE_NO_MEMORY(base_directory); if (strcmp(base_directory, "/") != 0) { trim_string(base_directory, NULL, "/"); } pvfs->ntvfs = ntvfs; pvfs->base_directory = base_directory; /* the directory must exist. Note that we deliberately don't check that it is readable */ if (stat(pvfs->base_directory, &st) != 0 || !S_ISDIR(st.st_mode)) { DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n", pvfs->base_directory, sharename)); return NT_STATUS_BAD_NETWORK_NAME; } ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type); ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); if (tcon->generic.level == RAW_TCON_TCONX) { tcon->tconx.out.fs_type = ntvfs->ctx->fs_type; tcon->tconx.out.dev_type = ntvfs->ctx->dev_type; } ntvfs->private_data = pvfs; pvfs->brl_context = brlock_init(pvfs, pvfs->ntvfs->ctx->server_id, pvfs->ntvfs->ctx->lp_ctx, pvfs->ntvfs->ctx->msg_ctx); if (pvfs->brl_context == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } pvfs->odb_context = odb_init(pvfs, pvfs->ntvfs->ctx); if (pvfs->odb_context == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* allow this to be NULL - we just disable change notify */ pvfs->notify_context = notify_init(pvfs, pvfs->ntvfs->ctx->server_id, pvfs->ntvfs->ctx->msg_ctx, pvfs->ntvfs->ctx->lp_ctx, pvfs->ntvfs->ctx->event_ctx, pvfs->ntvfs->ctx->config); pvfs->wbc_ctx = wbc_init(pvfs, pvfs->ntvfs->ctx->msg_ctx, pvfs->ntvfs->ctx->event_ctx); if (pvfs->wbc_ctx == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* allocate the search handle -> ptr tree */ pvfs->search.idtree = idr_init(pvfs); NT_STATUS_HAVE_NO_MEMORY(pvfs->search.idtree); status = pvfs_mangle_init(pvfs); NT_STATUS_NOT_OK_RETURN(status); pvfs_setup_options(pvfs); talloc_set_destructor(pvfs, pvfs_state_destructor); #ifdef SIGXFSZ /* who had the stupid idea to generate a signal on a large file write instead of just failing it!? */ BlockSignals(true, SIGXFSZ); #endif return NT_STATUS_OK; }
/* setup config options for a posix share */ static void pvfs_setup_options(struct pvfs_state *pvfs) { struct share_config *scfg = pvfs->ntvfs->ctx->config; const char *eadb; if (share_bool_option(scfg, SHARE_MAP_HIDDEN, SHARE_MAP_HIDDEN_DEFAULT)) pvfs->flags |= PVFS_FLAG_MAP_HIDDEN; if (share_bool_option(scfg, SHARE_MAP_ARCHIVE, SHARE_MAP_ARCHIVE_DEFAULT)) pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE; if (share_bool_option(scfg, SHARE_MAP_SYSTEM, SHARE_MAP_SYSTEM_DEFAULT)) pvfs->flags |= PVFS_FLAG_MAP_SYSTEM; if (share_bool_option(scfg, SHARE_READONLY, SHARE_READONLY_DEFAULT)) pvfs->flags |= PVFS_FLAG_READONLY; if (share_bool_option(scfg, SHARE_STRICT_SYNC, SHARE_STRICT_SYNC_DEFAULT)) pvfs->flags |= PVFS_FLAG_STRICT_SYNC; if (share_bool_option(scfg, SHARE_STRICT_LOCKING, SHARE_STRICT_LOCKING_DEFAULT)) pvfs->flags |= PVFS_FLAG_STRICT_LOCKING; if (share_bool_option(scfg, SHARE_CI_FILESYSTEM, SHARE_CI_FILESYSTEM_DEFAULT)) pvfs->flags |= PVFS_FLAG_CI_FILESYSTEM; if (share_bool_option(scfg, PVFS_FAKE_OPLOCKS, PVFS_FAKE_OPLOCKS_DEFAULT)) { pvfs->flags |= PVFS_FLAG_FAKE_OPLOCKS; } /* this must be a power of 2 */ pvfs->alloc_size_rounding = share_int_option(scfg, PVFS_ALLOCATION_ROUNDING, PVFS_ALLOCATION_ROUNDING_DEFAULT); pvfs->search.inactivity_time = share_int_option(scfg, PVFS_SEARCH_INACTIVITY, PVFS_SEARCH_INACTIVITY_DEFAULT); #if HAVE_XATTR_SUPPORT if (share_bool_option(scfg, PVFS_XATTR, PVFS_XATTR_DEFAULT)) pvfs->flags |= PVFS_FLAG_XATTR_ENABLE; #endif pvfs->sharing_violation_delay = share_int_option(scfg, PVFS_SHARE_DELAY, PVFS_SHARE_DELAY_DEFAULT); pvfs->share_name = talloc_strdup(pvfs, scfg->name); pvfs->fs_attribs = FS_ATTR_CASE_SENSITIVE_SEARCH | FS_ATTR_CASE_PRESERVED_NAMES | FS_ATTR_UNICODE_ON_DISK | FS_ATTR_SPARSE_FILES; /* allow xattrs to be stored in a external tdb */ eadb = share_string_option(scfg, PVFS_EADB, NULL); if (eadb != NULL) { pvfs->ea_db = tdb_wrap_open(pvfs, eadb, 50000, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); if (pvfs->ea_db != NULL) { pvfs->flags |= PVFS_FLAG_XATTR_ENABLE; } else { DEBUG(0,("Failed to open eadb '%s' - %s\n", eadb, strerror(errno))); pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE; } } if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS; } if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { pvfs->fs_attribs |= FS_ATTR_PERSISTANT_ACLS; } pvfs->sid_cache.creator_owner = dom_sid_parse_talloc(pvfs, SID_CREATOR_OWNER); pvfs->sid_cache.creator_group = dom_sid_parse_talloc(pvfs, SID_CREATOR_GROUP); /* check if the system really supports xattrs */ if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { pvfs_xattr_probe(pvfs); } /* enable an ACL backend */ pvfs->acl_ops = pvfs_acl_backend_byname(share_string_option(scfg, PVFS_ACL, "xattr")); }
/* connect to a share - used when a tree_connect operation comes in. For a disk based backend we needs to ensure that the base directory exists (tho it doesn't need to be accessible by the user, that comes later) */ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, const char *sharename) { struct pvfs_state *pvfs; struct stat st; char *base_directory; NTSTATUS status; pvfs = talloc_zero(ntvfs, struct pvfs_state); NT_STATUS_HAVE_NO_MEMORY(pvfs); /* for simplicity of path construction, remove any trailing slash now */ base_directory = talloc_strdup(pvfs, share_string_option(ntvfs->ctx->config, SHARE_PATH, "")); NT_STATUS_HAVE_NO_MEMORY(base_directory); if (strcmp(base_directory, "/") != 0) { trim_string(base_directory, NULL, "/"); } pvfs->ntvfs = ntvfs; pvfs->base_directory = base_directory; /* the directory must exist. Note that we deliberately don't check that it is readable */ if (stat(pvfs->base_directory, &st) != 0 || !S_ISDIR(st.st_mode)) { DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n", pvfs->base_directory, sharename)); return NT_STATUS_BAD_NETWORK_NAME; } ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type); ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); ntvfs->private_data = pvfs; pvfs->brl_context = brl_init(pvfs, pvfs->ntvfs->ctx->server_id, pvfs->ntvfs->ctx->msg_ctx); if (pvfs->brl_context == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } pvfs->odb_context = odb_init(pvfs, pvfs->ntvfs->ctx); if (pvfs->odb_context == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* allow this to be NULL - we just disable change notify */ pvfs->notify_context = notify_init(pvfs, pvfs->ntvfs->ctx->server_id, pvfs->ntvfs->ctx->msg_ctx, event_context_find(pvfs), pvfs->ntvfs->ctx->config); pvfs->sidmap = sidmap_open(pvfs); if (pvfs->sidmap == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* allocate the search handle -> ptr tree */ pvfs->search.idtree = idr_init(pvfs); NT_STATUS_HAVE_NO_MEMORY(pvfs->search.idtree); status = pvfs_mangle_init(pvfs); NT_STATUS_NOT_OK_RETURN(status); pvfs_setup_options(pvfs); talloc_set_destructor(pvfs, pvfs_state_destructor); #ifdef SIGXFSZ /* who had the stupid idea to generate a signal on a large file write instead of just failing it!? */ BlockSignals(True, SIGXFSZ); #endif return NT_STATUS_OK; }
static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon *io) { struct smbsrv_tcon *tcon; NTSTATUS status; enum ntvfs_type type; uint16_t type_smb2; uint32_t unknown2; const char *service = io->smb2.in.path; struct share_config *scfg; const char *sharetype; if (strncmp(service, "\\\\", 2) == 0) { const char *p = strchr(service+2, '\\'); if (p) { service = p + 1; } } status = share_get_config(req, req->smb_conn->share_context, service, &scfg); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smb2srv_tcon_backend: couldn't find service %s\n", service)); return NT_STATUS_BAD_NETWORK_NAME; } if (!socket_check_access(req->smb_conn->connection->socket, scfg->name, share_string_list_option(req, scfg, SHARE_HOSTS_ALLOW), share_string_list_option(req, scfg, SHARE_HOSTS_DENY))) { return NT_STATUS_ACCESS_DENIED; } /* work out what sort of connection this is */ sharetype = share_string_option(scfg, SHARE_TYPE, "DISK"); if (sharetype && strcmp(sharetype, "IPC") == 0) { type = NTVFS_IPC; type_smb2 = 0x0002; unknown2 = 0x00000030; } else if (sharetype && strcmp(sharetype, "PRINTER") == 0) { type = NTVFS_PRINT; type_smb2 = 0x0003; unknown2 = 0x00000000; } else { type = NTVFS_DISK; type_smb2 = 0x0001; unknown2 = 0x00000800; } tcon = smbsrv_smb2_tcon_new(req->session, scfg->name); if (!tcon) { DEBUG(0,("smb2srv_tcon_backend: Couldn't find free connection.\n")); return NT_STATUS_INSUFFICIENT_RESOURCES; } req->tcon = tcon; /* init ntvfs function pointers */ status = ntvfs_init_connection(tcon, scfg, type, req->smb_conn->negotiate.protocol, req->smb_conn->connection->event.ctx, req->smb_conn->connection->msg_ctx, req->smb_conn->connection->server_id, &tcon->ntvfs); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb2srv_tcon_backend: ntvfs_init_connection failed for service %s\n", scfg->name)); goto failed; } status = ntvfs_set_oplock_handler(tcon->ntvfs, smb2srv_send_oplock_break, tcon); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the oplock handler!\n")); goto failed; } status = ntvfs_set_addr_callbacks(tcon->ntvfs, smbsrv_get_my_addr, smbsrv_get_peer_addr, req->smb_conn); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the addr callbacks!\n")); goto failed; } status = ntvfs_set_handle_callbacks(tcon->ntvfs, smb2srv_handle_create_new, smb2srv_handle_make_valid, smb2srv_handle_destroy, smb2srv_handle_search_by_wire_key, smb2srv_handle_get_wire_key, tcon); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the handle callbacks!\n")); goto failed; } req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req, req->session->session_info, 0, /* TODO: fill in PID */ req->request_time, req, NULL, 0); if (!req->ntvfs) { status = NT_STATUS_NO_MEMORY; goto failed; } /* Invoke NTVFS connection hook */ status = ntvfs_connect(req->ntvfs, scfg->name); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smb2srv_tcon_backend: NTVFS ntvfs_connect() failed!\n")); goto failed; } io->smb2.out.unknown1 = type_smb2; /* 1 - DISK, 2 - Print, 3 - IPC */ io->smb2.out.unknown2 = unknown2; io->smb2.out.unknown3 = 0x00000000; io->smb2.out.access_mask= SEC_RIGHTS_FILE_ALL; io->smb2.out.tid = tcon->tid; return NT_STATUS_OK; failed: req->tcon = NULL; talloc_free(tcon); return status; }
/* connect to a share - used when a tree_connect operation comes in. */ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_tcon* tcon) { NTSTATUS status; struct cvfs_private *p; const char *host, *user, *pass, *domain, *remote_share, *sharename; struct share_config *scfg = ntvfs->ctx->config; struct smb2_tree *tree; struct cli_credentials *credentials; bool machine_account; struct smbcli_options options; switch (tcon->generic.level) { case RAW_TCON_TCON: sharename = tcon->tcon.in.service; break; case RAW_TCON_TCONX: sharename = tcon->tconx.in.path; break; case RAW_TCON_SMB2: sharename = tcon->smb2.in.path; break; default: return NT_STATUS_INVALID_LEVEL; } if (strncmp(sharename, "\\\\", 2) == 0) { char *str = strchr(sharename+2, '\\'); if (str) { sharename = str + 1; } } /* Here we need to determine which server to connect to. * For now we use parametric options, type cifs. */ host = share_string_option(scfg, SMB2_SERVER, NULL); user = share_string_option(scfg, SMB2_USER, NULL); pass = share_string_option(scfg, SMB2_PASSWORD, NULL); domain = share_string_option(scfg, SMB2_DOMAIN, NULL); remote_share = share_string_option(scfg, SMB2_SHARE, NULL); if (!remote_share) { remote_share = sharename; } machine_account = share_bool_option(scfg, SMB2_USE_MACHINE_ACCT, SMB2_USE_MACHINE_ACCT_DEFAULT); p = talloc_zero(ntvfs, struct cvfs_private); if (!p) { return NT_STATUS_NO_MEMORY; } ntvfs->private_data = p; if (!host) { DEBUG(1,("CIFS backend: You must supply server\n")); return NT_STATUS_INVALID_PARAMETER; } if (user && pass) { DEBUG(5, ("CIFS backend: Using specified password\n")); credentials = cli_credentials_init(p); if (!credentials) { return NT_STATUS_NO_MEMORY; } cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx); cli_credentials_set_username(credentials, user, CRED_SPECIFIED); if (domain) { cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); } cli_credentials_set_password(credentials, pass, CRED_SPECIFIED); } else if (machine_account) { DEBUG(5, ("CIFS backend: Using machine account\n")); credentials = cli_credentials_init(p); cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx); if (domain) { cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED); } status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { return status; } } else if (req->session_info->credentials) { DEBUG(5, ("CIFS backend: Using delegated credentials\n")); credentials = req->session_info->credentials; } else { DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n")); return NT_STATUS_INVALID_PARAMETER; } lpcfg_smbcli_options(ntvfs->ctx->lp_ctx, &options); status = smb2_connect(p, host, lpcfg_parm_string_list(p, ntvfs->ctx->lp_ctx, NULL, "smb2", "ports", NULL), remote_share, lpcfg_resolve_context(ntvfs->ctx->lp_ctx), credentials, &tree, ntvfs->ctx->event_ctx, &options, lpcfg_socket_options(ntvfs->ctx->lp_ctx), lpcfg_gensec_settings(p, ntvfs->ctx->lp_ctx)); NT_STATUS_NOT_OK_RETURN(status); status = smb2_get_roothandle(tree, &p->roothandle); NT_STATUS_NOT_OK_RETURN(status); p->tree = tree; p->transport = p->tree->session->transport; p->ntvfs = ntvfs; ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type); ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); if (tcon->generic.level == RAW_TCON_TCONX) { tcon->tconx.out.fs_type = ntvfs->ctx->fs_type; tcon->tconx.out.dev_type = ntvfs->ctx->dev_type; } /* we need to receive oplock break requests from the server */ /* TODO: enable oplocks smbcli_oplock_handler(p->transport, oplock_handler, p); */ return NT_STATUS_OK; }
NTSTATUS srvsvc_create_ntvfs_context(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, const char *share, struct ntvfs_context **_ntvfs) { NTSTATUS status; struct srvsvc_ntvfs_ctx *c; struct ntvfs_request *ntvfs_req; enum ntvfs_type type; struct share_context *sctx; struct share_config *scfg; const char *sharetype; union smb_tcon tcon; const struct tsocket_address *local_address; const struct tsocket_address *remote_address; status = share_get_context_by_name(mem_ctx, lpcfg_share_backend(dce_call->conn->dce_ctx->lp_ctx), dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, &sctx); if (!NT_STATUS_IS_OK(status)) { return status; } status = share_get_config(mem_ctx, sctx, share, &scfg); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("srvsvc_create_ntvfs_context: couldn't find service %s\n", share)); return status; } #if 0 /* TODO: fix access cecking */ if (!socket_check_access(dce_call->connection->socket, scfg->name, share_string_list_option(scfg, SHARE_HOSTS_ALLOW), share_string_list_option(scfg, SHARE_HOSTS_DENY))) { return NT_STATUS_ACCESS_DENIED; } #endif /* work out what sort of connection this is */ sharetype = share_string_option(scfg, SHARE_TYPE, SHARE_TYPE_DEFAULT); if (sharetype && strcmp(sharetype, "IPC") == 0) { type = NTVFS_IPC; } else if (sharetype && strcmp(sharetype, "PRINTER")) { type = NTVFS_PRINT; } else { type = NTVFS_DISK; } c = talloc(mem_ctx, struct srvsvc_ntvfs_ctx); NT_STATUS_HAVE_NO_MEMORY(c); /* init ntvfs function pointers */ status = ntvfs_init_connection(c, scfg, type, PROTOCOL_NT1, 0,/* ntvfs_client_caps */ dce_call->event_ctx, dce_call->conn->msg_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->server_id, &c->ntvfs); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("srvsvc_create_ntvfs_context: ntvfs_init_connection failed for service %s\n", scfg->name)); return status; } talloc_set_destructor(c, srvsvc_ntvfs_ctx_destructor); /* * NOTE: we only set the addr callbacks as we're not interesseted in oplocks or in getting file handles */ local_address = dcesrv_connection_get_local_address(dce_call->conn); remote_address = dcesrv_connection_get_remote_address(dce_call->conn); status = ntvfs_set_addresses(c->ntvfs, local_address, remote_address); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("srvsvc_create_ntvfs_context: NTVFS failed to set the addr callbacks!\n")); return status; } ntvfs_req = ntvfs_request_create(c->ntvfs, mem_ctx, dce_call->conn->auth_state.session_info, 0, /* TODO: fill in PID */ dce_call->time, NULL, NULL, 0); NT_STATUS_HAVE_NO_MEMORY(ntvfs_req); /* Invoke NTVFS connection hook */ tcon.tcon.level = RAW_TCON_TCON; ZERO_STRUCT(tcon.tcon.in); tcon.tcon.in.service = scfg->name; status = ntvfs_connect(ntvfs_req, &tcon); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("srvsvc_create_ntvfs_context: NTVFS ntvfs_connect() failed!\n")); return status; } *_ntvfs = c->ntvfs; return NT_STATUS_OK; }