Exemple #1
0
func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string) error {
	var req []byte
	switch k := s.(type) {
	case *rsa.PrivateKey:
		if len(k.Primes) != 2 {
			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
		}
		k.Precompute()
		req = ssh.Marshal(rsaCertMsg{
			Type:      cert.Type(),
			CertBytes: cert.Marshal(),
			D:         k.D,
			Iqmp:      k.Precomputed.Qinv,
			P:         k.Primes[0],
			Q:         k.Primes[1],
			Comments:  comment,
		})
	case *dsa.PrivateKey:
		req = ssh.Marshal(dsaCertMsg{
			Type:      cert.Type(),
			CertBytes: cert.Marshal(),
			X:         k.X,
			Comments:  comment,
		})
	case *ecdsa.PrivateKey:
		req = ssh.Marshal(ecdsaCertMsg{
			Type:      cert.Type(),
			CertBytes: cert.Marshal(),
			D:         k.D,
			Comments:  comment,
		})
	default:
		return fmt.Errorf("agent: unsupported key type %T", s)
	}

	signer, err := ssh.NewSignerFromKey(s)
	if err != nil {
		return err
	}
	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
		return errors.New("agent: signer and cert have different public key")
	}

	resp, err := c.call(req)
	if err != nil {
		return err
	}
	if _, ok := resp.(*successAgentMsg); ok {
		return nil
	}
	return errors.New("agent: failure")
}
Exemple #2
0
// Insert adds a private key to the agent.
func (c *client) insertKey(s interface{}, comment string) error {
	var req []byte
	switch k := s.(type) {
	case *rsa.PrivateKey:
		if len(k.Primes) != 2 {
			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
		}
		k.Precompute()
		req = ssh.Marshal(rsaKeyMsg{
			Type:     ssh.KeyAlgoRSA,
			N:        k.N,
			E:        big.NewInt(int64(k.E)),
			D:        k.D,
			Iqmp:     k.Precomputed.Qinv,
			P:        k.Primes[0],
			Q:        k.Primes[1],
			Comments: comment,
		})
	case *dsa.PrivateKey:
		req = ssh.Marshal(dsaKeyMsg{
			Type:     ssh.KeyAlgoDSA,
			P:        k.P,
			Q:        k.Q,
			G:        k.G,
			Y:        k.Y,
			X:        k.X,
			Comments: comment,
		})
	case *ecdsa.PrivateKey:
		nistID := fmt.Sprintf("nistp%d", k.Params().BitSize)
		req = ssh.Marshal(ecdsaKeyMsg{
			Type:     "ecdsa-sha2-" + nistID,
			Curve:    nistID,
			KeyBytes: elliptic.Marshal(k.Curve, k.X, k.Y),
			D:        k.D,
			Comments: comment,
		})
	default:
		return fmt.Errorf("agent: unsupported key type %T", s)
	}
	resp, err := c.call(req)
	if err != nil {
		return err
	}
	if _, ok := resp.(*successAgentMsg); ok {
		return nil
	}
	return errors.New("agent: failure")
}
Exemple #3
0
func marshalKey(k *Key) []byte {
	var record struct {
		Blob    []byte
		Comment string
	}
	record.Blob = k.Marshal()
	record.Comment = k.Comment

	return ssh.Marshal(&record)
}
Exemple #4
0
func (s *server) processRequestBytes(reqData []byte) []byte {
	rep, err := s.processRequest(reqData)
	if err != nil {
		if err != errLocked {
			// TODO(hanwen): provide better logging interface?
			log.Printf("agent %d: %v", reqData[0], err)
		}
		return []byte{agentFailure}
	}

	if err == nil && rep == nil {
		return []byte{agentSuccess}
	}

	return ssh.Marshal(rep)
}
Exemple #5
0
func (s *sshServer) run(c *gc.C) {
	netconn, err := s.listener.Accept()
	c.Assert(err, gc.IsNil)
	defer func() {
		err = netconn.Close()
		c.Assert(err, gc.IsNil)
	}()
	conn, chans, reqs, err := cryptossh.NewServerConn(netconn, s.cfg)
	c.Assert(err, gc.IsNil)
	s.client = cryptossh.NewClient(conn, chans, reqs)
	var wg sync.WaitGroup
	defer wg.Wait()
	sessionChannels := s.client.HandleChannelOpen("session")
	c.Assert(sessionChannels, gc.NotNil)
	for newChannel := range sessionChannels {
		c.Assert(newChannel.ChannelType(), gc.Equals, "session")
		channel, reqs, err := newChannel.Accept()
		c.Assert(err, gc.IsNil)
		wg.Add(1)
		go func() {
			defer wg.Done()
			defer channel.Close()
			for req := range reqs {
				switch req.Type {
				case "exec":
					c.Assert(req.WantReply, jc.IsTrue)
					n := binary.BigEndian.Uint32(req.Payload[:4])
					command := string(req.Payload[4 : n+4])
					c.Assert(command, gc.Equals, testCommandFlat)
					req.Reply(true, nil)
					channel.Write([]byte("abc value\n"))
					_, err := channel.SendRequest("exit-status", false, cryptossh.Marshal(&struct{ n uint32 }{0}))
					c.Assert(err, gc.IsNil)
					return
				default:
					c.Fatalf("Unexpected request type: %v", req.Type)
				}
			}
		}()
	}
}
Exemple #6
0
// Sign has the agent sign the data using a protocol 2 key as defined
// in [PROTOCOL.agent] section 2.6.2.
func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
	req := ssh.Marshal(signRequestAgentMsg{
		KeyBlob: key.Marshal(),
		Data:    data,
	})

	msg, err := c.call(req)
	if err != nil {
		return nil, err
	}

	switch msg := msg.(type) {
	case *signResponseAgentMsg:
		var sig ssh.Signature
		if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil {
			return nil, err
		}

		return &sig, nil
	case *failureAgentMsg:
		return nil, errors.New("agent: failed to sign challenge")
	}
	panic("unreachable")
}
Exemple #7
0
func Echo(ws *websocket.Conn) {
	ip := ws.Request().URL.Query().Get("ip")
	fmt.Println("conn ip", ip)

	port := 22
	username := "******"
	password := "******"

	authMethods := []ssh.AuthMethod{}
	keyboardInteractiveChallenge := func(
		user,
		instruction string,
		questions []string,
		echos []bool,
	) (answers []string, err error) {
		if len(questions) == 0 {
			return []string{}, nil
		}
		return []string{password}, nil
	}
	authMethods = append(authMethods, ssh.KeyboardInteractive(keyboardInteractiveChallenge))
	authMethods = append(authMethods, ssh.Password(password))
	sshConfig := &ssh.ClientConfig{
		User: username,
		Auth: authMethods,
	}
	sshConfig.Config.SetDefaults()
	sshConfig.Config.Ciphers = append(sshConfig.Config.Ciphers, "arcfour")
	fmt.Println(sshConfig.Config.Ciphers)

	conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%v", ip, port), sshConfig)
	if err != nil {
		fmt.Println("1Unable to connect %s", err)
		return
	}
	defer conn.Close()
	cmd, err := conn.NewSession()
	if err != nil {
		fmt.Println("Can't NewSession", err)
		return
	}
	modes := ssh.TerminalModes{
		ssh.ECHO:          1,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	// Request pseudo terminal
	if err := cmd.RequestPty("xterm", 80, 40, modes); err != nil {
		fmt.Println("request for pseudo terminal failed: %s", err)
	}

	cmd.Stdout = &Writer{Conn: ws}
	cmd.Stderr = &Writer{Conn: ws}
	stdin, err := cmd.StdinPipe()
	if err != nil {
		fmt.Println("Can't get stdin")
		return
	}

	err = cmd.Shell()
	if err != nil {
		fmt.Println("Can't start cmd:", err)
		return
	}

	for {
		var reply string

		if err = websocket.Message.Receive(ws, &reply); err != nil {
			fmt.Println("Can't receive")
			break
		}

		fmt.Println("Received back from client: " + reply)

		request := make(map[string]interface{}, 0)
		err := json.Unmarshal([]byte(reply), &request)
		fmt.Println("Received back from client: ", request)
		if err == nil {
			switch request["cmd"].(string) {
			case "window-change":
				w, _ := strconv.Atoi(fmt.Sprint(request["width"]))
				h, _ := strconv.Atoi(fmt.Sprint(request["height"]))
				if h > 0 && w > 0 {
					req := ptyWindowChangeMsg{
						Columns: uint32(w),
						Rows:    uint32(h),
						Width:   uint32(w * 8),
						Height:  uint32(h * 8),
					}
					fmt.Println("Send window-change:", req)
					ok, err := cmd.SendRequest("window-change", true, ssh.Marshal(&req))
					// Request pseudo terminal
					if err == nil && !ok {
						fmt.Println("request for pseudo terminal failed: %v", err)
					}
				}
			case "shell":
				fmt.Println("Write:", request["input"])
				stdin.Write([]byte(request["input"].(string)))

			case "ping":
				req := ptyEnvMsg{Name: "__keep_alive__", Value: "1"}
				cmd.SendRequest("env", true, ssh.Marshal(&req))

				resp := WsResponse{Command: "pong", Parameters: map[string]interface{}{}}
				json_bytes, err := json.Marshal(resp)
				if err != nil {
					fmt.Println("Marshal error:", err)
					return
				}
				websocket.Message.Send(ws, string(json_bytes))
			}
		} else {
			fmt.Println(err)
		}
	}
}
Exemple #8
0
func (c *client) Unlock(passphrase []byte) error {
	req := ssh.Marshal(&agentUnlockMsg{
		Passphrase: passphrase,
	})
	return c.simpleCall(req)
}
Exemple #9
0
func (c *client) Remove(key ssh.PublicKey) error {
	req := ssh.Marshal(&agentRemoveIdentityMsg{
		KeyBlob: key.Marshal(),
	})
	return c.simpleCall(req)
}
Exemple #10
0
func 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-receive-pack" {
				ch.Stderr().Write([]byte("Only `git push` 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
			}

			if err := ensureCacheRepo(cmdargs[1]); err != nil {
				fail("ensureCacheRepo", err)
				return
			}
			cmd := exec.Command("git-shell", "-c", cmdargs[0]+" '"+cmdargs[1]+"'")
			cmd.Dir = *repoPath
			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)
			}
		}
	}
}
Exemple #11
0
func (s *server) processRequest(data []byte) (interface{}, error) {
	switch data[0] {
	case agentRequestV1Identities:
		return &agentV1IdentityMsg{0}, nil
	case agentRemoveIdentity:
		var req agentRemoveIdentityMsg
		if err := ssh.Unmarshal(data, &req); err != nil {
			return nil, err
		}

		var wk wireKey
		if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
			return nil, err
		}

		return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob})

	case agentRemoveAllIdentities:
		return nil, s.agent.RemoveAll()

	case agentLock:
		var req agentLockMsg
		if err := ssh.Unmarshal(data, &req); err != nil {
			return nil, err
		}

		return nil, s.agent.Lock(req.Passphrase)

	case agentUnlock:
		var req agentLockMsg
		if err := ssh.Unmarshal(data, &req); err != nil {
			return nil, err
		}
		return nil, s.agent.Unlock(req.Passphrase)

	case agentSignRequest:
		var req signRequestAgentMsg
		if err := ssh.Unmarshal(data, &req); err != nil {
			return nil, err
		}

		var wk wireKey
		if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
			return nil, err
		}

		k := &Key{
			Format: wk.Format,
			Blob:   req.KeyBlob,
		}

		sig, err := s.agent.Sign(k, req.Data) //  TODO(hanwen): flags.
		if err != nil {
			return nil, err
		}
		return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil
	case agentRequestIdentities:
		keys, err := s.agent.List()
		if err != nil {
			return nil, err
		}

		rep := identitiesAnswerAgentMsg{
			NumKeys: uint32(len(keys)),
		}
		for _, k := range keys {
			rep.Keys = append(rep.Keys, marshalKey(k)...)
		}
		return rep, nil
	case agentAddIdentity:
		return nil, s.insertIdentity(data)
	}

	return nil, fmt.Errorf("unknown opcode %d", data[0])
}
Exemple #12
0
// handleChannel runs the needed commands on a given SSH server connection against the user
// that opened the communication channel.
func 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":
			assert := func(at string, err error) bool {
				if err != nil {
					log.Printf("%s failed: %s", at, err)
					ch.Stderr().Write([]byte("Internal error.\n"))
					return true
				}
				return false
			}

			defer func() {
				log.Printf("Connection lost from %s", conn.RemoteAddr().String())
			}()

			if req.WantReply {
				req.Reply(true, nil)
			}

			cmdline := string(req.Payload[4:])

			cmdargs, err := shlex.Split(cmdline)
			if assert("shlex.Split", err) {
				return
			}

			if len(cmdargs) != 2 {
				ch.Stderr().Write([]byte("Invalid arguments.\n"))
				return
			}

			if cmdargs[0] != "git-receive-pack" {
				ch.Stderr().Write([]byte("Only `git push` is supported.\n"))
				return
			}

			user := conn.Permissions.Extensions["user"]
			reponame := strings.TrimSuffix(strings.TrimPrefix(cmdargs[1], "/"), ".git")

			log.Printf("Push from %s at %s", user, reponame)

			if err := makeGitRepo(reponame); err != nil {
				ch.Stderr().Write([]byte("Error: " + err.Error()))
				return
			}

			log.Printf("Writing hooks...")

			err = ioutil.WriteFile(reponame+"/hooks/pre-receive", []byte(`#!/bin/bash
strip_remote_prefix() {
	sed -u "s/^/"$'\e[1G'"/"
}

set -eo pipefail; while read oldrev newrev refname; do
	/app/cloudchaser -etcd-machine `+*etcduplink+` pre $newrev 2>&1 | strip_remote_prefix
done`), 0755)
			if err != nil {
				return
			}

			err = ioutil.WriteFile(reponame+"/hooks/post-receive", []byte(`#!/bin/bash

strip_remote_prefix() {
	sed -u "s/^/"$'\e[1G'"/"
}

set -eo pipefail; while read oldrev newrev refname; do
	/app/builder -etcd-host `+*etcduplink+` $REPO ${refname##*/} $newrev 2>&1 | strip_remote_prefix
done`), 0755)
			if err != nil {
				return
			}

			log.Printf("Doing git receive...")

			receive := exec.Command("git-receive-pack", reponame)
			if conn.Permissions.Extensions["environ"] != "" {
				receive.Env = append(receive.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
			}

			receive.Env = append(receive.Env, "USER="******"user"])
			receive.Env = append(receive.Env, "REMOTE_HOST="+conn.RemoteAddr().String())
			receive.Env = append(receive.Env, "REPO="+reponame)

			done, err := attachCmd(receive, ch, ch.Stderr(), ch)
			if err != nil {
				ch.Stderr().Write([]byte("Error: " + err.Error()))
				return
			}

			if assert("receive.Start", receive.Start()) {
				return
			}

			done.Wait()

			log.Printf("Receive done")

			status, rcvErr := exitStatus(receive.Wait())
			if rcvErr != nil {
				ch.Stderr().Write([]byte("Error: " + rcvErr.Error()))
				return
			}

			_, err = ch.SendRequest("exit-status", false, ssh.Marshal(&status))
			assert("sendExit", err)

			return

		case "env":
			if req.WantReply {
				req.Reply(true, nil)
			}
		default:
			return
		}
	}
}
Exemple #13
0
func processRequests(conn *ssh.ServerConn, reqs <-chan *ssh.Request) {
	for req := range reqs {
		if req.Type != "tcpip-forward" {
			// accept only tcpip-forward requests
			if req.WantReply {
				req.Reply(false, nil)
			}
			continue
		}
		type channelForwardMsg struct {
			Laddr string
			Lport uint32
		}
		m := &channelForwardMsg{}
		ssh.Unmarshal(req.Payload, m)

		privateBytes, err := ioutil.ReadFile(appConfig.RemotePrivateKeyPath)
		if err != nil {
			log.Fatal(err.Error())
		}

		signer, err := ssh.ParsePrivateKey(privateBytes)
		if err != nil {
			log.Fatal(err.Error())
		}

		config := &ssh.ClientConfig{
			User: appConfig.RemoteSSHUser,
			Auth: []ssh.AuthMethod{
				ssh.PublicKeys(signer),
			},
		}
		sshClientConn, err := ssh.Dial("tcp", appConfig.RemoteSSHAddr, config)
		if err != nil {
			log.Fatal(err.Error())
		}

		type channelOpenForwardMsg struct {
			raddr string
			rport uint32
			laddr string
			lport uint32
		}

		fm := &channelOpenForwardMsg{
			raddr: "localhost",
			rport: m.Lport,
			laddr: "localhost",
			lport: m.Lport,
		}
		channel, reqs, err := conn.Conn.OpenChannel("forwarded-tcpip", ssh.Marshal(fm))
		if err != nil {
			log.Fatal(err.Error())
		}

		go ssh.DiscardRequests(reqs)

		portListener, err := sshClientConn.Listen("tcp", appConfig.RemoteForwardAddress)
		if err != nil {
			log.Fatal(err.Error())
		}

		go func() {
			for {
				sshConn, err := portListener.Accept()
				if err != nil {
					log.Fatal(err.Error())
				}

				// Copy localConn.Reader to sshConn.Writer
				go func(sshConn net.Conn) {
					_, err := io.Copy(sshConn, channel)
					if err != nil {
						log.Println("io.Copy failed: %v", err)
						sshConn.Close()
						return
					}
				}(sshConn)

				// Copy sshConn.Reader to localConn.Writer
				go func(sshConn net.Conn) {
					_, err := io.Copy(channel, sshConn)
					if err != nil {
						log.Println("io.Copy failed: %v", err)
						sshConn.Close()
						return
					}
				}(sshConn)
			}
		}()
		req.Reply(true, nil)
	}
}