151 lines
4.9 KiB
C
151 lines
4.9 KiB
C
#include "server.h"
|
|
|
|
struct {
|
|
int sock_fd;
|
|
char* request;
|
|
uid_t uid;
|
|
char* client_path;
|
|
} server_globals = {
|
|
.request = NULL,
|
|
.uid = 0,
|
|
.client_path = NULL,
|
|
};
|
|
|
|
int server_init(char* path) {
|
|
umask(0);
|
|
server_globals.sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
if (server_globals.sock_fd < 0) {
|
|
return errno;
|
|
}
|
|
|
|
struct sockaddr_un server_addr;
|
|
|
|
memset(&server_addr, 0, sizeof(server_addr));
|
|
server_addr.sun_family = AF_UNIX;
|
|
// copy in the provided directory path for the socket
|
|
memcpy(server_addr.sun_path, path, strlen(path));
|
|
|
|
// // is this needed?
|
|
// signal(SIGPIPE, SIG_IGN);
|
|
|
|
socklen_t server_addr_len = sizeof(server_addr.sun_family) + strlen(server_addr.sun_path);
|
|
|
|
unlink(server_addr.sun_path);
|
|
if (bind(server_globals.sock_fd, (struct sockaddr *)&server_addr, server_addr_len) != 0) {
|
|
return errno;
|
|
}
|
|
|
|
int optval = 1;
|
|
if (setsockopt(server_globals.sock_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) != 0) {
|
|
return errno;
|
|
}
|
|
|
|
server_globals.client_path = malloc(CLIENT_PATH_LENGTH);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int server_listen() {
|
|
struct sockaddr_un client_addr;
|
|
struct msghdr message_hdr;
|
|
// tells recvmsg where to put the client address name
|
|
message_hdr.msg_name = (struct sockaddr *)&client_addr;
|
|
// only ever expect the abstract address to be 5 chars long (plus one for null at beginning)
|
|
// sockaddr_un is big enough to handle up to 108 characters but we don't want more than 6
|
|
message_hdr.msg_namelen = sizeof(sa_family_t) + CLIENT_PATH_LENGTH;
|
|
|
|
// this is where the message (the client's request) will be stored, it's weird cause it can support multiple buffers
|
|
struct iovec iovec;
|
|
// the buffer to receive into is just the memory for the request in the return result, this way no copying is required
|
|
iovec.iov_base = NULL;
|
|
iovec.iov_len = 0;
|
|
message_hdr.msg_iov = &iovec;
|
|
// there's only one element in the iovec cause we only use one buffer
|
|
message_hdr.msg_iovlen = 1;
|
|
|
|
// set after call, not checked so it shouldn't matter
|
|
message_hdr.msg_flags = 0;
|
|
|
|
// this is the buffer for getting ancillary data (namely, the UID of the requesting client)
|
|
char message_control_buffer[CONTROL_BUFFER_SIZE];
|
|
message_hdr.msg_control = &message_control_buffer;
|
|
message_hdr.msg_controllen = CONTROL_BUFFER_SIZE;
|
|
|
|
// call gets info about waiting message and sender (address and uid)
|
|
ssize_t msg_size = recvmsg(server_globals.sock_fd, &message_hdr, MSG_PEEK | MSG_TRUNC);
|
|
|
|
// for now, just output how big it was, later, we will check to make sure it's the correct size
|
|
if (msg_size < 0) {
|
|
return errno;
|
|
}
|
|
|
|
// extract credentials from the message
|
|
struct ucred credentials;
|
|
memcpy(&credentials, CMSG_DATA((struct cmsghdr *)message_hdr.msg_control), sizeof(credentials));
|
|
|
|
// recvmsg populated msg_name with the client's actual path info.
|
|
// copy that into the client path
|
|
// client_addr.sun_path should be updated by recvmsg
|
|
memcpy(server_globals.client_path, client_addr.sun_path, CLIENT_PATH_LENGTH);
|
|
|
|
server_globals.uid = credentials.uid;
|
|
// username = getpwuid(credentials.uid)->pw_name;
|
|
|
|
// allocate buffer to receive the actual message
|
|
free(server_globals.request);
|
|
server_globals.request = malloc(msg_size);
|
|
|
|
ssize_t recv_size = recv(server_globals.sock_fd, server_globals.request, msg_size, 0);
|
|
|
|
if (recv_size < 0) {
|
|
return errno;
|
|
}
|
|
|
|
// request was already added to result, so it's ready to go
|
|
return 0;
|
|
}
|
|
|
|
int server_respond(char* response) {
|
|
// set up client address
|
|
struct sockaddr_un client_addr;
|
|
client_addr.sun_family = AF_UNIX;
|
|
memcpy(client_addr.sun_path, server_globals.client_path, CLIENT_PATH_LENGTH);
|
|
|
|
// send stream
|
|
// NOTE: I added a 1 here to include the null byte at the end of the string, because it didn't seem to be included otherwise
|
|
// but it appears to work without that when the client sends the request? Probably needs more investigation
|
|
ssize_t sent = sendto(server_globals.sock_fd, response, strlen(response) + 1, 0, (struct sockaddr *)&client_addr, sizeof(sa_family_t) + CLIENT_PATH_LENGTH);
|
|
|
|
if (sent < 0) {
|
|
return errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
char* server_get_request() {
|
|
return server_globals.request;
|
|
}
|
|
|
|
char* server_get_username(uid_t uid) {
|
|
// if this doesn't work sometime you can try storing the uid instead and then calling getpwuid in here
|
|
return getpwuid(uid)->pw_name;
|
|
}
|
|
|
|
uid_t server_get_uid() {
|
|
return server_globals.uid;
|
|
}
|
|
|
|
// void __attribute__ ((constructor)) init(void) {
|
|
|
|
// }
|
|
|
|
// TODO: proper signal handling (e.g. this doesn't run when SIGINT stops the program)
|
|
void __attribute__ ((destructor)) server_clean_up(void) {
|
|
// TODO: error handling?
|
|
close(server_globals.sock_fd);
|
|
free(server_globals.request);
|
|
free(server_globals.client_path);
|
|
// don't need to free username since it's provided by getpwuid
|
|
}
|