#include <pwd.h>
#include <string.h>
#include "ini.h"
+#include "utility.h"
#include "version.h"
#define CFG_FILE "/etc/repo_shell.cfg"
#define GIT_ACL_FILE "git_acl.cfg"
+#define SHELL "/bin/bash"
typedef struct {
char *svn_root;
char *owner;
} cfg_t;
-static const char* shell_argv[] = { "/bin/bash", NULL };
-
-#undef USE_DEFAULTS
-#ifdef USE_DEFAULTS /* perhaps we want defaults? Not sure */
-static cfg_t cfg {
- svn_root: "/var/lib/svn/repositories",
- git_root: "/var/lib/git",
- owner: "repo"
-};
-#else
static cfg_t cfg;
-#endif
-
-static void die(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- fprintf(stderr, "error: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n" );
- va_end(ap);
- exit(1);
-}
-
-char *xstrdup(const char *str)
-{
- char *ret = strdup(str);
- if (!ret)
- die("out of memory");
- return ret;
-}
-
-void *xmalloc(size_t size)
-{
- void *ret;
-
- ret = malloc(size);
- if (!ret && !size)
- ret = malloc(1);
- if (!ret)
- die("out of memory");
- return ret;
-}
static uid_t user_uid(char *user)
{
static char *add_prefix(char *prefix, char* arg)
{
- int size;
-
- if (arg && prefix && strlen(prefix)) {
- char *n = xmalloc(sizeof(char *) *
- (strlen(prefix) + strlen(arg) + 2));
- strcpy(n, prefix);
- strcat(n, "/");
- strcat(n, arg);
- arg = n;
+ char *narg = arg;
+ int i;
+
+ if (arg && prefix && (i = strlen(prefix))) {
+ narg = xmalloc(sizeof(char *) * (i + strlen(arg) + 2));
+ strcpy(narg, prefix);
+ strcpy(narg + i++, "/");
+ strcpy(narg + i, arg);
}
- return arg;
+ return narg;
}
static int check_ssh_interactive(uid_t uid)
static int git_check_access(const char *cmd, const char *repo, const char *user)
{
- int rw = 1; /* 0=no access, 1=read only, 2=read/write */
-
- /* What access is required per the incoming command? */
- if (!strcmp(cmd, "git-upload-pack") ||
- !strcmp(cmd, "git-upload-archive"))
- rw = 2;
+ /* What access is required per the incoming command?
+ * 0=none, 1=read-only, 2=read-write
+ */
+ int rw = (!strcmp(cmd, "git-upload-pack") ||
+ !strcmp(cmd, "git-upload-archive")) ? 2 : 1;
/* Return true (1) if the user permissions >= those required */
return (git_acl(user, repo) >= rw) ? 1 : 0;
return execvp(svnserve_argv[0], (char *const *) svnserve_argv);
}
-#define SPLIT_CMDLINE_BAD_ENDING 1
-#define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
-static const char *split_cmdline_errors[] = {
- "cmdline ends with \\",
- "unclosed quote"
-};
-
-int split_cmdline(char *cmdline, const char ***argv)
-{
- int src, dst, count = 0, size = 16;
- char quoted = 0;
-
- *argv = xmalloc(sizeof(char *) * size);
-
- /* split alias_string */
- (*argv)[count++] = cmdline;
- for (src = dst = 0; cmdline[src];) {
- char c = cmdline[src];
- if (!quoted && isspace(c)) {
- cmdline[dst++] = 0;
- while (cmdline[++src]
- && isspace(cmdline[src]))
- ; /* skip */
- ALLOC_GROW(*argv, count+1, size);
- (*argv)[count++] = cmdline + dst;
- } else if (!quoted && (c == '\'' || c == '"')) {
- quoted = c;
- src++;
- } else if (c == quoted) {
- quoted = 0;
- src++;
- } else {
- if (c == '\\' && quoted != '\'') {
- src++;
- c = cmdline[src];
- if (!c) {
- free(*argv);
- *argv = NULL;
- return -SPLIT_CMDLINE_BAD_ENDING;
- }
- }
- cmdline[dst++] = c;
- src++;
- }
- }
-
- cmdline[dst] = 0;
-
- if (quoted) {
- free(*argv);
- *argv = NULL;
- return -SPLIT_CMDLINE_UNCLOSED_QUOTE;
- }
-
- ALLOC_GROW(*argv, count+1, size);
- (*argv)[count] = NULL;
-
- return count;
-}
-
-const char *split_cmdline_strerror(int split_cmdline_errno) {
- return split_cmdline_errors[-split_cmdline_errno-1];
-}
-
static void cd_to_homedir(void)
{
const char *home = getenv("HOME");
if (!home)
- die("could not determine user's home directory; HOME is unset");
+ die("user variable HOME is unset");
if (chdir(home) == -1)
die("could not chdir to user's home directory");
}
{ NULL },
};
-static int handler(void* user, const char* section, const char* name,
+static int ini_handler(void* user, const char* section, const char* name,
const char* value)
{
cfg_t* pconfig = (cfg_t*)user;
if (argc == 1 && check_ssh_interactive(getuid())) {
setuid(getuid());
- execvp(shell_argv[0], (char *const *) shell_argv);
- }
+ argv[0] = SHELL;
+ execvp(argv[0], (char *const *) argv);
+ }
-#ifdef USE_DEFAULTS
- ini_parse("repo_shell.cfg", handler, &cfg);
-#else
- if (ini_parse(CFG_FILE, handler, &cfg) < 0)
+ if (ini_parse(CFG_FILE, ini_handler, &cfg) < 0)
die("cannot read config file %s", CFG_FILE);
-#endif
prog = xstrdup(argv[2]);
if (!strncmp(prog, "git", 3) && isspace(prog[3]))
setuid(getuid());
cd_to_homedir();
- count = split_cmdline(prog, &user_argv);
- if (count >= 0) {
- execvp(user_argv[0], (char *const *) user_argv);
- free(user_argv);
- die("unrecognized command '%s'", argv[2]);
- } else {
- free(prog);
- die("invalid command format '%s': %s", argv[2],
- split_cmdline_strerror(count));
- }
+ argv[0] = SHELL;
+ execvp(argv[0], (char *const *) argv);
}