// Read the version message, calling exit if this is not a supported // version. func processVerMsg(msgInit msgInit, exit exitFn) { var m core.Message msgInit(&m, exit) if m.MsgType() != 'V' { exit("expected version ('V') message, "+ "but received %c", m.MsgType()) } // hard-coded lengh limit, but it's very generous if m.Size() > 10*KB { log.Printf("oversized message string, msg size is %d", m.Size()) } s, err := buf.ReadCString(m.Payload()) if err != nil { exit("couldn't read version string: %v", err) } if !(strings.HasPrefix(s, "PG-9.0") || strings.HasPrefix(s, "PG-9.1") || strings.HasPrefix(s, "PG-9.2") || strings.HasPrefix(s, "PG-9.3") || strings.HasPrefix(s, "PG-9.4") || strings.HasPrefix(s, "PG-9.5")) || !strings.HasSuffix(s, "/logfebe-1") { exit("protocol version not supported: %s", s) } }
// Process the identity ('I') message, reporting the identity therein. func processIdentMsg(msgInit msgInit, exit exitFn) string { var m core.Message msgInit(&m, exit) // Read the remote system identifier string if m.MsgType() != 'I' { exit("expected identification ('I') message, "+ "but received %c", m.MsgType()) } // hard-coded lengh limit, but it's very generous if m.Size() > 10*KB { log.Printf("oversized message string, msg size is %d", m.Size()) } s, err := buf.ReadCString(m.Payload()) if err != nil { exit("couldn't read identification string: %v", err) } return s }
// Process a log message, sending it to the client. func processLogMsg(die dieCh, primary *logplexc.Client, audit *logplexc.Client, msgInit msgInit, sr *serveRecord, exit exitFn) { var m core.Message for { // Poll request to exit select { case <-die: return default: break } msgInit(&m, exit) // Refuse to handle any log message above an arbitrary // size. Furthermore, exit the worker, closing the0 // connection, so that the client doesn't even bother // to wait for this process to drain the oversized // item and anything following it; these will be // dropped. It's on the client to gracefully handle // the error and re-connect after this happens. if m.Size() > 1*MB { exit("client %q sent oversized log record") } payload, err := m.Force() if err != nil { exit("could not retrieve payload of message: %v", err) } var lr logRecord parseLogRecord(&lr, payload, exit) routeLogRecord(&lr, primary, audit, sr, exit) } }
func (c *FrontendConnection) auth(dbcfg VirtualDatabaseConfiguration, sm *fbproto.StartupMessage) bool { authFailed := func(sqlstate, format string, v ...interface{}) bool { var msg fbcore.Message message := fmt.Sprintf(format, v...) initFatalMessage(&msg, sqlstate, message) _ = c.WriteMessage(&msg) _ = c.FlushStream() return false } username, ok := sm.Params["user"] if !ok { return authFailed("08P01", `required startup parameter "user" nor present in startup packet`) } dbname, ok := sm.Params["database"] if !ok { dbname = username } authMethod, ok := dbcfg.FindDatabase(dbname) if !ok { return authFailed("3D000", "database %q does not exist", dbname) } switch authMethod { case "trust": return true case "md5": // handled below default: elog.Errorf("unrecognized authentication method %q", authMethod) return authFailed("XX000", "internal error") } salt := make([]byte, 4) _, err := rand.Read(salt) if err != nil { elog.Errorf("could not generate random salt: %s", err) return authFailed("XX000", "internal error") } var msg fbcore.Message buf := &bytes.Buffer{} fbbuf.WriteInt32(buf, 5) buf.Write(salt) msg.InitFromBytes(fbproto.MsgAuthenticationMD5PasswordR, buf.Bytes()) err = c.WriteAndFlush(&msg) if err != nil { elog.Logf("error during startup sequence: %s", err) return false } err = c.stream.Next(&msg) if err == io.EOF { elog.Debugf("EOF during startup sequence") return false } else if err != nil { elog.Logf("error during startup sequence: %s", err) return false } if msg.MsgType() != fbproto.MsgPasswordMessageP { return authFailed("08P01", "unexpected response %x", msg.MsgType()) } // don't bother with messages which are clearly too big if msg.Size() > 100 { return authFailed("28001", "password authentication failed for user %q", username) } password, err := msg.Force() if err != nil { elog.Logf("error during startup sequence: %s", err) return false } success, err := dbcfg.MD5Auth(dbname, username, salt, password) if err != nil { elog.Logf("error during startup sequence: %s", err) return false } if !success { return authFailed("28001", "password authentication failed for user %q", username) } return true }