1  /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * This provides a clean way to interface lws user code to be able to
25  * work unchanged on different systems for fetching common system information,
26  * and performing common system operations like reboot.
27  */
28 
29 /*
30  * Types of system blob that can be set and retreived
31  */
32 
33 typedef enum {
34 	LWS_SYSBLOB_TYPE_AUTH,
35 	LWS_SYSBLOB_TYPE_CLIENT_CERT_DER = LWS_SYSBLOB_TYPE_AUTH + 2,
36 	LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
37 	LWS_SYSBLOB_TYPE_DEVICE_SERIAL,
38 	LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION,
39 	LWS_SYSBLOB_TYPE_DEVICE_TYPE,
40 	LWS_SYSBLOB_TYPE_NTP_SERVER,
41 	LWS_SYSBLOB_TYPE_MQTT_CLIENT_ID,
42 	LWS_SYSBLOB_TYPE_MQTT_USERNAME,
43 	LWS_SYSBLOB_TYPE_MQTT_PASSWORD,
44 
45 #if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
46 	/* extend 4 more auth blobs, each has 2 slots */
47 	LWS_SYSBLOB_TYPE_EXT_AUTH1,
48 	LWS_SYSBLOB_TYPE_EXT_AUTH2 = LWS_SYSBLOB_TYPE_EXT_AUTH1 + 2,
49 	LWS_SYSBLOB_TYPE_EXT_AUTH3 = LWS_SYSBLOB_TYPE_EXT_AUTH2 + 2,
50 	LWS_SYSBLOB_TYPE_EXT_AUTH4 = LWS_SYSBLOB_TYPE_EXT_AUTH3 + 2,
51 	LWS_SYSBLOB_TYPE_EXT_AUTH4_1,
52 #endif
53 
54 	LWS_SYSBLOB_TYPE_COUNT /* ... always last */
55 } lws_system_blob_item_t;
56 
57 /* opaque generic blob whose content may be on-the-heap or pointed-to
58  * directly case by case.  When it's on the heap, it can be produced by
59  * appending (it's a buflist underneath).  Either way, it can be consumed by
60  * copying out a given length from a given offset.
61  */
62 
63 typedef struct lws_system_blob lws_system_blob_t;
64 
65 LWS_EXTERN LWS_VISIBLE void
66 lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
67 
68 LWS_EXTERN LWS_VISIBLE void
69 lws_system_blob_heap_empty(lws_system_blob_t *b);
70 
71 LWS_EXTERN LWS_VISIBLE int
72 lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
73 
74 LWS_EXTERN LWS_VISIBLE size_t
75 lws_system_blob_get_size(lws_system_blob_t *b);
76 
77 /* return 0 and sets *ptr to point to blob data if possible, nonzero = fail */
78 LWS_EXTERN LWS_VISIBLE int
79 lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr);
80 
81 LWS_EXTERN LWS_VISIBLE int
82 lws_system_blob_get(lws_system_blob_t *b, uint8_t *ptr, size_t *len, size_t ofs);
83 
84 LWS_EXTERN LWS_VISIBLE void
85 lws_system_blob_destroy(lws_system_blob_t *b);
86 
87 /*
88  * Get the opaque blob for index idx of various system blobs.  Returns 0 if
89  * *b was set otherwise nonzero means out of range
90  */
91 
92 LWS_EXTERN LWS_VISIBLE lws_system_blob_t *
93 lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
94                     int idx);
95 
96 /*
97  * Lws view of system state... normal operation from user code perspective is
98  * dependent on implicit (eg, knowing the date for cert validation) and
99  * explicit dependencies.
100  *
101  * Bit of lws and user code can register notification handlers that can enforce
102  * dependent operations before state transitions can complete.
103  */
104 
105 typedef enum { /* keep system_state_names[] in sync in context.c */
106 	LWS_SYSTATE_UNKNOWN,
107 
108 	LWS_SYSTATE_CONTEXT_CREATED,	 /* context was just created */
109 	LWS_SYSTATE_INITIALIZED,	 /* protocols initialized.  Lws itself
110 					  * can operate normally */
111 	LWS_SYSTATE_IFACE_COLDPLUG,	 /* existing net ifaces iterated */
112 	LWS_SYSTATE_DHCP,		 /* at least one net iface configured */
113 	LWS_SYSTATE_CPD_PRE_TIME,	 /* Captive portal detect without valid
114 					  * time, good for non-https tests... if
115 					  * you care about it, implement and
116 					  * call lws_system_ops_t
117 					  * .captive_portal_detect_request()
118 					  * and move the state forward according
119 					  * to the result. */
120 	LWS_SYSTATE_TIME_VALID,		 /* ntpclient ran, or hw time valid...
121 					  * tls cannot work until we reach here
122 					  */
123 	LWS_SYSTATE_CPD_POST_TIME,	 /* Captive portal detect after time was
124 					  * time, good for https tests... if
125 					  * you care about it, implement and
126 					  * call lws_system_ops_t
127 					  * .captive_portal_detect_request()
128 					  * and move the state forward according
129 					  * to the result. */
130 
131 	LWS_SYSTATE_POLICY_VALID,	 /* user code knows how to operate... */
132 	LWS_SYSTATE_REGISTERED,		 /* device has an identity... */
133 	LWS_SYSTATE_AUTH1,		 /* identity used for main auth token */
134 	LWS_SYSTATE_AUTH2,		 /* identity used for optional auth */
135 
136 	LWS_SYSTATE_OPERATIONAL,	 /* user code can operate normally */
137 
138 	LWS_SYSTATE_POLICY_INVALID,	 /* user code is changing its policies
139 					  * drop everything done with old
140 					  * policy, switch to new then enter
141 					  * LWS_SYSTATE_POLICY_VALID */
142 } lws_system_states_t;
143 
144 /* Captive Portal Detect -related */
145 
146 typedef enum {
147 	LWS_CPD_UNKNOWN = 0,	/* test didn't happen ince last DHCP acq yet */
148 	LWS_CPD_INTERNET_OK,	/* no captive portal: our CPD test passed OK,
149 				 * we can go out on the internet */
150 	LWS_CPD_CAPTIVE_PORTAL,	/* we inferred we're behind a captive portal */
151 	LWS_CPD_NO_INTERNET,	/* we couldn't touch anything */
152 } lws_cpd_result_t;
153 
154 typedef void (*lws_attach_cb_t)(struct lws_context *context, int tsi, void *opaque);
155 struct lws_attach_item;
156 
157 typedef struct lws_system_ops {
158 	int (*reboot)(void);
159 	int (*set_clock)(lws_usec_t us);
160 	int (*attach)(struct lws_context *context, int tsi, lws_attach_cb_t cb,
161 		      lws_system_states_t state, void *opaque,
162 		      struct lws_attach_item **get);
163 	/**< if \p get is NULL, add an attach callback request to the pt for
164 	 * \p cb with arg \p opaque, that should be called when we're at or past
165 	 * system state \p state.
166 	 *
167 	 * If \p get is non-NULL, look for the first listed item on the pt whose
168 	 * state situation is ready, and set *get to point to it.  If no items,
169 	 * or none where the system state is right, set *get to NULL.
170 	 *
171 	 * It's done like this so (*attach) can perform system-specific
172 	 * locking outside of lws core, for both getting and adding items the
173 	 * same so it is thread-safe.  A non-threadsafe helper
174 	 * __lws_system_attach() is provided to do the actual work inside the
175 	 * system-specific locking.
176 	 */
177 	int (*captive_portal_detect_request)(struct lws_context *context);
178 	/**< Check if we can go out on the internet cleanly, or if we are being
179 	 * redirected or intercepted by a captive portal.
180 	 * Start the check that proceeds asynchronously, and report the results
181 	 * by calling lws_captive_portal_detect_result() api
182 	 */
183 
184 	int (*metric_report)(lws_metric_pub_t *mdata);
185 	/**< metric \p item is reporting an event of kind \p rpt,
186 	 * held in \p mdata... return 0 to leave the metric object as it is,
187 	 * or nonzero to reset it. */
188 
189 	uint32_t	wake_latency_us;
190 	/**< time taken for this device to wake from suspend, in us
191 	 */
192 } lws_system_ops_t;
193 
194 #if defined(LWS_WITH_SYS_STATE)
195 
196 /**
197  * lws_system_get_state_manager() - return the state mgr object for system state
198  *
199  * \param context: the lws_context
200  *
201  * The returned pointer can be used with the lws_state_ apis
202  */
203 
204 LWS_EXTERN LWS_VISIBLE lws_state_manager_t *
205 lws_system_get_state_manager(struct lws_context *context);
206 
207 #endif
208 
209 /* wrappers handle NULL members or no ops struct set at all cleanly */
210 
211 #define LWSSYSGAUTH_HEX (1 << 0)
212 
213 /**
214  * lws_system_get_ops() - get ahold of the system ops struct from the context
215  *
216  * \param context: the lws_context
217  *
218  * Returns the system ops struct.  It may return NULL and if not, anything in
219  * there may be NULL.
220  */
221 LWS_EXTERN LWS_VISIBLE const lws_system_ops_t *
222 lws_system_get_ops(struct lws_context *context);
223 
224 #if defined(LWS_WITH_SYS_STATE)
225 
226 /**
227  * lws_system_context_from_system_mgr() - return context from system state mgr
228  *
229  * \param mgr: pointer to specifically the system state mgr
230  *
231  * Returns the context from the system state mgr.  Helper since the lws_context
232  * is opaque.
233  */
234 LWS_EXTERN LWS_VISIBLE struct lws_context *
235 lws_system_context_from_system_mgr(lws_state_manager_t *mgr);
236 
237 #endif
238 
239 /**
240  * __lws_system_attach() - get and set items on context attach list
241  *
242  * \param context: context to get or set attach items to
243  * \param tsi: thread service index (normally 0)
244  * \param cb: callback to call from context event loop thread
245  * \param state: the lws_system state we have to be in or have passed through
246  * \param opaque: optional pointer to user specific info given to callback
247  * \param get: NULL, or pointer to pointer to take detached tail item on exit
248  *
249  * This allows other threads to enqueue callback requests to happen from a pt's
250  * event loop thread safely.  The callback gets the context pointer and a user
251  * opaque pointer that can be optionally given when the item is added to the
252  * attach list.
253  *
254  * This api is the no-locking core function for getting and setting items on the
255  * pt's attach list.  The lws_system operation (*attach) is the actual
256  * api that user and internal code calls for this feature, it should perform
257  * system-specific locking, call this helper, release the locking and then
258  * return the result.  This api is public only so it can be used in the locked
259  * implementation of (*attach).
260  *
261  * If get is NULL, then the call adds to the head of the pt attach list using
262  * cb, state, and opaque; if get is non-NULL, then *get is set to the first
263  * waiting attached item that meets the state criteria and that item is removed
264  * from the list.
265  *
266  * This is a non-threadsafe helper only designed to be called from
267  * implementations of struct lws_system's (*attach) operation where system-
268  * specific locking has been applied around it, making it threadsafe.
269  */
270 LWS_EXTERN LWS_VISIBLE int
271 __lws_system_attach(struct lws_context *context, int tsi, lws_attach_cb_t cb,
272 		    lws_system_states_t state, void *opaque,
273 		    struct lws_attach_item **get);
274 
275 
276 enum {
277 	LWSDH_IPV4_SUBNET_MASK		= 0,
278 	LWSDH_IPV4_BROADCAST,
279 	LWSDH_LEASE_SECS,
280 	LWSDH_REBINDING_SECS,
281 	LWSDH_RENEWAL_SECS,
282 
283 	_LWSDH_NUMS_COUNT,
284 
285 	LWSDH_SA46_IP			= 0,
286 	LWSDH_SA46_DNS_SRV_1,
287 	LWSDH_SA46_DNS_SRV_2,
288 	LWSDH_SA46_DNS_SRV_3,
289 	LWSDH_SA46_DNS_SRV_4,
290 	LWSDH_SA46_IPV4_ROUTER,
291 	LWSDH_SA46_NTP_SERVER,
292 	LWSDH_SA46_DHCP_SERVER,
293 
294 	_LWSDH_SA46_COUNT,
295 };
296 
297 typedef struct lws_dhcpc_ifstate {
298 	char				ifname[16];
299 	char				domain[64];
300 	uint8_t				mac[6];
301 	uint32_t			nums[_LWSDH_NUMS_COUNT];
302 	lws_sockaddr46			sa46[_LWSDH_SA46_COUNT];
303 } lws_dhcpc_ifstate_t;
304 
305 typedef int (*dhcpc_cb_t)(void *opaque, lws_dhcpc_ifstate_t *is);
306 
307 /**
308  * lws_dhcpc_request() - add a network interface to dhcpc management
309  *
310  * \param c: the lws_context
311  * \param i: the interface name, like "eth0"
312  * \param af: address family
313  * \param cb: the change callback
314  * \param opaque: opaque pointer given to the callback
315  *
316  * Register a network interface as being managed by DHCP.  lws will proceed to
317  * try to acquire an IP.  Requires LWS_WITH_SYS_DHCP_CLIENT at cmake.
318  */
319 LWS_EXTERN LWS_VISIBLE int
320 lws_dhcpc_request(struct lws_context *c, const char *i, int af, dhcpc_cb_t cb,
321 		void *opaque);
322 
323 /**
324  * lws_dhcpc_remove() - remove a network interface to dhcpc management
325  *
326  * \param context: the lws_context
327  * \param iface: the interface name, like "eth0"
328  *
329  * Remove handling of the network interface from dhcp.
330  */
331 LWS_EXTERN LWS_VISIBLE int
332 lws_dhcpc_remove(struct lws_context *context, const char *iface);
333 
334 /**
335  * lws_dhcpc_status() - has any interface reached BOUND state
336  *
337  * \param context: the lws_context
338  * \param sa46: set to a DNS server from a bound interface, or NULL
339  *
340  * Returns 1 if any network interface managed by dhcpc has reached the BOUND
341  * state (has acquired an IP, gateway and DNS server), otherwise 0.
342  */
343 LWS_EXTERN LWS_VISIBLE int
344 lws_dhcpc_status(struct lws_context *context, lws_sockaddr46 *sa46);
345 
346 /**
347  * lws_system_cpd_start() - helper to initiate captive portal detection
348  *
349  * \param context: the lws_context
350  *
351  * Resets the context's captive portal state to LWS_CPD_UNKNOWN and calls the
352  * lws_system_ops_t captive_portal_detect_request() implementation to begin
353  * testing the captive portal state.
354  */
355 LWS_EXTERN LWS_VISIBLE int
356 lws_system_cpd_start(struct lws_context *context);
357 
358 LWS_EXTERN LWS_VISIBLE void
359 lws_system_cpd_start_defer(struct lws_context *cx, lws_usec_t defer_us);
360 
361 
362 /**
363  * lws_system_cpd_set() - report the result of the captive portal detection
364  *
365  * \param context: the lws_context
366  * \param result: one of the LWS_CPD_ constants representing captive portal state
367  *
368  * Sets the context's captive portal detection state to result.  User captive
369  * portal detection code would call this once it had a result from its test.
370  */
371 LWS_EXTERN LWS_VISIBLE void
372 lws_system_cpd_set(struct lws_context *context, lws_cpd_result_t result);
373 
374 
375 /**
376  * lws_system_cpd_state_get() - returns the last tested captive portal state
377  *
378  * \param context: the lws_context
379  *
380  * Returns one of the LWS_CPD_ constants indicating the system's understanding
381  * of the current captive portal situation.
382  */
383 LWS_EXTERN LWS_VISIBLE lws_cpd_result_t
384 lws_system_cpd_state_get(struct lws_context *context);
385