1 /* 2 * SPDX-License-Identifier: ISC 3 * 4 * Copyright (c) 2013-2015, 2017 Todd C. Miller <Todd.Miller@sudo.ws> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #ifndef SUDO_EVENT_H 20 #define SUDO_EVENT_H 21 22 #include <time.h> /* for struct timespec */ 23 #include <signal.h> /* for sigatomic_t and NSIG */ 24 #include "sudo_queue.h" 25 26 struct timeval; /* for deprecated APIs */ 27 28 /* Event types (keep in sync with sudo_plugin.h) */ 29 #define SUDO_EV_TIMEOUT 0x01 /* fire after timeout */ 30 #define SUDO_EV_READ 0x02 /* fire when readable */ 31 #define SUDO_EV_WRITE 0x04 /* fire when writable */ 32 #define SUDO_EV_PERSIST 0x08 /* persist until deleted */ 33 #define SUDO_EV_SIGNAL 0x10 /* fire on signal receipt */ 34 #define SUDO_EV_SIGINFO 0x20 /* fire on signal receipt (siginfo) */ 35 36 /* User-settable events for sudo_ev_init() (SUDO_EV_TIMEOUT not valid here) */ 37 #define SUDO_EV_MASK (SUDO_EV_READ|SUDO_EV_WRITE|SUDO_EV_PERSIST|SUDO_EV_SIGNAL|SUDO_EV_SIGINFO) 38 39 /* Event flags (internal) */ 40 #define SUDO_EVQ_INSERTED 0x01 /* event is on the event queue */ 41 #define SUDO_EVQ_ACTIVE 0x02 /* event is on the active queue */ 42 #define SUDO_EVQ_TIMEOUTS 0x04 /* event is on the timeouts queue */ 43 44 /* Event loop flags */ 45 #define SUDO_EVLOOP_ONCE 0x01 /* Only run once through the loop */ 46 #define SUDO_EVLOOP_NONBLOCK 0x02 /* Do not block in event loop */ 47 48 /* Event base flags (internal) */ 49 #define SUDO_EVBASE_LOOPONCE SUDO_EVLOOP_ONCE 50 #define SUDO_EVBASE_LOOPEXIT 0x02 51 #define SUDO_EVBASE_LOOPBREAK 0x04 52 #define SUDO_EVBASE_LOOPCONT 0x08 53 #define SUDO_EVBASE_GOT_EXIT 0x10 54 #define SUDO_EVBASE_GOT_BREAK 0x20 55 #define SUDO_EVBASE_GOT_MASK 0xf0 56 57 /* Must match sudo_plugin_ev_callback_t in sudo_plugin.h */ 58 typedef void (*sudo_ev_callback_t)(int fd, int what, void *closure); 59 60 /* 61 * Container for SUDO_EV_SIGINFO events that gets passed as the closure 62 * pointer. This allows us to pass a siginfo_t without changing everything. 63 */ 64 struct sudo_ev_siginfo_container { 65 void *closure; 66 siginfo_t *siginfo; 67 char si_buf[1]; 68 }; 69 70 /* Member of struct sudo_event_base. */ 71 struct sudo_event { 72 TAILQ_ENTRY(sudo_event) entries; 73 TAILQ_ENTRY(sudo_event) active_entries; 74 TAILQ_ENTRY(sudo_event) timeouts_entries; 75 struct sudo_event_base *base; /* base this event belongs to */ 76 int fd; /* fd/signal we are interested in */ 77 short events; /* SUDO_EV_* flags (in) */ 78 short revents; /* SUDO_EV_* flags (out) */ 79 short flags; /* internal event flags */ 80 short pfd_idx; /* index into pfds array (XXX) */ 81 sudo_ev_callback_t callback;/* user-provided callback */ 82 struct timespec timeout; /* for SUDO_EV_TIMEOUT */ 83 void *closure; /* user-provided data pointer */ 84 }; 85 TAILQ_HEAD(sudo_event_list, sudo_event); 86 87 struct sudo_event_base { 88 struct sudo_event_list events; /* tail queue of all events */ 89 struct sudo_event_list active; /* tail queue of active events */ 90 struct sudo_event_list timeouts; /* tail queue of timeout events */ 91 struct sudo_event signal_event; /* storage for signal pipe event */ 92 struct sudo_event_list signals[NSIG]; /* array of signal event tail queues */ 93 struct sigaction *orig_handlers[NSIG]; /* original signal handlers */ 94 siginfo_t *siginfo[NSIG]; /* detailed signal info */ 95 sig_atomic_t signal_pending[NSIG]; /* pending signals */ 96 sig_atomic_t signal_caught; /* at least one signal caught */ 97 int num_handlers; /* number of installed handlers */ 98 int signal_pipe[2]; /* so we can wake up on signal */ 99 #if defined(HAVE_POLL) || defined(HAVE_PPOLL) 100 struct pollfd *pfds; /* array of struct pollfd */ 101 int pfd_max; /* size of the pfds array */ 102 int pfd_high; /* highest slot used */ 103 int pfd_free; /* idx of next free entry or pfd_max if full */ 104 #else 105 fd_set *readfds_in; /* read I/O descriptor set (in) */ 106 fd_set *writefds_in; /* write I/O descriptor set (in) */ 107 fd_set *readfds_out; /* read I/O descriptor set (out) */ 108 fd_set *writefds_out; /* write I/O descriptor set (out) */ 109 int maxfd; /* max fd we can store in readfds/writefds */ 110 int highfd; /* highest fd to pass as 1st arg to select */ 111 #endif /* HAVE_POLL */ 112 unsigned int flags; /* SUDO_EVBASE_* */ 113 }; 114 115 /* Allocate a new event base. */ 116 sudo_dso_public struct sudo_event_base *sudo_ev_base_alloc_v1(void); 117 #define sudo_ev_base_alloc() sudo_ev_base_alloc_v1() 118 119 /* Free an event base. */ 120 sudo_dso_public void sudo_ev_base_free_v1(struct sudo_event_base *base); 121 #define sudo_ev_base_free(_a) sudo_ev_base_free_v1((_a)) 122 123 /* Set the default event base. */ 124 sudo_dso_public void sudo_ev_base_setdef_v1(struct sudo_event_base *base); 125 #define sudo_ev_base_setdef(_a) sudo_ev_base_setdef_v1((_a)) 126 127 /* Allocate a new event. */ 128 sudo_dso_public struct sudo_event *sudo_ev_alloc_v1(int fd, short events, sudo_ev_callback_t callback, void *closure); 129 #define sudo_ev_alloc(_a, _b, _c, _d) sudo_ev_alloc_v1((_a), (_b), (_c), (_d)) 130 131 /* Free an event. */ 132 sudo_dso_public void sudo_ev_free_v1(struct sudo_event *ev); 133 #define sudo_ev_free(_a) sudo_ev_free_v1((_a)) 134 135 /* Set an event struct that was pre-allocated. */ 136 sudo_dso_public int sudo_ev_set_v1(struct sudo_event *ev, int fd, short events, sudo_ev_callback_t callback, void *closure); 137 #define sudo_ev_set(_a, _b, _c, _d, _e) sudo_ev_set_v1((_a), (_b), (_c), (_d), (_e)) 138 139 /* Add an event, returns 0 on success, -1 on error */ 140 sudo_dso_public int sudo_ev_add_v1(struct sudo_event_base *head, struct sudo_event *ev, const struct timeval *timo, bool tohead); 141 sudo_dso_public int sudo_ev_add_v2(struct sudo_event_base *head, struct sudo_event *ev, const struct timespec *timo, bool tohead); 142 #define sudo_ev_add(_a, _b, _c, _d) sudo_ev_add_v2((_a), (_b), (_c), (_d)) 143 144 /* Delete an event, returns 0 on success, -1 on error */ 145 sudo_dso_public int sudo_ev_del_v1(struct sudo_event_base *head, struct sudo_event *ev); 146 #define sudo_ev_del(_a, _b) sudo_ev_del_v1((_a), (_b)) 147 148 /* Dispatch events, returns SUDO_CB_SUCCESS, SUDO_CB_BREAK or SUDO_CB_ERROR */ 149 sudo_dso_public int sudo_ev_dispatch_v1(struct sudo_event_base *head); 150 #define sudo_ev_dispatch(_a) sudo_ev_dispatch_v1((_a)) 151 152 /* Main event loop, returns SUDO_CB_SUCCESS, SUDO_CB_BREAK or SUDO_CB_ERROR */ 153 sudo_dso_public int sudo_ev_loop_v1(struct sudo_event_base *head, int flags); 154 #define sudo_ev_loop(_a, _b) sudo_ev_loop_v1((_a), (_b)) 155 156 /* Return pending event types, fills in ts if non-NULL and there is a timeout */ 157 sudo_dso_public int sudo_ev_pending_v1(struct sudo_event *ev, short events, struct timespec *ts); 158 #define sudo_ev_pending(_a, _b, _c) sudo_ev_pending_v1((_a), (_b), (_c)) 159 160 /* Return the remaining timeout associated with an event (deprecated). */ 161 sudo_dso_public int sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timeval *tv); 162 sudo_dso_public int sudo_ev_get_timeleft_v2(struct sudo_event *ev, struct timespec *tv); 163 #define sudo_ev_get_timeleft(_a, _b) sudo_ev_get_timeleft_v2((_a), (_b)) 164 165 /* Cause the event loop to exit after one run through. */ 166 sudo_dso_public void sudo_ev_loopexit_v1(struct sudo_event_base *base); 167 #define sudo_ev_loopexit(_a) sudo_ev_loopexit_v1((_a)) 168 169 /* Break out of the event loop right now. */ 170 sudo_dso_public void sudo_ev_loopbreak_v1(struct sudo_event_base *base); 171 #define sudo_ev_loopbreak(_a) sudo_ev_loopbreak_v1((_a)) 172 173 /* Rescan for events and restart the event loop. */ 174 sudo_dso_public void sudo_ev_loopcontinue_v1(struct sudo_event_base *base); 175 #define sudo_ev_loopcontinue(_a) sudo_ev_loopcontinue_v1((_a)) 176 177 /* Returns true if event loop stopped due to sudo_ev_loopexit(). */ 178 sudo_dso_public bool sudo_ev_got_exit_v1(struct sudo_event_base *base); 179 #define sudo_ev_got_exit(_a) sudo_ev_got_exit_v1((_a)) 180 181 /* Returns true if event loop stopped due to sudo_ev_loopbreak(). */ 182 sudo_dso_public bool sudo_ev_got_break_v1(struct sudo_event_base *base); 183 #define sudo_ev_got_break(_a) sudo_ev_got_break_v1((_a)) 184 185 /* Return the fd associated with an event. */ 186 #define sudo_ev_get_fd(_ev) ((_ev) ? (_ev)->fd : -1) 187 188 /* Return the (absolute) timeout associated with an event or NULL. */ 189 #define sudo_ev_get_timeout(_ev) \ 190 (ISSET((_ev)->flags, SUDO_EVQ_TIMEOUTS) ? &(_ev)->timeout : NULL) 191 192 /* Return the base an event is associated with or NULL. */ 193 #define sudo_ev_get_base(_ev) ((_ev) ? (_ev)->base : NULL) 194 195 /* Magic pointer value to use self pointer as callback arg. */ 196 #define sudo_ev_self_cbarg() ((void *)-1) 197 198 /* Add an event to the base's active queue and mark it active (internal). */ 199 void sudo_ev_activate(struct sudo_event_base *base, struct sudo_event *ev); 200 201 /* 202 * Backend implementation. 203 */ 204 int sudo_ev_base_alloc_impl(struct sudo_event_base *base); 205 void sudo_ev_base_free_impl(struct sudo_event_base *base); 206 int sudo_ev_add_impl(struct sudo_event_base *base, struct sudo_event *ev); 207 int sudo_ev_del_impl(struct sudo_event_base *base, struct sudo_event *ev); 208 int sudo_ev_scan_impl(struct sudo_event_base *base, int flags); 209 210 #endif /* SUDO_EVENT_H */ 211