git / brickware / marrow.git - 512c504

(2 months ago)commit 512c504: Slice forward approach

Summary | History | Files

commit 512c504

authorTanner Stenson <tanner@brickware.sh>
dateTue Oct 28 22:59:43 2025 -0400

message

Slice forward approach

diff

commit 512c504b4e8dd77984078c1a2eb7a212b6fa27dd
Author: Tanner Stenson <tanner@brickware.sh>
Date:   Tue Oct 28 22:59:43 2025 -0400

    Slice forward approach

diff --git a/marrow-auth.c b/marrow-auth.c
index 4f770fa..45b7474 100644
--- a/marrow-auth.c
+++ b/marrow-auth.c
@@ -124,9 +124,9 @@ main(int32_t argc, char *argv[]) {
     }
 
     // TODO: loop over config dir per user
-    const struct slice conf_path = cstrtoslice(argv[1]);
-    const struct slice ssh_keytype = cstrtoslice(argv[2]);
-    const struct slice ssh_key = cstrtoslice(argv[3]);
+    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) {
@@ -180,11 +180,11 @@ main(int32_t argc, char *argv[]) {
                     // 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,
-                            ssh_keytype.size,
+                            (int32_t)ssh_keytype.size,
                             ssh_keytype.ptr,
-                            ssh_key.size,
+                            (int32_t)ssh_key.size,
                             ssh_key.ptr,
-                            origin_comment.size,
+                            (int32_t)origin_comment.size,
                             origin_comment.ptr);
                     match = 1;
                 }
@@ -203,9 +203,9 @@ main(int32_t argc, char *argv[]) {
     // 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",
-                ssh_keytype.size,
+                (int32_t)ssh_keytype.size,
                 ssh_keytype.ptr,
-                ssh_key.size,
+                (int32_t)ssh_key.size,
                 ssh_key.ptr
                 );
     }
diff --git a/marrow-shell.c b/marrow-shell.c
index c0cd2f3..ffbf82e 100644
--- a/marrow-shell.c
+++ b/marrow-shell.c
@@ -8,6 +8,8 @@
 #include <errno.h>
 #include <stdint.h>
 
+#include "./slice.h"
+
 #define MAX_CMD_LEN 4096
 #define GIT_BASE_PATH "/srv/git"
 
