1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

lws_system generic blobs

Remove the auth lws_system stuff and redo it using generic blobs
with separate namespaces.  Support pointing to already-in-memory
blobs without using heap as well as multi-fragment appened blobs
eg, parsed out of JSON chunk by chunk and chained in heap.

Support auth the new way, along with client cert + key in DER
namespaces.
This commit is contained in:
Andy Green 2019-12-07 19:41:58 +00:00
parent fdbfafd1b5
commit c1a3defb88
4 changed files with 158 additions and 178 deletions

View file

@ -24,30 +24,62 @@
* This provides a clean way to interface lws user code to be able to
* work unchanged on different systems for fetching common system information,
* and performing common system operations like reboot.
*
* An ops struct with the system-specific implementations is set at
* context creation time, and apis are provided that call through to
* those where they exist.
*/
/*
* Types of system blob that can be set and retreived
*/
typedef enum {
LWS_SYSI_HRS_DEVICE_MODEL = 1,
LWS_SYSI_HRS_DEVICE_SERIAL,
LWS_SYSI_HRS_FIRMWARE_VERSION,
LWS_SYSI_HRS_NTP_SERVER,
LWS_SYSI_HRS_CLIENT_CERT_DER,
LWS_SYSBLOB_TYPE_AUTH,
LWS_SYSBLOB_TYPE_CLIENT_CERT_DER = LWS_SYSBLOB_TYPE_AUTH + 2,
LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
LWS_SYSBLOB_TYPE_DEVICE_SERIAL,
LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION,
LWS_SYSBLOB_TYPE_DEVICE_TYPE,
LWS_SYSBLOB_TYPE_NTP_SERVER,
LWS_SYSI_USER_BASE = 100
} lws_system_item_t;
LWS_SYSBLOB_TYPE_COUNT /* ... always last */
} lws_system_blob_item_t;
typedef struct lws_system_arg {
union {
const char *hrs; /* human readable string */
void *data;
time_t t;
} u;
size_t len;
} lws_system_arg_t;
/* opaque generic blob whose content may be on-the-heap or pointed-to
* directly case by case. When it's on the heap, it can be produced by
* appending (it's a buflist underneath). Either way, it can be consumed by
* copying out a given length from a given offset.
*/
typedef struct lws_system_blob lws_system_blob_t;
LWS_EXTERN LWS_VISIBLE void
lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
LWS_EXTERN LWS_VISIBLE void
lws_system_blob_heap_empty(lws_system_blob_t *b);
LWS_EXTERN LWS_VISIBLE int
lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
LWS_EXTERN LWS_VISIBLE size_t
lws_system_blob_get_size(lws_system_blob_t *b);
/* return 0 and sets *ptr to point to blob data if possible, nonzero = fail */
LWS_EXTERN LWS_VISIBLE int
lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr);
LWS_EXTERN LWS_VISIBLE int
lws_system_blob_get(lws_system_blob_t *b, uint8_t *ptr, size_t *len, size_t ofs);
LWS_EXTERN LWS_VISIBLE void
lws_system_blob_destroy(lws_system_blob_t *b);
/*
* Get the opaque blob for index idx of various system blobs. Returns 0 if
* *b was set otherwise nonzero means out of range
*/
LWS_EXTERN LWS_VISIBLE lws_system_blob_t *
lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
int idx);
/*
* Lws view of system state... normal operation from user code perspective is
@ -82,25 +114,9 @@ typedef enum { /* keep system_state_names[] in sync in context.c */
* LWS_SYSTATE_POLICY_VALID */
} lws_system_states_t;
typedef enum {
LWSSYS_AUTH_GET,
LWSSYS_AUTH_TOTAL_LENGTH,
LWSSYS_AUTH_APPEND,
LWSSYS_AUTH_FREE,
} lws_system_auth_op_t;
typedef int (*lws_system_auth_cb_t)(struct lws_context *context, int idx,
size_t ofs, uint8_t *buf, size_t *plen,
lws_system_auth_op_t set);
typedef struct lws_system_ops {
int (*get_info)(lws_system_item_t i, lws_system_arg_t *arg);
int (*reboot)(void);
int (*set_clock)(lws_usec_t us);
lws_system_auth_cb_t auth;
/**< Systemwide auth token management. For set, content may be appended
* incrementally safely. For get, content may be read out in arbitrary
* fragments using \p ofs. */
} lws_system_ops_t;
/**
@ -118,50 +134,9 @@ lws_system_get_state_manager(struct lws_context *context);
/* wrappers handle NULL members or no ops struct set at all cleanly */
/**
* lws_system_get_info() - get standardized system information
*
* \param context: the lws_context
* \param item: which information to fetch
* \param arg: where to place the result
*
* This queries a standardized information-fetching ops struct that can be
* applied to the context... the advantage is it allows you to get common items
* of information like a device serial number writing the code once, even if the
* actual serial number must be fetched in wildly different ways depending on
* the exact platform it's running on.
*
* Point arg to your lws_system_arg_t, on return it will be set. It doesn't
* copy the content just sets pointer and length.
*/
LWS_EXTERN LWS_VISIBLE int
lws_system_get_info(struct lws_context *context, lws_system_item_t item,
lws_system_arg_t *arg);
#define LWSSYSGAUTH_HEX (1 << 0)
/**
* lws_system_get_auth() - retreive system auth token helper
*
* \param context: the lws_context
* \param idx: which auth token
* \param ofs: offset in source to copy from
* \param buf: where to store result, or NULL
* \param buflen: size of buf
* \param flags: how to write the result
*
* Attempts to fill buf with the requested system auth token. If flags has
* LWSSYSGAUTH_HEX set, then the auth token is written as pairs of hex chars
* for each byte. If not set, written as 1 byte per byte binary.
*
* If buf is NULL, returns <= 0 if auth token is not set or > 0 if set, without
* writing anything. *buflen is still set to the size of the auth token.
*/
LWS_EXTERN LWS_VISIBLE int
lws_system_get_auth(struct lws_context *context, int idx, size_t ofs,
uint8_t *buf, size_t buflen, int flags);
/**
* lws_system_get_ops() - get ahold of the system ops struct from the context
*

View file

@ -254,6 +254,17 @@ struct lws_deferred_free
void *payload;
};
typedef struct lws_system_blob {
union {
struct lws_buflist *bl;
struct {
const uint8_t *ptr;
size_t len;
} direct;
} u;
char is_direct;
} lws_system_blob_t;
/*
* the rest is managed per-context, that includes
*
@ -274,6 +285,8 @@ struct lws_context {
struct lws_plat_file_ops fops_zip;
#endif
lws_system_blob_t system_blobs[LWS_SYSBLOB_TYPE_COUNT];
#if defined(LWS_WITH_NETWORK)
struct lws_context_per_thread pt[LWS_MAX_SMP];
lws_retry_bo_t default_retry;
@ -309,15 +322,11 @@ struct lws_context {
lws_async_dns_t async_dns;
#endif
struct lws_buflist *auth_token[2];
#if defined(LWS_WITH_NETWORK)
lws_state_manager_t mgr_system;
lws_state_notify_link_t protocols_notify;
#if defined (LWS_WITH_SYS_DHCP_CLIENT)
lws_dll2_owner_t dhcpc_owner;
/**< list of ifaces with dhcpc */
#endif
#endif
/* pointers */

