mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-09-01 02:35:03 +00:00
improvements in SCM_CREDENTIALS subscription system
This commit is contained in:
@@ -1278,6 +1278,50 @@ int uwsgi_pass_cred(int fd, char *code, size_t code_len) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int uwsgi_pass_cred2(int fd, char *code, size_t code_len, struct sockaddr *addr, size_t addr_len) {
|
||||
#ifdef SCM_CREDENTIALS
|
||||
struct msghdr cr_msg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec cr_iov;
|
||||
void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
|
||||
|
||||
cr_iov.iov_base = code;
|
||||
cr_iov.iov_len = code_len;
|
||||
|
||||
cr_msg.msg_name = addr;
|
||||
cr_msg.msg_namelen = addr_len;
|
||||
|
||||
cr_msg.msg_iov = &cr_iov;
|
||||
cr_msg.msg_iovlen = 1;
|
||||
|
||||
cr_msg.msg_flags = 0;
|
||||
cr_msg.msg_control = cr_msg_control;
|
||||
cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&cr_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_CREDENTIALS;
|
||||
|
||||
struct ucred *u = (struct ucred*) CMSG_DATA(cmsg);
|
||||
u->pid = getpid();
|
||||
u->uid = getuid();
|
||||
u->gid = getgid();
|
||||
|
||||
if (sendmsg(fd, &cr_msg, 0) < 0) {
|
||||
uwsgi_error("uwsgi_pass_cred2()/sendmsg()");
|
||||
free(cr_msg_control);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(cr_msg_control);
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_recv_cred(int fd, char *code, size_t code_len, pid_t *pid, uid_t *uid, gid_t *gid) {
|
||||
#ifdef SCM_CREDENTIALS
|
||||
struct iovec iov;
|
||||
@@ -1313,6 +1357,8 @@ int uwsgi_recv_cred(int fd, char *code, size_t code_len, pid_t *pid, uid_t *uid,
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (uwsgi_strncmp(code, code_len, iov.iov_base, iov.iov_len)) goto clear;
|
||||
|
||||
struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
|
||||
*pid = u->pid;
|
||||
*uid = u->uid;
|
||||
@@ -1327,3 +1373,53 @@ clear:
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t uwsgi_recv_cred2(int fd, char *buf, size_t buf_len, pid_t *pid, uid_t *uid, gid_t *gid) {
|
||||
#ifdef SCM_CREDENTIALS
|
||||
struct iovec iov;
|
||||
ssize_t ret = -1;
|
||||
|
||||
void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = buf_len;
|
||||
|
||||
struct msghdr msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
msg.msg_control = msg_control;
|
||||
msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
|
||||
|
||||
ssize_t len = recvmsg(fd, &msg, 0);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("uwsgi_recv_cred2()/recvmsg()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (!cmsg) goto clear;
|
||||
|
||||
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
|
||||
*pid = u->pid;
|
||||
*uid = u->uid;
|
||||
*gid = u->gid;
|
||||
ret = len;
|
||||
|
||||
clear:
|
||||
free(msg_control);
|
||||
return ret;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -18,81 +18,6 @@ static size_t get_content_length(char *buf, uint16_t size) {
|
||||
}
|
||||
|
||||
|
||||
ssize_t send_udp_message(uint8_t modifier1, uint8_t modifier2, char *host, char *message, uint16_t message_size) {
|
||||
|
||||
int fd;
|
||||
struct sockaddr_in udp_addr;
|
||||
struct sockaddr_un un_addr;
|
||||
char *udp_port;
|
||||
ssize_t ret;
|
||||
|
||||
struct uwsgi_header *uh;
|
||||
|
||||
udp_port = strchr(host, ':');
|
||||
if (udp_port) {
|
||||
udp_port[0] = 0;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&udp_addr, 0, sizeof(struct sockaddr_in));
|
||||
udp_addr.sin_family = AF_INET;
|
||||
udp_addr.sin_port = htons(atoi(udp_port + 1));
|
||||
udp_addr.sin_addr.s_addr = inet_addr(host);
|
||||
}
|
||||
else {
|
||||
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&un_addr, 0, sizeof(struct sockaddr_un));
|
||||
un_addr.sun_family = AF_UNIX;
|
||||
// use 102 as the magic number
|
||||
strncat(un_addr.sun_path, host, 102);
|
||||
|
||||
}
|
||||
|
||||
if (message) {
|
||||
uh = (struct uwsgi_header *) message;
|
||||
}
|
||||
else {
|
||||
uh = (struct uwsgi_header *) uwsgi_malloc(4);
|
||||
}
|
||||
|
||||
uh->modifier1 = modifier1;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uh->pktsize = uwsgi_swap16(message_size);
|
||||
#else
|
||||
uh->pktsize = message_size;
|
||||
#endif
|
||||
uh->modifier2 = modifier2;
|
||||
|
||||
if (udp_port) {
|
||||
ret = sendto(fd, (char *) uh, message_size + 4, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
|
||||
udp_port[0] = ':';
|
||||
}
|
||||
else {
|
||||
ret = sendto(fd, (char *) uh, message_size + 4, 0, (struct sockaddr *) &un_addr, sizeof(un_addr));
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("send_udp_message()/sendto()");
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if ((char *) uh != message) {
|
||||
free(uh);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_read_response(int fd, struct uwsgi_header *uh, int timeout, char **buf) {
|
||||
|
||||
char *ptr = (char *) uh;
|
||||
|
||||
@@ -1928,6 +1928,19 @@ found:
|
||||
return up;
|
||||
}
|
||||
|
||||
int uwsgi_socket_passcred(int fd) {
|
||||
#ifdef SO_PASSCRED
|
||||
int optval = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) {
|
||||
uwsgi_error("uwsgi_socket_passcred()/setsockopt()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_protocols_register() {
|
||||
uwsgi_register_protocol("uwsgi", uwsgi_proto_uwsgi_setup);
|
||||
uwsgi_register_protocol("puwsgi", uwsgi_proto_puwsgi_setup);
|
||||
|
||||
+89
-1
@@ -49,6 +49,23 @@ static void uwsgi_subscription_sni_check(struct uwsgi_subscribe_slot *current_sl
|
||||
}
|
||||
#endif
|
||||
|
||||
int uwsgi_subscription_credentials_check(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) {
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, uwsgi.subscriptions_credentials_check_dir) {
|
||||
char *filename = uwsgi_concat2n(usl->value, usl->len, slot->key, slot->keylen);
|
||||
struct stat st;
|
||||
int ret = stat(filename, &st);
|
||||
free(filename);
|
||||
if (ret != 0) continue;
|
||||
uwsgi_log("%d %d %d %d\n", st.st_uid, usr->uid, st.st_gid, usr->gid);
|
||||
if (st.st_uid != usr->uid) continue;
|
||||
if (st.st_gid != usr->gid) continue;
|
||||
// accepted...
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) {
|
||||
|
||||
if (keylen > 0xff)
|
||||
@@ -393,6 +410,11 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi.subscriptions_credentials_check_dir && !uwsgi_subscription_credentials_check(current_slot, usr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = current_slot->nodes;
|
||||
while (node) {
|
||||
if (!uwsgi_strncmp(node->name, node->len, usr->address, usr->address_len)) {
|
||||
@@ -501,6 +523,13 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
#endif
|
||||
current_slot->keylen = usr->keylen;
|
||||
memcpy(current_slot->key, usr->key, usr->keylen);
|
||||
if (uwsgi.subscriptions_credentials_check_dir) {
|
||||
if (!uwsgi_subscription_credentials_check(current_slot, usr)) {
|
||||
free(current_slot);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
current_slot->key[usr->keylen] = 0;
|
||||
current_slot->hits = 0;
|
||||
#ifdef UWSGI_SSL
|
||||
@@ -556,6 +585,62 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
|
||||
}
|
||||
|
||||
static void send_subscription(char *host, char *message, uint16_t message_size) {
|
||||
|
||||
int fd;
|
||||
struct sockaddr_in udp_addr;
|
||||
struct sockaddr_un un_addr;
|
||||
ssize_t ret;
|
||||
|
||||
char *udp_port = strchr(host, ':');
|
||||
if (udp_port) {
|
||||
udp_port[0] = 0;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("send_subscription()/socket()");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&udp_addr, 0, sizeof(struct sockaddr_in));
|
||||
udp_addr.sin_family = AF_INET;
|
||||
udp_addr.sin_port = htons(atoi(udp_port + 1));
|
||||
udp_addr.sin_addr.s_addr = inet_addr(host);
|
||||
}
|
||||
else {
|
||||
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("send_subscription()/socket()");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&un_addr, 0, sizeof(struct sockaddr_un));
|
||||
un_addr.sun_family = AF_UNIX;
|
||||
// use 102 as the magic number
|
||||
strncat(un_addr.sun_path, host, 102);
|
||||
|
||||
}
|
||||
|
||||
if (udp_port) {
|
||||
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
|
||||
udp_port[0] = ':';
|
||||
}
|
||||
else {
|
||||
if (uwsgi.subscriptions_use_credentials) {
|
||||
// could be useless as internally the socket could add them automagically
|
||||
ret = uwsgi_pass_cred2(fd, message, message_size, (struct sockaddr *) &un_addr, sizeof(un_addr));
|
||||
}
|
||||
else {
|
||||
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &un_addr, sizeof(un_addr));
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("send_subscription()/sendto()");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
|
||||
|
||||
@@ -612,7 +697,10 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
|
||||
if (uwsgi_buffer_append_keyval(ub, "sni_ca", 6, sni_ca, strlen(sni_ca))) goto end;
|
||||
}
|
||||
|
||||
send_udp_message(224, cmd, udp_address, ub->buf, ub->pos - 4);
|
||||
// add uwsgi header
|
||||
if (uwsgi_buffer_set_uh(ub, 224, cmd)) goto end;
|
||||
|
||||
send_subscription(udp_address, ub->buf, ub->pos);
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
|
||||
@@ -577,6 +577,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER},
|
||||
{"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER},
|
||||
#endif
|
||||
{"subscriptions-credentials-check", required_argument, 0, "add a directory to search for subscriptions key credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_credentials_check_dir, UWSGI_OPT_MASTER},
|
||||
{"subscriptions-use-credentials", no_argument, 0, "enable management of SCM_CREDENTIALS in subscriptions UNIX sockets", uwsgi_opt_true, &uwsgi.subscriptions_use_credentials, 0},
|
||||
{"subscription-algo", required_argument, 0, "set load balancing algorithm for the subscription system", uwsgi_opt_ssa, NULL, 0},
|
||||
{"subscription-dotsplit", no_argument, 0, "try to fallback to the next part (dot based) in subscription key", uwsgi_opt_true, &uwsgi.subscription_dotsplit, 0},
|
||||
{"subscribe-to", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER},
|
||||
|
||||
@@ -4,7 +4,7 @@ common functions for various routers (fastrouter, http...)
|
||||
|
||||
*/
|
||||
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -79,6 +79,11 @@ void uwsgi_corerouter_setup_sockets(struct uwsgi_corerouter *ucr) {
|
||||
}
|
||||
else {
|
||||
ugs->fd = bind_to_unix_dgram(ugs->name);
|
||||
if (uwsgi.subscriptions_use_credentials) {
|
||||
if (uwsgi_socket_passcred(ugs->fd)) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
uwsgi_socket_nb(ugs->fd);
|
||||
}
|
||||
@@ -113,10 +118,17 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
|
||||
int i;
|
||||
struct uwsgi_subscribe_req usr;
|
||||
char bbuf[4096];
|
||||
ssize_t len = -1;
|
||||
|
||||
ssize_t len = recv(ugs->fd, bbuf, 4096, 0);
|
||||
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
|
||||
|
||||
if (uwsgi.subscriptions_use_credentials) {
|
||||
len = uwsgi_recv_cred2(ugs->fd, bbuf, 4096, &usr.pid, &usr.uid, &usr.gid);
|
||||
}
|
||||
else {
|
||||
len = recv(ugs->fd, bbuf, 4096, 0);
|
||||
}
|
||||
if (len > 0) {
|
||||
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
|
||||
uwsgi_hooked_parse(bbuf + 4, len - 4, corerouter_manage_subscription, &usr);
|
||||
if (usr.sign_len > 0) {
|
||||
// calc the base size
|
||||
|
||||
@@ -2145,6 +2145,9 @@ struct uwsgi_server {
|
||||
const EVP_MD *subscriptions_sign_check_md;
|
||||
#endif
|
||||
|
||||
struct uwsgi_string_list *subscriptions_credentials_check_dir;
|
||||
int subscriptions_use_credentials;
|
||||
|
||||
struct uwsgi_dyn_dict *static_maps;
|
||||
struct uwsgi_dyn_dict *static_maps2;
|
||||
struct uwsgi_dyn_dict *check_static;
|
||||
@@ -2947,8 +2950,6 @@ uint32_t uwsgi_swap32(uint32_t);
|
||||
uint64_t uwsgi_swap64(uint64_t);
|
||||
#endif
|
||||
|
||||
ssize_t send_udp_message(uint8_t, uint8_t, char *, char *, uint16_t);
|
||||
|
||||
int uwsgi_parse_request(int, struct wsgi_request *, int);
|
||||
int uwsgi_parse_vars(struct wsgi_request *);
|
||||
|
||||
@@ -3210,6 +3211,10 @@ struct uwsgi_subscribe_req {
|
||||
|
||||
char *sni_ca;
|
||||
uint16_t sni_ca_len;
|
||||
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
void uwsgi_nuclear_blast();
|
||||
@@ -4649,7 +4654,10 @@ int uwsgi_run(void);
|
||||
|
||||
int uwsgi_is_connected(int);
|
||||
int uwsgi_pass_cred(int, char *, size_t);
|
||||
int uwsgi_pass_cred2(int, char *, size_t, struct sockaddr *, size_t);
|
||||
int uwsgi_recv_cred(int, char *, size_t, pid_t *, uid_t *, gid_t *);
|
||||
ssize_t uwsgi_recv_cred2(int, char *, size_t, pid_t *, uid_t *, gid_t *);
|
||||
int uwsgi_socket_passcred(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user