uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p, struct fss_PrepareShadowCopySet *r) { struct fss_sc_set *sc_set; if (!fss_permitted(p)) { return HRES_ERROR_V(HRES_E_ACCESSDENIED); } sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId); if (sc_set == NULL) { return HRES_ERROR_V(HRES_E_INVALIDARG); } if (sc_set->state != FSS_SC_ADDED) { return FSRVP_E_BAD_STATE; } /* stop msg sequence timer */ TALLOC_FREE(fss_global.seq_tmr); /* * Windows Server "8" Beta takes ~60s here, presumably flushing * everything to disk. We may want to do something similar. */ /* start msg sequence timer, 1800 on success */ fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr); return 0; }
uint32_t _fss_IsPathSupported(struct pipes_struct *p, struct fss_IsPathSupported *r) { int snum; char *service; char *base_vol; NTSTATUS status; struct connection_struct *conn; char *share; TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx); if (tmp_ctx == NULL) { return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } if (!fss_permitted(p)) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_ACCESSDENIED); } status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return fss_ntstatus_map(status); } snum = find_service(tmp_ctx, share, &service); if ((snum == -1) || (service == NULL)) { DEBUG(0, ("share at %s not found\n", r->in.ShareName)); talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } status = fss_vfs_conn_create(tmp_ctx, server_event_context(), p->msg_ctx, p->session_info, snum, &conn); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_ACCESSDENIED); } if (!become_user_by_session(conn, p->session_info)) { DEBUG(0, ("failed to become user\n")); talloc_free(tmp_ctx); fss_vfs_conn_destroy(conn); return HRES_ERROR_V(HRES_E_ACCESSDENIED); } status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, lp_path(tmp_ctx, snum), &base_vol); unbecome_user(); fss_vfs_conn_destroy(conn); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return FSRVP_E_NOT_SUPPORTED; } *r->out.OwnerMachineName = lp_netbios_name(); *r->out.SupportedByThisProvider = 1; talloc_free(tmp_ctx); return 0; }
static uint32_t map_share_name(struct fss_sc_smap *sc_smap, const struct fss_sc *sc) { bool hidden_base = false; if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') { /* * If MappedShare.ShareName ends with a $ character (meaning * that the share is hidden), then the exposed share name will * have the $ suffix appended. * FIXME: turns out Windows doesn't do this, contrary to docs */ hidden_base = true; } sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s", sc_smap->share_name, sc->id_str, hidden_base ? "$" : ""); if (sc_smap->sc_share_name == NULL) { return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } return 0; }
static uint32_t map_share_comment(struct fss_sc_smap *sc_smap, const struct fss_sc *sc) { char *time_str; time_str = http_timestring(sc_smap, sc->create_ts); if (time_str == NULL) { return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s", sc_smap->share_name, time_str); if (sc_smap->sc_share_comment == NULL) { return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } return 0; }
uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p, struct fss_IsPathShadowCopied *r) { if (!fss_permitted(p)) { return HRES_ERROR_V(HRES_E_ACCESSDENIED); } /* not yet supported */ return FSRVP_E_NOT_SUPPORTED; }
uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p, struct fss_AbortShadowCopySet *r) { NTSTATUS status; struct fss_sc_set *sc_set; if (!fss_permitted(p)) { return HRES_ERROR_V(HRES_E_ACCESSDENIED); } sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId); if (sc_set == NULL) { return HRES_ERROR_V(HRES_E_INVALIDARG); } DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str)); if ((sc_set->state == FSS_SC_COMMITED) || (sc_set->state == FSS_SC_EXPOSED) || (sc_set->state == FSS_SC_RECOVERED)) { return 0; } if (sc_set->state == FSS_SC_CREATING) { return FSRVP_E_BAD_STATE; } DLIST_REMOVE(fss_global.sc_sets, sc_set); talloc_free(sc_set); fss_global.sc_sets_count--; become_root(); status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets, fss_global.sc_sets_count, fss_global.db_path); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("failed to store fss server state: %s\n", nt_errstr(status))); } return 0; }
uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p, struct fss_RecoveryCompleteShadowCopySet *r) { NTSTATUS status; struct fss_sc_set *sc_set; if (!fss_permitted(p)) { return HRES_ERROR_V(HRES_E_ACCESSDENIED); } sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId); if (sc_set == NULL) { return HRES_ERROR_V(HRES_E_INVALIDARG); } if (sc_set->state != FSS_SC_EXPOSED) { return FSRVP_E_BAD_STATE; } /* stop msg sequence timer */ TALLOC_FREE(fss_global.seq_tmr); if (sc_set->context & ATTR_NO_AUTO_RECOVERY) { /* TODO set read-only */ } sc_set->state = FSS_SC_RECOVERED; fss_global.cur_ctx = 0; fss_global.ctx_set = false; become_root(); status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets, fss_global.sc_sets_count, fss_global.db_path); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("failed to store fss server state: %s\n", nt_errstr(status))); } return 0; }
uint32_t _fss_GetSupportedVersion(struct pipes_struct *p, struct fss_GetSupportedVersion *r) { if (!fss_permitted(p)) { return HRES_ERROR_V(HRES_E_ACCESSDENIED); } *r->out.MinVersion = fss_global.min_vers; *r->out.MaxVersion = fss_global.max_vers; return 0; }
static uint32_t fss_ntstatus_map(NTSTATUS status) { int i; if (NT_STATUS_IS_OK(status)) return 0; /* check fsrvp specific errors first */ for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) { if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) { return ntstatus_to_fsrvp_map[i].fsrvp_err; } } /* fall-back to generic hresult values */ for (i = 0; i < ARRAY_SIZE(ntstatus_to_hres_map); i++) { if (NT_STATUS_EQUAL(status, ntstatus_to_hres_map[i].status)) { return HRES_ERROR_V(ntstatus_to_hres_map[i].hres); } } return HRES_ERROR_V(HRES_E_FAIL); }
uint32_t _fss_SetContext(struct pipes_struct *p, struct fss_SetContext *r) { if (!fss_permitted(p)) { return HRES_ERROR_V(HRES_E_ACCESSDENIED); } /* ATTR_AUTO_RECOVERY flag can be applied to any */ switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) { case FSRVP_CTX_BACKUP: DEBUG(6, ("fss ctx set backup\n")); break; case FSRVP_CTX_FILE_SHARE_BACKUP: DEBUG(6, ("fss ctx set file share backup\n")); break; case FSRVP_CTX_NAS_ROLLBACK: DEBUG(6, ("fss ctx set nas rollback\n")); break; case FSRVP_CTX_APP_ROLLBACK: DEBUG(6, ("fss ctx set app rollback\n")); break; default: DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context)); return HRES_ERROR_V(HRES_E_INVALIDARG); break; /* not reached */ } fss_global.ctx_set = true; fss_global.cur_ctx = r->in.Context; TALLOC_FREE(fss_global.seq_tmr); /* kill timer if running */ fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr); fss_global.cur_ctx = r->in.Context; return 0; }
uint32_t _fss_StartShadowCopySet(struct pipes_struct *p, struct fss_StartShadowCopySet *r) { struct fss_sc_set *sc_set; uint32_t ret; if (!fss_permitted(p)) { ret = HRES_ERROR_V(HRES_E_ACCESSDENIED); goto err_out; } if (!fss_global.ctx_set) { DEBUG(3, ("invalid sequence: start sc set requested without " "prior context set\n")); ret = FSRVP_E_BAD_STATE; goto err_out; } /* * At any given time, Windows servers allow only one shadow copy set to * be going through the creation process. */ if (sc_set_active(fss_global.sc_sets)) { DEBUG(3, ("StartShadowCopySet called while in progress\n")); ret = FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS; goto err_out; } /* stop msg seq timer */ TALLOC_FREE(fss_global.seq_tmr); sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set); if (sc_set == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_tmr_restart; } sc_set->id = GUID_random(); /* Windows servers ignore client ids */ sc_set->id_str = GUID_string(sc_set, &sc_set->id); if (sc_set->id_str == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_sc_set_free; } sc_set->state = FSS_SC_STARTED; sc_set->context = fss_global.cur_ctx; DLIST_ADD_END(fss_global.sc_sets, sc_set, struct fss_sc_set *); fss_global.sc_sets_count++; DEBUG(6, ("%s: shadow-copy set %u added\n", sc_set->id_str, fss_global.sc_sets_count)); /* start msg seq timer */ fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr); r->out.pShadowCopySetId = &sc_set->id; return 0; err_sc_set_free: talloc_free(sc_set); err_tmr_restart: fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr); err_out: return ret; }
static bool test_fsrvp_sc_create(struct torture_context *tctx, struct dcerpc_pipe *p, const char *share, enum test_fsrvp_inject inject, struct fssagent_share_mapping_1 **sc_map) { struct fss_IsPathSupported r_pathsupport_get; struct fss_GetSupportedVersion r_version_get; struct fss_SetContext r_context_set; struct fss_StartShadowCopySet r_scset_start; struct fss_AddToShadowCopySet r_scset_add1; struct fss_AddToShadowCopySet r_scset_add2; struct fss_PrepareShadowCopySet r_scset_prep; struct fss_CommitShadowCopySet r_scset_commit; struct fss_ExposeShadowCopySet r_scset_expose; struct fss_GetShareMapping r_sharemap_get; struct dcerpc_binding_handle *b = p->binding_handle; NTSTATUS status; time_t start_time; TALLOC_CTX *tmp_ctx = talloc_new(tctx); struct fssagent_share_mapping_1 *map = NULL; int sleep_time; /* * PrepareShadowCopySet & CommitShadowCopySet often exceed the default * 60 second dcerpc request timeout against Windows Server "8" Beta. */ dcerpc_binding_handle_set_timeout(b, 240); ZERO_STRUCT(r_pathsupport_get); r_pathsupport_get.in.ShareName = share; status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get); torture_assert_ntstatus_ok(tctx, status, "IsPathSupported failed"); torture_assert_int_equal(tctx, r_pathsupport_get.out.result, 0, "failed IsPathSupported response"); torture_assert(tctx, r_pathsupport_get.out.SupportedByThisProvider, "path not supported"); ZERO_STRUCT(r_version_get); status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get); torture_assert_ntstatus_ok(tctx, status, "GetSupportedVersion failed"); torture_assert_int_equal(tctx, r_version_get.out.result, 0, "failed GetSupportedVersion response"); ZERO_STRUCT(r_context_set); r_context_set.in.Context = FSRVP_CTX_BACKUP; status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set); torture_assert_ntstatus_ok(tctx, status, "SetContext failed"); torture_assert_int_equal(tctx, r_context_set.out.result, 0, "failed SetContext response"); if (inject == TEST_FSRVP_TOUT_SET_CTX) { sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss", "sequence timeout", 180); torture_comment(tctx, "sleeping for %d\n", sleep_time); smb_msleep((sleep_time * 1000) + 500); } ZERO_STRUCT(r_scset_start); r_scset_start.in.ClientShadowCopySetId = GUID_random(); status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start); torture_assert_ntstatus_ok(tctx, status, "StartShadowCopySet failed"); if (inject == TEST_FSRVP_TOUT_SET_CTX) { /* expect error due to message sequence timeout after set_ctx */ torture_assert_int_equal(tctx, r_scset_start.out.result, FSRVP_E_BAD_STATE, "StartShadowCopySet timeout response"); goto done; } torture_assert_int_equal(tctx, r_scset_start.out.result, 0, "failed StartShadowCopySet response"); torture_comment(tctx, "%s: shadow-copy set created\n", GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId)); if (inject == TEST_FSRVP_TOUT_START_SET) { sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss", "sequence timeout", 180); torture_comment(tctx, "sleeping for %d\n", sleep_time); smb_msleep((sleep_time * 1000) + 500); } ZERO_STRUCT(r_scset_add1); r_scset_add1.in.ClientShadowCopyId = GUID_random(); r_scset_add1.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; r_scset_add1.in.ShareName = share; status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add1); torture_assert_ntstatus_ok(tctx, status, "AddToShadowCopySet failed"); if (inject == TEST_FSRVP_TOUT_START_SET) { torture_assert_int_equal(tctx, r_scset_add1.out.result, HRES_ERROR_V(HRES_E_INVALIDARG), "AddToShadowCopySet timeout response"); goto done; } torture_assert_int_equal(tctx, r_scset_add1.out.result, 0, "failed AddToShadowCopySet response"); torture_comment(tctx, "%s(%s): %s added to shadow-copy set\n", GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId), GUID_string(tmp_ctx, r_scset_add1.out.pShadowCopyId), r_scset_add1.in.ShareName); /* attempts to add the same share twice should fail */ ZERO_STRUCT(r_scset_add2); r_scset_add2.in.ClientShadowCopyId = GUID_random(); r_scset_add2.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; r_scset_add2.in.ShareName = share; status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add2); torture_assert_ntstatus_ok(tctx, status, "AddToShadowCopySet failed"); torture_assert_int_equal(tctx, r_scset_add2.out.result, FSRVP_E_OBJECT_ALREADY_EXISTS, "failed AddToShadowCopySet response"); if (inject == TEST_FSRVP_TOUT_ADD_TO_SET) { sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss", "sequence timeout", 1800); torture_comment(tctx, "sleeping for %d\n", sleep_time); smb_msleep((sleep_time * 1000) + 500); } start_time = time_mono(NULL); ZERO_STRUCT(r_scset_prep); r_scset_prep.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; // r_scset_prep.in.TimeOutInMilliseconds = (1800 * 1000); /* win8 */ r_scset_prep.in.TimeOutInMilliseconds = (240 * 1000); status = dcerpc_fss_PrepareShadowCopySet_r(b, tmp_ctx, &r_scset_prep); torture_assert_ntstatus_ok(tctx, status, "PrepareShadowCopySet failed"); if (inject == TEST_FSRVP_TOUT_ADD_TO_SET) { torture_assert_int_equal(tctx, r_scset_prep.out.result, HRES_ERROR_V(HRES_E_INVALIDARG), "PrepareShadowCopySet tout response"); goto done; } torture_assert_int_equal(tctx, r_scset_prep.out.result, 0, "failed PrepareShadowCopySet response"); torture_comment(tctx, "%s: prepare completed in %llu secs\n", GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId), (unsigned long long)(time_mono(NULL) - start_time)); if (inject == TEST_FSRVP_TOUT_PREPARE) { sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss", "sequence timeout", 1800); torture_comment(tctx, "sleeping for %d\n", sleep_time); smb_msleep((sleep_time * 1000) + 500); } start_time = time_mono(NULL); ZERO_STRUCT(r_scset_commit); r_scset_commit.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; r_scset_commit.in.TimeOutInMilliseconds = (180 * 1000); /* win8 */ status = dcerpc_fss_CommitShadowCopySet_r(b, tmp_ctx, &r_scset_commit); torture_assert_ntstatus_ok(tctx, status, "CommitShadowCopySet failed"); if (inject == TEST_FSRVP_TOUT_PREPARE) { torture_assert_int_equal(tctx, r_scset_commit.out.result, HRES_ERROR_V(HRES_E_INVALIDARG), "CommitShadowCopySet tout response"); goto done; } torture_assert_int_equal(tctx, r_scset_commit.out.result, 0, "failed CommitShadowCopySet response"); torture_comment(tctx, "%s: commit completed in %llu secs\n", GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId), (unsigned long long)(time_mono(NULL) - start_time)); if (inject == TEST_FSRVP_TOUT_COMMIT) { sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss", "sequence timeout", 180); torture_comment(tctx, "sleeping for %d\n", sleep_time); smb_msleep((sleep_time * 1000) + 500); } else if (inject == TEST_FSRVP_STOP_B4_EXPOSE) { /* return partial snapshot information */ map = talloc_zero(tctx, struct fssagent_share_mapping_1); map->ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; map->ShadowCopyId = *r_scset_add1.out.pShadowCopyId; goto done; }
uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p, struct fss_ExposeShadowCopySet *r) { NTSTATUS status; struct fss_sc_set *sc_set; struct fss_sc *sc; uint32_t ret; struct smbconf_ctx *fconf_ctx; struct smbconf_ctx *rconf_ctx; sbcErr cerr; char *fconf_path; TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx); if (tmp_ctx == NULL) { return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } if (!fss_permitted(p)) { ret = HRES_ERROR_V(HRES_E_ACCESSDENIED); goto err_out; } sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId); if (sc_set == NULL) { ret = HRES_ERROR_V(HRES_E_INVALIDARG); goto err_out; } if (sc_set->state != FSS_SC_COMMITED) { ret = FSRVP_E_BAD_STATE; goto err_out; } /* stop message sequence timer */ TALLOC_FREE(fss_global.seq_tmr); /* * Prepare to clone the base share definition for the snapshot share. * Create both registry and file conf contexts, as the base share * definition may be located in either. The snapshot share definition * is always written to the registry. */ cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry"); if (!SBC_ERROR_IS_OK(cerr)) { DEBUG(0, ("failed registry smbconf init: %s\n", sbcErrorString(cerr))); ret = HRES_ERROR_V(HRES_E_FAIL); goto err_tmr_restart; } fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE()); if (fconf_path == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_tmr_restart; } cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path); if (!SBC_ERROR_IS_OK(cerr)) { DEBUG(0, ("failed %s smbconf init: %s\n", fconf_path, sbcErrorString(cerr))); ret = HRES_ERROR_V(HRES_E_FAIL); goto err_tmr_restart; } /* registry IO must be done as root */ become_root(); cerr = smbconf_transaction_start(rconf_ctx); if (!SBC_ERROR_IS_OK(cerr)) { DEBUG(0, ("error starting transaction: %s\n", sbcErrorString(cerr))); ret = HRES_ERROR_V(HRES_E_FAIL); unbecome_root(); goto err_tmr_restart; } for (sc = sc_set->scs; sc; sc = sc->next) { ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc); if (ret) { DEBUG(0,("failed to expose shadow copy of %s\n", sc->volume_name)); goto err_cancel; } } cerr = smbconf_transaction_commit(rconf_ctx); if (!SBC_ERROR_IS_OK(cerr)) { DEBUG(0, ("error committing transaction: %s\n", sbcErrorString(cerr))); ret = HRES_ERROR_V(HRES_E_FAIL); goto err_cancel; } unbecome_root(); message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL); for (sc = sc_set->scs; sc; sc = sc->next) { struct fss_sc_smap *sm; for (sm = sc->smaps; sm; sm = sm->next) sm->is_exposed = true; } sc_set->state = FSS_SC_EXPOSED; become_root(); status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets, fss_global.sc_sets_count, fss_global.db_path); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("failed to store fss server state: %s\n", nt_errstr(status))); } /* start message sequence timer */ fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr); talloc_free(tmp_ctx); return 0; err_cancel: smbconf_transaction_cancel(rconf_ctx); unbecome_root(); err_tmr_restart: fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr); err_out: talloc_free(tmp_ctx); return ret; }
/* * Expose a new share using libsmbconf, cloning the existing configuration * from the base share. The base share may be defined in either the registry * or smb.conf. * XXX this is called as root */ static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx, struct smbconf_ctx *rconf_ctx, TALLOC_CTX *mem_ctx, struct fss_sc *sc) { struct fss_sc_smap *sc_smap; uint32_t err = 0; for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) { sbcErr cerr; struct smbconf_service *base_service = NULL; struct security_descriptor *sd; size_t sd_size; cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx, sc_smap->share_name, &base_service); if (!SBC_ERROR_IS_OK(cerr)) { DEBUG(0, ("failed to get base share %s definition: " "%s\n", sc_smap->share_name, sbcErrorString(cerr))); err = HRES_ERROR_V(HRES_E_FAIL); break; } /* smap share name already defined when added */ err = map_share_comment(sc_smap, sc); if (err) { DEBUG(0, ("failed to map share comment\n")); break; } base_service->name = sc_smap->sc_share_name; cerr = smbconf_create_set_share(rconf_ctx, base_service); if (!SBC_ERROR_IS_OK(cerr)) { DEBUG(0, ("failed to create share %s: %s\n", base_service->name, sbcErrorString(cerr))); err = HRES_ERROR_V(HRES_E_FAIL); break; } cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name, "path", sc->sc_path); if (!SBC_ERROR_IS_OK(cerr)) { DEBUG(0, ("failed to set path param: %s\n", sbcErrorString(cerr))); err = HRES_ERROR_V(HRES_E_FAIL); break; } if (sc_smap->sc_share_comment != NULL) { cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name, "comment", sc_smap->sc_share_comment); if (!SBC_ERROR_IS_OK(cerr)) { DEBUG(0, ("failed to set comment param: %s\n", sbcErrorString(cerr))); err = HRES_ERROR_V(HRES_E_FAIL); break; } } talloc_free(base_service); /* * Obtain the base share SD, which also needs to be cloned. * Share SDs are stored in share_info.tdb, so are not covered by * the registry transaction. * The base share SD should be cloned at the time of exposure, * rather than when the snapshot is taken. This matches Windows * Server 2012 behaviour. */ sd = get_share_security(mem_ctx, sc_smap->share_name, &sd_size); if (sd == NULL) { DEBUG(2, ("no share SD to clone for %s snapshot\n", sc_smap->share_name)); } else { bool ok; ok = set_share_security(sc_smap->sc_share_name, sd); TALLOC_FREE(sd); if (!ok) { DEBUG(0, ("failed to set %s share SD\n", sc_smap->sc_share_name)); err = HRES_ERROR_V(HRES_E_FAIL); break; } } } return err; }
uint32_t _fss_GetShareMapping(struct pipes_struct *p, struct fss_GetShareMapping *r) { NTSTATUS status; struct fss_sc_set *sc_set; struct fss_sc *sc; struct fss_sc_smap *sc_smap; char *share; struct fssagent_share_mapping_1 *sm_out; TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx); if (tmp_ctx == NULL) { return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } if (!fss_permitted(p)) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_ACCESSDENIED); } sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId); if (sc_set == NULL) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } /* * If ShadowCopySet.Status is not "Exposed", the server SHOULD<9> fail * the call with FSRVP_E_BAD_STATE. * <9> If ShadowCopySet.Status is "Started", "Added", * "CreationInProgress", or "Committed", Windows Server 2012 FSRVP * servers return an error value of 0x80042311. */ if ((sc_set->state == FSS_SC_STARTED) || (sc_set->state == FSS_SC_ADDED) || (sc_set->state == FSS_SC_CREATING) || (sc_set->state == FSS_SC_COMMITED)) { talloc_free(tmp_ctx); return 0x80042311; /* documented magic value */ } sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId); if (sc == NULL) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return fss_ntstatus_map(status); } sc_smap = sc_smap_lookup(sc->smaps, share); if (sc_smap == NULL) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } if (r->in.Level != 1) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1); if (sm_out == NULL) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } sm_out->ShadowCopySetId = sc_set->id; sm_out->ShadowCopyId = sc->id; sm_out->ShareNameUNC = talloc_asprintf(sm_out, "\\\\%s\\%s", lp_netbios_name(), sc_smap->share_name); if (sm_out->ShareNameUNC == NULL) { talloc_free(sm_out); talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } sm_out->ShadowCopyShareName = sc_smap->sc_share_name; unix_to_nt_time(&sm_out->tstamp, sc->create_ts); r->out.ShareMapping->ShareMapping1 = sm_out; talloc_free(tmp_ctx); /* reset msg sequence timer */ TALLOC_FREE(fss_global.seq_tmr); fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr); return 0; }
uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p, struct fss_AddToShadowCopySet *r) { uint32_t ret; struct fss_sc_set *sc_set; struct fss_sc *sc; struct fss_sc_smap *sc_smap; int snum; char *service; char *base_vol; char *share; char *path_name; struct connection_struct *conn; NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx); if (tmp_ctx == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_out; } if (!fss_permitted(p)) { ret = HRES_ERROR_V(HRES_E_ACCESSDENIED); goto err_tmp_free; } sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId); if (sc_set == NULL) { ret = HRES_ERROR_V(HRES_E_INVALIDARG); goto err_tmp_free; } status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share); if (!NT_STATUS_IS_OK(status)) { ret = fss_ntstatus_map(status); goto err_tmp_free; } snum = find_service(tmp_ctx, share, &service); if ((snum == -1) || (service == NULL)) { DEBUG(0, ("share at %s not found\n", r->in.ShareName)); ret = HRES_ERROR_V(HRES_E_INVALIDARG); goto err_tmp_free; } path_name = lp_path(tmp_ctx, snum); if (path_name == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_tmp_free; } status = fss_vfs_conn_create(tmp_ctx, server_event_context(), p->msg_ctx, p->session_info, snum, &conn); if (!NT_STATUS_IS_OK(status)) { ret = HRES_ERROR_V(HRES_E_ACCESSDENIED); goto err_tmp_free; } if (!become_user_by_session(conn, p->session_info)) { DEBUG(0, ("failed to become user\n")); fss_vfs_conn_destroy(conn); ret = HRES_ERROR_V(HRES_E_ACCESSDENIED); goto err_tmp_free; } status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol); unbecome_user(); fss_vfs_conn_destroy(conn); if (!NT_STATUS_IS_OK(status)) { ret = FSRVP_E_NOT_SUPPORTED; goto err_tmp_free; } if ((sc_set->state != FSS_SC_STARTED) && (sc_set->state != FSS_SC_ADDED)) { ret = FSRVP_E_BAD_STATE; goto err_tmp_free; } /* stop msg seq timer */ TALLOC_FREE(fss_global.seq_tmr); /* * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList * where ShadowCopy.VolumeName matches the file store on which the * share identified by ShareName is hosted. If an entry is found, the * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS. * If no entry is found, the server MUST create a new ShadowCopy * object * XXX Windows appears to allow multiple mappings for the same vol! */ sc = sc_lookup_volname(sc_set->scs, base_vol); if (sc != NULL) { ret = FSRVP_E_OBJECT_ALREADY_EXISTS; goto err_tmr_restart; } sc = talloc_zero(sc_set, struct fss_sc); if (sc == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_tmr_restart; } talloc_steal(sc, base_vol); sc->volume_name = base_vol; sc->sc_set = sc_set; sc->create_ts = time(NULL); sc->id = GUID_random(); /* Windows servers ignore client ids */ sc->id_str = GUID_string(sc, &sc->id); if (sc->id_str == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_sc_free; } sc_smap = talloc_zero(sc, struct fss_sc_smap); if (sc_smap == NULL) { ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY); goto err_sc_free; } talloc_steal(sc_smap, service); sc_smap->share_name = service; sc_smap->is_exposed = false; /* * generate the sc_smap share name now. It is a unique identifier for * the smap used as a tdb key for state storage. */ ret = map_share_name(sc_smap, sc); if (ret) { goto err_sc_free; } /* add share map to shadow-copy */ DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *); sc->smaps_count++; /* add shadow-copy to shadow-copy set */ DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *); sc_set->scs_count++; DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n", sc->volume_name, sc_set->id_str)); /* start the Message Sequence Timer with timeout of 1800 seconds */ fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr); sc_set->state = FSS_SC_ADDED; r->out.pShadowCopyId = &sc->id; talloc_free(tmp_ctx); return 0; err_sc_free: talloc_free(sc); err_tmr_restart: fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr); err_tmp_free: talloc_free(tmp_ctx); err_out: return ret; }
/* push a HRESULT */ _PUBLIC_ enum ndr_err_code ndr_push_HRESULT(struct ndr_push *ndr, int ndr_flags, HRESULT status) { return ndr_push_uint32(ndr, NDR_SCALARS, HRES_ERROR_V(status)); }