(connDetails *connections.ConnectionDetails, reqs <-chan *ssh.Request, wg *sync.WaitGroup)
| 1297 | } |
| 1298 | |
| 1299 | func handleSSHConnection(connDetails *connections.ConnectionDetails, reqs <-chan *ssh.Request, wg *sync.WaitGroup) { |
| 1300 | defer wg.Done() |
| 1301 | |
| 1302 | mudlog.Info("New SSH Connection", "connectionID", connDetails.ConnectionId(), "remoteAddr", connDetails.RemoteAddr().String()) |
| 1303 | |
| 1304 | // Handle SSH channel requests (pty-req, window-change, shell, exec, etc.) |
| 1305 | // We run this in a goroutine so the read loop below can start immediately. |
| 1306 | go func() { |
| 1307 | for req := range reqs { |
| 1308 | switch req.Type { |
| 1309 | case "pty-req": |
| 1310 | // Parse terminal dimensions from the pty-req payload. |
| 1311 | // Payload: string term, uint32 cols, uint32 rows, uint32 width-px, uint32 height-px, string modes |
| 1312 | if len(req.Payload) >= 12 { |
| 1313 | // Skip the terminal name string: 4-byte length prefix + string bytes |
| 1314 | nameLen := int(req.Payload[0])<<24 | int(req.Payload[1])<<16 | int(req.Payload[2])<<8 | int(req.Payload[3]) |
| 1315 | offset := 4 + nameLen |
| 1316 | if offset+8 <= len(req.Payload) { |
| 1317 | cols := uint32(req.Payload[offset])<<24 | uint32(req.Payload[offset+1])<<16 | uint32(req.Payload[offset+2])<<8 | uint32(req.Payload[offset+3]) |
| 1318 | rows := uint32(req.Payload[offset+4])<<24 | uint32(req.Payload[offset+5])<<16 | uint32(req.Payload[offset+6])<<8 | uint32(req.Payload[offset+7]) |
| 1319 | if cols > 0 && rows > 0 { |
| 1320 | cs := connections.GetClientSettings(connDetails.ConnectionId()) |
| 1321 | cs.Display.ScreenWidth = cols |
| 1322 | cs.Display.ScreenHeight = rows |
| 1323 | connections.OverwriteClientSettings(connDetails.ConnectionId(), cs) |
| 1324 | } |
| 1325 | } |
| 1326 | } |
| 1327 | if req.WantReply { |
| 1328 | req.Reply(true, nil) |
| 1329 | } |
| 1330 | case "window-change": |
| 1331 | // Payload: uint32 cols, uint32 rows, uint32 width-px, uint32 height-px |
| 1332 | if len(req.Payload) >= 8 { |
| 1333 | cols := uint32(req.Payload[0])<<24 | uint32(req.Payload[1])<<16 | uint32(req.Payload[2])<<8 | uint32(req.Payload[3]) |
| 1334 | rows := uint32(req.Payload[4])<<24 | uint32(req.Payload[5])<<16 | uint32(req.Payload[6])<<8 | uint32(req.Payload[7]) |
| 1335 | if cols > 0 && rows > 0 { |
| 1336 | cs := connections.GetClientSettings(connDetails.ConnectionId()) |
| 1337 | cs.Display.ScreenWidth = cols |
| 1338 | cs.Display.ScreenHeight = rows |
| 1339 | connections.OverwriteClientSettings(connDetails.ConnectionId(), cs) |
| 1340 | connections.NotifyWindowChange(connDetails.ConnectionId(), cols, rows) |
| 1341 | } |
| 1342 | } |
| 1343 | if req.WantReply { |
| 1344 | req.Reply(true, nil) |
| 1345 | } |
| 1346 | case "shell", "exec": |
| 1347 | if req.WantReply { |
| 1348 | req.Reply(true, nil) |
| 1349 | } |
| 1350 | default: |
| 1351 | if req.WantReply { |
| 1352 | req.Reply(false, nil) |
| 1353 | } |
| 1354 | } |
| 1355 | } |
| 1356 | }() |
no test coverage detected