NTSTATUS make_auth4_context(TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context_out) { struct auth_context *auth_context; NTSTATUS nt_status; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); nt_status = make_auth_context_subsystem(tmp_ctx, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } if (auth_context->make_auth4_context) { nt_status = auth_context->make_auth4_context(auth_context, mem_ctx, auth4_context_out); TALLOC_FREE(tmp_ctx); return nt_status; } else { struct auth4_context *auth4_context = make_auth4_context_s3(tmp_ctx, auth_context); if (auth4_context == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } *auth4_context_out = talloc_steal(mem_ctx, auth4_context); TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; } }
NTSTATUS auth_ntlmssp_start(AUTH_NTLMSSP_STATE **auth_ntlmssp_state) { NTSTATUS nt_status; TALLOC_CTX *mem_ctx; mem_ctx = talloc_init("AUTH NTLMSSP context"); *auth_ntlmssp_state = TALLOC_ZERO_P(mem_ctx, AUTH_NTLMSSP_STATE); if (!*auth_ntlmssp_state) { DEBUG(0,("auth_ntlmssp_start: talloc failed!\n")); talloc_destroy(mem_ctx); return NT_STATUS_NO_MEMORY; } ZERO_STRUCTP(*auth_ntlmssp_state); (*auth_ntlmssp_state)->mem_ctx = mem_ctx; if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(&(*auth_ntlmssp_state)->ntlmssp_state))) { return nt_status; } if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*auth_ntlmssp_state)->auth_context))) { return nt_status; } (*auth_ntlmssp_state)->ntlmssp_state->auth_context = (*auth_ntlmssp_state); (*auth_ntlmssp_state)->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; (*auth_ntlmssp_state)->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; (*auth_ntlmssp_state)->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; (*auth_ntlmssp_state)->ntlmssp_state->check_password = auth_ntlmssp_check_password; (*auth_ntlmssp_state)->ntlmssp_state->server_role = (enum server_types)lp_server_role(); return NT_STATUS_OK; }
NTSTATUS check_plaintext_password(const char *smb_name, DATA_BLOB plaintext_password, auth_serversupplied_info **server_info) { struct auth_context *plaintext_auth_context = NULL; auth_usersupplied_info *user_info = NULL; const uint8 *chal; NTSTATUS nt_status; if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) { return nt_status; } chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context); if (!make_user_info_for_reply(&user_info, smb_name, lp_workgroup(), chal, plaintext_password)) { return NT_STATUS_NO_MEMORY; } nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, user_info, server_info); (plaintext_auth_context->free)(&plaintext_auth_context); free_user_info(&user_info); return nt_status; }
NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8]) { NTSTATUS nt_status; if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(auth_context))) { return nt_status; } (*auth_context)->challenge = data_blob_talloc((*auth_context)->mem_ctx, chal, 8); (*auth_context)->challenge_set_by = "fixed"; return nt_status; }
static void get_challenge(char buff[8]) { NTSTATUS nt_status; const uint8 *cryptkey; /* We might be called more than once, muliple negprots are premitted */ if (negprot_global_auth_context) { DEBUG(3, ("get challenge: is this a secondary negprot? negprot_global_auth_context is non-NULL!\n")); (negprot_global_auth_context->free)(&negprot_global_auth_context); } DEBUG(10, ("get challenge: creating negprot_global_auth_context\n")); if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) { DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status))); smb_panic("cannot make_negprot_global_auth_context!\n"); } DEBUG(10, ("get challenge: getting challenge\n")); cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context); memcpy(buff, cryptkey, 8); }
static void get_challenge(struct smbd_server_connection *sconn, uint8 buff[8]) { NTSTATUS nt_status; /* We might be called more than once, multiple negprots are * permitted */ if (sconn->smb1.negprot.auth_context) { DEBUG(3, ("get challenge: is this a secondary negprot? " "sconn->negprot.auth_context is non-NULL!\n")); TALLOC_FREE(sconn->smb1.negprot.auth_context); } DEBUG(10, ("get challenge: creating negprot_global_auth_context\n")); nt_status = make_auth_context_subsystem( sconn, &sconn->smb1.negprot.auth_context); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status))); smb_panic("cannot make_negprot_global_auth_context!"); } DEBUG(10, ("get challenge: getting challenge\n")); sconn->smb1.negprot.auth_context->get_ntlm_challenge( sconn->smb1.negprot.auth_context, buff); }
NTSTATUS auth_generic_prepare(const struct tsocket_address *remote_address, struct auth_generic_state **auth_ntlmssp_state) { struct auth_context *auth_context; struct auth_generic_state *ans; NTSTATUS nt_status; ans = talloc_zero(NULL, struct auth_generic_state); if (!ans) { DEBUG(0,("auth_ntlmssp_start: talloc failed!\n")); return NT_STATUS_NO_MEMORY; } nt_status = make_auth_context_subsystem(talloc_tos(), &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(ans); return nt_status; } ans->auth_context = talloc_steal(ans, auth_context); if (auth_context->prepare_gensec) { nt_status = auth_context->prepare_gensec(ans, &ans->gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(ans); return nt_status; } *auth_ntlmssp_state = ans; return NT_STATUS_OK; } else { struct gensec_settings *gensec_settings; struct loadparm_context *lp_ctx; lp_ctx = loadparm_init_s3(ans, loadparm_s3_context()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); TALLOC_FREE(ans); return NT_STATUS_INVALID_SERVER_STATE; } gensec_settings = lpcfg_gensec_settings(ans, lp_ctx); if (lp_ctx == NULL) { DEBUG(10, ("lpcfg_gensec_settings failed\n")); TALLOC_FREE(ans); return NT_STATUS_NO_MEMORY; } nt_status = gensec_server_start(ans, gensec_settings, NULL, &ans->gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(ans); return nt_status; } talloc_unlink(ans, lp_ctx); talloc_unlink(ans, gensec_settings); } nt_status = gensec_set_remote_address(ans->gensec_security, remote_address); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(ans); return nt_status; } *auth_ntlmssp_state = ans; return NT_STATUS_OK; }
NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address, struct gensec_security **gensec_security_out) { struct gensec_security *gensec_security; struct auth_context *auth_context; NTSTATUS nt_status; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); nt_status = make_auth_context_subsystem(tmp_ctx, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } if (auth_context->prepare_gensec) { nt_status = auth_context->prepare_gensec(auth_context, tmp_ctx, &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } } else { const struct gensec_security_ops **backends = NULL; struct gensec_settings *gensec_settings; struct loadparm_context *lp_ctx; size_t idx = 0; struct cli_credentials *server_credentials; const char *dns_name; const char *dns_domain; struct auth4_context *auth4_context = make_auth4_context_s3(tmp_ctx, auth_context); if (auth4_context == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); TALLOC_FREE(tmp_ctx); return NT_STATUS_INVALID_SERVER_STATE; } gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx); if (lp_ctx == NULL) { DEBUG(10, ("lpcfg_gensec_settings failed\n")); TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* * This should be a 'netbios domain -> DNS domain' * mapping, and can currently validly return NULL on * poorly configured systems. * * This is used for the NTLMSSP server * */ dns_name = get_mydnsfullname(); if (dns_name == NULL) { dns_name = ""; } dns_domain = get_mydnsdomname(tmp_ctx); if (dns_domain == NULL) { dns_domain = ""; } gensec_settings->server_dns_name = strlower_talloc(gensec_settings, dns_name); if (gensec_settings->server_dns_name == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } gensec_settings->server_dns_domain = strlower_talloc(gensec_settings, dns_domain); if (gensec_settings->server_dns_domain == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } backends = talloc_zero_array(gensec_settings, const struct gensec_security_ops *, 6); if (backends == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } gensec_settings->backends = backends; gensec_init(); /* These need to be in priority order, krb5 before NTLMSSP */ #if defined(HAVE_KRB5) backends[idx++] = &gensec_gse_krb5_security_ops; #endif backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP); backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_SCHANNEL); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM); /* * This is anonymous for now, because we just use it * to set the kerberos state at the moment */ server_credentials = cli_credentials_init_anon(tmp_ctx); if (!server_credentials) { DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n")); return NT_STATUS_NO_MEMORY; } cli_credentials_set_conf(server_credentials, lp_ctx); if (lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) { cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS); } else { cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS); } nt_status = gensec_server_start(tmp_ctx, gensec_settings, auth4_context, &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } gensec_set_credentials(gensec_security, server_credentials); talloc_unlink(tmp_ctx, lp_ctx); talloc_unlink(tmp_ctx, server_credentials); talloc_unlink(tmp_ctx, gensec_settings); talloc_unlink(tmp_ctx, auth4_context); } nt_status = gensec_set_remote_address(gensec_security, remote_address); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } *gensec_security_out = talloc_steal(mem_ctx, gensec_security); TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; }
NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u) { NTSTATUS status = NT_STATUS_OK; NET_USER_INFO_3 *usr_info = NULL; NET_ID_INFO_CTR *ctr = q_u->sam_id.ctr; DOM_CRED srv_cred; UNISTR2 *uni_samlogon_user = NULL; UNISTR2 *uni_samlogon_domain = NULL; UNISTR2 *uni_samlogon_workstation = NULL; fstring nt_username, nt_domain, nt_workstation; auth_usersupplied_info *user_info = NULL; auth_serversupplied_info *server_info = NULL; extern userdom_struct current_user_info; SAM_ACCOUNT *sampw; struct auth_context *auth_context = NULL; usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3)); if (!usr_info) return NT_STATUS_NO_MEMORY; ZERO_STRUCTP(usr_info); /* store the user information, if there is any. */ r_u->user = usr_info; r_u->switch_value = 0; /* indicates no info */ r_u->auth_resp = 1; /* authoritative response */ r_u->switch_value = 3; /* indicates type of validation user info */ if (!get_valid_user_struct(p->vuid)) return NT_STATUS_NO_SUCH_USER; if ( (lp_server_schannel() == True) && (!p->netsec_auth_validated) ) { /* 'server schannel = yes' should enforce use of schannel, the client did offer it in auth2, but obviously did not use it. */ return NT_STATUS_ACCESS_DENIED; } /* checks and updates credentials. creates reply credentials */ if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))) return NT_STATUS_INVALID_HANDLE; memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred)); r_u->buffer_creds = 1; /* yes, we have valid server credentials */ memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds)); /* find the username */ switch (q_u->sam_id.logon_level) { case INTERACTIVE_LOGON_TYPE: uni_samlogon_user = &ctr->auth.id1.uni_user_name; uni_samlogon_domain = &ctr->auth.id1.uni_domain_name; uni_samlogon_workstation = &ctr->auth.id1.uni_wksta_name; DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup())); break; case NET_LOGON_TYPE: uni_samlogon_user = &ctr->auth.id2.uni_user_name; uni_samlogon_domain = &ctr->auth.id2.uni_domain_name; uni_samlogon_workstation = &ctr->auth.id2.uni_wksta_name; DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup())); break; default: DEBUG(2,("SAM Logon: unsupported switch value\n")); return NT_STATUS_INVALID_INFO_CLASS; } /* end switch */ rpcstr_pull(nt_username,uni_samlogon_user->buffer,sizeof(nt_username),uni_samlogon_user->uni_str_len*2,0); rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0); rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0); DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain)); fstrcpy(current_user_info.smb_name, nt_username); sub_set_smb_name(nt_username); DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", q_u->sam_id.ctr->switch_value, nt_username)); status = NT_STATUS_OK; switch (ctr->switch_value) { case NET_LOGON_TYPE: { const char *wksname = nt_workstation; if (!NT_STATUS_IS_OK(status = make_auth_context_fixed(&auth_context, ctr->auth.id2.lm_chal))) { return status; } /* For a network logon, the workstation name comes in with two * backslashes in the front. Strip them if they are there. */ if (*wksname == '\\') wksname++; if (*wksname == '\\') wksname++; /* Standard challenge/response authenticaion */ if (!make_user_info_netlogon_network(&user_info, nt_username, nt_domain, wksname, ctr->auth.id2.lm_chal_resp.buffer, ctr->auth.id2.lm_chal_resp.str_str_len, ctr->auth.id2.nt_chal_resp.buffer, ctr->auth.id2.nt_chal_resp.str_str_len)) { status = NT_STATUS_NO_MEMORY; } break; } case INTERACTIVE_LOGON_TYPE: /* 'Interactive' autheticaion, supplies the password in its MD4 form, encrypted with the session key. We will convert this to chellange/responce for the auth subsystem to chew on */ { const uint8 *chal; if (!NT_STATUS_IS_OK(status = make_auth_context_subsystem(&auth_context))) { return status; } chal = auth_context->get_ntlm_challenge(auth_context); if (!make_user_info_netlogon_interactive(&user_info, nt_username, nt_domain, nt_workstation, chal, ctr->auth.id1.lm_owf.data, ctr->auth.id1.nt_owf.data, p->dc.sess_key)) { status = NT_STATUS_NO_MEMORY; } break; } default: DEBUG(2,("SAM Logon: unsupported switch value\n")); return NT_STATUS_INVALID_INFO_CLASS; } /* end switch */ if ( NT_STATUS_IS_OK(status) ) { status = auth_context->check_ntlm_password(auth_context, user_info, &server_info); } (auth_context->free)(&auth_context); free_user_info(&user_info); DEBUG(5, ("_net_sam_logon: check_password returned status %s\n", nt_errstr(status))); /* Check account and password */ if (!NT_STATUS_IS_OK(status)) { free_server_info(&server_info); return status; } if (server_info->guest) { /* We don't like guest domain logons... */ DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST denied.\n")); free_server_info(&server_info); return NT_STATUS_LOGON_FAILURE; } /* This is the point at which, if the login was successful, that the SAM Local Security Authority should record that the user is logged in to the domain. */ { DOM_GID *gids = NULL; const DOM_SID *user_sid = NULL; const DOM_SID *group_sid = NULL; DOM_SID domain_sid; uint32 user_rid, group_rid; int num_gids = 0; pstring my_name; fstring user_sid_string; fstring group_sid_string; uchar user_session_key[16]; uchar lm_session_key[16]; uchar netlogon_sess_key[16]; sampw = server_info->sam_account; /* set up pointer indicating user/password failed to be found */ usr_info->ptr_user_info = 0; user_sid = pdb_get_user_sid(sampw); group_sid = pdb_get_group_sid(sampw); sid_copy(&domain_sid, user_sid); sid_split_rid(&domain_sid, &user_rid); if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) { DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid %s\n but group sid %s.\nThe conflicting domain portions are not supported for NETLOGON calls\n", pdb_get_domain(sampw), pdb_get_username(sampw), sid_to_string(user_sid_string, user_sid), sid_to_string(group_sid_string, group_sid))); return NT_STATUS_UNSUCCESSFUL; } pstrcpy(my_name, global_myname()); if (!NT_STATUS_IS_OK(status = nt_token_to_group_list(p->mem_ctx, &domain_sid, server_info->ptok, &num_gids, &gids))) { return status; } ZERO_STRUCT(netlogon_sess_key); memcpy(netlogon_sess_key, p->dc.sess_key, 8); if (server_info->user_session_key.length) { memcpy(user_session_key, server_info->user_session_key.data, MIN(sizeof(user_session_key), server_info->user_session_key.length)); SamOEMhash(user_session_key, netlogon_sess_key, 16); } if (server_info->lm_session_key.length) { memcpy(lm_session_key, server_info->lm_session_key.data, MIN(sizeof(lm_session_key), server_info->lm_session_key.length)); SamOEMhash(lm_session_key, netlogon_sess_key, 16); } ZERO_STRUCT(netlogon_sess_key); init_net_user_info3(p->mem_ctx, usr_info, user_rid, group_rid, pdb_get_username(sampw), pdb_get_fullname(sampw), pdb_get_homedir(sampw), pdb_get_dir_drive(sampw), pdb_get_logon_script(sampw), pdb_get_profile_path(sampw), pdb_get_logon_time(sampw), get_time_t_max(), get_time_t_max(), pdb_get_pass_last_set_time(sampw), pdb_get_pass_can_change_time(sampw), pdb_get_pass_must_change_time(sampw), 0, /* logon_count */ 0, /* bad_pw_count */ num_gids, /* uint32 num_groups */ gids , /* DOM_GID *gids */ 0x20 , /* uint32 user_flgs (?) */ server_info->user_session_key.length ? user_session_key : NULL, server_info->lm_session_key.length ? lm_session_key : NULL, my_name , /* char *logon_srv */ pdb_get_domain(sampw), &domain_sid, /* DOM_SID *dom_sid */ /* Should be users domain sid, not servers - for trusted domains */ NULL); /* char *other_sids */ ZERO_STRUCT(user_session_key); ZERO_STRUCT(lm_session_key); } free_server_info(&server_info); return status; }
static NTSTATUS gensec_ntlmssp3_server_start(struct gensec_security *gensec_security) { NTSTATUS nt_status; bool is_standalone; const char *netbios_name; const char *netbios_domain; const char *dns_name; char *dns_domain; struct gensec_ntlmssp_context *gensec_ntlmssp; if ((enum server_role)lp_server_role() == ROLE_STANDALONE) { is_standalone = true; } else { is_standalone = false; } netbios_name = lp_netbios_name(); netbios_domain = lp_workgroup(); /* This should be a 'netbios domain -> DNS domain' mapping */ dns_domain = get_mydnsdomname(talloc_tos()); if (dns_domain) { strlower_m(dns_domain); } dns_name = get_mydnsfullname(); nt_status = gensec_ntlmssp_start(gensec_security); NT_STATUS_NOT_OK_RETURN(nt_status); gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); nt_status = make_auth_context_subsystem(gensec_ntlmssp, &gensec_ntlmssp->auth_context); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } nt_status = ntlmssp_server_start(gensec_ntlmssp, is_standalone, netbios_name, netbios_domain, dns_name, dns_domain, &gensec_ntlmssp->ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } gensec_ntlmssp->ntlmssp_state->callback_private = gensec_ntlmssp; gensec_ntlmssp->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; gensec_ntlmssp->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; gensec_ntlmssp->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; gensec_ntlmssp->ntlmssp_state->check_password = auth_ntlmssp_check_password; if (gensec_ntlmssp->gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_ntlmssp->gensec_security->want_features & GENSEC_FEATURE_SIGN) { gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_ntlmssp->gensec_security->want_features & GENSEC_FEATURE_SEAL) { gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } return NT_STATUS_OK; }
NTSTATUS auth_ntlmssp_start(const struct tsocket_address *remote_address, struct auth_ntlmssp_state **auth_ntlmssp_state) { NTSTATUS nt_status; bool is_standalone; const char *netbios_name; const char *netbios_domain; const char *dns_name; char *dns_domain; struct auth_ntlmssp_state *ans; struct auth_context *auth_context; if ((enum server_role)lp_server_role() == ROLE_STANDALONE) { is_standalone = true; } else { is_standalone = false; } netbios_name = lp_netbios_name(); netbios_domain = lp_workgroup(); /* This should be a 'netbios domain -> DNS domain' mapping */ dns_domain = get_mydnsdomname(talloc_tos()); if (dns_domain) { strlower_m(dns_domain); } dns_name = get_mydnsfullname(); ans = talloc_zero(NULL, struct auth_ntlmssp_state); if (!ans) { DEBUG(0,("auth_ntlmssp_start: talloc failed!\n")); return NT_STATUS_NO_MEMORY; } ans->remote_address = tsocket_address_copy(remote_address, ans); if (ans->remote_address == NULL) { DEBUG(0,("auth_ntlmssp_start: talloc failed!\n")); return NT_STATUS_NO_MEMORY; } nt_status = ntlmssp_server_start(ans, is_standalone, netbios_name, netbios_domain, dns_name, dns_domain, &ans->ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } nt_status = make_auth_context_subsystem(talloc_tos(), &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } ans->auth_context = talloc_steal(ans, auth_context); ans->ntlmssp_state->callback_private = ans; ans->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; ans->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; ans->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; ans->ntlmssp_state->check_password = auth_ntlmssp_check_password; talloc_set_destructor((TALLOC_CTX *)ans, auth_ntlmssp_state_destructor); *auth_ntlmssp_state = ans; return NT_STATUS_OK; }
int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, int length,int bufsize) { int sess_vuid; int smb_bufsize; DATA_BLOB lm_resp; DATA_BLOB nt_resp; DATA_BLOB plaintext_password; fstring user; fstring sub_user; /* Sainitised username for substituion */ fstring domain; fstring native_os; fstring native_lanman; fstring primary_domain; static BOOL done_sesssetup = False; auth_usersupplied_info *user_info = NULL; auth_serversupplied_info *server_info = NULL; NTSTATUS nt_status; BOOL doencrypt = global_encrypted_passwords_negotiated; DATA_BLOB session_key; START_PROFILE(SMBsesssetupX); ZERO_STRUCT(lm_resp); ZERO_STRUCT(nt_resp); ZERO_STRUCT(plaintext_password); DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2))); /* a SPNEGO session setup has 12 command words, whereas a normal NT1 session setup has 13. See the cifs spec. */ if (CVAL(inbuf, smb_wct) == 12 && (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) { if (!global_spnego_negotiated) { DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n")); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } if (SVAL(inbuf,smb_vwv4) == 0) { setup_new_vc_session(); } return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize); } smb_bufsize = SVAL(inbuf,smb_vwv2); if (Protocol < PROTOCOL_NT1) { uint16 passlen1 = SVAL(inbuf,smb_vwv7); /* Never do NT status codes with protocols before NT1 as we don't get client caps. */ remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) { return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } if (doencrypt) { lm_resp = data_blob(smb_buf(inbuf), passlen1); } else { plaintext_password = data_blob(smb_buf(inbuf), passlen1+1); /* Ensure null termination */ plaintext_password.data[passlen1] = 0; } srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE); *domain = 0; } else { uint16 passlen1 = SVAL(inbuf,smb_vwv7); uint16 passlen2 = SVAL(inbuf,smb_vwv8); enum remote_arch_types ra_type = get_remote_arch(); char *p = smb_buf(inbuf); char *save_p = smb_buf(inbuf); uint16 byte_count; if(global_client_caps == 0) { global_client_caps = IVAL(inbuf,smb_vwv11); if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } /* client_caps is used as final determination if client is NT or Win95. This is needed to return the correct error codes in some circumstances. */ if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) { if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) { set_remote_arch( RA_WIN95); } } } if (!doencrypt) { /* both Win95 and WinNT stuff up the password lengths for non-encrypting systems. Uggh. if passlen1==24 its a win95 system, and its setting the password length incorrectly. Luckily it still works with the default code because Win95 will null terminate the password anyway if passlen1>0 and passlen2>0 then maybe its a NT box and its setting passlen2 to some random value which really stuffs things up. we need to fix that one. */ if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1) passlen2 = 0; } /* check for nasty tricks */ if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) { return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) { return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } /* Save the lanman2 password and the NT md4 password. */ if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) { doencrypt = False; } if (doencrypt) { lm_resp = data_blob(p, passlen1); nt_resp = data_blob(p+passlen1, passlen2); } else { pstring pass; BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS; #if 0 /* This was the previous fix. Not sure if it's still valid. JRA. */ if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) { /* NT4.0 stuffs up plaintext unicode password lengths... */ srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1, sizeof(pass), passlen1, STR_TERMINATE); #endif if (unic && (passlen2 == 0) && passlen1) { /* Only a ascii plaintext password was sent. */ srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass), passlen1, STR_TERMINATE|STR_ASCII); } else { srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass), unic ? passlen2 : passlen1, STR_TERMINATE); } plaintext_password = data_blob(pass, strlen(pass)+1); } p += passlen1 + passlen2; p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE); p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE); p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE); p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE); /* not documented or decoded by Ethereal but there is one more string in the extra bytes which is the same as the PrimaryDomain when using extended security. Windows NT 4 and 2003 use this string to store the native lanman string. Windows 9x does not include a string here at all so we have to check if we have any extra bytes left */ byte_count = SVAL(inbuf, smb_vwv13); if ( PTR_DIFF(p, save_p) < byte_count) p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE); else fstrcpy( primary_domain, "null" ); DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", domain, native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { if ( strlen(native_lanman) == 0 ) ra_lanman_string( primary_domain ); else ra_lanman_string( native_lanman ); } } if (SVAL(inbuf,smb_vwv4) == 0) { setup_new_vc_session(); } DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name())); if (*user) { if (global_spnego_negotiated) { /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */ DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n")); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } fstrcpy(sub_user, user); } else { fstrcpy(sub_user, lp_guestaccount()); } sub_set_smb_name(sub_user); reload_services(True); if (lp_security() == SEC_SHARE) { /* in share level we should ignore any passwords */ data_blob_free(&lm_resp); data_blob_free(&nt_resp); data_blob_clear_free(&plaintext_password); map_username(sub_user); add_session_user(sub_user); add_session_workgroup(domain); /* Then force it to null for the benfit of the code below */ *user = 0; } if (!*user) { nt_status = check_guest_password(&server_info); } else if (doencrypt) { if (!negprot_global_auth_context) { DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n")); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } nt_status = make_user_info_for_reply_enc(&user_info, user, domain, lm_resp, nt_resp); if (NT_STATUS_IS_OK(nt_status)) { nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, user_info, &server_info); } } else { struct auth_context *plaintext_auth_context = NULL; const uint8 *chal; nt_status = make_auth_context_subsystem(&plaintext_auth_context); if (NT_STATUS_IS_OK(nt_status)) { chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context); if (!make_user_info_for_reply(&user_info, user, domain, chal, plaintext_password)) { nt_status = NT_STATUS_NO_MEMORY; } if (NT_STATUS_IS_OK(nt_status)) { nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, user_info, &server_info); (plaintext_auth_context->free)(&plaintext_auth_context); } } } free_user_info(&user_info); if (!NT_STATUS_IS_OK(nt_status)) { nt_status = do_map_to_guest(nt_status, &server_info, user, domain); } if (!NT_STATUS_IS_OK(nt_status)) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); data_blob_clear_free(&plaintext_password); return ERROR_NT(nt_status_squash(nt_status)); } /* Ensure we can't possible take a code path leading to a null defref. */ if (!server_info) { return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } nt_status = create_local_token(server_info); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("create_local_token failed: %s\n", nt_errstr(nt_status))); data_blob_free(&nt_resp); data_blob_free(&lm_resp); data_blob_clear_free(&plaintext_password); return ERROR_NT(nt_status_squash(nt_status)); } if (server_info->user_session_key.data) { session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length); } else { session_key = data_blob(NULL, 0); } data_blob_clear_free(&plaintext_password); /* it's ok - setup a reply */ set_message(outbuf,3,0,True); if (Protocol >= PROTOCOL_NT1) { char *p = smb_buf( outbuf ); p += add_signature( outbuf, p ); set_message_end( outbuf, p ); /* perhaps grab OS version here?? */ } if (server_info->guest) { SSVAL(outbuf,smb_vwv2,1); } /* register the name and uid as being validated, so further connections to a uid can get through without a password, on the same VC */ if (lp_security() == SEC_SHARE) { sess_vuid = UID_FIELD_INVALID; data_blob_free(&session_key); TALLOC_FREE(server_info); } else { /* register_vuid keeps the server info */ sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user); if (sess_vuid == UID_FIELD_INVALID) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } /* current_user_info is changed on new vuid */ reload_services( True ); sessionsetup_start_signing_engine(server_info, inbuf); } data_blob_free(&nt_resp); data_blob_free(&lm_resp); SSVAL(outbuf,smb_uid,sess_vuid); SSVAL(inbuf,smb_uid,sess_vuid); if (!done_sesssetup) max_send = MIN(max_send,smb_bufsize); done_sesssetup = True; END_PROFILE(SMBsesssetupX); return chain_reply(inbuf,outbuf,length,bufsize); }
NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address, struct gensec_security **gensec_security_out) { struct gensec_security *gensec_security; struct auth_context *auth_context; NTSTATUS nt_status; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); nt_status = make_auth_context_subsystem(tmp_ctx, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } if (auth_context->prepare_gensec) { nt_status = auth_context->prepare_gensec(tmp_ctx, &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } } else { struct gensec_settings *gensec_settings; struct loadparm_context *lp_ctx; lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_context()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); TALLOC_FREE(tmp_ctx); return NT_STATUS_INVALID_SERVER_STATE; } gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx); if (lp_ctx == NULL) { DEBUG(10, ("lpcfg_gensec_settings failed\n")); TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } gensec_settings->backends = talloc_zero_array(gensec_settings, struct gensec_security_ops *, 2); if (gensec_settings->backends == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } gensec_settings->backends[0] = &gensec_ntlmssp3_server_ops; nt_status = gensec_server_start(tmp_ctx, gensec_settings, NULL, &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } talloc_unlink(tmp_ctx, lp_ctx); talloc_unlink(tmp_ctx, gensec_settings); } nt_status = gensec_set_remote_address(gensec_security, remote_address); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } *gensec_security_out = talloc_steal(mem_ctx, gensec_security); TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; }