2016-11-16 13:47:49 +00:00
package mysql
import (
2019-10-16 23:35:17 +00:00
"fmt"
2020-01-14 00:14:44 +00:00
"github.com/VividCortex/mysqlerr"
2021-06-06 22:07:29 +00:00
"github.com/fleetdm/fleet/server/fleet"
2020-01-14 00:14:44 +00:00
"github.com/go-sql-driver/mysql"
2020-05-29 16:12:39 +00:00
"github.com/jmoiron/sqlx"
2017-01-13 18:35:25 +00:00
"github.com/pkg/errors"
2016-11-16 13:47:49 +00:00
)
2021-06-06 22:07:29 +00:00
func ( d * Datastore ) NewAppConfig ( info * fleet . AppConfig ) ( * fleet . AppConfig , error ) {
2016-12-20 21:54:30 +00:00
if err := d . SaveAppConfig ( info ) ; err != nil {
2017-01-13 18:35:25 +00:00
return nil , errors . Wrap ( err , "new app config" )
2016-11-16 13:47:49 +00:00
}
2016-12-20 21:54:30 +00:00
return info , nil
2016-11-16 13:47:49 +00:00
}
2021-06-06 22:07:29 +00:00
func ( d * Datastore ) AppConfig ( ) ( * fleet . AppConfig , error ) {
info := & fleet . AppConfig { }
2016-11-16 13:47:49 +00:00
err := d . db . Get ( info , "SELECT * FROM app_configs LIMIT 1" )
if err != nil {
2017-01-13 18:35:25 +00:00
return nil , errors . Wrap ( err , "selecting app config" )
2016-11-16 13:47:49 +00:00
}
return info , nil
}
2019-10-16 23:35:17 +00:00
func ( d * Datastore ) isEventSchedulerEnabled ( ) ( bool , error ) {
rows , err := d . db . Query ( "SELECT @@event_scheduler" )
if err != nil {
return false , err
}
if ! rows . Next ( ) {
return false , errors . New ( "Error detecting MySQL event scheduler status." )
}
var value string
if err := rows . Scan ( & value ) ; err != nil {
return false , err
}
return value == "ON" , nil
}
func ( d * Datastore ) ManageHostExpiryEvent ( hostExpiryEnabled bool , hostExpiryWindow int ) error {
2019-11-12 22:41:16 +00:00
var err error
hostExpiryConfig := struct {
Window int ` db:"host_expiry_window" `
} { }
if err = d . db . Get ( & hostExpiryConfig , "SELECT host_expiry_window from app_configs LIMIT 1" ) ; err != nil {
return errors . Wrap ( err , "get expiry window setting" )
2019-10-16 23:35:17 +00:00
}
2019-11-12 22:41:16 +00:00
shouldUpdateWindow := hostExpiryEnabled && hostExpiryConfig . Window != hostExpiryWindow
if ! hostExpiryEnabled || shouldUpdateWindow {
if _ , err := d . db . Exec ( "DROP EVENT IF EXISTS host_expiry" ) ; err != nil {
2020-01-14 00:14:44 +00:00
if driverErr , ok := err . ( * mysql . MySQLError ) ; ! ok || driverErr . Number != mysqlerr . ER_DBACCESS_DENIED_ERROR {
return errors . Wrap ( err , "drop existing host_expiry event" )
}
2019-11-12 22:41:16 +00:00
}
}
if shouldUpdateWindow {
sql := fmt . Sprintf ( "CREATE EVENT IF NOT EXISTS host_expiry ON SCHEDULE EVERY 1 HOUR ON COMPLETION PRESERVE DO DELETE FROM hosts WHERE seen_time < DATE_SUB(NOW(), INTERVAL %d DAY)" , hostExpiryWindow )
if _ , err := d . db . Exec ( sql ) ; err != nil {
return errors . Wrap ( err , "create new host_expiry event" )
}
}
return nil
2019-10-16 23:35:17 +00:00
}
2021-06-06 22:07:29 +00:00
func ( d * Datastore ) SaveAppConfig ( info * fleet . AppConfig ) error {
2019-10-16 23:35:17 +00:00
eventSchedulerEnabled , err := d . isEventSchedulerEnabled ( )
if err != nil {
return err
}
if ! eventSchedulerEnabled && info . HostExpiryEnabled {
return errors . New ( "MySQL Event Scheduler must be enabled to configure Host Expiry." )
}
if err := d . ManageHostExpiryEvent ( info . HostExpiryEnabled , info . HostExpiryWindow ) ; err != nil {
return err
}
2016-12-20 21:54:30 +00:00
// Note that we hard code the ID column to 1, insuring that, if no rows
// exist, a row will be created with INSERT, if a row does exist the key
// will be violate uniqueness constraint and an UPDATE will occur
insertStatement := `
2021-06-23 01:02:20 +00:00
INSERT INTO app_configs (
id ,
org_name ,
org_logo_url ,
server_url ,
smtp_configured ,
smtp_sender_address ,
smtp_server ,
smtp_port ,
smtp_authentication_type ,
smtp_enable_ssl_tls ,
smtp_authentication_method ,
smtp_domain ,
smtp_user_name ,
smtp_password ,
smtp_verify_ssl_certs ,
smtp_enable_start_tls ,
entity_id ,
issuer_uri ,
idp_image_url ,
metadata ,
metadata_url ,
idp_name ,
enable_sso ,
enable_sso_idp_login ,
fim_interval ,
fim_file_accesses ,
host_expiry_enabled ,
host_expiry_window ,
live_query_disabled ,
additional_queries ,
agent_options ,
enable_analytics
)
VALUES ( 1 , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )
ON DUPLICATE KEY UPDATE
org_name = VALUES ( org_name ) ,
org_logo_url = VALUES ( org_logo_url ) ,
server_url = VALUES ( server_url ) ,
smtp_configured = VALUES ( smtp_configured ) ,
smtp_sender_address = VALUES ( smtp_sender_address ) ,
smtp_server = VALUES ( smtp_server ) ,
smtp_port = VALUES ( smtp_port ) ,
smtp_authentication_type = VALUES ( smtp_authentication_type ) ,
smtp_enable_ssl_tls = VALUES ( smtp_enable_ssl_tls ) ,
smtp_authentication_method = VALUES ( smtp_authentication_method ) ,
smtp_domain = VALUES ( smtp_domain ) ,
smtp_user_name = VALUES ( smtp_user_name ) ,
smtp_password = VALUES ( smtp_password ) ,
smtp_verify_ssl_certs = VALUES ( smtp_verify_ssl_certs ) ,
smtp_enable_start_tls = VALUES ( smtp_enable_start_tls ) ,
entity_id = VALUES ( entity_id ) ,
issuer_uri = VALUES ( issuer_uri ) ,
idp_image_url = VALUES ( idp_image_url ) ,
metadata = VALUES ( metadata ) ,
metadata_url = VALUES ( metadata_url ) ,
idp_name = VALUES ( idp_name ) ,
enable_sso = VALUES ( enable_sso ) ,
enable_sso_idp_login = VALUES ( enable_sso_idp_login ) ,
fim_interval = VALUES ( fim_interval ) ,
fim_file_accesses = VALUES ( fim_file_accesses ) ,
host_expiry_enabled = VALUES ( host_expiry_enabled ) ,
host_expiry_window = VALUES ( host_expiry_window ) ,
live_query_disabled = VALUES ( live_query_disabled ) ,
additional_queries = VALUES ( additional_queries ) ,
agent_options = VALUES ( agent_options ) ,
enable_analytics = VALUES ( enable_analytics )
2017-05-09 00:43:48 +00:00
`
2016-12-20 21:54:30 +00:00
2019-10-16 23:35:17 +00:00
_ , err = d . db . Exec ( insertStatement ,
2016-12-20 21:54:30 +00:00
info . OrgName ,
info . OrgLogoURL ,
2021-06-06 23:58:23 +00:00
info . ServerURL ,
2016-12-20 21:54:30 +00:00
info . SMTPConfigured ,
info . SMTPSenderAddress ,
info . SMTPServer ,
info . SMTPPort ,
info . SMTPAuthenticationType ,
info . SMTPEnableTLS ,
info . SMTPAuthenticationMethod ,
info . SMTPDomain ,
info . SMTPUserName ,
info . SMTPPassword ,
info . SMTPVerifySSLCerts ,
info . SMTPEnableStartTLS ,
2017-05-09 00:43:48 +00:00
info . EntityID ,
info . IssuerURI ,
info . IDPImageURL ,
info . Metadata ,
info . MetadataURL ,
info . IDPName ,
info . EnableSSO ,
2021-03-30 19:56:20 +00:00
info . EnableSSOIdPLogin ,
2018-02-26 20:54:13 +00:00
info . FIMInterval ,
info . FIMFileAccesses ,
2019-10-16 23:35:17 +00:00
info . HostExpiryEnabled ,
info . HostExpiryWindow ,
2020-01-14 00:53:04 +00:00
info . LiveQueryDisabled ,
2020-05-21 15:36:00 +00:00
info . AdditionalQueries ,
2021-06-17 20:47:15 +00:00
info . AgentOptions ,
2021-06-23 01:02:20 +00:00
info . EnableAnalytics ,
2016-11-16 13:47:49 +00:00
)
2016-12-20 21:54:30 +00:00
2016-11-16 13:47:49 +00:00
return err
}
2020-05-29 16:12:39 +00:00
2021-06-06 22:07:29 +00:00
func ( d * Datastore ) VerifyEnrollSecret ( secret string ) ( * fleet . EnrollSecret , error ) {
var s fleet . EnrollSecret
2021-05-31 16:02:05 +00:00
err := d . db . Get ( & s , "SELECT team_id FROM enroll_secrets WHERE secret = ?" , secret )
2020-05-29 16:12:39 +00:00
if err != nil {
2021-05-31 16:02:05 +00:00
return nil , errors . New ( "no matching secret found" )
2020-05-29 16:12:39 +00:00
}
2021-05-31 16:02:05 +00:00
return & s , nil
2020-05-29 16:12:39 +00:00
}
2021-06-06 22:07:29 +00:00
func ( d * Datastore ) ApplyEnrollSecrets ( teamID * uint , secrets [ ] * fleet . EnrollSecret ) error {
2020-05-29 16:12:39 +00:00
err := d . withRetryTxx ( func ( tx * sqlx . Tx ) error {
2021-05-31 16:02:05 +00:00
if teamID != nil {
sql := ` DELETE FROM enroll_secrets WHERE team_id = ? `
if _ , err := tx . Exec ( sql , teamID ) ; err != nil {
return errors . Wrap ( err , "clear before insert" )
}
} else {
sql := ` DELETE FROM enroll_secrets WHERE team_id IS NULL `
if _ , err := tx . Exec ( sql ) ; err != nil {
return errors . Wrap ( err , "clear before insert" )
}
}
for _ , secret := range secrets {
2020-05-29 16:12:39 +00:00
sql := `
2021-05-31 16:02:05 +00:00
INSERT INTO enroll_secrets ( secret , team_id )
VALUES ( ? , ? )
2020-05-29 16:12:39 +00:00
`
2021-05-31 16:02:05 +00:00
if _ , err := tx . Exec ( sql , secret . Secret , teamID ) ; err != nil {
2020-05-29 16:12:39 +00:00
return errors . Wrap ( err , "upsert secret" )
}
}
return nil
} )
return err
}
2021-06-06 22:07:29 +00:00
func ( d * Datastore ) GetEnrollSecrets ( teamID * uint ) ( [ ] * fleet . EnrollSecret , error ) {
2021-05-31 16:02:05 +00:00
var args [ ] interface { }
sql := "SELECT * FROM enroll_secrets WHERE "
// MySQL requires comparing NULL with IS. NULL = NULL evaluates to FALSE.
if teamID == nil {
sql += "team_id IS NULL"
} else {
sql += "team_id = ?"
args = append ( args , teamID )
}
2021-06-06 22:07:29 +00:00
var secrets [ ] * fleet . EnrollSecret
2021-05-31 16:02:05 +00:00
if err := d . db . Select ( & secrets , sql , args ... ) ; err != nil {
2020-05-29 16:12:39 +00:00
return nil , errors . Wrap ( err , "get secrets" )
}
2021-05-31 16:02:05 +00:00
return secrets , nil
2020-05-29 16:12:39 +00:00
}