func NewSession(gateway *Gateway, connection *ssh.ServerConn) (*Session, error) { glog.V(1).Infof("new session: user = %s, remote = %v", connection.User(), connection.RemoteAddr()) return &Session{ gateway: gateway, connection: connection, user: connection.User(), remoteAddr: connection.RemoteAddr(), localAddr: connection.LocalAddr(), services: make(map[string]map[uint16]bool), lock: &sync.Mutex{}, active: true, created: time.Now(), used: time.Now(), channelsClosed: 0, bytesRead: 0, bytesWritten: 0, }, nil }
// NewClient initializes a new client func NewClient(conn *ssh.ServerConn, chans <-chan ssh.NewChannel, reqs <-chan *ssh.Request, server *Server) *Client { client := Client{ Idx: clientCounter, ClientID: conn.RemoteAddr().String(), ChannelIdx: 0, Conn: conn, Chans: chans, Reqs: reqs, Server: server, // Default ClientConfig, will be overwritten if a hook is used Config: &ClientConfig{ ImageName: strings.Replace(conn.User(), "_", "/", -1), RemoteUser: "******", AuthenticationMethod: "noauth", AuthenticationComment: "", AuthenticationAttempts: 0, Env: envhelper.Environment{}, Command: make([]string, 0), }, } if server.LocalUser != "" { client.Config.IsLocal = client.Config.ImageName == server.LocalUser } if _, found := server.ClientConfigs[client.ClientID]; !found { server.ClientConfigs[client.ClientID] = client.Config } client.Config = server.ClientConfigs[conn.RemoteAddr().String()] client.Config.Env.ApplyDefaults() clientCounter++ remoteAddr := strings.Split(client.ClientID, ":") log.Infof("Accepted %s for %s from %s port %s ssh2: %s", client.Config.AuthenticationMethod, conn.User(), remoteAddr[0], remoteAddr[1], client.Config.AuthenticationComment) return &client }
func (s *Server) handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel) { ch, reqs, err := newChan.Accept() if err != nil { log.Println("newChan.Accept failed:", err) return } defer ch.Close() for req := range reqs { switch req.Type { case "exec": fail := func(at string, err error) { log.Printf("%s failed: %s", at, err) ch.Stderr().Write([]byte("Internal error.\n")) } if req.WantReply { req.Reply(true, nil) } cmdline := string(req.Payload[4:]) cmdargs, err := shlex.Split(cmdline) if err != nil || len(cmdargs) != 2 { ch.Stderr().Write([]byte("Invalid arguments.\n")) return } if cmdargs[0] != "git-upload-pack" { ch.Stderr().Write([]byte("Only `git fetch` is supported.\n")) return } cmdargs[1] = strings.TrimSuffix(strings.TrimPrefix(cmdargs[1], "/"), ".git") if strings.Contains(cmdargs[1], "..") { ch.Stderr().Write([]byte("Invalid repo.\n")) return } cmd := exec.Command(s.Shell, "-c", cmdargs[0]+" '"+cmdargs[1]+"'") cmd.Dir = s.Dir cmd.Env = append(os.Environ(), "RECEIVE_USER="******"RECEIVE_REPO="+cmdargs[1], ) done, err := attachCmd(cmd, ch, ch.Stderr(), ch) if err != nil { fail("attachCmd", err) return } if err := cmd.Start(); err != nil { fail("cmd.Start", err) return } done.Wait() status, err := exitStatus(cmd.Wait()) if err != nil { fail("exitStatus", err) return } if _, err := ch.SendRequest("exit-status", false, ssh.Marshal(&status)); err != nil { fail("sendExit", err) } return case "env": if req.WantReply { req.Reply(true, nil) } } } }