From 0ca2a45cd4c93438c6443ce9cc2bf33bb276a3b4 Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Tue, 9 Apr 2024 09:18:44 -0400 Subject: [PATCH] Use a static identifier, use actual deadline value in payload --- ee/server/service/mdm.go | 17 +++++++---------- server/datastore/mysql/mdm.go | 31 ++++++++++++++++++++++++------- server/fleet/apple_mdm.go | 2 -- server/fleet/mdm.go | 4 ++++ 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/ee/server/service/mdm.go b/ee/server/service/mdm.go index 25b3e454d2..641b5de6e5 100644 --- a/ee/server/service/mdm.go +++ b/ee/server/service/mdm.go @@ -1056,9 +1056,6 @@ func (svc *Service) GetMDMDiskEncryptionSummary(ctx context.Context, teamID *uin } func (svc *Service) mdmAppleEditedMacOSUpdates(ctx context.Context, teamID *uint, updates fleet.MacOSUpdates) error { - // TODO: is there a notion of "DDM enabled" or not, where the DDM profile - // should not be created? - if updates.MinimumVersion.Value == "" { // OS updates disabled, remove the profile if err := svc.ds.DeleteMDMAppleDeclarationByName(ctx, teamID, mdm.FleetMacOSUpdatesProfileName); err != nil { @@ -1076,19 +1073,19 @@ func (svc *Service) mdmAppleEditedMacOSUpdates(ctx context.Context, teamID *uint // OS updates enabled, create or update the profile with the current settings - const macOSSoftwareUpdateType = `com.apple.configuration.softwareupdate.enforcement.specific` - ident := uuid.NewString() - // TODO(mna): is that correct payload? Identifier is a uuid? Is it ok if it - // changes on every update? + const ( + macOSSoftwareUpdateType = `com.apple.configuration.softwareupdate.enforcement.specific` + macOSSoftwareUpdateIdent = `macos-software-update-94f4bbdf-f439-4fb1-8d27-ae1bb793e105` + ) rawDecl := []byte(fmt.Sprintf(`{ "Identifier": %q, "Type": %q, "Payload": { "TargetOSVersion": %q, - "TargetLocalDateTime ": "2024-03-01T12:00:00," + "TargetLocalDateTime ": "%sT12:00:00" } -}`, ident, macOSSoftwareUpdateType, updates.MinimumVersion.Value)) - d := fleet.NewMDMAppleDeclaration(rawDecl, teamID, mdm.FleetMacOSUpdatesProfileName, macOSSoftwareUpdateType, ident) +}`, macOSSoftwareUpdateIdent, macOSSoftwareUpdateType, updates.MinimumVersion.Value, updates.Deadline.Value)) + d := fleet.NewMDMAppleDeclaration(rawDecl, teamID, mdm.FleetMacOSUpdatesProfileName, macOSSoftwareUpdateType, macOSSoftwareUpdateIdent) // associate the profile with the built-in label that ensures the host is on // macOS 14+ to receive that profile diff --git a/server/datastore/mysql/mdm.go b/server/datastore/mysql/mdm.go index 85881657a5..79a2e1df69 100644 --- a/server/datastore/mysql/mdm.go +++ b/server/datastore/mysql/mdm.go @@ -316,9 +316,10 @@ func (ds *Datastore) BulkSetPendingMDMHostProfiles( profileUUIDs, hostUUIDs []string, ) error { var ( - countArgs int - macProfUUIDs []string - winProfUUIDs []string + countArgs int + macProfUUIDs []string + winProfUUIDs []string + hasAppleDecls bool ) if len(hostIDs) > 0 { @@ -332,9 +333,14 @@ func (ds *Datastore) BulkSetPendingMDMHostProfiles( // split into mac and win profiles for _, puid := range profileUUIDs { - if strings.HasPrefix(puid, "a") { + if strings.HasPrefix(puid, fleet.MDMAppleProfileUUIDPrefix) { macProfUUIDs = append(macProfUUIDs, puid) + } else if strings.HasPrefix(puid, fleet.MDMAppleDeclarationUUIDPrefix) { + hasAppleDecls = true } else { + // Note: defaulting to windows profiles without checking the prefix as + // many tests fail otherwise and it's a whole rabbit hole that I can't + // address at the moment. winProfUUIDs = append(winProfUUIDs, puid) } } @@ -348,8 +354,19 @@ func (ds *Datastore) BulkSetPendingMDMHostProfiles( if countArgs == 0 { return nil } - if len(macProfUUIDs) > 0 && len(winProfUUIDs) > 0 { - return errors.New("profile uuids must all be Apple or Windows profiles") + + var countProfUUIDs int + if len(macProfUUIDs) > 0 { + countProfUUIDs++ + } + if len(winProfUUIDs) > 0 { + countProfUUIDs++ + } + if hasAppleDecls { + countProfUUIDs++ + } + if countProfUUIDs > 1 { + return errors.New("profile uuids must all be Apple profiles, Apple declarations or Windows profiles") } var ( @@ -417,7 +434,7 @@ WHERE return ds.withTx(ctx, func(tx sqlx.ExtContext) error { // TODO: this could be optimized to avoid querying for platform when // profileIDs or profileUUIDs are provided. - if len(hosts) == 0 { + if len(hosts) == 0 && !hasAppleDecls { uuidStmt, args, err := sqlx.In(uuidStmt, args...) if err != nil { return ctxerr.Wrap(ctx, err, "prepare query to load host UUIDs") diff --git a/server/fleet/apple_mdm.go b/server/fleet/apple_mdm.go index 22bd82d6d4..84a8dc9498 100644 --- a/server/fleet/apple_mdm.go +++ b/server/fleet/apple_mdm.go @@ -451,8 +451,6 @@ const ( DEPAssignProfileResponseFailed DEPAssignProfileResponseStatus = "FAILED" ) -const MDMAppleDeclarationUUIDPrefix = "d" - // NanoEnrollment represents a row in the nano_enrollments table managed by // nanomdm. It is meant to be used internally by the server, not to be returned // as part of endpoints, and as a precaution its json-encoding is explicitly diff --git a/server/fleet/mdm.go b/server/fleet/mdm.go index baa501bb4b..7d66519313 100644 --- a/server/fleet/mdm.go +++ b/server/fleet/mdm.go @@ -12,6 +12,10 @@ import ( const ( MDMPlatformApple = "apple" MDMPlatformMicrosoft = "microsoft" + + MDMAppleDeclarationUUIDPrefix = "d" + MDMAppleProfileUUIDPrefix = "a" + MDMWindowsProfileUUIDPrefix = "w" ) type AppleMDM struct {