Files
Erupe/server/channelserver/handlers_register.go
Houmgaor 604d53d6d7 fix(channelserver): validate packet fields before use in handlers
Several handlers used packet fields as array indices or SQL column
names without bounds checking, allowing crafted packets to panic the
server or produce malformed SQL.

Panic fixes (high severity):
- handlers_mail: bounds check AccIndex against mailList length
- handlers_misc: validate ArmourID >= 10000 and MogType <= 4
- handlers_mercenary: check RawDataPayload length before slicing
- handlers_house: check RawDataPayload length in SaveDecoMyset
- handlers_register: guard empty RawDataPayload in OperateRegister

SQL column name fixes (medium severity):
- handlers_misc: early return on unknown PointType
- handlers_items: reject unknown StampType in weekly stamp handlers
- handlers_achievement: cap AchievementID at 32
- handlers_goocoo: skip goocoo.Index > 4
- handlers_house: cap BoxIndex for warehouse operations
- handlers_tower: fix MissionIndex=0 bypassing normalization guard
2026-02-19 00:23:04 +01:00

148 lines
3.9 KiB
Go

package channelserver
import (
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
)
func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfRegisterEvent)
bf := byteframe.NewByteFrame()
// Some kind of check if there's already a session
if pkt.CheckOnly && s.server.getRaviSemaphore() == nil {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
}
bf.WriteUint8(uint8(pkt.WorldID))
bf.WriteUint8(uint8(pkt.LandID))
bf.WriteUint16(s.server.raviente.id)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
}
func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfReleaseEvent)
// Do this ack manually because it uses a non-(0|1) error code
/*
_ACK_SUCCESS = 0
_ACK_ERROR = 1
_ACK_EINPROGRESS = 16
_ACK_ENOENT = 17
_ACK_ENOSPC = 18
_ACK_ETIMEOUT = 19
_ACK_EINVALID = 64
_ACK_EFAILED = 65
_ACK_ENOMEM = 66
_ACK_ENOTEXIT = 67
_ACK_ENOTREADY = 68
_ACK_EALREADY = 69
_ACK_DISABLE_WORK = 71
*/
s.QueueSendMHF(&mhfpacket.MsgSysAck{
AckHandle: pkt.AckHandle,
IsBufferResponse: false,
ErrorCode: 0x41,
AckData: []byte{0x00, 0x00, 0x00, 0x00},
})
}
// RaviUpdate represents a Raviente register update entry.
type RaviUpdate struct {
Op uint8
Dest uint8
Data uint32
}
func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysOperateRegister)
if len(pkt.RawDataPayload) == 0 {
return
}
var raviUpdates []RaviUpdate
var raviUpdate RaviUpdate
// Strip null terminator
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload[:len(pkt.RawDataPayload)-1])
for i := len(pkt.RawDataPayload) / 6; i > 0; i-- {
raviUpdate.Op = bf.ReadUint8()
raviUpdate.Dest = bf.ReadUint8()
raviUpdate.Data = bf.ReadUint32()
raviUpdates = append(raviUpdates, raviUpdate)
}
bf = byteframe.NewByteFrame()
var _old, _new uint32
s.server.raviente.Lock()
for _, update := range raviUpdates {
switch update.Op {
case 2:
_old, _new = s.server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, true)
case 13, 14:
_old, _new = s.server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, false)
}
bf.WriteUint8(1)
bf.WriteUint8(update.Dest)
bf.WriteUint32(_old)
bf.WriteUint32(_new)
}
s.server.raviente.Unlock()
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
if s.server.erupeConfig.GameplayOptions.LowLatencyRaviente {
s.notifyRavi()
}
}
func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLoadRegister)
bf := byteframe.NewByteFrame()
bf.WriteUint8(0)
bf.WriteUint8(pkt.Values)
for i := uint8(0); i < pkt.Values; i++ {
switch pkt.RegisterID {
case 0x40000:
bf.WriteUint32(s.server.raviente.state[i])
case 0x50000:
bf.WriteUint32(s.server.raviente.support[i])
case 0x60000:
bf.WriteUint32(s.server.raviente.register[i])
}
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
func (s *Session) notifyRavi() {
sema := s.server.getRaviSemaphore()
if sema == nil {
return
}
var temp mhfpacket.MHFPacket
raviNotif := byteframe.NewByteFrame()
temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x40000}
raviNotif.WriteUint16(uint16(temp.Opcode()))
_ = temp.Build(raviNotif, s.clientContext)
temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x50000}
raviNotif.WriteUint16(uint16(temp.Opcode()))
_ = temp.Build(raviNotif, s.clientContext)
temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x60000}
raviNotif.WriteUint16(uint16(temp.Opcode()))
_ = temp.Build(raviNotif, s.clientContext)
raviNotif.WriteUint16(0x0010) // End it.
if s.server.erupeConfig.GameplayOptions.LowLatencyRaviente {
for session := range sema.clients {
session.QueueSendNonBlocking(raviNotif.Data())
}
} else {
for session := range sema.clients {
if session.charID == s.charID {
session.QueueSendNonBlocking(raviNotif.Data())
}
}
}
}
func handleMsgSysNotifyRegister(s *Session, p mhfpacket.MHFPacket) {}