aysiu
04/29/2024, 10:30 PMSELECT pa.value deadline, pb.value os_version
FROM plist pa
INNER JOIN plist pb
ON split(pa.subkey,'\/',2) = split(pb.subkey,'\/',2)
WHERE pa.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pb.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pa.subkey LIKE '%TargetLocalDateTime%'
AND pb.subkey LIKE '%TargetOSVersion%'
This example is a table self-join (where the indexed primary key would be the best to join on) but even for regular INNER JOINs or LEFT JOINs on other tables, a key to join on would be helpful.aysiu
04/29/2024, 10:35 PMFG
04/29/2024, 10:39 PMaysiu
04/29/2024, 10:57 PM{
SUCorePersistedStateContentsType = SoftwareUpdateCorePersistedStateFile;
SUCorePersistedStateCoreFields = {
};
SUCorePersistedStateCoreSecureCodedObjectsFields = {
};
SUCorePersistedStateCoreVersion = "2.1.0";
SUCorePersistedStatePolicyFields = {
Declarations = {
"com.apple.RemoteManagement.SoftwareUpdateExtension/ABCDEFG123-1234-ABCD-5678-A1B2C3D4E5:abcdeFghiJKLMNOpqrstUVwxyz1234567890.abcdeFghiJKLMNOpqrstUVwxyz1234567890=" = {
RMStoreDeclarationKey = "com.apple.RemoteManagement.SoftwareUpdateExtension/ABCDEFG123-1234-ABCD-5678-A1B2C3D4E5:abcdeFghiJKLMNOpqrstUVwxyz1234567890.abcdeFghiJKLMNOpqrstUVwxyz1234567890=";
TargetLocalDateTime = "2023-11-14T00:00:00";
TargetOSVersion = "14.1.1";
};
};
};
SUCorePersistedStatePolicySecureCodedObjectsFields = {
};
SUCorePersistedStatePolicyVersion = "1.0";
}
More documentation here: https://www.sudoade.com/ddm-software-update-logs/aysiu
04/29/2024, 10:58 PMKathy Satterlee
04/30/2024, 1:08 AMKathy Satterlee
04/30/2024, 1:08 AMFG
04/30/2024, 11:17 AMaysiu
04/30/2024, 2:59 PMSince the queries are run on the host itself, using only the data available for that host, there’s no need to provide that unique key.That's fine if you query a single table, but when you're joining tables, you have to join on a common key. Do you have examples on how you recommend joining tables? How would you have done the self-join I posted above without using that
split()
workaround?
i can't speak to your specific implementation but in house we've used fleed for years and rely on fleet decorator queries to ensure that every event has the same fieldsI'm not familiar with decorator queries. Can you link some documentation that helped you?
FG
04/30/2024, 3:13 PMKathy Satterlee
04/30/2024, 3:18 PMON
entirely.
SELECT pa.value deadline, pb.value os_version
FROM plist pa, plist pb
WHERE pa.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pb.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pa.subkey LIKE '%TargetLocalDateTime%'
AND pb.subkey LIKE '%TargetOSVersion%'
Kathy Satterlee
04/30/2024, 3:18 PMKathy Satterlee
04/30/2024, 3:21 PMSELECT value , subkey
FROM plist
WHERE path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND subkey LIKE '%TargetLocalDateTime%'
OR subkey LIKE '%TargetOSVersion%'
Kathy Satterlee
04/30/2024, 3:28 PMKathy Satterlee
04/30/2024, 3:29 PMKathy Satterlee
04/30/2024, 3:30 PMKathy Satterlee
04/30/2024, 3:40 PMafter
the results have been sent. the query, in its entirety, is running locally on each host that you're querying.aysiu
05/06/2024, 8:57 PMI think that the key piece of information here is that a shared key like hostname or serial number isn't really needed because it would always match across every row in every table because the osquery db exists locally on each host.I disagree here. Let's say I want to look at the values from that query (which is on the plist table), but I also want to get corresponding values (same hosts) from the os_version table. Can you give an example of how you do that without joining on the hostname or serial number?
FG
05/06/2024, 10:35 PMFG
05/06/2024, 10:37 PMFG
05/06/2024, 10:45 PMWITH query1 AS (SELECT * FROM plist WHERE path = '/Users/blah/Library/LaunchAgents/org.nginx.nginx.plist'), query2 AS (SELECT * FROM os_version) SELECT query1.*,query2.* FROM query1, query2;
FG
05/06/2024, 10:48 PMaysiu
05/06/2024, 10:51 PMSELECT pa.value deadline, pb.value enforced_os_version, NULL current_version
FROM plist pa
INNER JOIN plist pb
ON split(pa.subkey,'\/',2) = split(pb.subkey,'\/',2)
WHERE pa.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pb.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pa.subkey LIKE '%TargetLocalDateTime%'
AND pb.subkey LIKE '%TargetOSVersion%'
UNION
SELECT NULL deadline, NULL enforced_os_version, version current_version
FROM os_version
I just get results from the first query and then results from the second query (intermixed, of course, but all on separate lines). That's how a UNION works. I don't want a UNION. I want a join. I want to be able to have the current OS version next to the enforced OS version and the deadline for a single machine.
I don't think I'm asking for something wild here. Being able to join tables is a fairly standard SQL/MySQL query practice.FG
05/06/2024, 11:22 PMKathy Satterlee
05/06/2024, 11:43 PMSELECT pa.value deadline, pb.value enforced_os_version, ov.current_version
FROM plist pa
INNER JOIN plist pb
ON split(pa.subkey,'\/',2) = split(pb.subkey,'\/',2)
WHERE pa.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pb.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pa.subkey LIKE '%TargetLocalDateTime%'
AND pb.subkey LIKE '%TargetOSVersion%'
JOIN os_version ov
Kathy Satterlee
05/06/2024, 11:52 PMSELECT pa.value deadline, pb.value enforced_os_version, ov.version current_version
FROM plist pa
INNER JOIN plist pb
ON split(pa.subkey,'\/',2) = split(pb.subkey,'\/',2)
WHERE pa.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pb.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pa.subkey LIKE '%TargetLocalDateTime%'
AND pb.subkey LIKE '%TargetOSVersion%'
JOIN os_version ov
I'd also be curious to see what you get for this:
SELECT pa.value deadline, pb.value os_version, ov.version current_version
FROM plist pa, plist pb, os_version ov
WHERE pa.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pb.path = '/var/db/softwareupdate/SoftwareUpdateDDMStatePersistence.plist'
AND pa.subkey LIKE '%TargetLocalDateTime%'
AND pb.subkey LIKE '%TargetOSVersion%'
FG
05/06/2024, 11:58 PMFG
05/06/2024, 11:59 PM+------------+------------+-----------------+
| deadline | os_version | current_version |
+------------+------------+-----------------+
| 2024/05/07 | 20.20.20 | 14.4.1 |
+------------+------------+-----------------+
$ cat /tmp/example.plist
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>TargetOSVersion</key>
<string>20.20.20</string>
<key>TargetLocalDateTime</key>
<string>2024/05/07</string>
</dict>
</plist>
FG
05/07/2024, 12:00 AMWITH policy AS (SELECT pa.value deadline, pb.value os_version
FROM plist pa, plist pb
WHERE pa.path = '/tmp/example.plist'
AND pb.path = '/tmp/example.plist'
AND pa.key LIKE '%TargetLocalDateTime%'
AND pb.key LIKE '%TargetOSVersion%'
)
SELECT deadline, os_version, version current_version FROM policy, os_version;
FG
05/07/2024, 12:02 AMWITH policy AS (SELECT pa.value deadline, pb.value os_version
FROM plist pa, plist pb
WHERE pa.path = '/tmp/example.plist'
AND pb.path = '/tmp/example.plist'
AND pa.key LIKE '%TargetLocalDateTime%'
AND pb.key LIKE '%TargetOSVersion%'
)
SELECT deadline, os_version, version current_version
FROM policy, os_version
WHERE os_version <> current_version;
Kathy Satterlee
05/07/2024, 12:03 AMKathy Satterlee
05/07/2024, 12:08 AM