@@ -25,7 +27,7 @@ get_git_user(void) {
 
 static int32_t
 is_anonymous(void) {
-    return NULL == get_git_user();
+    return 0x00 == get_git_user();
 }
 
 static git_command_t
@@ -50,46 +52,46 @@ is_write_command(git_command_t cmd) {
     return (CMD_GIT_RECEIVE_PACK == cmd);
 }
 
-static char *
+static struct slice
 extract_repo_path(const char *cmd) {
-    char *path = NULL;
     const char *start = strchr(cmd, '\'');
-    
+    struct slice result = {
+        .ptr = 0x00,
+        .size = 0,
+    };
+
     if (start) {
         start++;
         const char *end = strchr(start, '\'');
         if (end) {
-            size_t len = end - start;
-            path = malloc(len + 1);
-            if (path) {
-                strncpy(path, start, len);
-                path[len] = '\0';
-            }
+            result.ptr = start;
+            result.size = end - start;
         }
     } else {
         const char *space = strchr(cmd, ' ');
         if (space) {
             space++;
             while (' ' == *space) space++;
-            
-            size_t len = strlen(space);
-            path = malloc(len + 1);
-            if (path) {
-                strcpy(path, space);
-                char *end = strchr(path, ' ');
-                if (end) *end = '\0';
+
+            const char *end = strchr(space, ' ');
+            if (end) {
+                result.ptr = space;
+                result.size = end - space;
+            } else {
+                result.ptr = space;
+                result.size = strlen(space);
             }
         }
     }
-    
-    return (path);
+
+    return (result);
 }
 
 static char *
 normalize_path(const char *path) {
     char *normalized = malloc(PATH_MAX);
     if (!normalized) {
-        return NULL;
+        return 0x00;
     }
 
     char temp[PATH_MAX];
@@ -114,7 +116,7 @@ normalize_path(const char *path) {
             /* Normal component */
             components[comp_count++] = token;
         }
-        token = strtok(NULL, "/");
+        token = strtok(0x00, "/");
     }
 
     /* Rebuild the path */
@@ -133,17 +135,18 @@ normalize_path(const char *path) {
 }
 
 static int32_t
-validate_repo_path(const char *repo_path, const char *user) {
+validate_repo_path(const struct slice repo_path, const struct slice user) {
     char real_path[PATH_MAX];
     char expected_base[PATH_MAX];
 
-    if (0 == strncmp(repo_path, GIT_BASE_PATH, strlen(GIT_BASE_PATH))) {
-        snprintf(real_path, sizeof(real_path), "%s", repo_path);
+    if (repo_path.size >= strlen(GIT_BASE_PATH) &&
+        0 == strncmp(repo_path.ptr, GIT_BASE_PATH, strlen(GIT_BASE_PATH))) {
+        snprintf(real_path, sizeof(real_path), "%.*s", (int32_t)repo_path.size, repo_path.ptr);
     } else {
-        if ('/' == repo_path[0]) {
-            snprintf(real_path, sizeof(real_path), "%s%s", GIT_BASE_PATH, repo_path);
+        if (repo_path.size > 0 && '/' == repo_path.ptr[0]) {
+            snprintf(real_path, sizeof(real_path), "%s%.*s", GIT_BASE_PATH, (int32_t)repo_path.size, repo_path.ptr);
         } else {
-            snprintf(real_path, sizeof(real_path), "%s/%s", GIT_BASE_PATH, repo_path);
+            snprintf(real_path, sizeof(real_path), "%s/%.*s", GIT_BASE_PATH, (int32_t)repo_path.size, repo_path.ptr);
         }
     }
 
@@ -153,14 +156,14 @@ validate_repo_path(const char *repo_path, const char *user) {
         return 0;
     }
 
-    if (!user) {
+    if (slice_isempty(user)) {
         snprintf(expected_base, sizeof(expected_base), "%s/", GIT_BASE_PATH);
     } else {
-        snprintf(expected_base, sizeof(expected_base), "%s/%s/", GIT_BASE_PATH, user);
+        snprintf(expected_base, sizeof(expected_base), "%s/%.*s/", GIT_BASE_PATH, (int32_t)user.size, user.ptr);
     }
 
     int32_t valid = (0 == strncmp(resolved, expected_base, strlen(expected_base))) ||
-                    (0 == strcmp(resolved, GIT_BASE_PATH) && !user);
+                    (0 == strcmp(resolved, GIT_BASE_PATH) && slice_isempty(user));
 
 
     free(resolved);
@@ -168,55 +171,44 @@ validate_repo_path(const char *repo_path, const char *user) {
 }
 
 static int32_t
-check_permissions(const char *cmd) {
+check_permissions(const struct slice *user, const char *cmd) {
     git_command_t git_cmd = parse_command(cmd);
-    
+
     if (CMD_UNKNOWN == git_cmd) {
-        fputs("Error: Unknown command\n", stderr);
+        dprintf(STDERR_FILENO, "Error: Unknown command\n");
         return 0;
     }
-    
-    const char *user = get_git_user();
-    char *repo_path = extract_repo_path(cmd);
-    
-    if (!repo_path) {
-        fputs("Error: Could not extract repository path\n", stderr);
+
+    struct slice repo_path = extract_repo_path(cmd);
+    if (slice_isempty(repo_path)) {
+        dprintf(STDERR_FILENO, "Error: Could not extract repository path\n");
         return 0;
     }
-    
-    if (is_anonymous()) {
+
+    if (slice_isempty(*user)) {  /* anonymous */
         if (is_write_command(git_cmd)) {
-            fputs("Error: Anonymous users cannot perform write operations\n", stderr);
-            free(repo_path);
+            dprintf(STDERR_FILENO, "Error: Anonymous users cannot perform write operations\n");
             return 0;
         }
     } else {
         if (is_write_command(git_cmd)) {
-            if (!validate_repo_path(repo_path, user)) {
-                fputs("Error: User '", stderr);
-                fputs(user, stderr);
-                fputs("' can only write to repositories under ", stderr);
-                fputs(GIT_BASE_PATH, stderr);
-                fputs("/", stderr);
-                fputs(user, stderr);
-                fputs("/\n", stderr);
-                free(repo_path);
+            if (!validate_repo_path(repo_path, *user)) {
+                dprintf(STDERR_FILENO, "Error: User '%.*s' can only write to repositories under %s/%.*s/\n",
+                        (int32_t)user->size, user->ptr,
+                        GIT_BASE_PATH,
+                        (int32_t)user->size, user->ptr);
                 return 0;
             }
         }
     }
-    
+
     if (is_read_command(git_cmd)) {
-        if (!validate_repo_path(repo_path, NULL)) {
-            fputs("Error: Repository path must be under ", stderr);
-            fputs(GIT_BASE_PATH, stderr);
-            fputs("/\n", stderr);
-            free(repo_path);
+        if (!validate_repo_path(repo_path, slice_empty())) {
+            dprintf(STDERR_FILENO, "Error: Repository path must be under %s/\n", GIT_BASE_PATH);
             return 0;
         }
     }
-    
-    free(repo_path);
+
     return 1;
 }
 
@@ -248,21 +240,22 @@ static void
 execute_command(const char *cmd) {
     char command[MAX_CMD_LEN];
     git_command_t git_cmd = parse_command(cmd);
-    char *repo_path = extract_repo_path(cmd);
+    struct slice repo_path = extract_repo_path(cmd);
 
-    if (!repo_path) {
-        fputs("Error: Invalid command format\n", stderr);
+    if (slice_isempty(repo_path)) {
+        dprintf(STDERR_FILENO, "Error: Invalid command format\n");
         exit(1);
     }
 
     char full_path[PATH_MAX];
-    if (0 == strncmp(repo_path, GIT_BASE_PATH, strlen(GIT_BASE_PATH))) {
-        snprintf(full_path, sizeof(full_path), "%s", repo_path);
+    if (repo_path.size >= strlen(GIT_BASE_PATH) &&
+        0 == strncmp(repo_path.ptr, GIT_BASE_PATH, strlen(GIT_BASE_PATH))) {
+        snprintf(full_path, sizeof(full_path), "%.*s", (int32_t)repo_path.size, repo_path.ptr);
     } else {
-        if ('/' == repo_path[0]) {
-            snprintf(full_path, sizeof(full_path), "%s%s", GIT_BASE_PATH, repo_path);
+        if (repo_path.size > 0 && '/' == repo_path.ptr[0]) {
+            snprintf(full_path, sizeof(full_path), "%s%.*s", GIT_BASE_PATH, (int32_t)repo_path.size, repo_path.ptr);
         } else {
-            snprintf(full_path, sizeof(full_path), "%s/%s", GIT_BASE_PATH, repo_path);
+            snprintf(full_path, sizeof(full_path), "%s/%.*s", GIT_BASE_PATH, (int32_t)repo_path.size, repo_path.ptr);
         }
     }
 
@@ -272,18 +265,16 @@ execute_command(const char *cmd) {
         if (0 != stat(full_path, &st)) {
             if (ENOENT == errno) {
                 if (!create_bare_repository(full_path)) {
-                    fputs("Error: Failed to create repository\n", stderr);
-                    free(repo_path);
+                    dprintf(STDERR_FILENO, "Error: Failed to create repository\n");
                     exit(1);
                 }
             } else {
                 perror("stat");
-                free(repo_path);
                 exit(1);
             }
         }
     }
-    
+
     switch (git_cmd) {
         case CMD_GIT_UPLOAD_PACK:
             snprintf(command, sizeof(command), "git-upload-pack '%s'", full_path);
@@ -295,34 +286,29 @@ execute_command(const char *cmd) {
             snprintf(command, sizeof(command), "git-upload-archive '%s'", full_path);
             break;
         default:
-            fputs("Error: Unknown git command\n", stderr);
-            free(repo_path);
+            dprintf(STDERR_FILENO, "Error: Unknown git command\n");
             exit(1);
     }
-    
-    free(repo_path);
-    
-    execl("/bin/sh", "sh", "-c", command, NULL);
+
+    execl("/bin/sh", "sh", "-c", command, (char *)0x00);
     perror("execl");
     exit(1);
 }
 
 int32_t
 main(int32_t argc, char *argv[]) {
-    const char *username = NULL;
+    struct slice user = slice_empty();
     int32_t arg_offset = 0;
     
     /* Check for -u USER flag for authenticated access */
     if (argc > 2 && 0 == strcmp(argv[1], "-u")) {
-        username = argv[2];
+        user = slice_fromcstr(argv[2]);
         arg_offset = 2;
-        /* Set GIT_USER environment variable */
-        setenv("GIT_USER", username, 1);
     }
 
     /* Check for SSH_ORIGINAL_COMMAND first (SSH forced command) */
     const char *ssh_cmd = getenv("SSH_ORIGINAL_COMMAND");
-    const char *cmd = NULL;
+    const char *cmd = 0x00;
     
     if (ssh_cmd) {
         cmd = ssh_cmd;
@@ -330,29 +316,24 @@ main(int32_t argc, char *argv[]) {
         /* Fallback to command line argument */
         cmd = argv[2 + arg_offset];
     } else {
-        fputs("Usage: ", stderr);
-        fputs(argv[0], stderr);
-        fputs(" [-u USER] -c <command>\n", stderr);
-        fputs("This shell is designed to work with git SSH access\n", stderr);
-        fputs("Usually invoked via SSH with SSH_ORIGINAL_COMMAND set\n", stderr);
-        fputs("Supported commands:\n", stderr);
-        fputs("  git-upload-pack <repo>   - Clone/fetch repository\n", stderr);
-        fputs("  git-receive-pack <repo>  - Push to repository\n", stderr);
-        fputs("  git-upload-archive <repo> - Archive repository\n", stderr);
+        dprintf(STDERR_FILENO, "Usage: %s", argv[0]);
+        dprintf(STDERR_FILENO, " [-u USER] -c <command>\n");
+        dprintf(STDERR_FILENO, "This shell is designed to work with git SSH access\n");
+        dprintf(STDERR_FILENO, "Usually invoked via SSH with SSH_ORIGINAL_COMMAND set\n");
+        dprintf(STDERR_FILENO, "Supported commands:\n");
+        dprintf(STDERR_FILENO, "  git-upload-pack <repo>   - Clone/fetch repository\n");
+        dprintf(STDERR_FILENO, "  git-receive-pack <repo>  - Push to repository\n");
+        dprintf(STDERR_FILENO, "  git-upload-archive <repo> - Archive repository\n");
         return (EXIT_FAILURE);
     }
     
-    const char *user = get_git_user();
-    
-    if (user) {
-        fputs("Authenticated as: ", stderr);
-        fputs(user, stderr);
-        fputs("\n", stderr);
+    if (slice_isempty(user)) {
+        dprintf(STDERR_FILENO, "Authenticated as: %.*s\n", (int32_t)user.size, user.ptr);
     } else {
-        fputs("Anonymous access\n", stderr);
+        dprintf(STDERR_FILENO, "Anonymous access\n");
     }
     
-    if (!check_permissions(cmd)) {
+    if (!check_permissions(&user, cmd)) {
         return 1;
     }
     
diff --git a/slice.c b/slice.c
index c3fcab1..9ce19c3 100644
--- a/slice.c
+++ b/slice.c
@@ -1,10 +1,11 @@
 #include <unistd.h>
 #include <string.h>
+#include <stdlib.h>
 #include "./slice.h"
 
 
 struct slice
-cstrtoslice(const char *s) {
+slice_fromcstr(const char *s) {
     struct slice result;
 
     result.ptr = s;
@@ -12,3 +13,33 @@ cstrtoslice(const char *s) {
 
     return (result);
 }
+
+int32_t
+slice_isempty(const struct slice s) {
+    if (0 == s.size) return (1);
+    return (0);
+}
+
+struct slice
+slice_empty(void) {
+    return (struct slice){
+        .ptr = 0x00,
+        .size = 0,
+    };
+}
+
+char *
+slice_tocstr(const struct slice s) {
+    if (0 == s.ptr || 0 == s.size) {
+        return 0x00;
+    }
+
+    char *str = malloc(s.size + 1);
+    if (!str) {
+        return 0x00;
+    }
+
+    memcpy(str, s.ptr, s.size);
+    str[s.size] = '\0';
+    return str;
+}
diff --git a/slice.h b/slice.h
index b064ace..725351e 100644
--- a/slice.h
+++ b/slice.h
@@ -9,7 +9,15 @@ struct slice {
 };
 
 struct slice
-cstrtoslice(const char *s);
+slice_fromcstr(const char *s);
 
+int32_t
+slice_isempty(const struct slice s);
+
+struct slice
+slice_empty(void);
+
+char *
+slice_tocstr(const struct slice s);
 
 #endif