diff --git a/base/aaa/sess.go b/base/aaa/sess.go index 2b33531a..568a716b 100644 --- a/base/aaa/sess.go +++ b/base/aaa/sess.go @@ -21,7 +21,7 @@ func _sess_check(m *ice.Message, sessid string) { if m.Warn(kit.Time(kit.Format(value[mdb.TIME])) < kit.Time(m.Time()), ice.ErrNotValid, sessid) { return // 会话超时 } - m.Logs(ice.LOG_AUTH, + m.Auth( USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]), USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]), USERNICK, m.Option(ice.MSG_USERNICK, value[USERNICK]), diff --git a/base/aaa/user.go b/base/aaa/user.go index 21cd4455..db47d657 100644 --- a/base/aaa/user.go +++ b/base/aaa/user.go @@ -34,7 +34,7 @@ func _user_login(m *ice.Message, name, word string) { if m.Warn(word != "" && word != kit.Format(kit.Value(value, kit.Keys(mdb.EXTRA, PASSWORD))), ice.ErrNotRight) { return } - m.Logs(ice.LOG_AUTH, + m.Auth( USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]), USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]), USERNICK, m.Option(ice.MSG_USERNICK, value[USERNICK]), diff --git a/base/tcp/host.go b/base/tcp/host.go index cc4f3295..fa9a360a 100644 --- a/base/tcp/host.go +++ b/base/tcp/host.go @@ -54,7 +54,7 @@ func _islocalhost(m *ice.Message, ip string) (ok bool) { return false } if mdb.Richs(m, HOST, kit.Keym(aaa.WHITE), ip, nil) != nil { - m.Logs(ice.LOG_AUTH, aaa.WHITE, ip) + m.Auth(aaa.WHITE, ip) return true } return false diff --git a/base/web/space.go b/base/web/space.go index 27f74867..3cc42f92 100644 --- a/base/web/space.go +++ b/base/web/space.go @@ -102,7 +102,7 @@ func _space_handle(m *ice.Message, safe bool, frame *Frame, c *websocket.Conn, n if msg.Option(ice.MSG_USERROLE) == aaa.VOID && ice.Info.UserName == aaa.TECH { msg.Option(ice.MSG_USERROLE, aaa.TECH) // 演示空间 } - msg.Logs(ice.LOG_AUTH, aaa.USERROLE, msg.Option(ice.MSG_USERROLE), aaa.USERNAME, msg.Option(ice.MSG_USERNAME)) + msg.Auth(aaa.USERROLE, msg.Option(ice.MSG_USERROLE), aaa.USERNAME, msg.Option(ice.MSG_USERNAME)) msg.Go(func() { _space_exec(msg, source, target, c, name) }) continue } diff --git a/core/chat/action.go b/core/chat/action.go index f6c80b91..b181ec56 100644 --- a/core/chat/action.go +++ b/core/chat/action.go @@ -45,7 +45,7 @@ func _action_auth(m *ice.Message, share string) *ice.Message { msg.Append(mdb.TYPE, "") return msg // 共享过期 } - m.Logs(ice.LOG_AUTH, + m.Auth( aaa.USERROLE, m.Option(ice.MSG_USERROLE, msg.Append(aaa.USERROLE)), aaa.USERNAME, m.Option(ice.MSG_USERNAME, msg.Append(aaa.USERNAME)), aaa.USERNICK, m.Option(ice.MSG_USERNICK, msg.Append(aaa.USERNICK)), diff --git a/logs.go b/logs.go index ef61933b..688aa177 100644 --- a/logs.go +++ b/logs.go @@ -18,6 +18,10 @@ func (m *Message) join(arg ...Any) (string, []Any) { meta = append(meta, v) i-- continue + case []string: + list = append(list, v...) + i-- + continue } if key := strings.TrimSpace(kit.Format(arg[i])); i == len(arg)-1 { list = append(list, key) @@ -72,6 +76,10 @@ func (m *Message) Logs(level string, arg ...Any) *Message { return m.log(level, str, meta...) } +func (m *Message) Auth(arg ...Any) *Message { + str, meta := m.join(arg...) + return m.log(LOG_AUTH, str, meta...) +} func (m *Message) Cost(arg ...Any) *Message { str, meta := m.join(arg...) if len(arg) == 0 { diff --git a/misc/ssh/channel.go b/misc/ssh/channel.go index 516a7ace..26b72f02 100644 --- a/misc/ssh/channel.go +++ b/misc/ssh/channel.go @@ -2,13 +2,9 @@ package ssh import ( "io" - "net" - "os/exec" "strings" - "golang.org/x/crypto/ssh" ice "shylinux.com/x/icebergs" - "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/mdb" psh "shylinux.com/x/icebergs/base/ssh" @@ -16,27 +12,7 @@ import ( kit "shylinux.com/x/toolkits" ) -func _ssh_exec(m *ice.Message, cmd string, arg []string, env []string, input io.Reader, output io.Writer, done func()) { - m.Logs(mdb.IMPORT, CMD, cmd, ARG, arg, ENV, env) - c := exec.Command(cmd, arg...) - // c.Env = env - - c.Stdin = input - c.Stdout = output - c.Stderr = output - - m.Assert(c.Start()) - - m.Go(func() { - defer done() - c.Process.Wait() - }) -} -func _ssh_close(m *ice.Message, c net.Conn, channel ssh.Channel) { - defer channel.Close() - channel.Write([]byte(m.Conf(SERVICE, kit.Keym(GOODBYE)))) -} -func _ssh_watch(m *ice.Message, meta ice.Maps, h string, input io.Reader, output io.Writer) { +func _ssh_watch(m *ice.Message, h string, output io.Writer, input io.Reader) io.Closer { r, w := io.Pipe() bio := io.TeeReader(input, w) m.Go(func() { io.Copy(output, r) }) @@ -52,8 +28,7 @@ func _ssh_watch(m *ice.Message, meta ice.Maps, h string, input io.Reader, output switch buf[i] { case '\r', '\n': cmd := strings.TrimSpace(string(buf[:i])) - m.Logs(mdb.IMPORT, tcp.HOSTNAME, meta[tcp.HOSTNAME], aaa.USERNAME, meta[aaa.USERNAME], CMD, cmd) - m.Cmdy(mdb.INSERT, CHANNEL, kit.Keys(mdb.HASH, h), mdb.LIST, mdb.TYPE, CMD, mdb.TEXT, cmd) + m.Cmdy(mdb.INSERT, m.Prefix(CHANNEL), kit.Keys(mdb.HASH, h), mdb.LIST, mdb.TYPE, CMD, mdb.TEXT, cmd) i = 0 default: if i += n; i >= ice.MOD_BUFS { @@ -62,6 +37,7 @@ func _ssh_watch(m *ice.Message, meta ice.Maps, h string, input io.Reader, output } } }) + return r } const CHANNEL = "channel" @@ -70,34 +46,24 @@ func init() { psh.Index.MergeCommands(ice.Commands{ CHANNEL: {Name: "channel hash id auto", Help: "通道", Actions: ice.MergeActions(ice.Actions{ ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { - mdb.Richs(m, CHANNEL, "", mdb.FOREACH, func(key string, value ice.Map) { - kit.Value(value, kit.Keym(mdb.STATUS), tcp.CLOSE) + mdb.HashSelectUpdate(m, mdb.FOREACH, func(value ice.Map) { + kit.Value(value, mdb.STATUS, tcp.CLOSE) }) }}, - mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { - m.OptionFields(m.Config(mdb.FIELD)) - m.Cmdy(mdb.PRUNES, SERVICE, "", mdb.HASH, mdb.STATUS, tcp.ERROR) - m.Cmdy(mdb.PRUNES, CHANNEL, "", mdb.HASH, mdb.STATUS, tcp.CLOSE) - }}, - mdb.REPEAT: {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(CHANNEL, ctx.ACTION, ctx.COMMAND, CMD, m.Option(mdb.TEXT)) - }}, ctx.COMMAND: {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.INSERT, CHANNEL, kit.Keys(mdb.HASH, m.Option(mdb.HASH)), - mdb.LIST, mdb.TYPE, CMD, mdb.TEXT, m.Option(CMD)) - mdb.Richs(m, CHANNEL, "", m.Option(mdb.HASH), func(key string, value ice.Map) { - if w, ok := kit.Value(value, kit.Keym(INPUT)).(io.Writer); ok { - w.Write([]byte(m.Option(CMD) + ice.NL)) - } - }) - m.ProcessRefresh300ms() + mdb.ZoneInsert(m, m.OptionSimple(mdb.HASH), mdb.TYPE, CMD, mdb.TEXT, m.Option(CMD)) + if w, ok := mdb.HashTarget(m, m.Option(mdb.HASH), nil).(io.Writer); ok { + w.Write([]byte(m.Option(CMD) + ice.NL)) + m.Sleep300ms() + } }}, - }, mdb.HashAction(mdb.FIELD, "time,hash,status,username,hostport,tty,count")), Hand: func(m *ice.Message, arg ...string) { + mdb.REPEAT: {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy("", ctx.COMMAND, CMD, m.Option(mdb.TEXT)) + }}, + }, mdb.HashAction(mdb.FIELD, "time,hash,status,tty,count,username,hostport")), Hand: func(m *ice.Message, arg ...string) { if len(arg) == 0 { // 通道列表 m.Action(mdb.PRUNES) - mdb.HashSelect(m, arg...) - m.Set(ice.MSG_APPEND, ctx.ACTION) - m.Tables(func(value ice.Maps) { + mdb.HashSelect(m, arg...).Tables(func(value ice.Maps) { m.PushButton(kit.Select("", ctx.COMMAND, value[mdb.STATUS] == tcp.OPEN), mdb.REMOVE) }) return diff --git a/misc/ssh/service.go b/misc/ssh/service.go index 705b27cb..1c76aaac 100644 --- a/misc/ssh/service.go +++ b/misc/ssh/service.go @@ -5,10 +5,13 @@ import ( "encoding/base64" "errors" "fmt" + "io" "net" + "os" "strings" "golang.org/x/crypto/ssh" + pty "shylinux.com/x/creackpty" ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/cli" @@ -27,20 +30,20 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig { config := &ssh.ServerConfig{ PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight) - if tcp.IsLocalHost(m, strings.Split(conn.RemoteAddr().String(), ice.DF)[0]) { - m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User()) + if tcp.IsLocalHost(m, strings.Split(meta[tcp.HOSTPORT], ice.DF)[0]) { + m.Auth(aaa.USERNAME, meta[aaa.USERNAME], tcp.HOSTPORT, meta[tcp.HOSTPORT]) err = nil // 本机用户 } else { mdb.ZoneSelectCB(m, h, func(value ice.Maps) { - if !strings.HasPrefix(value[mdb.NAME], conn.User()+"@") { + if !strings.HasPrefix(value[mdb.NAME], meta[aaa.USERNAME]+"@") { return } if s, e := base64.StdEncoding.DecodeString(value[mdb.TEXT]); !m.Warn(e) { if pub, e := ssh.ParsePublicKey([]byte(s)); !m.Warn(e) { if bytes.Compare(pub.Marshal(), key.Marshal()) == 0 { - m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), tcp.HOSTNAME, value[mdb.NAME]) meta[tcp.HOSTNAME] = kit.Select("", kit.Split(value[mdb.NAME], "@"), 1) + m.Auth(aaa.USERNAME, meta[aaa.USERNAME], tcp.HOSTPORT, meta[tcp.HOSTPORT], tcp.HOSTNAME, meta[tcp.HOSTNAME]) err = nil // 认证成功 } } @@ -51,16 +54,12 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig { }, PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight) - if aaa.UserLogin(m, conn.User(), string(password)) { - m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User(), aaa.PASSWORD, strings.Repeat("*", len(string(password)))) + if aaa.UserLogin(m, meta[aaa.USERNAME], string(password)) { + m.Auth(aaa.USERNAME, meta[aaa.USERNAME], tcp.HOSTPORT, meta[tcp.HOSTPORT], aaa.PASSWORD, strings.Repeat("*", len(string(password)))) err = nil // 密码登录 } return &ssh.Permissions{Extensions: meta}, err }, - BannerCallback: func(conn ssh.ConnMetadata) string { - m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User()) - return m.Config(WELCOME) - }, } if key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, kit.HomePath(m.Option(PRIVATE))))); m.Assert(err) { @@ -73,7 +72,6 @@ func _ssh_accept(m *ice.Message, h string, c net.Conn) { if m.Warn(err) { return } - m.Go(func() { ssh.DiscardRequests(reqs) }) for ch := range chans { @@ -81,12 +79,67 @@ func _ssh_accept(m *ice.Message, h string, c net.Conn) { if m.Warn(err) { continue } - - func(channel ssh.Channel, requests <-chan *ssh.Request) { - m.Go(func() { _ssh_handle(m, conn.Permissions.Extensions, c, channel, requests) }) - }(channel, requests) + m.Go(func() { + m.Logs(CHANNEL, tcp.HOSTPORT, c.RemoteAddr().String(), "->", c.LocalAddr().String()) + defer m.Logs("dischan", tcp.HOSTPORT, c.RemoteAddr().String(), "->", c.LocalAddr().String()) + _ssh_prepare(m.Spawn(conn.Permissions.Extensions), channel, requests) + }) } } +func _ssh_prepare(m *ice.Message, channel ssh.Channel, requests <-chan *ssh.Request) { + pty, tty, err := pty.Open() + if m.Warn(err) { + return + } + defer tty.Close() + + list := []string{cli.PATH + "=" + kit.Env(cli.PATH)} + + for request := range requests { + m.Logs(REQUEST, tcp.HOSTPORT, m.Option(tcp.HOSTPORT), mdb.TYPE, request.Type) + + switch request.Type { + case "pty-req": + termLen := request.Payload[3] + termEnv := string(request.Payload[4 : termLen+4]) + _ssh_size(pty.Fd(), request.Payload[termLen+4:]) + list = append(list, "TERM="+termEnv) + case "window-change": + _ssh_size(pty.Fd(), request.Payload) + + case "env": + var env struct{ Name, Value string } + if err := ssh.Unmarshal(request.Payload, &env); err != nil { + continue + } + list = append(list, env.Name+"="+env.Value) + + case "shell": + _ssh_handle(m, channel, pty, tty) + case "exec": + defer channel.Close() + m.Optionv(cli.CMD_OUTPUT, channel) + m.Cmd(cli.SYSTEM, kit.Select("sh", kit.Env(cli.SHELL)), "-c", string(request.Payload[4:request.Payload[3]+4])) + return + } + request.Reply(true, nil) + } +} +func _ssh_handle(m *ice.Message, channel ssh.Channel, pty, tty *os.File) { + h := m.Cmdx(mdb.INSERT, m.Prefix(CHANNEL), "", mdb.HASH, mdb.STATUS, tcp.OPEN, TTY, tty.Name(), m.OptionSimple(aaa.USERNAME, tcp.HOSTPORT), kit.Dict(mdb.TARGET, pty)) + m.Go(func() { io.Copy(channel, pty) }) + p := _ssh_watch(m, h, pty, channel) + + m.Optionv(cli.CMD_INPUT, tty) + m.Optionv(cli.CMD_OUTPUT, tty) + channel.Write([]byte(m.Config(WELCOME))) + m.Cmd(cli.DAEMON, kit.Select("sh", kit.Env(cli.SHELL)), func() { + defer m.Cmd(mdb.MODIFY, m.Prefix(CHANNEL), "", mdb.HASH, mdb.HASH, h, mdb.STATUS, tcp.CLOSE) + channel.Write([]byte(m.Config(GOODBYE))) + channel.Close() + p.Close() + }) +} const ( WELCOME = "welcome" @@ -100,7 +153,7 @@ func init() { psh.Index.Merge(&ice.Context{Configs: ice.Configs{ SERVICE: {Name: SERVICE, Help: "服务", Value: kit.Data( mdb.SHORT, tcp.PORT, mdb.FIELD, "time,port,status,private,authkey,count", - WELCOME, "\r\nwelcome to contexts world\r\n", GOODBYE, "\r\ngoodbye of contexts world\r\n", + WELCOME, "welcome to contexts world\r\n", GOODBYE, "goodbye of contexts world\r\n", )}, }, Commands: ice.Commands{ SERVICE: {Name: "service port id auto listen prunes", Help: "服务", Actions: ice.MergeActions(ice.Actions{ @@ -128,7 +181,7 @@ func init() { mdb.INSERT: {Name: "insert text:textarea", Help: "添加", Hand: func(m *ice.Message, arg ...string) { if ls := kit.Split(m.Option(mdb.TEXT)); len(ls) > 2 { - m.Cmdy(mdb.INSERT, SERVICE, kit.Keys(mdb.HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST, + m.Cmdy(mdb.INSERT, m.Prefix(SERVICE), kit.Keys(mdb.HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST, mdb.TYPE, ls[0], mdb.NAME, ls[len(ls)-1], mdb.TEXT, strings.Join(ls[1:len(ls)-1], "+")) } }}, diff --git a/misc/ssh/service_linux.go b/misc/ssh/service_linux.go index e055000e..a18f9fb0 100644 --- a/misc/ssh/service_linux.go +++ b/misc/ssh/service_linux.go @@ -2,18 +2,8 @@ package ssh import ( "encoding/binary" - "io" - "net" "syscall" "unsafe" - - pty "shylinux.com/x/creackpty" - "golang.org/x/crypto/ssh" - ice "shylinux.com/x/icebergs" - "shylinux.com/x/icebergs/base/cli" - "shylinux.com/x/icebergs/base/mdb" - "shylinux.com/x/icebergs/base/tcp" - kit "shylinux.com/x/toolkits" ) type Winsize struct{ Height, Width, x, y uint16 } @@ -21,63 +11,6 @@ type Winsize struct{ Height, Width, x, y uint16 } func _ssh_size(fd uintptr, b []byte) { w := binary.BigEndian.Uint32(b) h := binary.BigEndian.Uint32(b[4:]) - ws := &Winsize{Width: uint16(w), Height: uint16(h)} syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) } -func _ssh_sizes(fd uintptr, w, h int) { - ws := &Winsize{Width: uint16(w), Height: uint16(h)} - syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) -} -func _ssh_handle(m *ice.Message, meta ice.Maps, c net.Conn, channel ssh.Channel, requests <-chan *ssh.Request) { - m.Logs(CHANNEL, tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr()) - defer m.Logs("dischan", tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr()) - - shell := kit.Select("bash", kit.Env("SHELL")) - list := []string{cli.PATH + "=" + kit.Env(cli.PATH)} - - pty, tty, err := pty.Open() - if m.Warn(err) { - return - } - defer tty.Close() - - h := mdb.Rich(m, CHANNEL, "", kit.Data(mdb.STATUS, tcp.OPEN, TTY, tty.Name(), INPUT, pty, OUTPUT, tty, meta)) - meta[CHANNEL] = h - - for request := range requests { - m.Logs(REQUEST, tcp.HOSTPORT, c.RemoteAddr(), mdb.TYPE, request.Type) - - switch request.Type { - case "pty-req": - termLen := request.Payload[3] - termEnv := string(request.Payload[4 : termLen+4]) - _ssh_size(pty.Fd(), request.Payload[termLen+4:]) - list = append(list, "TERM="+termEnv) - - case "window-change": - _ssh_size(pty.Fd(), request.Payload) - - case "env": - var env struct{ Name, Value string } - if err := ssh.Unmarshal(request.Payload, &env); err != nil { - continue - } - list = append(list, env.Name+"="+env.Value) - - case "exec": - _ssh_exec(m, shell, []string{"-c", string(request.Payload[4 : request.Payload[3]+4])}, list, channel, channel, func() { - channel.Close() - }) - case "shell": - _ssh_watch(m, meta, h, channel, pty) - m.Go(func() { io.Copy(channel, pty) }) - - _ssh_exec(m, shell, nil, list, tty, tty, func() { - defer m.Cmd(mdb.MODIFY, CHANNEL, "", mdb.HASH, mdb.HASH, h, mdb.STATUS, tcp.CLOSE) - _ssh_close(m, c, channel) - }) - } - request.Reply(true, nil) - } -}