1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
/*
* Wrapper for git-shell that only allows it to access ~/source.git.
*
* Also allows running a very few other special commands:
*
* logview tails site logs
* logdump dumps site logs
*
* In C for speed.
*
* Use in .ssh/authorized_keys:
* command="iki-git-shell",no-agent-forwarding,no-port-forwarding,no-X11-forwarding,no-pty,no-user-rc <key>
*
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
/* A "parked" flag file in the repo disables remote access.
* The file content explains why. */
void checkparked (const char *repo) {
char *flagfile;
FILE *f;
if (asprintf(&flagfile, "%s/parked", repo) == -1) {
perror("asprintf");
exit(1);
}
if ((f=fopen(flagfile, "r")) != NULL) {
int bufsize=1024;
char *buf=malloc(bufsize);
while (fread(buf, bufsize, 1, f) > 0) {
fwrite(buf, bufsize, 1, stderr);
}
exit(1);
}
}
void logs (const char *param) {
execlp("ikisite", "ikisite", "logs", param, NULL);
perror("ikisite");
exit(1);
}
int main (int argc, char **argv) {
char *repo, *command, *subcommand, *s;
struct passwd *passwd;
passwd=getpwuid(geteuid());
if (! passwd || ! passwd->pw_dir || ! strlen(passwd->pw_dir)) {
fprintf(stderr, "error: failed to determine home directory\n");
exit(1);
}
if (asprintf(&repo, "%s/source.git", passwd->pw_dir) == -1) {
perror("asprintf");
exit(1);
}
checkparked(repo);
/*
* The original command passed to ssh will be
* "git subcommand path" or "git-subcommand path".
* Pass the subcommand on to git-shell, along with the path to the
* repository.
*/
command=getenv("SSH_ORIGINAL_COMMAND");
if (! command) {
fprintf(stderr, "error: SSH_ORIGINAL_COMMAND not set\n");
exit(1);
}
s=strtok(command, " -"); /* handle "git-" and "git " */
if (! s) {
fprintf(stderr, "error: missing command\n");
exit(1);
}
if (strcmp(s, "logview") == 0) {
logs("--tail");
exit(0);
}
if (strcmp(s, "logdump") == 0) {
logs("--dump");
exit(0);
}
if (strcmp(s, "git") != 0) {
fprintf(stderr, "error: unknown command \"%s\"\n", s);
exit(1);
}
s=strtok(NULL, " ");
if (! s || ! strlen(s)) {
fprintf(stderr, "error: missing git subcommand\n");
}
if (asprintf(&subcommand, "git-%s", s) == -1) {
perror("asprintf");
exit(1);
}
/* git-shell currently needs some wacky quoting around the
* subcommand and repo that its man page does not show */
if (asprintf(&subcommand, "%s '%s'", subcommand, repo) == -1) {
perror("asprintf");
exit(1);
}
/* this variable is used to communicate to iki-git-hook-update
* that the commit is coming in from an external source */
setenv("UNTRUSTED_COMMIT", "1", 1);
execlp("git-shell", "git-shell", "-c", subcommand, NULL);
perror("git-shell");
exit(1);
}
|