Skip to content

Commit

Permalink
add possibility to to autmatically restart the agent when it is updated
Browse files Browse the repository at this point in the history
  • Loading branch information
zachmann committed Aug 26, 2024
1 parent 799f60d commit b06f03e
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 17 deletions.
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ endif
endif
ifndef ANY_MSYS
DEFINE_CONFIG_PATH := -DCONFIG_PATH=\"$(CONFIG_AFTER_INST_PATH)\"
DEFINE_BIN_PATH := -DBIN_PATH=\"$(BIN_AFTER_INST_PATH)/bin\"
endif

USE_CJSON_SO ?= $(shell /sbin/ldconfig -N -v $(sed 's/:/ /g' <<< $LD_LIBRARY_PATH) 2>/dev/null | grep -i libcjson >/dev/null && echo 1 || echo 0)
Expand Down Expand Up @@ -434,7 +435,7 @@ endif
$(OBJDIR)/$(CLIENT)/$(CLIENT).o : $(APILIB)/$(SHARED_LIB_NAME_FULL)
$(OBJDIR)/%.o : $(SRCDIR)/%.c
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -c $< -o $@ -DVERSION=\"$(VERSION)\" $(DEFINE_CONFIG_PATH) $(DEFINE_USE_CJSON_SO) $(DEFINE_USE_LIST_SO) $(DEFINE_USE_MUSTACHE_SO)
@$(CC) $(CFLAGS) -c $< -o $@ -DVERSION=\"$(VERSION)\" $(DEFINE_CONFIG_PATH) $(DEFINE_BIN_PATH) $(DEFINE_USE_CJSON_SO) $(DEFINE_USE_LIST_SO) $(DEFINE_USE_MUSTACHE_SO)
@# Create dependency infos
@{ \
set -e ;\
Expand All @@ -450,7 +451,7 @@ $(OBJDIR)/%.o : $(SRCDIR)/%.c

$(OBJDIR)/%.o : $(SRCDIR)/%.cc
@mkdir -p $(@D)
@$(CXX) $(CPPFLAGS) -c $< -o $@ -DVERSION=\"$(VERSION)\" $(DEFINE_CONFIG_PATH)
@$(CXX) $(CPPFLAGS) -c $< -o $@ -DVERSION=\"$(VERSION)\" $(DEFINE_CONFIG_PATH) $(DEFINE_BIN_PATH)
@# Create dependency infos
@{ \
set -e ;\
Expand All @@ -474,7 +475,7 @@ $(OBJDIR)/%.o : $(LIBDIR)/%.c
## Compile position independent code
$(PICOBJDIR)/%.o : $(SRCDIR)/%.c
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -fpic -fvisibility=hidden -c $< -o $@ -DVERSION=\"$(VERSION)\" -DCONFIG_PATH=\"$(CONFIG_AFTER_INST_PATH)\" $(DEFINE_USE_CJSON_SO) $(DEFINE_USE_LIST_SO) $(DEFINE_USE_MUSTACHE_SO)
@$(CC) $(CFLAGS) -fpic -fvisibility=hidden -c $< -o $@ -DVERSION=\"$(VERSION)\" $(DEFINE_CONFIG_PATH) $(DEFINE_BIN_PATH) $(DEFINE_USE_CJSON_SO) $(DEFINE_USE_LIST_SO) $(DEFINE_USE_MUSTACHE_SO)
@echo "Compiled "$<" with pic successfully!"

$(PICOBJDIR)/%.o : $(LIBDIR)/%.c
Expand Down
5 changes: 5 additions & 0 deletions src/defines/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
#include "msys.h"
#include "oidc_values.h"

#ifndef BIN_PATH
#define BIN_PATH "/usr/bin"
#endif
#define AGENT_PATH BIN_PATH "/oidc-agent"

// env var names
/**
* the name of the environment variable used to locate the IPC socket
Expand Down
30 changes: 22 additions & 8 deletions src/ipc/serveripc.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
#include "utils/file_io/fileUtils.h"
#include "utils/file_io/file_io.h"
#include "utils/file_io/safefile/check_file_path.h"
#include "utils/inotify.h"
#include "utils/json.h"
#include "utils/logger.h"
#include "utils/memory.h"
#include "utils/restart.h"
#include "utils/string/stringUtils.h"
#include "utils/tempenv.h"
#include "wrapper/list.h"
Expand Down Expand Up @@ -130,7 +132,7 @@ char* create_passed_socket_path(const char* requested_path) {
oidc_ipc_dir = oidc_strcopy(requested_path);
if (lastChar(oidc_ipc_dir) == '/') { // only dir specified
lastChar(oidc_ipc_dir) = '\0';
} else { // full path including file specified
} else { // full path including file specified
char* lastSlash = strrchr(oidc_ipc_dir, '/');
socket_file = oidc_strcopy(lastSlash + 1);
char* tmp = oidc_strncopy(oidc_ipc_dir, lastSlash - oidc_ipc_dir);
Expand Down Expand Up @@ -262,16 +264,21 @@ int ipc_bindAndListen(struct connection* con, const char* group) {
#endif
umask(previous_mask);
int flags;
if (-1 == (flags = fcntl(*(con->sock), F_GETFL, 0)))
if (-1 == (flags = fcntl(*(con->sock), F_GETFL, 0))) {
flags = 0;
}
fcntl(*(con->sock), F_SETFL, flags | O_NONBLOCK);

logger(DEBUG, "listen ipc\n");
logger(DEBUG, "listen ipc");
return listen(*(con->sock), 5);
}

int _determineMaxSockAndAddToReadSet(int sock_listencon, fd_set* readSet) {
int maxSock = sock_listencon;
int _determineMaxSockAndAddToReadSet(int sock_listencon, int inotify_fd,
fd_set* readSet) {
int maxSock = sock_listencon;
if (inotify_fd > maxSock) {
maxSock = inotify_fd;
}
list_node_t* node;
list_iterator_t* it = list_iterator_new(connectionDB_getList(), LIST_HEAD);
while ((node = list_iterator_next(it))) {
Expand Down Expand Up @@ -314,13 +321,16 @@ struct connection* _checkClientSocksForMsg(fd_set* readSet) {
* message avaible for reading or the client disconnected.
*/
struct connection* ipc_readAsyncFromMultipleConnectionsWithTimeout(
struct connection listencon, time_t death) {
struct connection listencon, int inotify_fd, time_t death) {
while (1) {
fd_set readSockSet;
FD_ZERO(&readSockSet);
FD_SET(*(listencon.sock), &readSockSet);
int maxSock =
_determineMaxSockAndAddToReadSet(*(listencon.sock), &readSockSet);
if (inotify_fd >= 0) {
FD_SET(inotify_fd, &readSockSet);
}
int maxSock = _determineMaxSockAndAddToReadSet(*(listencon.sock),
inotify_fd, &readSockSet);

struct timeval* timeout = initTimeout(death);
if (oidc_errno != OIDC_SUCCESS) { // death before now
Expand All @@ -332,6 +342,10 @@ struct connection* ipc_readAsyncFromMultipleConnectionsWithTimeout(
int ret = select(maxSock + 1, &readSockSet, NULL, NULL, timeout);
secFree(timeout);
if (ret > 0) {
if (inotify_fd >= 0 && FD_ISSET(inotify_fd, &readSockSet)) {
inotify_read(inotify_fd, "oidc-agent", restart_agent_with_set_args);
continue;
}
if (FD_ISSET(*(listencon.sock),
&readSockSet)) { // if listensock read something it means a
// new client connected
Expand Down
2 changes: 1 addition & 1 deletion src/ipc/serveripc.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

oidc_error_t initServerConnection(struct connection* con);
struct connection* ipc_readAsyncFromMultipleConnectionsWithTimeout(
struct connection, time_t);
struct connection listencon, int inotify_fd, time_t death);
char* ipc_vcryptCommunicateWithServerPath(const char* fmt, va_list args);
char* ipc_cryptCommunicateWithServerPath(const char* fmt, ...);
char* getServerSocketPath();
Expand Down
24 changes: 19 additions & 5 deletions src/oidc-agent/oidcp/oidcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "utils/crypt/crypt.h"
#include "utils/db/connection_db.h"
#include "utils/disableTracing.h"
#include "utils/inotify.h"
#include "utils/json.h"
#include "utils/listUtils.h"
#include "utils/memory.h"
Expand All @@ -45,6 +46,7 @@
#include "utils/printerUtils.h"
#include "utils/prompting/getprompt.h"
#include "utils/prompting/prompt_mode.h"
#include "utils/restart.h"
#include "utils/string/stringUtils.h"
#include "utils/uriUtils.h"
#ifdef __MSYS__
Expand Down Expand Up @@ -72,7 +74,7 @@ static void check_parent_alive(void) {
}
}

_Noreturn static void handleClientComm(struct ipcPipe pipes,
_Noreturn static void handleClientComm(struct ipcPipe pipes, int inotify_fd,
const struct arguments* arguments,
time_t parent_alive_interval) {
connectionDB_new();
Expand All @@ -89,7 +91,7 @@ _Noreturn static void handleClientComm(struct ipcPipe pipes,
}
}
struct connection* con = ipc_readAsyncFromMultipleConnectionsWithTimeout(
*unix_listencon, deadline);
*unix_listencon, inotify_fd, deadline);
if (con == NULL) { // timeout reached
if (parent_alive_interval != 0) {
check_parent_alive();
Expand Down Expand Up @@ -279,12 +281,24 @@ int main(int argc, char** argv) {
agent_state.defaultTimeout = arguments.lifetime;
struct ipcPipe pipes = startOidcd(&arguments);

if (ipc_bindAndListen(unix_listencon, arguments.group) != 0) {
if (ipc_bindAndListen(unix_listencon, arguments.group) != OIDC_SUCCESS) {
oidc_perror();
agent_log(ALERT, "%s", oidc_serror());
exit(EXIT_FAILURE);
}

set_prompt_mode(PROMPT_MODE_GUI);
handleClientComm(pipes, &arguments, parent_alive_interval);
#ifdef __linux__
set_restart_agent_args(argc, argv);
int inotify_fd = inotify_watch(AGENT_PATH);
if (inotify_fd < 0) {
agent_log(ERROR, "%s", oidc_serror());
exit(EXIT_FAILURE);
}
#else
int inotify_fd = -1;
#endif
handleClientComm(pipes, inotify_fd, &arguments, parent_alive_interval);
}

char* _extractShortnameFromReauthenticateInfo(const char* info) {
Expand Down Expand Up @@ -318,7 +332,7 @@ int _waitForCodeExchangeRequest(time_t expiration, const char* expected_state,
struct ipcPipe pipes) {
while (1) {
struct connection* con = ipc_readAsyncFromMultipleConnectionsWithTimeout(
*unix_listencon, expiration);
*unix_listencon, -1, expiration);
if (con == NULL) { // timeout reached
removeDeathPasswords();
return -1;
Expand Down
77 changes: 77 additions & 0 deletions src/utils/inotify.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "inotify.h"

#ifdef __linux__

#include "memory.h"
#include "oidc_error.h"
#include "string/stringUtils.h"

#define _XOPEN_SOURCE 500
#include <libgen.h>
#include <sys/inotify.h>
#include <unistd.h>

#define EVENT_SIZE (sizeof(struct inotify_event))
#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))

int inotify_watch(const char* file_path) {
if (file_path == NULL) {
oidc_setArgNullFuncError(__func__);
return -1;
}

char* fp_copy = oidc_strcopy(file_path);
char* directory = oidc_strcopy(dirname(fp_copy)); // Get directory part
secFree(fp_copy);
fp_copy = oidc_strcopy(file_path);
char* filename = oidc_strcopy(basename(fp_copy)); // Get filename part
secFree(fp_copy);

// Create inotify instance
int fd = inotify_init();
if (fd < 0) {
oidc_setErrnoError();
secFree(directory);
secFree(filename);
return -1;
}

// Add a watch for the directory
int wd = inotify_add_watch(fd, directory, IN_MOVED_FROM | IN_MOVED_TO);
if (wd == -1) {
oidc_setErrnoError();
close(fd);
secFree(directory);
secFree(filename);
return -1;
}

secFree(directory);
secFree(filename);
return fd;
}

oidc_error_t inotify_read(int fd, const char* filename, void (*callback)()) {
char buffer[EVENT_BUF_LEN];

ssize_t length = read(fd, buffer, EVENT_BUF_LEN);
if (length < 0) {
oidc_setErrnoError();
return oidc_errno;
}

size_t i = 0;
while (i < (size_t)length) {
struct inotify_event* event = (struct inotify_event*)&buffer[i];

if ((event->mask & IN_MOVED_FROM || event->mask & IN_MOVED_TO) &&
strequal(event->name, filename)) {
callback();
return OIDC_SUCCESS;
}
i += EVENT_SIZE + event->len;
}
return OIDC_SUCCESS;
}

#endif //__linux__
12 changes: 12 additions & 0 deletions src/utils/inotify.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef OIDC_AGENT_INOTIFY_H
#define OIDC_AGENT_INOTIFY_H

#ifdef __linux__

#include "oidc_error.h"

oidc_error_t inotify_read(int fd, const char* filename, void (*callback)());
int inotify_watch(const char* file_path);

#endif // __linux__
#endif // OIDC_AGENT_INOTIFY_H
36 changes: 36 additions & 0 deletions src/utils/restart.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#define _XOPEN_SOURCE 500
#include "restart.h"

#include <unistd.h>

#include "defines/settings.h"
#include "utils/agentLogger.h"
#include "utils/logger.h"
#include "utils/oidc_error.h"

static int restart_argc;
static char** restart_argv;

void set_restart_agent_args(int argc, char* argv[]) {
restart_argc = argc;
restart_argv = argv;
}

void restart_agent_with_set_args() {
restart_agent(restart_argc, restart_argv);
}

void restart_agent(int argc, char* argv[]) {
// Rebuild the arguments array, ensuring the last element is NULL as required
// by execv
char* new_argv[argc + 1];
for (int i = 0; i < argc; i++) { new_argv[i] = argv[i]; }
new_argv[argc] = NULL;

agent_log(INFO, "Restarting oidc-agent %s ...", AGENT_PATH);
execv(AGENT_PATH, new_argv);

// This is only reached in error case
oidc_setErrnoError();
agent_log(ERROR, "%s", oidc_serror());
}
8 changes: 8 additions & 0 deletions src/utils/restart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef OIDC_AGENT_RESTART_H
#define OIDC_AGENT_RESTART_H

void restart_agent(int argc, char* argv[]);
void restart_agent_with_set_args();
void set_restart_agent_args(int argc, char* argv[]);

#endif // OIDC_AGENT_RESTART_H

0 comments on commit b06f03e

Please sign in to comment.