mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
unix skt: allow control over skt user:group
If you're providing a unix socket service that will be proxied / served by another process on the same machine, the unix fd permissions on the listening unix socket fd have to be managed so only something running under the server credentials can open the listening unix socket.
This commit is contained in:
parent
ce1f395ead
commit
1062370f07
8 changed files with 90 additions and 6 deletions
|
@ -227,6 +227,8 @@ See also "apply-listen-accept" below.
|
|||
|
||||
- "`unix-socket`": "1" causes the unix socket specified in the interface option to be used instead of an INET socket
|
||||
|
||||
- "`unix-socket-perms`": "user:group" allows you to control the unix permissons on the listening unix socket. It's always get to `0600` mode, but you can control the user and group for the socket fd at creation time. This allows you to use unix user and groups to control who may open the other end of the unix socket on the local system.
|
||||
|
||||
- "`sts`": "1" causes lwsws to send a Strict Transport Security header with responses that informs the client he should never accept to connect to this address using http. This is needed to get the A+ security rating from SSL Labs for your server.
|
||||
|
||||
- "`access-log`": "filepath" sets where apache-compatible access logs will be written
|
||||
|
|
|
@ -649,6 +649,10 @@ struct lws_context_creation_info {
|
|||
* permissions. Like .uid but takes a string username. */
|
||||
const char *groupname; /**< CONTEXT: string groupname for post-init
|
||||
* permissions. Like .gid but takes a string groupname. */
|
||||
const char *unix_socket_perms; /**< VHOST: if your vhost is listening
|
||||
* on a unix socket, you can give a "username:groupname" string here
|
||||
* to control the owner:group it's created with. It's always created
|
||||
* with 0660 mode. */
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
|
|
|
@ -326,11 +326,38 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
|
|||
}
|
||||
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
if (LWS_UNIX_SOCK_ENABLED(vhost) && vhost->context->uid)
|
||||
if (chown(serv_unix.sun_path, vhost->context->uid,
|
||||
vhost->context->gid))
|
||||
lwsl_notice("%s: chown for unix skt %s failed\n",
|
||||
__func__, serv_unix.sun_path);
|
||||
if (LWS_UNIX_SOCK_ENABLED(vhost)) {
|
||||
uid_t uid = vhost->context->uid;
|
||||
gid_t gid = vhost->context->gid;
|
||||
|
||||
if (vhost->unix_socket_perms) {
|
||||
if (lws_plat_user_colon_group_to_ids(
|
||||
vhost->unix_socket_perms, &uid, &gid)) {
|
||||
lwsl_err("%s: Failed to translate %s\n",
|
||||
__func__, vhost->unix_socket_perms);
|
||||
return LWS_ITOSA_NOT_EXIST;
|
||||
}
|
||||
}
|
||||
if (uid && gid) {
|
||||
if (chown(serv_unix.sun_path, uid, gid)) {
|
||||
lwsl_err("%s: failed to set %s perms %u:%u\n",
|
||||
__func__, serv_unix.sun_path,
|
||||
(unsigned int)uid, (unsigned int)gid);
|
||||
|
||||
return LWS_ITOSA_NOT_EXIST;
|
||||
}
|
||||
lwsl_notice("%s: vh %s unix skt %s perms %u:%u\n",
|
||||
__func__, vhost->name, serv_unix.sun_path,
|
||||
(unsigned int)uid, (unsigned int)gid);
|
||||
|
||||
if (chmod(serv_unix.sun_path, 0660)) {
|
||||
lwsl_err("%s: failed to set %s to 0600 mode\n",
|
||||
__func__, serv_unix.sun_path);
|
||||
|
||||
return LWS_ITOSA_NOT_EXIST;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LWS_PLAT_OPTEE
|
||||
|
|
|
@ -394,6 +394,7 @@ struct lws_vhost {
|
|||
const char *iface;
|
||||
const char *listen_accept_role;
|
||||
const char *listen_accept_protocol;
|
||||
const char *unix_socket_perms;
|
||||
|
||||
void (*finalize)(struct lws_vhost *vh, void *arg);
|
||||
void *finalize_arg;
|
||||
|
|
|
@ -485,6 +485,7 @@ lws_create_vhost(struct lws_context *context,
|
|||
vh->finalize_arg = info->finalize_arg;
|
||||
vh->listen_accept_role = info->listen_accept_role;
|
||||
vh->listen_accept_protocol = info->listen_accept_protocol;
|
||||
vh->unix_socket_perms = info->unix_socket_perms;
|
||||
|
||||
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
|
||||
if (ar->init_vhost)
|
||||
|
|
|
@ -593,6 +593,11 @@ lws_plat_init(struct lws_context *context,
|
|||
LWS_EXTERN int
|
||||
lws_plat_drop_app_privileges(struct lws_context *context);
|
||||
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
int
|
||||
lws_plat_user_colon_group_to_ids(const char *u_colon_g, uid_t *puid, gid_t *pgid);
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_check_byte_utf8(unsigned char state, unsigned char c);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
|
|
|
@ -43,6 +43,45 @@ _lws_plat_apply_caps(int mode, const cap_value_t *cv, int count)
|
|||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_plat_user_colon_group_to_ids(const char *u_colon_g, uid_t *puid, gid_t *pgid)
|
||||
{
|
||||
char *colon = strchr(u_colon_g, ':'), u[33];
|
||||
struct passwd *p;
|
||||
struct group *g;
|
||||
int ulen;
|
||||
|
||||
if (!colon)
|
||||
return 1;
|
||||
|
||||
ulen = lws_ptr_diff(colon, u_colon_g);
|
||||
if (ulen < 2 || ulen > (int)sizeof(u) - 1)
|
||||
return 1;
|
||||
|
||||
memcpy(u, u_colon_g, ulen);
|
||||
u[ulen] = '\0';
|
||||
|
||||
colon++;
|
||||
|
||||
g = getgrnam(colon);
|
||||
if (!g) {
|
||||
lwsl_err("%s: unknown group '%s'\n", __func__, colon);
|
||||
|
||||
return 1;
|
||||
}
|
||||
*pgid = g->gr_gid;
|
||||
|
||||
p = getpwnam(u);
|
||||
if (!p) {
|
||||
lwsl_err("%s: unknown group '%s'\n", __func__, u);
|
||||
|
||||
return 1;
|
||||
}
|
||||
*puid = p->pw_uid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_drop_app_privileges(struct lws_context *context)
|
||||
{
|
||||
|
@ -105,7 +144,7 @@ lws_plat_drop_app_privileges(struct lws_context *context)
|
|||
return 1;
|
||||
}
|
||||
|
||||
lwsl_notice("%s: effective group %s\n", __func__,
|
||||
lwsl_notice("%s: effective group '%s'\n", __func__,
|
||||
g->gr_name);
|
||||
} else
|
||||
lwsl_info("%s: not changing group\n", __func__);
|
||||
|
|
|
@ -67,6 +67,7 @@ static const char * const paths_vhosts[] = {
|
|||
"vhosts[].port",
|
||||
"vhosts[].interface",
|
||||
"vhosts[].unix-socket",
|
||||
"vhosts[].unix-socket-perms",
|
||||
"vhosts[].sts",
|
||||
"vhosts[].host-ssl-key",
|
||||
"vhosts[].host-ssl-cert",
|
||||
|
@ -133,6 +134,7 @@ enum lejp_vhost_paths {
|
|||
LEJPVP_PORT,
|
||||
LEJPVP_INTERFACE,
|
||||
LEJPVP_UNIXSKT,
|
||||
LEJPVP_UNIXSKT_PERMS,
|
||||
LEJPVP_STS,
|
||||
LEJPVP_HOST_SSL_KEY,
|
||||
LEJPVP_HOST_SSL_CERT,
|
||||
|
@ -593,6 +595,9 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
|
|||
else
|
||||
a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
|
||||
return 0;
|
||||
case LEJPVP_UNIXSKT_PERMS:
|
||||
a->info->unix_socket_perms = a->p;
|
||||
break;
|
||||
case LEJPVP_STS:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |= LWS_SERVER_OPTION_STS;
|
||||
|
|
Loading…
Add table
Reference in a new issue