View file

@ -125,7 +125,6 @@ callback_ntpc(struct lws *wsi, enum lws_callback_reasons reason, void *user,
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
lws_get_protocol(wsi));
uint8_t pkt[LWS_PRE + 48];
lws_system_arg_t arg;
uint64_t ns;
switch (reason) {
@ -157,11 +156,10 @@ callback_ntpc(struct lws *wsi, enum lws_callback_reasons reason, void *user,
v->notify_link.name = "ntpclient";
lws_state_reg_notifier(&wsi->context->mgr_system, &v->notify_link);
if (lws_system_get_info(wsi->context, LWS_SYSI_HRS_NTP_SERVER,
&arg))
v->ntp_server_ads = "pool.ntp.org";
else
v->ntp_server_ads = arg.u.hrs;
v->ntp_server_ads = "pool.ntp.org";
lws_system_blob_get_single_ptr(lws_system_get_blob(
v->context, LWS_SYSBLOB_TYPE_NTP_SERVER, 0),
(const uint8_t **)&v->ntp_server_ads);
lws_ntpc_retry_conn(&v->sul_conn);
break;

View file

@ -24,19 +24,10 @@
#include <private-lib-core.h>
#if defined(LWS_WITH_NETWORK)
static const char *hex = "0123456789ABCDEF";
#endif
int
lws_system_get_info(struct lws_context *context, lws_system_item_t item,
lws_system_arg_t *arg)
{
if (!context->system_ops || !context->system_ops->get_info)
return 1;
return context->system_ops->get_info(item, arg);
}
/*
* It's either a buflist (.is_direct = 0) or
* a direct pointer + len (.is_direct = 1)
*/
const lws_system_ops_t *
lws_system_get_ops(struct lws_context *context)
@ -44,102 +35,109 @@ lws_system_get_ops(struct lws_context *context)
return context->system_ops;
}
#if defined(LWS_WITH_NETWORK)
int
lws_system_auth_default_cb(struct lws_context *context, int idx, size_t ofs,
uint8_t *buf, size_t *plen, lws_system_auth_op_t op)
{
int n;
if (idx >= (int)LWS_ARRAY_SIZE(context->auth_token))
void
lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len)
{
b->is_direct = 1;
b->u.direct.ptr = ptr;
b->u.direct.len = len;
}
void
lws_system_blob_heap_empty(lws_system_blob_t *b)
{
b->is_direct = 0;
lws_buflist_destroy_all_segments(&b->u.bl);
}
int
lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *buf, size_t len)
{
assert(!b->is_direct);
if (lws_buflist_append_segment(&b->u.bl, buf, len) < 0)
return -1;
switch (op) {
case LWSSYS_AUTH_GET:
if (!context->auth_token[idx]) {
lwsl_notice("%s: token %d not set\n", __func__, idx);
return -1;
}
return 0;
}
if (!buf) /* we just need to tell him that it exists */
return -2;
size_t
lws_system_blob_get_size(lws_system_blob_t *b)
{
if (b->is_direct)
return b->u.direct.len;
n = lws_buflist_linear_copy(&context->auth_token[idx], ofs, buf,
*plen);
if (n < 0)
return -2;
*plen = (size_t)n;
return 0;
case LWSSYS_AUTH_TOTAL_LENGTH:
*plen = lws_buflist_total_len(&context->auth_token[idx]);
return 0;
case LWSSYS_AUTH_APPEND:
if (lws_buflist_append_segment(&context->auth_token[idx], buf,
*plen) < 0)
return -1;
return 0;
case LWSSYS_AUTH_FREE:
lws_buflist_destroy_all_segments(&context->auth_token[idx]);
return 0;
default:
break;
}
return -1;
return lws_buflist_total_len(&b->u.bl);
}
int
lws_system_get_auth(struct lws_context *context, int idx, size_t ofs,
uint8_t *buf, size_t buflen, int flags)
lws_system_blob_get(lws_system_blob_t *b, uint8_t *buf, size_t *len, size_t ofs)
{
size_t bl = buflen;
uint8_t *p, b;
int n;
if (!context->system_ops || !context->system_ops->auth)
n = lws_system_auth_default_cb(context, idx, ofs, buf, &buflen,
LWSSYS_AUTH_GET);
else
n = context->system_ops->auth(context, idx, ofs, buf, &buflen,
LWSSYS_AUTH_GET);
if (b->is_direct) {
if (n < 0) {
if (buf)
lwsl_err("%s: auth %d get failed %d, space %d\n",
__func__, idx, n, (int)bl);
return n;
}
assert(b->u.direct.ptr);
if (buf && (flags & LWSSYSGAUTH_HEX)) {
if (bl < (buflen * 2) + 1) {
lwsl_err("%s: auth in hex oversize %d\n", __func__,
(int)bl);
return -1;
if (ofs >= b->u.direct.len) {
*len = 0;
return 1;
}
/* convert to ascii hex inplace, backwards */
if (*len > b->u.direct.len - ofs)
*len = b->u.direct.len - ofs;
p = buf + (buflen * 2);
*p = '\0'; /* terminating NUL */
memcpy(buf, b->u.direct.ptr + ofs, *len);
for (n = (int)buflen - 1; n >= 0; n--) {
p -= 2;
b = buf[n];
p[0] = hex[(b >> 4) & 0xf];
p[1] = hex[b & 0xf];
}
buflen = (buflen * 2);
return 0;
}
return (int)buflen;
n = lws_buflist_linear_copy(&b->u.bl, ofs, buf, *len);
if (n < 0)
return -2;
*len = n;
return 0;
}
#endif
int
lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr)
{
if (b->is_direct) {
*ptr = b->u.direct.ptr;
return 0;
}
if (!b->u.bl)
return -1;
if (b->u.bl->next)
return -1; /* multipart buflist, no single pointer to it all */
*ptr = (const uint8_t *)&b->u.bl[1];
return 0;
}
void
lws_system_blob_destroy(lws_system_blob_t *b)
{
if (!b)
return;
if (!b->is_direct)
lws_buflist_destroy_all_segments(&b->u.bl);
}
lws_system_blob_t *
lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
int idx)
{
if (idx < 0 ||
idx >= (int)LWS_ARRAY_SIZE(context->system_blobs))
return NULL;
return &context->system_blobs[type + idx];
}