Example #1
0
// HandleChannel handles one SSH channel
func (c *Client) HandleChannel(newChannel ssh.NewChannel) error {
	if newChannel.ChannelType() != "session" {
		log.Debugf("Unknown channel type: %s", newChannel.ChannelType())
		newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
		return nil
	}

	channel, requests, err := newChannel.Accept()
	if err != nil {
		log.Errorf("newChannel.Accept failed: %v", err)
		return err
	}
	c.ChannelIdx++
	log.Debugf("HandleChannel.channel (client=%d channel=%d)", c.Idx, c.ChannelIdx)

	log.Debug("Creating pty...")
	c.Pty, c.Tty, err = pty.Open()
	if err != nil {
		log.Errorf("pty.Open failed: %v", err)
		return nil
	}

	c.HandleChannelRequests(channel, requests)

	return nil
}
Example #2
0
// Handle is the SSH client entrypoint, it takes a net.Conn
// instance and handle all the ssh and ssh2docker stuff
func (s *Server) Handle(netConn net.Conn) error {
	if err := s.Init(); err != nil {
		return err
	}

	log.Debugf("Server.Handle netConn=%v", netConn)
	// Initialize a Client object
	conn, chans, reqs, err := ssh.NewServerConn(netConn, s.SshConfig)

	if err != nil {
		log.Infof("Received disconnect from %s: 11: Bye Bye [preauth]", netConn.RemoteAddr().String())
		return err
	}
	client := NewClient(conn, chans, reqs, s)

	// Handle requests
	if err = client.HandleRequests(); err != nil {
		return err
	}

	// Handle channels
	if err = client.HandleChannels(); err != nil {
		return err
	}
	return nil
}
Example #3
0
// functionVars returns the function ARN's as terraform -var arguments.
func (p *Proxy) functionVars() (args []string) {
	args = append(args, "-var")
	args = append(args, fmt.Sprintf("aws_region=%s", p.Region))

	args = append(args, "-var")
	args = append(args, fmt.Sprintf("apex_environment=%s", p.Environment))

	if p.Role != "" {
		args = append(args, "-var")
		args = append(args, fmt.Sprintf("apex_function_role=%s", p.Role))
	}

	for _, fn := range p.Functions {
		config, err := fn.GetConfig()
		if err != nil {
			log.Debugf("can't fetch function config: %s", err.Error())
			continue
		}

		args = append(args, "-var")
		args = append(args, fmt.Sprintf("apex_function_%s=%s", fn.Name, *config.Configuration.FunctionArn))
	}

	return args
}
Example #4
0
// DockerKill kills a container
func DockerKill(containerID string) error {
	cmd := exec.Command("docker", "kill", "-s", "9", containerID)
	_, err := cmd.CombinedOutput()
	if err != nil {
		return err
	}
	log.Debugf("Killed container: %q", containerID)
	return nil
}
Example #5
0
// DockerRemove removes a container
func DockerRemove(containerID string) error {
	cmd := exec.Command("docker", "rm", "-f", containerID)
	_, err := cmd.CombinedOutput()
	if err != nil {
		return err
	}
	log.Debugf("Deleted container: %q", containerID)
	return nil
}
Example #6
0
// HandleRequests handles SSH requests
func (c *Client) HandleRequests() error {
	go func(in <-chan *ssh.Request) {
		for req := range in {
			log.Debugf("HandleRequest: %v", req)
			if req.WantReply {
				req.Reply(false, nil)
			}
		}
	}(c.Reqs)
	return nil
}
Example #7
0
File: list.go Project: kujohn/apex
// outputTFvars format.
func outputTFvars() {
	for _, fn := range root.Project.Functions {
		config, err := fn.GetConfig()
		if err != nil {
			log.Debugf("can't fetch function config: %s", err.Error())
			continue
		}

		fmt.Printf("apex_function_%s=%q\n", fn.Name, *config.Configuration.FunctionArn)
	}
}
Example #8
0
File: infra.go Project: elizar/apex
// functionVars returns the function ARN's as terraform -var arguments.
func (p *Proxy) functionVars() (args []string) {
	for _, fn := range p.Functions {
		config, err := fn.GetConfig()
		if err != nil {
			log.Debugf("can't fetch function config: %s", err.Error())
			continue
		}

		args = append(args, "-var")
		args = append(args, fmt.Sprintf("apex_function_%s=%s", fn.Name, *config.Configuration.FunctionArn))
	}

	return args
}
Example #9
0
// CheckConfig checks if the ClientConfig has access
func (s *Server) CheckConfig(config *ClientConfig) error {
	if !config.Allowed && (s.PasswordAuthScript != "" || s.PublicKeyAuthScript != "") {
		log.Debugf("config.Allowed = false")
		return fmt.Errorf("Access not allowed")
	}

	if s.AllowedImages != nil {
		allowed := false
		for _, image := range s.AllowedImages {
			if image == config.ImageName {
				allowed = true
				break
			}
		}
		if !allowed {
			log.Warnf("Image is not allowed: %q", config.ImageName)
			return fmt.Errorf("Image not allowed")
		}
	}

	return nil
}
Example #10
0
// PublicKeyCallback is called when the user tries to authenticate using an SSH public key
func (s *Server) PublicKeyCallback(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
	username := conn.User()
	clientID := conn.RemoteAddr().String()
	keyText := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key)))
	log.Debugf("PublicKeyCallback: %q %q", username, keyText)
	// sessionID := conn.SessionID()

	config := s.ClientConfigs[clientID]
	if config == nil {
		s.ClientConfigs[clientID] = &ClientConfig{
			RemoteUser:             username,
			ImageName:              username,
			Keys:                   []string{},
			AuthenticationMethod:   "noauth",
			AuthenticationAttempts: 0,
			AuthenticationComment:  "",
			Env: make(envhelper.Environment, 0),
		}
	}
	config = s.ClientConfigs[clientID]
	config.Keys = append(config.Keys, keyText)
	return nil, s.CheckConfig(config)
}
Example #11
0
// Debugf level formatted message.
func Debugf(msg string, v ...interface{}) {
	apexlog.Debugf(msg, v...)
}
Example #12
0
func SetWinsize(fd uintptr, w, h uint32) {
	log.Debugf("Window resize '%dx%d'", w, h)
	ws := &Winsize{Width: uint16(w), Height: uint16(h)}
	syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws)))
}
Example #13
0
// PasswordCallback is called when the user tries to authenticate using a password
func (s *Server) PasswordCallback(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
	username := conn.User()
	clientID := conn.RemoteAddr().String()

	log.Debugf("PasswordCallback: %q %q", username, password)

	// map config in the memory
	config := s.ClientConfigs[clientID]
	if config == nil {
		s.ClientConfigs[clientID] = &ClientConfig{
			//Allowed: true,
			RemoteUser:             username,
			ImageName:              username,
			Keys:                   []string{},
			AuthenticationMethod:   "noauth",
			AuthenticationAttempts: 0,
			AuthenticationComment:  "",
			Env: make(envhelper.Environment, 0),
		}
		config = s.ClientConfigs[clientID]
	}

	// if there is a password callback
	if s.PasswordAuthScript == "" {
		return nil, s.CheckConfig(config)
	}

	config.AuthenticationAttempts++

	var output []byte
	switch {
	case strings.HasPrefix(s.PasswordAuthScript, "http://"),
		strings.HasPrefix(s.PasswordAuthScript, "https://"):
		input := struct {
			Username string `json:"username"`
			Password string `json:"password"`
		}{
			Username: username,
			Password: string(password),
		}
		resp, body, errs := gorequest.New().Type("json").Post(s.PasswordAuthScript).Send(input).End()
		if len(errs) > 0 {
			return nil, fmt.Errorf("gorequest errs: %v", errs)
		}
		if resp.StatusCode != 200 {
			return nil, fmt.Errorf("invalid status code: %d", resp.StatusCode)
		}
		output = []byte(body)
	default:
		script, err := homedir.Expand(s.PasswordAuthScript)
		if err != nil {
			log.Warnf("Failed to expandUser: %v", err)
			return nil, err
		}
		cmd := exec.Command(script, username, string(password))
		cmd.Env = config.Env.List()
		// FIXME: redirect stderr to log
		cmd.Stderr = os.Stderr
		output, err = cmd.Output()
		if err != nil {
			log.Warnf("Failed to execute password-auth-script: %v", err)
			return nil, err
		}
	}

	if err := json.Unmarshal(output, &config); err != nil {
		log.Warnf("Failed to unmarshal json %q: %v", string(output), err)
		return nil, err
	}

	if err := s.CheckConfig(config); err != nil {
		return nil, err
	}

	// success
	config.AuthenticationMethod = "password"
	return nil, nil
}
Example #14
0
// HandleChannelRequests handles channel requests
func (c *Client) HandleChannelRequests(channel ssh.Channel, requests <-chan *ssh.Request) {
	go func(in <-chan *ssh.Request) {
		defer c.Tty.Close()

		for req := range in {
			ok := false
			switch req.Type {
			case "shell":
				log.Debugf("HandleChannelRequests.req shell")
				if len(req.Payload) != 0 {
					break
				}
				ok = true

				entrypoint := ""
				if c.Config.EntryPoint != "" {
					entrypoint = c.Config.EntryPoint
				}

				var args []string
				if c.Config.Command != nil {
					args = c.Config.Command
				}

				if entrypoint == "" && len(args) == 0 {
					args = []string{c.Server.DefaultShell}
				}

				c.runCommand(channel, entrypoint, args)

			case "exec":
				command := string(req.Payload[4:])
				log.Debugf("HandleChannelRequests.req exec: %q", command)
				ok = true

				args, err := shlex.Split(command)
				if err != nil {
					log.Errorf("Failed to parse command %q: %v", command, args)
				}
				c.runCommand(channel, c.Config.EntryPoint, args)

			case "pty-req":
				ok = true
				c.Config.UseTTY = true
				termLen := req.Payload[3]
				c.Config.Env["TERM"] = string(req.Payload[4 : termLen+4])
				c.Config.Env["USE_TTY"] = "1"
				w, h := ttyhelper.ParseDims(req.Payload[termLen+4:])
				ttyhelper.SetWinsize(c.Pty.Fd(), w, h)
				log.Debugf("HandleChannelRequests.req pty-req: TERM=%q w=%q h=%q", c.Config.Env["TERM"], int(w), int(h))

			case "window-change":
				w, h := ttyhelper.ParseDims(req.Payload)
				ttyhelper.SetWinsize(c.Pty.Fd(), w, h)
				continue

			case "env":
				keyLen := req.Payload[3]
				key := string(req.Payload[4 : keyLen+4])
				valueLen := req.Payload[keyLen+7]
				value := string(req.Payload[keyLen+8 : keyLen+8+valueLen])
				log.Debugf("HandleChannelRequets.req 'env': %s=%q", key, value)
				c.Config.Env[key] = value

			default:
				log.Debugf("Unhandled request type: %q: %v", req.Type, req)
			}

			if req.WantReply {
				if !ok {
					log.Debugf("Declining %s request...", req.Type)
				}
				req.Reply(ok, nil)
			}
		}
	}(requests)
}
Example #15
0
func (c *Client) runCommand(channel ssh.Channel, entrypoint string, command []string) {
	var cmd *exec.Cmd
	var err error

	if c.Config.IsLocal {
		cmd = exec.Command(entrypoint, command...)
	} else {
		// checking if a container already exists for this user
		existingContainer := ""
		if !c.Server.NoJoin {
			cmd = exec.Command("docker", "ps", "--filter=label=ssh2docker", fmt.Sprintf("--filter=label=image=%s", c.Config.ImageName), fmt.Sprintf("--filter=label=user=%s", c.Config.RemoteUser), "--quiet", "--no-trunc")
			cmd.Env = c.Config.Env.List()
			buf, err := cmd.CombinedOutput()
			if err != nil {
				log.Warnf("docker ps ... failed: %v", err)
				channel.Close()
				return
			}
			existingContainer = strings.TrimSpace(string(buf))
		}

		// Opening Docker process
		if existingContainer != "" {
			// Attaching to an existing container
			args := []string{"exec"}
			if len(c.Config.DockerExecArgs) > 0 {
				args = append(args, c.Config.DockerExecArgs...)
				if err := c.alterArgs(args); err != nil {
					log.Errorf("Failed to execute template on args: %v", err)
					return
				}
			} else {
				inlineExec, err := c.alterArg(c.Server.DockerExecArgsInline)
				if err != nil {
					log.Errorf("Failed to execute template on arg: %v", err)
					return
				}
				execArgs, err := shlex.Split(inlineExec)
				if err != nil {
					log.Errorf("Failed to split arg %q: %v", inlineExec, err)
					return
				}
				args = append(args, execArgs...)
			}

			args = append(args, existingContainer)
			if entrypoint != "" {
				args = append(args, entrypoint)
			}
			args = append(args, command...)
			log.Debugf("Executing 'docker %s'", strings.Join(args, " "))
			cmd = exec.Command("docker", args...)
			cmd.Env = c.Config.Env.List()
		} else {
			// Creating and attaching to a new container
			args := []string{"run"}
			if len(c.Config.DockerRunArgs) > 0 {
				args = append(args, c.Config.DockerRunArgs...)
				if err := c.alterArgs(args); err != nil {
					log.Errorf("Failed to execute template on args: %v", err)
					return
				}
			} else {
				inlineRun, err := c.alterArg(c.Server.DockerRunArgsInline)
				if err != nil {
					log.Errorf("Failed to execute template on arg: %v", err)
					return
				}
				runArgs, err := shlex.Split(inlineRun)
				if err != nil {
					log.Errorf("Failed to split arg %q: %v", inlineRun, err)
					return
				}
				args = append(args, runArgs...)
			}

			args = append(args, "--label=ssh2docker", fmt.Sprintf("--label=user=%s", c.Config.RemoteUser), fmt.Sprintf("--label=image=%s", c.Config.ImageName))
			if c.Config.User != "" {
				args = append(args, "-u", c.Config.User)
			}
			if entrypoint != "" {
				args = append(args, "--entrypoint", entrypoint)
			}

			args = append(args, c.Config.ImageName)
			args = append(args, command...)
			log.Debugf("Executing 'docker %s'", strings.Join(args, " "))
			cmd = exec.Command("docker", args...)
			cmd.Env = c.Config.Env.List()
		}
	}

	if c.Server.Banner != "" {
		banner := c.Server.Banner
		banner = strings.Replace(banner, "\r", "", -1)
		banner = strings.Replace(banner, "\n", "\n\r", -1)
		fmt.Fprintf(channel, "%s\n\r", banner)
	}

	cmd.Stdout = channel
	cmd.Stdin = channel
	cmd.Stderr = channel
	var wg sync.WaitGroup
	if c.Config.UseTTY {
		cmd.Stdout = c.Tty
		cmd.Stdin = c.Tty
		cmd.Stderr = c.Tty

		wg.Add(1)
		go func() {
			io.Copy(channel, c.Pty)
			wg.Done()
		}()
		wg.Add(1)
		go func() {
			io.Copy(c.Pty, channel)
			wg.Done()
		}()
		defer wg.Wait()
	}
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setctty: c.Config.UseTTY,
		Setsid:  true,
	}

	err = cmd.Start()
	if err != nil {
		log.Warnf("cmd.Start failed: %v", err)
		channel.Close()
		return
	}

	if err := cmd.Wait(); err != nil {
		log.Warnf("cmd.Wait failed: %v", err)
	}
	channel.Close()
	log.Debugf("cmd.Wait done")
}
Example #16
0
// KeyboardInteractiveCallback is called after PublicKeyCallback
func (s *Server) KeyboardInteractiveCallback(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
	username := conn.User()
	clientID := conn.RemoteAddr().String()
	log.Debugf("KeyboardInteractiveCallback: %q", username)

	config := s.ClientConfigs[clientID]
	if config == nil {
		s.ClientConfigs[clientID] = &ClientConfig{
			RemoteUser:             username,
			ImageName:              username,
			Keys:                   []string{},
			AuthenticationMethod:   "noauth",
			AuthenticationAttempts: 0,
			AuthenticationComment:  "",
			Env: make(envhelper.Environment, 0),
		}
	}
	config = s.ClientConfigs[clientID]

	if len(config.Keys) == 0 {
		log.Warnf("No user keys, continuing with password authentication")
		return nil, s.CheckConfig(config)
	}

	if s.PublicKeyAuthScript == "" {
		log.Debugf("%d keys received, but no hook script, continuing", len(config.Keys))
		return nil, s.CheckConfig(config)
	}

	config.AuthenticationAttempts++
	log.Debugf("%d keys received, trying to authenticate using publickey hook", len(config.Keys))

	var output []byte
	switch {
	case strings.HasPrefix(s.PublicKeyAuthScript, "http://"),
		strings.HasPrefix(s.PublicKeyAuthScript, "https://"):
		input := struct {
			Username   string   `json:"username"`
			Publickeys []string `json:"publickeys"`
		}{
			Username:   username,
			Publickeys: config.Keys,
		}
		resp, body, errs := gorequest.New().Type("json").Post(s.PublicKeyAuthScript).Send(input).End()
		if len(errs) > 0 {
			return nil, fmt.Errorf("gorequest errs: %v", errs)
		}
		if resp.StatusCode != 200 {
			return nil, fmt.Errorf("invalid status code: %d", resp.StatusCode)
		}
		output = []byte(body)
	default:
		script, err := homedir.Expand(s.PublicKeyAuthScript)
		if err != nil {
			log.Warnf("Failed to expandUser: %v", err)
			return nil, err
		}
		cmd := exec.Command(script, append([]string{username}, config.Keys...)...)
		cmd.Env = config.Env.List()
		// FIXME: redirect stderr to log
		cmd.Stderr = os.Stderr
		output, err = cmd.Output()
		if err != nil {
			log.Warnf("Failed to execute publickey-auth-script: %v", err)
			return nil, err
		}
	}

	if err := json.Unmarshal(output, &config); err != nil {
		log.Warnf("Failed to unmarshal json %q: %v", string(output), err)
		return nil, err
	}

	if err := s.CheckConfig(config); err != nil {
		return nil, err
	}

	// success
	config.AuthenticationMethod = "publickey"
	return nil, nil
}
Example #17
0
		if len(args) == 0 && !followAll {
			cmd.Help()
			return
		}

		// Set up MQTT Client
		setupMQTT()

		// Subscribe to device topics
		switch {
		case followAll:
			devices = []string{"+"}
			log.Debug("Will subscribe to all devices")
		case len(args) == 1:
			devices = args
			log.Debugf("Will subscribe to device %s", devices[0])
		default:
			devices = args
			log.Debugf("Will subscribe to %d devices", len(devices))
		}

		// Connect
		connectMQTT()

		// Keep running...
		for {
			time.Sleep(60 * time.Second)
		}

	},
}