/* * Hook to allow handling of NTLM authentication for AD operation * without directly linking the s4 auth stack * * This ensures we use the source4 authentication stack, as well as * the authorization stack to create the user's token. This ensures * consistency between NTLM logins and NTLMSSP logins, as NTLMSSP is * handled by the hook above. */ static NTSTATUS make_auth4_context_s4(TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct imessaging_context *msg_ctx; struct server_id *server_id; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(frame); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_id = new_server_id_task(frame); if (server_id == NULL) { DEBUG(1, ("new_server_id_task failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_init(frame, lp_ctx, *server_id, event_ctx, true); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } talloc_reparent(frame, msg_ctx, server_id); status = auth_context_create(mem_ctx, event_ctx, msg_ctx, lp_ctx, auth4_context); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, *auth4_context, msg_ctx); talloc_reparent(frame, *auth4_context, event_ctx); talloc_reparent(frame, *auth4_context, lp_ctx); TALLOC_FREE(frame); return status; }
struct imessaging_context *winbind_imessaging_context(void) { static struct imessaging_context *msg = NULL; struct loadparm_context *lp_ctx; if (msg != NULL) { return msg; } lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers()); if (lp_ctx == NULL) { smb_panic("Could not load smb.conf to init winbindd's imessaging context.\n"); } /* * Note we MUST use the NULL context here, not the autofree context, * to avoid side effects in forked children exiting. */ msg = imessaging_init(NULL, lp_ctx, procid_self(), winbind_event_context(), false); talloc_unlink(NULL, lp_ctx); if (msg == NULL) { smb_panic("Could not init winbindd's messaging context.\n"); } return msg; }
/* setup messaging for the top level samba (parent) task */ static NTSTATUS setup_parent_messaging(struct tevent_context *event_ctx, struct loadparm_context *lp_ctx) { struct imessaging_context *msg; NTSTATUS status; msg = imessaging_init(talloc_autofree_context(), lpcfg_imessaging_path(event_ctx, lp_ctx), cluster_id(0, SAMBA_PARENT_TASKID), event_ctx, false); NT_STATUS_HAVE_NO_MEMORY(msg); irpc_add_name(msg, "samba"); status = IRPC_REGISTER(msg, irpc, SAMBA_TERMINATE, samba_terminate, NULL); return status; }
/* called when a new socket connection has been established. This is called in the process context of the new process (if appropriate) */ static void stream_new_connection(struct tevent_context *ev, struct loadparm_context *lp_ctx, struct socket_context *sock, struct server_id server_id, void *private_data) { struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket); struct stream_connection *srv_conn; srv_conn = talloc_zero(ev, struct stream_connection); if (!srv_conn) { DEBUG(0,("talloc(mem_ctx, struct stream_connection) failed\n")); return; } talloc_steal(srv_conn, sock); srv_conn->private_data = stream_socket->private_data; srv_conn->model_ops = stream_socket->model_ops; srv_conn->socket = sock; srv_conn->server_id = server_id; srv_conn->ops = stream_socket->ops; srv_conn->event.ctx = ev; srv_conn->lp_ctx = lp_ctx; if (!socket_check_access(sock, "smbd", lpcfg_hostsallow(NULL, lpcfg_default_service(lp_ctx)), lpcfg_hostsdeny(NULL, lpcfg_default_service(lp_ctx)))) { stream_terminate_connection(srv_conn, "denied by access rules"); return; } srv_conn->event.fde = tevent_add_fd(ev, srv_conn, socket_get_fd(sock), 0, stream_io_handler_fde, srv_conn); if (!srv_conn->event.fde) { stream_terminate_connection(srv_conn, "tevent_add_fd() failed"); return; } /* setup to receive internal messages on this connection */ srv_conn->msg_ctx = imessaging_init(srv_conn, lpcfg_imessaging_path(srv_conn, lp_ctx), srv_conn->server_id, ev, false); if (!srv_conn->msg_ctx) { stream_terminate_connection(srv_conn, "imessaging_init() failed"); return; } srv_conn->remote_address = socket_get_remote_addr(srv_conn->socket, srv_conn); if (!srv_conn->remote_address) { stream_terminate_connection(srv_conn, "socket_get_remote_addr() failed"); return; } srv_conn->local_address = socket_get_local_addr(srv_conn->socket, srv_conn); if (!srv_conn->local_address) { stream_terminate_connection(srv_conn, "socket_get_local_addr() failed"); return; } { TALLOC_CTX *tmp_ctx; const char *title; tmp_ctx = talloc_new(srv_conn); title = talloc_asprintf(tmp_ctx, "conn[%s] c[%s] s[%s] server_id[%s]", stream_socket->ops->name, tsocket_address_string(srv_conn->remote_address, tmp_ctx), tsocket_address_string(srv_conn->local_address, tmp_ctx), server_id_str(tmp_ctx, &server_id)); if (title) { stream_connection_set_title(srv_conn, title); } talloc_free(tmp_ctx); } /* we're now ready to start receiving events on this stream */ TEVENT_FD_READABLE(srv_conn->event.fde); /* call the server specific accept code */ stream_socket->ops->accept_connection(srv_conn); }
/* * Hook to allow handling of NTLM authentication for AD operation * without directly linking the s4 auth stack * * This ensures we use the source4 authentication stack, as well as * the authorization stack to create the user's token. This ensures * consistency between NTLM logins and NTLMSSP logins, as NTLMSSP is * handled by the hook above. */ static NTSTATUS make_auth4_context_s4(const struct auth_context *auth_context, TALLOC_CTX *mem_ctx, struct auth4_context **auth4_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct imessaging_context *msg_ctx; struct server_id *server_id; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(frame); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_id = new_server_id_task(frame); if (server_id == NULL) { DEBUG(1, ("new_server_id_task failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_init(frame, lp_ctx, *server_id, event_ctx, true); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } talloc_reparent(frame, msg_ctx, server_id); /* Allow forcing a specific auth4 module */ if (!auth_context->forced_samba4_methods) { status = auth_context_create(mem_ctx, event_ctx, msg_ctx, lp_ctx, auth4_context); } else { const char * const *forced_auth_methods = (const char * const *)str_list_make(mem_ctx, auth_context->forced_samba4_methods, NULL); status = auth_context_create_methods(mem_ctx, forced_auth_methods, event_ctx, msg_ctx, lp_ctx, NULL, auth4_context); } if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, *auth4_context, msg_ctx); talloc_reparent(frame, *auth4_context, event_ctx); talloc_reparent(frame, *auth4_context, lp_ctx); TALLOC_FREE(frame); return status; }
/* * Hook to allow the source4 set of GENSEC modules to handle * blob-based authentication mechanisms, without directly linking the * mechanism code. * * This may eventually go away, when the GSSAPI acceptors are merged, * when we will just rely on the make_auth4_context_s4 hook instead. * * Even for NTLMSSP, which has a common module, significant parts of * the behaviour are overridden here, because it uses the source4 NTLM * stack and the source4 mapping between the PAC/SamLogon response and * the local token. * * It is important to override all this to ensure that the exact same * token is generated and used in the SMB and LDAP servers, for NTLM * and for Kerberos. */ static NTSTATUS prepare_gensec(const struct auth_context *auth_context, TALLOC_CTX *mem_ctx, struct gensec_security **gensec_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct gensec_security *gensec_ctx; struct imessaging_context *msg_ctx; struct cli_credentials *server_credentials; struct server_id *server_id; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(frame); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_id = new_server_id_task(frame); if (server_id == NULL) { DEBUG(1, ("new_server_id_task failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_init(frame, lp_ctx, *server_id, event_ctx, true); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } talloc_reparent(frame, msg_ctx, server_id); server_credentials = cli_credentials_init(frame); if (!server_credentials) { DEBUG(1, ("Failed to init server credentials")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } cli_credentials_set_conf(server_credentials, lp_ctx); status = cli_credentials_set_machine_account(server_credentials, lp_ctx); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } status = samba_server_gensec_start(mem_ctx, event_ctx, msg_ctx, lp_ctx, server_credentials, "cifs", &gensec_ctx); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, gensec_ctx, msg_ctx); talloc_reparent(frame, gensec_ctx, event_ctx); talloc_reparent(frame, gensec_ctx, lp_ctx); talloc_reparent(frame, gensec_ctx, server_credentials); gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY); gensec_want_feature(gensec_ctx, GENSEC_FEATURE_UNIX_TOKEN); *gensec_context = gensec_ctx; TALLOC_FREE(frame); return status; }
/* test ping speed */ static bool test_ping_speed(struct torture_context *tctx) { struct tevent_context *ev; struct imessaging_context *msg_client_ctx; struct imessaging_context *msg_server_ctx; int ping_count = 0; int pong_count = 0; struct timeval tv; int timelimit = torture_setting_int(tctx, "timelimit", 10); uint32_t msg_ping, msg_exit; lpcfg_set_cmdline(tctx->lp_ctx, "pid directory", "piddir.tmp"); ev = tctx->ev; msg_server_ctx = imessaging_init(tctx, tctx->lp_ctx, cluster_id(0, 1), ev, true); torture_assert(tctx, msg_server_ctx != NULL, "Failed to init ping messaging context"); imessaging_register_tmp(msg_server_ctx, NULL, ping_message, &msg_ping); imessaging_register_tmp(msg_server_ctx, tctx, exit_message, &msg_exit); msg_client_ctx = imessaging_init(tctx, tctx->lp_ctx, cluster_id(0, 2), ev, true); torture_assert(tctx, msg_client_ctx != NULL, "msg_client_ctx imessaging_init() failed"); imessaging_register_tmp(msg_client_ctx, &pong_count, pong_message, &msg_pong); tv = timeval_current(); torture_comment(tctx, "Sending pings for %d seconds\n", timelimit); while (timeval_elapsed(&tv) < timelimit) { DATA_BLOB data; NTSTATUS status1, status2; data.data = discard_const_p(uint8_t, "testing"); data.length = strlen((const char *)data.data); status1 = imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_ping, &data); status2 = imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_ping, NULL); torture_assert_ntstatus_ok(tctx, status1, "msg1 failed"); ping_count++; torture_assert_ntstatus_ok(tctx, status2, "msg2 failed"); ping_count++; while (ping_count > pong_count + 20) { tevent_loop_once(ev); } } torture_comment(tctx, "waiting for %d remaining replies (done %d)\n", ping_count - pong_count, pong_count); while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) { tevent_loop_once(ev); } torture_comment(tctx, "sending exit\n"); imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_exit, NULL); torture_assert_int_equal(tctx, ping_count, pong_count, "ping test failed"); torture_comment(tctx, "ping rate of %.0f messages/sec\n", (ping_count+pong_count)/timeval_elapsed(&tv)); talloc_free(msg_client_ctx); talloc_free(msg_server_ctx); return true; }
static bool test_messaging_overflow(struct torture_context *tctx) { struct imessaging_context *msg_ctx; ssize_t nwritten, nread; pid_t child; char c = 0; int up_pipe[2], down_pipe[2]; int i, ret, child_status; ret = pipe(up_pipe); torture_assert(tctx, ret == 0, "pipe failed"); ret = pipe(down_pipe); torture_assert(tctx, ret == 0, "pipe failed"); child = fork(); if (child < 0) { torture_fail(tctx, "fork failed"); } if (child == 0) { ret = tevent_re_initialise(tctx->ev); torture_assert(tctx, ret == 0, "tevent_re_initialise failed"); msg_ctx = imessaging_init(tctx, tctx->lp_ctx, cluster_id(getpid(), 0), tctx->ev); torture_assert(tctx, msg_ctx != NULL, "imessaging_init failed"); do { nwritten = write(up_pipe[1], &c, 1); } while ((nwritten == -1) && (errno == EINTR)); ret = close(down_pipe[1]); torture_assert(tctx, ret == 0, "close failed"); do { nread = read(down_pipe[0], &c, 1); } while ((nread == -1) && (errno == EINTR)); exit(0); } do { nread = read(up_pipe[0], &c, 1); } while ((nread == -1) && (errno == EINTR)); msg_ctx = imessaging_init(tctx, tctx->lp_ctx, cluster_id(getpid(), 0), tctx->ev); torture_assert(tctx, msg_ctx != NULL, "imessaging_init failed"); for (i=0; i<1000; i++) { NTSTATUS status; status = imessaging_send(msg_ctx, cluster_id(child, 0), MSG_PING, NULL); torture_assert_ntstatus_ok(tctx, status, "imessaging_send failed"); } tevent_loop_once(tctx->ev); talloc_free(msg_ctx); ret = close(down_pipe[1]); torture_assert(tctx, ret == 0, "close failed"); ret = waitpid(child, &child_status, 0); torture_assert(tctx, ret == child, "wrong child exited"); torture_assert(tctx, child_status == 0, "child failed"); poll(NULL, 0, 500); return true; }