NTSTATUS auth_generic_server_get_user_info(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, struct auth_session_info **session_info) { NTSTATUS status; status = gensec_session_info(gensec_security, mem_ctx, session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, (__location__ ": Failed to get authenticated user " "info: %s\n", nt_errstr(status))); return status; } DEBUG(5, (__location__ "OK: user: %s domain: %s\n", (*session_info)->info->account_name, (*session_info)->info->domain_name)); return NT_STATUS_OK; }
/* add any auth information needed in a alter ack, and process the authentication information found in the alter. */ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt) { struct dcesrv_connection *dce_conn = call->conn; NTSTATUS status; /* on a pure interface change there is no auth_info structure setup */ if (!call->conn->auth_state.auth_info || dce_conn->auth_state.auth_info->credentials.length == 0) { return NT_STATUS_OK; } if (!call->conn->auth_state.gensec_security) { return NT_STATUS_INVALID_PARAMETER; } status = gensec_update(dce_conn->auth_state.gensec_security, call, call->event_ctx, dce_conn->auth_state.auth_info->credentials, &dce_conn->auth_state.auth_info->credentials); if (NT_STATUS_IS_OK(status)) { status = gensec_session_info(dce_conn->auth_state.gensec_security, dce_conn, &dce_conn->auth_state.session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return status; } /* Now that we are authenticated, got back to the generic session key... */ dce_conn->auth_state.session_key = dcesrv_generic_session_key; return NT_STATUS_OK; } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { dce_conn->auth_state.auth_info->auth_pad_length = 0; dce_conn->auth_state.auth_info->auth_reserved = 0; return NT_STATUS_OK; } DEBUG(4, ("GENSEC mech rejected the incoming authentication at auth alter_ack: %s\n", nt_errstr(status))); return status; }
/* process the final stage of a auth request */ bool dcesrv_auth_auth3(struct dcesrv_call_state *call) { struct ncacn_packet *pkt = &call->pkt; struct dcesrv_connection *dce_conn = call->conn; NTSTATUS status; uint32_t auth_length; /* We can't work without an existing gensec state, and an new blob to feed it */ if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security || pkt->u.auth3.auth_info.length == 0) { return false; } status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info, dce_conn->auth_state.auth_info, &auth_length, true); if (!NT_STATUS_IS_OK(status)) { return false; } /* Pass the extra data we got from the client down to gensec for processing */ status = gensec_update(dce_conn->auth_state.gensec_security, call, call->event_ctx, dce_conn->auth_state.auth_info->credentials, &dce_conn->auth_state.auth_info->credentials); if (NT_STATUS_IS_OK(status)) { status = gensec_session_info(dce_conn->auth_state.gensec_security, dce_conn, &dce_conn->auth_state.session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return false; } /* Now that we are authenticated, go back to the generic session key... */ dce_conn->auth_state.session_key = dcesrv_generic_session_key; return true; } else { DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_auth3: %s\n", nt_errstr(status))); return false; } }
/* add any auth information needed in a bind ack, and process the authentication information found in the bind. */ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt) { struct dcesrv_connection *dce_conn = call->conn; NTSTATUS status; if (!call->conn->auth_state.gensec_security) { return NT_STATUS_OK; } status = gensec_update(dce_conn->auth_state.gensec_security, call, dce_conn->auth_state.auth_info->credentials, &dce_conn->auth_state.auth_info->credentials); if (NT_STATUS_IS_OK(status)) { status = gensec_session_info(dce_conn->auth_state.gensec_security, &dce_conn->auth_state.session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return status; } if (dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_HEADER_SIGNING) { gensec_want_feature(dce_conn->auth_state.gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER); } /* Now that we are authenticated, go back to the generic session key... */ dce_conn->auth_state.session_key = dcesrv_generic_session_key; return NT_STATUS_OK; } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { dce_conn->auth_state.auth_info->auth_pad_length = 0; dce_conn->auth_state.auth_info->auth_reserved = 0; return NT_STATUS_OK; } else { DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_ack: %s\n", nt_errstr(status))); return status; } }
NTSTATUS auth_generic_server_get_user_info(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, struct auth_session_info **session_info) { NTSTATUS status; /* this has to be done as root in order to get to the * messaging sockets for IDMAP and privilege.ldb in the AD * DC */ become_root(); status = gensec_session_info(gensec_security, mem_ctx, session_info); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, (__location__ ": Failed to get authenticated user " "info: %s\n", nt_errstr(status))); return status; } DEBUG(5, (__location__ "OK: user: %s domain: %s\n", (*session_info)->info->account_name, (*session_info)->info->domain_name)); return NT_STATUS_OK; }
static void reply_sesssetup_and_X_spnego(struct smb_request *req) { const uint8_t *p; DATA_BLOB in_blob; DATA_BLOB out_blob = data_blob_null; size_t bufrem; char *tmp; const char *native_os; const char *native_lanman; const char *primary_domain; uint16_t data_blob_len = SVAL(req->vwv+7, 0); enum remote_arch_types ra_type = get_remote_arch(); uint64_t vuid = req->vuid; NTSTATUS status = NT_STATUS_OK; struct smbXsrv_connection *xconn = req->xconn; struct smbd_server_connection *sconn = req->sconn; uint16_t action = 0; bool is_authenticated = false; NTTIME now = timeval_to_nttime(&req->request_time); struct smbXsrv_session *session = NULL; uint16_t smb_bufsize = SVAL(req->vwv+2, 0); uint32_t client_caps = IVAL(req->vwv+10, 0); struct smbXsrv_session_auth0 *auth; DEBUG(3,("Doing spnego session setup\n")); if (!xconn->smb1.sessions.done_sesssetup) { global_client_caps = client_caps; if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } } p = req->buf; if (data_blob_len == 0) { /* an invalid request */ reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE)); return; } bufrem = smbreq_bufrem(req, p); /* pull the spnego blob */ in_blob = data_blob_const(p, MIN(bufrem, data_blob_len)); #if 0 file_save("negotiate.dat", in_blob.data, in_blob.length); #endif p = req->buf + in_blob.length; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); native_os = tmp ? tmp : ""; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); native_lanman = tmp ? tmp : ""; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); primary_domain = tmp ? tmp : ""; DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { /* Vista sets neither the OS or lanman strings */ if ( !strlen(native_os) && !strlen(native_lanman) ) set_remote_arch(RA_VISTA); /* Windows 2003 doesn't set the native lanman string, but does set primary domain which is a bug I think */ if ( !strlen(native_lanman) ) { ra_lanman_string( primary_domain ); } else { ra_lanman_string( native_lanman ); } } else if ( ra_type == RA_VISTA ) { if ( strncmp(native_os, "Mac OS X", 8) == 0 ) { set_remote_arch(RA_OSX); } } if (vuid != 0) { status = smb1srv_session_lookup(xconn, vuid, now, &session); if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { reply_force_doserror(req, ERRSRV, ERRbaduid); return; } if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { status = NT_STATUS_OK; } if (NT_STATUS_IS_OK(status)) { session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; status = NT_STATUS_MORE_PROCESSING_REQUIRED; TALLOC_FREE(session->pending_auth); } if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { reply_nterror(req, nt_status_squash(status)); return; } } if (session == NULL) { /* create a new session */ status = smbXsrv_session_create(xconn, now, &session); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, nt_status_squash(status)); return; } } status = smbXsrv_session_find_auth(session, xconn, now, &auth); if (!NT_STATUS_IS_OK(status)) { status = smbXsrv_session_create_auth(session, xconn, now, 0, /* flags */ 0, /* security */ &auth); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, nt_status_squash(status)); return; } } if (auth->gensec == NULL) { status = auth_generic_prepare(session, xconn->remote_address, xconn->local_address, "SMB", &auth->gensec); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY); gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN); gensec_want_feature(auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT); status = gensec_start_mech_by_oid(auth->gensec, GENSEC_OID_SPNEGO); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to start SPNEGO handler!\n")); TALLOC_FREE(session);; reply_nterror(req, nt_status_squash(status)); return; } } become_root(); status = gensec_update(auth->gensec, talloc_tos(), in_blob, &out_blob); unbecome_root(); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (NT_STATUS_IS_OK(status) && session->global->auth_session_info == NULL) { struct auth_session_info *session_info = NULL; status = gensec_session_info(auth->gensec, session, &session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("Failed to generate session_info " "(user and group token) for session setup: %s\n", nt_errstr(status))); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) { action |= SMB_SETUP_GUEST; } if (session_info->session_key.length > 0) { struct smbXsrv_session *x = session; /* * Note: the SMB1 signing key is not truncated to 16 byte! */ x->global->signing_key = data_blob_dup_talloc(x->global, session_info->session_key); if (x->global->signing_key.data == NULL) { data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } /* * clear the session key * the first tcon will add setup the application key */ data_blob_clear_free(&session_info->session_key); } session->compat = talloc_zero(session, struct user_struct); if (session->compat == NULL) { data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } session->compat->session = session; session->compat->homes_snum = -1; session->compat->session_info = session_info; session->compat->session_keystr = NULL; session->compat->vuid = session->global->session_wire_id; DLIST_ADD(sconn->users, session->compat); sconn->num_users++; if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { is_authenticated = true; session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); } if (srv_is_signing_negotiated(xconn) && is_authenticated && session->global->signing_key.length > 0) { /* * Try and turn on server signing on the first non-guest * sessionsetup. */ srv_set_signing(xconn, session->global->signing_key, data_blob_null); } set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); session->status = NT_STATUS_OK; session->global->auth_session_info = talloc_move(session->global, &session_info); session->global->auth_session_info_seqnum += 1; session->global->channels[0].auth_session_info_seqnum = session->global->auth_session_info_seqnum; session->global->auth_time = now; if (client_caps & CAP_DYNAMIC_REAUTH) { session->global->expiration_time = gensec_expire_time(auth->gensec); } else { session->global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY; } if (!session_claim(session)) { DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n", (unsigned long long)session->compat->vuid)); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } if (!xconn->smb1.sessions.done_sesssetup) { if (smb_bufsize < SMB_BUFFER_SIZE_MIN) { reply_force_doserror(req, ERRSRV, ERRerror); return; } xconn->smb1.sessions.max_send = smb_bufsize; xconn->smb1.sessions.done_sesssetup = true; } /* current_user_info is changed on new vuid */ reload_services(sconn, conn_snum_used, true); } else if (NT_STATUS_IS_OK(status)) {
static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private1, unsigned int mux_id, void **private2) { DATA_BLOB in; DATA_BLOB out = data_blob(NULL, 0); char *out_base64 = NULL; const char *reply_arg = NULL; struct gensec_ntlm_state { struct gensec_security *gensec_state; const char *set_password; }; struct gensec_ntlm_state *state; struct tevent_context *ev; struct imessaging_context *msg; NTSTATUS nt_status; bool first = false; const char *reply_code; struct cli_credentials *creds; static char *want_feature_list = NULL; static DATA_BLOB session_key; TALLOC_CTX *mem_ctx; if (*private1) { state = (struct gensec_ntlm_state *)*private1; } else { state = talloc_zero(NULL, struct gensec_ntlm_state); if (!state) { mux_printf(mux_id, "BH No Memory\n"); exit(1); } *private1 = state; if (opt_password) { state->set_password = opt_password; } } if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); mux_printf(mux_id, "BH Query invalid\n"); return; } if (strlen(buf) > 3) { if(strncmp(buf, "SF ", 3) == 0) { DEBUG(10, ("Setting flags to negotiate\n")); talloc_free(want_feature_list); want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3); mux_printf(mux_id, "OK\n"); return; } in = base64_decode_data_blob(buf + 3); } else { in = data_blob(NULL, 0); } if (strncmp(buf, "YR", 2) == 0) { if (state->gensec_state) { talloc_free(state->gensec_state); state->gensec_state = NULL; } } else if ( (strncmp(buf, "OK", 2) == 0)) { /* Just return BH, like ntlm_auth from Samba 3 does. */ mux_printf(mux_id, "BH Command expected\n"); data_blob_free(&in); return; } else if ( (strncmp(buf, "TT ", 3) != 0) && (strncmp(buf, "KK ", 3) != 0) && (strncmp(buf, "AF ", 3) != 0) && (strncmp(buf, "NA ", 3) != 0) && (strncmp(buf, "UG", 2) != 0) && (strncmp(buf, "PW ", 3) != 0) && (strncmp(buf, "GK", 2) != 0) && (strncmp(buf, "GF", 2) != 0)) { DEBUG(1, ("SPNEGO request [%s] invalid\n", buf)); mux_printf(mux_id, "BH SPNEGO request invalid\n"); data_blob_free(&in); return; } ev = s4_event_context_init(state); if (!ev) { exit(1); } mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx"); /* setup gensec */ if (!(state->gensec_state)) { switch (stdio_helper_mode) { case GSS_SPNEGO_CLIENT: case NTLMSSP_CLIENT_1: /* setup the client side */ nt_status = gensec_client_start(NULL, &state->gensec_state, ev, lpcfg_gensec_settings(NULL, lp_ctx)); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); exit(1); } break; case GSS_SPNEGO_SERVER: case SQUID_2_5_NTLMSSP: { const char *winbind_method[] = { "winbind", NULL }; struct auth4_context *auth_context; msg = imessaging_client_init(state, lpcfg_imessaging_path(state, lp_ctx), ev); if (!msg) { talloc_free(mem_ctx); exit(1); } nt_status = auth_context_create_methods(mem_ctx, winbind_method, ev, msg, lp_ctx, NULL, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); exit(1); } if (!NT_STATUS_IS_OK(gensec_server_start(state, ev, lpcfg_gensec_settings(state, lp_ctx), auth_context, &state->gensec_state))) { talloc_free(mem_ctx); exit(1); } break; } default: talloc_free(mem_ctx); abort(); } creds = cli_credentials_init(state->gensec_state); cli_credentials_set_conf(creds, lp_ctx); if (opt_username) { cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED); } if (opt_domain) { cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED); } if (state->set_password) { cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED); } else { cli_credentials_set_password_callback(creds, get_password); creds->priv_data = (void*)(uintptr_t)mux_id; } if (opt_workstation) { cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED); } switch (stdio_helper_mode) { case GSS_SPNEGO_SERVER: case SQUID_2_5_NTLMSSP: cli_credentials_set_machine_account(creds, lp_ctx); break; default: break; } gensec_set_credentials(state->gensec_state, creds); gensec_want_feature_list(state->gensec_state, want_feature_list); switch (stdio_helper_mode) { case GSS_SPNEGO_CLIENT: case GSS_SPNEGO_SERVER: nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO); if (!in.length) { first = true; } break; case NTLMSSP_CLIENT_1: if (!in.length) { first = true; } /* fall through */ case SQUID_2_5_NTLMSSP: nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP); break; default: talloc_free(mem_ctx); abort(); } if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status))); mux_printf(mux_id, "BH GENSEC mech failed to start\n"); talloc_free(mem_ctx); return; } } /* update */ if (strncmp(buf, "PW ", 3) == 0) { state->set_password = talloc_strndup(state, (const char *)in.data, in.length); cli_credentials_set_password(gensec_get_credentials(state->gensec_state), state->set_password, CRED_SPECIFIED); mux_printf(mux_id, "OK\n"); data_blob_free(&in); talloc_free(mem_ctx); return; } if (strncmp(buf, "UG", 2) == 0) { int i; char *grouplist = NULL; struct auth_session_info *session_info; nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("gensec_session_info failed: %s\n", nt_errstr(nt_status))); mux_printf(mux_id, "BH %s\n", nt_errstr(nt_status)); data_blob_free(&in); talloc_free(mem_ctx); return; } /* get the string onto the context */ grouplist = talloc_strdup(mem_ctx, ""); for (i=0; i<session_info->security_token->num_sids; i++) { struct security_token *token = session_info->security_token; const char *sidstr = dom_sid_string(session_info, &token->sids[i]); grouplist = talloc_asprintf_append_buffer(grouplist, "%s,", sidstr); } mux_printf(mux_id, "GL %s\n", grouplist); talloc_free(session_info); data_blob_free(&in); talloc_free(mem_ctx); return; } if (strncmp(buf, "GK", 2) == 0) { char *base64_key; DEBUG(10, ("Requested session key\n")); nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key); if(!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status))); mux_printf(mux_id, "BH No session key\n"); talloc_free(mem_ctx); return; } else { base64_key = base64_encode_data_blob(state, session_key); mux_printf(mux_id, "GK %s\n", base64_key); talloc_free(base64_key); } talloc_free(mem_ctx); return; } if (strncmp(buf, "GF", 2) == 0) { struct ntlmssp_state *ntlmssp_state; uint32_t neg_flags; ntlmssp_state = talloc_get_type(state->gensec_state->private_data, struct ntlmssp_state); neg_flags = ntlmssp_state->neg_flags; DEBUG(10, ("Requested negotiated feature flags\n")); mux_printf(mux_id, "GF 0x%08x\n", neg_flags); return; } nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out); /* don't leak 'bad password'/'no such user' info to the network client */ nt_status = nt_status_squash(nt_status); if (out.length) { out_base64 = base64_encode_data_blob(mem_ctx, out); } else { out_base64 = NULL; } if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { reply_arg = "*"; if (first) { reply_code = "YR"; } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) { reply_code = "KK"; } else if (state->gensec_state->gensec_role == GENSEC_SERVER) { reply_code = "TT"; } else { abort(); } } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) { reply_code = "BH NT_STATUS_ACCESS_DENIED"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) { reply_code = "BH NT_STATUS_UNSUCCESSFUL"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); } else if (!NT_STATUS_IS_OK(nt_status)) { reply_code = "NA"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) { struct auth_session_info *session_info; nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { reply_code = "BH Failed to retrive session info"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status))); } else { reply_code = "AF"; reply_arg = talloc_asprintf(state->gensec_state, "%s%s%s", session_info->info->domain_name, lpcfg_winbind_separator(lp_ctx), session_info->info->account_name); talloc_free(session_info); } } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) { reply_code = "AF"; reply_arg = out_base64; } else { abort(); } switch (stdio_helper_mode) { case GSS_SPNEGO_SERVER: mux_printf(mux_id, "%s %s %s\n", reply_code, out_base64 ? out_base64 : "*", reply_arg ? reply_arg : "*"); break; default: if (out_base64) { mux_printf(mux_id, "%s %s\n", reply_code, out_base64); } else if (reply_arg) { mux_printf(mux_id, "%s %s\n", reply_code, reply_arg); } else { mux_printf(mux_id, "%s\n", reply_code); } } talloc_free(mem_ctx); return; }
/* add any auth information needed in a bind ack, and process the authentication information found in the bind. */ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt) { struct dcesrv_connection *dce_conn = call->conn; NTSTATUS status; bool want_header_signing = false; if (!call->conn->auth_state.gensec_security) { return NT_STATUS_OK; } if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) { dce_conn->auth_state.client_hdr_signing = true; want_header_signing = true; } if (!lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", true)) { want_header_signing = false; } status = gensec_update(dce_conn->auth_state.gensec_security, call, call->event_ctx, dce_conn->auth_state.auth_info->credentials, &dce_conn->auth_state.auth_info->credentials); if (NT_STATUS_IS_OK(status)) { status = gensec_session_info(dce_conn->auth_state.gensec_security, dce_conn, &dce_conn->auth_state.session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return status; } if (!gensec_have_feature(dce_conn->auth_state.gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER)) { want_header_signing = false; } if (want_header_signing) { gensec_want_feature(dce_conn->auth_state.gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER); dce_conn->auth_state.hdr_signing = true; pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN; } /* Now that we are authenticated, go back to the generic session key... */ dce_conn->auth_state.session_key = dcesrv_generic_session_key; return NT_STATUS_OK; } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { dce_conn->auth_state.auth_info->auth_pad_length = 0; dce_conn->auth_state.auth_info->auth_reserved = 0; if (!gensec_have_feature(dce_conn->auth_state.gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER)) { want_header_signing = false; } if (want_header_signing) { gensec_want_feature(dce_conn->auth_state.gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER); dce_conn->auth_state.hdr_signing = true; pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN; } return NT_STATUS_OK; } else { DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_ack: %s\n", nt_errstr(status))); return status; } }
static bool kpasswd_process_request(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, struct gensec_security *gensec_security, uint16_t version, DATA_BLOB *input, DATA_BLOB *reply) { struct auth_session_info *session_info; size_t pw_len; if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security, &session_info))) { return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, "gensec_session_info failed!", reply); } switch (version) { case KRB5_KPASSWD_VERS_CHANGEPW: { DATA_BLOB password; if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx), CH_UTF8, CH_UTF16, (const char *)input->data, input->length, (void **)&password.data, &pw_len, false)) { return false; } password.length = pw_len; return kpasswdd_change_password(kdc, mem_ctx, session_info, &password, reply); break; } case KRB5_KPASSWD_VERS_SETPW: { NTSTATUS status; enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR; struct samr_DomInfo1 *dominfo = NULL; struct ldb_context *samdb; struct ldb_message *msg; krb5_context context = kdc->smb_krb5_context->krb5_context; ChangePasswdDataMS chpw; DATA_BLOB password; krb5_principal principal; char *set_password_on_princ; struct ldb_dn *set_password_on_dn; size_t len; int ret; msg = ldb_msg_new(mem_ctx); if (!msg) { return false; } ret = decode_ChangePasswdDataMS(input->data, input->length, &chpw, &len); if (ret) { return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_MALFORMED, "failed to decode password change structure", reply); } if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(kdc->task->lp_ctx), CH_UTF8, CH_UTF16, (const char *)chpw.newpasswd.data, chpw.newpasswd.length, (void **)&password.data, &pw_len, false)) { free_ChangePasswdDataMS(&chpw); return false; } password.length = pw_len; if ((chpw.targname && !chpw.targrealm) || (!chpw.targname && chpw.targrealm)) { return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_MALFORMED, "Realm and principal must be both present, or neither present", reply); } if (chpw.targname && chpw.targrealm) { #ifdef SAMBA4_INTERNAL_HEIMDAL if (_krb5_principalname2krb5_principal(kdc->smb_krb5_context->krb5_context, &principal, *chpw.targname, *chpw.targrealm) != 0) { free_ChangePasswdDataMS(&chpw); return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_MALFORMED, "failed to extract principal to set", reply); } #else /* SAMBA4_INTERNAL_HEIMDAL */ return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_BAD_VERSION, "Operation Not Implemented", reply); #endif /* SAMBA4_INTERNAL_HEIMDAL */ } else { free_ChangePasswdDataMS(&chpw); return kpasswdd_change_password(kdc, mem_ctx, session_info, &password, reply); } free_ChangePasswdDataMS(&chpw); if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) { krb5_free_principal(context, principal); return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_MALFORMED, "krb5_unparse_name failed!", reply); } krb5_free_principal(context, principal); samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info); if (!samdb) { return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, "Unable to open database!", reply); } DEBUG(3, ("%s\\%s (%s) is changing password of %s\n", session_info->server_info->domain_name, session_info->server_info->account_name, dom_sid_string(mem_ctx, session_info->security_token->user_sid), set_password_on_princ)); ret = ldb_transaction_start(samdb); if (ret) { status = NT_STATUS_TRANSACTION_ABORTED; return kpasswd_make_pwchange_reply(kdc, mem_ctx, status, SAM_PWD_CHANGE_NO_ERROR, NULL, reply); } status = crack_user_principal_name(samdb, mem_ctx, set_password_on_princ, &set_password_on_dn, NULL); free(set_password_on_princ); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(samdb); return kpasswd_make_pwchange_reply(kdc, mem_ctx, status, SAM_PWD_CHANGE_NO_ERROR, NULL, reply); } msg = ldb_msg_new(mem_ctx); if (msg == NULL) { ldb_transaction_cancel(samdb); status = NT_STATUS_NO_MEMORY; } else { msg->dn = ldb_dn_copy(msg, set_password_on_dn); if (!msg->dn) { status = NT_STATUS_NO_MEMORY; } } if (NT_STATUS_IS_OK(status)) { /* Admin password set */ status = samdb_set_password(samdb, mem_ctx, set_password_on_dn, NULL, msg, &password, NULL, NULL, false, /* this is not a user password change */ &reject_reason, &dominfo); } if (NT_STATUS_IS_OK(status)) { /* modify the samdb record */ ret = samdb_replace(samdb, mem_ctx, msg); if (ret != 0) { DEBUG(2,("Failed to modify record to set password on %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(samdb))); status = NT_STATUS_ACCESS_DENIED; } } if (NT_STATUS_IS_OK(status)) { ret = ldb_transaction_commit(samdb); if (ret != 0) { DEBUG(1,("Failed to commit transaction to set password on %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(samdb))); status = NT_STATUS_TRANSACTION_ABORTED; } } else { ldb_transaction_cancel(samdb); } return kpasswd_make_pwchange_reply(kdc, mem_ctx, status, reject_reason, dominfo, reply); } default: return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_BAD_VERSION, talloc_asprintf(mem_ctx, "Protocol version %u not supported", version), reply); } return true; }
static NTSTATUS smbd_smb2_auth_generic(struct smbd_smb2_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, DATA_BLOB in_security_buffer, uint16_t *out_session_flags, DATA_BLOB *out_security_buffer, uint64_t *out_session_id) { NTSTATUS status; *out_security_buffer = data_blob_null; if (session->gensec_security == NULL) { status = auth_generic_prepare(session, session->sconn->remote_address, &session->gensec_security); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); return status; } gensec_want_feature(session->gensec_security, GENSEC_FEATURE_SESSION_KEY); gensec_want_feature(session->gensec_security, GENSEC_FEATURE_UNIX_TOKEN); status = gensec_start_mech_by_oid(session->gensec_security, GENSEC_OID_SPNEGO); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); return status; } } become_root(); status = gensec_update(session->gensec_security, smb2req, NULL, in_security_buffer, out_security_buffer); unbecome_root(); if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); return nt_status_squash(status); } if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { *out_session_id = session->vuid; return status; } status = gensec_session_info(session->gensec_security, session, &session->session_info); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); return status; } *out_session_id = session->vuid; return smbd_smb2_auth_generic_return(session, smb2req, in_security_mode, in_security_buffer, out_session_flags, out_session_id); }
/* * Given the username/password, do a kinit, store the ticket in * cache_name if specified, and return the PAC_LOGON_INFO (the * structure containing the important user information such as * groups). */ NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx, const char *name, const char *pass, time_t time_offset, time_t *expire_time, time_t *renew_till_time, const char *cache_name, bool request_pac, bool add_netbios_addr, time_t renewable_time, const char *impersonate_princ_s, struct PAC_LOGON_INFO **_logon_info) { krb5_error_code ret; NTSTATUS status = NT_STATUS_INVALID_PARAMETER; DATA_BLOB tkt, tkt_wrapped, ap_rep, sesskey1; const char *auth_princ = NULL; const char *local_service = NULL; const char *cc = "MEMORY:kerberos_return_pac"; struct auth_session_info *session_info; struct gensec_security *gensec_server_context; struct gensec_settings *gensec_settings; size_t idx = 0; struct auth4_context *auth_context; struct loadparm_context *lp_ctx; struct PAC_LOGON_INFO *logon_info = NULL; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); ZERO_STRUCT(tkt); ZERO_STRUCT(ap_rep); ZERO_STRUCT(sesskey1); if (!name || !pass) { return NT_STATUS_INVALID_PARAMETER; } if (cache_name) { cc = cache_name; } if (!strchr_m(name, '@')) { auth_princ = talloc_asprintf(mem_ctx, "%s@%s", name, lp_realm()); } else { auth_princ = name; } NT_STATUS_HAVE_NO_MEMORY(auth_princ); local_service = talloc_asprintf(mem_ctx, "%s$@%s", lp_netbios_name(), lp_realm()); NT_STATUS_HAVE_NO_MEMORY(local_service); ret = kerberos_kinit_password_ext(auth_princ, pass, time_offset, expire_time, renew_till_time, cc, request_pac, add_netbios_addr, renewable_time, &status); if (ret) { DEBUG(1,("kinit failed for '%s' with: %s (%d)\n", auth_princ, error_message(ret), ret)); /* status already set */ goto out; } DEBUG(10,("got TGT for %s in %s\n", auth_princ, cc)); if (expire_time) { DEBUGADD(10,("\tvalid until: %s (%d)\n", http_timestring(talloc_tos(), *expire_time), (int)*expire_time)); } if (renew_till_time) { DEBUGADD(10,("\trenewable till: %s (%d)\n", http_timestring(talloc_tos(), *renew_till_time), (int)*renew_till_time)); } /* we cannot continue with krb5 when UF_DONT_REQUIRE_PREAUTH is set, * in that case fallback to NTLM - gd */ if (expire_time && renew_till_time && (*expire_time == 0) && (*renew_till_time == 0)) { return NT_STATUS_INVALID_LOGON_TYPE; } ret = cli_krb5_get_ticket(mem_ctx, local_service, time_offset, &tkt, &sesskey1, 0, cc, NULL, impersonate_princ_s); if (ret) { DEBUG(1,("failed to get ticket for %s: %s\n", local_service, error_message(ret))); if (impersonate_princ_s) { DEBUGADD(1,("tried S4U2SELF impersonation as: %s\n", impersonate_princ_s)); } status = krb5_to_nt_status(ret); goto out; } /* wrap that up in a nice GSS-API wrapping */ tkt_wrapped = spnego_gen_krb5_wrap(tmp_ctx, tkt, TOK_ID_KRB_AP_REQ); if (tkt_wrapped.data == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } auth_context = talloc_zero(tmp_ctx, struct auth4_context); if (auth_context == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } auth_context->generate_session_info_pac = kerberos_fetch_pac; lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_context()); if (lp_ctx == NULL) { status = NT_STATUS_INVALID_SERVER_STATE; DEBUG(10, ("loadparm_init_s3 failed\n")); goto out; } gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx); if (lp_ctx == NULL) { status = NT_STATUS_NO_MEMORY; DEBUG(10, ("lpcfg_gensec_settings failed\n")); goto out; } gensec_settings->backends = talloc_zero_array(gensec_settings, struct gensec_security_ops *, 2); if (gensec_settings->backends == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } gensec_init(); gensec_settings->backends[idx++] = &gensec_gse_krb5_security_ops; status = gensec_server_start(tmp_ctx, gensec_settings, auth_context, &gensec_server_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, (__location__ "Failed to start server-side GENSEC to validate a Kerberos ticket: %s\n", nt_errstr(status))); goto out; } talloc_unlink(tmp_ctx, lp_ctx); talloc_unlink(tmp_ctx, gensec_settings); talloc_unlink(tmp_ctx, auth_context); status = gensec_start_mech_by_oid(gensec_server_context, GENSEC_OID_KERBEROS5); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, (__location__ "Failed to start server-side GENSEC krb5 to validate a Kerberos ticket: %s\n", nt_errstr(status))); goto out; } /* Do a client-server update dance */ status = gensec_update(gensec_server_context, tmp_ctx, NULL, tkt_wrapped, &ap_rep); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("gensec_update() failed: %s\n", nt_errstr(status))); goto out; } /* Now return the PAC information to the callers. We ingore * the session_info and instead pick out the PAC via the * private_data on the auth_context */ status = gensec_session_info(gensec_server_context, tmp_ctx, &session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Unable to obtain PAC via gensec_session_info\n")); goto out; } logon_info = talloc_get_type_abort(gensec_server_context->auth_context->private_data, struct PAC_LOGON_INFO); if (logon_info == NULL) { DEBUG(1,("no PAC\n")); status = NT_STATUS_INVALID_PARAMETER; goto out; } *_logon_info = talloc_move(mem_ctx, &logon_info); out: talloc_free(tmp_ctx); if (cc != cache_name) { ads_kdestroy(cc); } data_blob_free(&tkt); data_blob_free(&ap_rep); data_blob_free(&sesskey1); return status; }
/* authorize a zone update */ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr, const char *type, const char *key, uint32_t keydatalen, uint8_t *keydata, void *dbdata) { struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data); TALLOC_CTX *tmp_ctx; DATA_BLOB ap_req; struct cli_credentials *server_credentials; char *keytab_name; int ret; int ldb_ret; NTSTATUS nt_status; struct gensec_security *gensec_ctx; struct auth_session_info *session_info; struct ldb_dn *dn; isc_result_t result; struct ldb_result *res; const char * attrs[] = { NULL }; uint32_t access_mask; /* Remove cached credentials, if any */ if (state->session_info) { talloc_free(state->session_info); state->session_info = NULL; } if (state->update_name) { talloc_free(state->update_name); state->update_name = NULL; } tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { state->log(ISC_LOG_ERROR, "samba_dlz: no memory"); return ISC_FALSE; } ap_req = data_blob_const(keydata, keydatalen); server_credentials = cli_credentials_init(tmp_ctx); if (!server_credentials) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to init server credentials"); talloc_free(tmp_ctx); return ISC_FALSE; } cli_credentials_set_krb5_context(server_credentials, state->smb_krb5_ctx); cli_credentials_set_conf(server_credentials, state->lp); keytab_name = talloc_asprintf(tmp_ctx, "file:%s/dns.keytab", lpcfg_private_dir(state->lp)); ret = cli_credentials_set_keytab_name(server_credentials, state->lp, keytab_name, CRED_SPECIFIED); if (ret != 0) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to obtain server credentials from %s", keytab_name); talloc_free(tmp_ctx); return ISC_FALSE; } talloc_free(keytab_name); nt_status = gensec_server_start(tmp_ctx, lpcfg_gensec_settings(tmp_ctx, state->lp), state->auth_context, &gensec_ctx); if (!NT_STATUS_IS_OK(nt_status)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to start gensec server"); talloc_free(tmp_ctx); return ISC_FALSE; } gensec_set_credentials(gensec_ctx, server_credentials); nt_status = gensec_start_mech_by_name(gensec_ctx, "spnego"); if (!NT_STATUS_IS_OK(nt_status)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to start spnego"); talloc_free(tmp_ctx); return ISC_FALSE; } nt_status = gensec_update(gensec_ctx, tmp_ctx, state->ev_ctx, ap_req, &ap_req); if (!NT_STATUS_IS_OK(nt_status)) { state->log(ISC_LOG_ERROR, "samba_dlz: spnego update failed"); talloc_free(tmp_ctx); return ISC_FALSE; } nt_status = gensec_session_info(gensec_ctx, tmp_ctx, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to create session info"); talloc_free(tmp_ctx); return ISC_FALSE; } /* Get the DN from name */ result = b9_find_name_dn(state, name, tmp_ctx, &dn); if (result != ISC_R_SUCCESS) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to find name %s", name); talloc_free(tmp_ctx); return ISC_FALSE; } /* make sure the dn exists, or find parent dn in case new object is being added */ ldb_ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); if (ldb_ret == LDB_ERR_NO_SUCH_OBJECT) { ldb_dn_remove_child_components(dn, 1); access_mask = SEC_ADS_CREATE_CHILD; talloc_free(res); } else if (ldb_ret == LDB_SUCCESS) { access_mask = SEC_STD_REQUIRED | SEC_ADS_SELF_WRITE; talloc_free(res); } else { talloc_free(tmp_ctx); return ISC_FALSE; } /* Do ACL check */ ldb_ret = dsdb_check_access_on_dn(state->samdb, tmp_ctx, dn, session_info->security_token, access_mask, NULL); if (ldb_ret != LDB_SUCCESS) { state->log(ISC_LOG_INFO, "samba_dlz: disallowing update of signer=%s name=%s type=%s error=%s", signer, name, type, ldb_strerror(ldb_ret)); talloc_free(tmp_ctx); return ISC_FALSE; } /* Cache session_info, so it can be used in the actual add/delete operation */ state->update_name = talloc_strdup(state, name); if (state->update_name == NULL) { state->log(ISC_LOG_ERROR, "samba_dlz: memory allocation error"); talloc_free(tmp_ctx); return ISC_FALSE; } state->session_info = talloc_steal(state, session_info); state->log(ISC_LOG_INFO, "samba_dlz: allowing update of signer=%s name=%s tcpaddr=%s type=%s key=%s", signer, name, tcpaddr, type, key); talloc_free(tmp_ctx); return ISC_TRUE; }
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; }
krb5_error_code kpasswd_handle_request(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, struct gensec_security *gensec_security, uint16_t verno, DATA_BLOB *decoded_data, DATA_BLOB *kpasswd_reply, const char **error_string) { struct auth_session_info *session_info; NTSTATUS status; status = gensec_session_info(gensec_security, mem_ctx, &session_info); if (!NT_STATUS_IS_OK(status)) { *error_string = talloc_asprintf(mem_ctx, "gensec_session_info failed - " "%s", nt_errstr(status)); return KRB5_KPASSWD_HARDERROR; } switch(verno) { case 1: { DATA_BLOB password; bool ok; ok = convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(kdc->task->lp_ctx), CH_UTF8, CH_UTF16, (const char *)decoded_data->data, decoded_data->length, (void **)&password.data, &password.length); if (!ok) { *error_string = "String conversion failed!"; DBG_WARNING("%s\n", *error_string); return KRB5_KPASSWD_HARDERROR; } return kpasswd_change_password(kdc, mem_ctx, session_info, &password, kpasswd_reply, error_string); } case RFC3244_VERSION: { return kpasswd_set_password(kdc, mem_ctx, session_info, decoded_data, kpasswd_reply, error_string); } default: return KRB5_KPASSWD_BAD_VERSION; } return 0; }