<?php
// This is called by a remote client that does push or fetch
error_reporting(E_ALL);
ini_set("track_errors", "On");
$_start = microtime(TRUE);
require_once("/etc/rg/config.php");
$INC = dirname(__FILE__) . "/../inc";
require_once($INC . "/util.inc.php");
require_once($INC . "/log.inc.php");
require_once($INC . "/db.inc.php");
require_once($INC . "/repo.inc.php");
rg_log_set_file("/tmp/rg_ssh.log");
$rg_sql_debug = $rg_db_debug;
function fatal($str)
{
global $access_type;
rg_log("Sending error: " . $str);
$str2 = "FATAL ERROR: " . $str . "\n";
if ($access_type == 2) { // git
$str3 = "\n" . $str2;
$len = strlen($str3) + 4;
$str4 = sprintf("%04x", $len) . $str3;
fwrite(STDERR, $str4);
} else { // ssh
fwrite(STDERR, $str2);
}
exit(1);
}
rg_log("Start: euid=" . posix_geteuid() . "...");
//rg_log("_SERVER: " . print_r($_SERVER, TRUE));
umask(0022);
if (isset($_SERVER['SSH_CONNECTION'])) {
rg_log("SSH connection: " . @$_SERVER['SSH_CONNECTION']);
$access_type = 1;
// we do not have host info
$host = "";
// first parameter must be uid of the user
$uid = @$_SERVER['argv'][1];
if (empty($uid))
fatal("uid not provided!");
rg_log("\tuid is $uid.");
$cmd_repo = trim(@$_SERVER['SSH_ORIGINAL_COMMAND']);
if (empty($cmd_repo))
fatal("No SSH_ORIGINAL_COMMAND provided!");
} else {
rg_log("git-daemon connection...");
$access_type = 2;
// we have no client info
$uid = 0;
$f = @fopen("php://stdin", "r");
if ($f === FALSE)
fatal("\tCannot open stdin!");
$line = @fread($f, 8000);
if ($line === FALSE)
fatal("\tCannot read!");
fclose($f);
$line_len = strlen($line);
if ($line_len < 4)
fatal("\tLine is too short!");
$len = @hexdec(substr($line, 0, 4));
if ($line_len < $len)
fatal("Too less data ($line_len/$len) received!");
// parse something like: 002bgit-upload-pack /aa.git.host=localhost
$line = substr($line, 4);
$v = explode("\0", $line);
$cmd_repo = trim($v[0]);
$host = trim(substr($v[1], 5));
}
// extract command and compute permissions
if (strncmp($cmd_repo, "git-upload-pack", 15) == 0) {
$cmd = "git-upload-pack";
$perms = "F";
} else if (strncmp($cmd_repo, "git-receive-pack", 16) == 0) {
$cmd = "git-receive-pack";
$perms = "P";
} else {
fatal("Unknown command!");
}
// extract repository name
$repo = substr($cmd_repo, strlen($cmd));
$repo = trim($repo, "' ");
$repo = ltrim($repo, "/");
$repo = preg_replace('/\.git$/' , '', $repo);
rg_log("host=[$host] cmd=[$cmd] repo=[$repo] perms=[$perms].");
// validity/security checks
if (rg_repo_ok($repo) !== TRUE)
fatal("Repo [$repo] is invalid (" . rg_repo_error() . ")");
$db = rg_sql_open($rg_db);
if ($db === FALSE)
fatal("Internal error (db)!");
// load info about the repository
$ri = rg_repo_info($db, 0, $repo);
if ($ri['ok'] != 1)
fatal("Temporary error!");
if ($ri['exists'] != 1)
fatal("Repo does not exists!");
if ($ri['deleted'] == 1)
fatal("Repo was deleted!");
$rg_ui = array("uid" => $uid, "is_admin" => 0);
if (!rg_repo_allow($db, $ri, $rg_ui, $perms))
fatal("You do not have this type of access to this repository!");
// TODO: limit per connection
// TODO: limit time and/or cpu
$repo_base = rg_repo_name2base($repo);
$repo_path = $repo_base . $repo . ".git";
rg_log("repo_path=$repo_path.");
$run = "git-shell -c \"" . $cmd . " '" . escapeshellcmd($repo_path) . "'\"";
rg_log("Running [$run]...");
passthru($run, $ret);
rg_log("[$run] returned $ret.");
$diff = sprintf("%u", (microtime(TRUE) - $_start) * 1000);
rg_log("Took " . $diff . "ms.");
@file_put_contents($repo_path . "/rg/last_access",
"repo: " . $repo . " ($repo_path)"
. "\nat: " . sprintf("%u", $_start)
. "\nuid: " . $uid
. "\ncmd: $cmd"
. "\nperms: $perms"
. "\nTook: " . $diff . "ms");
// Mark repository dirty for disk statistics and other stuff
if (strcmp($cmd, "git-receive-pack") == 0)
@file_put_contents($rg_path . "/dirty", "");
?>
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"
Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit
Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit
You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a
pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master