static NTSTATUS update_write_time_on_close(struct files_struct *fsp) { struct smb_file_time ft; NTSTATUS status; struct share_mode_lock *lck = NULL; ZERO_STRUCT(ft); if (!fsp->update_write_time_on_close) { return NT_STATUS_OK; } if (null_timespec(fsp->close_write_time)) { fsp->close_write_time = timespec_current(); } /* Ensure we have a valid stat struct for the source. */ status = vfs_stat_fsp(fsp); if (!NT_STATUS_IS_OK(status)) { return status; } if (!VALID_STAT(fsp->fsp_name->st)) { /* if it doesn't seem to be a real file */ return NT_STATUS_OK; } /* * get_existing_share_mode_lock() isn't really the right * call here, as we're being called after * close_remove_share_mode() inside close_normal_file() * so it's quite normal to not have an existing share * mode here. However, get_share_mode_lock() doesn't * work because that will create a new share mode if * one doesn't exist - so stick with this call (just * ignore any error we get if the share mode doesn't * exist. */ lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); if (lck) { /* On close if we're changing the real file time we * must update it in the open file db too. */ (void)set_write_time(fsp->file_id, fsp->close_write_time); /* Close write times overwrite sticky write times so we must replace any sticky write time here. */ if (!null_timespec(lck->data->changed_write_time)) { (void)set_sticky_write_time(fsp->file_id, fsp->close_write_time); } TALLOC_FREE(lck); } ft.mtime = fsp->close_write_time; /* As this is a close based update, we are not directly changing the file attributes from a client call, but indirectly from a write. */ status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false); if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("update_write_time_on_close: smb_set_file_time " "on file %s returned %s\n", fsp_str_dbg(fsp), nt_errstr(status))); return status; } return status; }
NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn, struct auth_session_info *session_info, uint64_t persistent_id, const struct GUID *create_guid, NTTIME now, struct smbXsrv_open **_open) { struct smbXsrv_open_table *table = conn->open_table; struct db_record *local_rec = NULL; struct smbXsrv_open *op = NULL; void *ptr = NULL; TDB_DATA val; uint32_t global_id = persistent_id & UINT32_MAX; uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU; NTSTATUS status; struct security_token *current_token = NULL; if (session_info == NULL) { return NT_STATUS_INVALID_HANDLE; } current_token = session_info->security_token; if (current_token == NULL) { return NT_STATUS_INVALID_HANDLE; } if (global_zeros != 0) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } op = talloc_zero(table, struct smbXsrv_open); if (op == NULL) { return NT_STATUS_NO_MEMORY; } op->table = table; status = smbXsrv_open_global_lookup(table, global_id, op, &op->global); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(op); return status; } /* * If the provided create_guid is NULL, this means that * the reconnect request was a v1 request. In that case * we should skipt the create GUID verification, since * it is valid to v1-reconnect a v2-opened handle. */ if ((create_guid != NULL) && !GUID_equal(&op->global->create_guid, create_guid)) { TALLOC_FREE(op); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (!security_token_is_sid(current_token, &op->global->open_owner)) { TALLOC_FREE(op); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (!op->global->durable) { TALLOC_FREE(op); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (table->local.num_opens >= table->local.max_opens) { TALLOC_FREE(op); return NT_STATUS_INSUFFICIENT_RESOURCES; } status = smbXsrv_open_local_allocate_id(table->local.db_ctx, table->local.lowest_id, table->local.highest_id, op, &local_rec, &op->local_id); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(op); return status; } op->idle_time = now; op->status = NT_STATUS_FILE_CLOSED; op->global->open_volatile_id = op->local_id; op->global->server_id = messaging_server_id(conn->msg_ctx); ptr = op; val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr)); status = dbwrap_record_store(local_rec, val, TDB_REPLACE); TALLOC_FREE(local_rec); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(op); return status; } table->local.num_opens += 1; talloc_set_destructor(op, smbXsrv_open_destructor); status = smbXsrv_open_global_store(op->global); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(op); return status; } if (CHECK_DEBUGLVL(10)) { struct smbXsrv_openB open_blob; ZERO_STRUCT(open_blob); open_blob.version = 0; open_blob.info.info0 = op; DEBUG(10,("smbXsrv_open_recreate: global_id (0x%08x) stored\n", op->global->open_global_id)); NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob); } *_open = op; return NT_STATUS_OK; }
NTSTATUS smbXsrv_open_create(struct smbXsrv_connection *conn, struct auth_session_info *session_info, NTTIME now, struct smbXsrv_open **_open) { struct smbXsrv_open_table *table = conn->open_table; struct db_record *local_rec = NULL; struct smbXsrv_open *op = NULL; void *ptr = NULL; TDB_DATA val; struct smbXsrv_open_global0 *global = NULL; NTSTATUS status; struct dom_sid *current_sid = NULL; struct security_token *current_token = NULL; if (session_info == NULL) { return NT_STATUS_INVALID_HANDLE; } current_token = session_info->security_token; if (current_token == NULL) { return NT_STATUS_INVALID_HANDLE; } if (current_token->num_sids > PRIMARY_USER_SID_INDEX) { current_sid = ¤t_token->sids[PRIMARY_USER_SID_INDEX]; } if (current_sid == NULL) { return NT_STATUS_INVALID_HANDLE; } if (table->local.num_opens >= table->local.max_opens) { return NT_STATUS_INSUFFICIENT_RESOURCES; } op = talloc_zero(table, struct smbXsrv_open); if (op == NULL) { return NT_STATUS_NO_MEMORY; } op->table = table; op->status = NT_STATUS_OK; /* TODO: start with INTERNAL_ERROR */ op->idle_time = now; status = smbXsrv_open_global_allocate(table->global.db_ctx, op, &global); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(op); return status; } op->global = global; status = smbXsrv_open_local_allocate_id(table->local.db_ctx, table->local.lowest_id, table->local.highest_id, op, &local_rec, &op->local_id); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(op); return status; } global->open_persistent_id = global->open_global_id; global->open_volatile_id = op->local_id; global->server_id = messaging_server_id(conn->msg_ctx); global->open_time = now; global->open_owner = *current_sid; if (conn->protocol >= PROTOCOL_SMB2_10) { global->client_guid = conn->smb2.client.guid; } ptr = op; val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr)); status = dbwrap_record_store(local_rec, val, TDB_REPLACE); TALLOC_FREE(local_rec); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(op); return status; } table->local.num_opens += 1; talloc_set_destructor(op, smbXsrv_open_destructor); status = smbXsrv_open_global_store(global); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smbXsrv_open_create: " "global_id (0x%08x) store failed - %s\n", op->global->open_global_id, nt_errstr(status))); TALLOC_FREE(op); return status; } if (CHECK_DEBUGLVL(10)) { struct smbXsrv_openB open_blob; ZERO_STRUCT(open_blob); open_blob.version = SMBXSRV_VERSION_0; open_blob.info.info0 = op; DEBUG(10,("smbXsrv_open_create: global_id (0x%08x) stored\n", op->global->open_global_id)); NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob); } *_open = op; return NT_STATUS_OK; }
static bool test_PACVerify(struct torture_context *tctx, struct dcerpc_pipe *p, struct cli_credentials *credentials) { NTSTATUS status; struct netr_LogonSamLogon r; union netr_LogonLevel logon; union netr_Validation validation; uint8_t authoritative; struct netr_Authenticator return_authenticator; struct netr_GenericInfo generic; struct netr_Authenticator auth, auth2; struct netlogon_creds_CredentialState *creds; struct gensec_security *gensec_client_context; struct gensec_security *gensec_server_context; DATA_BLOB client_to_server, server_to_client, pac_wrapped, payload; struct PAC_Validate pac_wrapped_struct; enum ndr_err_code ndr_err; struct auth_session_info *session_info; char *tmp_dir; TALLOC_CTX *tmp_ctx = talloc_new(tctx); torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed"); if (!test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, credentials, SEC_CHAN_BDC, &creds)) { return false; } status = torture_temp_dir(tctx, "PACVerify", &tmp_dir); torture_assert_ntstatus_ok(tctx, status, "torture_temp_dir failed"); status = gensec_client_start(tctx, &gensec_client_context, tctx->ev, lp_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed"); status = gensec_set_target_hostname(gensec_client_context, TEST_MACHINE_NAME); status = gensec_set_credentials(gensec_client_context, cmdline_credentials); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed"); status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI"); torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed"); status = gensec_server_start(tctx, tctx->ev, lp_gensec_settings(tctx, tctx->lp_ctx), NULL, &gensec_server_context); torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed"); status = gensec_set_credentials(gensec_server_context, credentials); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed"); status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI"); torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed"); server_to_client = data_blob(NULL, 0); do { /* Do a client-server update dance */ status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server); if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { ; torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed"); } status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client); if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { ; torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed"); } if (NT_STATUS_IS_OK(status)) { break; } } while (1); /* Extract the PAC using Samba's code */ status = gensec_session_info(gensec_server_context, &session_info); torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed"); pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length; pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type; pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length; pac_wrapped_struct.ChecksumAndSignature = payload = data_blob_talloc(tmp_ctx, NULL, pac_wrapped_struct.ChecksumLength + pac_wrapped_struct.SignatureLength); memcpy(&payload.data[0], session_info->server_info->pac_srv_sig.signature.data, pac_wrapped_struct.ChecksumLength); memcpy(&payload.data[pac_wrapped_struct.ChecksumLength], session_info->server_info->pac_kdc_sig.signature.data, pac_wrapped_struct.SignatureLength); ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct, (ndr_push_flags_fn_t)ndr_push_PAC_Validate); torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed"); torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption"); netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length); generic.length = pac_wrapped.length; generic.data = pac_wrapped.data; /* Validate it over the netlogon pipe */ generic.identity_info.parameter_control = 0; generic.identity_info.logon_id_high = 0; generic.identity_info.logon_id_low = 0; generic.identity_info.domain_name.string = session_info->server_info->domain_name; generic.identity_info.account_name.string = session_info->server_info->account_name; generic.identity_info.workstation.string = TEST_MACHINE_NAME; generic.package_name.string = "Kerberos"; logon.generic = &generic; ZERO_STRUCT(auth2); netlogon_creds_client_authenticator(creds, &auth); r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon = &logon; r.in.logon_level = NetlogonGenericInformation; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); r.in.computer_name = cli_credentials_get_workstation(credentials); r.in.validation_level = NetlogonValidationGenericInfo2; r.out.validation = &validation; r.out.authoritative = &authoritative; r.out.return_authenticator = &return_authenticator; status = dcerpc_netr_LogonSamLogon(p, tctx, &r); torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed"); /* This will break the signature nicely (even in the crypto wrapping), check we get a logon failure */ generic.data[generic.length-1]++; logon.generic = &generic; ZERO_STRUCT(auth2); netlogon_creds_client_authenticator(creds, &auth); r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = NetlogonGenericInformation; r.in.logon = &logon; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); r.in.computer_name = cli_credentials_get_workstation(credentials); r.in.validation_level = NetlogonValidationGenericInfo2; status = dcerpc_netr_LogonSamLogon(p, tctx, &r); torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed"); torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred), "Credential chaining failed"); /* This will break the parsing nicely (even in the crypto wrapping), check we get INVALID_PARAMETER */ generic.length--; logon.generic = &generic; ZERO_STRUCT(auth2); netlogon_creds_client_authenticator(creds, &auth); r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = NetlogonGenericInformation; r.in.logon = &logon; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); r.in.computer_name = cli_credentials_get_workstation(credentials); r.in.validation_level = NetlogonValidationGenericInfo2; status = dcerpc_netr_LogonSamLogon(p, tctx, &r); torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed"); torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred), "Credential chaining failed"); pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length; pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type; /* Break the SignatureType */ pac_wrapped_struct.SignatureType++; pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length; pac_wrapped_struct.ChecksumAndSignature = payload = data_blob_talloc(tmp_ctx, NULL, pac_wrapped_struct.ChecksumLength + pac_wrapped_struct.SignatureLength); memcpy(&payload.data[0], session_info->server_info->pac_srv_sig.signature.data, pac_wrapped_struct.ChecksumLength); memcpy(&payload.data[pac_wrapped_struct.ChecksumLength], session_info->server_info->pac_kdc_sig.signature.data, pac_wrapped_struct.SignatureLength); ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct, (ndr_push_flags_fn_t)ndr_push_PAC_Validate); torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed"); torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption"); netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length); generic.length = pac_wrapped.length; generic.data = pac_wrapped.data; logon.generic = &generic; ZERO_STRUCT(auth2); netlogon_creds_client_authenticator(creds, &auth); r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = NetlogonGenericInformation; r.in.logon = &logon; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); r.in.computer_name = cli_credentials_get_workstation(credentials); r.in.validation_level = NetlogonValidationGenericInfo2; status = dcerpc_netr_LogonSamLogon(p, tctx, &r); torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed"); torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred), "Credential chaining failed"); pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length; pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type; pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length; pac_wrapped_struct.ChecksumAndSignature = payload = data_blob_talloc(tmp_ctx, NULL, pac_wrapped_struct.ChecksumLength + pac_wrapped_struct.SignatureLength); memcpy(&payload.data[0], session_info->server_info->pac_srv_sig.signature.data, pac_wrapped_struct.ChecksumLength); memcpy(&payload.data[pac_wrapped_struct.ChecksumLength], session_info->server_info->pac_kdc_sig.signature.data, pac_wrapped_struct.SignatureLength); /* Break the signature length */ pac_wrapped_struct.SignatureLength++; ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct, (ndr_push_flags_fn_t)ndr_push_PAC_Validate); torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed"); torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption"); netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length); generic.length = pac_wrapped.length; generic.data = pac_wrapped.data; logon.generic = &generic; ZERO_STRUCT(auth2); netlogon_creds_client_authenticator(creds, &auth); r.in.credential = &auth; r.in.return_authenticator = &auth2; r.in.logon_level = NetlogonGenericInformation; r.in.logon = &logon; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); r.in.computer_name = cli_credentials_get_workstation(credentials); r.in.validation_level = NetlogonValidationGenericInfo2; status = dcerpc_netr_LogonSamLogon(p, tctx, &r); torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed"); torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred), "Credential chaining failed"); return true; }
WERROR cli_srvsvc_net_file_enum(struct cli_state *cli, TALLOC_CTX *mem_ctx, uint32 file_level, const char *user_name, SRV_FILE_INFO_CTR *ctr, int preferred_len, ENUM_HND *hnd) { prs_struct qbuf, rbuf; SRV_Q_NET_FILE_ENUM q; SRV_R_NET_FILE_ENUM r; WERROR result = W_ERROR(ERRgeneral); int i; ZERO_STRUCT(q); ZERO_STRUCT(r); /* Initialise parse structures */ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); /* Initialise input parameters */ init_srv_q_net_file_enum(&q, cli->srv_name_slash, NULL, user_name, file_level, ctr, preferred_len, hnd); /* Marshall data and send request */ if (!srv_io_q_net_file_enum("", &q, &qbuf, 0) || !rpc_api_pipe_req(cli, SRV_NET_FILE_ENUM, &qbuf, &rbuf)) goto done; /* Unmarshall response */ if (!srv_io_r_net_file_enum("", &r, &rbuf, 0)) goto done; result = r.status; if (!W_ERROR_IS_OK(result)) goto done; /* copy the data over to the ctr */ ZERO_STRUCTP(ctr); ctr->switch_value = file_level; ctr->num_entries = ctr->num_entries2 = r.ctr.num_entries; switch(file_level) { case 3: ctr->file.info3 = (SRV_FILE_INFO_3 *)talloc( mem_ctx, sizeof(SRV_FILE_INFO_3) * ctr->num_entries); memset(ctr->file.info3, 0, sizeof(SRV_FILE_INFO_3) * ctr->num_entries); for (i = 0; i < r.ctr.num_entries; i++) { SRV_FILE_INFO_3 *info3 = &ctr->file.info3[i]; char *s; /* Copy pointer crap */ memcpy(&info3->info_3, &r.ctr.file.info3[i].info_3, sizeof(FILE_INFO_3)); /* Duplicate strings */ s = unistr2_tdup(mem_ctx, &r.ctr.file.info3[i].info_3_str.uni_path_name); if (s) init_unistr2(&info3->info_3_str.uni_path_name, s, UNI_STR_TERMINATE); s = unistr2_tdup(mem_ctx, &r.ctr.file.info3[i].info_3_str.uni_user_name); if (s) init_unistr2(&info3->info_3_str.uni_user_name, s, UNI_STR_TERMINATE); } break; } done: prs_mem_free(&qbuf); prs_mem_free(&rbuf); return result; }
static int process_options(int argc, char **argv, int local_flags) { int ch; const char *configfile = get_dyn_CONFIGFILE(); local_flags |= LOCAL_SET_PASSWORD; ZERO_STRUCT(user_name); user_name[0] = '\0'; while ((ch = getopt(argc, argv, "c:axdehminjr:sw:R:D:U:LW")) != EOF) { switch(ch) { case 'L': #if !defined(NSS_WRAPPER) if (getuid() != 0) { fprintf(stderr, "smbpasswd -L can only be used by root.\n"); exit(1); } #endif local_flags |= LOCAL_AM_ROOT; break; case 'c': configfile = optarg; break; case 'a': local_flags |= LOCAL_ADD_USER; break; case 'x': local_flags |= LOCAL_DELETE_USER; local_flags &= ~LOCAL_SET_PASSWORD; break; case 'd': local_flags |= LOCAL_DISABLE_USER; local_flags &= ~LOCAL_SET_PASSWORD; break; case 'e': local_flags |= LOCAL_ENABLE_USER; local_flags &= ~LOCAL_SET_PASSWORD; break; case 'm': local_flags |= LOCAL_TRUST_ACCOUNT; break; case 'i': local_flags |= LOCAL_INTERDOM_ACCOUNT; break; case 'j': d_printf("See 'net join' for this functionality\n"); exit(1); break; case 'n': local_flags |= LOCAL_SET_NO_PASSWORD; local_flags &= ~LOCAL_SET_PASSWORD; new_passwd = smb_xstrdup("NO PASSWORD"); break; case 'r': remote_machine = optarg; break; case 's': set_line_buffering(stdin); set_line_buffering(stdout); set_line_buffering(stderr); stdin_passwd_get = True; break; case 'w': local_flags |= LOCAL_SET_LDAP_ADMIN_PW; fstrcpy(ldap_secret, optarg); break; case 'R': lp_set_name_resolve_order(optarg); break; case 'D': DEBUGLEVEL = atoi(optarg); break; case 'U': { got_username = True; fstrcpy(user_name, optarg); break; case 'W': local_flags |= LOCAL_SET_LDAP_ADMIN_PW; *ldap_secret = '\0'; break; } case 'h': default: usage(); } } argc -= optind; argv += optind; switch(argc) { case 0: if (!got_username) fstrcpy(user_name, ""); break; case 1: if (!(local_flags & LOCAL_AM_ROOT)) { usage(); } else { if (got_username) { usage(); } else { fstrcpy(user_name, argv[0]); } } break; default: usage(); } if (!lp_load(configfile,True,False,False,True)) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", configfile); exit(1); } return local_flags; }
/* list files in a directory matching a wildcard pattern */ static NTSTATUS svfs_search_first(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_search_first *io, void *search_private, bool (*callback)(void *, const union smb_search_data *)) { struct svfs_dir *dir; int i; struct svfs_private *p = ntvfs->private_data; struct search_state *search; union smb_search_data file; unsigned int max_count; if (io->generic.level != RAW_SEARCH_TRANS2) { return NT_STATUS_NOT_SUPPORTED; } if (io->generic.data_level != RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO) { return NT_STATUS_NOT_SUPPORTED; } search = talloc_zero(p, struct search_state); if (!search) { return NT_STATUS_NO_MEMORY; } max_count = io->t2ffirst.in.max_count; dir = svfs_list(ntvfs, req, io->t2ffirst.in.pattern); if (!dir) { return NT_STATUS_FOOBAR; } search->handle = p->next_search_handle; search->dir = dir; if (dir->count < max_count) { max_count = dir->count; } for (i=0; i < max_count;i++) { ZERO_STRUCT(file); unix_to_nt_time(&file.both_directory_info.create_time, dir->files[i].st.st_ctime); unix_to_nt_time(&file.both_directory_info.access_time, dir->files[i].st.st_atime); unix_to_nt_time(&file.both_directory_info.write_time, dir->files[i].st.st_mtime); unix_to_nt_time(&file.both_directory_info.change_time, dir->files[i].st.st_mtime); file.both_directory_info.name.s = dir->files[i].name; file.both_directory_info.short_name.s = dir->files[i].name; file.both_directory_info.size = dir->files[i].st.st_size; file.both_directory_info.attrib = svfs_unix_to_dos_attrib(dir->files[i].st.st_mode); if (!callback(search_private, &file)) { break; } } search->current_index = i; io->t2ffirst.out.count = i; io->t2ffirst.out.handle = search->handle; io->t2ffirst.out.end_of_search = (i == dir->count) ? 1 : 0; /* work out if we are going to keep the search state */ if ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE) || ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) { talloc_free(search); } else { p->next_search_handle++; DLIST_ADD(p->search, search); } return NT_STATUS_OK; }
int main(int argc, char **argv) { CacServerHandle *hnd = NULL; TALLOC_CTX *mem_ctx = NULL; fstring tmp; mem_ctx = talloc_init("cac_shutdown"); hnd = cac_NewServerHandle(True); cac_SetAuthDataFn(hnd, cactest_GetAuthDataFn); cac_parse_cmd_line(argc, argv, hnd); hnd->_internal.srv_level = SRV_WIN_NT4; if(!cac_Connect(hnd, NULL)) { fprintf(stderr, "Could not connect to server %s. Error: %s\n", hnd->server, nt_errstr(hnd->status)); exit(-1); } struct Shutdown s; ZERO_STRUCT(s); printf("Message: "); cactest_readline(stdin, tmp); s.in.message = talloc_strdup(mem_ctx, tmp); printf("timeout: "); scanf("%d", &s.in.timeout); printf("Reboot? [y/n]: "); cactest_readline(stdin, tmp); s.in.reboot = ( tmp[0] == 'y') ? True : False; printf("Force? [y/n]: "); cactest_readline(stdin, tmp); s.in.force = (tmp[0] == 'y') ? True : False; if(!cac_Shutdown(hnd, mem_ctx, &s)) { fprintf(stderr, "could not shut down server: error %s\n", nt_errstr(hnd->status)); goto done; } printf("Server %s is shutting down. Would you like to try to abort? [y/n]: ", hnd->server); fscanf(stdin, "%s", tmp); if(tmp[0] == 'y') { if(!cac_AbortShutdown(hnd, mem_ctx)) { fprintf(stderr, "Could not abort shutdown. Error %s\n", nt_errstr(hnd->status)); } } done: cac_FreeHandle(hnd); talloc_destroy(mem_ctx); return 0; }
/* process a control request */ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, struct ctdb_req_control_old *c, TDB_DATA indata, TDB_DATA *outdata, uint32_t srcnode, const char **errormsg, bool *async_reply) { uint32_t opcode = c->opcode; uint64_t srvid = c->srvid; uint32_t client_id = c->client_id; switch (opcode) { case CTDB_CONTROL_PROCESS_EXISTS: { CHECK_CONTROL_DATA_SIZE(sizeof(pid_t)); return ctdb_control_process_exists(ctdb, *(pid_t *)indata.dptr); } case CTDB_CONTROL_SET_DEBUG: { CHECK_CONTROL_DATA_SIZE(sizeof(int32_t)); DEBUGLEVEL = *(int32_t *)indata.dptr; return 0; } case CTDB_CONTROL_GET_DEBUG: { CHECK_CONTROL_DATA_SIZE(0); outdata->dptr = (uint8_t *)&(DEBUGLEVEL); outdata->dsize = sizeof(DEBUGLEVEL); return 0; } case CTDB_CONTROL_STATISTICS: { CHECK_CONTROL_DATA_SIZE(0); ctdb->statistics.memory_used = talloc_total_size(NULL); ctdb->statistics.num_clients = ctdb->num_clients; ctdb->statistics.frozen = (ctdb_db_all_frozen(ctdb) ? 1 : 0); ctdb->statistics.recovering = (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE); ctdb->statistics.statistics_current_time = timeval_current(); outdata->dptr = (uint8_t *)&ctdb->statistics; outdata->dsize = sizeof(ctdb->statistics); return 0; } case CTDB_CONTROL_GET_ALL_TUNABLES: { CHECK_CONTROL_DATA_SIZE(0); outdata->dptr = (uint8_t *)&ctdb->tunable; outdata->dsize = sizeof(ctdb->tunable); return 0; } case CTDB_CONTROL_DUMP_MEMORY: { CHECK_CONTROL_DATA_SIZE(0); return ctdb_dump_memory(ctdb, outdata); } case CTDB_CONTROL_STATISTICS_RESET: { struct ctdb_db_context *ctdb_db; CHECK_CONTROL_DATA_SIZE(0); ZERO_STRUCT(ctdb->statistics); for (ctdb_db = ctdb->db_list; ctdb_db != NULL; ctdb_db = ctdb_db->next) { ctdb_db_statistics_reset(ctdb_db); } ctdb->statistics.statistics_start_time = timeval_current(); return 0; } case CTDB_CONTROL_GETVNNMAP: return ctdb_control_getvnnmap(ctdb, opcode, indata, outdata); case CTDB_CONTROL_GET_DBMAP: return ctdb_control_getdbmap(ctdb, opcode, indata, outdata); case CTDB_CONTROL_GET_NODEMAPv4: return control_not_implemented("GET_NODEMAPv4", "GET_NODEMAP"); case CTDB_CONTROL_GET_NODEMAP: return ctdb_control_getnodemap(ctdb, opcode, indata, outdata); case CTDB_CONTROL_GET_NODES_FILE: return ctdb_control_getnodesfile(ctdb, opcode, indata, outdata); case CTDB_CONTROL_RELOAD_NODES_FILE: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_reload_nodes_file(ctdb, opcode); case CTDB_CONTROL_SET_DB_STICKY: { uint32_t db_id; struct ctdb_db_context *ctdb_db; CHECK_CONTROL_DATA_SIZE(sizeof(db_id)); db_id = *(uint32_t *)indata.dptr; ctdb_db = find_ctdb_db(ctdb, db_id); if (ctdb_db == NULL) return -1; return ctdb_set_db_sticky(ctdb, ctdb_db); } case CTDB_CONTROL_SETVNNMAP: return ctdb_control_setvnnmap(ctdb, opcode, indata, outdata); case CTDB_CONTROL_PULL_DB: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_pulldb)); return ctdb_control_pull_db(ctdb, indata, outdata); case CTDB_CONTROL_SET_DMASTER: return control_not_implemented("SET_DMASTER", NULL); case CTDB_CONTROL_PUSH_DB: return ctdb_control_push_db(ctdb, indata); case CTDB_CONTROL_GET_RECMODE: { return ctdb->recovery_mode; } case CTDB_CONTROL_SET_RECMASTER: { return ctdb_control_set_recmaster(ctdb, opcode, indata); } case CTDB_CONTROL_GET_RECMASTER: return ctdb->recovery_master; case CTDB_CONTROL_GET_PID: return getpid(); case CTDB_CONTROL_GET_PNN: return ctdb->pnn; case CTDB_CONTROL_PING: CHECK_CONTROL_DATA_SIZE(0); return ctdb->num_clients; case CTDB_CONTROL_GET_RUNSTATE: CHECK_CONTROL_DATA_SIZE(0); outdata->dptr = (uint8_t *)&ctdb->runstate; outdata->dsize = sizeof(uint32_t); return 0; case CTDB_CONTROL_SET_DB_READONLY: { uint32_t db_id; struct ctdb_db_context *ctdb_db; CHECK_CONTROL_DATA_SIZE(sizeof(db_id)); db_id = *(uint32_t *)indata.dptr; ctdb_db = find_ctdb_db(ctdb, db_id); if (ctdb_db == NULL) return -1; return ctdb_set_db_readonly(ctdb, ctdb_db); } case CTDB_CONTROL_GET_DBNAME: { uint32_t db_id; struct ctdb_db_context *ctdb_db; CHECK_CONTROL_DATA_SIZE(sizeof(db_id)); db_id = *(uint32_t *)indata.dptr; ctdb_db = find_ctdb_db(ctdb, db_id); if (ctdb_db == NULL) return -1; outdata->dptr = discard_const(ctdb_db->db_name); outdata->dsize = strlen(ctdb_db->db_name)+1; return 0; } case CTDB_CONTROL_GETDBPATH: { uint32_t db_id; struct ctdb_db_context *ctdb_db; CHECK_CONTROL_DATA_SIZE(sizeof(db_id)); db_id = *(uint32_t *)indata.dptr; ctdb_db = find_ctdb_db(ctdb, db_id); if (ctdb_db == NULL) return -1; outdata->dptr = discard_const(ctdb_db->db_path); outdata->dsize = strlen(ctdb_db->db_path)+1; return 0; } case CTDB_CONTROL_DB_ATTACH: return ctdb_control_db_attach(ctdb, indata, outdata, srvid, false, client_id, c, async_reply); case CTDB_CONTROL_DB_ATTACH_PERSISTENT: return ctdb_control_db_attach(ctdb, indata, outdata, srvid, true, client_id, c, async_reply); case CTDB_CONTROL_SET_CALL: return control_not_implemented("SET_CALL", NULL); case CTDB_CONTROL_TRAVERSE_START: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start)); return ctdb_control_traverse_start(ctdb, indata, outdata, srcnode, client_id); case CTDB_CONTROL_TRAVERSE_START_EXT: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start_ext)); return ctdb_control_traverse_start_ext(ctdb, indata, outdata, srcnode, client_id); case CTDB_CONTROL_TRAVERSE_ALL: return ctdb_control_traverse_all(ctdb, indata, outdata); case CTDB_CONTROL_TRAVERSE_ALL_EXT: return ctdb_control_traverse_all_ext(ctdb, indata, outdata); case CTDB_CONTROL_TRAVERSE_DATA: return ctdb_control_traverse_data(ctdb, indata, outdata); case CTDB_CONTROL_TRAVERSE_KILL: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start)); return ctdb_control_traverse_kill(ctdb, indata, outdata, srcnode); case CTDB_CONTROL_REGISTER_SRVID: return daemon_register_message_handler(ctdb, client_id, srvid); case CTDB_CONTROL_DEREGISTER_SRVID: return daemon_deregister_message_handler(ctdb, client_id, srvid); case CTDB_CONTROL_CHECK_SRVIDS: return daemon_check_srvids(ctdb, indata, outdata); case CTDB_CONTROL_ENABLE_SEQNUM: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_ltdb_enable_seqnum(ctdb, *(uint32_t *)indata.dptr); case CTDB_CONTROL_UPDATE_SEQNUM: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_ltdb_update_seqnum(ctdb, *(uint32_t *)indata.dptr, srcnode); case CTDB_CONTROL_FREEZE: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_freeze(ctdb, c, async_reply); case CTDB_CONTROL_THAW: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_thaw(ctdb, (uint32_t)c->srvid, true); case CTDB_CONTROL_SET_RECMODE: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_set_recmode(ctdb, c, indata, async_reply, errormsg); case CTDB_CONTROL_GET_MONMODE: CHECK_CONTROL_DATA_SIZE(0); return ctdb_monitoring_mode(ctdb); case CTDB_CONTROL_ENABLE_MONITOR: CHECK_CONTROL_DATA_SIZE(0); ctdb_enable_monitoring(ctdb); return 0; case CTDB_CONTROL_RUN_EVENTSCRIPTS: return ctdb_run_eventscripts(ctdb, c, indata, async_reply); case CTDB_CONTROL_DISABLE_MONITOR: CHECK_CONTROL_DATA_SIZE(0); ctdb_disable_monitoring(ctdb); return 0; case CTDB_CONTROL_SHUTDOWN: DEBUG(DEBUG_NOTICE,("Received SHUTDOWN command.\n")); ctdb_shutdown_sequence(ctdb, 0); /* In case above returns due to duplicate shutdown */ return 0; case CTDB_CONTROL_TAKEOVER_IPv4: return control_not_implemented("TAKEOVER_IPv4", "TAKEOVER_IP"); case CTDB_CONTROL_TAKEOVER_IP: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip)); return ctdb_control_takeover_ip(ctdb, c, indata, async_reply); case CTDB_CONTROL_RELEASE_IPv4: return control_not_implemented("RELEASE_IPv4", "RELEASE_IP"); case CTDB_CONTROL_RELEASE_IP: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip)); return ctdb_control_release_ip(ctdb, c, indata, async_reply); case CTDB_CONTROL_IPREALLOCATED: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_ipreallocated(ctdb, c, async_reply); case CTDB_CONTROL_GET_PUBLIC_IPSv4: return control_not_implemented("GET_PUBLIC_IPSv4", "GET_PUBLIC_IPS"); case CTDB_CONTROL_GET_PUBLIC_IPS: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_get_public_ips(ctdb, c, outdata); case CTDB_CONTROL_TCP_CLIENT: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection)); return ctdb_control_tcp_client(ctdb, client_id, indata); case CTDB_CONTROL_STARTUP: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_startup(ctdb, srcnode); case CTDB_CONTROL_TCP_ADD: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection)); return ctdb_control_tcp_add(ctdb, indata, false); case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection)); return ctdb_control_tcp_add(ctdb, indata, true); case CTDB_CONTROL_TCP_REMOVE: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection)); return ctdb_control_tcp_remove(ctdb, indata); case CTDB_CONTROL_SET_TUNABLE: return ctdb_control_set_tunable(ctdb, indata); case CTDB_CONTROL_GET_TUNABLE: return ctdb_control_get_tunable(ctdb, indata, outdata); case CTDB_CONTROL_LIST_TUNABLES: return ctdb_control_list_tunables(ctdb, outdata); case CTDB_CONTROL_MODIFY_FLAGS: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_node_flag_change)); return ctdb_control_modflags(ctdb, indata); case CTDB_CONTROL_KILL_TCP: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection)); return ctdb_control_kill_tcp(ctdb, indata); case CTDB_CONTROL_GET_TCP_TICKLE_LIST: CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr)); return ctdb_control_get_tcp_tickle_list(ctdb, indata, outdata); case CTDB_CONTROL_SET_TCP_TICKLE_LIST: /* data size is verified in the called function */ return ctdb_control_set_tcp_tickle_list(ctdb, indata); case CTDB_CONTROL_REGISTER_SERVER_ID: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id)); return ctdb_control_register_server_id(ctdb, client_id, indata); case CTDB_CONTROL_UNREGISTER_SERVER_ID: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id)); return ctdb_control_unregister_server_id(ctdb, indata); case CTDB_CONTROL_CHECK_SERVER_ID: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id)); return ctdb_control_check_server_id(ctdb, indata); case CTDB_CONTROL_GET_SERVER_ID_LIST: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_get_server_id_list(ctdb, outdata); case CTDB_CONTROL_PERSISTENT_STORE: return control_not_implemented("PERSISTENT_STORE", NULL); case CTDB_CONTROL_UPDATE_RECORD: return ctdb_control_update_record(ctdb, c, indata, async_reply); case CTDB_CONTROL_SEND_GRATUITOUS_ARP: return ctdb_control_send_gratious_arp(ctdb, indata); case CTDB_CONTROL_TRANSACTION_START: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_transaction_start(ctdb, *(uint32_t *)indata.dptr); case CTDB_CONTROL_TRANSACTION_COMMIT: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_transaction_commit(ctdb, *(uint32_t *)indata.dptr); case CTDB_CONTROL_WIPE_DATABASE: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb)); return ctdb_control_wipe_database(ctdb, indata); case CTDB_CONTROL_UPTIME: return ctdb_control_uptime(ctdb, outdata); case CTDB_CONTROL_START_RECOVERY: return ctdb_control_start_recovery(ctdb, c, async_reply); case CTDB_CONTROL_END_RECOVERY: return ctdb_control_end_recovery(ctdb, c, async_reply); case CTDB_CONTROL_TRY_DELETE_RECORDS: return ctdb_control_try_delete_records(ctdb, indata, outdata); case CTDB_CONTROL_ADD_PUBLIC_IP: return ctdb_control_add_public_address(ctdb, indata); case CTDB_CONTROL_DEL_PUBLIC_IP: return ctdb_control_del_public_address(ctdb, c, indata, async_reply); case CTDB_CONTROL_GET_CAPABILITIES: return ctdb_control_get_capabilities(ctdb, outdata); case CTDB_CONTROL_START_PERSISTENT_UPDATE: return ctdb_control_start_persistent_update(ctdb, c, indata); case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE: return ctdb_control_cancel_persistent_update(ctdb, c, indata); case CTDB_CONTROL_TRANS2_COMMIT: case CTDB_CONTROL_TRANS2_COMMIT_RETRY: return control_not_implemented("TRANS2_COMMIT", "TRANS3_COMMIT"); case CTDB_CONTROL_TRANS2_ERROR: return control_not_implemented("TRANS2_ERROR", NULL); case CTDB_CONTROL_TRANS2_FINISHED: return control_not_implemented("TRANS2_FINISHED", NULL); case CTDB_CONTROL_TRANS2_ACTIVE: return control_not_implemented("TRANS2_ACTIVE", NULL); case CTDB_CONTROL_TRANS3_COMMIT: return ctdb_control_trans3_commit(ctdb, c, indata, async_reply); case CTDB_CONTROL_RECD_PING: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_recd_ping(ctdb); case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_get_event_script_status(ctdb, *(uint32_t *)indata.dptr, outdata); case CTDB_CONTROL_RECD_RECLOCK_LATENCY: CHECK_CONTROL_DATA_SIZE(sizeof(double)); CTDB_UPDATE_RECLOCK_LATENCY(ctdb, "recd reclock", reclock.recd, *((double *)indata.dptr)); return 0; case CTDB_CONTROL_GET_RECLOCK_FILE: CHECK_CONTROL_DATA_SIZE(0); if (ctdb->recovery_lock_file != NULL) { outdata->dptr = discard_const(ctdb->recovery_lock_file); outdata->dsize = strlen(ctdb->recovery_lock_file) + 1; } return 0; case CTDB_CONTROL_SET_RECLOCK_FILE: { char *t; if (indata.dsize == 0) { TALLOC_FREE(ctdb->recovery_lock_file); return 0; } /* Return silent success if unchanged. Recovery * master updates all nodes on each recovery - we * don't need the extra memory allocation or log * message each time. */ if (ctdb->recovery_lock_file != NULL && strcmp(discard_const(indata.dptr), ctdb->recovery_lock_file) == 0) { return 0; } t = talloc_strdup(ctdb, discard_const(indata.dptr)); if (t == NULL) { DEBUG(DEBUG_ERR, ("Out of memory in SET_RECLOCK_FILE\n")); return -1; } talloc_free(ctdb->recovery_lock_file); ctdb->recovery_lock_file = t; DEBUG(DEBUG_NOTICE, ("Updated recovery lock file to %s\n", t)); return 0; } case CTDB_CONTROL_STOP_NODE: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_stop_node(ctdb); case CTDB_CONTROL_CONTINUE_NODE: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_continue_node(ctdb); case CTDB_CONTROL_SET_NATGWSTATE: return control_not_implemented("SET_NATGWSTATE", NULL); case CTDB_CONTROL_SET_LMASTERROLE: { uint32_t lmasterrole; CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); lmasterrole = *(uint32_t *)indata.dptr; if (lmasterrole == 0) { ctdb->capabilities &= ~CTDB_CAP_LMASTER; } else { ctdb->capabilities |= CTDB_CAP_LMASTER; } return 0; } case CTDB_CONTROL_SET_RECMASTERROLE: { uint32_t recmasterrole; CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); recmasterrole = *(uint32_t *)indata.dptr; if (recmasterrole == 0) { ctdb->capabilities &= ~CTDB_CAP_RECMASTER; } else { ctdb->capabilities |= CTDB_CAP_RECMASTER; } return 0; } case CTDB_CONTROL_ENABLE_SCRIPT: return ctdb_control_enable_script(ctdb, indata); case CTDB_CONTROL_DISABLE_SCRIPT: return ctdb_control_disable_script(ctdb, indata); case CTDB_CONTROL_SET_BAN_STATE: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_ban_state)); return ctdb_control_set_ban_state(ctdb, indata); case CTDB_CONTROL_GET_BAN_STATE: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_get_ban_state(ctdb, outdata); case CTDB_CONTROL_SET_DB_PRIORITY: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_db_priority)); return ctdb_control_set_db_priority(ctdb, indata, client_id); case CTDB_CONTROL_GET_DB_PRIORITY: { uint32_t db_id; struct ctdb_db_context *ctdb_db; CHECK_CONTROL_DATA_SIZE(sizeof(db_id)); db_id = *(uint32_t *)indata.dptr; ctdb_db = find_ctdb_db(ctdb, db_id); if (ctdb_db == NULL) return -1; return ctdb_db->priority; } case CTDB_CONTROL_TRANSACTION_CANCEL: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_transaction_cancel(ctdb); case CTDB_CONTROL_REGISTER_NOTIFY: return ctdb_control_register_notify(ctdb, client_id, indata); case CTDB_CONTROL_DEREGISTER_NOTIFY: CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t)); return ctdb_control_deregister_notify(ctdb, client_id, indata); case CTDB_CONTROL_GET_LOG: return control_not_implemented("GET_LOG", NULL); case CTDB_CONTROL_CLEAR_LOG: return control_not_implemented("CLEAR_LOG", NULL); case CTDB_CONTROL_GET_DB_SEQNUM: CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t)); return ctdb_control_get_db_seqnum(ctdb, indata, outdata); case CTDB_CONTROL_DB_SET_HEALTHY: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_db_set_healthy(ctdb, indata); case CTDB_CONTROL_DB_GET_HEALTH: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_db_get_health(ctdb, indata, outdata); case CTDB_CONTROL_GET_PUBLIC_IP_INFO: CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr)); return ctdb_control_get_public_ip_info(ctdb, c, indata, outdata); case CTDB_CONTROL_GET_IFACES: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_get_ifaces(ctdb, c, outdata); case CTDB_CONTROL_SET_IFACE_LINK_STATE: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_iface)); return ctdb_control_set_iface_link(ctdb, c, indata); case CTDB_CONTROL_GET_STAT_HISTORY: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_get_stat_history(ctdb, c, outdata); case CTDB_CONTROL_SCHEDULE_FOR_DELETION: { struct ctdb_control_schedule_for_deletion *d; size_t size = offsetof(struct ctdb_control_schedule_for_deletion, key); CHECK_CONTROL_MIN_DATA_SIZE(size); d = (struct ctdb_control_schedule_for_deletion *)indata.dptr; size += d->keylen; CHECK_CONTROL_DATA_SIZE(size); return ctdb_control_schedule_for_deletion(ctdb, indata); } case CTDB_CONTROL_GET_DB_STATISTICS: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_get_db_statistics(ctdb, *(uint32_t *)indata.dptr, outdata); case CTDB_CONTROL_RELOAD_PUBLIC_IPS: CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_reload_public_ips(ctdb, c, async_reply); case CTDB_CONTROL_RECEIVE_RECORDS: return ctdb_control_receive_records(ctdb, indata, outdata); case CTDB_CONTROL_DB_DETACH: return ctdb_control_db_detach(ctdb, indata, client_id); case CTDB_CONTROL_DB_FREEZE: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_db_freeze(ctdb, c, *(uint32_t *)indata.dptr, async_reply); case CTDB_CONTROL_DB_THAW: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_db_thaw(ctdb, *(uint32_t *)indata.dptr); case CTDB_CONTROL_DB_TRANSACTION_START: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb)); return ctdb_control_db_transaction_start(ctdb, indata); case CTDB_CONTROL_DB_TRANSACTION_COMMIT: CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb)); return ctdb_control_db_transaction_commit(ctdb, indata); case CTDB_CONTROL_DB_TRANSACTION_CANCEL: CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t)); return ctdb_control_db_transaction_cancel(ctdb, indata); default: DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode)); return -1; } }
static NTSTATUS sam_lookup_useraliases(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32_t num_sids, const struct dom_sid *sids, uint32_t *pnum_aliases, uint32_t **palias_rids) { struct rpc_pipe_client *samr_pipe; struct policy_handle dom_pol; uint32_t num_aliases = 0; uint32_t *alias_rids = NULL; TALLOC_CTX *tmp_ctx; NTSTATUS status, result; struct dcerpc_binding_handle *b = NULL; DEBUG(3,("sam_lookup_useraliases\n")); ZERO_STRUCT(dom_pol); if (pnum_aliases) { *pnum_aliases = 0; } tmp_ctx = talloc_stackframe(); if (tmp_ctx == NULL) { return NT_STATUS_NO_MEMORY; } status = open_internal_samr_conn(tmp_ctx, domain, &samr_pipe, &dom_pol); if (!NT_STATUS_IS_OK(status)) { goto done; } b = samr_pipe->binding_handle; status = rpc_lookup_useraliases(tmp_ctx, samr_pipe, &dom_pol, num_sids, sids, &num_aliases, &alias_rids); if (!NT_STATUS_IS_OK(status)) { goto done; } if (pnum_aliases) { *pnum_aliases = num_aliases; } if (palias_rids) { *palias_rids = talloc_move(mem_ctx, &alias_rids); } done: if (b && is_valid_policy_hnd(&dom_pol)) { dcerpc_samr_Close(b, mem_ctx, &dom_pol, &result); } TALLOC_FREE(tmp_ctx); return status; }
static void interpret_interface(char *token) { struct sockaddr_storage ss; struct sockaddr_storage ss_mask; struct sockaddr_storage ss_net; struct sockaddr_storage ss_bcast; struct iface_struct ifs; char *p; int i; bool added=false; bool goodaddr = false; /* first check if it is an interface name */ for (i=0;i<total_probed;i++) { if (gen_fnmatch(token, probed_ifaces[i].name) == 0) { add_interface(&probed_ifaces[i]); added = true; } } if (added) { return; } /* maybe it is a DNS name */ p = strchr_m(token,'/'); if (p == NULL) { if (!interpret_string_addr(&ss, token, 0)) { DEBUG(2, ("interpret_interface: Can't find address " "for %s\n", token)); return; } for (i=0;i<total_probed;i++) { if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&probed_ifaces[i].ip)) { add_interface(&probed_ifaces[i]); return; } } DEBUG(2,("interpret_interface: " "can't determine interface for %s\n", token)); return; } /* parse it into an IP address/netmasklength pair */ *p = 0; goodaddr = interpret_string_addr(&ss, token, 0); *p++ = '/'; if (!goodaddr) { DEBUG(2,("interpret_interface: " "can't determine interface for %s\n", token)); return; } if (strlen(p) > 2) { goodaddr = interpret_string_addr(&ss_mask, p, 0); if (!goodaddr) { DEBUG(2,("interpret_interface: " "can't determine netmask from %s\n", p)); return; } } else { char *endp = NULL; unsigned long val = strtoul(p, &endp, 0); if (p == endp || (endp && *endp != '\0')) { DEBUG(2,("interpret_interface: " "can't determine netmask value from %s\n", p)); return; } if (!make_netmask(&ss_mask, &ss, val)) { DEBUG(2,("interpret_interface: " "can't apply netmask value %lu from %s\n", val, p)); return; } } make_bcast(&ss_bcast, &ss, &ss_mask); make_net(&ss_net, &ss, &ss_mask); /* Maybe the first component was a broadcast address. */ if (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) || sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) { for (i=0;i<total_probed;i++) { if (same_net((struct sockaddr *)&ss, (struct sockaddr *)&probed_ifaces[i].ip, (struct sockaddr *)&ss_mask)) { /* Temporarily replace netmask on * the detected interface - user knows * best.... */ struct sockaddr_storage saved_mask = probed_ifaces[i].netmask; probed_ifaces[i].netmask = ss_mask; DEBUG(2,("interpret_interface: " "using netmask value %s from " "config file on interface %s\n", p, probed_ifaces[i].name)); add_interface(&probed_ifaces[i]); probed_ifaces[i].netmask = saved_mask; return; } } DEBUG(2,("interpret_interface: Can't determine ip for " "broadcast address %s\n", token)); return; } /* Just fake up the interface definition. User knows best. */ DEBUG(2,("interpret_interface: Adding interface %s\n", token)); ZERO_STRUCT(ifs); (void)strlcpy(ifs.name, token, sizeof(ifs.name)); ifs.flags = IFF_BROADCAST; ifs.ip = ss; ifs.netmask = ss_mask; ifs.bcast = ss_bcast; add_interface(&ifs); }
static NTSTATUS sam_rids_to_names(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, uint32 *rids, size_t num_rids, char **pdomain_name, char ***pnames, enum lsa_SidType **ptypes) { struct rpc_pipe_client *lsa_pipe; struct policy_handle lsa_policy; enum lsa_SidType *types = NULL; char *domain_name = NULL; char **names = NULL; TALLOC_CTX *tmp_ctx; NTSTATUS status, result; struct dcerpc_binding_handle *b = NULL; DEBUG(3,("sam_rids_to_names for %s\n", domain->name)); ZERO_STRUCT(lsa_policy); /* Paranoia check */ if (!sid_check_is_builtin(domain_sid) && !sid_check_is_our_sam(domain_sid) && !sid_check_is_unix_users(domain_sid) && !sid_check_is_unix_groups(domain_sid) && !sid_check_is_in_wellknown_domain(domain_sid)) { DEBUG(0, ("sam_rids_to_names: possible deadlock - trying to " "lookup SID %s\n", sid_string_dbg(domain_sid))); return NT_STATUS_NONE_MAPPED; } tmp_ctx = talloc_stackframe(); if (tmp_ctx == NULL) { return NT_STATUS_NO_MEMORY; } status = open_internal_lsa_conn(tmp_ctx, &lsa_pipe, &lsa_policy); if (!NT_STATUS_IS_OK(status)) { goto done; } b = lsa_pipe->binding_handle; status = rpc_rids_to_names(tmp_ctx, lsa_pipe, &lsa_policy, domain, domain_sid, rids, num_rids, &domain_name, &names, &types); if (!NT_STATUS_IS_OK(status)) { goto done; } if (pdomain_name) { *pdomain_name = talloc_move(mem_ctx, &domain_name); } if (ptypes) { *ptypes = talloc_move(mem_ctx, &types); } if (pnames) { *pnames = talloc_move(mem_ctx, &names); } done: if (b && is_valid_policy_hnd(&lsa_policy)) { dcerpc_lsa_Close(b, mem_ctx, &lsa_policy, &result); } TALLOC_FREE(tmp_ctx); return status; }
/* Lookup group membership given a rid. */ static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const struct dom_sid *group_sid, enum lsa_SidType type, uint32_t *pnum_names, struct dom_sid **psid_mem, char ***pnames, uint32_t **pname_types) { struct rpc_pipe_client *samr_pipe; struct policy_handle dom_pol; uint32_t num_names = 0; struct dom_sid *sid_mem = NULL; char **names = NULL; uint32_t *name_types = NULL; TALLOC_CTX *tmp_ctx; NTSTATUS status, result; struct dcerpc_binding_handle *b = NULL; DEBUG(3,("sam_lookup_groupmem\n")); ZERO_STRUCT(dom_pol); /* Paranoia check */ if (sid_check_is_in_builtin(group_sid) && (type != SID_NAME_ALIAS)) { /* There's no groups, only aliases in BUILTIN */ return NT_STATUS_NO_SUCH_GROUP; } if (pnum_names) { *pnum_names = 0; } tmp_ctx = talloc_stackframe(); if (tmp_ctx == NULL) { return NT_STATUS_NO_MEMORY; } status = open_internal_samr_conn(tmp_ctx, domain, &samr_pipe, &dom_pol); if (!NT_STATUS_IS_OK(status)) { goto done; } b = samr_pipe->binding_handle; status = rpc_lookup_groupmem(tmp_ctx, samr_pipe, &dom_pol, domain->name, &domain->sid, group_sid, type, &num_names, &sid_mem, &names, &name_types); if (pnum_names) { *pnum_names = num_names; } if (pnames) { *pnames = talloc_move(mem_ctx, &names); } if (pname_types) { *pname_types = talloc_move(mem_ctx, &name_types); } if (psid_mem) { *psid_mem = talloc_move(mem_ctx, &sid_mem); } done: if (b && is_valid_policy_hnd(&dom_pol)) { dcerpc_samr_Close(b, mem_ctx, &dom_pol, &result); } TALLOC_FREE(tmp_ctx); return status; }
static PyObject *samr_set_user_info2(PyObject *self, PyObject *args, PyObject *kw) { samr_user_hnd_object *user_hnd = (samr_user_hnd_object *)self; static char *kwlist[] = { "dict", NULL }; PyObject *info, *result = NULL; SAM_USERINFO_CTR ctr; TALLOC_CTX *mem_ctx; uchar sess_key[16]; NTSTATUS ntstatus; int level; union { SAM_USER_INFO_16 id16; SAM_USER_INFO_21 id21; } pinfo; if (!PyArg_ParseTupleAndKeywords( args, kw, "O!", kwlist, &PyDict_Type, &info)) return NULL; if (!get_level_value(info, &level)) { PyErr_SetString(samr_error, "invalid info level"); return NULL; } ZERO_STRUCT(ctr); ctr.switch_value = level; switch(level) { case 16: ctr.info.id16 = &pinfo.id16; if (!py_to_SAM_USER_INFO_16(ctr.info.id16, info)) { PyErr_SetString( samr_error, "error converting user info"); goto done; } break; case 21: ctr.info.id21 = &pinfo.id21; if (!py_to_SAM_USER_INFO_21(ctr.info.id21, info)) { PyErr_SetString( samr_error, "error converting user info"); goto done; } break; default: PyErr_SetString(samr_error, "unsupported info level"); goto done; } /* Call RPC function */ if (!(mem_ctx = talloc_init("samr_set_user_info2"))) { PyErr_SetString( samr_error, "unable to init talloc context\n"); goto done; } ntstatus = rpccli_samr_set_userinfo2( user_hnd->cli, mem_ctx, &user_hnd->user_pol, level, sess_key, &ctr); talloc_destroy(mem_ctx); if (!NT_STATUS_IS_OK(ntstatus)) { PyErr_SetObject(samr_ntstatus, py_ntstatus_tuple(ntstatus)); goto done; } Py_INCREF(Py_None); result = Py_None; done: return result; }
static bool test_smb2_open_brlocked(struct torture_context *tctx, struct smb2_tree *tree) { union smb_open io, io1; union smb_lock io2; struct smb2_lock_element lock[1]; const char *fname = DNAME "\\torture_ntcreatex.txt"; NTSTATUS status; bool ret = true; struct smb2_handle h; char b = 42; torture_comment(tctx, "Testing SMB2 open with a byte range locked file\n"); smb2_util_unlink(tree, fname); status = torture_smb2_testdir(tree, DNAME, &h); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(io.smb2); io.generic.level = RAW_OPEN_SMB2; io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED; io.smb2.in.desired_access = 0x2019f; io.smb2.in.alloc_size = 0; io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE; io.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; io.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING; io.smb2.in.fname = fname; status = smb2_create(tree, tctx, &(io.smb2)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_write(tree, io.smb2.out.file.handle, &b, 0, 1); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(io2.smb2); io2.smb2.level = RAW_LOCK_SMB2; io2.smb2.in.file.handle = io.smb2.out.file.handle; io2.smb2.in.lock_count = 1; ZERO_STRUCT(lock); lock[0].offset = 0; lock[0].length = 1; lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; io2.smb2.in.locks = &lock[0]; status = smb2_lock(tree, &(io2.smb2)); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(io1.smb2); io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED; io1.smb2.in.desired_access = 0x20196; io1.smb2.in.alloc_size = 0; io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io1.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; io1.smb2.in.create_options = 0; io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; io1.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING; io1.smb2.in.fname = fname; status = smb2_create(tree, tctx, &(io1.smb2)); CHECK_STATUS(status, NT_STATUS_OK); smb2_util_close(tree, io.smb2.out.file.handle); smb2_util_close(tree, io1.smb2.out.file.handle); smb2_util_unlink(tree, fname); smb2_deltree(tree, DNAME); return ret; }
static int rpc_trust_common(struct net_context *net_ctx, int argc, const char **argv, enum trust_op op) { TALLOC_CTX *mem_ctx; NTSTATUS status; int ret; int success = -1; struct cli_state *cli[2] = {NULL, NULL}; struct rpc_pipe_client *pipe_hnd[2] = {NULL, NULL}; DATA_BLOB session_key[2]; struct policy_handle pol_hnd[2]; struct lsa_TrustDomainInfoAuthInfoInternal authinfo; DATA_BLOB auth_blob; char *trust_pw = NULL; struct other_dom_data *other_dom_data; struct net_context *other_net_ctx = NULL; struct dom_data dom_data[2]; void (*usage)(void); ZERO_STRUCT(session_key); switch (op) { case TRUST_CREATE: usage = print_trust_usage; break; case TRUST_DELETE: usage = print_trust_delete_usage; break; default: DEBUG(0, ("Unsupported trust operation.\n")); return -1; } if (net_ctx->display_usage) { usage(); return 0; } mem_ctx = talloc_init("trust op"); if (mem_ctx == NULL) { DEBUG(0, ("talloc_init failed.\n")); return -1; } ret = parse_trust_args(mem_ctx, argc, argv, &other_dom_data, &trust_pw); if (ret != 0) { if (ret == EINVAL) { usage(); } else { DEBUG(0, ("Failed to parse arguments.\n")); } goto done; } if (other_dom_data->host != 0) { other_net_ctx = talloc_zero(other_dom_data, struct net_context); if (other_net_ctx == NULL) { DEBUG(0, ("talloc_zero failed.\n")); goto done; } other_net_ctx->opt_host = other_dom_data->host; other_net_ctx->opt_user_name = other_dom_data->user_name; } else {
static bool test_smb2_open_multi(struct torture_context *tctx, struct smb2_tree *tree) { const char *fname = "test_oplock.dat"; NTSTATUS status; bool ret = true; union smb_open io; struct smb2_tree **trees; struct smb2_request **requests; union smb_open *ios; int i, num_files = 3; int num_ok = 0; int num_collision = 0; torture_comment(tctx, "Testing SMB2 Open with multiple connections\n"); trees = talloc_array(tctx, struct smb2_tree *, num_files); requests = talloc_array(tctx, struct smb2_request *, num_files); ios = talloc_array(tctx, union smb_open, num_files); if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) || (ios == NULL)) { torture_comment(tctx, ("talloc failed\n")); ret = false; goto done; } tree->session->transport->options.request_timeout = 60; for (i=0; i<num_files; i++) { if (!torture_smb2_connection(tctx, &(trees[i]))) { torture_comment(tctx, "Could not open %d'th connection\n", i); ret = false; goto done; } trees[i]->session->transport->options.request_timeout = 60; } /* cleanup */ smb2_util_unlink(tree, fname); /* base ntcreatex parms */ ZERO_STRUCT(io.smb2); io.generic.level = RAW_OPEN_SMB2; io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL; io.smb2.in.alloc_size = 0; io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE| NTCREATEX_SHARE_ACCESS_DELETE; io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; io.smb2.in.create_options = 0; io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; io.smb2.in.security_flags = 0; io.smb2.in.fname = fname; io.smb2.in.create_flags = 0; for (i=0; i<num_files; i++) { ios[i] = io; requests[i] = smb2_create_send(trees[i], &(ios[i].smb2)); if (requests[i] == NULL) { torture_comment(tctx, "could not send %d'th request\n", i); ret = false; goto done; } } torture_comment(tctx, "waiting for replies\n"); while (1) { bool unreplied = false; for (i=0; i<num_files; i++) { if (requests[i] == NULL) { continue; } if (requests[i]->state < SMB2_REQUEST_DONE) { unreplied = true; break; } status = smb2_create_recv(requests[i], tctx, &(ios[i].smb2)); torture_comment(tctx, "File %d returned status %s\n", i, nt_errstr(status)); if (NT_STATUS_IS_OK(status)) { num_ok += 1; } if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) { num_collision += 1; } requests[i] = NULL; } if (!unreplied) { break; } if (tevent_loop_once(tctx->ev) != 0) { torture_comment(tctx, "tevent_loop_once failed\n"); ret = false; goto done; } } if ((num_ok != 1) || (num_ok + num_collision != num_files)) { ret = false; } done: smb2_deltree(tree, fname); return ret; }
static bool test_smb2_open_for_delete(struct torture_context *tctx, struct smb2_tree *tree) { union smb_open io; union smb_fileinfo finfo; const char *fname = DNAME "\\torture_open_for_delete.txt"; NTSTATUS status; struct smb2_handle h, h1; bool ret = true; torture_comment(tctx, "Checking SMB2_OPEN for delete on a readonly file.\n"); smb2_util_unlink(tree, fname); smb2_deltree(tree, fname); status = torture_smb2_testdir(tree, DNAME, &h); CHECK_STATUS(status, NT_STATUS_OK); /* reasonable default parameters */ ZERO_STRUCT(io.smb2); io.generic.level = RAW_OPEN_SMB2; io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED; io.smb2.in.alloc_size = 0; io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL; io.smb2.in.file_attributes = FILE_ATTRIBUTE_READONLY; io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; io.smb2.in.create_options = 0; io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; io.smb2.in.security_flags = 0; io.smb2.in.fname = fname; /* Create the readonly file. */ status = smb2_create(tree, tctx, &(io.smb2)); CHECK_STATUS(status, NT_STATUS_OK); h1 = io.smb2.out.file.handle; CHECK_VAL(io.smb2.out.oplock_level, 0); io.smb2.in.create_options = 0; CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED); CHECK_ALL_INFO(io.smb2.out.file_attr, attrib); smb2_util_close(tree, h1); /* Now try and open for delete only - should succeed. */ io.smb2.in.desired_access = SEC_STD_DELETE; io.smb2.in.file_attributes = 0; io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; status = smb2_create(tree, tctx, &(io.smb2)); CHECK_STATUS(status, NT_STATUS_OK); smb2_util_unlink(tree, fname); smb2_util_close(tree, h1); smb2_util_unlink(tree, fname); smb2_deltree(tree, DNAME); return ret; }
/* open a file */ static NTSTATUS svfs_open(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_open *io) { struct svfs_private *p = ntvfs->private_data; char *unix_path; struct stat st; int fd, flags; struct svfs_file *f; int create_flags, rdwr_flags; bool readonly; NTSTATUS status; struct ntvfs_handle *handle; if (io->generic.level != RAW_OPEN_GENERIC) { return ntvfs_map_open(ntvfs, req, io); } readonly = share_bool_option(ntvfs->ctx->config, SHARE_READONLY, SHARE_READONLY_DEFAULT); if (readonly) { create_flags = 0; rdwr_flags = O_RDONLY; } else { create_flags = O_CREAT; rdwr_flags = O_RDWR; } unix_path = svfs_unix_path(ntvfs, req, io->ntcreatex.in.fname); switch (io->generic.in.open_disposition) { case NTCREATEX_DISP_SUPERSEDE: case NTCREATEX_DISP_OVERWRITE_IF: flags = create_flags | O_TRUNC; break; case NTCREATEX_DISP_OPEN: case NTCREATEX_DISP_OVERWRITE: flags = 0; break; case NTCREATEX_DISP_CREATE: flags = create_flags | O_EXCL; break; case NTCREATEX_DISP_OPEN_IF: flags = create_flags; break; default: flags = 0; break; } flags |= rdwr_flags; if (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) { flags = O_RDONLY | O_DIRECTORY; if (readonly) { goto do_open; } switch (io->generic.in.open_disposition) { case NTCREATEX_DISP_CREATE: if (mkdir(unix_path, 0755) == -1) { DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path, errno)); return map_nt_error_from_unix(errno); } break; case NTCREATEX_DISP_OPEN_IF: if (mkdir(unix_path, 0755) == -1 && errno != EEXIST) { DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path, errno)); return map_nt_error_from_unix(errno); } break; } } do_open: fd = open(unix_path, flags, 0644); if (fd == -1) { return map_nt_error_from_unix(errno); } if (fstat(fd, &st) == -1) { DEBUG(9,("svfs_open: fstat errno=%d\n", errno)); close(fd); return map_nt_error_from_unix(errno); } status = ntvfs_handle_new(ntvfs, req, &handle); NT_STATUS_NOT_OK_RETURN(status); f = talloc(handle, struct svfs_file); NT_STATUS_HAVE_NO_MEMORY(f); f->fd = fd; f->name = talloc_strdup(f, unix_path); NT_STATUS_HAVE_NO_MEMORY(f->name); DLIST_ADD(p->open_files, f); status = ntvfs_handle_set_backend_data(handle, ntvfs, f); NT_STATUS_NOT_OK_RETURN(status); ZERO_STRUCT(io->generic.out); unix_to_nt_time(&io->generic.out.create_time, st.st_ctime); unix_to_nt_time(&io->generic.out.access_time, st.st_atime); unix_to_nt_time(&io->generic.out.write_time, st.st_mtime); unix_to_nt_time(&io->generic.out.change_time, st.st_mtime); io->generic.out.file.ntvfs = handle; io->generic.out.alloc_size = st.st_size; io->generic.out.size = st.st_size; io->generic.out.attrib = svfs_unix_to_dos_attrib(st.st_mode); io->generic.out.is_directory = S_ISDIR(st.st_mode) ? 1 : 0; return NT_STATUS_OK; }
/* * Test creating a file with a NULL DACL. */ static bool test_create_null_dacl(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; struct smb2_create io; const char *fname = "nulldacl.txt"; bool ret = true; struct smb2_handle handle; union smb_fileinfo q; union smb_setfileinfo s; struct security_descriptor *sd = security_descriptor_initialise(tctx); struct security_acl dacl; torture_comment(tctx, "TESTING SEC_DESC WITH A NULL DACL\n"); smb2_util_unlink(tree, fname); ZERO_STRUCT(io); io.level = RAW_OPEN_SMB2; io.in.create_flags = 0; io.in.desired_access = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC | SEC_STD_WRITE_OWNER; io.in.create_options = 0; io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.in.alloc_size = 0; io.in.create_disposition = NTCREATEX_DISP_CREATE; io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS; io.in.security_flags = 0; io.in.fname = fname; io.in.sec_desc = sd; /* XXX create_options ? */ io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | NTCREATEX_OPTIONS_ASYNC_ALERT | NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | 0x00200000; torture_comment(tctx, "creating a file with a empty sd\n"); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); handle = io.out.file.handle; torture_comment(tctx, "get the original sd\n"); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); /* * Testing the created DACL, * the server should add the inherited DACL * when SEC_DESC_DACL_PRESENT isn't specified */ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) { ret = false; torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n"); } if (q.query_secdesc.out.sd->dacl == NULL) { ret = false; torture_fail_goto(tctx, done, "no DACL has been created on the server!\n"); } torture_comment(tctx, "set NULL DACL\n"); sd->type |= SEC_DESC_DACL_PRESENT; s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; s.set_secdesc.in.file.handle = handle; s.set_secdesc.in.secinfo_flags = SECINFO_DACL; s.set_secdesc.in.sd = sd; status = smb2_setinfo_file(tree, &s); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "get the sd\n"); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); /* Testing the modified DACL */ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) { ret = false; torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n"); } if (q.query_secdesc.out.sd->dacl != NULL) { ret = false; torture_fail_goto(tctx, done, "DACL has been created on the server!\n"); } io.in.create_disposition = NTCREATEX_DISP_OPEN; torture_comment(tctx, "try open for read control\n"); io.in.desired_access = SEC_STD_READ_CONTROL; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_STD_READ_CONTROL); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for write\n"); io.in.desired_access = SEC_FILE_WRITE_DATA; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_FILE_WRITE_DATA); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for read\n"); io.in.desired_access = SEC_FILE_READ_DATA; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_FILE_READ_DATA); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for generic write\n"); io.in.desired_access = SEC_GENERIC_WRITE; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_RIGHTS_FILE_WRITE); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for generic read\n"); io.in.desired_access = SEC_GENERIC_READ; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_RIGHTS_FILE_READ); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "set DACL with 0 aces\n"); ZERO_STRUCT(dacl); dacl.revision = SECURITY_ACL_REVISION_NT4; dacl.num_aces = 0; sd->dacl = &dacl; s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; s.set_secdesc.in.file.handle = handle; s.set_secdesc.in.secinfo_flags = SECINFO_DACL; s.set_secdesc.in.sd = sd; status = smb2_setinfo_file(tree, &s); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "get the sd\n"); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); /* Testing the modified DACL */ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) { ret = false; torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n"); } if (q.query_secdesc.out.sd->dacl == NULL) { ret = false; torture_fail_goto(tctx, done, "no DACL has been created on the server!\n"); } if (q.query_secdesc.out.sd->dacl->num_aces != 0) { torture_result(tctx, TORTURE_FAIL, "DACL has %u aces!\n", q.query_secdesc.out.sd->dacl->num_aces); ret = false; goto done; } torture_comment(tctx, "try open for read control\n"); io.in.desired_access = SEC_STD_READ_CONTROL; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_STD_READ_CONTROL); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for write => access_denied\n"); io.in.desired_access = SEC_FILE_WRITE_DATA; status = smb2_create(tree, tctx, &io); if (torture_setting_bool(tctx, "hide_on_access_denied", false)) { CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "try open for read => access_denied\n"); io.in.desired_access = SEC_FILE_READ_DATA; status = smb2_create(tree, tctx, &io); if (torture_setting_bool(tctx, "hide_on_access_denied", false)) { CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "try open for generic write => access_denied\n"); io.in.desired_access = SEC_GENERIC_WRITE; status = smb2_create(tree, tctx, &io); if (torture_setting_bool(tctx, "hide_on_access_denied", false)) { CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "try open for generic read => access_denied\n"); io.in.desired_access = SEC_GENERIC_READ; status = smb2_create(tree, tctx, &io); if (torture_setting_bool(tctx, "hide_on_access_denied", false)) { CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "set empty sd\n"); sd->type &= ~SEC_DESC_DACL_PRESENT; sd->dacl = NULL; s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; s.set_secdesc.in.file.handle = handle; s.set_secdesc.in.secinfo_flags = SECINFO_DACL; s.set_secdesc.in.sd = sd; status = smb2_setinfo_file(tree, &s); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "get the sd\n"); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); /* Testing the modified DACL */ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) { ret = false; torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n"); } if (q.query_secdesc.out.sd->dacl != NULL) { ret = false; torture_fail_goto(tctx, done, "DACL has been created on the server!\n"); } done: smb2_util_close(tree, handle); smb2_util_unlink(tree, fname); smb2_tdis(tree); smb2_logoff(tree->session); return ret; }
/* continue a search */ static NTSTATUS svfs_search_next(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_search_next *io, void *search_private, bool (*callback)(void *, const union smb_search_data *)) { struct svfs_dir *dir; int i; struct svfs_private *p = ntvfs->private_data; struct search_state *search; union smb_search_data file; unsigned int max_count; if (io->generic.level != RAW_SEARCH_TRANS2) { return NT_STATUS_NOT_SUPPORTED; } if (io->generic.data_level != RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO) { return NT_STATUS_NOT_SUPPORTED; } for (search=p->search; search; search = search->next) { if (search->handle == io->t2fnext.in.handle) break; } if (!search) { /* we didn't find the search handle */ return NT_STATUS_FOOBAR; } dir = search->dir; /* the client might be asking for something other than just continuing with the search */ if (!(io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) && (io->t2fnext.in.flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) && io->t2fnext.in.last_name && *io->t2fnext.in.last_name) { /* look backwards first */ for (i=search->current_index; i > 0; i--) { if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) { search->current_index = i; goto found; } } /* then look forwards */ for (i=search->current_index+1; i <= dir->count; i++) { if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) { search->current_index = i; goto found; } } } found: max_count = search->current_index + io->t2fnext.in.max_count; if (max_count > dir->count) { max_count = dir->count; } for (i = search->current_index; i < max_count;i++) { ZERO_STRUCT(file); unix_to_nt_time(&file.both_directory_info.create_time, dir->files[i].st.st_ctime); unix_to_nt_time(&file.both_directory_info.access_time, dir->files[i].st.st_atime); unix_to_nt_time(&file.both_directory_info.write_time, dir->files[i].st.st_mtime); unix_to_nt_time(&file.both_directory_info.change_time, dir->files[i].st.st_mtime); file.both_directory_info.name.s = dir->files[i].name; file.both_directory_info.short_name.s = dir->files[i].name; file.both_directory_info.size = dir->files[i].st.st_size; file.both_directory_info.attrib = svfs_unix_to_dos_attrib(dir->files[i].st.st_mode); if (!callback(search_private, &file)) { break; } } io->t2fnext.out.count = i - search->current_index; io->t2fnext.out.end_of_search = (i == dir->count) ? 1 : 0; search->current_index = i; /* work out if we are going to keep the search state */ if ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) || ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) { DLIST_REMOVE(p->search, search); talloc_free(search); } return NT_STATUS_OK; }
/* test some interesting combinations found by gentest */ static bool test_create_gentest(struct torture_context *tctx, struct smb2_tree *tree) { struct smb2_create io; NTSTATUS status; uint32_t access_mask, file_attributes_set; uint32_t ok_mask, not_supported_mask, invalid_parameter_mask; uint32_t not_a_directory_mask, unexpected_mask; union smb_fileinfo q; ZERO_STRUCT(io); io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE| NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE; io.in.create_options = 0; io.in.fname = FNAME; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); io.in.create_options = 0xF0000000; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); io.in.create_options = 0; io.in.file_attributes = FILE_ATTRIBUTE_DEVICE; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); io.in.file_attributes = FILE_ATTRIBUTE_VOLUME; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); io.in.create_disposition = NTCREATEX_DISP_OPEN; io.in.file_attributes = FILE_ATTRIBUTE_VOLUME; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); io.in.create_disposition = NTCREATEX_DISP_CREATE; io.in.desired_access = 0x08000000; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); io.in.desired_access = 0x04000000; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); io.in.file_attributes = 0; io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; ok_mask = 0; not_supported_mask = 0; invalid_parameter_mask = 0; not_a_directory_mask = 0; unexpected_mask = 0; { int i; for (i=0;i<32;i++) { io.in.create_options = 1<<i; if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { continue; } status = smb2_create(tree, tctx, &io); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { not_supported_mask |= 1<<i; } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { invalid_parameter_mask |= 1<<i; } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) { not_a_directory_mask |= 1<<i; } else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) { ok_mask |= 1<<i; status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); } else { unexpected_mask |= 1<<i; torture_comment(tctx, "create option 0x%08x returned %s\n", 1<<i, nt_errstr(status)); } } } io.in.create_options = 0; CHECK_EQUAL(ok_mask, 0x00efcf7e); CHECK_EQUAL(not_a_directory_mask, 0x00000001); CHECK_EQUAL(not_supported_mask, 0x00102080); CHECK_EQUAL(invalid_parameter_mask, 0xff000000); CHECK_EQUAL(unexpected_mask, 0x00000000); io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; io.in.file_attributes = 0; access_mask = 0; { int i; for (i=0;i<32;i++) { io.in.desired_access = 1<<i; status = smb2_create(tree, tctx, &io); if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) { access_mask |= io.in.desired_access; } else { CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); } } } if (TARGET_IS_WIN7(tctx)) { CHECK_EQUAL(access_mask, 0x0de0fe00); } else if (torture_setting_bool(tctx, "samba4", false)) { CHECK_EQUAL(access_mask, 0x0cf0fe00); } else { CHECK_EQUAL(access_mask, 0x0df0fe00); } io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; io.in.file_attributes = 0; ok_mask = 0; invalid_parameter_mask = 0; unexpected_mask = 0; file_attributes_set = 0; { int i; for (i=0;i<32;i++) { io.in.file_attributes = 1<<i; if (io.in.file_attributes & FILE_ATTRIBUTE_ENCRYPTED) { continue; } smb2_deltree(tree, FNAME); status = smb2_create(tree, tctx, &io); if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { invalid_parameter_mask |= 1<<i; } else if (NT_STATUS_IS_OK(status)) { uint32_t expected; ok_mask |= 1<<i; expected = (io.in.file_attributes | FILE_ATTRIBUTE_ARCHIVE) & 0x00005127; io.out.file_attr &= ~FILE_ATTRIBUTE_NONINDEXED; CHECK_EQUAL(io.out.file_attr, expected); file_attributes_set |= io.out.file_attr; status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); } else { unexpected_mask |= 1<<i; torture_comment(tctx, "file attribute 0x%08x returned %s\n", 1<<i, nt_errstr(status)); } } } CHECK_EQUAL(ok_mask, 0x00003fb7); CHECK_EQUAL(invalid_parameter_mask, 0xffff8048); CHECK_EQUAL(unexpected_mask, 0x00000000); CHECK_EQUAL(file_attributes_set, 0x00001127); smb2_deltree(tree, FNAME); /* * Standalone servers doesn't support encryption */ io.in.file_attributes = FILE_ATTRIBUTE_ENCRYPTED; status = smb2_create(tree, tctx, &io); if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { torture_comment(tctx, "FILE_ATTRIBUTE_ENCRYPTED returned %s\n", nt_errstr(status)); } else { CHECK_STATUS(status, NT_STATUS_OK); CHECK_EQUAL(io.out.file_attr, (FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_ARCHIVE)); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); } smb2_deltree(tree, FNAME); ZERO_STRUCT(io); io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; io.in.file_attributes = 0; io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; io.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE; io.in.create_options = 0; io.in.fname = FNAME ":stream1"; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); io.in.fname = FNAME; io.in.file_attributes = 0x8040; io.in.share_access = NTCREATEX_SHARE_ACCESS_READ; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); io.in.fname = FNAME; io.in.file_attributes = 0; io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA; io.in.query_maximal_access = true; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_EQUAL(io.out.maximal_access, 0x001f01ff); q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; q.access_information.in.file.handle = io.out.file.handle; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access); io.in.file_attributes = 0; io.in.desired_access = 0; io.in.query_maximal_access = false; io.in.share_access = 0; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); smb2_deltree(tree, FNAME); return true; }
bool make_user_info_netlogon_interactive(struct auth_usersupplied_info **user_info, const char *smb_name, const char *client_domain, const char *workstation_name, uint32 logon_parameters, const uchar chal[8], const uchar lm_interactive_pwd[16], const uchar nt_interactive_pwd[16], const uchar *dc_sess_key) { struct samr_Password lm_pwd; struct samr_Password nt_pwd; unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; unsigned char key[16]; memcpy(key, dc_sess_key, 16); if (lm_interactive_pwd) memcpy(lm_pwd.hash, lm_interactive_pwd, sizeof(lm_pwd.hash)); if (nt_interactive_pwd) memcpy(nt_pwd.hash, nt_interactive_pwd, sizeof(nt_pwd.hash)); #ifdef DEBUG_PASSWORD DEBUG(100,("key:")); dump_data(100, key, sizeof(key)); DEBUG(100,("lm owf password:"******"nt owf password:"******"decrypt of lm owf password:"******"decrypt of nt owf password:")); dump_data(100, nt_pwd.hash, sizeof(nt_pwd)); #endif if (lm_interactive_pwd) SMBOWFencrypt(lm_pwd.hash, chal, local_lm_response); if (nt_interactive_pwd) SMBOWFencrypt(nt_pwd.hash, chal, local_nt_response); /* Password info paranoia */ ZERO_STRUCT(key); { bool ret; NTSTATUS nt_status; DATA_BLOB local_lm_blob; DATA_BLOB local_nt_blob; if (lm_interactive_pwd) { local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response)); } if (nt_interactive_pwd) { local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response)); } nt_status = make_user_info_map( user_info, smb_name, client_domain, workstation_name, lm_interactive_pwd ? &local_lm_blob : NULL, nt_interactive_pwd ? &local_nt_blob : NULL, lm_interactive_pwd ? &lm_pwd : NULL, nt_interactive_pwd ? &nt_pwd : NULL, NULL, AUTH_PASSWORD_HASH); if (NT_STATUS_IS_OK(nt_status)) { (*user_info)->logon_parameters = logon_parameters; } ret = NT_STATUS_IS_OK(nt_status) ? True : False; data_blob_free(&local_lm_blob); data_blob_free(&local_nt_blob); return ret; } }
/* try the various request blobs */ static bool test_create_blob(struct torture_context *tctx, struct smb2_tree *tree) { struct smb2_create io; NTSTATUS status; smb2_deltree(tree, FNAME); ZERO_STRUCT(io); io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE| NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE; io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | NTCREATEX_OPTIONS_ASYNC_ALERT | NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | 0x00200000; io.in.fname = FNAME; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing alloc size\n"); /* FIXME We use 1M cause that's the rounded size of Samba. * We should ask the server for the cluser size and calulate it * correctly. */ io.in.alloc_size = 0x00100000; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing durable open\n"); io.in.durable_open = true; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing query maximal access\n"); io.in.query_maximal_access = true; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_EQUAL(io.out.maximal_access, 0x001f01ff); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing timewarp\n"); io.in.timewarp = 10000; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); io.in.timewarp = 0; torture_comment(tctx, "Testing query_on_disk\n"); io.in.query_on_disk_id = true; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing unknown tag\n"); status = smb2_create_blob_add(tctx, &io.in.blobs, "FooO", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing bad tag length 0\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "x", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); torture_comment(tctx, "Testing bad tag length 1\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "x", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); torture_comment(tctx, "Testing bad tag length 2\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); torture_comment(tctx, "Testing bad tag length 3\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); torture_comment(tctx, "Testing tag length 4\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing tag length 5\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxxxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing tag length 6\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxxxxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing tag length 7\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxxxxxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing tag length 8\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxxxxxxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing tag length 16\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxxxxxxxxxxxxxxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing tag length 17\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxxxxxxxxxxxxxxxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Testing tag length 34\n"); ZERO_STRUCT(io.in.blobs); status = smb2_create_blob_add(tctx, &io.in.blobs, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", data_blob(NULL, 0)); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); smb2_deltree(tree, FNAME); return true; }
WERROR cli_srvsvc_net_share_enum(struct cli_state *cli, TALLOC_CTX *mem_ctx, uint32 info_level, SRV_SHARE_INFO_CTR *ctr, int preferred_len, ENUM_HND *hnd) { prs_struct qbuf, rbuf; SRV_Q_NET_SHARE_ENUM q; SRV_R_NET_SHARE_ENUM r; WERROR result = W_ERROR(ERRgeneral); int i; ZERO_STRUCT(q); ZERO_STRUCT(r); /* Initialise parse structures */ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); /* Initialise input parameters */ init_srv_q_net_share_enum( &q, cli->srv_name_slash, info_level, preferred_len, hnd); /* Marshall data and send request */ if (!srv_io_q_net_share_enum("", &q, &qbuf, 0) || !rpc_api_pipe_req(cli, SRV_NET_SHARE_ENUM_ALL, &qbuf, &rbuf)) goto done; /* Unmarshall response */ if (!srv_io_r_net_share_enum("", &r, &rbuf, 0)) goto done; result = r.status; if (!W_ERROR_IS_OK(result)) goto done; /* Oh yuck yuck yuck - we have to copy all the info out of the SRV_SHARE_INFO_CTR in the SRV_R_NET_SHARE_ENUM as when we do a prs_mem_free() it will all be invalidated. The various share info structures suck badly too. This really is gross. */ ZERO_STRUCTP(ctr); if (!r.ctr.num_entries) goto done; ctr->info_level = info_level; ctr->num_entries = r.ctr.num_entries; switch(info_level) { case 1: ctr->share.info1 = (SRV_SHARE_INFO_1 *)talloc( mem_ctx, sizeof(SRV_SHARE_INFO_1) * ctr->num_entries); memset(ctr->share.info1, 0, sizeof(SRV_SHARE_INFO_1)); for (i = 0; i < ctr->num_entries; i++) { SRV_SHARE_INFO_1 *info1 = &ctr->share.info1[i]; char *s; /* Copy pointer crap */ memcpy(&info1->info_1, &r.ctr.share.info1[i].info_1, sizeof(SH_INFO_1)); /* Duplicate strings */ s = unistr2_tdup(mem_ctx, &r.ctr.share.info1[i].info_1_str.uni_netname); if (s) init_unistr2(&info1->info_1_str.uni_netname, s, UNI_STR_TERMINATE); s = unistr2_tdup(mem_ctx, &r.ctr.share.info1[i].info_1_str.uni_remark); if (s) init_unistr2(&info1->info_1_str.uni_remark, s, UNI_STR_TERMINATE); } break; case 2: ctr->share.info2 = (SRV_SHARE_INFO_2 *)talloc( mem_ctx, sizeof(SRV_SHARE_INFO_2) * ctr->num_entries); memset(ctr->share.info2, 0, sizeof(SRV_SHARE_INFO_2)); for (i = 0; i < ctr->num_entries; i++) { SRV_SHARE_INFO_2 *info2 = &ctr->share.info2[i]; char *s; /* Copy pointer crap */ memcpy(&info2->info_2, &r.ctr.share.info2[i].info_2, sizeof(SH_INFO_2)); /* Duplicate strings */ s = unistr2_tdup(mem_ctx, &r.ctr.share.info2[i].info_2_str.uni_netname); if (s) init_unistr2(&info2->info_2_str.uni_netname, s, UNI_STR_TERMINATE); s = unistr2_tdup(mem_ctx, &r.ctr.share.info2[i].info_2_str.uni_remark); if (s) init_unistr2(&info2->info_2_str.uni_remark, s, UNI_STR_TERMINATE); s = unistr2_tdup(mem_ctx, &r.ctr.share.info2[i].info_2_str.uni_path); if (s) init_unistr2(&info2->info_2_str.uni_path, s, UNI_STR_TERMINATE); s = unistr2_tdup(mem_ctx, &r.ctr.share.info2[i].info_2_str.uni_passwd); if (s) init_unistr2(&info2->info_2_str.uni_passwd, s, UNI_STR_TERMINATE); } break; } done: prs_mem_free(&qbuf); prs_mem_free(&rbuf); return result; }
/* try creating with acls */ static bool test_create_acl_ext(struct torture_context *tctx, struct smb2_tree *tree, bool test_dir) { bool ret = true; struct smb2_create io; NTSTATUS status; struct security_ace ace; struct security_descriptor *sd; struct dom_sid *test_sid; union smb_fileinfo q = {}; uint32_t attrib = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | (test_dir ? FILE_ATTRIBUTE_DIRECTORY : 0); NTSTATUS (*delete_func)(struct smb2_tree *, const char *) = test_dir ? smb2_util_rmdir : smb2_util_unlink; smb2_deltree(tree, FNAME); ZERO_STRUCT(io); io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.in.create_disposition = NTCREATEX_DISP_CREATE; io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT | 0x00200000 | (test_dir ? NTCREATEX_OPTIONS_DIRECTORY : (NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)); io.in.fname = FNAME; torture_comment(tctx, "basic create\n"); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = io.out.file.handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); sd = q.query_secdesc.out.sd; status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); status = delete_func(tree, FNAME); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "adding a new ACE\n"); test_sid = dom_sid_parse_talloc(tctx, SID_NT_AUTHENTICATED_USERS); ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.access_mask = SEC_STD_ALL; ace.trustee = *test_sid; status = security_descriptor_dacl_add(sd, &ace); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "creating a file with an initial ACL\n"); io.in.sec_desc = sd; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd)); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); status = delete_func(tree, FNAME); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "creating with attributes\n"); io.in.sec_desc = NULL; io.in.file_attributes = attrib; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib)); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); status = delete_func(tree, FNAME); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "creating with attributes and ACL\n"); io.in.sec_desc = sd; io.in.file_attributes = attrib; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd)); FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib)); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); status = delete_func(tree, FNAME); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "creating with attributes, ACL and owner\n"); sd = security_descriptor_dacl_create(tctx, 0, SID_WORLD, SID_BUILTIN_USERS, SID_WORLD, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_READ | SEC_STD_ALL, 0, NULL); io.in.sec_desc = sd; io.in.file_attributes = attrib; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd)); FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib)); done: status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); status = delete_func(tree, FNAME); CHECK_STATUS(status, NT_STATUS_OK); return ret; }
static NTSTATUS smbXsrv_open_global_store(struct smbXsrv_open_global0 *global) { struct smbXsrv_open_globalB global_blob; DATA_BLOB blob = data_blob_null; TDB_DATA key; TDB_DATA val; NTSTATUS status; enum ndr_err_code ndr_err; /* * TODO: if we use other versions than '0' * we would add glue code here, that would be able to * store the information in the old format. */ if (global->db_rec == NULL) { return NT_STATUS_INTERNAL_ERROR; } key = dbwrap_record_get_key(global->db_rec); val = dbwrap_record_get_value(global->db_rec); ZERO_STRUCT(global_blob); global_blob.version = smbXsrv_version_global_current(); if (val.dsize >= 8) { global_blob.seqnum = IVAL(val.dptr, 4); } global_blob.seqnum += 1; global_blob.info.info0 = global; ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob, (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_globalB); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(1,("smbXsrv_open_global_store: key '%s' ndr_push - %s\n", hex_encode_talloc(global->db_rec, key.dptr, key.dsize), nt_errstr(status))); TALLOC_FREE(global->db_rec); return status; } val = make_tdb_data(blob.data, blob.length); status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("smbXsrv_open_global_store: key '%s' store - %s\n", hex_encode_talloc(global->db_rec, key.dptr, key.dsize), nt_errstr(status))); TALLOC_FREE(global->db_rec); return status; } if (CHECK_DEBUGLVL(10)) { DEBUG(10,("smbXsrv_open_global_store: key '%s' stored\n", hex_encode_talloc(global->db_rec, key.dptr, key.dsize))); NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob); } TALLOC_FREE(global->db_rec); return NT_STATUS_OK; }
/* test SMB2 open */ static bool test_smb2_open(struct torture_context *tctx, struct smb2_tree *tree) { union smb_open io; union smb_fileinfo finfo; const char *fname = DNAME "\\torture_ntcreatex.txt"; const char *dname = DNAME "\\torture_ntcreatex.dir"; NTSTATUS status; struct smb2_handle h, h1; bool ret = true; int i; struct { uint32_t create_disp; bool with_file; NTSTATUS correct_status; } open_funcs[] = { { NTCREATEX_DISP_SUPERSEDE, true, NT_STATUS_OK }, { NTCREATEX_DISP_SUPERSEDE, false, NT_STATUS_OK }, { NTCREATEX_DISP_OPEN, true, NT_STATUS_OK }, { NTCREATEX_DISP_OPEN, false, NT_STATUS_OBJECT_NAME_NOT_FOUND }, { NTCREATEX_DISP_CREATE, true, NT_STATUS_OBJECT_NAME_COLLISION }, { NTCREATEX_DISP_CREATE, false, NT_STATUS_OK }, { NTCREATEX_DISP_OPEN_IF, true, NT_STATUS_OK }, { NTCREATEX_DISP_OPEN_IF, false, NT_STATUS_OK }, { NTCREATEX_DISP_OVERWRITE, true, NT_STATUS_OK }, { NTCREATEX_DISP_OVERWRITE, false, NT_STATUS_OBJECT_NAME_NOT_FOUND }, { NTCREATEX_DISP_OVERWRITE_IF, true, NT_STATUS_OK }, { NTCREATEX_DISP_OVERWRITE_IF, false, NT_STATUS_OK }, { 6, true, NT_STATUS_INVALID_PARAMETER }, { 6, false, NT_STATUS_INVALID_PARAMETER }, }; torture_comment(tctx, "Checking SMB2 Open\n"); smb2_util_unlink(tree, fname); smb2_util_rmdir(tree, dname); status = torture_smb2_testdir(tree, DNAME, &h); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(io.smb2); /* reasonable default parameters */ io.generic.level = RAW_OPEN_SMB2; io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED; io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL; io.smb2.in.alloc_size = 1024*1024; io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; io.smb2.in.create_options = 0; io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; io.smb2.in.security_flags = 0; io.smb2.in.fname = fname; /* test the create disposition */ for (i=0; i<ARRAY_SIZE(open_funcs); i++) { if (open_funcs[i].with_file) { io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; status= smb2_create(tree, tctx, &(io.smb2)); if (!NT_STATUS_IS_OK(status)) { torture_comment(tctx, "Failed to create file %s status %s %d\n", fname, nt_errstr(status), i); ret = false; goto done; } smb2_util_close(tree, io.smb2.out.file.handle); } io.smb2.in.create_disposition = open_funcs[i].create_disp; status = smb2_create(tree, tctx, &(io.smb2)); if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) { torture_comment(tctx, "(%s) incorrect status %s should be %s (i=%d " "with_file=%d open_disp=%d)\n", __location__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status), i, (int)open_funcs[i].with_file, (int)open_funcs[i].create_disp); ret = false; goto done; } if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) { smb2_util_close(tree, io.smb2.out.file.handle); smb2_util_unlink(tree, fname); } } /* basic field testing */ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; status = smb2_create(tree, tctx, &(io.smb2)); CHECK_STATUS(status, NT_STATUS_OK); h1 = io.smb2.out.file.handle; CHECK_VAL(io.smb2.out.oplock_level, 0); CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED); CHECK_NTTIME(io.smb2.out.create_time, create_time); CHECK_NTTIME(io.smb2.out.access_time, access_time); CHECK_NTTIME(io.smb2.out.write_time, write_time); CHECK_NTTIME(io.smb2.out.change_time, change_time); CHECK_ALL_INFO(io.smb2.out.file_attr, attrib); CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size); CHECK_ALL_INFO(io.smb2.out.size, size); /* check fields when the file already existed */ smb2_util_close(tree, h1); smb2_util_unlink(tree, fname); status = smb2_create_complex_file(tree, fname, &h1); CHECK_STATUS(status, NT_STATUS_OK); smb2_util_close(tree, h1); io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; status = smb2_create(tree, tctx, &(io.smb2)); CHECK_STATUS(status, NT_STATUS_OK); h1 = io.smb2.out.file.handle; CHECK_VAL(io.smb2.out.oplock_level, 0); CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_EXISTED); CHECK_NTTIME(io.smb2.out.create_time, create_time); CHECK_NTTIME(io.smb2.out.access_time, access_time); CHECK_NTTIME(io.smb2.out.write_time, write_time); CHECK_NTTIME(io.smb2.out.change_time, change_time); CHECK_ALL_INFO(io.smb2.out.file_attr, attrib); CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size); CHECK_ALL_INFO(io.smb2.out.size, size); smb2_util_close(tree, h1); smb2_util_unlink(tree, fname); /* create a directory */ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL; io.smb2.in.alloc_size = 0; io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.smb2.in.create_options = 0; io.smb2.in.fname = dname; fname = dname; smb2_util_rmdir(tree, fname); smb2_util_unlink(tree, fname); io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; status = smb2_create(tree, tctx, &(io.smb2)); CHECK_STATUS(status, NT_STATUS_OK); h1 = io.smb2.out.file.handle; CHECK_VAL(io.smb2.out.oplock_level, 0); CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED); CHECK_NTTIME(io.smb2.out.create_time, create_time); CHECK_NTTIME(io.smb2.out.access_time, access_time); CHECK_NTTIME(io.smb2.out.write_time, write_time); CHECK_NTTIME(io.smb2.out.change_time, change_time); CHECK_ALL_INFO(io.smb2.out.file_attr, attrib); CHECK_VAL(io.smb2.out.file_attr & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_DIRECTORY); CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size); CHECK_ALL_INFO(io.smb2.out.size, size); CHECK_VAL(io.smb2.out.size, 0); CHECK_VAL(io.smb2.out.alloc_size, 0); smb2_util_unlink(tree, fname); done: smb2_util_close(tree, h1); smb2_util_unlink(tree, fname); smb2_deltree(tree, DNAME); return ret; }
NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now) { struct smbXsrv_open_table *table; struct db_record *local_rec = NULL; struct db_record *global_rec = NULL; NTSTATUS status; NTSTATUS error = NT_STATUS_OK; if (op->table == NULL) { return NT_STATUS_OK; } table = op->table; op->table = NULL; op->status = NT_STATUS_FILE_CLOSED; op->global->disconnect_time = now; server_id_set_disconnected(&op->global->server_id); global_rec = op->global->db_rec; op->global->db_rec = NULL; if (global_rec == NULL) { uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE]; TDB_DATA key; key = smbXsrv_open_global_id_to_key( op->global->open_global_id, key_buf); global_rec = dbwrap_fetch_locked(table->global.db_ctx, op->global, key); if (global_rec == NULL) { DEBUG(0, ("smbXsrv_open_close(0x%08x): " "Failed to lock global key '%s'\n", op->global->open_global_id, hex_encode_talloc(global_rec, key.dptr, key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } if (global_rec != NULL && op->global->durable) { /* * If it is a durable open we need to update the global part * instead of deleting it */ op->global->db_rec = global_rec; status = smbXsrv_open_global_store(op->global); if (NT_STATUS_IS_OK(status)) { /* * smbXsrv_open_global_store does the free * of op->global->db_rec */ global_rec = NULL; } if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smbXsrv_open_close(0x%08x)" "smbXsrv_open_global_store() failed - %s\n", op->global->open_global_id, nt_errstr(status))); error = status; } if (NT_STATUS_IS_OK(status) && CHECK_DEBUGLVL(10)) { struct smbXsrv_openB open_blob; ZERO_STRUCT(open_blob); open_blob.version = SMBXSRV_VERSION_0; open_blob.info.info0 = op; DEBUG(10,("smbXsrv_open_close(0x%08x): " "stored disconnect\n", op->global->open_global_id)); NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob); } } if (global_rec != NULL) { status = dbwrap_record_delete(global_rec); if (!NT_STATUS_IS_OK(status)) { TDB_DATA key = dbwrap_record_get_key(global_rec); DEBUG(0, ("smbXsrv_open_close(0x%08x): " "failed to delete global key '%s': %s\n", op->global->open_global_id, hex_encode_talloc(global_rec, key.dptr, key.dsize), nt_errstr(status))); error = status; } } TALLOC_FREE(global_rec); local_rec = op->db_rec; if (local_rec == NULL) { uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE]; TDB_DATA key; key = smbXsrv_open_local_id_to_key(op->local_id, key_buf); local_rec = dbwrap_fetch_locked(table->local.db_ctx, op, key); if (local_rec == NULL) { DEBUG(0, ("smbXsrv_open_close(0x%08x): " "Failed to lock local key '%s'\n", op->global->open_global_id, hex_encode_talloc(local_rec, key.dptr, key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } if (local_rec != NULL) { status = dbwrap_record_delete(local_rec); if (!NT_STATUS_IS_OK(status)) { TDB_DATA key = dbwrap_record_get_key(local_rec); DEBUG(0, ("smbXsrv_open_close(0x%08x): " "failed to delete local key '%s': %s\n", op->global->open_global_id, hex_encode_talloc(local_rec, key.dptr, key.dsize), nt_errstr(status))); error = status; } table->local.num_opens -= 1; } if (op->db_rec == NULL) { TALLOC_FREE(local_rec); } op->db_rec = NULL; if (op->compat) { op->compat->op = NULL; file_free(NULL, op->compat); op->compat = NULL; } return error; }
static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, struct files_struct *fsp, uint8_t in_info_type, uint8_t in_file_info_class, uint32_t in_output_buffer_length, DATA_BLOB in_input_buffer, uint32_t in_additional_information, uint32_t in_flags) { struct tevent_req *req; struct smbd_smb2_getinfo_state *state; struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat_conn; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_getinfo_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->status = NT_STATUS_OK; state->out_output_buffer = data_blob_null; DEBUG(10,("smbd_smb2_getinfo_send: %s - fnum[%d]\n", fsp_str_dbg(fsp), fsp->fnum)); smbreq = smbd_smb2_fake_smb_request(smb2req); if (tevent_req_nomem(smbreq, req)) { return tevent_req_post(req, ev); } if (IS_IPC(conn)) { smb2_ipc_getinfo(req, state, ev, in_info_type, in_file_info_class); return tevent_req_post(req, ev); } switch (in_info_type) { case SMB2_GETINFO_FILE: { uint16_t file_info_level; char *data = NULL; unsigned int data_size = 0; bool delete_pending = false; struct timespec write_time_ts; struct file_id fileid; struct ea_list *ea_list = NULL; int lock_data_count = 0; char *lock_data = NULL; size_t fixed_portion; ZERO_STRUCT(write_time_ts); switch (in_file_info_class) { case 0x0F:/* RAW_FILEINFO_SMB2_ALL_EAS */ file_info_level = 0xFF00 | in_file_info_class; break; case 0x12:/* RAW_FILEINFO_SMB2_ALL_INFORMATION */ file_info_level = 0xFF00 | in_file_info_class; break; default: /* the levels directly map to the passthru levels */ file_info_level = in_file_info_class + 1000; break; } if (fsp->fake_file_handle) { /* * This is actually for the QUOTA_FAKE_FILE --metze */ /* We know this name is ok, it's already passed the checks. */ } else if (fsp && fsp->fh->fd == -1) { /* * This is actually a QFILEINFO on a directory * handle (returned from an NT SMB). NT5.0 seems * to do this call. JRA. */ if (INFO_LEVEL_IS_UNIX(file_info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) { DEBUG(3,("smbd_smb2_getinfo_send: " "SMB_VFS_LSTAT of %s failed " "(%s)\n", fsp_str_dbg(fsp), strerror(errno))); status = map_nt_error_from_unix(errno); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } } else if (SMB_VFS_STAT(conn, fsp->fsp_name)) { DEBUG(3,("smbd_smb2_getinfo_send: " "SMB_VFS_STAT of %s failed (%s)\n", fsp_str_dbg(fsp), strerror(errno))); status = map_nt_error_from_unix(errno); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } fileid = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); get_file_infos(fileid, fsp->name_hash, &delete_pending, &write_time_ts); } else { /* * Original code - this is an open file. */ if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { DEBUG(3, ("smbd_smb2_getinfo_send: " "fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); status = map_nt_error_from_unix(errno); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } fileid = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); get_file_infos(fileid, fsp->name_hash, &delete_pending, &write_time_ts); } status = smbd_do_qfilepathinfo(conn, state, file_info_level, fsp, fsp->fsp_name, delete_pending, write_time_ts, ea_list, lock_data_count, lock_data, STR_UNICODE, in_output_buffer_length, &fixed_portion, &data, &data_size); if (!NT_STATUS_IS_OK(status)) { SAFE_FREE(data); if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { status = NT_STATUS_INVALID_INFO_CLASS; } tevent_req_nterror(req, status); return tevent_req_post(req, ev); } if (in_output_buffer_length < fixed_portion) { SAFE_FREE(data); tevent_req_nterror( req, NT_STATUS_INFO_LENGTH_MISMATCH); return tevent_req_post(req, ev); } if (data_size > 0) { state->out_output_buffer = data_blob_talloc(state, data, data_size); SAFE_FREE(data); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return tevent_req_post(req, ev); } if (data_size > in_output_buffer_length) { state->out_output_buffer.length = in_output_buffer_length; status = STATUS_BUFFER_OVERFLOW; } } SAFE_FREE(data); break; } case SMB2_GETINFO_FS: { uint16_t file_info_level; char *data = NULL; int data_size = 0; size_t fixed_portion; /* the levels directly map to the passthru levels */ file_info_level = in_file_info_class + 1000; status = smbd_do_qfsinfo(conn, state, file_info_level, STR_UNICODE, in_output_buffer_length, &fixed_portion, fsp->fsp_name, &data, &data_size); /* some responses set STATUS_BUFFER_OVERFLOW and return partial, but valid data */ if (!(NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW))) { SAFE_FREE(data); if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { status = NT_STATUS_INVALID_INFO_CLASS; } tevent_req_nterror(req, status); return tevent_req_post(req, ev); } if (in_output_buffer_length < fixed_portion) { SAFE_FREE(data); tevent_req_nterror( req, NT_STATUS_INFO_LENGTH_MISMATCH); return tevent_req_post(req, ev); } if (data_size > 0) { state->out_output_buffer = data_blob_talloc(state, data, data_size); SAFE_FREE(data); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return tevent_req_post(req, ev); } if (data_size > in_output_buffer_length) { state->out_output_buffer.length = in_output_buffer_length; status = STATUS_BUFFER_OVERFLOW; } } SAFE_FREE(data); break; } case SMB2_GETINFO_SECURITY: { uint8_t *p_marshalled_sd = NULL; size_t sd_size = 0; status = smbd_do_query_security_desc(conn, state, fsp, /* Security info wanted. */ in_additional_information, in_output_buffer_length, &p_marshalled_sd, &sd_size); if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) { /* Return needed size. */ state->out_output_buffer = data_blob_talloc(state, NULL, 4); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return tevent_req_post(req, ev); } SIVAL(state->out_output_buffer.data,0,(uint32_t)sd_size); state->status = NT_STATUS_BUFFER_TOO_SMALL; break; } if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("smbd_smb2_getinfo_send: " "smbd_do_query_security_desc of %s failed " "(%s)\n", fsp_str_dbg(fsp), nt_errstr(status))); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } if (sd_size > 0) { state->out_output_buffer = data_blob_talloc(state, p_marshalled_sd, sd_size); if (tevent_req_nomem(state->out_output_buffer.data, req)) { return tevent_req_post(req, ev); } } break; } default: DEBUG(10,("smbd_smb2_getinfo_send: " "unknown in_info_type of %u " " for file %s\n", (unsigned int)in_info_type, fsp_str_dbg(fsp) )); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } state->status = status; tevent_req_done(req); return tevent_req_post(req, ev); }