1
0
Fork 0
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:
Andy Green 2019-03-25 08:07:28 +08:00
parent ce1f395ead
commit 1062370f07
8 changed files with 90 additions and 6 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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__);

View file

@ -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;