= Configure /etc/repo_shell.cfg
-The file /etc/repo_shell.cfg must contain certain fields:
+The file /etc/repo_shell.cfg must contain certain fields as shown in the example
+below. The spaces surrounding the equal sign ('=') are optional.
- owner=repo
- svn_root=/var/lib/svn/repositories
- git_root=/var/lib/git
- git_acl_file=/var/lib/git/.gitacls
+ owner = repo
+ svn_root = /var/lib/svn/repositories
+ git_root = /var/lib/git
+ git_acl_file = /var/lib/git/.gitacls
+ allowed_interactive =
owner is the system account username which will own all repositories, and is
preferaby a system account used for no other purpose. Use the adduser or
repository access, as implemented internally bit repo_shell. A recommended
pathname is /var/lib/git/.gitacls
+allow_interactive contains a list of users that may log into the server via SSH,
+or that may issue arbitrary commands to the server via SSH. Instead of a list,
+the wildcard character '*' can be used to indicate all users. Note that this
+only affects users that have /usr/local/bin/repo_shell as their login shell.
+If the server is only hosting repositories, there is no reason for users to be
+allowed 'interactive' access.
+
= Create owner and paths
In accordance with the contents of /etc/repo_shell.cfg:
#define SHELL "/bin/bash"
typedef struct {
+ char *user;
char *svn_root;
char *git_root;
char *owner;
char *git_acl_file;
+ bool allow_interactive;
} cfg_t;
static cfg_t cfg;
-static uid_t user_uid(char *user)
+/* This is the function for which setuid root is needed for repo_shell */
+static void change_user(char *user)
{
struct passwd *pw = getpwnam(user);
if (!pw)
- die("invalid user %s", user);
- return pw->pw_uid;
-}
-
-static void change_user(char *user)
-{
- /* This is the function for which setuid is required, as root */
- setuid(user_uid(user));
+ die("invalid user %s", pw->pw_name);
+ setuid(pw->pw_uid);
}
static char *dequote(char *arg)
return narg;
}
-static int check_ssh_interactive(uid_t uid)
-{
- /* TODO: Check the config file for the user owning uid to see if that
- * user should be able to execute any commands other than those required
- * to support repository access. Return a boolean true/false.
- */
- return 1; /* for now */
-}
-
/* Return true if the user's permissions >= those required */
static bool git_check_access(const char *cmd, const char *repo,
const char *user)
pconfig->owner = xstrdup(value);
else if (!strcmp(name, "git_acl_file"))
pconfig->git_acl_file = xstrdup(value);
+ else if (!strcmp(name, "allow_interactive"))
+ pconfig->allow_interactive = str_has_word(value, pconfig->user);
else
return 0; /* unknown section/name, error */
return 1;
struct commands *cmd;
int devnull_fd;
int count;
+ struct passwd *pw;
/*
* Always open file descriptors 0/1/2 to avoid clobbering files
return 0;
}
+ pw = getpwuid(getuid());
+ cfg.user = xstrdup(pw->pw_name);
+ if (ini_parse(CFG_FILE, ini_handler, &cfg) < 0)
+ die("cannot read config file %s", CFG_FILE);
+
if (argc == 1) {
- if (!check_ssh_interactive(getuid()))
+ if (!cfg.allow_interactive) {
+ fprintf(stderr, "\n");
die("only repository access is allowed");
+ }
setuid(getuid());
argv[0] = SHELL;
execvp(argv[0], (char *const *) argv);
return 1;
}
- if (ini_parse(CFG_FILE, ini_handler, &cfg) < 0)
- die("cannot read config file %s", CFG_FILE);
-
if ((!strcmp(argv[1], "-t") || !strcmp(argv[1], "--test"))) {
perms_t p;
for (cmd = cmd_list ; cmd->name ; cmd++) {
int len = strlen(cmd->name);
char *arg;
- struct passwd *pw;
if (strncmp(cmd->name, prog, len))
continue;
arg = NULL;
continue;
}
- pw = getpwuid(getuid());
- exit(cmd->exec(cmd->name, arg, pw->pw_name));
+ exit(cmd->exec(cmd->name, arg, cfg.user));
}
}
- if (!check_ssh_interactive(getuid()))
+ if (!cfg.allow_interactive)
die("only repository access is allowed");
-
setuid(getuid());
cd_to_homedir();
argv[0] = SHELL;