func main() { syscall.Umask(0022) // set umask for pushes clientId := common.Getenv("SSH_CLIENT", "local") logfilePath := common.Getenv("LOGFILE", "/var/log/gitorious/gitorious-shell.log") internalApiUrl := common.Getenv("GITORIOUS_INTERNAL_API_URL", "http://localhost:3000/api/internal") logger := getLogger(logfilePath, clientId) internalApi := &api.GitoriousInternalApi{internalApiUrl} logger.Printf("client connected") if len(os.Args) < 2 { say("Error occured, please contact support") logger.Printf("username argument missing, check .authorized_keys file") os.Exit(1) } username := os.Args[1] logger.Printf("user authenticated as %v", username) sshCommand := strings.Trim(os.Getenv("SSH_ORIGINAL_COMMAND"), " \n") if sshCommand == "" { // deny regular ssh login attempts say("Hey %v! Sorry, Gitorious doesn't provide shell access. Bye!", username) logger.Printf("SSH_ORIGINAL_COMMAND missing, aborting...") os.Exit(1) } logger.Printf("processing command: %v", sshCommand) command, repoPath, err := parseGitShellCommand(sshCommand) if err != nil { say("Invalid command") logger.Printf("%v, aborting...", err) os.Exit(1) } repoConfig, err := internalApi.GetRepoConfig(repoPath, username) if err != nil { if httpErr, ok := err.(*api.HttpError); ok { if httpErr.StatusCode == 403 { say("Access denied") logger.Printf("%v, aborting...", err) os.Exit(1) } else if httpErr.StatusCode == 404 { say("Invalid repository path") logger.Printf("%v, aborting...", err) os.Exit(1) } } say("Error occured, please contact support") logger.Printf("%v, aborting...", err) os.Exit(1) } logger.Printf("full repo path: %v", repoConfig.FullPath) if !common.PreReceiveHookExists(repoConfig.FullPath) { say("Error occurred, please contact support") logger.Printf("pre-receive hook for %v is missing or is not executable, aborting...", repoConfig.FullPath) os.Exit(1) } gitShellCommand := formatGitShellCommand(command, repoConfig.FullPath) env := createSshEnv(username, repoConfig) logger.Printf(`invoking git-shell with command "%v"`, gitShellCommand) if stderr, err := execGitShell(gitShellCommand, env, os.Stdin, os.Stdout); err != nil { say("Error occurred, please contact support") logger.Printf("error occured in git-shell: %v", err) logger.Printf("stderr: %v", stderr) os.Exit(1) } logger.Printf("done") }
func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { logger := &common.SessionLogger{h.logger, req.RemoteAddr} logger.Printf("client connected") var username string if usernameOrEmail, password, ok := BasicAuth(req); ok { user, err := h.internalApi.AuthenticateUser(usernameOrEmail, password) if err != nil { say(w, http.StatusInternalServerError, "Error occured, please contact support") logger.Printf("%v, disconnecting...", err) return } if user != nil { username = user.Username logger.Printf("user authenticated as %v", username) } else { requestBasicAuth(w, "Invalid username or password") logger.Printf("invalid credentials, requesting basic auth, disconnecting...") return } } logger.Printf("processing request: %v", req.URL.String()) repoPath, slug, err := parsePath(req.URL.Path) if err != nil { say(w, http.StatusBadRequest, "Invalid command") logger.Printf("%v, disconnecting...", err) return } if (req.URL.Query().Get("service") == "git-receive-pack" || slug == "/git-receive-pack") && username == "" { requestBasicAuth(w, "Anonymous pushing not allowed") logger.Printf("denying anonymous push, requesting basic auth, disconnecting...") return } repoConfig, err := h.internalApi.GetRepoConfig(repoPath, username) if err != nil { if httpErr, ok := err.(*api.HttpError); ok { if httpErr.StatusCode == 403 { requestBasicAuth(w, "Access denied") logger.Printf("%v, requesting basic auth, disconnecting...", err) return } else if httpErr.StatusCode == 404 { say(w, http.StatusNotFound, "Invalid repository path") logger.Printf("%v, disconnecting...", err) return } } say(w, http.StatusInternalServerError, "Error occured, please contact support") logger.Printf("%v, disconnecting...", err) return } logger.Printf("full repo path: %v", repoConfig.FullPath) if !common.PreReceiveHookExists(repoConfig.FullPath) { say(w, http.StatusInternalServerError, "Error occurred, please contact support") logger.Printf("pre-receive hook for %v is missing or is not executable, aborting...", repoConfig.FullPath) return } translatedPath := repoConfig.FullPath + slug env := createHttpEnv(username, repoConfig, translatedPath) logger.Printf(`invoking git-http-backend with translated path "%v"`, translatedPath) execGitHttpBackend(env, w, req) logger.Printf("done") }