(2 months ago)commit 512c504: Slice forward approach
tree / marrow-auth.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include "./slice.h"
#define MAX_LINE 4096
#define MAX_USERNAME 256
#define AUTH_FILE "/etc/marrow/authorized_keys"
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
static int32_t
_openat(const int32_t wfd, const struct slice *path, int32_t flags) {
char cpath[PATH_MAX];
if (path->size >= PATH_MAX) return -1;
memcpy(cpath, path->ptr, path->size);
cpath[path->size] = '\0';
return openat(wfd, cpath, flags);
}
// TODO: slice delim variant
static struct slice
_sltok_r(const struct slice *src, const char delim, struct slice *rest) {
struct slice result;
size_t i;
result.ptr = src->ptr;
result.size = 0;
rest->ptr = src->ptr;
rest->size = src->size;
i = 0;
while (i < src->size) {
++rest->ptr;
--rest->size;
if (delim == src->ptr[i++]) {
break;
}
++result.size;
}
return (result);
}
static int32_t
_slcmp(const struct slice *a, const struct slice *b) {
int32_t rc;
if (a->size < b->size) {
rc = strncmp(a->ptr, b->ptr, a->size);
if (0 == rc) {
rc = -1;
}
} else if (a->size > b->size) {
rc = strncmp(a->ptr, b->ptr, b->size);
if (0 == rc) {
rc = 1;
}
} else {
rc = strncmp(a->ptr, b->ptr, a->size);
}
return (rc);
}
static int32_t
_readline(struct slice *dest, const int32_t fd, char *buffer, const size_t sz_buffer) {
// TODO: make this read in chunks, and store the context in a struct
ssize_t sz_read;
char c;
dest->ptr = buffer;
dest->size = 0;
while (dest->size < (sz_buffer - 1)) {
sz_read = read(fd, &c, 1);
if (-1 == sz_read) {
perror("read");
// TODO: handle error
return (-1);
}
if (0 == sz_read) {
break;
}
if ('\n' == c) {
if (0 < dest->size) {
break;
}
continue;
}
buffer[dest->size++] = c;
}
return (0);
}
int32_t
main(int32_t argc, char *argv[]) {
int32_t fd;
// usage: marrow-auth /usr/local/etc/marrow %t %k
if (argc < 3) {
dprintf(STDERR_FILENO, "usage: marrow-auth config_dir key_type base64_key\n");
return (EXIT_FAILURE);
}
// TODO: loop over config dir per user
const struct slice conf_path = slice_fromcstr(argv[1]);
const struct slice ssh_keytype = slice_fromcstr(argv[2]);
const struct slice ssh_key = slice_fromcstr(argv[3]);
fd = _openat(AT_FDCWD, &conf_path, O_RDONLY);
if (0 > fd) {
perror("openat");
return (EXIT_FAILURE);
}
char buf[4096];
long basep = 0;
int nbytes;
int32_t match = 0;
while ((nbytes = getdirentries(fd, buf, sizeof(buf), &basep)) > 0) {
char *ptr = buf;
while (ptr < buf + nbytes) {
struct dirent *dp = (struct dirent *)ptr;
if (dp->d_reclen == 0) break;
ptr += dp->d_reclen;
if (0 == strcmp(".", dp->d_name) || 0 == strcmp("..", dp->d_name)) {
continue;
}
// TODO: check each line in configuration file (key per line)
int32_t auth_fd = openat(fd, dp->d_name, O_RDONLY);
char key_buffer[8192];
struct slice key;
int32_t rc;
while (!match) {
rc = _readline(&key, auth_fd, key_buffer, sizeof(key_buffer));
if (-1 == rc || 0 == key.size) {
break;
}
struct slice rest;
struct slice origin_keytype;
struct slice origin_key;
struct slice origin_comment;
origin_keytype = _sltok_r(&key, ' ', &rest);
key = rest;
origin_key = _sltok_r(&key, ' ', &rest);
key = rest;
origin_comment = _sltok_r(&key, ' ', &rest);
if (0 == _slcmp(&ssh_keytype, &origin_keytype) && 0 == _slcmp(&ssh_key, &origin_key)) {
// TODO: if match, return ssh authorized_key format for that user
printf("command=\"/usr/local/bin/marrow-shell -u %s\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %.*s %.*s %.*s\n",
dp->d_name,
(int32_t)ssh_keytype.size,
ssh_keytype.ptr,
(int32_t)ssh_key.size,
ssh_key.ptr,
(int32_t)origin_comment.size,
origin_comment.ptr);
match = 1;
}
}
close(auth_fd);
if (match) {
break;
}
}
}
close(fd);
// TODO: if no match, return ssh authorized_key format
if (!match) {
printf("command=\"/usr/local/bin/marrow-shell\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %.*s %.*s anonymous\n",
(int32_t)ssh_keytype.size,
ssh_keytype.ptr,
(int32_t)ssh_key.size,
ssh_key.ptr
);
}
return (EXIT_SUCCESS);
}