diff options
-rw-r--r-- | include/intercept.pb-c.h | 4 | ||||
-rw-r--r-- | include/sudo_event.h | 3 | ||||
-rw-r--r-- | src/exec_intercept.c | 89 | ||||
-rw-r--r-- | src/exec_intercept.h | 1 | ||||
-rw-r--r-- | src/intercept.pb-c.c | 19 | ||||
-rw-r--r-- | src/intercept.proto | 2 | ||||
-rw-r--r-- | src/sudo_intercept_common.c | 18 |
7 files changed, 97 insertions, 39 deletions
diff --git a/include/intercept.pb-c.h b/include/intercept.pb-c.h index 9d6390b8b..2ea168329 100644 --- a/include/intercept.pb-c.h +++ b/include/intercept.pb-c.h @@ -72,6 +72,7 @@ struct InterceptHello /* * Sudo response to an InterceptHello from sudo_intercept.so. * The client uses the port number and token to connect back to sudo. + * If log_only is set there is no InterceptResponse to a PolicyCheckRequest. */ struct HelloResponse { @@ -79,10 +80,11 @@ struct HelloResponse uint64_t token_lo; uint64_t token_hi; int32_t portno; + protobuf_c_boolean log_only; }; #define HELLO_RESPONSE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&hello_response__descriptor) \ - , 0, 0, 0 } + , 0, 0, 0, 0 } /* diff --git a/include/sudo_event.h b/include/sudo_event.h index 12bb89478..67dfb20bd 100644 --- a/include/sudo_event.h +++ b/include/sudo_event.h @@ -192,6 +192,9 @@ sudo_dso_public bool sudo_ev_got_break_v1(struct sudo_event_base *base); /* Return the base an event is associated with or NULL. */ #define sudo_ev_get_base(_ev) ((_ev) ? (_ev)->base : NULL) +/* Set the base an event is associated with. */ +#define sudo_ev_set_base(_ev, _b) ((_ev)->base = (_b)) + /* Magic pointer value to use self pointer as callback arg. */ #define sudo_ev_self_cbarg() ((void *)-1) diff --git a/src/exec_intercept.c b/src/exec_intercept.c index 9d630ea00..741773ba5 100644 --- a/src/exec_intercept.c +++ b/src/exec_intercept.c @@ -54,6 +54,44 @@ static void intercept_accept_cb(int fd, int what, void *v); static void intercept_cb(int fd, int what, void *v); /* + * Enable the closure->ev event with the specified events and callback, + * and set the connection state to new_state if it is valid. + * Returns true on success, else false. + */ +static bool +intercept_enable_event(int fd, short events, enum intercept_state new_state, + sudo_ev_callback_t callback, struct intercept_closure *closure) +{ + int rc; + debug_decl(intercept_enable_event, SUDO_DEBUG_EXEC); + + rc = sudo_ev_set(&closure->ev, fd, events, callback, closure); + if (rc == -1 || sudo_ev_add(NULL, &closure->ev, NULL, false) == -1) { + sudo_warn("%s", U_("unable to add event to queue")); + debug_return_bool(false); + } + if (new_state != INVALID_STATE) + closure->state = new_state; + debug_return_bool(true); +} + +static bool +enable_read_event(int fd, enum intercept_state new_state, + sudo_ev_callback_t callback, struct intercept_closure *closure) +{ + return intercept_enable_event(fd, SUDO_EV_READ|SUDO_EV_PERSIST, + new_state, callback, closure); +} + +static bool +enable_write_event(int fd, sudo_ev_callback_t callback, + struct intercept_closure *closure) +{ + return intercept_enable_event(fd, SUDO_EV_WRITE|SUDO_EV_PERSIST, + INVALID_STATE, callback, closure); +} + +/* * Create an intercept closure. * Returns an opaque pointer to the closure, which is also * passed to the event callback when not using ptrace(2). @@ -63,7 +101,6 @@ intercept_setup(int fd, struct sudo_event_base *evbase, struct command_details *details) { struct intercept_closure *closure; - int rc; debug_decl(intercept_setup, SUDO_DEBUG_EXEC); sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, @@ -76,6 +113,7 @@ intercept_setup(int fd, struct sudo_event_base *evbase, } closure->details = details; closure->listen_sock = -1; + sudo_ev_set_base(&closure->ev, evbase); if (ISSET(details->flags, CD_USE_PTRACE)) { /* @@ -92,15 +130,10 @@ intercept_setup(int fd, struct sudo_event_base *evbase, * Not using ptrace(2), use LD_PRELOAD (or its equivalent). If * we've already seen an InterceptHello, expect a policy check first. */ - closure->state = sudo_token_isset(intercept_token) ? + const int new_state = sudo_token_isset(intercept_token) ? RECV_SECRET : RECV_HELLO_INITIAL; - - rc = sudo_ev_set(&closure->ev, fd, SUDO_EV_READ|SUDO_EV_PERSIST, - intercept_cb, closure); - if (rc == -1 || sudo_ev_add(evbase, &closure->ev, NULL, false) == -1) { - sudo_warn("%s", U_("unable to add event to queue")); + if (!enable_read_event(fd, new_state, intercept_cb, closure)) goto bad; - } } debug_return_ptr(closure); @@ -546,11 +579,9 @@ intercept_verify_token(int fd, struct intercept_closure *closure) static bool intercept_read(int fd, struct intercept_closure *closure) { - struct sudo_event_base *evbase = sudo_ev_get_base(&closure->ev); InterceptRequest *req = NULL; bool ret = false; ssize_t nread; - int rc; debug_decl(intercept_read, SUDO_DEBUG_EXEC); if (closure->state == RECV_SECRET) { @@ -644,7 +675,7 @@ unpack: sudo_debug_printf(SUDO_DEBUG_INFO, "%s: finished receiving %u bytes from client", __func__, closure->len); - sudo_ev_del(evbase, &closure->ev); + sudo_ev_del(NULL, &closure->ev); free(closure->buf); closure->buf = NULL; closure->len = 0; @@ -663,6 +694,11 @@ unpack: ret = intercept_check_policy_req(req->u.policy_check_req, closure); if (!ret) goto done; + if (!ISSET(closure->details->flags, CD_INTERCEPT)) { + /* Just logging, re-use event to read next InterceptHello. */ + ret = enable_read_event(fd, RECV_HELLO, intercept_cb, closure); + goto done; + } break; case INTERCEPT_REQUEST__TYPE_HELLO: switch (closure->state) { @@ -686,12 +722,8 @@ unpack: } /* Switch event to write mode for the reply. */ - rc = sudo_ev_set(&closure->ev, fd, SUDO_EV_WRITE|SUDO_EV_PERSIST, - intercept_cb, closure); - if (rc == -1 || sudo_ev_add(evbase, &closure->ev, NULL, false) == -1) { - sudo_warn("%s", U_("unable to add event to queue")); + if (!enable_write_event(fd, intercept_cb, closure)) goto done; - } ret = true; @@ -744,6 +776,7 @@ fmt_hello_response(struct intercept_closure *closure) hello_resp.portno = intercept_listen_port; hello_resp.token_lo = intercept_token.u64[0]; hello_resp.token_hi = intercept_token.u64[1]; + hello_resp.log_only = !ISSET(closure->details->flags, CD_INTERCEPT); resp.u.hello_resp = &hello_resp; resp.type_case = INTERCEPT_RESPONSE__TYPE_HELLO_RESP; @@ -811,10 +844,8 @@ fmt_error_message(struct intercept_closure *closure) static bool intercept_write(int fd, struct intercept_closure *closure) { - struct sudo_event_base *evbase = sudo_ev_get_base(&closure->ev); bool ret = false; ssize_t nwritten; - int rc; debug_decl(intercept_write, SUDO_DEBUG_EXEC); sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, "state %d", @@ -864,9 +895,9 @@ intercept_write(int fd, struct intercept_closure *closure) debug_return_bool(true); } - sudo_debug_printf(SUDO_DEBUG_INFO, "%s: sent %u bytes to client", - __func__, closure->len); - sudo_ev_del(evbase, &closure->ev); + sudo_debug_printf(SUDO_DEBUG_INFO, + "%s: sent %u bytes to client", __func__, closure->len); + sudo_ev_del(NULL, &closure->ev); free(closure->buf); closure->buf = NULL; closure->len = 0; @@ -874,27 +905,19 @@ intercept_write(int fd, struct intercept_closure *closure) switch (closure->state) { case RECV_HELLO_INITIAL: - /* Re-use event for the listener. */ + /* Re-use the listener event. */ close(fd); - rc = sudo_ev_set(&closure->ev, closure->listen_sock, - SUDO_EV_READ|SUDO_EV_PERSIST, intercept_accept_cb, closure); - if (rc == -1 || sudo_ev_add(evbase, &closure->ev, NULL, false) == -1) { - sudo_warn("%s", U_("unable to add event to queue")); + if (!enable_read_event(closure->listen_sock, RECV_CONNECTION, + intercept_accept_cb, closure)) goto done; - } closure->listen_sock = -1; closure->state = RECV_CONNECTION; accept_closure = closure; break; case POLICY_ACCEPT: /* Re-use event to read InterceptHello from sudo_intercept.so ctor. */ - rc = sudo_ev_set(&closure->ev, fd, SUDO_EV_READ|SUDO_EV_PERSIST, - intercept_cb, closure); - if (rc == -1 || sudo_ev_add(evbase, &closure->ev, NULL, false) == -1) { - sudo_warn("%s", U_("unable to add event to queue")); + if (!enable_read_event(fd, RECV_HELLO, intercept_cb, closure)) goto done; - } - closure->state = RECV_HELLO; break; default: /* Done with this connection. */ diff --git a/src/exec_intercept.h b/src/exec_intercept.h index e9d3a6ac3..baf429bb6 100644 --- a/src/exec_intercept.h +++ b/src/exec_intercept.h @@ -20,6 +20,7 @@ #define SUDO_EXEC_INTERCEPT_H enum intercept_state { + INVALID_STATE, RECV_HELLO_INITIAL, RECV_HELLO, RECV_SECRET, diff --git a/src/intercept.pb-c.c b/src/intercept.pb-c.c index e4e44c9b6..36d11eeb8 100644 --- a/src/intercept.pb-c.c +++ b/src/intercept.pb-c.c @@ -456,7 +456,7 @@ const ProtobufCMessageDescriptor intercept_hello__descriptor = (ProtobufCMessageInit) intercept_hello__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor hello_response__field_descriptors[3] = +static const ProtobufCFieldDescriptor hello_response__field_descriptors[4] = { { "token_lo", @@ -494,8 +494,21 @@ static const ProtobufCFieldDescriptor hello_response__field_descriptors[3] = 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, + { + "log_only", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(HelloResponse, log_only), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, }; static const unsigned hello_response__field_indices_by_name[] = { + 3, /* field[3] = log_only */ 2, /* field[2] = portno */ 1, /* field[1] = token_hi */ 0, /* field[0] = token_lo */ @@ -503,7 +516,7 @@ static const unsigned hello_response__field_indices_by_name[] = { static const ProtobufCIntRange hello_response__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 3 } + { 0, 4 } }; const ProtobufCMessageDescriptor hello_response__descriptor = { @@ -513,7 +526,7 @@ const ProtobufCMessageDescriptor hello_response__descriptor = "HelloResponse", "", sizeof(HelloResponse), - 3, + 4, hello_response__field_descriptors, hello_response__field_indices_by_name, 1, hello_response__number_ranges, diff --git a/src/intercept.proto b/src/intercept.proto index 786ae7bba..53a068a19 100644 --- a/src/intercept.proto +++ b/src/intercept.proto @@ -22,11 +22,13 @@ message InterceptHello { /* * Sudo response to an InterceptHello from sudo_intercept.so. * The client uses the port number and token to connect back to sudo. + * If log_only is set there is no InterceptResponse to a PolicyCheckRequest. */ message HelloResponse { fixed64 token_lo = 1; fixed64 token_hi = 2; int32 portno = 3; + bool log_only = 4; } /* diff --git a/src/sudo_intercept_common.c b/src/sudo_intercept_common.c index 9558c0530..5c5844243 100644 --- a/src/sudo_intercept_common.c +++ b/src/sudo_intercept_common.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2021 Todd C. Miller <Todd.Miller@sudo.ws> + * Copyright (c) 2021-2022 Todd C. Miller <Todd.Miller@sudo.ws> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -61,6 +61,7 @@ extern char **environ; static union sudo_token_un intercept_token; static in_port_t intercept_port; +static bool log_only; /* Send entire request to sudo (blocking). */ static bool @@ -273,6 +274,7 @@ sudo_interposer_init(void) intercept_token.u64[0] = res->u.hello_resp->token_lo; intercept_token.u64[1] = res->u.hello_resp->token_hi; intercept_port = res->u.hello_resp->portno; + log_only = res->u.hello_resp->log_only; } else { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "unexpected type_case value %d in %s from %s", @@ -420,6 +422,18 @@ command_allowed(const char *cmnd, char * const argv[], if (!send_policy_check_req(sock, cmnd, argv, envp)) goto done; + if (log_only) { + /* Just logging, no policy check. */ + nenvp = sudo_preload_dso(envp, sudo_conf_intercept_path(), sock); + if (nenvp == NULL) + goto oom; + *ncmndp = (char *)cmnd; /* safe */ + *nargvp = (char **)argv; /* safe */ + *nenvpp = nenvp; + ret = true; + goto done; + } + res = recv_intercept_response(sock); if (res == NULL) goto done; @@ -467,7 +481,7 @@ command_allowed(const char *cmnd, char * const argv[], default: sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, "unexpected type_case value %d in %s from %s", - res->type_case, "InterceptResponse", "sudo"); + res->type_case, "InterceptResponse", "sudo"); goto done; } |