go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/macos.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package resources 5 6 import ( 7 "bufio" 8 "bytes" 9 "encoding/json" 10 "errors" 11 "io" 12 "strings" 13 14 "go.mondoo.com/cnquery/providers-sdk/v1/util/convert" 15 "go.mondoo.com/cnquery/providers/os/connection/shared" 16 "go.mondoo.com/cnquery/providers/os/resources/macos" 17 "howett.net/plist" 18 ) 19 20 func (m *mqlMacos) userPreferences() (map[string]interface{}, error) { 21 conn := m.MqlRuntime.Connection.(shared.Connection) 22 preferences, err := macos.NewPreferences(conn).UserPreferences() 23 if err != nil { 24 return nil, err 25 } 26 27 return convert.JsonToDict(preferences) 28 } 29 30 func (m *mqlMacos) userHostPreferences() (map[string]interface{}, error) { 31 conn := m.MqlRuntime.Connection.(shared.Connection) 32 33 preferences, err := macos.NewPreferences(conn).UserHostPreferences() 34 if err != nil { 35 return nil, err 36 } 37 38 return convert.JsonToDict(preferences) 39 } 40 41 func (m *mqlMacos) globalAccountPolicies() (map[string]interface{}, error) { 42 conn := m.MqlRuntime.Connection.(shared.Connection) 43 44 cmd, err := conn.RunCommand("pwpolicy -getaccountpolicies") 45 if err != nil { 46 return nil, err 47 } 48 49 data, err := io.ReadAll(cmd.Stdout) 50 if err != nil { 51 return nil, err 52 } 53 54 return Decode(bytes.NewReader(data)) 55 } 56 57 // GetPreferences returns the time machine preferences 58 // 59 // NOTE: this cannot be implemented via: 60 // parse.plist('/Library/Preferences/com.apple.TimeMachine.plist').params['AutoBackup'] == 1 61 // since the binary is missing the Full Disk Access (FDA), therefore even applications with 62 // sudo permissions cannot access the file. Instead we need to call 63 // defaults read /Library/Preferences/com.apple.TimeMachine.plist which has FDA 64 // see https://developer.apple.com/forums/thread/108348 65 func (m *mqlMacosTimemachine) preferences() (map[string]interface{}, error) { 66 conn := m.MqlRuntime.Connection.(shared.Connection) 67 68 cmd, err := conn.RunCommand("defaults read /Library/Preferences/com.apple.TimeMachine.plist") 69 if err != nil { 70 return nil, err 71 } 72 73 var buf bytes.Buffer 74 scanner := bufio.NewScanner(cmd.Stdout) 75 for scanner.Scan() { 76 line := scanner.Text() 77 // skip the BackupAlias since they are not parsable when returned by the `defaults` command 78 if strings.HasPrefix(strings.TrimSpace(line), "BackupAlias") { 79 continue 80 } 81 buf.WriteString(line) 82 } 83 84 if err := scanner.Err(); err != nil { 85 return nil, err 86 } 87 88 return Decode(bytes.NewReader(buf.Bytes())) 89 } 90 91 func (m *mqlMacosSystemsetup) runCmd(command string) (string, error) { 92 conn := m.MqlRuntime.Connection.(shared.Connection) 93 94 cmd, err := conn.RunCommand(command) 95 if err != nil { 96 return "", err 97 } 98 99 data, err := io.ReadAll(cmd.Stdout) 100 if err != nil { 101 return "", err 102 } 103 104 // NOTE: systemsetup returns exit 0 even if it does not have enough permissions 105 // Therefore we need to handle this case here 106 if strings.TrimSpace(string(data)) == "You need administrator access to run this tool... exiting!" { 107 return "", errors.New("macos.systemsetup needs elevated permissions") 108 } 109 110 return string(data), nil 111 } 112 113 func (m *mqlMacosSystemsetup) date() (string, error) { 114 data, err := m.runCmd("systemsetup -getdate") 115 return macos.SystemSetupCmdOutput{}.ParseDate(data), err 116 } 117 118 func (m *mqlMacosSystemsetup) time() (string, error) { 119 data, err := m.runCmd("systemsetup -gettime") 120 return macos.SystemSetupCmdOutput{}.ParseTime(data), err 121 } 122 123 func (m *mqlMacosSystemsetup) timeZone() (string, error) { 124 data, err := m.runCmd("systemsetup -gettimezone") 125 return macos.SystemSetupCmdOutput{}.ParseTimeZone(data), err 126 } 127 128 func (m *mqlMacosSystemsetup) usingNetworkTime() (string, error) { 129 data, err := m.runCmd("systemsetup -getusingnetworktime") 130 return macos.SystemSetupCmdOutput{}.ParseUsingNetworktTime(data), err 131 } 132 133 func (m *mqlMacosSystemsetup) networkTimeServer() (string, error) { 134 data, err := m.runCmd("systemsetup -getnetworktimeserver") 135 return macos.SystemSetupCmdOutput{}.ParseNetworkTimeServer(data), err 136 } 137 138 func (m *mqlMacosSystemsetup) sleep() ([]interface{}, error) { 139 data, err := m.runCmd("systemsetup -getsleep") 140 return convert.SliceAnyToInterface(macos.SystemSetupCmdOutput{}.ParseSleep(data)), err 141 } 142 143 func (m *mqlMacosSystemsetup) displaySleep() (string, error) { 144 data, err := m.runCmd("systemsetup -getdisplaysleep") 145 return macos.SystemSetupCmdOutput{}.ParseDisplaySleep(data), err 146 } 147 148 func (m *mqlMacosSystemsetup) harddiskSleep() (string, error) { 149 data, err := m.runCmd("systemsetup -getdisplaysleep") 150 return macos.SystemSetupCmdOutput{}.ParseHardDiskSleep(data), err 151 } 152 153 func (m *mqlMacosSystemsetup) wakeOnModem() (string, error) { 154 data, err := m.runCmd("systemsetup -getwakeonmodem") 155 return macos.SystemSetupCmdOutput{}.ParseWakeOnModem(data), err 156 } 157 158 func (m *mqlMacosSystemsetup) wakeOnNetworkAccess() (string, error) { 159 data, err := m.runCmd("systemsetup -getwakeonnetworkaccess") 160 return macos.SystemSetupCmdOutput{}.ParseWakeOnNetwork(data), err 161 } 162 163 func (m *mqlMacosSystemsetup) restartPowerFailure() (string, error) { 164 data, err := m.runCmd("systemsetup -getrestartpowerfailure") 165 return macos.SystemSetupCmdOutput{}.ParseRestartPowerFailure(data), err 166 } 167 168 func (m *mqlMacosSystemsetup) restartFreeze() (string, error) { 169 data, err := m.runCmd("systemsetup -getrestartfreeze") 170 return macos.SystemSetupCmdOutput{}.ParseRestartFreeze(data), err 171 } 172 173 func (m *mqlMacosSystemsetup) allowPowerButtonToSleepComputer() (string, error) { 174 data, err := m.runCmd("systemsetup -getallowpowerbuttontosleepcomputer") 175 return macos.SystemSetupCmdOutput{}.ParseAllowPowerButtonToSleep(data), err 176 } 177 178 func (m *mqlMacosSystemsetup) remoteLogin() (string, error) { 179 data, err := m.runCmd("systemsetup -getremotelogin") 180 return macos.SystemSetupCmdOutput{}.ParseRemoteLogin(data), err 181 } 182 183 func (m *mqlMacosSystemsetup) remoteAppleEvents() (string, error) { 184 data, err := m.runCmd("systemsetup -getremoteappleevents") 185 return macos.SystemSetupCmdOutput{}.ParseRemoteAppleEvents(data), err 186 } 187 188 func (m *mqlMacosSystemsetup) computerName() (string, error) { 189 data, err := m.runCmd("systemsetup -getcomputername") 190 return macos.SystemSetupCmdOutput{}.ParseComputerName(data), err 191 } 192 193 func (m *mqlMacosSystemsetup) localSubnetName() (string, error) { 194 data, err := m.runCmd("systemsetup -getlocalsubnetname") 195 return macos.SystemSetupCmdOutput{}.ParseLocalSubnetname(data), err 196 } 197 198 func (m *mqlMacosSystemsetup) startupDisk() (string, error) { 199 data, err := m.runCmd("systemsetup -getstartupdisk") 200 return data, err 201 } 202 203 func (m *mqlMacosSystemsetup) waitForStartupAfterPowerFailure() (string, error) { 204 data, err := m.runCmd("systemsetup -getwaitforstartupafterpowerfailure") 205 return macos.SystemSetupCmdOutput{}.ParseWaitForStartupAfterPowerFailure(data), err 206 } 207 208 func (m *mqlMacosSystemsetup) disableKeyboardWhenEnclosureLockIsEngaged() (string, error) { 209 data, err := m.runCmd("systemsetup -getdisablekeyboardwhenenclosurelockisengaged") 210 return macos.SystemSetupCmdOutput{}.ParseDisableKeyboardWhenEnclosureLockIsEngaged(data), err 211 } 212 213 func Decode(r io.ReadSeeker) (map[string]interface{}, error) { 214 var data map[string]interface{} 215 decoder := plist.NewDecoder(r) 216 err := decoder.Decode(&data) 217 if err != nil { 218 return nil, err 219 } 220 221 // NOTE: we need to do the extra conversion here to make sure we use supported 222 // values by our dict structure: string, float64, int64 223 // plist also uses uint64 heavily which we do not support 224 // TODO: we really do not want to use the poor-man's json conversion version 225 jsondata, err := json.Marshal(data) 226 if err != nil { 227 return nil, err 228 } 229 230 var dataJson map[string]interface{} 231 err = json.Unmarshal(jsondata, &dataJson) 232 if err != nil { 233 return nil, err 234 } 235 236 return dataJson, nil 237 }