Ejemplo n.º 1
0
func appendSSLConnectionStringParam(logger lager.Logger, driverName, databaseConnectionString, sqlCACertFile string) string {
	switch driverName {
	case "mysql":
		if sqlCACertFile != "" {
			certBytes, err := ioutil.ReadFile(sqlCACertFile)
			if err != nil {
				logger.Fatal("failed-to-read-sql-ca-file", err)
			}

			caCertPool := x509.NewCertPool()
			if ok := caCertPool.AppendCertsFromPEM(certBytes); !ok {
				logger.Fatal("failed-to-parse-sql-ca", err)
			}

			tlsConfig := &tls.Config{
				InsecureSkipVerify: false,
				RootCAs:            caCertPool,
			}

			mysql.RegisterTLSConfig("bbs-tls", tlsConfig)
			databaseConnectionString = fmt.Sprintf("%s?tls=bbs-tls", databaseConnectionString)
		}
	case "postgres":
		if sqlCACertFile == "" {
			databaseConnectionString = fmt.Sprintf("%s?sslmode=disable", databaseConnectionString)
		} else {
			databaseConnectionString = fmt.Sprintf("%s?sslmode=verify-ca&sslrootcert=%s", databaseConnectionString, sqlCACertFile)
		}
	}

	return databaseConnectionString
}
Ejemplo n.º 2
0
func getEngine() (*xorm.Engine, error) {
	LoadConfig()

	cnnstr := ""
	switch DbCfg.Type {
	case "mysql":
		protocol := "tcp"
		if strings.HasPrefix(DbCfg.Host, "/") {
			protocol = "unix"
		}

		cnnstr = fmt.Sprintf("%s:%[email protected]%s(%s)/%s?charset=utf8",
			DbCfg.User, DbCfg.Pwd, protocol, DbCfg.Host, DbCfg.Name)

		if mysqlConfig.SslMode == "true" || mysqlConfig.SslMode == "skip-verify" {
			tlsCert, err := makeCert("custom", mysqlConfig)
			if err != nil {
				return nil, err
			}
			mysql.RegisterTLSConfig("custom", tlsCert)
			cnnstr += "&tls=custom"
		}
	case "postgres":
		var host, port = "127.0.0.1", "5432"
		fields := strings.Split(DbCfg.Host, ":")
		if len(fields) > 0 && len(strings.TrimSpace(fields[0])) > 0 {
			host = fields[0]
		}
		if len(fields) > 1 && len(strings.TrimSpace(fields[1])) > 0 {
			port = fields[1]
		}
		if DbCfg.Pwd == "" {
			DbCfg.Pwd = "''"
		}
		if DbCfg.User == "" {
			DbCfg.User = "******"
		}
		cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s", DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode)
	case "sqlite3":
		if !filepath.IsAbs(DbCfg.Path) {
			DbCfg.Path = filepath.Join(setting.DataPath, DbCfg.Path)
		}
		os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
		cnnstr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc&_loc=Local"
	default:
		return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
	}

	log.Info("Database: %v", DbCfg.Type)

	return xorm.NewEngine(DbCfg.Type, cnnstr)
}
Ejemplo n.º 3
0
func (driver *Driver) Initialize(url string) error {
	urlWithoutScheme := strings.SplitN(url, "mysql://", 2)
	if len(urlWithoutScheme) != 2 {
		return errors.New("invalid mysql:// scheme")
	}

	// check if env vars vor mysql ssl connection are set and if yes use them
	if os.Getenv("MYSQL_SERVER_CA") != "" && os.Getenv("MYSQL_CLIENT_KEY") != "" && os.Getenv("MYSQL_CLIENT_CERT") != "" {
		rootCertPool := x509.NewCertPool()
		pem, err := ioutil.ReadFile(os.Getenv("MYSQL_SERVER_CA"))
		if err != nil {
			return err
		}

		if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
			return errors.New("Failed to append PEM")
		}

		clientCert := make([]tls.Certificate, 0, 1)
		certs, err := tls.LoadX509KeyPair(os.Getenv("MYSQL_CLIENT_CERT"), os.Getenv("MYSQL_CLIENT_KEY"))
		if err != nil {
			return err
		}

		clientCert = append(clientCert, certs)
		mysql.RegisterTLSConfig("custom", &tls.Config{
			RootCAs:            rootCertPool,
			Certificates:       clientCert,
			InsecureSkipVerify: true,
		})

		urlWithoutScheme[1] += "&tls=custom"
	}

	db, err := sql.Open("mysql", urlWithoutScheme[1])
	if err != nil {
		return err
	}
	if err := db.Ping(); err != nil {
		return err
	}
	driver.db = db

	if err := driver.ensureVersionTableExists(); err != nil {
		return err
	}
	return nil
}
Ejemplo n.º 4
0
// ConnectToMySQLDatabase generates a secure or insecure TCP MySQL database connection on port 3306
func ConnectToMySQLDatabase(username, password, database, server string, tlsInfo *TLSCertificates, secure bool) (*sql.DB, error) {
	if secure {
		// Create a cert pool
		rootCertPool := x509.NewCertPool()
		// Load the Certificate Authority cert
		pem, err := ioutil.ReadFile(tlsInfo.BasePath + tlsInfo.CACertRelativePath)
		if err != nil {
			return nil, fmt.Errorf("Failed to open ca cert: %s", err.Error())
		}

		// Append the CA cert to the cert pool
		ok := rootCertPool.AppendCertsFromPEM(pem)
		if !ok {
			return nil, fmt.Errorf("Failed to append Certs from PEM.")
		}

		// Load the Client Certificate and Key
		clientCert := make([]tls.Certificate, 0, 1)
		certs, err := tls.LoadX509KeyPair(tlsInfo.BasePath+tlsInfo.ClientCertRelativePath,
			tlsInfo.BasePath+tlsInfo.ClientKeyRelativePath)
		if err != nil {
			return nil, fmt.Errorf("Failed to load x509 client cert and key: %s", err.Error())
		}
		clientCert = append(clientCert, certs)

		// Register the TLS configuration with MySQL
		mysql.RegisterTLSConfig("custom", &tls.Config{
			RootCAs:      rootCertPool,
			Certificates: clientCert,
		})

		// Open the connection
		url := fmt.Sprintf("%s:%[email protected](%s:3306)/%s?tls=skip-verify", username, password, server, database)
		db, err := sql.Open("mysql", url)
		if err != nil {
			return nil, fmt.Errorf("Couldn't connect to database: %s", err.Error())
		}

		return db, nil
	}

	url := fmt.Sprintf("%s:%[email protected](%s:3306)/%s", username, password, server, database)
	db, err := sql.Open("mysql", url)
	if err != nil {
		return nil, fmt.Errorf("Couldn't connect to database: %s", err.Error())
	}
	return db, nil
}
Ejemplo n.º 5
0
// Create a TLS configuration from the config supplied CA, Certificate, and Private key.
// Register the TLS config with the mysql drivers as the "orchestrator" config
// Modify the supplied URI to call the TLS config
func SetupMySQLOrchestratorTLS(uri string) (string, error) {
	if !orchestratorTLSConfigured {
		tlsConfig, err := ssl.NewTLSConfig(config.Config.MySQLOrchestratorSSLCAFile, true)
		if err != nil {
			return "", log.Fatalf("Can't create TLS configuration for Orchestrator connection %s: %s", uri, err)
		}
		tlsConfig.InsecureSkipVerify = config.Config.MySQLOrchestratorSSLSkipVerify
		if err = ssl.AppendKeyPair(tlsConfig, config.Config.MySQLOrchestratorSSLCertFile, config.Config.MySQLOrchestratorSSLPrivateKeyFile); err != nil {
			return "", log.Fatalf("Can't setup TLS key pairs for %s: %s", uri, err)
		}
		if err = mysql.RegisterTLSConfig("orchestrator", tlsConfig); err != nil {
			return "", log.Fatalf("Can't register mysql TLS config for orchestrator: %s", err)
		}
		orchestratorTLSConfigured = true
	}
	return fmt.Sprintf("%s&tls=orchestrator", uri), nil
}
Ejemplo n.º 6
0
// Create a TLS configuration from the config supplied CA, Certificate, and Private key.
// Register the TLS config with the mysql drivers as the "topology" config
// Modify the supplied URI to call the TLS config
// TODO: Way to have password mixed with TLS for various nodes in the topology.  Currently everything is TLS or everything is password
func SetupMySQLTopologyTLS(uri string) (string, error) {
	if !topologyTLSConfigured {
		tlsConfig, err := ssl.NewTLSConfig(config.Config.MySQLTopologySSLCAFile, !config.Config.MySQLTopologySSLSkipVerify)
		// Drop to TLS 1.0 for talking to MySQL
		tlsConfig.MinVersion = tls.VersionTLS10
		if err != nil {
			return "", log.Fatalf("Can't create TLS configuration for Topology connection %s: %s", uri, err)
		}
		tlsConfig.InsecureSkipVerify = config.Config.MySQLTopologySSLSkipVerify
		if err = ssl.AppendKeyPair(tlsConfig, config.Config.MySQLTopologySSLCertFile, config.Config.MySQLTopologySSLPrivateKeyFile); err != nil {
			return "", log.Fatalf("Can't setup TLS key pairs for %s: %s", uri, err)
		}
		if err = mysql.RegisterTLSConfig("topology", tlsConfig); err != nil {
			return "", log.Fatalf("Can't register mysql TLS config for topology: %s", err)
		}
		topologyTLSConfigured = true
	}
	return fmt.Sprintf("%s&tls=topology", uri), nil
}
Ejemplo n.º 7
0
// Establish a TLS connection with a given CA certificate
// Register a tsl.Config associted with the same key as the dns param from sql.Open
// foo:[email protected](127.0.0.1:3306)/dbname?tls=default
func setupMySQLTLSConfig(tlsCaFile string) error {
	rootCertPool := x509.NewCertPool()

	pem, err := ioutil.ReadFile(tlsCaFile)
	if err != nil {
		return err
	}

	if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
		return err
	}

	err = mysql.RegisterTLSConfig(mysqlTLSKey, &tls.Config{
		RootCAs: rootCertPool,
	})
	if err != nil {
		return err
	}

	return nil
}
Ejemplo n.º 8
0
func Query(host string, cxn Sqlcxn, wg *sync.WaitGroup) {
	defer wg.Done()

	var dsn string
	dsn = cxn.Username + ":" + cxn.Password + "@tcp(" + host + ":" + strconv.Itoa(cxn.Port) + ")/"
	if cxn.MultiStatements == true {
		dsn += "?multiStatements=true"
	} else {
		dsn += "?multiStatements=false"
	}
	if cxn.TlsConfig.Certificates != nil {
		mysql.RegisterTLSConfig("omnisql", &cxn.TlsConfig)
		dsn += "&tls=omnisql"
	}
	if cxn.ConnectTimeout <= 0 {
		dsn += "&timeout=2"
	} else {
		dsn += "&timeout=" + strconv.Itoa(cxn.ConnectTimeout) + "s"
	}
	dsn += "&readTimeout=" + strconv.Itoa(cxn.ReadTimeout) + "s"
	dsn += "&writeTimeout=" + strconv.Itoa(cxn.WriteTimeout) + "s"

	// SSL Support
	if cxn.SslCa != "" || cxn.SslCaPath != "" || cxn.SslCert != "" || cxn.SslCipher != "" || cxn.SslKey != "" {
		dsn += "&tls=omnisql"
	}

	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Println(host, "\t", err.Error())
		return
	}
	defer db.Close()

	// Execute the query
	rows, err := db.Query(cxn.Query)
	if err != nil {
		log.Println("WARNING: Could not connect to '" + host + "': Unknown MySQL server host '" + host + "'")
		return
	}

	// Get column names
	columns, err := rows.Columns()
	if err != nil {
		log.Println(host, "\t", err.Error())
		return
	}

	// Make a slice for the values
	values := make([]sql.RawBytes, len(columns))

	// rows.Scan wants '[]interface{}' as an argument, so we must copy the
	// references into such a slice
	// See http://code.google.com/p/go-wiki/wiki/InterfaceSlice for details
	scanArgs := make([]interface{}, len(values))
	for i := range values {
		scanArgs[i] = &values[i]
	}

	// Fetch rows
	for rows.Next() {
		var res string
		res += host
		// get RawBytes from data
		err = rows.Scan(scanArgs...)
		if err != nil {
			log.Println(host, "\t", err.Error())
			return
		}

		// Now do something with the data.
		// Here we just print each column as a string.
		for _, col := range values {
			// Here we can check if the value is nil (NULL value)
			if col == nil {
				res += "\tNULL"
			} else {
				res += "\t"
				res += string(col)
			}
		}
		fmt.Println(res)
	}
	if err = rows.Err(); err != nil {
		log.Println(host, "\t", err.Error())
		return
	}
	return
}
Ejemplo n.º 9
0
func main() {
	var (
		dbUser          = flag.String("db-user", "auth", "Auth database username.")
		dbPasswd        = flag.String("db-pass", "", "Auth database password.")
		dbHost          = flag.String("db-host", "", "Auth database host.")
		dbPort          = flag.String("db-port", "3306", "Auth database port.")
		dbServerName    = flag.String("db-server-name", "", "Auth database server name.")
		dbServerCACert  = flag.String("db-server-ca-cert", "/etc/auth/db-server-ca.pem", "Database server ca certificate")
		dbClientCert    = flag.String("db-client-cert", "/etc/auth/db-client-cert.pem", "Database client certificate.")
		dbClientKey     = flag.String("db-client-key", "/etc/auth/db-client-key.pem", "Database client key.")
		debugListenAddr = flag.String("debug-listen-addr", "127.0.0.1:7801", "HTTP listen address.")
		listenAddr      = flag.String("listen-addr", "127.0.0.1:7800", "HTTP listen address.")
		tlsCert         = flag.String("tls-cert", "/etc/auth/cert.pem", "TLS server certificate.")
		tlsKey          = flag.String("tls-key", "/etc/auth/key.pem", "TLS server key.")
		jwtPrivateKey   = flag.String("jwt-private-key", "/etc/auth/jwt-key.pem", "The RSA private key to use for signing JWTs")
	)
	flag.Parse()

	var err error
	log.Println("Auth service starting...")

	certPool := x509.NewCertPool()
	pem, err := ioutil.ReadFile(*dbServerCACert)
	if err != nil {
		log.Fatal(err)
	}
	if ok := certPool.AppendCertsFromPEM(pem); !ok {
		log.Fatal("Failed to append PEM.")
	}
	clientCert := make([]tls.Certificate, 0, 1)
	certs, err := tls.LoadX509KeyPair(*dbClientCert, *dbClientKey)
	if err != nil {
		log.Fatal(err)
	}
	clientCert = append(clientCert, certs)
	mysql.RegisterTLSConfig("custom", &tls.Config{
		ServerName:   *dbServerName,
		RootCAs:      certPool,
		Certificates: clientCert,
	})

	dbAddr := net.JoinHostPort(*dbHost, *dbPort)
	dbConfig := mysql.Config{
		User:      *dbUser,
		Passwd:    *dbPasswd,
		Net:       "tcp",
		Addr:      dbAddr,
		DBName:    "auth",
		TLSConfig: "custom",
	}

	for {
		db, err = sql.Open("mysql", dbConfig.FormatDSN())
		if err != nil {
			goto dberror
		}
		err = db.Ping()
		if err != nil {
			goto dberror
		}
		break

	dberror:
		log.Println(err)
		log.Println("error connecting to the auth database, retrying in 5 secs.")
		time.Sleep(5 * time.Second)
	}

	ta, err := credentials.NewServerTLSFromFile(*tlsCert, *tlsKey)
	if err != nil {
		log.Fatal(err)
	}

	gs := grpc.NewServer(grpc.Creds(ta))

	as, err := NewAuthServer(*jwtPrivateKey)
	if err != nil {
		log.Fatal(err)
	}
	pb.RegisterAuthServer(gs, as)

	hs := health.NewHealthServer()
	hs.SetServingStatus("grpc.health.v1.authservice", 1)
	healthpb.RegisterHealthServer(gs, hs)

	ln, err := net.Listen("tcp", *listenAddr)
	if err != nil {
		log.Fatal(err)
	}
	go gs.Serve(ln)

	trace.AuthRequest = func(req *http.Request) (any, sensitive bool) { return true, true }
	log.Println("Auth service started successfully.")
	log.Fatal(http.ListenAndServe(*debugListenAddr, nil))
}
Ejemplo n.º 10
0
func main() {
	var (
		email    = flag.String("e", "", "The user email address.")
		username = flag.String("u", "", "The username.")
		isAdmin  = flag.Bool("a", false, "Enable the admin flag.")
	)
	flag.Parse()

	fmt.Println("enter password:"******"marshaling error: ", err)
	}

	certPool := x509.NewCertPool()
	pem, err := ioutil.ReadFile("/etc/auth/server-ca.pem")
	if err != nil {
		log.Fatal(err)
	}
	if ok := certPool.AppendCertsFromPEM(pem); !ok {
		log.Fatal("Failed to append PEM.")
	}
	clientCert := make([]tls.Certificate, 0, 1)
	certs, err := tls.LoadX509KeyPair("/etc/auth/client-cert.pem", "/etc/auth/client-key.pem")
	if err != nil {
		log.Fatal(err)
	}
	clientCert = append(clientCert, certs)
	mysql.RegisterTLSConfig("custom", &tls.Config{
		ServerName:   "hightowerlabs:database",
		RootCAs:      certPool,
		Certificates: clientCert,
	})

	db, err := sql.Open("mysql", "auth:[email protected](104.196.125.211:3306)/auth?tls=custom")
	if err != nil {
		log.Fatal(err)
	}

	_, err = db.Exec("INSERT INTO users (username, proto) VALUES (?, ?)", user.Username, data)
	if err != nil {
		log.Fatal(err)
	}
}
Ejemplo n.º 11
0
func main() {
	flag.Parse()

	if *dump == "" {
		log.Fatalf("no -dump file specified")
	}

	if *enableSsl {
		rootCertPool := x509.NewCertPool()
		pem, err := ioutil.ReadFile(*sslCa)
		if err != nil {
			log.Fatalln("ioutil.Readline:", err)
		}
		if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
			log.Fatal("Failed to append CA certificate PEM.")
		}
		clientCert := []tls.Certificate{}
		certs, err := tls.LoadX509KeyPair(*sslCert, *sslKey)
		if err != nil {
			log.Fatalln("tls.LoadX509KeyPair:", err)
		}
		clientCert = append(clientCert, certs)
		mysql.RegisterTLSConfig("custom", &tls.Config{
			RootCAs:      rootCertPool,
			Certificates: clientCert,
			ServerName:   *serverName,
		})
	}
	db, err := sql.Open("mysql", *dsn)
	if err != nil {
		log.Fatalln("sql.Open:", err)
	}
	defer db.Close()

	f, err := os.Open(*dump)
	if err != nil {
		log.Fatalf("os.Open: %v", err)
	}
	defer f.Close()
	dumpInfo, err := f.Stat()
	if err != nil {
		log.Fatalf("Stat: %v", err)
	}
	size := dumpInfo.Size()

	logFilename := fmt.Sprintf("%s.log", dumpInfo.Name())
	pos, err := recover(logFilename)
	if err != nil {
		log.Fatalf("recover from log: %v", err)
	}
	if pos != 0 {
		log.Printf("seeking to %d in %q", pos, f.Name())
		if _, err = f.Seek(pos, os.SEEK_SET); err != nil {
			log.Fatalf("Seek: %v", err)
		}
	}

	logFile, err := os.OpenFile(logFilename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("os.OpenFile: %v", err)
	}
	defer logFile.Close()

	// buf[i:j] are the bytes that have been read from f but not
	// yet replayed. k indicates up to where we read in a
	// multi-line query.
	buf := make([]byte, 1024*1024)
	i, j, k, readErr := 0, 0, 0, error(nil)
	for {
		if p := bytes.IndexByte(buf[k:j], '\n'); p >= 0 {
			k += p + 1 // The +1 is for the trailing '\n'.
			pos += int64(p + 1)
			if replay(db, buf[i:k-1], pos, size) {
				i = k
				err = save(logFile, pos)
				if err != nil {
					log.Fatalf("Error saving to log: %v", err)
				}
			}
			continue
		}

		if readErr != nil {
			if readErr == io.EOF {
				if i != j {
					log.Println(i, j)
					log.Fatalf(`The contents of %q do not end with a "\n"`, *dump)
				}
				return
			}
			log.Fatal(readErr)
		}

		// First, make sure at least half of the buffer is empty. If we can do
		// that by moving the contents of buf[i:j] to the start of the existing
		// buffer, that's great. Otherwise, allocate a bigger buffer.
		newBuf := buf
		if j-i > len(buf)/2 {
			newBuf = make([]byte, len(buf)*2)
		}
		i, j, k = 0, copy(newBuf, buf[i:j]), k-i
		buf = newBuf
		// Read some more bytes.
		var n int
		n, readErr = f.Read(buf[j:])
		j += n
	}
}
Ejemplo n.º 12
0
func main() {
	flag.Parse()

	if *dump == "" {
		log.Fatalf("no -dump file specified")
	}

	var finalDsn = *dsn
	if *enableSsl {
		pem, err := ioutil.ReadFile(*sslCa)
		if err != nil {
			log.Fatalln("ioutil.Readline:", err)
		}
		rootCertPool := x509.NewCertPool()
		if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
			log.Fatal("Failed to append CA certificate PEM.")
		}
		clientCert := []tls.Certificate{}
		certs, err := tls.LoadX509KeyPair(*sslCert, *sslKey)
		if err != nil {
			log.Fatalln("tls.LoadX509KeyPair:", err)
		}
		clientCert = append(clientCert, certs)
		const customTLSName = "custom"
		tlserr := mysql.RegisterTLSConfig(customTLSName, &tls.Config{
			RootCAs:      rootCertPool,
			Certificates: clientCert,
			ServerName:   *serverName,
		})
		if tlserr != nil {
			log.Fatalln("mysql.RegisterTLSConfig:", tlserr)
		}
		finalDsn = strings.Join([]string{finalDsn, "?tls=", customTLSName}, "")
	}

	if *prompt {
		// DSN strings look like:
		//     user:[email protected](0.0.0.0:3306)/
		// With this flag the user can avoid typing their password:
		//     [email protected](0.0.0.0:3306)/
		// Save text before ':' and after '@' so we can insert the password
		// to create a proper DSN string.
		dsnRegex := regexp.MustCompile(`(\w*):?\w*(@.+)`)
		matches := dsnRegex.FindStringSubmatch(finalDsn)
		if matches == nil {
			fmt.Print("Incorrect format for dsn. Usage:\n")
			flag.PrintDefaults()
			os.Exit(1)
		}

		fmt.Print("Enter password: "******"Error reading password:"******"\n")

		// Insert password into the connection string.
		finalDsn = strings.Join([]string{matches[1], ":", string(password), matches[2]}, "")
	}

	db, err := sql.Open("mysql", finalDsn)
	if err != nil {
		log.Fatalln("sql.Open:", err)
	}
	defer db.Close()

	f, err := os.Open(*dump)
	if err != nil {
		log.Fatalf("os.Open: %v", err)
	}
	defer f.Close()
	dumpInfo, err := f.Stat()
	if err != nil {
		log.Fatalf("Stat: %v", err)
	}
	size := dumpInfo.Size()

	logFilename := fmt.Sprintf("%s.log", dumpInfo.Name())
	pos, err := recover(logFilename)
	if err != nil {
		log.Fatalf("recover from log: %v", err)
	}
	if pos != 0 {
		log.Printf("seeking to %d in %q", pos, f.Name())
		if _, err = f.Seek(pos, os.SEEK_SET); err != nil {
			log.Fatalf("Seek: %v", err)
		}
	}

	logFile, err := os.OpenFile(logFilename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("os.OpenFile: %v", err)
	}
	defer logFile.Close()

	// buf[i:j] are the bytes that have been read from f but not
	// yet replayed. k indicates up to where we read in a
	// multi-line query.
	buf := make([]byte, 1024*1024)
	i, j, k, readErr := 0, 0, 0, error(nil)
	for {
		if p := bytes.IndexByte(buf[k:j], '\n'); p >= 0 {
			k += p + 1 // The +1 is for the trailing '\n'.
			pos += int64(p + 1)
			if replay(db, buf[i:k-1], pos, size) {
				i = k
				err = save(logFile, pos)
				if err != nil {
					log.Fatalf("Error saving to log: %v", err)
				}
			}
			continue
		}

		if readErr != nil {
			if readErr == io.EOF {
				if i != j {
					log.Println(i, j)
					log.Fatalf(`The contents of %q do not end with a "\n"`, *dump)
				}
				return
			}
			log.Fatal(readErr)
		}

		// First, make sure at least half of the buffer is empty. If we can do
		// that by moving the contents of buf[i:j] to the start of the existing
		// buffer, that's great. Otherwise, allocate a bigger buffer.
		newBuf := buf
		if j-i > len(buf)/2 {
			newBuf = make([]byte, len(buf)*2)
		}
		i, j, k = 0, copy(newBuf, buf[i:j]), k-i
		buf = newBuf
		// Read some more bytes.
		var n int
		n, readErr = f.Read(buf[j:])
		j += n
	}
}