|
|
|
@@ -2503,6 +2503,8 @@ event_loop:
|
|
|
|
|
var attachedItem models.SSHSession
|
|
|
|
|
var attachedSessionID string
|
|
|
|
|
var attachedPrepared *sshSessionPrepared
|
|
|
|
|
var attachedStatus string
|
|
|
|
|
var attachedMessage string
|
|
|
|
|
|
|
|
|
|
if strings.TrimSpace(msg.SessionID) == "" {
|
|
|
|
|
api.sendSSHSessionWS(&sendMu, ws, sshSessionStreamMessage{
|
|
|
|
@@ -2539,6 +2541,40 @@ event_loop:
|
|
|
|
|
})
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if !preparedOK {
|
|
|
|
|
attachedStatus = "closed"
|
|
|
|
|
attachedMessage = item.Error
|
|
|
|
|
if item.Status == "error" {
|
|
|
|
|
attachedStatus = "error"
|
|
|
|
|
}
|
|
|
|
|
if attachedMessage == "" {
|
|
|
|
|
if item.Status == "closed" {
|
|
|
|
|
attachedMessage = "SSH session is closed"
|
|
|
|
|
} else if item.Status == "error" {
|
|
|
|
|
attachedMessage = "SSH session failed"
|
|
|
|
|
} else {
|
|
|
|
|
attachedMessage = "SSH session cannot be resumed. Connect again to start a new session."
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
api.sendSSHSessionWS(&sendMu, ws, sshSessionStreamMessage{
|
|
|
|
|
SessionID: msg.SessionID,
|
|
|
|
|
Type: "status",
|
|
|
|
|
Status: attachedStatus,
|
|
|
|
|
Message: attachedMessage,
|
|
|
|
|
})
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
prepared, preparedOK = api.SSHPreparedSessionStore.Take(msg.SessionID)
|
|
|
|
|
if !preparedOK {
|
|
|
|
|
api.sendSSHSessionWS(&sendMu, ws, sshSessionStreamMessage{
|
|
|
|
|
SessionID: msg.SessionID,
|
|
|
|
|
Type: "status",
|
|
|
|
|
Status: "error",
|
|
|
|
|
Message: "ssh session preparation not found",
|
|
|
|
|
})
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
attachedPrepared = &prepared
|
|
|
|
|
attachment = &sshWorkspaceAttachment{
|
|
|
|
|
InputCh: make(chan sshSessionStreamMessage, sshSessionInputBufferSize),
|
|
|
|
|
InputErrCh: make(chan error, 1),
|
|
|
|
@@ -2551,12 +2587,6 @@ event_loop:
|
|
|
|
|
user.Username)
|
|
|
|
|
attachedItem = item
|
|
|
|
|
attachedSessionID = attachedItem.ID
|
|
|
|
|
if preparedOK {
|
|
|
|
|
prepared, preparedOK = api.SSHPreparedSessionStore.Take(msg.SessionID)
|
|
|
|
|
if preparedOK {
|
|
|
|
|
attachedPrepared = &prepared
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
go func(runItem models.SSHSession, runPrepared *sshSessionPrepared, runSessionID string, runAttachment *sshWorkspaceAttachment) {
|
|
|
|
|
defer func() {
|
|
|
|
|
select {
|
|
|
|
@@ -2665,7 +2695,17 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
var transcriptRecorder *sshSessionTranscriptRecorder
|
|
|
|
|
var transcriptSendBinary func([]byte)
|
|
|
|
|
var promptedAuthInput SSHPromptedAuthInput
|
|
|
|
|
var runtimeStartedAt time.Time
|
|
|
|
|
|
|
|
|
|
runtimeStartedAt = time.Now()
|
|
|
|
|
defer func() {
|
|
|
|
|
api.Logger.Write(logIDSSHBroker, codit_logger.LOG_INFO,
|
|
|
|
|
"session runtime exited session=%s requester=%s user=%s dur_ms=%d",
|
|
|
|
|
sessionItem.ID,
|
|
|
|
|
sessionItem.RemoteAddr,
|
|
|
|
|
user.Username,
|
|
|
|
|
time.Since(runtimeStartedAt).Milliseconds())
|
|
|
|
|
}()
|
|
|
|
|
runtimeSession = &sshActiveSession{}
|
|
|
|
|
runtimeSession.SetResources(transportWS, nil, nil, nil)
|
|
|
|
|
if api.SSHSessionRegistry != nil {
|
|
|
|
@@ -2727,7 +2767,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", "", 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2808,7 +2848,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2820,7 +2860,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2840,7 +2880,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2852,7 +2892,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2872,7 +2912,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2892,7 +2932,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2910,7 +2950,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
if closeReason != "" {
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2926,7 +2966,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2944,7 +2984,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2956,7 +2996,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -2974,7 +3014,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
now = time.Now().UTC().Unix()
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, 0, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, 0, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -3055,7 +3095,7 @@ func (api *API) runSSHSessionStream(store *db.Store, user models.User, sessionIt
|
|
|
|
|
if closeReason != "" {
|
|
|
|
|
_ = store.UpdateSSHSessionStatus(sessionItem.ID, "closed", connectedFingerprint, connectedAt, now, closeReason)
|
|
|
|
|
api.logSSHSessionClosed(sessionItem, profile, user, "closed", closeReason, connectedAt, now)
|
|
|
|
|
if sendStatus != nil {
|
|
|
|
|
if sendStatus != nil && !isSSHSessionTransportCloseReason(closeReason) {
|
|
|
|
|
sendStatus(sshSessionStreamMessage{Type: "status", Status: "closed", Message: closeReason})
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@@ -3340,6 +3380,23 @@ func sshSessionWebsocketCloseReason(err error) string {
|
|
|
|
|
return "websocket closed"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func isSSHSessionTransportCloseReason(reason string) bool {
|
|
|
|
|
reason = strings.TrimSpace(reason)
|
|
|
|
|
if reason == "websocket closed" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if reason == "websocket send failed" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if reason == "websocket input queue full" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if reason == "detached" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (api *API) sendSSHSessionWS(mu *sync.Mutex, ws *websocket.Conn, msg sshSessionStreamMessage) error {
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|