Crinit -- Configurable Rootfs Init
notiserv.c File Reference

(2023-08-02, commit: 9434b31)

Implementation of the notification and service interface. More...

#include "notiserv.h"
#include <libgen.h>
#include <linux/capability.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/un.h>
#include <unistd.h>
#include "logio.h"
#include "rtimcmd.h"
#include "thrpool.h"
Include dependency graph for notiserv.c:

Classes

struct  crinitConnThrArgs_t
 

Macros

#define _GNU_SOURCE
 Needed for SCM_CREDENTIALS, struct ucred,... More...
 
#define crinitGettid()   ((pid_t)syscall(SYS_gettid))
 
#define MAX_CONN_BACKLOG   100
 

Typedefs

typedef struct crinitConnThrArgs_t crinitConnThrArgs_t
 

Functions

static void * crinitConnThread (void *args)
 
static int crinitCreateSockFile (int *sockFd, const char *path)
 
static bool crinitCmsgHdrCheck (const struct cmsghdr *cmh)
 
static bool crinitUcredCheckEqual (const struct ucred *a, const struct ucred *b)
 
static int crinitSendStr (int sockFd, const char *str)
 
static int crinitRecvStr (int sockFd, char **str, struct ucred *passedCreds)
 
static bool crinitCheckPerm (crinitRtimOp_t op, const struct ucred *passedCreds)
 
static int crinitProcCapget (cap_user_data_t out, pid_t pid)
 
static int crinitMkdirp (char *pathname, mode_t mode)
 
int crinitStartInterfaceServer (crinitTaskDB_t *ctx, const char *sockFile)
 

Variables

static crinitThreadPool_t crinitWorkers
 The worker thread pool to run connThread() in. More...
 
static crinitTaskDB_tcrinitTdbRef
 Pointer to the crinitTaskDB_t to operate on. More...
 

Detailed Description

Implementation of the notification and service interface.

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Needed for SCM_CREDENTIALS, struct ucred,...

◆ crinitGettid

#define crinitGettid ( )    ((pid_t)syscall(SYS_gettid))

Macro wrapper for the gettid syscall in case glibc is not new enough to contain one itself

◆ MAX_CONN_BACKLOG

#define MAX_CONN_BACKLOG   100

Maximum number of unserviced connections until the server starts refusing

Typedef Documentation

◆ crinitConnThrArgs_t

Helper structure defining the arguments to connThread()

Function Documentation

◆ crinitCheckPerm()

static bool crinitCheckPerm ( crinitRtimOp_t  op,
const struct ucred *  passedCreds 
)
inlinestatic

Checks if given process credentials imply permission to execute remote command.

Parameters
opThe opcode of the command the process requests to execute.
passedCredsThe credentials of the requesting process obtained via SCM_CREDENTIALS.
Returns
true if passedCreds imply the sending process is permitted to execute op. Returns false otherwise, also on errors.

◆ crinitCmsgHdrCheck()

static bool crinitCmsgHdrCheck ( const struct cmsghdr *  cmh)
inlinestatic

Checks if a received struct cmsghdr has expected length and contents.

Expected is a struct cmsghdr containing SCM_CREDENTIALS.

Parameters
cmhThe header to check.
Returns
true if everything is as expected, false otherwise

◆ crinitConnThread()

static void * crinitConnThread ( void *  args)
static

The worker thread function for handling a connection to a client.

Will accept connections in a loop, send RTR, handle incoming requests, and send responses. Automatically gets informed of client PID, UID, and GID through SO_PASSCRED/SCM_CREDENTIALS, so that permission handling is possible.

Uses crinitThreadPoolThreadAvailCallback() and crinitThreadPoolThreadBusyCallback() to signal its status to the thread pool.

The client-side equivalent connection-handling function is crinitXfer() in crinit-client.c. The following image illustrates the high level client/server protocol.

Parameters
argsArguments to the function, see crinitConnThrArgs_t.
Returns
Does not return unless its thread is canceled in which case the return value is undefined.

◆ crinitCreateSockFile()

static int crinitCreateSockFile ( int *  sockFd,
const char *  path 
)
static

Create AF_UNIX socket file, bind() and listen().

Will overwrite any exist file at path.

Parameters
sockFdReturn pointer for the socket file descriptor.
pathPath to the socket file whcih should be created.
Returns
0 on success, -1 on error

◆ crinitMkdirp()

static int crinitMkdirp ( char *  pathname,
mode_t  mode 
)
inlinestatic

Recursive mkdir(), equivalent to mkdir -p.

Note: Will modify the input pathname during execution to seperate paths.

Parameters
pathnameThe complete path to recursively generate.
modeThe mode passed to mkdir().
Returns
0 on success, -1 on error

◆ crinitProcCapget()

static int crinitProcCapget ( cap_user_data_t  out,
pid_t  pid 
)
inlinestatic

Gets capabilities of process specified by PID.

Parameters
outReturn pointer for capabilities. Note, that the Linux API defines cap_user_data_t as a pointer to struct __user_cap_header_struct. The given pointer needs to point to at least two elements.
pidPID of the process from which to get the capabilities.
Returns
0 on success, -1 on error

◆ crinitRecvStr()

static int crinitRecvStr ( int  sockFd,
char **  str,
struct ucred *  passedCreds 
)
inlinestatic

Receives a string from a connected client.

The low level protocol is to first wait for a size_t informing the server of the length of the following string (including the terminating zero) and then the string itself. The complementary client-side function is crinitRecv().

This function will also extract the message metadata received via SO_PASSCRED and return the credentials of the sender via passedCreds.

This function will allocate memory for the received string using malloc(). The string should be free()'d when no longer needed.

The following image illustrates the low level send/receive protocol:

Parameters
sockFdThe socket file descriptor connected to the client.
strReturn pointer for the received string.
passedCredsReturn pointer for SCM_CREDENTIALS metadata.
Returns
0 on success, -1 otherwise

◆ crinitSendStr()

static int crinitSendStr ( int  sockFd,
const char *  str 
)
inlinestatic

Sends a string to a connected client.

The low level protocol is to first send a size_t informing the client of the length of the following string (including the terminating zero) and then the string itself. The complementary client-side function is crinitSend().

The following image illustrates the low level send/receive protocol:

Parameters
sockFdThe socket file descriptor connected to the client.
strThe string to send.
Returns
0 on success, -1 otherwise

◆ crinitStartInterfaceServer()

int crinitStartInterfaceServer ( crinitTaskDB_t ctx,
const char *  sockfile 
)

Starts the Notification and Service interface socket server.

Will create the AF_UNIX socket for clients to connect to and spawn a number of worker threads to service incoming connections (see notiserv.c and thrpool.h).

Parameters
ctxPointer to the crinitTaskDB_t which the Server should use for incoming requests.
sockfilePath where to create the AF_UNIX socket file.
Returns
0 on success, -1 on error

◆ crinitUcredCheckEqual()

static bool crinitUcredCheckEqual ( const struct ucred *  a,
const struct ucred *  b 
)
inlinestatic

Checks if two struct ucred are equal.

Two struct ucred are equal if and only if their members pid, uid, and gid are equal with their respective counterparts.

Parameters
aFirst operand.
bSecond operand.
Returns
true if a and b are equal, false if not

Variable Documentation

◆ crinitTdbRef

crinitTaskDB_t* crinitTdbRef
static

Pointer to the crinitTaskDB_t to operate on.

◆ crinitWorkers

crinitThreadPool_t crinitWorkers
static

The worker thread pool to run connThread() in.