static void try_expand(struct torture_context *tctx, const struct ndr_interface_table *iface, int opnum, DATA_BLOB *base_in, int insert_ofs, int depth) { DATA_BLOB stub_in, stub_out; int n; NTSTATUS status; struct dcerpc_pipe *p = NULL; reopen(tctx, &p, iface); /* work out how much to expand to get a non fault */ for (n=0;n<2000;n++) { stub_in = data_blob(NULL, base_in->length + n); data_blob_clear(&stub_in); memcpy(stub_in.data, base_in->data, insert_ofs); memcpy(stub_in.data+insert_ofs+n, base_in->data+insert_ofs, base_in->length-insert_ofs); status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { print_depth(depth); printf("expand by %d gives %s\n", n, nt_errstr(status)); if (n >= 4) { test_ptr_scan(tctx, iface, opnum, &stub_in, insert_ofs, insert_ofs+n, depth+1); } return; } else { #if 0 print_depth(depth); printf("expand by %d gives fault %s\n", n, dcerpc_errstr(tctx, p->last_fault_code)); #endif } if (p->last_fault_code == 5) { reopen(tctx, &p, iface); } } talloc_free(p); }
/* upgrade one alias record from the old tdb format */ static int upgrade_alias_record(TDB_CONTEXT *tdb_ctx, TDB_DATA key, TDB_DATA data, void *state) { const char *p = (const char *)data.dptr; char *string_sid; DOM_SID member; TALLOC_CTX *frame; if (strncmp((char *)key.dptr, MEMBEROF_PREFIX, MIN(key.dsize, strlen(MEMBEROF_PREFIX))) != 0) { return 0; } if (!string_to_sid(&member, strlen(MEMBEROF_PREFIX) + (const char *)key.dptr)) { DEBUG(0,("Bad alias key %s during upgrade\n", (const char *)key.dptr)); *(int *)state = -1; } frame = talloc_stackframe(); while (next_token_talloc(frame,&p, &string_sid, " ")) { DOM_SID alias; NTSTATUS status; string_to_sid(&alias, string_sid); status = add_aliasmem(&alias, &member); if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_ALIAS)) { DEBUG(0,("Ignoring orphaned alias record '%s'\n", string_sid)); } else if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to add alias member during upgrade - %s\n", nt_errstr(status))); *(int *)state = -1; TALLOC_FREE(frame); return -1; } } TALLOC_FREE(frame); return 0; }
/* mark the transport as dead */ void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status) { smbcli_sock_dead(transport->socket); if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) { status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; } /* kill only the first pending receive - this is so that if that async function frees the connection we don't die trying to use old memory. The caller has to cope with only one network error */ if (transport->pending_recv) { struct smbcli_request *req = transport->pending_recv; req->state = SMBCLI_REQUEST_ERROR; req->status = status; DLIST_REMOVE(transport->pending_recv, req); if (req->async.fn) { req->async.fn(req); } } }
static void test_ptr_scan(struct torture_context *tctx, const struct ndr_interface_table *iface, int opnum, DATA_BLOB *base_in, int min_ofs, int max_ofs, int depth) { DATA_BLOB stub_in, stub_out; int ofs; NTSTATUS status; struct dcerpc_pipe *p = NULL; reopen(tctx, &p, iface); stub_in = data_blob(NULL, base_in->length); memcpy(stub_in.data, base_in->data, base_in->length); /* work out which elements are pointers */ for (ofs=min_ofs;ofs<=max_ofs-4;ofs+=4) { SIVAL(stub_in.data, ofs, 1); status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { print_depth(depth); printf("possible ptr at ofs %d - fault %s\n", ofs-min_ofs, dcerpc_errstr(tctx, p->last_fault_code)); if (p->last_fault_code == 5) { reopen(tctx, &p, iface); } if (depth == 0) { try_expand(tctx, iface, opnum, &stub_in, ofs+4, depth+1); } else { try_expand(tctx, iface, opnum, &stub_in, max_ofs, depth+1); } SIVAL(stub_in.data, ofs, 0); continue; } SIVAL(stub_in.data, ofs, 0); } talloc_free(p); }
NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, struct auth_session_info **session_info) { NTSTATUS nt_status; struct gensec_ntlmssp_context *gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); uint32_t session_info_flags = 0; if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) { session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN; } session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; if (gensec_security->auth_context && gensec_security->auth_context->generate_session_info) { nt_status = gensec_security->auth_context->generate_session_info(gensec_security->auth_context, mem_ctx, gensec_ntlmssp->server_returned_info, gensec_ntlmssp->ntlmssp_state->user, session_info_flags, session_info); } else { DEBUG(0, ("Cannot generate a session_info without the auth_context\n")); return NT_STATUS_INTERNAL_ERROR; } NT_STATUS_NOT_OK_RETURN(nt_status); nt_status = gensec_ntlmssp_session_key(gensec_security, *session_info, &(*session_info)->session_key); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) { (*session_info)->session_key = data_blob_null; nt_status = NT_STATUS_OK; } return nt_status; }
static NTSTATUS rids_to_names(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *sid, uint32 *rids, size_t num_rids, char **domain_name, char ***names, enum lsa_SidType **types) { NTSTATUS result; result = msrpc_methods.rids_to_names(domain, mem_ctx, sid, rids, num_rids, domain_name, names, types); if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) { result = msrpc_methods.rids_to_names(domain, mem_ctx, sid, rids, num_rids, domain_name, names, types); } return result; }
static void smb2srv_sesssetup_send(struct smb2srv_request *req, union smb_sesssetup *io) { uint16_t unknown1; if (NT_STATUS_IS_OK(req->status)) { unknown1 = 0x0003; } else if (NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { unknown1 = 0x0002; } else { smb2srv_send_error(req, req->status); return; } SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, True, io->smb2.out.secblob.length)); SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, unknown1); SBVAL(req->out.hdr, SMB2_HDR_UID, io->smb2.out.uid); SSVAL(req->out.body, 0x02, io->smb2.out._pad); SMB2SRV_CHECK(smb2_push_o16s16_blob(&req->out, 0x04, io->smb2.out.secblob)); smb2srv_send_reply(req); }
/* perform the receive side of a async dcerpc request */ NTSTATUS dcerpc_request_recv(struct rpc_request *req, TALLOC_CTX *mem_ctx, DATA_BLOB *stub_data) { NTSTATUS status; while (req->state != RPC_REQUEST_DONE) { struct tevent_context *ctx = dcerpc_event_context(req->p); if (event_loop_once(ctx) != 0) { return NT_STATUS_CONNECTION_DISCONNECTED; } } *stub_data = req->payload; status = req->status; if (stub_data->data) { stub_data->data = talloc_steal(mem_ctx, stub_data->data); } if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { req->p->last_fault_code = req->fault_code; } talloc_unlink(talloc_parent(req), req); return status; }
static void smb2srv_sesssetup_send(struct smb2srv_request *req, union smb_sesssetup *io) { uint16_t credit; if (NT_STATUS_IS_OK(req->status)) { credit = 0x0003; } else if (NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { credit = 0x0002; } else { smb2srv_send_error(req, req->status); return; } SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, true, io->smb2.out.secblob.length)); SSVAL(req->out.hdr, SMB2_HDR_CREDIT, credit); SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, io->smb2.out.uid); SSVAL(req->out.body, 0x02, io->smb2.out.session_flags); SMB2SRV_CHECK(smb2_push_o16s16_blob(&req->out, 0x04, io->smb2.out.secblob)); smb2srv_send_reply(req); }
static NTSTATUS auth_generic_server_authtype_start_as_root(TALLOC_CTX *mem_ctx, uint8_t auth_type, uint8_t auth_level, DATA_BLOB *token_in, DATA_BLOB *token_out, const struct tsocket_address *remote_address, struct gensec_security **ctx) { struct gensec_security *gensec_security = NULL; NTSTATUS status; status = auth_generic_prepare(talloc_tos(), remote_address, &gensec_security); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, (__location__ ": auth_generic_prepare failed: %s\n", nt_errstr(status))); return status; } status = gensec_start_mech_by_authtype(gensec_security, auth_type, auth_level); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, (__location__ ": auth_generic_start failed: %s\n", nt_errstr(status))); TALLOC_FREE(gensec_security); return status; } status = gensec_update(gensec_security, mem_ctx, NULL, *token_in, token_out); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { DEBUG(2, (__location__ ": gensec_update failed: %s\n", nt_errstr(status))); TALLOC_FREE(gensec_security); return status; } /* steal gensec context to the caller */ *ctx = talloc_move(mem_ctx, &gensec_security); return NT_STATUS_OK; }
/* We should now have either an authenticated LSA pipe, or an error. * On success, open a policy handle */ static void init_domain_recv_lsa_pipe(struct composite_context *ctx) { struct rpc_request *req; struct init_domain_state *state = talloc_get_type(ctx->async.private_data, struct init_domain_state); state->ctx->status = dcerpc_secondary_auth_connection_recv(ctx, state->domain, &state->domain->libnet_ctx->lsa.pipe); if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_LOGON_FAILURE)) { if (retry_with_schannel(state, state->domain->lsa_binding, &ndr_table_lsarpc, init_domain_recv_lsa_pipe)) { return; } } if (!composite_is_ok(state->ctx)) return; talloc_steal(state->domain->libnet_ctx, state->domain->libnet_ctx->lsa.pipe); talloc_reparent(state, state->domain->libnet_ctx->lsa.pipe, state->domain->lsa_binding); state->domain->libnet_ctx->lsa.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; state->domain->libnet_ctx->lsa.name = state->domain->info->name; ZERO_STRUCT(state->domain->libnet_ctx->lsa.handle); state->lsa_openpolicy.in.system_name = talloc_asprintf(state, "\\\\%s", dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe)); ZERO_STRUCT(state->objectattr); state->lsa_openpolicy.in.attr = &state->objectattr; state->lsa_openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; state->lsa_openpolicy.out.handle = &state->domain->libnet_ctx->lsa.handle; req = dcerpc_lsa_OpenPolicy2_send(state->domain->libnet_ctx->lsa.pipe, state, &state->lsa_openpolicy); composite_continue_rpc(state->ctx, req, init_domain_recv_lsa_policy, state); }
/* see if the server recognises wide-a characters */ static BOOL test_widea(struct torture_context *tctx, struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { const uint32_t name1[] = {'a'}; const uint32_t name2[] = {0xff41}; const uint32_t name3[] = {0xff21}; NTSTATUS status; printf("Testing wide-a\n"); status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name1, 1); if (!NT_STATUS_IS_OK(status)) { printf("Failed to create 'a' - %s\n", nt_errstr(status)); return False; } status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name2, 1); if (!NT_STATUS_IS_OK(status)) { printf("Failed to create wide-a - %s\n", nt_errstr(status)); return False; } status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name3, 1); if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) { printf("Expected %s creating wide-A - %s\n", nt_errstr(NT_STATUS_OBJECT_NAME_COLLISION), nt_errstr(status)); return False; } return True; }
static ssize_t posix_eadb_getattr(struct tdb_wrap *db_ctx, const char *fname, int fd, const char *name, void *value, size_t size) { ssize_t result = -1; NTSTATUS status; DATA_BLOB blob; DEBUG(10, ("posix_eadb_getattr called for file %s/fd %d, name %s\n", fname, fd, name)); status = pull_xattr_blob_tdb_raw(db_ctx, talloc_tos(), name, fname, fd, size, &blob); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { errno = ENOATTR; return -1; } if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("posix_eadb_fetch_attrs failed: %s\n", nt_errstr(status))); errno = EINVAL; return -1; } if (blob.length > size) { errno = ERANGE; goto fail; } memcpy(value, blob.data, blob.length); result = blob.length; fail: return result; }
/**************************************************************************** Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available, and for tokenGroups in the DSDB stack. Supply either a principal or a DN ****************************************************************************/ _PUBLIC_ NTSTATUS auth_get_user_info_dc_principal(TALLOC_CTX *mem_ctx, struct auth_context *auth_ctx, const char *principal, struct ldb_dn *user_dn, struct auth_user_info_dc **user_info_dc) { NTSTATUS nt_status; struct auth_method_context *method; for (method = auth_ctx->methods; method; method = method->next) { if (!method->ops->get_user_info_dc_principal) { continue; } nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, user_info_dc); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { continue; } return nt_status; } return NT_STATUS_NOT_IMPLEMENTED; }
/* Lookup group membership given a rid. */ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, const DOM_SID *group_sid, enum lsa_SidType type, uint32 *num_names, DOM_SID **sid_mem, char ***names, uint32 **name_types) { NTSTATUS result; result = msrpc_methods.lookup_groupmem(domain, mem_ctx, group_sid, type, num_names, sid_mem, names, name_types); if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) result = msrpc_methods.lookup_groupmem(domain, mem_ctx, group_sid, type, num_names, sid_mem, names, name_types); return result; }
/** recv a session setup reply */ NTSTATUS smb2_session_setup_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_session_setup *io) { NTSTATUS status; if (!smb2_request_receive(req) || (smb2_request_is_error(req) && !NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED))) { return smb2_request_destroy(req); } SMB2_CHECK_PACKET_RECV(req, 0x08, true); io->out.session_flags = SVAL(req->in.body, 0x02); io->out.uid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID); status = smb2_pull_o16s16_blob(&req->in, mem_ctx, req->in.body+0x04, &io->out.secblob); if (!NT_STATUS_IS_OK(status)) { smb2_request_destroy(req); return status; } return smb2_request_destroy(req); }
static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle, const char *name, uint32_t security_info, TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc) { struct SMB4ACL_T *pacl; NTSTATUS status; TALLOC_CTX *frame = talloc_stackframe(); status = nfs4_get_nfs4_acl(handle, frame, name, &pacl); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { pacl = nfs4acls_inheritacl(handle, name, frame); } else if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return status; } status = smb_get_nt_acl_nfs4(handle->conn, name, security_info, mem_ctx, ppdesc, pacl); TALLOC_FREE(frame); return status; }
/* function to map policy errors */ krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status) { krb5_error_code ret; if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) ret = KRB5KDC_ERR_KEY_EXPIRED; else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) ret = KRB5KDC_ERR_KEY_EXPIRED; else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) ret = KRB5KDC_ERR_CLIENT_REVOKED; else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) ret = KRB5KDC_ERR_CLIENT_REVOKED; else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) ret = KRB5KDC_ERR_CLIENT_REVOKED; else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) ret = KRB5KDC_ERR_CLIENT_REVOKED; else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) ret = KRB5KDC_ERR_POLICY; else ret = KRB5KDC_ERR_POLICY; return ret; }
NTSTATUS connect_to_service(struct net_context *c, struct cli_state **cli_ctx, struct sockaddr_storage *server_ss, const char *server_name, const char *service_name, const char *service_type) { NTSTATUS nt_status; int flags = 0; c->opt_password = net_prompt_pass(c, c->opt_user_name); if (c->opt_kerberos) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } if (c->opt_kerberos && c->opt_password) { flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; } if (c->opt_ccache) { flags |= CLI_FULL_CONNECTION_USE_CCACHE; } nt_status = cli_full_connection(cli_ctx, NULL, server_name, server_ss, c->opt_port, service_name, service_type, c->opt_user_name, c->opt_workgroup, c->opt_password, flags, Undefined); if (!NT_STATUS_IS_OK(nt_status)) { d_fprintf(stderr, _("Could not connect to server %s\n"), server_name); /* Display a nicer message depending on the result */ if (NT_STATUS_V(nt_status) == NT_STATUS_V(NT_STATUS_LOGON_FAILURE)) d_fprintf(stderr, _("The username or password was not " "correct.\n")); if (NT_STATUS_V(nt_status) == NT_STATUS_V(NT_STATUS_ACCOUNT_LOCKED_OUT)) d_fprintf(stderr, _("The account was locked out.\n")); if (NT_STATUS_V(nt_status) == NT_STATUS_V(NT_STATUS_ACCOUNT_DISABLED)) d_fprintf(stderr, _("The account was disabled.\n")); return nt_status; } if (c->smb_encrypt) { nt_status = cli_force_encryption(*cli_ctx, c->opt_user_name, c->opt_password, c->opt_workgroup); if (NT_STATUS_EQUAL(nt_status,NT_STATUS_NOT_SUPPORTED)) { d_printf(_("Encryption required and " "server that doesn't support " "UNIX extensions - failing connect\n")); } else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNKNOWN_REVISION)) { d_printf(_("Encryption required and " "can't get UNIX CIFS extensions " "version from server.\n")); } else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNSUPPORTED_COMPRESSION)) { d_printf(_("Encryption required and " "share %s doesn't support " "encryption.\n"), service_name); } else if (!NT_STATUS_IS_OK(nt_status)) { d_printf(_("Encryption required and " "setup failed with error %s.\n"), nt_errstr(nt_status)); } if (!NT_STATUS_IS_OK(nt_status)) { cli_shutdown(*cli_ctx); *cli_ctx = NULL; } } return nt_status; }
static bool process_lockingX(struct blocking_lock_record *blr) { unsigned char locktype = CVAL(blr->req->vwv+3, 0); files_struct *fsp = blr->fsp; uint16 num_ulocks = SVAL(blr->req->vwv+6, 0); uint16 num_locks = SVAL(blr->req->vwv+7, 0); uint64_t count = (uint64_t)0, offset = (uint64_t)0; uint32 lock_pid; bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); uint8_t *data; NTSTATUS status = NT_STATUS_OK; data = (uint8_t *)blr->req->buf + ((large_file_format ? 20 : 10)*num_ulocks); /* * Data now points at the beginning of the list * of smb_lkrng structs. */ for(; blr->lock_num < num_locks; blr->lock_num++) { struct byte_range_lock *br_lck = NULL; bool err; lock_pid = get_lock_pid( data, blr->lock_num, large_file_format); count = get_lock_count( data, blr->lock_num, large_file_format); offset = get_lock_offset( data, blr->lock_num, large_file_format, &err); /* * We know err cannot be set as if it was the lock * request would never have been queued. JRA. */ errno = 0; br_lck = do_lock(smbd_messaging_context(), fsp, lock_pid, count, offset, ((locktype & LOCKING_ANDX_SHARED_LOCK) ? READ_LOCK : WRITE_LOCK), WINDOWS_LOCK, True, &status, &blr->blocking_pid, blr); TALLOC_FREE(br_lck); if (NT_STATUS_IS_ERR(status)) { break; } } if(blr->lock_num == num_locks) { /* * Success - we got all the locks. */ DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n", fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) ); reply_lockingX_success(blr); return True; } if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { /* * We have other than a "can't get lock" * error. Free any locks we had and return an error. * Return True so we get dequeued. */ blocking_lock_reply_error(blr, status); return True; } /* * Still can't get all the locks - keep waiting. */ DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \ Waiting....\n", blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum)); return False; }
/** * confirm that a domain join is still valid * * @return A shell status integer (0 for success) * **/ NTSTATUS net_rpc_join_ok(struct net_context *c, const char *domain, const char *server, struct sockaddr_storage *pss) { enum security_types sec; unsigned int conn_flags = NET_FLAGS_PDC; uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_hnd = NULL; struct rpc_pipe_client *netlogon_pipe = NULL; NTSTATUS ntret = NT_STATUS_UNSUCCESSFUL; sec = (enum security_types)lp_security(); if (sec == SEC_ADS) { /* Connect to IPC$ using machine account's credentials. We don't use anonymous connection here, as it may be denied by server's local policy. */ net_use_machine_account(c); } else { /* some servers (e.g. WinNT) don't accept machine-authenticated smb connections */ conn_flags |= NET_FLAGS_ANONYMOUS; } /* Connect to remote machine */ ntret = net_make_ipc_connection_ex(c, domain, server, pss, conn_flags, &cli); if (!NT_STATUS_IS_OK(ntret)) { return ntret; } /* Setup the creds as though we're going to do schannel... */ ntret = get_schannel_session_key(cli, domain, &neg_flags, &netlogon_pipe); /* We return NT_STATUS_INVALID_NETWORK_RESPONSE if the server is refusing to negotiate schannel, but the creds were set up ok. That'll have to do. */ if (!NT_STATUS_IS_OK(ntret)) { if (NT_STATUS_EQUAL(ntret, NT_STATUS_INVALID_NETWORK_RESPONSE)) { cli_shutdown(cli); return NT_STATUS_OK; } else { DEBUG(0,("net_rpc_join_ok: failed to get schannel session " "key from server %s for domain %s. Error was %s\n", cli->desthost, domain, nt_errstr(ntret) )); cli_shutdown(cli); return ntret; } } /* Only do the rest of the schannel test if the client is allowed to do this. */ if (!lp_client_schannel()) { cli_shutdown(cli); /* We're good... */ return ntret; } ntret = cli_rpc_pipe_open_schannel_with_key( cli, &ndr_table_netlogon.syntax_id, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, &netlogon_pipe->dc, &pipe_hnd); if (!NT_STATUS_IS_OK(ntret)) { DEBUG(0,("net_rpc_join_ok: failed to open schannel session " "on netlogon pipe to server %s for domain %s. Error was %s\n", cli->desthost, domain, nt_errstr(ntret) )); /* * Note: here, we have: * (pipe_hnd != NULL) if and only if NT_STATUS_IS_OK(ntret) */ } cli_shutdown(cli); return ntret; }
int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv) { /* libsmb variables */ struct cli_state *cli; TALLOC_CTX *mem_ctx; uint32 acb_info = ACB_WSTRUST; uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; enum netr_SchannelType sec_channel_type; struct rpc_pipe_client *pipe_hnd = NULL; struct dcerpc_binding_handle *b = NULL; /* rpc variables */ struct policy_handle lsa_pol, sam_pol, domain_pol, user_pol; struct dom_sid *domain_sid; uint32 user_rid; /* Password stuff */ char *clear_trust_password = NULL; struct samr_CryptPassword crypt_pwd; uchar md4_trust_password[16]; union samr_UserInfo set_info; /* Misc */ NTSTATUS status, result; int retval = 1; const char *domain = NULL; char *acct_name; struct lsa_String lsa_acct_name; uint32 acct_flags=0; uint32_t access_granted = 0; union lsa_PolicyInformation *info = NULL; struct samr_Ids user_rids; struct samr_Ids name_types; /* check what type of join */ if (argc >= 0) { sec_channel_type = get_sec_channel_type(argv[0]); } else { sec_channel_type = get_sec_channel_type(NULL); } switch (sec_channel_type) { case SEC_CHAN_WKSTA: acb_info = ACB_WSTRUST; break; case SEC_CHAN_BDC: acb_info = ACB_SVRTRUST; break; #if 0 case SEC_CHAN_DOMAIN: acb_info = ACB_DOMTRUST; break; #endif default: DEBUG(0,("secure channel type %d not yet supported\n", sec_channel_type)); break; } /* Make authenticated connection to remote machine */ status = net_make_ipc_connection(c, NET_FLAGS_PDC, &cli); if (!NT_STATUS_IS_OK(status)) { return 1; } if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) { DEBUG(0, ("Could not initialise talloc context\n")); goto done; } /* Fetch domain sid */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n", nt_errstr(status) )); goto done; } b = pipe_hnd->binding_handle; CHECK_RPC_ERR(rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true, SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol), "error opening lsa policy handle"); CHECK_DCERPC_ERR(dcerpc_lsa_QueryInfoPolicy(b, mem_ctx, &lsa_pol, LSA_POLICY_INFO_ACCOUNT_DOMAIN, &info, &result), "error querying info policy"); domain = info->account_domain.name.string; domain_sid = info->account_domain.sid; dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result); TALLOC_FREE(pipe_hnd); /* Done with this pipe */ /* Bail out if domain didn't get set. */ if (!domain) { DEBUG(0, ("Could not get domain name.\n")); goto done; } /* Create domain user */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n", nt_errstr(status) )); goto done; } b = pipe_hnd->binding_handle; CHECK_DCERPC_ERR(dcerpc_samr_Connect2(b, mem_ctx, pipe_hnd->desthost, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_LOOKUP_DOMAIN, &sam_pol, &result), "could not connect to SAM database"); CHECK_DCERPC_ERR(dcerpc_samr_OpenDomain(b, mem_ctx, &sam_pol, SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 | SAMR_DOMAIN_ACCESS_CREATE_USER | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, domain_sid, &domain_pol, &result), "could not open domain"); /* Create domain user */ if ((acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname())) == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } strlower_m(acct_name); init_lsa_String(&lsa_acct_name, acct_name); acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE | SEC_STD_WRITE_DAC | SEC_STD_DELETE | SAMR_USER_ACCESS_SET_PASSWORD | SAMR_USER_ACCESS_GET_ATTRIBUTES | SAMR_USER_ACCESS_SET_ATTRIBUTES; DEBUG(10, ("Creating account with flags: %d\n",acct_flags)); status = dcerpc_samr_CreateUser2(b, mem_ctx, &domain_pol, &lsa_acct_name, acb_info, acct_flags, &user_pol, &access_granted, &user_rid, &result); if (!NT_STATUS_IS_OK(status)) { goto done; } if (!NT_STATUS_IS_OK(result) && !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) { status = result; d_fprintf(stderr,_("Creation of workstation account failed\n")); /* If NT_STATUS_ACCESS_DENIED then we have a valid username/password combo but the user does not have administrator access. */ if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) d_fprintf(stderr, _("User specified does not have " "administrator privileges\n")); goto done; } /* We *must* do this.... don't ask... */ if (NT_STATUS_IS_OK(result)) { dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); } CHECK_DCERPC_ERR_DEBUG(dcerpc_samr_LookupNames(b, mem_ctx, &domain_pol, 1, &lsa_acct_name, &user_rids, &name_types, &result), ("error looking up rid for user %s: %s/%s\n", acct_name, nt_errstr(status), nt_errstr(result))); if (user_rids.count != 1) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto done; } if (name_types.count != 1) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto done; } if (name_types.ids[0] != SID_NAME_USER) { DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0])); goto done; } user_rid = user_rids.ids[0]; /* Open handle on user */ CHECK_DCERPC_ERR_DEBUG( dcerpc_samr_OpenUser(b, mem_ctx, &domain_pol, SEC_FLAG_MAXIMUM_ALLOWED, user_rid, &user_pol, &result), ("could not re-open existing user %s: %s/%s\n", acct_name, nt_errstr(status), nt_errstr(result))); /* Create a random machine account password */ clear_trust_password = generate_random_str(talloc_tos(), DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); E_md4hash(clear_trust_password, md4_trust_password); /* Set password on machine account */ init_samr_CryptPassword(clear_trust_password, &cli->user_session_key, &crypt_pwd); set_info.info24.password = crypt_pwd; set_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON; CHECK_DCERPC_ERR(dcerpc_samr_SetUserInfo2(b, mem_ctx, &user_pol, 24, &set_info, &result), "error setting trust account password"); /* Why do we have to try to (re-)set the ACB to be the same as what we passed in the samr_create_dom_user() call? When a NT workstation is joined to a domain by an administrator the acb_info is set to 0x80. For a normal user with "Add workstations to the domain" rights the acb_info is 0x84. I'm not sure whether it is supposed to make a difference or not. NT seems to cope with either value so don't bomb out if the set userinfo2 level 0x10 fails. -tpot */ set_info.info16.acct_flags = acb_info; /* Ignoring the return value is necessary for joining a domain as a normal user with "Add workstation to domain" privilege. */ status = dcerpc_samr_SetUserInfo(b, mem_ctx, &user_pol, 16, &set_info, &result); dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); TALLOC_FREE(pipe_hnd); /* Done with this pipe */ /* Now check the whole process from top-to-bottom */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Error connecting to NETLOGON pipe. Error was %s\n", nt_errstr(status) )); goto done; } status = rpccli_netlogon_setup_creds(pipe_hnd, cli->desthost, /* server name */ domain, /* domain */ global_myname(), /* client name */ global_myname(), /* machine account name */ md4_trust_password, sec_channel_type, &neg_flags); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error in domain join verification (credential setup failed): %s\n\n", nt_errstr(status))); if ( NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && (sec_channel_type == SEC_CHAN_BDC) ) { d_fprintf(stderr, _("Please make sure that no computer " "account\nnamed like this machine " "(%s) exists in the domain\n"), global_myname()); } goto done; } /* We can only check the schannel connection if the client is allowed to do this and the server supports it. If not, just assume success (after all the rpccli_netlogon_setup_creds() succeeded, and we'll do the same again (setup creds) in net_rpc_join_ok(). JRA. */ if (lp_client_schannel() && (neg_flags & NETLOGON_NEG_SCHANNEL)) { struct rpc_pipe_client *netlogon_schannel_pipe; status = cli_rpc_pipe_open_schannel_with_key( cli, &ndr_table_netlogon.syntax_id, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, &pipe_hnd->dc, &netlogon_schannel_pipe); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error in domain join verification (schannel setup failed): %s\n\n", nt_errstr(status))); if ( NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && (sec_channel_type == SEC_CHAN_BDC) ) { d_fprintf(stderr, _("Please make sure that no " "computer account\nnamed " "like this machine (%s) " "exists in the domain\n"), global_myname()); } goto done; } TALLOC_FREE(netlogon_schannel_pipe); } TALLOC_FREE(pipe_hnd); /* Now store the secret in the secrets database */ strupper_m(CONST_DISCARD(char *, domain)); if (!secrets_store_domain_sid(domain, domain_sid)) { DEBUG(0, ("error storing domain sid for %s\n", domain)); goto done; } if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) { DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain)); } /* double-check, connection from scratch */ status = net_rpc_join_ok(c, domain, cli->desthost, &cli->dest_ss); retval = NT_STATUS_IS_OK(status) ? 0 : -1; done: /* Display success or failure */ if (domain) { if (retval != 0) { fprintf(stderr,_("Unable to join domain %s.\n"),domain); } else { printf(_("Joined domain %s.\n"),domain); } } cli_shutdown(cli); TALLOC_FREE(clear_trust_password); return retval; }
static NTSTATUS connect_to_domain_password_server(struct cli_state **cli, const char *domain, const char *dc_name, const struct sockaddr_storage *dc_ss, struct rpc_pipe_client **pipe_ret) { NTSTATUS result; struct rpc_pipe_client *netlogon_pipe = NULL; *cli = NULL; *pipe_ret = NULL; /* TODO: Send a SAMLOGON request to determine whether this is a valid logonserver. We can avoid a 30-second timeout if the DC is down if the SAMLOGON request fails as it is only over UDP. */ /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ /* * With NT4.x DC's *all* authentication must be serialized to avoid * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA. */ mutex = grab_named_mutex(NULL, dc_name, 10); if (mutex == NULL) { return NT_STATUS_NO_LOGON_SERVERS; } /* Attempt connection */ result = cli_full_connection(cli, lp_netbios_name(), dc_name, dc_ss, 0, "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT); if (!NT_STATUS_IS_OK(result)) { /* map to something more useful */ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) { result = NT_STATUS_NO_LOGON_SERVERS; } if (*cli) { cli_shutdown(*cli); *cli = NULL; } TALLOC_FREE(mutex); return result; } /* * We now have an anonymous connection to IPC$ on the domain password server. */ /* * Even if the connect succeeds we need to setup the netlogon * pipe here. We do this as we may just have changed the domain * account password on the PDC and yet we may be talking to * a BDC that doesn't have this replicated yet. In this case * a successful connect to a DC needs to take the netlogon connect * into account also. This patch from "Bjart Kvarme" <*****@*****.**>. */ /* open the netlogon pipe. */ if (lp_client_schannel()) { /* We also setup the creds chain in the open_schannel call. */ result = cli_rpc_pipe_open_schannel( *cli, &ndr_table_netlogon, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, &netlogon_pipe); } else { result = cli_rpc_pipe_open_noauth( *cli, &ndr_table_netlogon, &netlogon_pipe); } if (!NT_STATUS_IS_OK(result)) { DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); cli_shutdown(*cli); *cli = NULL; TALLOC_FREE(mutex); return result; }
/**************************************************************************** Perform a session setup (async recv) ****************************************************************************/ NTSTATUS smb_raw_sesssetup_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, union smb_sesssetup *parms) { uint16_t len; uint8_t *p; if (!smbcli_request_receive(req)) { return smbcli_request_destroy(req); } if (!NT_STATUS_IS_OK(req->status) && !NT_STATUS_EQUAL(req->status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { return smbcli_request_destroy(req); } switch (parms->old.level) { case RAW_SESSSETUP_OLD: SMBCLI_CHECK_WCT(req, 3); ZERO_STRUCT(parms->old.out); parms->old.out.vuid = SVAL(req->in.hdr, HDR_UID); parms->old.out.action = SVAL(req->in.vwv, VWV(2)); p = req->in.data; if (p) { p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.os, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.lanman, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.domain, p, -1, STR_TERMINATE); } break; case RAW_SESSSETUP_NT1: SMBCLI_CHECK_WCT(req, 3); ZERO_STRUCT(parms->nt1.out); parms->nt1.out.vuid = SVAL(req->in.hdr, HDR_UID); parms->nt1.out.action = SVAL(req->in.vwv, VWV(2)); p = req->in.data; if (p) { p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.os, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.lanman, p, -1, STR_TERMINATE); if (p < (req->in.data + req->in.data_size)) { p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.domain, p, -1, STR_TERMINATE); } } break; case RAW_SESSSETUP_SPNEGO: SMBCLI_CHECK_WCT(req, 4); ZERO_STRUCT(parms->spnego.out); parms->spnego.out.vuid = SVAL(req->in.hdr, HDR_UID); parms->spnego.out.action = SVAL(req->in.vwv, VWV(2)); len = SVAL(req->in.vwv, VWV(3)); p = req->in.data; if (!p) { break; } parms->spnego.out.secblob = smbcli_req_pull_blob(&req->in.bufinfo, mem_ctx, p, len); p += parms->spnego.out.secblob.length; p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE); p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.workgroup, p, -1, STR_TERMINATE); break; case RAW_SESSSETUP_SMB2: req->status = NT_STATUS_INTERNAL_ERROR; break; } failed: return smbcli_request_destroy(req); }
/* * epm_Insert * * Add the specified entries to an endpoint map. */ error_status_t _epm_Insert(struct pipes_struct *p, struct epm_Insert *r) { TALLOC_CTX *tmp_ctx; error_status_t rc; NTSTATUS status; uint32_t i; struct dcerpc_binding *b; struct dcesrv_endpoint *ep; struct dcesrv_iface_list *iflist; struct dcesrv_iface *iface; bool add_ep; /* If this is not a priviledged users, return */ if (p->transport != NCALRPC || !is_priviledged_pipe(p->session_info)) { p->fault_state = DCERPC_FAULT_OP_RNG_ERROR; return EPMAPPER_STATUS_CANT_PERFORM_OP; } tmp_ctx = talloc_stackframe(); if (tmp_ctx == NULL) { return EPMAPPER_STATUS_NO_MEMORY; } DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n", r->in.num_ents)); for (i = 0; i < r->in.num_ents; i++) { add_ep = false; b = NULL; status = dcerpc_binding_from_tower(tmp_ctx, &r->in.entries[i].tower->tower, &b); if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) { rc = EPMAPPER_STATUS_NO_MEMORY; goto done; } if (!NT_STATUS_IS_OK(status)) { rc = EPMAPPER_STATUS_CANT_PERFORM_OP; goto done; } DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n", derpc_transport_string_by_transport(b->transport), r->in.entries[i].annotation)); /* Check if the entry already exits */ ep = find_endpoint(endpoint_table, b); if (ep == NULL) { /* No entry found, create it */ ep = talloc_zero(NULL, struct dcesrv_endpoint); if (ep == NULL) { rc = EPMAPPER_STATUS_NO_MEMORY; goto done; } add_ep = true; ep->ep_description = talloc_steal(ep, b); } /* TODO Replace the entry if the replace flag is set */ /* Create an interface */ iface = talloc(tmp_ctx, struct dcesrv_iface); if (iface == NULL) { rc = EPMAPPER_STATUS_NO_MEMORY; goto done; } iface->name = talloc_strdup(iface, r->in.entries[i].annotation); if (iface->name == NULL) { rc = EPMAPPER_STATUS_NO_MEMORY; goto done; } iface->syntax_id = b->object; /* * Check if the rpc service is alrady registered on the * endpoint. */ if (find_interface(ep, iface) != NULL) { DEBUG(8, ("dcesrv_interface_register: interface '%s' " "already registered on endpoint\n", iface->name)); /* FIXME wrong error code? */ rc = EPMAPPER_STATUS_OK; goto done; } /* Create an entry for the interface */ iflist = talloc(ep, struct dcesrv_iface_list); if (iflist == NULL) { rc = EPMAPPER_STATUS_NO_MEMORY; goto done; } iflist->iface = talloc_move(iflist, &iface); /* Finally add the interface on the endpoint */ DLIST_ADD(ep->iface_list, iflist); /* If it's a new endpoint add it to the endpoint_table */ if (add_ep) { DLIST_ADD(endpoint_table, ep); } }
/***************************************************************************** convert an NT status32 code to a PAM error *****************************************************************************/ int nt_status_to_pam(NTSTATUS nt_status) { if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0; return 4; /* PAM_SYSTEM_ERR */ }
/* handler for completion of a smbcli_request sub-request */ static void request_handler(struct smbcli_request *req) { struct composite_context *c = (struct composite_context *)req->async.private_data; struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state); struct smbcli_session *session = req->session; DATA_BLOB null_data_blob = data_blob(NULL, 0); NTSTATUS session_key_err, nt_status; struct smbcli_request *check_req = NULL; const char *os = NULL; const char *lanman = NULL; if (req->sign_caller_checks) { req->do_not_free = true; check_req = req; } state->remote_status = smb_raw_sesssetup_recv(req, state, &state->setup); c->status = state->remote_status; state->req = NULL; /* * we only need to check the signature if the * NT_STATUS_OK is returned */ if (!NT_STATUS_IS_OK(state->remote_status)) { talloc_free(check_req); check_req = NULL; } switch (state->setup.old.level) { case RAW_SESSSETUP_OLD: state->io->out.vuid = state->setup.old.out.vuid; /* This doesn't work, as this only happens on old * protocols, where this comparison won't match. */ if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { /* we neet to reset the vuid for a new try */ session->vuid = 0; if (cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_old(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } os = state->setup.old.out.os; lanman = state->setup.old.out.lanman; break; case RAW_SESSSETUP_NT1: state->io->out.vuid = state->setup.nt1.out.vuid; if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { /* we need to reset the vuid for a new try */ session->vuid = 0; if (cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_nt1(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } os = state->setup.nt1.out.os; lanman = state->setup.nt1.out.lanman; break; case RAW_SESSSETUP_SPNEGO: state->io->out.vuid = state->setup.spnego.out.vuid; if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { const char *principal; /* we need to reset the vuid for a new try */ session->vuid = 0; principal = gensec_get_target_principal(session->gensec); if (principal == NULL) { const char *hostname = gensec_get_target_hostname(session->gensec); const char *service = gensec_get_target_service(session->gensec); if (hostname != NULL && service != NULL) { principal = talloc_asprintf(state, "%s/%s", service, hostname); } } if (cli_credentials_failed_kerberos_login(state->io->in.credentials, principal, &state->logon_retries) || cli_credentials_wrong_password(state->io->in.credentials)) { nt_status = session_setup_spnego(c, session, state->io, &state->req); if (NT_STATUS_IS_OK(nt_status)) { talloc_free(check_req); c->status = nt_status; composite_continue_smb(c, state->req, request_handler, c); return; } } } if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(c->status)) { break; } if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* The status value here, from the earlier pass at GENSEC is * vital to the security of the system. Even if the other end * accepts, if GENSEC claims 'MORE_PROCESSING_REQUIRED' then * you must keep feeding it blobs, or else the remote * host/attacker might avoid mutal authentication * requirements */ state->gensec_status = gensec_update(session->gensec, state, c->event_ctx, state->setup.spnego.out.secblob, &state->setup.spnego.in.secblob); c->status = state->gensec_status; if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(c->status)) { break; } } else { state->setup.spnego.in.secblob = data_blob(NULL, 0); } if (NT_STATUS_IS_OK(state->remote_status)) { DATA_BLOB session_key; if (state->setup.spnego.in.secblob.length) { c->status = NT_STATUS_INTERNAL_ERROR; break; } session_key_err = gensec_session_key(session->gensec, session, &session_key); if (NT_STATUS_IS_OK(session_key_err)) { smb1cli_conn_activate_signing(session->transport->conn, session_key, null_data_blob); } c->status = smb1cli_session_set_session_key(session->smbXcli, session_key); data_blob_free(&session_key); if (!NT_STATUS_IS_OK(c->status)) { break; } } if (state->setup.spnego.in.secblob.length) { /* * set the session->vuid value only for calling * smb_raw_sesssetup_send() */ uint16_t vuid = session->vuid; session->vuid = state->io->out.vuid; state->req = smb_raw_sesssetup_send(session, &state->setup); session->vuid = vuid; if (state->req && !smb1cli_conn_signing_is_active(state->req->transport->conn)) { state->req->sign_caller_checks = true; } composite_continue_smb(c, state->req, request_handler, c); return; } os = state->setup.spnego.out.os; lanman = state->setup.spnego.out.lanman; break; case RAW_SESSSETUP_SMB2: c->status = NT_STATUS_INTERNAL_ERROR; break; } if (check_req) { bool ok; check_req->sign_caller_checks = false; ok = smb1cli_conn_check_signing(check_req->transport->conn, check_req->in.buffer, 1); if (!ok) { c->status = NT_STATUS_ACCESS_DENIED; } talloc_free(check_req); check_req = NULL; } if (!NT_STATUS_IS_OK(c->status)) { composite_error(c, c->status); return; } if (os) { session->os = talloc_strdup(session, os); if (composite_nomem(session->os, c)) return; } else { session->os = NULL; } if (lanman) { session->lanman = talloc_strdup(session, lanman); if (composite_nomem(session->lanman, c)) return; } else { session->lanman = NULL; } composite_done(c); }
/* Modern, all singing, all dancing extended security (and possibly SPNEGO) request */ static NTSTATUS session_setup_spnego(struct composite_context *c, struct smbcli_session *session, struct smb_composite_sesssetup *io, struct smbcli_request **req) { struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state); NTSTATUS status; const char *chosen_oid = NULL; state->setup.spnego.level = RAW_SESSSETUP_SPNEGO; state->setup.spnego.in.bufsize = session->transport->options.max_xmit; state->setup.spnego.in.mpx_max = session->transport->options.max_mux; state->setup.spnego.in.vc_num = 1; state->setup.spnego.in.sesskey = io->in.sesskey; state->setup.spnego.in.capabilities = io->in.capabilities; state->setup.spnego.in.os = "Unix"; state->setup.spnego.in.lanman = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING); state->setup.spnego.in.workgroup = io->in.workgroup; status = gensec_client_start(session, &session->gensec, io->in.gensec_settings); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status))); return status; } gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY); status = gensec_set_credentials(session->gensec, io->in.credentials); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start set GENSEC client credentials: %s\n", nt_errstr(status))); return status; } status = gensec_set_target_hostname(session->gensec, smbXcli_conn_remote_name(session->transport->conn)); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", nt_errstr(status))); return status; } status = gensec_set_target_service(session->gensec, "cifs"); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start set GENSEC target service: %s\n", nt_errstr(status))); return status; } if (session->transport->negotiate.secblob.length) { chosen_oid = GENSEC_OID_SPNEGO; status = gensec_start_mech_by_oid(session->gensec, chosen_oid); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n", gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status))); chosen_oid = GENSEC_OID_NTLMSSP; status = gensec_start_mech_by_oid(session->gensec, chosen_oid); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start set (fallback) GENSEC client mechanism %s: %s\n", gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status))); return status; } } } else { /* without a sec blob, means raw NTLMSSP */ chosen_oid = GENSEC_OID_NTLMSSP; status = gensec_start_mech_by_oid(session->gensec, chosen_oid); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n", gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status))); } } if (strequal(chosen_oid, GENSEC_OID_SPNEGO)) { status = gensec_update(session->gensec, state, c->event_ctx, session->transport->negotiate.secblob, &state->setup.spnego.in.secblob); } else { status = gensec_update(session->gensec, state, c->event_ctx, data_blob(NULL, 0), &state->setup.spnego.in.secblob); } if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed initial gensec_update with mechanism %s: %s\n", gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status))); return status; } state->gensec_status = status; *req = smb_raw_sesssetup_send(session, &state->setup); if (!*req) { return NT_STATUS_NO_MEMORY; } /* * we need to check the signature ourself * as the session key might be the acceptor subkey * which comes within the response itself */ if (!smb1cli_conn_signing_is_active((*req)->transport->conn)) { (*req)->sign_caller_checks = true; } return (*req)->status; }
/* try a netlogon SamLogon */ bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx, struct cli_credentials *credentials, struct netlogon_creds_CredentialState *creds) { NTSTATUS status; struct netr_LogonSamLogonEx r; struct netr_NetworkInfo ninfo; union netr_LogonLevel logon; union netr_Validation validation; uint8_t authoritative = 0; uint32_t _flags = 0; DATA_BLOB names_blob, chal, lm_resp, nt_resp; int i; int flags = CLI_CRED_NTLM_AUTH; struct dcerpc_binding_handle *b = p->binding_handle; struct netr_UserSessionKey key; struct netr_LMSessionKey LMSessKey; uint32_t validation_levels[] = { 2, 3 }; struct netr_SamBaseInfo *base = NULL; const char *crypto_alg = ""; bool can_do_validation_6 = true; enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; if (lpcfg_client_lanman_auth(tctx->lp_ctx)) { flags |= CLI_CRED_LANMAN_AUTH; } if (lpcfg_client_ntlmv2_auth(tctx->lp_ctx)) { flags |= CLI_CRED_NTLMv2_AUTH; } cli_credentials_get_ntlm_username_domain(cmdline_credentials, tctx, &ninfo.identity_info.account_name.string, &ninfo.identity_info.domain_name.string); generate_random_buffer(ninfo.challenge, sizeof(ninfo.challenge)); chal = data_blob_const(ninfo.challenge, sizeof(ninfo.challenge)); names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials), cli_credentials_get_domain(credentials)); status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx, &flags, chal, names_blob, &lm_resp, &nt_resp, NULL, NULL); torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed"); ninfo.lm.data = lm_resp.data; ninfo.lm.length = lm_resp.length; ninfo.nt.data = nt_resp.data; ninfo.nt.length = nt_resp.length; ninfo.identity_info.parameter_control = 0; ninfo.identity_info.logon_id_low = 0; ninfo.identity_info.logon_id_high = 0; ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials); logon.network = &ninfo; r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p)); r.in.computer_name = cli_credentials_get_workstation(credentials); r.in.logon_level = NetlogonNetworkInformation; r.in.logon= &logon; r.in.flags = &_flags; r.out.validation = &validation; r.out.authoritative = &authoritative; r.out.flags = &_flags; /* - retrieve level6 - save usrsession and lmsession key - retrieve level 2 - calculate, compare - retrieve level 3 - calculate, compare */ if (creds) { if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { crypto_alg = "AES"; } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { crypto_alg = "ARCFOUR"; } } dcerpc_binding_handle_auth_info(b, NULL, &auth_level); if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { r.in.validation_level = 6; torture_comment(tctx, "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n", ninfo.identity_info.account_name.string, crypto_alg, r.in.validation_level); torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r), "LogonSamLogonEx failed"); } else { torture_comment(tctx, "Skip auth_level[%u] Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n", auth_level, ninfo.identity_info.account_name.string, crypto_alg, r.in.validation_level); r.out.result = NT_STATUS_INVALID_INFO_CLASS; } if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) { can_do_validation_6 = false; } else { torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogonEx failed"); key = r.out.validation->sam6->base.key; LMSessKey = r.out.validation->sam6->base.LMSessKey; DEBUG(1,("unencrypted session keys from validation_level 6:\n")); dump_data(1, r.out.validation->sam6->base.key.key, 16); dump_data(1, r.out.validation->sam6->base.LMSessKey.key, 8); } for (i=0; i < ARRAY_SIZE(validation_levels); i++) { r.in.validation_level = validation_levels[i]; torture_comment(tctx, "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n", ninfo.identity_info.account_name.string, crypto_alg, r.in.validation_level); torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r), "LogonSamLogonEx failed"); torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogonEx failed"); if (creds == NULL) { /* when this test is called without creds no point in * testing the session keys */ continue; } switch (validation_levels[i]) { case 2: base = &r.out.validation->sam2->base; break; case 3: base = &r.out.validation->sam3->base; break; default: break; } DEBUG(1,("encrypted keys validation_level %d:\n", validation_levels[i])); dump_data(1, base->key.key, 16); dump_data(1, base->LMSessKey.key, 8); if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { netlogon_creds_aes_decrypt(creds, base->key.key, 16); netlogon_creds_aes_decrypt(creds, base->LMSessKey.key, 8); } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { netlogon_creds_arcfour_crypt(creds, base->key.key, 16); netlogon_creds_arcfour_crypt(creds, base->LMSessKey.key, 8); } DEBUG(1,("decryped keys validation_level %d\n", validation_levels[i])); dump_data(1, base->key.key, 16); dump_data(1, base->LMSessKey.key, 8); if (!can_do_validation_6) { /* we cant compare against unencrypted keys */ continue; } torture_assert_mem_equal(tctx, base->key.key, key.key, 16, "unexpected user session key\n"); torture_assert_mem_equal(tctx, base->LMSessKey.key, LMSessKey.key, 8, "unexpected LM session key\n"); } return true; }
/* do some samr ops using the schannel connection */ static bool test_samr_ops(struct torture_context *tctx, struct dcerpc_binding_handle *b) { struct samr_GetDomPwInfo r; struct samr_PwInfo info; struct samr_Connect connect_r; struct samr_OpenDomain opendom; int i; struct lsa_String name; struct policy_handle handle; struct policy_handle domain_handle; name.string = lpcfg_workgroup(tctx->lp_ctx); r.in.domain_name = &name; r.out.info = &info; connect_r.in.system_name = 0; connect_r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; connect_r.out.connect_handle = &handle; torture_comment(tctx, "Testing Connect and OpenDomain on BUILTIN\n"); torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect_r(b, tctx, &connect_r), "Connect failed"); if (!NT_STATUS_IS_OK(connect_r.out.result)) { if (NT_STATUS_EQUAL(connect_r.out.result, NT_STATUS_ACCESS_DENIED)) { torture_comment(tctx, "Connect failed (expected, schannel mapped to anonymous): %s\n", nt_errstr(connect_r.out.result)); } else { torture_comment(tctx, "Connect failed - %s\n", nt_errstr(connect_r.out.result)); return false; } } else { opendom.in.connect_handle = &handle; opendom.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; opendom.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32"); opendom.out.domain_handle = &domain_handle; torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &opendom), "OpenDomain failed"); if (!NT_STATUS_IS_OK(opendom.out.result)) { torture_comment(tctx, "OpenDomain failed - %s\n", nt_errstr(opendom.out.result)); return false; } } torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string); /* do several ops to test credential chaining */ for (i=0;i<5;i++) { torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r), "GetDomPwInfo failed"); if (!NT_STATUS_IS_OK(r.out.result)) { if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED)) { torture_comment(tctx, "GetDomPwInfo op %d failed - %s\n", i, nt_errstr(r.out.result)); return false; } } } return true; }