├── carthage.sh
├── Cartfile
├── shared
├── images
│ ├── logo.png
│ ├── dndIcon.png
│ ├── dndText.png
│ ├── appStore.pdf
│ ├── dndText@2x.png
│ ├── dndText copy.png
│ └── objectiveSee.png
├── preferences.plist
├── XPCUserProto.h
├── Update.h
├── Logging.h
├── XPCDaemonProto.h
├── XPC.h
├── XPCDaemonClient.h
├── UpdateWindowController.h
├── Utilities.h
├── Update.m
├── UpdateWindowController.m
├── Logging.m
└── XPCDaemonClient.m
├── mainApp
├── mainApp
│ ├── Images
│ │ ├── one.png
│ │ ├── two.png
│ │ ├── alert.png
│ │ ├── close.png
│ │ ├── hacker.png
│ │ ├── laptop.png
│ │ ├── linked.png
│ │ ├── logo.png
│ │ ├── logoBG.png
│ │ ├── scan.png
│ │ ├── three.png
│ │ ├── checkbox.png
│ │ ├── closeAlt.png
│ │ ├── logoOver.png
│ │ ├── settings.png
│ │ ├── connected.png
│ │ ├── mobilePhone.png
│ │ ├── prefsAction.png
│ │ ├── prefsLink.png
│ │ ├── prefsUpdate.png
│ │ ├── unconnected.png
│ │ └── prefsGeneral.png
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ ├── icon_16x16.png
│ │ │ ├── icon_32x32.png
│ │ │ ├── icon_128x128.png
│ │ │ ├── icon_16x16@2x.png
│ │ │ ├── icon_256x256.png
│ │ │ ├── icon_32x32@2x.png
│ │ │ ├── icon_512x512.png
│ │ │ ├── icon_128x128@2x.png
│ │ │ ├── icon_256x256@2x.png
│ │ │ └── Contents.json
│ ├── patrons.txt
│ ├── QuickResponseCode.h
│ ├── AboutWindowController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── Info.plist
│ ├── WelcomeWindowController.h
│ ├── 3rdParty
│ │ ├── HyperlinkTextField.h
│ │ └── HyperlinkTextField.m
│ ├── AboutWindowController.m
│ ├── Base.lproj
│ │ └── MainMenu.xib
│ ├── PrefsWindowController.h
│ └── QuickResponseCode.m
└── mainApp.xcodeproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ └── xcshareddata
│ └── xcschemes
│ └── mainApp.xcscheme
├── loginItem
├── loginItem
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── icon_16x16.png
│ │ │ ├── icon_32x32.png
│ │ │ ├── icon_128x128.png
│ │ │ ├── icon_16x16@2x.png
│ │ │ ├── icon_256x256.png
│ │ │ ├── icon_32x32@2x.png
│ │ │ ├── icon_512x512.png
│ │ │ ├── icon_128x128@2x.png
│ │ │ ├── icon_256x256@2x.png
│ │ │ └── Contents.json
│ │ └── statusIcon.imageset
│ │ │ ├── statusIcon.png
│ │ │ ├── statusIcon@2x.png
│ │ │ └── Contents.json
│ ├── Images
│ │ ├── popoverClose.png
│ │ ├── statusIcon.png
│ │ ├── statusIcon@2x.png
│ │ ├── popoverCloseAlt.png
│ │ ├── statusIconWhite.png
│ │ ├── statusIconDisabled.png
│ │ ├── statusIconWhite@2x.png
│ │ ├── statusIconDisabled@2x.png
│ │ ├── statusIconDisabledWhite.png
│ │ └── statusIconDisabledWhite@2x.png
│ ├── StatusBarPopoverController.h
│ ├── XPCUser.h
│ ├── Camera.h
│ ├── StatusBarPopoverController.m
│ ├── StatusBarMenu.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── Info.plist
│ ├── 3rdParty
│ │ ├── HyperlinkTextField.h
│ │ └── HyperlinkTextField.m
│ ├── Base.lproj
│ │ └── MainMenu.xib
│ ├── XPCUser.m
│ ├── AppReceipt.h
│ ├── StatusBarPopover.xib
│ └── Camera.m
└── loginItem.xcodeproj
│ └── project.xcworkspace
│ └── contents.xcworkspacedata
├── configure
├── Configure
│ ├── Images
│ │ ├── digita.png
│ │ └── malwarebytes.png
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ ├── icon_16x16.png
│ │ │ ├── icon_32x32.png
│ │ │ ├── icon_128x128.png
│ │ │ ├── icon_16x16@2x.png
│ │ │ ├── icon_256x256.png
│ │ │ ├── icon_32x32@2x.png
│ │ │ ├── icon_512x512.png
│ │ │ ├── icon_128x128@2x.png
│ │ │ ├── icon_256x256@2x.png
│ │ │ └── Contents.json
│ ├── AboutWindowController.h
│ ├── HelperComms.h
│ ├── Configure.h
│ ├── MainMenu.xib
│ ├── AppDelegate.h
│ ├── Info.plist
│ ├── ConfigureWindowController.h
│ ├── AboutWindowController.m
│ ├── Script
│ │ └── configure.sh
│ ├── main.m
│ ├── HelperComms.m
│ └── AppDelegate.m
├── configure.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── configure.xcscheme
├── Helper
│ ├── HelperInterface.h
│ ├── launchDaemon.plist
│ ├── Info.plist
│ ├── HelperListener.h
│ ├── Helper.m
│ └── HelperListener.m
└── Shared
│ └── XPCProtocol.h
├── launchDaemon
├── Resources
│ ├── deviceCSRRequest.p12
│ ├── rootCA.pem
│ └── awsRootCA.pem
├── launchDaemon
│ ├── libs
│ │ ├── libprocInfo.a
│ │ └── procInfo.h
│ ├── main.h
│ ├── monitor
│ │ ├── VolumeMonitor.h
│ │ ├── DownloadMonitor.h
│ │ ├── AuthEvent.m
│ │ ├── ProcListener.h
│ │ ├── AuthEvent.h
│ │ ├── ThunderboltMonitor.h
│ │ ├── USBMonitor.h
│ │ ├── UserAuthMonitor.h
│ │ ├── VolumeMonitor.m
│ │ ├── Monitor.h
│ │ ├── ProcListener.m
│ │ ├── DownloadMonitor.m
│ │ ├── USBMonitor.m
│ │ └── ThunderboltMonitor.m
│ ├── FrameworkInterface.h
│ ├── com.objective-see.dnd.plist
│ ├── XPCDaemon.h
│ ├── NSMutableArray+QueueAdditions.h
│ ├── Preferences.h
│ ├── XPCListener.h
│ ├── NSMutableArray+QueueAdditions.m
│ ├── Lid.h
│ ├── FrameworkInterface.m
│ └── XPCListener.m
├── launchDaemon.xcodeproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── Info.plist
├── dnd.xcworkspace
├── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── contents.xcworkspacedata
├── Cartfile.resolved
├── .gitignore
└── README.md
/carthage.sh:
--------------------------------------------------------------------------------
1 | carthage update dnd --platform macOS
2 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "DigitaSecurity/dnd" "cameraUpdates"
2 | github "getsentry/sentry-cocoa" "4.1.0"
3 |
--------------------------------------------------------------------------------
/shared/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/shared/images/logo.png
--------------------------------------------------------------------------------
/shared/images/dndIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/shared/images/dndIcon.png
--------------------------------------------------------------------------------
/shared/images/dndText.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/shared/images/dndText.png
--------------------------------------------------------------------------------
/shared/images/appStore.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/shared/images/appStore.pdf
--------------------------------------------------------------------------------
/shared/images/dndText@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/shared/images/dndText@2x.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/one.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/one.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/two.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/two.png
--------------------------------------------------------------------------------
/shared/images/dndText copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/shared/images/dndText copy.png
--------------------------------------------------------------------------------
/shared/images/objectiveSee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/shared/images/objectiveSee.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/alert.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/close.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/hacker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/hacker.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/laptop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/laptop.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/linked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/linked.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/logo.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/logoBG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/logoBG.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/scan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/scan.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/three.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/three.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/checkbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/checkbox.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/closeAlt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/closeAlt.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/logoOver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/logoOver.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/settings.png
--------------------------------------------------------------------------------
/configure/Configure/Images/digita.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Images/digita.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/connected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/connected.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/mobilePhone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/mobilePhone.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/prefsAction.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/prefsAction.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/prefsLink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/prefsLink.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/prefsUpdate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/prefsUpdate.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/unconnected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/unconnected.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Images/prefsGeneral.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Images/prefsGeneral.png
--------------------------------------------------------------------------------
/configure/Configure/Images/malwarebytes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Images/malwarebytes.png
--------------------------------------------------------------------------------
/launchDaemon/Resources/deviceCSRRequest.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/launchDaemon/Resources/deviceCSRRequest.p12
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/popoverClose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/popoverClose.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/statusIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/statusIcon.png
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/libs/libprocInfo.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/launchDaemon/launchDaemon/libs/libprocInfo.a
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/statusIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/statusIcon@2x.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/popoverCloseAlt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/popoverCloseAlt.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/statusIconWhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/statusIconWhite.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/statusIconDisabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/statusIconDisabled.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/statusIconWhite@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/statusIconWhite@2x.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/statusIconDisabled@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/statusIconDisabled@2x.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/statusIconDisabledWhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/statusIconDisabledWhite.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Images/statusIconDisabledWhite@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Images/statusIconDisabledWhite@2x.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/statusIcon.imageset/statusIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/statusIcon.imageset/statusIcon.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/statusIcon.imageset/statusIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/statusIcon.imageset/statusIcon@2x.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/configure/Configure/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objective-see/DoNotDisturb/HEAD/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/mainApp/mainApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/loginItem/loginItem.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/mainApp/mainApp/patrons.txt:
--------------------------------------------------------------------------------
1 | Patrons:
2 | Halo Privacy, Ash Morgan, Jesse Daguanno, Beau Galbraith, Nando Mendonca, Khalil Sehnaoui, Jeff Golden, Geoffrey Weber, Randy Wong, Gamer_Bot
3 |
4 | Friends of Objective-See:
5 | Digita Security, Malwarebytes, Don MacAskill
6 |
--------------------------------------------------------------------------------
/configure/configure.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/dnd.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/shared/preferences.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | contactAction
6 |
7 | headlessMode
8 |
9 | passiveMode
10 |
11 | updateMode
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/loginItem/loginItem/StatusBarPopoverController.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: StatusBarPopoverController.h
3 | // project: DND (login item)
4 | // description: controller for status bar popover (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | @interface StatusBarPopoverController : NSViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/loginItem/loginItem/XPCUser.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCUser.h
3 | // project: DND (login item)
4 | // description: user XPC methods (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 | #import
12 |
13 | #import "XPCUserProto.h"
14 |
15 | @interface XPCUser : NSObject
16 | {
17 |
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/configure/Helper/HelperInterface.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: HelperInterface.h
3 | // project: (open-source) installer
4 | // description: interface for app installer comms (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | #import "XPCProtocol.h"
13 | #import "HelperInterface.h"
14 |
15 | @interface HelperInterface : NSObject
16 | {
17 |
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/configure/Helper/launchDaemon.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Label
6 | com.objective-see.dnd.installer.helper
7 | MachServices
8 |
9 | com.objective-see.dnd.installer.helper
10 |
11 |
12 | EnableTransactions
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/statusIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "statusIcon.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "statusIcon@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/main.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: main.h
3 | // project: DND (launch daemon)
4 | // description: main interface/entry point for launch daemon (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | /* FUNCTIONS */
11 |
12 | //uninstall
13 | // remove DND identity
14 | BOOL uninstall(void);
15 |
16 | //init a handler for SIGTERM
17 | // can perform actions such as closing logging
18 | void register4Shutdown(void);
19 |
20 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/VolumeMonitor.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: VolumeMonitor.h
3 | // project: DND (launch daemon)
4 | // description: mounted volumes monitor (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 | @import Foundation;
12 |
13 | @interface VolumeMonitor : NSObject
14 |
15 | /* PROPERTIES */
16 |
17 | /* METHODS */
18 |
19 | //start monitoring
20 | -(void)start;
21 |
22 | //stop monitoring
23 | -(void)stop;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/loginItem/loginItem/Camera.h:
--------------------------------------------------------------------------------
1 | //
2 | // Camera.h
3 | // loginItem
4 | //
5 | // Created by Patrick Wardle on 9/1/18.
6 | // Copyright © 2018 Objective-See. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface Camera : NSObject
13 |
14 | /* PROPERTIES */
15 |
16 | //av session
17 | @property(nonatomic, retain)AVCaptureSession* session;
18 |
19 | /* METHODS */
20 |
21 | //capture an image from the webcam
22 | -(NSData*)captureImage;
23 |
24 |
25 |
26 | @end
27 |
28 |
--------------------------------------------------------------------------------
/shared/XPCUserProto.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCUserProtocol
3 | // project: DND (shared)
4 | // description: protocol for talking to the user (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | @protocol XPCUserProtocol
13 |
14 | //show an alert
15 | // returns with rep
16 | -(void)alertShow:(NSDictionary*)alert;
17 |
18 | //dismiss alert(s)
19 | -(void)alertDismiss;
20 |
21 | //take a picture
22 | -(void)captureImage:(void (^)(NSData *))reply;
23 |
24 | @end
25 |
26 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/DownloadMonitor.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: DownloadMonitor.h
3 | // project: DND (launch daemon)
4 | // description: download file monitor (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | @interface DownloadMonitor : NSObject
13 |
14 | /* PROPERTIES */
15 |
16 | //query
17 | @property(nonatomic, retain)NSMetadataQuery* query;
18 |
19 | /* METHODS */
20 |
21 | //start monitoring
22 | -(void)start;
23 |
24 | //stop monitoring
25 | -(void)stop;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/shared/Update.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: Update.h
3 | // project: DND (shared)
4 | // description: checks for new versions of DND (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 |
11 | #ifndef Update_h
12 | #define Update_h
13 |
14 | @import Foundation;
15 |
16 | @interface Update : NSObject
17 |
18 |
19 | //check for an update
20 | // will invoke app delegate method to update UI when check completes
21 | -(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler;
22 |
23 | @end
24 |
25 |
26 | #endif /* Update_h */
27 |
--------------------------------------------------------------------------------
/loginItem/loginItem/StatusBarPopoverController.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: StatusBarPopoverController.h
3 | // project: DND (login item)
4 | // description: controller for status bar popover
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "AppDelegate.h"
11 | #import "StatusBarPopoverController.h"
12 |
13 | @implementation StatusBarPopoverController
14 |
15 | //'close' button handler
16 | // simply close popover
17 | -(IBAction)interactionHandler:(NSControl *)sender
18 | {
19 | //close
20 | [[[self view] window] close];
21 |
22 | return;
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/configure/Shared/XPCProtocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: userCommsInterface.h
3 | // project: DND (shared)
4 | // description: protocol for talking to the daemon
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #ifndef userCommsInterface_h
11 | #define userCommsInterface_h
12 |
13 | @import Foundation;
14 |
15 | @protocol XPCProtocol
16 |
17 | //install
18 | -(void)install:(NSString*)app reply:(void (^)(NSNumber*))reply;
19 |
20 | //uninstall
21 | -(void)uninstall:(NSString*)app full:(BOOL)full reply:(void (^)(NSNumber*))reply;
22 |
23 | //remove (self)
24 | -(void)remove;
25 |
26 | @end
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/FrameworkInterface.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: FrameworkInterface.h
3 | // project: DND (launch daemon)
4 | // description: interface to Digita Security's (swift) framework (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import
11 |
12 | @import Foundation;
13 |
14 | @interface FrameworkInterface : NSObject
15 |
16 | /* METHODS */
17 |
18 | //identity
19 | @property(nonatomic, retain)DNDIdentity *identity;
20 |
21 | //initialize an identity for DND comms
22 | // generates client id, etc. and then creates identity
23 | -(BOOL)initIdentity:(BOOL)full;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/AuthEvent.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: AuthEvent.h
3 | // project: DND (launch daemon)
4 | // description: user authentication event object
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "AuthEvent.h"
11 |
12 | @implementation AuthEvent
13 |
14 | //for pretty print
15 | -(NSString *)description
16 | {
17 | //description
18 | NSString *description = nil;
19 |
20 | //init
21 | description = [NSString stringWithFormat:@"user auth event \n uid: %d / pid: %d / text: %@ / ret: %d\n", self.uid, self.pid, self.text, self.result];
22 |
23 | return description;
24 | }
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/mainApp/mainApp/QuickResponseCode.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: QuickResponseCode.h
3 | // project: DND (main app)
4 | // description: QR Code logic (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 | @import Foundation;
12 |
13 | #import "XPCDaemonClient.h"
14 |
15 | @interface QuickResponseCode : NSObject
16 |
17 | /* PROPERTIES */
18 |
19 | //daemon comms obj
20 | @property(nonatomic, retain)XPCDaemonClient* daemonComms;
21 |
22 |
23 | /* METHODS */
24 |
25 | //generate a QRC code
26 | // gets QRC string from image, then generates image
27 | -(void)generateQRC:(float)size reply:(void (^)(NSImage* qrc))reply;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/configure/Configure/AboutWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: AboutWindowController.h
3 | // project: DND (config)
4 | // description: window showing 'about' info (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | @interface AboutWindowController : NSWindowController
13 | {
14 |
15 | }
16 |
17 | /* PROPERTIES */
18 |
19 | //version label/string
20 | @property (weak, atomic) IBOutlet NSTextField *versionLabel;
21 |
22 | //patrons
23 | @property (unsafe_unretained, atomic) IBOutlet NSTextView *patrons;
24 |
25 | //'support us' button
26 | @property (weak, atomic) IBOutlet NSButton *supportUs;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/com.objective-see.dnd.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MachServices
6 |
7 | com.objective-see.dndDaemon
8 |
9 |
10 | Label
11 | com.objective-see.dnd
12 | ProgramArguments
13 |
14 | /Library/Objective-See/DND/Do Not Disturb.bundle/Contents/MacOS/Do Not Disturb
15 |
16 | RunAtLoad
17 |
18 | LSUIElement
19 |
20 | EnableTransactions
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/XPCDaemon.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCDaemon.h
3 | // project: DND (launch daemon)
4 | // description: interface for user XPC methods (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 | #import
12 |
13 | #import "XPCDaemonProto.h"
14 |
15 |
16 | @interface XPCDaemon : NSObject
17 | {
18 |
19 | }
20 |
21 | /* PROPERTIES */
22 |
23 | //registration info from server
24 | @property(nonatomic,retain)NSDictionary *registrationInfo;
25 |
26 | //registration wait semaphore
27 | @property dispatch_semaphore_t registrationSema;
28 |
29 | /* METHODS */
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/shared/Logging.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: Logging.h
3 | // project: DND (shared)
4 | // description: logging (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #ifndef __DND__Logging__
11 | #define __DND__Logging__
12 |
13 | @import Foundation;
14 | #import
15 |
16 | //log to file flag
17 | #define LOG_TO_FILE 0x10
18 |
19 | //log a msg to syslog
20 | // also disk, if error
21 | void logMsg(int level, NSString* msg);
22 |
23 | //prep/open log file
24 | BOOL initLogging(void);
25 |
26 | //get path to log file
27 | NSString* logFilePath(void);
28 |
29 | //de-init logging
30 | void deinitLogging(void);
31 |
32 | //log to file
33 | void log2File(NSString* msg);
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "Alamofire/Alamofire" "4.7.3"
2 | github "Alamofire/AlamofireImage" "75fadf98aab78c0829923dd496f369950aa32d6f"
3 | github "DigitaSecurity/CocoaAsyncSocket" "79a11b7036d0a77ca95de42cc1c92b5a4c50f0c9"
4 | github "DigitaSecurity/dnd" "d9a93e985b83d537942e561f028e39b978cb56a5"
5 | github "SnapKit/SnapKit" "4.0.0"
6 | github "SwiftyJSON/SwiftyJSON" "4.1.0"
7 | github "emaloney/CleanroomLogger" "5.1.0"
8 | github "emqtt/CocoaMQTT" "b851bdabc01dd98dda9781765ad510d818773819"
9 | github "getsentry/sentry-cocoa" "4.1.0"
10 | github "ninjaprox/NVActivityIndicatorView" "4.3.0"
11 | github "radex/SwiftyTimer" "2.0.0"
12 | github "realm/realm-cocoa" "11dd806fcaacd680d12d616b3a5e93d85bf942f9"
13 | github "saoudrizwan/Disk" "0.3.3"
14 | github "soffes/CommonCrypto" "v1.1.0"
15 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/ProcListener.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: ProcListener.h
3 | // project: DND (launch daemon)
4 | // description: interface with process monitor library (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 |
11 | @import Foundation;
12 |
13 | #import "procInfo.h"
14 |
15 | @interface ProcessMonitor : NSObject
16 | {
17 |
18 | }
19 |
20 | /* PROPERTIES */
21 |
22 | //process info (monitor) object
23 | @property(nonatomic, retain)ProcInfo* procMon;
24 |
25 | //list of active processes
26 | @property(nonatomic, retain)NSMutableDictionary* processes;
27 |
28 | /* METHODS */
29 |
30 | //init
31 | -(id)init;
32 |
33 | //start
34 | -(void)start;
35 |
36 | //stop
37 | -(void)stop;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/mainApp/mainApp/AboutWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: AboutWindowController.h
3 | // project: DND (main app)
4 | // description: 'about' window controller (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | @interface AboutWindowController : NSWindowController
13 | {
14 |
15 | }
16 |
17 | /* PROPERTIES */
18 |
19 | //version label/string
20 | @property (weak) IBOutlet NSTextField *versionLabel;
21 |
22 | //patrons
23 | @property (unsafe_unretained) IBOutlet NSTextView *patrons;
24 |
25 | /* METHODS */
26 |
27 | //automatically invoked when user clicks any of the buttons
28 | // perform actions, such as loading patreon or products URL
29 | -(IBAction)buttonHandler:(id)sender;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/shared/XPCDaemonProto.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCDaemonProtocol.h
3 | // project: DND (shared)
4 | // description: methods exported by the daemon
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | @protocol XPCDaemonProtocol
13 |
14 | //process qrc request from client
15 | -(void)qrcRequest:(void (^)(NSData *))reply;
16 |
17 | //wait for phone to complete registration
18 | // calls into framework that comms w/ server to wait for phone
19 | -(void)recvRegistrationACK:(void (^)(NSDictionary* registrationInfo))reply;
20 |
21 | //get preferences
22 | -(void)getPreferences:(NSString*)preference reply:(void (^)(NSDictionary* preferences))reply;
23 |
24 | //update preferences
25 | -(void)updatePreferences:(NSDictionary*)preferences;
26 |
27 | @end
28 |
29 |
--------------------------------------------------------------------------------
/loginItem/loginItem/StatusBarMenu.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: StatusBarMenu.h
3 | // project: DND (login item)
4 | // description: menu handler for status bar icon (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | #import "XPCDaemonClient.h"
13 |
14 | @interface StatusBarMenu : NSObject
15 | {
16 |
17 | }
18 |
19 | //status item
20 | @property (nonatomic, strong, readwrite) NSStatusItem *statusItem;
21 |
22 | //popover
23 | @property (retain, nonatomic)NSPopover *popover;
24 |
25 | //daemom comms object
26 | @property (nonatomic, retain)XPCDaemonClient* daemonComms;
27 |
28 | //disabled flag
29 | @property BOOL isDisabled;
30 |
31 | /* METHODS */
32 |
33 | //init
34 | -(id)init:(NSMenu*)menu firstTime:(BOOL)firstTime;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/AuthEvent.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: AuthEvent.h
3 | // project: DND (launch daemon)
4 | // description: user authentication event object (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | @interface AuthEvent : NSObject
13 |
14 | /* PROPERTIES */
15 |
16 | //type
17 | // used by audit
18 | @property u_int16_t type;
19 |
20 | //process did auth
21 | @property pid_t pid;
22 |
23 | //uid
24 | @property uid_t uid;
25 |
26 | //text from audit event
27 | @property(nonatomic, retain)NSString* text;
28 |
29 | //auth result
30 | @property(nonatomic) u_int32_t result;
31 |
32 | //flag for touch ID events
33 | @property(nonatomic) BOOL wasTouchID;
34 |
35 | //timestamp
36 | @property(nonatomic, retain)NSDate* timestamp;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/NSMutableArray+QueueAdditions.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: NSMutableArray+QueueAdditions.h
3 | // project: DND (launch daemon)
4 | // description: queue implementation via NSMutableArray (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 | // note: based on https://github.com/esromneb/ios-queue-object/blob/master/NSMutableArray%2BQueueAdditions.m
10 |
11 | @import Foundation;
12 |
13 | @interface NSMutableArray (QueueAdditions)
14 | {
15 |
16 | }
17 |
18 | /* METHODS */
19 |
20 | //add object to end of queue
21 | -(void)enqueue:(id)item;
22 |
23 | //grab first item
24 | // and then remove it from queue
25 | -(id)dequeue;
26 |
27 | //grab first item
28 | // but don't remove it from queue
29 | -(id)peek;
30 |
31 | //determine if queue is empty
32 | -(BOOL)isEmpty;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/configure/Configure/HelperComms.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: HelperComms.h
3 | // project: DND (shared)
4 | // description: talk to daemon (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | #import "XPCProtocol.h"
13 |
14 |
15 | @interface HelperComms : NSObject
16 |
17 | //remote deamon proxy object
18 | @property(nonatomic, retain) id daemon;
19 |
20 | //xpc connection
21 | @property (atomic, strong, readwrite) NSXPCConnection* xpcServiceConnection;
22 |
23 | /* METHODS */
24 |
25 | //install
26 | // takes flag to indicate full/partial
27 | -(void)install:(void (^)(NSNumber*))reply;
28 |
29 | //uninstall
30 | // takes flag to indicate full/partial
31 | -(void)uninstall:(BOOL)full reply:(void (^)(NSNumber*))reply;
32 |
33 | //remove
34 | -(void)remove;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/launchDaemon/Resources/rootCA.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICKDCCAc6gAwIBAgIJAOa/jOb/vBpZMAoGCCqGSM49BAMCMGcxCzAJBgNVBAYT
3 | AlVTMQswCQYDVQQIDAJNRDEPMA0GA1UEBwwGRnVsdG9uMQ8wDQYDVQQKDAZEaWdp
4 | dGExDDAKBgNVBAsMA0RORDEbMBkGA1UEAwwSZGlnaXRhc2VjdXJpdHkuY29tMB4X
5 | DTE4MDQxNjE1NTk1MloXDTI4MDQxMzE1NTk1MlowZzELMAkGA1UEBhMCVVMxCzAJ
6 | BgNVBAgMAk1EMQ8wDQYDVQQHDAZGdWx0b24xDzANBgNVBAoMBkRpZ2l0YTEMMAoG
7 | A1UECwwDRE5EMRswGQYDVQQDDBJkaWdpdGFzZWN1cml0eS5jb20wWTATBgcqhkjO
8 | PQIBBggqhkjOPQMBBwNCAARj4i5ccseA1tus0ZhEKKCevjtfl5EoJQpbnJSXH6bm
9 | uwNeQdc5PLi9VA+5C5M+dtcURye1nVasmBHYuJns491Mo2MwYTAdBgNVHQ4EFgQU
10 | CjcY3ZiQpZHb9XRWsN0FIGwqMfAwHwYDVR0jBBgwFoAUCjcY3ZiQpZHb9XRWsN0F
11 | IGwqMfAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0E
12 | AwIDSAAwRQIhAI/J3ykMyD1eUaYkvhLojX1k2B1By5D9MpuXN+YaSgklAiAZFI1p
13 | cc3KBeyvbi42ZsFOo5hRO256aL27eS550fHNOw==
14 | -----END CERTIFICATE-----
15 |
--------------------------------------------------------------------------------
/dnd.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
9 |
10 |
11 |
14 |
16 |
17 |
18 |
21 |
23 |
24 |
25 |
28 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/ThunderboltMonitor.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: ThunderboltMonitor.h
3 | // project: DND (launch daemon)
4 | // description: thunderbolt device monitor (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | @interface ThunderboltMonitor : NSObject
13 |
14 | /* PROPERTIES */
15 |
16 | //notification port
17 | @property(nonatomic) IONotificationPortRef notificationPort;
18 |
19 | //callback for tb devices
20 | void tbDeviceAppeared(void *refCon, io_iterator_t iterator);
21 |
22 | //run loop source
23 | @property(nonatomic)CFRunLoopSourceRef runLoopSource;
24 |
25 |
26 | /* METHODS */
27 |
28 | //start
29 | -(BOOL)start;
30 |
31 | //stop
32 | -(void)stop;
33 |
34 | //process new tb insertion
35 | // get info about device and log
36 | -(void)handleNewDevice:(io_iterator_t)iterator;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/USBMonitor.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: USBMonitor.h
3 | // project: DND (launch daemon)
4 | // description: USB device monitor (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 | #import
12 |
13 | @interface USBMonitor : NSObject
14 |
15 | /* PROPERTIES */
16 |
17 | //notification port
18 | @property(nonatomic) IONotificationPortRef notificationPort;
19 |
20 | //callback for USB devices
21 | void usbDeviceAppeared(void *refCon, io_iterator_t iterator);
22 |
23 | //run loop source
24 | @property(nonatomic)CFRunLoopSourceRef runLoopSource;
25 |
26 |
27 | /* METHODS */
28 |
29 | //start
30 | -(BOOL)start;
31 |
32 | //stop
33 | -(void)stop;
34 |
35 | //process new USB insertion
36 | // get info about device and log
37 | -(void)handleNewDevice:(io_iterator_t)iterator;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/Preferences.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: Preferences.h
3 | // project: DND (launch daemon)
4 | // description: store/retrieve user preferences (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | @interface Preferences : NSObject
13 |
14 | /* PROPERTIES */
15 |
16 | //preferences
17 | @property(nonatomic, retain)NSMutableDictionary* preferences;
18 |
19 | /* METHODS */
20 |
21 | //get all prefs
22 | // or a specific one...
23 | -(NSDictionary*)get:(NSString*)preference;
24 |
25 | //set
26 | // directly override value
27 | -(void)set:(NSString*)key value:(id)value;
28 |
29 | //update prefs
30 | // saves and handles logic for specific prefs
31 | -(BOOL)update:(NSDictionary*)updates;
32 |
33 | //ping server for registered devices
34 | // then update preferences with this list...
35 | -(void)updateRegisteredDevices;
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/configure/Configure/Configure.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: Configure.h
3 | // project: DND (config)
4 | // description: configure DND, install/uninstall (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "HelperComms.h"
11 |
12 | @import Foundation;
13 |
14 | @interface Configure : NSObject
15 | {
16 |
17 | }
18 |
19 | /* PROPERTIES */
20 |
21 | //helper installed & connected
22 | @property(nonatomic) BOOL gotHelp;
23 |
24 | //daemom comms object
25 | @property(nonatomic, retain) HelperComms* xpcComms;
26 |
27 | /* METHODS */
28 |
29 | //determine if extension is installed
30 | -(BOOL)isInstalled;
31 |
32 | //invokes appropriate install || uninstall logic
33 | -(BOOL)configure:(NSInteger)parameter;
34 |
35 | //install
36 | -(BOOL)install;
37 |
38 | //uninstall
39 | -(BOOL)uninstall:(BOOL)full;
40 |
41 | //remove helper (daemon)
42 | -(void)removeHelper;
43 |
44 | @end
45 |
46 |
--------------------------------------------------------------------------------
/configure/Configure/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/configure/Helper/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | com.objective-see.dnd.installer.helper
7 | CFBundleInfoDictionaryVersion
8 | 6.0
9 | CFBundleName
10 | helper
11 | CFBundleVersion
12 | 1.3.0
13 | NSHumanReadableCopyright
14 | Copyright (c) 2018 Objective-See
15 | SMAuthorizedClients
16 |
17 | anchor apple generic and identifier "com.objective-see.dnd.installer" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = VBG97UB4TA)
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/launchDaemon/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.3.0
19 | CFBundleVersion
20 | 1.3.0
21 | NSHumanReadableCopyright
22 | Copyright © 2018 Objective-See. All rights reserved.
23 | NSPrincipalClass
24 |
25 | LSUIElement
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/UserAuthMonitor.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: UserAuthEvent.h
3 | // project: DND (launch daemon)
4 | // description: user authentication event monitor (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | #import "AuthEvent.h"
13 |
14 | @import Foundation;
15 |
16 | /* DEFINES */
17 |
18 | //audit pipe
19 | #define AUDIT_PIPE "/dev/auditpipe"
20 |
21 | //audit class for login/logout
22 | #define AUDIT_CLASS_LO 0x00001000
23 |
24 | //audit class for authen/author
25 | #define AUDIT_CLASS_AA 0x00002000
26 |
27 | //auth user
28 | // see: /etc/security/audit_event
29 | #define AUE_auth_user 45023
30 |
31 | @interface UserAuthMonitor : NSObject
32 |
33 | /* PROPERTIES */
34 |
35 | //flag to stop
36 | @property(nonatomic)BOOL shouldStop;
37 |
38 | /* METHODS */
39 |
40 | //thread function
41 | // setup login / lockscreen monitoring
42 | -(BOOL)start;
43 |
44 | //stop
45 | -(void)stop;
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/shared/XPC.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPC.h
3 | // project: DND (shared)
4 | // description: xpc protocols, ivars, etc,
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #ifndef XPC_h
11 | #define XPC_h
12 |
13 | //protocol
14 | // methods that deamon exports
15 | @protocol XPC_DAEMON
16 |
17 |
18 |
19 | @end
20 |
21 | //protocol
22 | // methods that user exports
23 | @protocol XPC_USER
24 |
25 | - (void) updateProgress: (double) currentProgress;
26 | - (void) finished;
27 |
28 | @end
29 |
30 | @interface XPCListener : NSObject
31 |
32 | /* PROPERTIES */
33 |
34 | //XPC listener
35 | @property(retain, nonatomic)NSXPCListener* listener;
36 |
37 | /* METHODS */
38 |
39 | //setup XPC listener
40 | -(BOOL)initListener;
41 |
42 | //automatically invoked when new client (attempts) to connect
43 | -(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection;
44 |
45 | @end
46 |
47 | #endif /* XPC_h */
48 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | .DS_Store
6 |
7 | ## Build generated
8 | build/
9 | DerivedData/
10 |
11 | ## Various settings
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | xcuserdata/
21 |
22 | ## Other
23 | *.moved-aside
24 | *.xccheckout
25 | *.xcscmblueprint
26 |
27 | ## Obj-C/Swift specific
28 | *.hmap
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | # CocoaPods
34 | #
35 | # We recommend against adding the Pods directory to your .gitignore. However
36 | # you should judge for yourself, the pros and cons are mentioned at:
37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
38 | #
39 | # Pods/
40 |
41 | # Carthage
42 | #
43 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
44 | Carthage/Checkouts
45 | Carthage/Build
46 |
--------------------------------------------------------------------------------
/configure/Helper/HelperListener.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: HelperListener.h
3 | // project: (open-source) installer
4 | // description: XPC listener for connections for user components (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | #import "HelperInterface.h"
13 |
14 | //function def
15 | OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
16 |
17 | @interface HelperListener : NSObject
18 | {
19 |
20 | }
21 |
22 | /* PROPERTIES */
23 |
24 | //XPC listener obj
25 | @property(nonatomic, retain)NSXPCListener* listener;
26 |
27 | /* METHODS */
28 |
29 | //setup XPC listener
30 | -(BOOL)initListener;
31 |
32 | //automatically invoked
33 | // allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection
34 | // note: we only allow binaries signed by Objective-See to talk to this to be extra safe :)
35 | -(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection;
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/XPCListener.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCListener.h
3 | // project: DND (launch daemon)
4 | // description: XPC listener for connections from user components (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | @interface XPCListener : NSObject
13 | {
14 |
15 | }
16 |
17 | /* PROPERTIES */
18 |
19 | //XPC listener
20 | @property(nonatomic, retain)NSXPCListener* listener;
21 |
22 | //XPC connection for login item
23 | @property(weak)NSXPCConnection* loginItem;
24 |
25 | //XPC connection for main app
26 | @property(weak)NSXPCConnection* mainApp;
27 |
28 | /* METHODS */
29 |
30 | //setup XPC listener
31 | -(BOOL)initListener;
32 |
33 | //automatically invoked
34 | // allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection
35 | // note: we only allow binaries signed by Objective-See to talk to this!
36 | -(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/shared/XPCDaemonClient.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCDaemonClient
3 | // project: DND (shared)
4 | // description: talk to the daemon, via XPC (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | #import "XPCDaemonProto.h"
13 |
14 | @interface XPCDaemonClient : NSObject
15 | {
16 |
17 | }
18 |
19 | /* PROPERTIES */
20 |
21 | //xpc connection
22 | @property (atomic, strong, readwrite) NSXPCConnection* xpcServiceConnection;
23 |
24 | /* METHODS */
25 |
26 | //ask daemon for QRC info
27 | // name, uuid, key, key size, etc...
28 | -(void)qrcRequest:(void (^)(NSData* qrcInfo))reply;
29 |
30 | //wait for phone to complete registration
31 | // calls into framework that comms w/ server to wait for phone
32 | -(void)recvRegistrationACK:(void (^)(NSDictionary* registrationInfo))reply;
33 |
34 | //get preferences
35 | // note: synchronous
36 | -(NSDictionary*)getPreferences:(NSString*)preference;
37 |
38 | //update (save) preferences
39 | -(void)updatePreferences:(NSDictionary*)preferences;
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/mainApp/mainApp/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: AppDelegate.h
3 | // project: DND (main app)
4 | // description: application delegate (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | #import "XPCDaemonClient.h"
13 | #import "AboutWindowController.h"
14 | #import "PrefsWindowController.h"
15 | #import "UpdateWindowController.h"
16 | #import "WelcomeWindowController.h"
17 | #import "3rdParty/HyperlinkTextField.h"
18 |
19 | @interface AppDelegate : NSApplication
20 |
21 | /* PROPERTIES */
22 |
23 | //welcome view controller
24 | @property(nonatomic, retain)WelcomeWindowController* welcomeWindowController;
25 |
26 | //about window controller
27 | @property(nonatomic, retain)AboutWindowController* aboutWindowController;
28 |
29 | //preferences window controller
30 | @property(nonatomic, retain)PrefsWindowController* prefsWindowController;
31 |
32 | /* METHODS */
33 |
34 | //start the (helper) login item
35 | -(BOOL)startLoginItem:(BOOL)shouldRestart;
36 |
37 | //build/return path to login item
38 | -(NSString*)path2LoginItem;
39 |
40 | @end
41 |
42 |
--------------------------------------------------------------------------------
/loginItem/loginItem/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: AppDelegate.h
3 | // project: DND (login item)
4 | // description: app delegate for login item (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 | @import AVFoundation;
12 |
13 | #import "StatusBarMenu.h"
14 | #import "XPCDaemonClient.h"
15 | #import "UpdateWindowController.h"
16 |
17 | @interface AppDelegate : NSObject
18 |
19 | /* PROPERTIES */
20 |
21 | //status bar menu
22 | @property (weak) IBOutlet NSMenu *statusMenu;
23 |
24 | //status bar menu controller
25 | @property(nonatomic, retain)StatusBarMenu* statusBarMenuController;
26 |
27 | //touch bar
28 | @property(nonatomic, retain)NSTouchBar* touchBar;
29 |
30 | //update window controller
31 | @property(nonatomic, retain)UpdateWindowController* updateWindowController;
32 |
33 | //daemon comms
34 | @property(nonatomic, retain)XPCDaemonClient* daemonComms;
35 |
36 | //observer
37 | @property(nonatomic, retain)NSObject* appObserver;
38 |
39 | /* METHODS */
40 |
41 | //init/show touch bar
42 | -(void)initTouchBar;
43 |
44 | @end
45 |
46 |
--------------------------------------------------------------------------------
/mainApp/mainApp/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: main.m
3 | // project: Do Not Disturb (main app)
4 | // description: main interface, toggle login item, or just kick off app interface
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 | @import Sentry;
12 |
13 | #import "Consts.h"
14 | #import "Logging.h"
15 | #import "Utilities.h"
16 |
17 | #import
18 |
19 | int main(int argc, const char * argv[])
20 | {
21 | //return var
22 | int iReturn = -1;
23 |
24 | //dbg msg
25 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"STARTED: config/prefs app (args: %@)", [[NSProcessInfo processInfo] arguments]]);
26 |
27 | //init crash reporting
28 | initCrashReporting();
29 |
30 | //already running?
31 | if(YES == isAppRunning([[NSBundle mainBundle] bundleIdentifier]))
32 | {
33 | //dbg msg
34 | logMsg(LOG_DEBUG, @"an instance of DND (main app) is already running");
35 |
36 | //bail
37 | goto bail;
38 | }
39 |
40 | //launch app normally
41 | iReturn = NSApplicationMain(argc, argv);
42 |
43 | bail:
44 |
45 | return iReturn;
46 | }
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Do Not Disturb
2 |
3 | 'Do Not Disturb' (DnD) is a free open-source security tool for macOS that aims to detect unauthorized physical access to your laptop!
4 | Full details and usage instructions can be found [here](https://objective-see.com/products/dnd.html).
5 |
6 | **To Build**
7 | DnD should build cleanly in Xcode (though you will have to remove code signing constraints, or replace with your own Apple developer signing certificate).
8 |
9 | **To Install**
10 | Build or [download](https://bitbucket.org/objective-see/deploy/downloads/DoNotDisturb_1.0.0.zip) the pre-built installer application. Install, by simply running the installer (UI) application.
11 |
12 | ❤ Love this product or want to support it? Check out my [patreon page](https://www.patreon.com/objective_see) :)
13 |
14 | **Mahalo!**
15 | This product is supported by the following patrons:
16 | + Lance Gaines
17 | + Ash Morgan
18 | + Khalil Sehnaoui
19 | + Nando Mendonca
20 | + Bill Smartt
21 | + Martin OConnell
22 | + David Sulpy
23 | + Shain Singh
24 | + Chad Collins
25 | + Harry Hoffman
26 | + Keelian Wardle
27 | + Christopher Giffard
28 | + Conrad Rushing
29 | + soreq
30 | + Stuart Ashenbrenner
31 | + trifero
32 | + Peter Sinclair
33 | + Ming
34 | + Gamer Bot
35 |
--------------------------------------------------------------------------------
/loginItem/loginItem/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: main.m
3 | // project: DND (login item)
4 | // description: main interface to login item
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 | @import Sentry;
12 |
13 | #import "Consts.h"
14 | #import "Logging.h"
15 | #import "Utilities.h"
16 |
17 | //main
18 | // only allow one instance, but then just invoke app's main
19 | int main(int argc, const char * argv[])
20 | {
21 | //return var
22 | int iReturn = -1;
23 |
24 | //dbg msg
25 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"STARTED: login item (args: %@)", [[NSProcessInfo processInfo] arguments]]);
26 |
27 | //init crash reporting
28 | initCrashReporting();
29 |
30 | //already running?
31 | if(YES == isAppRunning([[NSBundle mainBundle] bundleIdentifier]))
32 | {
33 | //dbg msg
34 | logMsg(LOG_DEBUG, @"an instance of DND login item is already running, will exit");
35 |
36 | //no error per se
37 | iReturn = 0;
38 |
39 | //bail
40 | goto bail;
41 | }
42 |
43 | //launch app normally
44 | iReturn = NSApplicationMain(argc, argv);
45 |
46 | bail:
47 |
48 | return iReturn;
49 | }
50 |
--------------------------------------------------------------------------------
/mainApp/mainApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.3.0
21 | CFBundleVersion
22 | 1.3.0
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | Copyright © 2018 Objective-See. All rights reserved.
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | AppDelegate
31 | NSCameraUsageDescription
32 | When a lid open event occurs, this will allow the application to take a picture!
33 |
34 |
35 |
--------------------------------------------------------------------------------
/mainApp/mainApp/WelcomeWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: WelcomeWindowController.h
3 | // project: DND (main app)
4 | // description: 'welcome' window logic/controller (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | #import
13 |
14 | @interface WelcomeWindowController : NSWindowController
15 |
16 | /* PROPERTIES */
17 |
18 | //welcome view
19 | @property (strong) IBOutlet NSView *welcomeView;
20 |
21 | //app info view
22 | @property (strong) IBOutlet NSView *appInfo;
23 |
24 | //config view
25 | @property (strong) IBOutlet NSView *qrcView;
26 |
27 | //activity indicator
28 | @property (weak) IBOutlet NSProgressIndicator *activityIndicator;
29 |
30 | //activity msg
31 | @property (weak) IBOutlet NSTextField *activityMessage;
32 |
33 | //qrc image view
34 | @property (weak) IBOutlet NSImageView *qrcImageView;
35 |
36 | //linked view
37 | @property (strong) IBOutlet NSView *linkedView;
38 |
39 | //host name
40 | @property (weak) IBOutlet NSTextField *hostName;
41 |
42 | //(registered) device name
43 | @property (weak) IBOutlet NSTextField *deviceName;
44 |
45 | //welcome view controller
46 | @property(nonatomic, retain)NSViewController* welcomeViewController;
47 |
48 | /* METHODS */
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/configure/Configure/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: AppDelegate.h
3 | // project: DND (config)
4 | // description: application delegate (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | #import "Configure.h"
13 | #import "HelperComms.h"
14 | #import "AboutWindowController.h"
15 | #import "ConfigureWindowController.h"
16 |
17 | //block for install/uninstall
18 | typedef void (^block)(NSNumber*);
19 |
20 | @interface AppDelegate : NSObject
21 | {
22 |
23 | }
24 |
25 | //config object
26 | @property(nonatomic, retain) Configure* configureObj;
27 |
28 | //helper installed & connected
29 | @property(nonatomic) BOOL gotHelp;
30 |
31 | //daemom comms object
32 | @property(nonatomic, retain)HelperComms* xpcComms;
33 |
34 | //status msg
35 | @property (nonatomic, weak)IBOutlet NSTextField *statusMsg;
36 |
37 | //about window controller
38 | @property(nonatomic, retain)AboutWindowController* aboutWindowController;
39 |
40 | //configure window controller
41 | @property(nonatomic, retain)ConfigureWindowController* configureWindowController;
42 |
43 |
44 | /* METHODS */
45 |
46 | //display configuration window w/ 'install' || 'uninstall' button
47 | -(void)displayConfigureWindow:(BOOL)isInstalled;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/shared/UpdateWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: UpdateWindowController.m
3 | // project: DND (shared)
4 | // description: window handler for update window/popup (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | @interface UpdateWindowController : NSWindowController
13 | {
14 |
15 | }
16 |
17 | /* PROPERTIES */
18 |
19 | //version label/string
20 | @property(weak)IBOutlet NSTextField *infoLabel;
21 |
22 | //action button
23 | @property(weak)IBOutlet NSButton *actionButton;
24 |
25 | //label string
26 | @property(nonatomic, retain)NSString* infoLabelString;
27 |
28 | //first button ('update check')
29 | @property(weak)IBOutlet NSView *firstButton;
30 |
31 | //button title
32 | @property(nonatomic, retain)NSString* actionButtonTitle;
33 |
34 | //overlay view
35 | @property(weak)IBOutlet NSView *overlayView;
36 |
37 | //spinner
38 | @property(weak)IBOutlet NSProgressIndicator *progressIndicator;
39 |
40 | /* METHODS */
41 |
42 | //save the main label's & button title's text
43 | -(void)configure:(NSString*)label buttonTitle:(NSString*)buttonTitle;
44 |
45 | //invoked when user clicks button
46 | // trigger action such as opening product website, updating, etc
47 | -(IBAction)buttonHandler:(id)sender;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/VolumeMonitor.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: VolumeMonitor.h
3 | // project: DND (launch daemon)
4 | // description: mounted volume file monitor
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Logging.h"
11 | #import "VolumeMonitor.h"
12 |
13 | @implementation VolumeMonitor
14 |
15 | //start monitoring
16 | -(void)start
17 | {
18 | //add observer
19 | [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(volumeMounted:) name:NSWorkspaceDidMountNotification object:nil];
20 |
21 | return;
22 | }
23 |
24 | //stop monitoring
25 | -(void)stop
26 | {
27 | //remove observer
28 | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWorkspaceDidMountNotification object:nil];
29 |
30 | return;
31 | }
32 |
33 | //callback
34 | // log details of mounted volume
35 | -(void)volumeMounted:(NSNotification*)notification
36 | {
37 | //path
38 | NSString* path = nil;
39 |
40 | //get path
41 | path = [notification.userInfo[NSWorkspaceVolumeURLKey] path];
42 |
43 | //dbg msg and log
44 | logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"monitor event: volume mounted: %@\n%@", path, notification.userInfo]);
45 |
46 | return;
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/loginItem/loginItem/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.3.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.3.0
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | LSUIElement
28 |
29 | NSHumanReadableCopyright
30 | Copyright (c) 2018 Objective-See. All rights reserved.
31 | NSMainNibFile
32 | MainMenu
33 | NSPrincipalClass
34 | NSApplication
35 | NSUserNotificationAlertStyle
36 | alert
37 |
38 |
39 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/NSMutableArray+QueueAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: NSMutableArray+QueueAdditions.m
3 | // project: DND (launch daemon)
4 | // description: queue implementation via NSMutableArray
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 | // note: based on https://github.com/esromneb/ios-queue-object/blob/master/NSMutableArray%2BQueueAdditions.m
10 |
11 | #import "NSMutableArray+QueueAdditions.h"
12 |
13 | @implementation NSMutableArray (QueueAdditions)
14 |
15 | //add object to end of queue
16 | -(void)enqueue:(id)item
17 | {
18 | //sync
19 | @synchronized(self)
20 | {
21 | //add object
22 | [self addObject:item];
23 | }
24 |
25 | return;
26 | }
27 |
28 | //grab first item
29 | // and then remove it from queue
30 | -(id)dequeue
31 | {
32 | //object
33 | id queueObject = nil;
34 |
35 | //sync
36 | @synchronized(self)
37 | {
38 | //extract first item
39 | queueObject = [self firstObject];
40 |
41 | //delete it from queue
42 | [self removeObjectAtIndex:0];
43 |
44 | }//sync
45 |
46 | return queueObject;
47 | }
48 |
49 | //grab first item
50 | // but don't remove it from queue
51 | -(id)peek
52 | {
53 | return [self firstObject];
54 | }
55 |
56 | //determine if queue is empty
57 | -(BOOL)isEmpty
58 | {
59 | //empty?
60 | return (0 == self.count);
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/configure/Configure/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | APPL
15 | CFBundleShortVersionString
16 | 1.3.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1.3.0
21 | NSHumanReadableCopyright
22 | Copyright (c) 2018 Objective-See
23 | NSMainNibFile
24 | MainMenu
25 | NSPrincipalClass
26 | NSApplication
27 | SMPrivilegedExecutables
28 |
29 | com.objective-see.dnd.installer.helper
30 | anchor apple generic and identifier "com.objective-see.dnd.installer.helper" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = VBG97UB4TA)
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/configure/Configure/ConfigureWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: ConfigureWindowController.h
3 | // project: DND (config)
4 | // description: configure (install/uninstall) window (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | @interface ConfigureWindowController : NSWindowController
13 | {
14 |
15 | }
16 |
17 | /* PROPERTIES */
18 |
19 | //config (main) view
20 | @property (weak) IBOutlet NSView *configView;
21 |
22 | //"friends of objective-see"
23 | @property (strong, nonatomic) IBOutlet NSView *friendsView;
24 |
25 | //status msg
26 | @property (weak, nonatomic) IBOutlet NSTextField *statusMsg;
27 |
28 | //install button
29 | @property (weak, nonatomic) IBOutlet NSButton *installButton;
30 |
31 | //more info button
32 | @property (weak, nonatomic) IBOutlet NSButton *moreInfoButton;
33 |
34 | //uninstall button
35 | @property (weak, nonatomic) IBOutlet NSButton *uninstallButton;
36 |
37 | //activity indicator (spinner)
38 | @property (weak, nonatomic) IBOutlet NSProgressIndicator *activityIndicator;
39 |
40 | /* METHODS */
41 |
42 | //install/uninstall button handler
43 | -(IBAction)buttonHandler:(id)sender;
44 |
45 | //(more) info button handler
46 | -(IBAction)info:(id)sender;
47 |
48 | //configure window/buttons
49 | // also brings to front
50 | -(void)configure:(BOOL)isInstalled;
51 |
52 | //display (show) window
53 | -(void)display;
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/configure/Helper/Helper.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: Helper.m
3 | // project: (open-source) installer
4 | // description: main/entry point of daemon
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | #import "Logging.h"
13 | #import "XPCProtocol.h"
14 | #import "HelperListener.h"
15 | #import "HelperInterface.h"
16 |
17 | //helper daemon entry point
18 | // create XPC listener object and then just wait
19 | int main(int argc, const char * argv[])
20 | {
21 | //pragmas
22 | #pragma unused(argc)
23 | #pragma unused(argv)
24 |
25 | //status
26 | int status = -1;
27 |
28 | //pool
29 | @autoreleasepool
30 | {
31 | //helper listener (XPC) obj
32 | HelperListener* helperListener = nil;
33 |
34 | //alloc/init helper listener XPC obj
35 | helperListener = [[HelperListener alloc] init];
36 | if(nil == helperListener)
37 | {
38 | //err msg
39 | logMsg(LOG_ERR, @"failed to initialize user comms XPC listener");
40 |
41 | //bail
42 | goto bail;
43 | }
44 |
45 | //dbg msg
46 | logMsg(LOG_DEBUG, @"listening for client XPC connections...");
47 |
48 | //run loop
49 | [[NSRunLoop currentRunLoop] run];
50 |
51 | } //pool
52 |
53 | //happy
54 | // though not sure how we'll ever get here?
55 | status = 0;
56 |
57 | bail:
58 |
59 | return status;
60 | }
61 |
--------------------------------------------------------------------------------
/mainApp/mainApp/3rdParty/HyperlinkTextField.h:
--------------------------------------------------------------------------------
1 | //
2 | // HyperlinkTextField.h
3 | // NSTextFieldHyperlinks
4 | //
5 | // Created by Toomas Vahter on 25.12.12.
6 | // Copyright (c) 2012 Toomas Vahter. All rights reserved.
7 | //
8 | // This content is released under the MIT License (http://www.opensource.org/licenses/mit-license.php).
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 |
28 | @import Cocoa;
29 |
30 | @interface HyperlinkTextField : NSTextField
31 | @end
32 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/Monitor.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: Monitor.h
3 | // project: DND (launch daemon)
4 | // description: monitor all things (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "USBMonitor.h"
11 | #import "ProcListener.h"
12 | #import "VolumeMonitor.h"
13 | #import "DownloadMonitor.h"
14 | #import "UserAuthMonitor.h"
15 | #import "ThunderboltMonitor.h"
16 |
17 | @import Foundation;
18 |
19 | @interface Monitor : NSObject
20 |
21 | /* PROPERTIES */
22 |
23 | //dimiss flag
24 | @property BOOL wasDismissed;
25 |
26 | //observer for user auths events
27 | @property(nonatomic, retain)id userAuthObserver;
28 |
29 | //observer for dimisss events
30 | @property(nonatomic, retain)id dimisssObserver;
31 |
32 | //process listener obj
33 | @property(nonatomic, retain)ProcessMonitor* processMonitor;
34 |
35 | //usb monitor
36 | @property(nonatomic, retain)USBMonitor* usbMonitor;
37 |
38 | //download monitor
39 | @property(nonatomic, retain)DownloadMonitor* downloadMonitor;
40 |
41 | //user auth events monitor
42 | @property(nonatomic, retain)UserAuthMonitor* userAuthMonitor;
43 |
44 | //thunderbolt monitor
45 | @property(nonatomic, retain)ThunderboltMonitor* thunberboltMonitor;
46 |
47 | //(mounted) volume monitor
48 | @property(nonatomic, retain)VolumeMonitor* volumeMonitor;
49 |
50 | /* METHODS */
51 |
52 | //start all monitoring
53 | // processes, auth events, hardware insertions, etc
54 | -(BOOL)start:(NSUInteger)timeout;
55 |
56 | //stop all monitoring
57 | -(void)stop;
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/mainApp/mainApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "icon_16x16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "icon_16x16@2x.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "icon_32x32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "icon_32x32@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "icon_128x128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "icon_128x128@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "icon_256x256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "icon_256x256@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "icon_512x512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "idiom" : "mac",
59 | "size" : "512x512",
60 | "scale" : "2x"
61 | }
62 | ],
63 | "info" : {
64 | "version" : 1,
65 | "author" : "xcode"
66 | }
67 | }
--------------------------------------------------------------------------------
/configure/Configure/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "icon_16x16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "icon_16x16@2x.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "icon_32x32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "icon_32x32@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "icon_128x128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "icon_128x128@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "icon_256x256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "icon_256x256@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "icon_512x512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "idiom" : "mac",
59 | "size" : "512x512",
60 | "scale" : "2x"
61 | }
62 | ],
63 | "info" : {
64 | "version" : 1,
65 | "author" : "xcode"
66 | }
67 | }
--------------------------------------------------------------------------------
/loginItem/loginItem/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "icon_16x16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "icon_16x16@2x.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "icon_32x32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "icon_32x32@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "icon_128x128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "icon_128x128@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "icon_256x256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "icon_256x256@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "icon_512x512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "idiom" : "mac",
59 | "size" : "512x512",
60 | "scale" : "2x"
61 | }
62 | ],
63 | "info" : {
64 | "version" : 1,
65 | "author" : "xcode"
66 | }
67 | }
--------------------------------------------------------------------------------
/loginItem/loginItem/3rdParty/HyperlinkTextField.h:
--------------------------------------------------------------------------------
1 | //
2 | // HyperlinkTextField.h
3 | // NSTextFieldHyperlinks
4 | //
5 | // Created by Toomas Vahter on 25.12.12.
6 | // Copyright (c) 2012 Toomas Vahter. All rights reserved.
7 | //
8 | // This content is released under the MIT License (http://www.opensource.org/licenses/mit-license.php).
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 |
28 | @import Cocoa;
29 |
30 | @interface HyperlinkTextField : NSTextField
31 |
32 | @property (nonatomic, readonly) NSTextView *textView;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/ProcListener.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: ProcListener.m
3 | // project: DND (launch daemon)
4 | // description: interface with process monitor library
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Logging.h"
12 | #import "ProcListener.h"
13 |
14 | @implementation ProcessMonitor
15 |
16 | @synthesize procMon;
17 | @synthesize processes;
18 |
19 | //init
20 | -(id)init
21 | {
22 | //init super
23 | self = [super init];
24 | if(nil != self)
25 | {
26 | //alloc
27 | self.processes = [NSMutableDictionary dictionary];
28 |
29 | //init proc info (monitor)
30 | procMon = [[ProcInfo alloc] init];
31 | }
32 |
33 | return self;
34 | }
35 |
36 | //start
37 | // tell proc info lib to start
38 | -(void)start
39 | {
40 | //callback block
41 | ProcessCallbackBlock block = ^(Process* process)
42 | {
43 | //process start?
44 | if(process.type != EVENT_EXIT)
45 | {
46 | //start
47 | [self processStart:process];
48 | }
49 | };
50 |
51 | [self.procMon start:block];
52 |
53 | return;
54 | }
55 |
56 | //tell proc info lib to stop
57 | -(void)stop
58 | {
59 | //stop
60 | [self.procMon stop];
61 |
62 | return;
63 | }
64 |
65 | //process start
66 | // just log that fact
67 | -(void)processStart:(Process*)process
68 | {
69 | //dbg msg & log
70 | logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"monitor event: process start: (%d: %@ (args: %@))", process.pid, process.path, process.arguments]);
71 |
72 | return;
73 | }
74 |
75 | @end
76 |
--------------------------------------------------------------------------------
/launchDaemon/Resources/awsRootCA.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
3 | yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
4 | ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
5 | U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
6 | ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
7 | aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
8 | MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
9 | ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
10 | biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
11 | U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
12 | aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
13 | nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
14 | t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
15 | SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
16 | BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
17 | rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
18 | NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
19 | BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
20 | BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
21 | aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
22 | MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
23 | p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
24 | 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
25 | WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
26 | 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
27 | hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
28 | -----END CERTIFICATE-----
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/Lid.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: Lid.h
3 | // project: DND (launch daemon)
4 | // description: monitor and alert logic for lid open events (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Utilities.h"
11 | #import
12 |
13 | @import Foundation;
14 |
15 | #import
16 | #import
17 |
18 | /* FUNCTIONS */
19 |
20 | //check if user auth'd
21 | // a) within last 10 seconds
22 | // b) via biometrics (touchID)
23 | BOOL authViaTouchID(void);
24 |
25 | /* CLASS INTERFACE */
26 |
27 | @interface Lid : NSObject
28 | {
29 | //lid state
30 | LidState lidState;
31 |
32 | //dispatch queue
33 | dispatch_queue_t dispatchQ;
34 |
35 | //notification port
36 | IONotificationPortRef notificationPort;
37 |
38 | //notification object
39 | io_object_t notification;
40 |
41 | }
42 |
43 | /* PROPERTIES */
44 |
45 | //client
46 | @property(nonatomic, retain)DNDClientMac *client;
47 |
48 | //dismiss dispatch group
49 | @property(nonatomic, retain)dispatch_group_t dispatchGroup;
50 |
51 | //dispatch group flag
52 | @property BOOL dispatchGroupEmpty;
53 |
54 | //dispatch blocks
55 | @property(nonatomic, retain)NSMutableArray* dispatchBlocks;
56 |
57 | //latest undelivered alert
58 | @property(nonatomic, retain)NSDate* undeliveredAlert;
59 |
60 | //observer for dismiss alerts
61 | @property(nonatomic, retain)id dismissObserver;
62 |
63 | //observer for new client/user (login item)
64 | @property(nonatomic, retain)id userObserver;
65 |
66 | //undelivered alerts
67 | @property(nonatomic, retain)NSMutableArray* undeliveredAlerts;
68 |
69 | /* METHODS */
70 |
71 | //check if client should be init'd
72 | -(BOOL)shouldInitClient;
73 |
74 | //init dnd client
75 | -(BOOL)clientInit;
76 |
77 | //cancel all dipatch blocks
78 | -(void)cancelDispatchBlocks;
79 |
80 | //register for notifications
81 | -(BOOL)register4Notifications;
82 |
83 | //register for notifications
84 | -(void)unregister4Notifications;
85 |
86 | //proces lid open event
87 | -(void)processEvent:(NSDate*)timestamp user:(NSString*)user;
88 |
89 | //wait for dismiss
90 | // note: handles multiple client via dispatch group
91 | -(void)wait4Dismiss;
92 |
93 | //execute action
94 | -(int)executeAction:(NSString*)path user:(NSString*)user;
95 |
96 | @end
97 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/DownloadMonitor.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: DownloadMonitor.m
3 | // project: DND (launch daemon)
4 | // description: download file monitor
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Logging.h"
11 | #import "DownloadMonitor.h"
12 |
13 | @implementation DownloadMonitor
14 |
15 | @synthesize query;
16 |
17 | //start monitoring
18 | // note: will only detect files downloaded from apps such as browsers (that have 'kMDItemWhereFroms' key set)
19 | -(void)start
20 | {
21 | //alloc/init query
22 | query = [[NSMetadataQuery alloc] init];
23 |
24 | //has to be run on the main thread!
25 | dispatch_async(dispatch_get_main_queue(), ^{
26 |
27 | //add observer
28 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDownloadEvent:) name:NSMetadataQueryDidUpdateNotification object:self.query];
29 |
30 | //set delegate
31 | self.query.delegate = self;
32 |
33 | //set predicate
34 | self.query.predicate = [NSPredicate predicateWithFormat:@"%K like '*'", @"kMDItemWhereFroms"];
35 |
36 | //start
37 | [self.query startQuery];
38 |
39 | });
40 |
41 | return;
42 | }
43 |
44 | //stop monitoring
45 | -(void)stop
46 | {
47 | //remove notification
48 | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidUpdateNotification object:query];
49 |
50 | //stop
51 | [self.query stopQuery];
52 |
53 | //unset delegate
54 | [self.query setDelegate:nil];
55 |
56 | //unset
57 | self.query = nil;
58 |
59 | return;
60 | }
61 |
62 | //callback for downloaded files
63 | // process each, and log path, etc
64 | -(void)handleDownloadEvent:(NSNotification *)notification
65 | {
66 | //metadata items
67 | NSArray* items = nil;
68 |
69 | //file path
70 | NSString* path = nil;
71 |
72 | //extract metadata items
73 | items = notification.userInfo[@"kMDQueryUpdateAddedItems"];
74 |
75 | //process each
76 | // extract and log path
77 | for(NSMetadataItem* item in items)
78 | {
79 | //extract path
80 | path = [item valueForAttribute:(NSString *)kMDItemPath];
81 | if(0 == path.length)
82 | {
83 | //skip
84 | continue;
85 | }
86 |
87 | //dbg msg and log
88 | logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"monitor event: downloaded file: %@", path]);
89 | }
90 |
91 | return;
92 | }
93 |
94 | @end
95 |
--------------------------------------------------------------------------------
/mainApp/mainApp/AboutWindowController.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: AboutWindowController.m
3 | // project: DND (main app)
4 | // description: 'about' window controller
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Utilities.h"
12 | #import "AboutWindowController.h"
13 |
14 | @implementation AboutWindowController
15 |
16 | @synthesize patrons;
17 | @synthesize versionLabel;
18 |
19 | //automatically called when nib is loaded
20 | // center window
21 | -(void)awakeFromNib
22 | {
23 | //center
24 | [self.window center];
25 |
26 | return;
27 | }
28 |
29 | //automatically invoked when window is loaded
30 | // set to white
31 | -(void)windowDidLoad
32 | {
33 | //version
34 | NSString* version = nil;
35 |
36 | //super
37 | [super windowDidLoad];
38 |
39 | //not in mojave dark mode?
40 | // make window color white
41 | if(YES != isDarkMode())
42 | {
43 | //make white
44 | self.window.backgroundColor = NSColor.whiteColor;
45 | }
46 |
47 | //grab app version
48 | version = getAppVersion();
49 | if(nil == version)
50 | {
51 | //default
52 | version = @"unknown";
53 | }
54 |
55 | //set version sting
56 | self.versionLabel.stringValue = version;
57 |
58 | //load patrons
59 | // <3 you guys & girls
60 | self.patrons.string = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"patrons" ofType:@"txt"] encoding:NSUTF8StringEncoding error:NULL];
61 | if(nil == self.patrons.string)
62 | {
63 | //default
64 | self.patrons.string = @"error: failed to load patrons :/";
65 | }
66 |
67 | return;
68 | }
69 |
70 | //automatically invoked when window is closing
71 | // make window unmodal
72 | -(void)windowWillClose:(NSNotification *)notification
73 | {
74 | //make un-modal
75 | [[NSApplication sharedApplication] stopModal];
76 |
77 | return;
78 | }
79 |
80 | //automatically invoked when user clicks any of the buttons
81 | // perform actions, such as loading patreon or products URL
82 | -(IBAction)buttonHandler:(id)sender
83 | {
84 | //support us button
85 | if(((NSButton*)sender).tag == BUTTON_SUPPORT_US)
86 | {
87 | //open URL
88 | // invokes user's default browser
89 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]];
90 | }
91 |
92 | //more info button
93 | else if(((NSButton*)sender).tag == BUTTON_MORE_INFO)
94 | {
95 | //open URL
96 | // invokes user's default browser
97 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]];
98 | }
99 |
100 | return;
101 | }
102 | @end
103 |
--------------------------------------------------------------------------------
/configure/Configure/AboutWindowController.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: AboutWindowController.h
3 | // project: DND (config)
4 | // description: window showing 'about' info
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Utilities.h"
12 | #import "AboutWindowController.h"
13 |
14 | @implementation AboutWindowController
15 |
16 | @synthesize patrons;
17 | @synthesize supportUs;
18 | @synthesize versionLabel;
19 |
20 | //automatically called when nib is loaded
21 | // center window
22 | -(void)awakeFromNib
23 | {
24 | //center
25 | [self.window center];
26 | }
27 |
28 | //automatically invoked when window is loaded
29 | // set to white
30 | -(void)windowDidLoad
31 | {
32 | //super
33 | [super windowDidLoad];
34 |
35 | //not in mojave dark mode?
36 | // make window color white
37 | if(YES != isDarkMode())
38 | {
39 | //make white
40 | self.window.backgroundColor = NSColor.whiteColor;
41 | }
42 |
43 | //set version sting
44 | self.versionLabel.stringValue = [NSString stringWithFormat:@"Version: %@", getAppVersion()];
45 |
46 | //load patrons
47 | self.patrons.string = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"patrons" ofType:@"txt"] encoding:NSUTF8StringEncoding error:NULL];
48 |
49 | //make 'support us' default
50 | [self.supportUs setKeyEquivalent:@"\r"];
51 |
52 | //make first responder
53 | // calling this without a timeout sometimes fails :/
54 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
55 |
56 | //set first responder
57 | [self.window makeFirstResponder:self.supportUs];
58 |
59 | });
60 |
61 | return;
62 | }
63 |
64 | //automatically invoked when window is closing
65 | // make ourselves unmodal
66 | -(void)windowWillClose:(NSNotification *)notification
67 | {
68 | #pragma unused(notification)
69 |
70 | //make un-modal
71 | [[NSApplication sharedApplication] stopModal];
72 |
73 | return;
74 | }
75 |
76 | //automatically invoked when user clicks any of the buttons
77 | // load patreon or products webpage in user's default browser
78 | -(IBAction)buttonHandler:(id)sender
79 | {
80 | //support us button
81 | if(((NSButton*)sender).tag == BUTTON_SUPPORT_US)
82 | {
83 | //open URL
84 | // invokes user's default browser
85 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]];
86 | }
87 |
88 | //more info button
89 | else if(((NSButton*)sender).tag == BUTTON_MORE_INFO)
90 | {
91 | //open URL
92 | // invokes user's default browser
93 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]];
94 | }
95 |
96 | return;
97 | }
98 | @end
99 |
--------------------------------------------------------------------------------
/shared/Utilities.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: Utilities.h
3 | // project: DND (shared)
4 | // description: various helper/utility functions (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #ifndef Utilities_h
11 | #define Utilities_h
12 |
13 | @import Sentry;
14 | @import AVFoundation;
15 |
16 | #import
17 | #import
18 | #import
19 | #import
20 | #import
21 |
22 | //enum of lid states
23 | typedef NS_ENUM(int, LidState)
24 | {
25 | stateUnavailable = -1,
26 | stateOpen = 0,
27 | stateClosed = 1
28 | };
29 |
30 | /* FUNCTIONS */
31 |
32 | //init crash reporting
33 | void initCrashReporting(void);
34 |
35 | //loads a framework
36 | // note: assumes it is in 'Framework' dir
37 | NSBundle* loadFramework(NSString* name);
38 |
39 | //get app's version
40 | // extracted from Info.plist
41 | NSString* getAppVersion(void);
42 |
43 | //get path to (main) app
44 | // login item is in app bundle, so parse up to get main app
45 | NSString* getMainAppPath(void);
46 |
47 | //get name of logged in user
48 | NSString* getConsoleUser(void);
49 |
50 | //verify that an app bundle is
51 | // a) signed
52 | // b) signed with signing auth
53 | OSStatus verifyApp(NSString* path, NSString* signingAuth);
54 |
55 | //get state of lid
56 | int getLidState(void);
57 |
58 | //get process name
59 | // either via app bundle, or path
60 | NSString* getProcessName(NSString* path);
61 |
62 | //given a pid
63 | // get process's path
64 | NSString* getProcessPath(pid_t pid);
65 |
66 | //given a process path and user
67 | // return array of all matching pids
68 | NSMutableArray* getProcessIDs(NSString* processPath, int userID);
69 |
70 | //wait until a window is non nil
71 | // then make it modal
72 | void makeModal(NSWindowController* windowController);
73 |
74 | //check if an instance of an app is already running
75 | BOOL isAppRunning(NSString* bundleID);
76 |
77 | //set dir's|file's group/owner
78 | BOOL setFileOwner(NSString* path, NSNumber* groupID, NSNumber* ownerID, BOOL recursive);
79 |
80 | //exec a process with args
81 | // if 'shouldWait' is set, wait and return stdout/in and termination status
82 | NSMutableDictionary* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait);
83 |
84 | //toggle login item
85 | // either add (install) or remove (uninstall)
86 | BOOL toggleLoginItem(NSURL* loginItem, int toggleFlag);
87 |
88 | //touchID capable?
89 | BOOL hasTouchID(void);
90 |
91 | //get current console user
92 | NSString* currentConsoleUser(SCDynamicStoreRef store);
93 |
94 | //macOS Mojave+
95 | // gotta request camera access
96 | void requestCameraAccess(void);
97 |
98 | //check if (true) dark mode
99 | BOOL isDarkMode(void);
100 |
101 | #endif
102 |
--------------------------------------------------------------------------------
/mainApp/mainApp/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/shared/Update.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: Update.m
3 | // project: DND (shared)
4 | // description: checks for new versions of DND
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Update.h"
12 | #import "Logging.h"
13 | #import "Utilities.h"
14 | #import "AppDelegate.h"
15 |
16 |
17 | @implementation Update
18 |
19 | //check for an update
20 | // will invoke app delegate method to update UI when check completes
21 | -(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler
22 | {
23 | //latest version
24 | __block NSString* latestVersion = nil;
25 |
26 | //result
27 | __block NSInteger result = -1;
28 |
29 | //get latest version in background
30 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
31 |
32 | //grab latest version
33 | latestVersion = [self getLatestVersion];
34 | if(nil != latestVersion)
35 | {
36 | //check
37 | result = (NSOrderedAscending == [getAppVersion() compare:latestVersion options:NSNumericSearch]);
38 | }
39 |
40 | //invoke app delegate method
41 | // will update UI/show popup if necessart
42 | dispatch_async(dispatch_get_main_queue(),
43 | ^{
44 | completionHandler(result, latestVersion);
45 | });
46 |
47 | });
48 |
49 | return;
50 | }
51 |
52 | //query interwebz to get latest version
53 | -(NSString*)getLatestVersion
54 | {
55 | //product version(s) data
56 | NSData* productsVersionData = nil;
57 |
58 | //version dictionary
59 | NSDictionary* productsVersionDictionary = nil;
60 |
61 | //latest version
62 | NSString* latestVersion = nil;
63 |
64 | //get version from remote URL
65 | productsVersionData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]];
66 | if(nil == productsVersionData)
67 | {
68 | //bail
69 | goto bail;
70 | }
71 |
72 | //convert JSON to dictionary
73 | // wrap as may throw exception
74 | @try
75 | {
76 | //convert
77 | productsVersionDictionary = [NSJSONSerialization JSONObjectWithData:productsVersionData options:0 error:nil];
78 | if(nil == productsVersionDictionary)
79 | {
80 | //bail
81 | goto bail;
82 | }
83 | }
84 | @catch(NSException* exception)
85 | {
86 | //bail
87 | goto bail;
88 | }
89 |
90 | //extract latest version
91 | latestVersion = [[productsVersionDictionary objectForKey:@"Do Not Disturb"] objectForKey:@"version"];
92 |
93 | //dbg msg
94 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"latest version: %@", latestVersion]);
95 |
96 | bail:
97 |
98 | return latestVersion;
99 | }
100 |
101 | @end
102 |
--------------------------------------------------------------------------------
/configure/Configure/Script/configure.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #
4 | # file: configure.sh
5 | # project: DND (configure)
6 | # description: install/uninstall
7 | #
8 | # created by Patrick Wardle
9 | # copyright (c) 2018 Objective-See. All rights reserved.
10 | #
11 |
12 | INSTALL_DIRECTORY="/Library/Objective-See/DND"
13 |
14 | #install
15 | if [ "${1}" == "-install" ]; then
16 |
17 | echo "installing"
18 |
19 | #create DND directory
20 | mkdir -p $INSTALL_DIRECTORY
21 |
22 | #set permissions
23 | chown -R root:wheel "Do Not Disturb.bundle"
24 | chown -R root:wheel "com.objective-see.dnd.plist"
25 |
26 | #install & load launch daemon
27 | mv "Do Not Disturb.bundle" $INSTALL_DIRECTORY
28 | mv "com.objective-see.dnd.plist" /Library/LaunchDaemons/
29 | launchctl load "/Library/LaunchDaemons/com.objective-see.dnd.plist"
30 |
31 | #give launch daemon a second
32 | # time to initialize, get XPC interface up, etc...
33 | sleep 1.0
34 |
35 | echo "launch daemon installed and loaded"
36 |
37 | #install main app/helper app
38 | mv "Do Not Disturb.app" /Applications
39 |
40 | #remove xattrz
41 | xattr -rc "/Applications/Do Not Disturb.app"
42 |
43 | #start login item
44 | open -g -j "/Applications/Do Not Disturb.app/Contents/Library/LoginItems/Do Not Disturb Helper.app"
45 |
46 | echo "install complete"
47 | exit 0
48 |
49 | #uninstall
50 | elif [ "${1}" == "-uninstall" ]; then
51 |
52 | echo "uninstalling"
53 |
54 | #kill main app
55 | # ...it might be open
56 | killall "Do Not Disturb" 2> /dev/null
57 |
58 | #full uninstall?
59 | # tell daemon to perform uninstall logic (delete IDs, etc)
60 | if [[ "${2}" -eq "1" ]]; then
61 | "$INSTALL_DIRECTORY/Do Not Disturb.bundle/Contents/MacOS/Do Not Disturb" "-uninstall"
62 | fi
63 |
64 | #unload launch daemon & remove plist
65 | launchctl unload /Library/LaunchDaemons/com.objective-see.dnd.plist
66 | rm /Library/LaunchDaemons/com.objective-see.dnd.plist
67 |
68 | echo "unloaded launch daemon"
69 |
70 | #uninstall & remove main app/helper app
71 | rm -rf "/Applications/Do Not Disturb.app"
72 |
73 | #full uninstall?
74 | # delete DND's folder w/ everything
75 | if [[ "${2}" -eq "1" ]]; then
76 | rm -rf $INSTALL_DIRECTORY
77 |
78 | #no other objective-see tools?
79 | # then delete that directory too
80 | baseDir=$(dirname $INSTALL_DIRECTORY)
81 |
82 | if [ ! "$(ls -A $baseDir)" ]; then
83 | rm -rf $baseDir
84 | fi
85 |
86 | #partial
87 | # just delete daemon, leaving prefs, etc
88 | else
89 | rm -rf "$INSTALL_DIRECTORY/Do Not Disturb.bundle"
90 | fi
91 |
92 | #kill
93 | killall "Do Not Disturb" 2> /dev/null
94 | killall "com.objective-see.dnd.helper" 2> /dev/null
95 | killall "Do Not Disturb Helper" 2> /dev/null
96 |
97 | echo "uninstall complete"
98 | exit 0
99 | fi
100 |
101 | #invalid args
102 | echo "\nERROR: run w/ '-install' || '-uninstall'"
103 | exit -1
104 |
--------------------------------------------------------------------------------
/configure/Configure/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: main.m
3 | // project: DND (config)
4 | // description: main interface/entry point for config app
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | #import "Consts.h"
13 | #import "Logging.h"
14 | #import "utilities.h"
15 | #import "Configure.h"
16 |
17 | //cmdline interface
18 | // install or uninstall
19 | BOOL cmdlineInterface(int action);
20 |
21 | //main interface
22 | int main(int argc, char *argv[])
23 | {
24 | //status
25 | int status = -1;
26 |
27 | //cmdline install?
28 | if(YES == [[[NSProcessInfo processInfo] arguments] containsObject:CMDLINE_FLAG_INSTALL])
29 | {
30 | //dbg msg
31 | logMsg(LOG_DEBUG, @"performing commandline install");
32 |
33 | //install
34 | if(YES != cmdlineInterface(ACTION_INSTALL_FLAG))
35 | {
36 | //err msg
37 | printf("\nDND ERROR: install failed\n\n");
38 |
39 | //bail
40 | goto bail;
41 | }
42 |
43 | //dbg msg
44 | printf("DND: install ok!\n");
45 |
46 | //happy
47 | status = 0;
48 | }
49 |
50 | //cmdline uninstall?
51 | else if(YES == [[[NSProcessInfo processInfo] arguments] containsObject:CMDLINE_FLAG_UNINSTALL])
52 | {
53 | //dbg msg
54 | logMsg(LOG_DEBUG, @"performing commandline uninstall");
55 |
56 | //install
57 | if(YES != cmdlineInterface(ACTION_UNINSTALL_FLAG))
58 | {
59 | //err msg
60 | printf("\nDND ERROR: uninstall failed\n\n");
61 |
62 | //bail
63 | goto bail;
64 | }
65 |
66 | //dbg msg
67 | printf("DND: uninstall ok!\n");
68 |
69 | //happy
70 | status = 0;
71 | }
72 |
73 | //default run mode
74 | // just kick off main app logic
75 | else
76 | {
77 | //app main
78 | status = NSApplicationMain(argc, (const char **) argv);
79 | }
80 |
81 | bail:
82 |
83 | return status;
84 | }
85 |
86 | //cmdline interface
87 | // install or uninstall
88 | BOOL cmdlineInterface(int action)
89 | {
90 | //flag
91 | BOOL wasConfigured = NO;
92 |
93 | //configure obj
94 | Configure* configure = nil;
95 |
96 | //alloc/init
97 | configure = [[Configure alloc] init];
98 |
99 | //first check root
100 | if(0 != geteuid())
101 | {
102 | //err msg
103 | printf("\nDND ERROR: cmdline interface actions require root!\n\n");
104 |
105 | //bail
106 | goto bail;
107 | }
108 |
109 | //configure
110 | wasConfigured = [configure configure:action];
111 | if(YES != wasConfigured)
112 | {
113 | //bail
114 | goto bail;
115 | }
116 |
117 | //happy
118 | wasConfigured = YES;
119 |
120 | bail:
121 |
122 | //cleanup
123 | if(nil != configure)
124 | {
125 | //cleanup
126 | [configure removeHelper];
127 | }
128 |
129 | return wasConfigured;
130 | }
131 |
--------------------------------------------------------------------------------
/configure/Configure/HelperComms.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: DaemonComms.m
3 | // project: DND (shared)
4 | // description: talk to daemon
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | #import "Consts.h"
13 | #import "Logging.h"
14 | #import "AppDelegate.h"
15 | #import "HelperComms.h"
16 |
17 | @implementation HelperComms
18 |
19 | @synthesize daemon;
20 | @synthesize xpcServiceConnection;
21 |
22 | //init
23 | // create XPC connection & set remote obj interface
24 | -(id)init
25 | {
26 | //super
27 | self = [super init];
28 | if(nil != self)
29 | {
30 | //alloc/init
31 | xpcServiceConnection = [[NSXPCConnection alloc] initWithMachServiceName:INSTALLER_HELPER_ID options:0];
32 |
33 | //set remote object interface
34 | self.xpcServiceConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCProtocol)];
35 |
36 | //resume
37 | [self.xpcServiceConnection resume];
38 | }
39 |
40 | return self;
41 | }
42 |
43 | //install
44 | // note: XPC is async, so return logic handled in callback block
45 | -(void)install:(void (^)(NSNumber*))reply
46 | {
47 | //dbg msg
48 | logMsg(LOG_DEBUG, @"invoking 'install' XPC method");
49 |
50 | //install
51 | [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError)
52 | {
53 | //err msg
54 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'install' method on helper tool (error: %@)", proxyError]);
55 |
56 | //invoke block
57 | reply([NSNumber numberWithInt:-1]);
58 |
59 | }] install:[[NSBundle mainBundle] bundlePath] reply:^(NSNumber* result)
60 | {
61 | //invoke block
62 | reply(result);
63 | }];
64 |
65 | return;
66 | }
67 |
68 | //uninstall
69 | // note: XPC is async, so return logic handled in callback block
70 | -(void)uninstall:(BOOL)full reply:(void (^)(NSNumber*))reply
71 | {
72 | //dbg msg
73 | logMsg(LOG_DEBUG, @"invoking 'uninstall' XPC method");
74 |
75 | //uninstall
76 | [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError)
77 | {
78 | //err msg
79 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'uninstall' method on helper tool (error: %@)", proxyError]);
80 |
81 | //invoke block
82 | reply([NSNumber numberWithInt:-1]);
83 |
84 | }] uninstall:[[NSBundle mainBundle] bundlePath] full:full reply:^(NSNumber* result)
85 | {
86 | //invoke block
87 | reply(result);
88 | }];
89 |
90 | return;
91 | }
92 |
93 | //remove
94 | -(void)remove
95 | {
96 | //dbg msg
97 | logMsg(LOG_DEBUG, @"removing");
98 |
99 | //remove
100 | [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError)
101 | {
102 | //err msg
103 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'remove' method on helper tool (error: %@)", proxyError]);
104 |
105 | }] remove];
106 |
107 | return;
108 | }
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/loginItem/loginItem/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/loginItem/loginItem/XPCUser.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCUser.m
3 | // project: DND (login item)
4 | // description: user XPC methods
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Camera.h"
11 | #import "Consts.h"
12 | #import "Logging.h"
13 | #import "XPCUser.h"
14 | #import "AppDelegate.h"
15 |
16 | @implementation XPCUser
17 |
18 | //show an alert
19 | -(void)alertShow:(NSDictionary*)alert
20 | {
21 | //notification
22 | NSUserNotification* notification = nil;
23 |
24 | //formatter
25 | NSDateFormatter* dateFormat = nil;
26 |
27 | //dbg msg
28 | logMsg(LOG_DEBUG, @"XPC request from daemon: alert show");
29 |
30 | //alloc notification
31 | notification = [[NSUserNotification alloc] init];
32 |
33 | //alloc formatter
34 | dateFormat = [[NSDateFormatter alloc] init];
35 |
36 | //set date format
37 | [dateFormat setDateFormat:@"MM/dd/yyyy HH:mm:ss"];
38 |
39 | //set other button title
40 | notification.otherButtonTitle = @"Dismiss";
41 |
42 | //remove action button
43 | notification.hasActionButton = NO;
44 |
45 | //set title
46 | notification.title = @"⚠️ Do Not Disturb Alert";
47 |
48 | //set subtitle
49 | notification.subtitle = [NSString stringWithFormat:@"Lid Opened: %@", [dateFormat stringFromDate:alert[ALERT_TIMESTAMP]]];
50 |
51 | //set delegate to self
52 | [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
53 |
54 | //show alert on main thread
55 | dispatch_async(dispatch_get_main_queue(), ^{
56 |
57 | //deliver notification
58 | [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
59 |
60 | //init/show touch bar
61 | [((AppDelegate*)[[NSApplication sharedApplication] delegate]) initTouchBar];
62 |
63 | });
64 |
65 | return;
66 | }
67 |
68 | //dismiss alert(s)
69 | -(void)alertDismiss
70 | {
71 | //dbg msg
72 | logMsg(LOG_DEBUG, @"XPC request from daemon: alert dismiss");
73 |
74 | //dismiss alerts on main thread
75 | dispatch_async(dispatch_get_main_queue(), ^{
76 |
77 | //clear (all) notification(s)
78 | [[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications];
79 |
80 | //set app delegate's touch bar to nil
81 | // will hide/unset the touch bar alert....
82 | ((AppDelegate*)[[NSApplication sharedApplication] delegate]).touchBar = nil;
83 |
84 | });
85 |
86 | return;
87 | }
88 |
89 | //XPC method
90 | // capture an image from the webcam
91 | -(void)captureImage:(void (^)(NSData *))reply
92 | {
93 | //image data
94 | NSData* image = nil;
95 |
96 | //camera obj
97 | Camera* camera = nil;
98 |
99 | //dbg msg
100 | logMsg(LOG_DEBUG, @"XPC request from daemon: capture picture");
101 |
102 | //init camera
103 | camera = [[Camera alloc] init];
104 |
105 | //grab image
106 | image = [camera captureImage];
107 |
108 | //get current prefs
109 | reply(image);
110 |
111 | return;
112 | }
113 |
114 | //'NSUserNotificationCenterDelegate' delegate method
115 | // tell system to always present (show) the alert to user
116 | -(BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
117 | {
118 | return YES;
119 | }
120 |
121 | @end
122 |
--------------------------------------------------------------------------------
/loginItem/loginItem/AppReceipt.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppReceipt.h
3 | // RansomWhere?
4 | //
5 | // Created by Patrick Wardle on 5/1/16.
6 | //
7 | // note: code inspired by [1] https://gist.github.com/sazameki/3026845
8 |
9 | #ifndef AppReceipt_h
10 | #define AppReceipt_h
11 |
12 | #import
13 | #import
14 | #import
15 | #import
16 | #import
17 |
18 |
19 | //from 'Receipt Fields' section (Apple's 'Receipt Validation Programming Guide')
20 |
21 | //ANS.1 data struct
22 | typedef struct
23 | {
24 | size_t length;
25 | unsigned char *data;
26 | } ASN1_Data;
27 |
28 | //receipt attribute struct
29 | typedef struct
30 | {
31 | ASN1_Data type; // INTEGER
32 | ASN1_Data version; // INTEGER
33 | ASN1_Data value; // OCTET STRING
34 |
35 | } ReceiptAttribute;
36 |
37 | //receipt payload struct
38 | typedef struct
39 | {
40 | ReceiptAttribute **attrs;
41 |
42 | } ReceiptPayload;
43 |
44 | //ASN.1 receipt attribute template (from [1])
45 | static const SecAsn1Template kReceiptAttributeTemplate[] =
46 | {
47 | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ReceiptAttribute) },
48 | { SEC_ASN1_INTEGER, offsetof(ReceiptAttribute, type), NULL, 0 },
49 | { SEC_ASN1_INTEGER, offsetof(ReceiptAttribute, version), NULL, 0 },
50 | { SEC_ASN1_OCTET_STRING, offsetof(ReceiptAttribute, value), NULL, 0 },
51 | { 0, 0, NULL, 0 }
52 | };
53 |
54 | //ASN.1 receipt template set (from [1])
55 | static const SecAsn1Template kSetOfReceiptAttributeTemplate[] =
56 | {
57 | { SEC_ASN1_SET_OF, 0, kReceiptAttributeTemplate, sizeof(ReceiptPayload) },
58 | { 0, 0, NULL, 0 }
59 | };
60 |
61 | //attribute type for bundle ID
62 | #define RECEIPT_ATTR_BUNDLE_ID 2
63 |
64 | //attribute type for app version
65 | #define RECEIPT_ATTR_APP_VERSION 3
66 |
67 | //attribute type for opaque value
68 | #define RECEIPT_ATTR_OPAQUE_VALUE 4
69 |
70 | //attribute type for receipt's hash
71 | #define RECEIPT_ATTR_RECEIPT_HASH 5
72 |
73 | //key for bundle id
74 | #define KEY_BUNDLE_ID @"bundleID"
75 |
76 | //key for bundle id data
77 | #define KEY_BUNDLE_DATA @"bundleIDData"
78 |
79 | //key for app version
80 | #define KEY_APP_VERSION @"applicationVersion"
81 |
82 | //key for opaque value
83 | #define KEY_OPAQUE_VALUE @"opaqueValue"
84 |
85 | //key for receipt's sha-1 hash
86 | #define KEY_RECEIPT_HASH @"receiptHash"
87 |
88 | //class interface
89 | @interface AppReceipt : NSObject
90 | {
91 |
92 | }
93 |
94 | /* METHODS */
95 |
96 | //init with app path
97 | // ->locate/load receipt, etc
98 | -(instancetype)init:(NSBundle *)bundle;
99 |
100 | /* PROPERTIES */
101 |
102 | //encoded receipt data
103 | @property (nonatomic, retain) NSData* encodedData;
104 |
105 | //decoded receipt data
106 | @property (nonatomic, retain) NSData* decodedData;
107 |
108 | //receipt components
109 | @property(nonatomic, retain)NSMutableDictionary* components;
110 |
111 | //bundle id (from receipt)
112 | @property (nonatomic, strong, readonly) NSString *bundleIdentifier;
113 |
114 | //bundle id data (from receipt)
115 | @property (nonatomic, strong, readonly) NSData *bundleIdentifierData;
116 |
117 | //app version (from receipt)
118 | @property (nonatomic, strong, readonly) NSString *appVersion;
119 |
120 | //opaque value (from receipt)
121 | @property (nonatomic, strong, readonly) NSData *opaqueValue;
122 |
123 | //receipts hash (from receipt)
124 | @property (nonatomic, strong, readonly) NSData *receiptHash;
125 |
126 | @end
127 |
128 | #endif /* AppReceipt_h */
129 |
--------------------------------------------------------------------------------
/mainApp/mainApp/PrefsWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // file: PrefsWindowController.h
3 | // project: DND (main app)
4 | // description: preferences window controller (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Cocoa;
11 |
12 | #import "XPCDaemonClient.h"
13 | #import "UpdateWindowController.h"
14 |
15 | /* CONSTS */
16 |
17 | //general view
18 | #define TOOLBAR_GENERAL 0
19 |
20 | //action view
21 | #define TOOLBAR_ACTION 1
22 |
23 | //link view
24 | #define TOOLBAR_LINK 2
25 |
26 | //update view
27 | #define TOOLBAR_UPDATE 3
28 |
29 | //tool bar id for 'general'
30 | #define TOOLBAR_GENERAL_ID @"general"
31 |
32 | //passive mode button
33 | #define BUTTON_PASSIVE_MODE 1
34 |
35 | //no icon mode button
36 | #define BUTTON_NO_ICON_MODE 2
37 |
38 | //touch id mode button
39 | #define BUTTON_TOUCHID_MODE 3
40 |
41 | //start mode button
42 | #define BUTTON_START_MODE 4
43 |
44 | //execute action button
45 | #define BUTTON_EXECUTE_ACTION 5
46 |
47 | //monitor button
48 | #define BUTTON_MONITOR_ACTION 6
49 |
50 | //no remote tasking button
51 | #define BUTTON_NO_REMOTE_TASKING 7
52 |
53 | //no updates button
54 | #define BUTTON_NO_UPDATES_MODE 8
55 |
56 | @interface PrefsWindowController : NSWindowController
57 |
58 | /* PROPERTIES */
59 |
60 | //daemon comms object
61 | @property (retain, nonatomic)XPCDaemonClient* daemonComms;
62 |
63 | //preferences
64 | @property(nonatomic, retain)NSDictionary* preferences;
65 |
66 | //toolbar
67 | @property (weak) IBOutlet NSToolbar *toolbar;
68 |
69 | //general prefs view
70 | @property (weak) IBOutlet NSView *generalView;
71 |
72 | //action view
73 | @property (weak) IBOutlet NSView *actionView;
74 |
75 | //execute path
76 | @property (weak) IBOutlet NSTextField *executePath;
77 |
78 | /* LINK VIEW */
79 |
80 | //overlay view
81 | @property (strong) IBOutlet NSView *overlayView;
82 |
83 | //overlay spinner
84 | @property (weak) IBOutlet NSProgressIndicator *overlayProgressIndicator;
85 |
86 | //link toolbar item
87 | @property (weak) IBOutlet NSToolbarItem *linkToolbarItem;
88 |
89 | //link view
90 | @property (strong) IBOutlet NSView *linkView;
91 |
92 | //spinner
93 | @property (weak) IBOutlet NSProgressIndicator *qrcProgressIndicator;
94 |
95 | //activity msg
96 | @property (weak) IBOutlet NSTextField *activityMessage;
97 |
98 | //qrc panel
99 | @property (strong) IBOutlet NSPanel *qrcPanel;
100 |
101 | //qrc image view
102 | @property (weak) IBOutlet NSImageView *qrcImageView;
103 |
104 | /* LINKED (DEVICES) VIEW */
105 |
106 | //linked view
107 | @property (strong) IBOutlet NSView *linkedView;
108 |
109 | //host (computer) name
110 | @property (weak) IBOutlet NSTextField *hostName;
111 |
112 | //device names
113 | @property (unsafe_unretained) IBOutlet NSTextView *deviceNames;
114 |
115 |
116 | /* UPDATE VIEW */
117 |
118 | //update view
119 | @property (weak) IBOutlet NSView *updateView;
120 |
121 | //update button
122 | @property (weak) IBOutlet NSButton *updateButton;
123 |
124 | //update indicator (spinner)
125 | @property (weak) IBOutlet NSProgressIndicator *updateIndicator;
126 |
127 | //update label
128 | @property (weak) IBOutlet NSTextField *updateLabel;
129 |
130 | //update window controller
131 | @property(nonatomic, retain)UpdateWindowController* updateWindowController;
132 |
133 | /* METHODS */
134 |
135 | //toolbar button handler
136 | -(IBAction)toolbarButtonHandler:(id)sender;
137 |
138 | //button handler for all preference buttons
139 | -(IBAction)togglePreference:(id)sender;
140 |
141 | @end
142 |
--------------------------------------------------------------------------------
/shared/UpdateWindowController.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: UpdateWindowController.m
3 | // project: DND (shared)
4 | // description: window handler for update window/popup
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Logging.h"
12 | #import "Utilities.h"
13 | #import "AppDelegate.h"
14 | #import "UpdateWindowController.h"
15 |
16 |
17 | @implementation UpdateWindowController
18 |
19 | @synthesize infoLabel;
20 | @synthesize overlayView;
21 | @synthesize firstButton;
22 | @synthesize actionButton;
23 | @synthesize infoLabelString;
24 | @synthesize actionButtonTitle;
25 | @synthesize progressIndicator;
26 |
27 | //automatically called when nib is loaded
28 | // center window
29 | -(void)awakeFromNib
30 | {
31 | //center
32 | [self.window center];
33 |
34 | return;
35 | }
36 |
37 | //automatically invoked when window is loaded
38 | // set to white
39 | -(void)windowDidLoad
40 | {
41 | //super
42 | [super windowDidLoad];
43 |
44 | //not in mojave dark mode?
45 | // make window color white
46 | if(YES != isDarkMode())
47 | {
48 | //make white
49 | self.window.backgroundColor = NSColor.whiteColor;
50 | }
51 |
52 | //when supported
53 | // indicate title bar is transparent (too)
54 | if([self.window respondsToSelector:@selector(titlebarAppearsTransparent)])
55 | {
56 | //set transparency
57 | self.window.titlebarAppearsTransparent = YES;
58 | }
59 |
60 | //set main label
61 | [self.infoLabel setStringValue:self.infoLabelString];
62 |
63 | //set button text
64 | self.actionButton.title = self.actionButtonTitle;
65 |
66 | //hide first button when action is 'update'
67 | // don't need update check button ;)
68 | if(YES == [self.actionButton.title isEqualToString:@"Update"])
69 | {
70 | //hide
71 | self.firstButton.hidden = YES;
72 |
73 | //then make action button first responder
74 | [self.window makeFirstResponder:self.actionButton];
75 | }
76 |
77 | //make it key window
78 | [self.window makeKeyAndOrderFront:self];
79 |
80 | //make window front
81 | [NSApp activateIgnoringOtherApps:YES];
82 |
83 | return;
84 | }
85 |
86 | //automatically invoked when window is closing
87 | // make ourselves unmodal
88 | -(void)windowWillClose:(NSNotification *)notification
89 | {
90 | //make un-modal
91 | [[NSApplication sharedApplication] stopModal];
92 |
93 | return;
94 | }
95 |
96 | //save the main label's & button title's text
97 | // invoked before window is loaded (and thus buttons, etc are nil)
98 | -(void)configure:(NSString*)label buttonTitle:(NSString*)buttonTitle
99 | {
100 | //save label's string
101 | self.infoLabelString = label;
102 |
103 | //save button's title
104 | self.actionButtonTitle = buttonTitle;
105 |
106 | return;
107 | }
108 |
109 | //invoked when user clicks button
110 | // trigger action such as opening product website, updating, etc
111 | -(IBAction)buttonHandler:(id)sender
112 | {
113 | //handle 'update' / 'more info', etc
114 | // open DND's webpage, if they *didn't* click 'close'
115 | if(YES != [((NSButton*)sender).title isEqualToString:@"close"])
116 | {
117 | //open URL
118 | // invokes user's default browser
119 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]];
120 | }
121 |
122 | //always close window
123 | [[self window] close];
124 |
125 | return;
126 | }
127 | @end
128 |
--------------------------------------------------------------------------------
/mainApp/mainApp/QuickResponseCode.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: QuickResponseCode.m
3 | // project: DND (main app)
4 | // description: QR Code logic
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Logging.h"
11 | #import "XPCDaemonClient.h"
12 | #import "QuickResponseCode.h"
13 |
14 | #import
15 |
16 | @implementation QuickResponseCode
17 |
18 | @synthesize daemonComms;
19 |
20 | //init
21 | // create XPC connection & set remote obj interface
22 | -(id)init
23 | {
24 | //super
25 | self = [super init];
26 | if(nil != self)
27 | {
28 | //init daemon comms
29 | // will connect, etc.
30 | daemonComms = [[XPCDaemonClient alloc] init];
31 | }
32 |
33 | return self;
34 | }
35 |
36 | //generate a QRC code
37 | // gets QRC string from image, then generates image
38 | -(void)generateQRC:(float)size reply:(void (^)(NSImage* qrc))reply
39 | {
40 | //make request to daemon
41 | // give me a QRC code y0!
42 | [daemonComms qrcRequest:^(NSData* qrcData)
43 | {
44 | //qrc image
45 | NSImage* qrcImage = nil;
46 |
47 | //generate qrc image
48 | if(0 != qrcData.length)
49 | {
50 | //dbg msg
51 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"got qrc from daemon (size: %lu)", (unsigned long)qrcData.length]);
52 |
53 | //generate QRC image
54 | qrcImage = [self generateImage:qrcData size:size];
55 | }
56 |
57 | //didn't get anything from the daemon/framework :(
58 | else
59 | {
60 | //err msg
61 | logMsg(LOG_ERR, @"failed to generated QRC data");
62 | }
63 |
64 | //call back
65 | reply(qrcImage);
66 |
67 | }];
68 |
69 | return;
70 | }
71 |
72 | //generate qrc image
73 | -(NSImage*)generateImage:(NSData*)data size:(float)size
74 | {
75 | //qrc image
76 | NSImage* qrcImage = nil;
77 |
78 | //filter
79 | CIFilter *filter = NULL;
80 |
81 | //output image
82 | CIImage *outputImage = NULL;
83 |
84 | //transformed image
85 | CIImage *transformedImage = NULL;
86 |
87 | //image rep
88 | NSCIImageRep* imageRep = nil;
89 |
90 | //extent
91 | CGRect extent = {0};
92 |
93 | //scale
94 | CGFloat scale = 0.0f;
95 |
96 | //transform
97 | CGAffineTransform transform = {0};
98 |
99 | //init filter
100 | filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
101 | if(nil == filter)
102 | {
103 | //bail
104 | goto bail;
105 | }
106 |
107 | //set data
108 | [filter setValue:data forKey:@"inputMessage"];
109 |
110 | //set correction level
111 | [filter setValue:@"L" forKey:@"inputCorrectionLevel"];
112 |
113 | //grab output image
114 | outputImage = filter.outputImage;
115 |
116 | //init extent
117 | extent = outputImage.extent;
118 |
119 | //init scale
120 | scale = MIN(size/extent.size.width, size/extent.size.height);
121 |
122 | //init transform
123 | transform = CGAffineTransformMakeScale(scale, scale);
124 |
125 | //apply transform
126 | transformedImage = [outputImage imageByApplyingTransform:transform];
127 |
128 | //generate image representation
129 | imageRep = [NSCIImageRep imageRepWithCIImage:transformedImage];
130 |
131 | //init image
132 | qrcImage = [[NSImage alloc] initWithSize:imageRep.size];
133 |
134 | //add representation
135 | [qrcImage addRepresentation:imageRep];
136 |
137 | bail:
138 |
139 | return qrcImage;
140 | }
141 |
142 | @end
143 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/libs/procInfo.h:
--------------------------------------------------------------------------------
1 | //
2 | // File: procInfo.h
3 | // Project: Proc Info
4 | //
5 | // Created by: Patrick Wardle
6 | // Copyright: 2018 Objective-See
7 | // License: Creative Commons Attribution-NonCommercial 4.0 International License
8 | //
9 |
10 | #ifndef procInfo_h
11 | #define procInfo_h
12 |
13 | #import
14 | #import
15 | #import
16 |
17 | /* CLASSES */
18 |
19 | @class Binary;
20 | @class Process;
21 |
22 |
23 | /* DEFINES */
24 |
25 | //from audit_kevents.h
26 | #define EVENT_EXIT 1
27 | #define EVENT_FORK 2
28 | #define EVENT_EXECVE 23
29 | #define EVENT_EXEC 27
30 | #define EVENT_SPAWN 43190
31 |
32 | /* TYPEDEFS */
33 |
34 | //block for library
35 | typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
36 |
37 |
38 | /* OBJECT: PROCESS INFO */
39 |
40 | @interface ProcInfo : NSObject
41 |
42 | //init w/ flag
43 | // flag dictates if CPU-intensive logic (code signing, etc) should be preformed
44 | -(id _Nullable )init:(BOOL)goEasy;
45 |
46 | //start monitoring
47 | -(void)start:(ProcessCallbackBlock _Nonnull )callback;
48 |
49 | //stop monitoring
50 | -(void)stop;
51 |
52 | //get list of running processes
53 | -(NSMutableArray* _Nonnull)currentProcesses;
54 |
55 | @end
56 |
57 | /* OBJECT: PROCESS */
58 |
59 | @interface Process : NSObject
60 |
61 | /* PROPERTIES */
62 |
63 | //pid
64 | @property pid_t pid;
65 |
66 | //ppid
67 | @property pid_t ppid;
68 |
69 | //user id
70 | @property uid_t uid;
71 |
72 | //type
73 | // used by process mon
74 | @property u_int16_t type;
75 |
76 | //exit code
77 | @property u_int32_t exit;
78 |
79 | //path
80 | @property (nonatomic, retain) NSString* _Nullable path;
81 |
82 | //args
83 | @property (nonatomic, retain) NSMutableArray* _Nonnull arguments;
84 |
85 | //ancestors
86 | @property (nonatomic, retain) NSMutableArray* _Nonnull ancestors;
87 |
88 | //Binary object
89 | // has path, hash, etc
90 | @property (nonatomic, retain) Binary* _Nonnull binary;
91 |
92 | //timestamp
93 | @property (nonatomic, retain) NSDate* _Nonnull timestamp;
94 |
95 | /* METHODS */
96 |
97 | //init with a pid
98 | // method will then (try) fill out rest of object
99 | -(id _Nullable )init:(pid_t)processID;
100 |
101 | //set process's path
102 | -(void)pathFromPid;
103 |
104 | //generate list of ancestors
105 | -(void)enumerateAncestors;
106 |
107 | //class method to get parent of arbitrary process
108 | +(pid_t)getParentID:(pid_t)child;
109 |
110 | @end
111 |
112 | /* OBJECT: BINARY */
113 |
114 | @interface Binary : NSObject
115 | {
116 |
117 | }
118 |
119 | /* PROPERTIES */
120 |
121 | //path
122 | @property (nonatomic, retain)NSString* _Nonnull path;
123 |
124 | //name
125 | @property (nonatomic, retain)NSString* _Nonnull name;
126 |
127 | //icon
128 | @property (nonatomic, retain)NSImage* _Nonnull icon;
129 |
130 | //file attributes
131 | @property (nonatomic, retain)NSDictionary* _Nullable attributes;
132 |
133 | //bundle
134 | // nil for non-apps
135 | @property (nonatomic, retain)NSBundle* _Nullable bundle;
136 |
137 | //signing info
138 | @property (nonatomic, retain)NSDictionary* _Nonnull signingInfo;
139 |
140 | //flag indicating binary belongs to Apple OS
141 | @property BOOL isApple;
142 |
143 | //flag indicating binary is from official App Store
144 | @property BOOL isAppStore;
145 |
146 | /* METHODS */
147 |
148 | //init w/ an info dictionary
149 | -(id _Nonnull )init:(NSString* _Nonnull)path;
150 |
151 | //generate signing info
152 | // also classifies if Apple/from App Store/etc.
153 | // note: called automatically if proc monitor is run without 'goEasy' option
154 | -(void)generateSigningInfo;
155 |
156 | //get an icon for a process
157 | // for apps, this will be app's icon, otherwise just a standard system one
158 | // note: called automatically if proc monitor is run without 'goEasy' option
159 | -(void)getIcon;
160 |
161 | @end
162 |
163 | #endif
164 |
--------------------------------------------------------------------------------
/mainApp/mainApp.xcodeproj/xcshareddata/xcschemes/mainApp.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
68 |
70 |
76 |
77 |
78 |
79 |
80 |
81 |
87 |
89 |
95 |
96 |
97 |
98 |
100 |
101 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/loginItem/loginItem/StatusBarPopover.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/configure/Configure/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: AppDelegate.m
3 | // project: DND (config)
4 | // description: application delegate
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Sentry;
11 |
12 | #import "Consts.h"
13 | #import "Logging.h"
14 | #import "Configure.h"
15 | #import "Utilities.h"
16 | #import "AppDelegate.h"
17 | #import "HelperComms.h"
18 |
19 | #import
20 | #import
21 |
22 | @implementation AppDelegate
23 |
24 | @synthesize gotHelp;
25 | @synthesize xpcComms;
26 | @synthesize statusMsg;
27 | @synthesize configureObj;
28 |
29 | @synthesize aboutWindowController;
30 | @synthesize configureWindowController;
31 |
32 | //main app interface
33 | -(void)applicationDidFinishLaunching:(NSNotification *)notification
34 | {
35 | #pragma unused(notification)
36 |
37 | //init crash reporting client
38 | SentryClient.sharedClient = [[SentryClient alloc] initWithDsn:CRASH_REPORTING_URL didFailWithError:nil];
39 |
40 | //start crash handler
41 | [SentryClient.sharedClient startCrashHandlerWithError:nil];
42 |
43 | //make sure system is supported (lid)
44 | // if not, will inform user via alert
45 | if(YES != [self isSupported])
46 | {
47 | //dbg msg
48 | logMsg(LOG_ERR, @"device doesn't appear to have a lid (i.e. is unsupported)");
49 |
50 | //exit
51 | [NSApp terminate:self];
52 | }
53 |
54 | //alloc/init Config obj
55 | configureObj = [[Configure alloc] init];
56 |
57 | //show config window
58 | [self displayConfigureWindow:[self.configureObj isInstalled]];
59 |
60 | return;
61 | }
62 |
63 | //check if there's a lid
64 | // if not, alert to tell user
65 | -(BOOL)isSupported
66 | {
67 | //flag
68 | BOOL supported = NO;
69 |
70 | //alert
71 | NSAlert* alert = nil;
72 |
73 | //no lid
74 | // can't support!
75 | if(stateUnavailable == getLidState())
76 | {
77 | //init alert
78 | alert = [[NSAlert alloc] init];
79 |
80 | //set main text
81 | alert.messageText = @"Unsupported Device";
82 |
83 | //set informative text
84 | alert.informativeText = [NSString stringWithFormat:@"'%@' does not appear to be a laptop", [[NSHost currentHost] localizedName]];
85 |
86 | //add button
87 | [alert addButtonWithTitle:@"Ok"];
88 |
89 | //set style
90 | alert.alertStyle = NSAlertStyleWarning;
91 |
92 | //show it
93 | [alert runModal];
94 |
95 | //bail
96 | goto bail;
97 | }
98 |
99 | //happy
100 | supported = YES;
101 |
102 | bail:
103 |
104 | return supported;
105 |
106 | }
107 |
108 | //exit when last window is closed
109 | -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
110 | {
111 | #pragma unused(sender)
112 |
113 | return YES;
114 | }
115 |
116 | //app termination handler
117 | // tell helper to remove itself
118 | -(void)applicationWillTerminate:(NSNotification *)notification
119 | {
120 | #pragma unused(notification)
121 |
122 | //tell Config object we're going away
123 | // allows it to (possibly) uninstall the helper tool
124 | [self.configureObj removeHelper];
125 |
126 | return;
127 | }
128 |
129 | //display configuration window w/ 'install' || 'uninstall' button
130 | -(void)displayConfigureWindow:(BOOL)isInstalled
131 | {
132 | //alloc/init
133 | configureWindowController = [[ConfigureWindowController alloc] initWithWindowNibName:@"ConfigureWindowController"];
134 |
135 | //display it
136 | // call this first to so that outlets are connected
137 | [self.configureWindowController display];
138 |
139 | //configure it
140 | [self.configureWindowController configure:isInstalled];
141 |
142 | return;
143 | }
144 |
145 | //menu handler for 'about'
146 | -(IBAction)displayAboutWindow:(id)sender
147 | {
148 | #pragma unused(sender)
149 |
150 | //alloc/init settings window
151 | if(nil == self.aboutWindowController)
152 | {
153 | //alloc/init
154 | aboutWindowController = [[AboutWindowController alloc] initWithWindowNibName:@"AboutWindow"];
155 | }
156 |
157 | //center window
158 | [[self.aboutWindowController window] center];
159 |
160 | //show it
161 | [self.aboutWindowController showWindow:self];
162 |
163 | return;
164 | }
165 |
166 | @end
167 |
--------------------------------------------------------------------------------
/configure/Helper/HelperListener.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: HelperListener.m
3 | // project: (open-source) installer
4 | // description: XPC listener for connections for user components
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | @import Foundation;
11 |
12 | #import "Consts.h"
13 | #import "Logging.h"
14 | #import "XPCProtocol.h"
15 | #import "HelperListener.h"
16 | #import "HelperInterface.h"
17 |
18 | //interface for 'extension' to NSXPCConnection
19 | // allows us to access the 'private' auditToken iVar
20 | @interface ExtendedNSXPCConnection : NSXPCConnection
21 |
22 | //private iVar
23 | @property (nonatomic) audit_token_t auditToken;
24 |
25 | @end
26 |
27 | //implementation for 'extension' to NSXPCConnection
28 | // allows us to access the 'private' auditToken iVar
29 | @implementation ExtendedNSXPCConnection
30 |
31 | //private iVar
32 | @synthesize auditToken;
33 |
34 | @end
35 |
36 |
37 |
38 | @implementation HelperListener
39 |
40 |
41 | @synthesize listener;
42 |
43 | //init
44 | // create XPC listener
45 | -(id)init
46 | {
47 | //init super
48 | self = [super init];
49 | if(nil != self)
50 | {
51 | //setup XPC listener
52 | if(YES != [self initListener])
53 | {
54 | //unset
55 | self = nil;
56 |
57 | //bail
58 | goto bail;
59 |
60 | }
61 | }
62 |
63 | bail:
64 |
65 | return self;
66 | }
67 |
68 | //setup XPC listener
69 | -(BOOL)initListener
70 | {
71 | //result
72 | BOOL result = NO;
73 |
74 | //init listener
75 | listener = [[NSXPCListener alloc] initWithMachServiceName:INSTALLER_HELPER_ID];
76 | if(nil == self.listener)
77 | {
78 | //err msg
79 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to create mach service %@", INSTALLER_HELPER_ID]);
80 |
81 | //bail
82 | goto bail;
83 | }
84 |
85 | //dbg msg
86 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"created mach service %@", INSTALLER_HELPER_ID]);
87 |
88 | //set delegate
89 | self.listener.delegate = self;
90 |
91 | //ready to accept connections
92 | [self.listener resume];
93 |
94 | //happy
95 | result = YES;
96 |
97 | bail:
98 |
99 | return result;
100 | }
101 |
102 | #pragma mark -
103 | #pragma mark NSXPCConnection method overrides
104 |
105 | //automatically invoked
106 | // allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection
107 | // note: we only allow binaries signed by Objective-See to talk to this to be extra safe :)
108 | -(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
109 | {
110 | //pragma
111 | #pragma unused(listener)
112 |
113 | //flag
114 | BOOL shouldAccept = NO;
115 |
116 | //task ref
117 | SecTaskRef taskRef = 0;
118 |
119 | //signing req string
120 | NSString *requirementString = nil;
121 |
122 | //init signing req string
123 | requirementString = [NSString stringWithFormat:@"anchor trusted and certificate leaf [subject.CN] = \"%@\"", SIGNING_AUTH];
124 |
125 | //step 1: create task ref
126 | // uses NSXPCConnection's (private) 'auditToken' iVar
127 | taskRef = SecTaskCreateWithAuditToken(NULL, ((ExtendedNSXPCConnection*)newConnection).auditToken);
128 | if(NULL == taskRef)
129 | {
130 | //bail
131 | goto bail;
132 | }
133 |
134 | //step 2: validate
135 | // check that client is signed with Objective-See's dev cert
136 | if(0 != SecTaskValidateForRequirement(taskRef, (__bridge CFStringRef)(requirementString)))
137 | {
138 | //bail
139 | goto bail;
140 | }
141 |
142 | //set the interface that the exported object implements
143 | newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCProtocol)];
144 |
145 | //set object exported by connection
146 | newConnection.exportedObject = [[HelperInterface alloc] init];
147 |
148 | //resume
149 | [newConnection resume];
150 |
151 | //dbg msg
152 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"allowed XPC connection: %@", newConnection]);
153 |
154 | //happy
155 | shouldAccept = YES;
156 |
157 | bail:
158 |
159 | //release task ref object
160 | if(NULL != taskRef)
161 | {
162 | //release
163 | CFRelease(taskRef);
164 |
165 | //unset
166 | taskRef = NULL;
167 | }
168 |
169 | return shouldAccept;
170 | }
171 |
172 | @end
173 |
--------------------------------------------------------------------------------
/shared/Logging.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: Logging.h
3 | // project: DND (shared)
4 | // description: logging
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Logging.h"
12 | #import "Utilities.h"
13 |
14 | //global log file handle
15 | NSFileHandle* logFileHandle = nil;
16 |
17 | //log a msg
18 | // default to syslog, and if an err msg, to disk
19 | void logMsg(int level, NSString* msg)
20 | {
21 | //flag for logging
22 | BOOL shouldLog = NO;
23 |
24 | //log prefix
25 | NSMutableString* logPrefix = nil;
26 |
27 | //first grab logging flag
28 | shouldLog = (LOG_TO_FILE == (level & LOG_TO_FILE));
29 |
30 | //then remove it
31 | // make sure syslog is happy
32 | level &= ~LOG_TO_FILE;
33 |
34 | //alloc/init
35 | // always start w/ name + pid
36 | logPrefix = [NSMutableString stringWithFormat:@"Do Not Disturb (pid: %d)", getpid()];
37 |
38 | //if its error, add error to prefix
39 | if(LOG_ERR == level)
40 | {
41 | //add
42 | [logPrefix appendString:@" ERROR"];
43 | }
44 |
45 | //debug mode logic
46 | #ifdef DEBUG
47 |
48 | //in debug mode promote debug msgs to LOG_NOTICE
49 | // OS X only shows LOG_NOTICE and above
50 | if(LOG_DEBUG == level)
51 | {
52 | //promote
53 | level = LOG_NOTICE;
54 | }
55 |
56 | #endif
57 |
58 | //dump to syslog?
59 | // function can be invoked just to log to file...
60 | if(0 != level)
61 | {
62 | //syslog
63 | syslog(level, "%s: %s", [logPrefix UTF8String], [msg UTF8String]);
64 | }
65 |
66 | //when a message is to be logged to file
67 | // log it, when logging is enabled
68 | if(YES == shouldLog)
69 | {
70 | //but only when logging is enable
71 | if(nil != logFileHandle)
72 | {
73 | //log
74 | log2File(msg);
75 | }
76 | }
77 |
78 | return;
79 | }
80 |
81 | //get path to log file
82 | NSString* logFilePath()
83 | {
84 | return [INSTALL_DIRECTORY stringByAppendingPathComponent:LOG_FILE_NAME];
85 | }
86 |
87 | //log to file
88 | void log2File(NSString* msg)
89 | {
90 | //sync
91 | @synchronized(logFileHandle)
92 | {
93 | //append timestamp
94 | // write msg out to disk
95 | [logFileHandle writeData:[[NSString stringWithFormat:@"%@: %@\n", [NSDate date], msg] dataUsingEncoding:NSUTF8StringEncoding]];
96 | }
97 |
98 | return;
99 | }
100 |
101 | //prep/open log file
102 | BOOL initLogging()
103 | {
104 | //ret var
105 | BOOL bRet = NO;
106 |
107 | //log file path
108 | NSString* logPath = nil;
109 |
110 | //get path to log file
111 | logPath = logFilePath();
112 | if(nil == logPath)
113 | {
114 | //err msg
115 | logMsg(LOG_ERR, @"failed to build path for log file");
116 |
117 | //bail
118 | goto bail;
119 | }
120 |
121 | //first time
122 | // create log file
123 | if(YES != [[NSFileManager defaultManager] fileExistsAtPath:logPath])
124 | {
125 | //create
126 | if(YES != [[NSFileManager defaultManager] createFileAtPath:logPath contents:nil attributes:nil])
127 | {
128 | //err msg
129 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to create %@", logPath]);
130 |
131 | //bail
132 | goto bail;
133 | }
134 | }
135 |
136 | //get file handle
137 | logFileHandle = [NSFileHandle fileHandleForWritingAtPath:logPath];
138 | if(nil == logFileHandle)
139 | {
140 | //err msg
141 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to get log file handle to %@", logPath]);
142 |
143 | //bail
144 | goto bail;
145 | }
146 |
147 | //dbg msg
148 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"opened log file; %@", logPath]);
149 |
150 | //seek to end
151 | [logFileHandle seekToEndOfFile];
152 |
153 | //dbg msg
154 | // and to file
155 | logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging intialized");
156 |
157 | //happy
158 | bRet = YES;
159 |
160 | bail:
161 |
162 | return bRet;
163 | }
164 |
165 | //de-init logging
166 | void deinitLogging()
167 | {
168 | //dbg msg
169 | // and to file
170 | logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging ending");
171 |
172 | //sync
173 | @synchronized(logFileHandle)
174 | {
175 | //close file handle
176 | [logFileHandle closeFile];
177 |
178 | //unset
179 | logFileHandle = nil;
180 | }
181 |
182 | return;
183 | }
184 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/USBMonitor.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: USBMonitor.m
3 | // project: DND (launch daemon)
4 | // description: USB device monitor
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Logging.h"
12 | #import "USBMonitor.h"
13 |
14 | @implementation USBMonitor
15 |
16 | @synthesize runLoopSource;
17 | @synthesize notificationPort;
18 |
19 | //callback for USB devices
20 | void usbDeviceAppeared(void *refCon, io_iterator_t iterator)
21 | {
22 | //dbg msg
23 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"monitor event: usb device inserted"]);
24 |
25 | //process new device
26 | [(__bridge USBMonitor *)refCon handleNewDevice:iterator];
27 |
28 | return;
29 | }
30 |
31 | //start USB monitoring
32 | -(BOOL)start
33 | {
34 | //status
35 | BOOL initialized = NO;
36 |
37 | //status
38 | kern_return_t status = kIOReturnError;
39 |
40 | //iterator
41 | io_iterator_t iterator = 0;
42 |
43 | //device
44 | io_service_t device = 0;
45 |
46 | //create notification port
47 | self.notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
48 |
49 | //get run loop source
50 | self.runLoopSource = IONotificationPortGetRunLoopSource(self.notificationPort);
51 |
52 | //add source
53 | CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopDefaultMode);
54 |
55 | //add notification
56 | // pass in 'self' so can access obj-c methods in callbacks
57 | status = IOServiceAddMatchingNotification(self.notificationPort, kIOMatchedNotification, IOServiceMatching(kIOUSBDeviceClassName), usbDeviceAppeared,(__bridge void *)self, &iterator);
58 | if(kIOReturnSuccess != status)
59 | {
60 | //err
61 | logMsg(LOG_ERR, [NSString stringWithFormat:@"IOServiceAddMatchingNotification() failed with %d", status]);
62 |
63 | //bail
64 | goto bail;
65 | }
66 |
67 | //process existing devices
68 | // also 'drains' interator...
69 | device = IOIteratorNext(iterator);
70 | while(0 != device)
71 | {
72 | //record device name/properties
73 | [self logDeviceProperties:device];
74 |
75 | //release
76 | IOObjectRelease(device);
77 |
78 | //get next
79 | device = IOIteratorNext(iterator);
80 | }
81 |
82 | //happy
83 | initialized = YES;
84 |
85 | bail:
86 |
87 | return initialized;
88 | }
89 |
90 | //stop
91 | // invalidate runloop src and notification port
92 | -(void)stop
93 | {
94 | //invalidate runloop src
95 | if(nil != self.runLoopSource)
96 | {
97 | //invalidate
98 | CFRunLoopSourceInvalidate(self.runLoopSource);
99 |
100 | //unset
101 | self.runLoopSource = nil;
102 | }
103 |
104 | //destroy notification port
105 | if(nil != self.notificationPort)
106 | {
107 | //destroy
108 | IONotificationPortDestroy(self.notificationPort);
109 |
110 | //unset
111 | self.notificationPort = nil;
112 | }
113 |
114 | return;
115 | }
116 |
117 | //process new USB insertion
118 | // get info about device and log
119 | -(void)handleNewDevice:(io_iterator_t)iterator
120 | {
121 | //usb device
122 | io_service_t device;
123 |
124 | //process
125 | while((device = IOIteratorNext(iterator)))
126 | {
127 | //log msg
128 | logMsg(LOG_TO_FILE, [NSString stringWithFormat:@"monitor event: usb device inserted"]);
129 |
130 | //record device name/properties
131 | [self logDeviceProperties:device];
132 |
133 | //release device
134 | IOObjectRelease(device);
135 |
136 | //unset
137 | device = 0;
138 | }
139 |
140 | return;
141 | }
142 |
143 | //log name/properties of a device
144 | -(void)logDeviceProperties:(io_service_t)device
145 | {
146 | //device name
147 | io_name_t deviceName = {0};
148 |
149 | //device properties
150 | CFMutableDictionaryRef deviceProperties = NULL;
151 |
152 | //get device name
153 | if(KERN_SUCCESS == IORegistryEntryGetName(device, deviceName))
154 | {
155 | //dbg msg & log
156 | logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"usb device name: %s", deviceName]);
157 | }
158 |
159 | //get device properties
160 | if( (kIOReturnSuccess == IORegistryEntryCreateCFProperties(device, &deviceProperties, kCFAllocatorDefault, kNilOptions)) &&
161 | (NULL != deviceProperties) )
162 | {
163 | //dbg msg & log
164 | logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"usb device properties: %@", deviceProperties]);
165 | }
166 |
167 | //release device props
168 | if(NULL != deviceProperties)
169 | {
170 | //release
171 | CFRelease(deviceProperties);
172 |
173 | //unset
174 | deviceProperties = NULL;
175 | }
176 |
177 | return;
178 | }
179 |
180 | @end
181 |
--------------------------------------------------------------------------------
/shared/XPCDaemonClient.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCDaemonClient.m
3 | // project: DND (shared)
4 | // description: talk to the daemon, via XPC (header)
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Logging.h"
12 | #import "XPCUserProto.h"
13 | #import "XPCDaemonClient.h"
14 |
15 | #ifdef XPC_USER
16 | #import "XPCUser.h"
17 | #endif
18 |
19 | @implementation XPCDaemonClient
20 |
21 | @synthesize xpcServiceConnection;
22 |
23 | //init
24 | // create XPC connection & set remote obj interface
25 | -(id)init
26 | {
27 | //super
28 | self = [super init];
29 | if(nil != self)
30 | {
31 | //alloc/init
32 | xpcServiceConnection = [[NSXPCConnection alloc] initWithMachServiceName:DAEMON_MACH_SERVICE options:0];
33 |
34 | //set remote object interface
35 | self.xpcServiceConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCDaemonProtocol)];
36 |
37 | #ifdef XPC_USER
38 |
39 | //set exported object interface (protocol)
40 | self.xpcServiceConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCUserProtocol)];
41 |
42 | //set exported object
43 | // this will allow daemon to invoke user methods!
44 | self.xpcServiceConnection.exportedObject = [[XPCUser alloc] init];
45 |
46 | #endif
47 |
48 | //resume
49 | [self.xpcServiceConnection resume];
50 | }
51 |
52 | return self;
53 | }
54 |
55 | //ask daemon for QRC info
56 | // name, uuid, key, key size, etc...
57 | -(void)qrcRequest:(void (^)(NSData* qrcInfo))reply
58 | {
59 | //dbg msg
60 | logMsg(LOG_DEBUG, @"sending request, via XPC, for qrc info");
61 |
62 | //request qrc info
63 | [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError)
64 | {
65 | //err msg
66 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'qrcRequest' method on launch daemon (error: %@)", proxyError]);
67 |
68 | }] qrcRequest:^(NSData* qrcInfo)
69 | {
70 | //respond with info
71 | reply(qrcInfo);
72 | }];
73 |
74 | return;
75 | }
76 |
77 | //wait for phone to complete registration
78 | // calls into framework that comms w/ server to wait for phone
79 | -(void)recvRegistrationACK:(void (^)(NSDictionary* registrationInfo))reply
80 | {
81 | //dbg msg
82 | logMsg(LOG_DEBUG, @"sending request, via XPC, for recv registration ack/info");
83 |
84 | //recv registration info
85 | // note: this will block until phone pings server
86 | [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError)
87 | {
88 | //err msg
89 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'recvRegistrationACK' method on launch daemon (error: %@)", proxyError]);
90 |
91 | }] recvRegistrationACK:^(NSDictionary* registrationInfo)
92 | {
93 | //respond with alert
94 | reply(registrationInfo);
95 | }];
96 |
97 | return;
98 | }
99 |
100 | //get preferences
101 | // note: synchronous
102 | -(NSDictionary*)getPreferences:(NSString*)preference
103 | {
104 | //preferences
105 | __block NSDictionary* preferences = nil;
106 |
107 | //wait sema
108 | dispatch_semaphore_t semaphore = NULL;
109 |
110 | //init sema
111 | semaphore = dispatch_semaphore_create(0);
112 |
113 | //dbg msg
114 | logMsg(LOG_DEBUG, @"sending request, via XPC, for preferences");
115 |
116 | //request preferences
117 | [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError)
118 | {
119 | //err msg
120 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'getPreferences' method on launch daemon (error: %@)", proxyError]);
121 |
122 | //signal sema
123 | dispatch_semaphore_signal(semaphore);
124 |
125 | }] getPreferences:preference reply:^(NSDictionary* preferencesFromDaemon)
126 | {
127 | //dbg msg
128 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"got preferences: %@", preferencesFromDaemon]);
129 |
130 | //save
131 | preferences = preferencesFromDaemon;
132 |
133 | //signal sema
134 | dispatch_semaphore_signal(semaphore);
135 |
136 | }];
137 |
138 | //XPC is async
139 | // wait for preferences from daemon
140 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
141 |
142 | return preferences;
143 | }
144 |
145 | //update (save) preferences
146 | -(void)updatePreferences:(NSDictionary*)preferences
147 | {
148 | //dbg msg
149 | logMsg(LOG_DEBUG, @"sending request, via XPC, to update preferences");
150 |
151 | //update prefs
152 | [[self.xpcServiceConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError)
153 | {
154 | //err msg
155 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to execute 'updatePreferences' method on launch daemon (error: %@)", proxyError]);
156 |
157 | }] updatePreferences:preferences];
158 |
159 | return;
160 | }
161 |
162 | @end
163 |
--------------------------------------------------------------------------------
/loginItem/loginItem/Camera.m:
--------------------------------------------------------------------------------
1 | //
2 | // Camera.m
3 | // loginItem
4 | //
5 | // Created by Patrick Wardle on 9/1/18.
6 | // Copyright © 2018 Objective-See. All rights reserved.
7 | //
8 |
9 | #import "Camera.h"
10 | #import "Logging.h"
11 |
12 |
13 |
14 | @implementation Camera
15 |
16 | @synthesize session;
17 |
18 | //configure
19 | -(BOOL)configure
20 | {
21 | //flag
22 | BOOL configured = NO;
23 |
24 | //device
25 | AVCaptureDevice* device = nil;
26 |
27 | //input
28 | AVCaptureInput* input = nil;
29 |
30 | //output
31 | AVCaptureStillImageOutput* output = nil;
32 |
33 | //find default camera
34 | device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
35 | if(nil == device)
36 | {
37 | //err msg
38 | logMsg(LOG_ERR, @"failed to find camera for capture");
39 |
40 | //bail
41 | goto bail;
42 | }
43 |
44 | //init input from camera
45 | input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
46 | if(nil == input)
47 | {
48 | //err msg
49 | logMsg(LOG_ERR, @"failed to find input from camera");
50 |
51 | //bail
52 | goto bail;
53 | }
54 |
55 | //init session
56 | self.session = [[AVCaptureSession alloc] init];
57 |
58 | //check if input can be added to session
59 | if(YES != [self.session canAddInput:input])
60 | {
61 | //err msg
62 | logMsg(LOG_ERR, @"cannot add input to session");
63 |
64 | //bail
65 | goto bail;
66 | }
67 |
68 | //add input
69 | [self.session addInput:input];
70 |
71 | //init output
72 | output = [[AVCaptureStillImageOutput alloc] init];
73 |
74 | //set output settings (jpeg)
75 | output.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
76 |
77 | //check if output can be added to session
78 | if(YES != [self.session canAddOutput:output])
79 | {
80 | //err msg
81 | logMsg(LOG_ERR, @"cannot add output to session");
82 |
83 | //bail
84 | goto bail;
85 | }
86 |
87 | //add output
88 | [self.session addOutput:output];
89 |
90 | //happy
91 | configured = YES;
92 |
93 | bail:
94 |
95 | return configured;
96 | }
97 |
98 | //capture an image from the webcam
99 | -(NSData*)captureImage
100 | {
101 | //image
102 | __block NSData* image = nil;
103 |
104 | //output
105 | __block AVCaptureStillImageOutput* output = nil;
106 |
107 | //wait semaphore
108 | dispatch_semaphore_t semaphore = 0;
109 |
110 | //init sema
111 | semaphore = dispatch_semaphore_create(0);
112 |
113 | //configure/init session
114 | if(YES == [self configure])
115 | {
116 | //dbg msg
117 | logMsg(LOG_DEBUG, @"configured camera for capture");
118 |
119 | //start
120 | [self.session startRunning];
121 |
122 | //give session some time to start
123 | // could use KVO, etc, but this seems like a pain
124 | // see: https://stackoverflow.com/questions/27260697/avcapturedevice-adjustingexposure-is-false-but-captured-image-is-dark
125 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
126 |
127 | //grab output
128 | output = self.session.outputs.firstObject;
129 |
130 | //capture image
131 | [output captureStillImageAsynchronouslyFromConnection:[output connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error)
132 | {
133 | //covert image
134 | if( (nil == error) &&
135 | (NULL != imageDataSampleBuffer))
136 | {
137 | //dbg msg
138 | logMsg(LOG_DEBUG, @"captured image");
139 |
140 | //covert
141 | image = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
142 | }
143 |
144 | //error
145 | else
146 | {
147 | //err msg
148 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to capture image (%@)", error]);
149 | }
150 |
151 | //(always) signal sema
152 | dispatch_semaphore_signal(semaphore);
153 |
154 | }];
155 |
156 | });
157 |
158 | //wait for install to be completed by XPC
159 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
160 |
161 | //stop session
162 | if(YES == self.session.isRunning)
163 | {
164 | //stop
165 | [self.session stopRunning];
166 | }
167 | }
168 |
169 | //failed to init session
170 | else
171 | {
172 | //err msg
173 | logMsg(LOG_ERR, @"failed to initialize/configure camera capture session");
174 |
175 | //bail
176 | goto bail;
177 | }
178 |
179 | bail:
180 |
181 | return image;
182 | }
183 |
184 | @end
185 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/monitor/ThunderboltMonitor.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: ThunderboltMonitor.m
3 | // project: DND (launch daemon)
4 | // description: thunderbolt device monitor
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import
11 |
12 | #import "Consts.h"
13 | #import "Logging.h"
14 | #import "ThunderboltMonitor.h"
15 |
16 | @implementation ThunderboltMonitor
17 |
18 | @synthesize runLoopSource;
19 | @synthesize notificationPort;
20 |
21 | //TODO: buy thunderbolt device to test more!
22 |
23 | //callback for thunderbolt devices
24 | void tbDeviceAppeared(void *refCon, io_iterator_t iterator)
25 | {
26 | //dbg msg
27 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"monitor event: thunderbolt device inserted"]);
28 |
29 | //process new device
30 | [(__bridge ThunderboltMonitor *)refCon handleNewDevice:iterator];
31 |
32 | return;
33 | }
34 |
35 | //start thunderbolt monitoring
36 | // also record all existing connected devices
37 | -(BOOL)start
38 | {
39 | //status
40 | BOOL initialized = NO;
41 |
42 | //status
43 | kern_return_t status = kIOReturnError;
44 |
45 | //iterator
46 | io_iterator_t iterator = 0;
47 |
48 | //device
49 | io_service_t device = 0;
50 |
51 | //create notification port
52 | self.notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
53 |
54 | //get run loop source
55 | self.runLoopSource = IONotificationPortGetRunLoopSource(self.notificationPort);
56 |
57 | //add source
58 | CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopDefaultMode);
59 |
60 | //add notification
61 | // pass in 'self' so can access obj-c methods in callbacks
62 | status = IOServiceAddMatchingNotification(self.notificationPort, kIOMatchedNotification, IOServiceMatching("IOThunderboltPort"), tbDeviceAppeared,(__bridge void *)self, &iterator);
63 | if(kIOReturnSuccess != status)
64 | {
65 | //err
66 | logMsg(LOG_ERR, [NSString stringWithFormat:@"IOServiceAddMatchingNotification() failed with %d", status]);
67 |
68 | //bail
69 | goto bail;
70 | }
71 |
72 | //process existing devices
73 | // also 'drains' interator...
74 | device = IOIteratorNext(iterator);
75 | while(0 != device)
76 | {
77 | //record device name/properties
78 | [self logDeviceProperties:device];
79 |
80 | //release
81 | IOObjectRelease(device);
82 |
83 | //get next
84 | device = IOIteratorNext(iterator);
85 | }
86 |
87 | //happy
88 | initialized = YES;
89 |
90 | bail:
91 |
92 | return initialized;
93 | }
94 |
95 | //stop
96 | // invalidate runloop src and notification port
97 | -(void)stop
98 | {
99 | //invalidate runloop src
100 | if(nil != self.runLoopSource)
101 | {
102 | //invalidate
103 | CFRunLoopSourceInvalidate(self.runLoopSource);
104 |
105 | //unset
106 | self.runLoopSource = nil;
107 | }
108 |
109 | //destroy notification port
110 | if(nil != self.notificationPort)
111 | {
112 | //destroy
113 | IONotificationPortDestroy(self.notificationPort);
114 |
115 | //unset
116 | self.notificationPort = nil;
117 | }
118 |
119 | return;
120 | }
121 |
122 | //process new thunerbolt (PCI) insertion
123 | // get info about device (name/properties) and log
124 | -(void)handleNewDevice:(io_iterator_t)iterator
125 | {
126 | //usb device
127 | io_service_t device = 0;
128 |
129 | //process
130 | while((device = IOIteratorNext(iterator)))
131 | {
132 | //log msg
133 | logMsg(LOG_TO_FILE, [NSString stringWithFormat:@"monitor event: thunderbolt device inserted"]);
134 |
135 | //record device name/properties
136 | [self logDeviceProperties:device];
137 |
138 | //release device
139 | IOObjectRelease(device);
140 |
141 | //unset
142 | device = 0;
143 | }
144 |
145 | return;
146 | }
147 |
148 | //log name/properties of a device
149 | -(void)logDeviceProperties:(io_service_t)device
150 | {
151 | //device name
152 | io_name_t deviceName = {0};
153 |
154 | //device properties
155 | CFMutableDictionaryRef deviceProperties = NULL;
156 |
157 | //get device name
158 | if(KERN_SUCCESS == IORegistryEntryGetName(device, deviceName))
159 | {
160 | //dbg msg & log
161 | logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"thunderbolt device name: %s", deviceName]);
162 | }
163 |
164 | //get device properties
165 | if( (kIOReturnSuccess == IORegistryEntryCreateCFProperties(device, &deviceProperties, kCFAllocatorDefault, kNilOptions)) &&
166 | (NULL != deviceProperties) )
167 | {
168 | //dbg msg & log
169 | logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"thunderbolt device properties: %@", deviceProperties]);
170 | }
171 |
172 | //release device props
173 | if(NULL != deviceProperties)
174 | {
175 | //release
176 | CFRelease(deviceProperties);
177 |
178 | //unset
179 | deviceProperties = NULL;
180 | }
181 |
182 | return;
183 | }
184 |
185 | @end
186 |
--------------------------------------------------------------------------------
/loginItem/loginItem/3rdParty/HyperlinkTextField.m:
--------------------------------------------------------------------------------
1 | //
2 | // HyperlinkTextField.m
3 | // NSTextFieldHyperlinks
4 | //
5 | // Created by Toomas Vahter on 25.12.12.
6 | // Copyright (c) 2012 Toomas Vahter. All rights reserved.
7 | //
8 | // This content is released under the MIT License (http://www.opensource.org/licenses/mit-license.php).
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 |
28 | #import "HyperlinkTextField.h"
29 |
30 | @interface HyperlinkTextField ()
31 | @property (nonatomic, readonly) NSArray *hyperlinkInfos;
32 |
33 |
34 | - (void)_resetHyperlinkCursorRects;
35 | @end
36 |
37 | #define kHyperlinkInfoCharacterRangeKey @"range"
38 | #define kHyperlinkInfoURLKey @"url"
39 | #define kHyperlinkInfoRectKey @"rect"
40 |
41 | @implementation HyperlinkTextField
42 |
43 | @synthesize textView;
44 |
45 | - (void)_hyperlinkTextFieldInit
46 | {
47 | [self setEditable:NO];
48 | [self setSelectable:NO];
49 | }
50 |
51 |
52 | - (id)initWithFrame:(NSRect)frame
53 | {
54 | if ((self = [super initWithFrame:frame]))
55 | {
56 | [self _hyperlinkTextFieldInit];
57 | }
58 |
59 | return self;
60 | }
61 |
62 |
63 | - (id)initWithCoder:(NSCoder *)coder
64 | {
65 | if ((self = [super initWithCoder:coder]))
66 | {
67 | [self _hyperlinkTextFieldInit];
68 | }
69 |
70 | return self;
71 | }
72 |
73 |
74 | - (void)resetCursorRects
75 | {
76 | [super resetCursorRects];
77 | [self _resetHyperlinkCursorRects];
78 | }
79 |
80 |
81 | - (void)_resetHyperlinkCursorRects
82 | {
83 | for (NSDictionary *info in self.hyperlinkInfos)
84 | {
85 | [self addCursorRect:[[info objectForKey:kHyperlinkInfoRectKey] rectValue] cursor:[NSCursor pointingHandCursor]];
86 | }
87 | }
88 |
89 |
90 | #pragma mark -
91 | #pragma mark Accessors
92 |
93 | - (NSArray *)hyperlinkInfos
94 | {
95 | NSMutableArray *hyperlinkInfos = [[NSMutableArray alloc] init];
96 | NSRange stringRange = NSMakeRange(0, [self.attributedStringValue length]);
97 | __block NSTextView *tView = self.textView;
98 | [self.attributedStringValue enumerateAttribute:NSLinkAttributeName inRange:stringRange options:0 usingBlock:^(id value, NSRange range, BOOL *stop)
99 | {
100 | if (value)
101 | {
102 | NSUInteger rectCount = 0;
103 | NSRectArray rectArray = [tView.layoutManager rectArrayForCharacterRange:range withinSelectedCharacterRange:range inTextContainer:tView.textContainer rectCount:&rectCount];
104 | for (NSUInteger i = 0; i < rectCount; i++)
105 | {
106 | [hyperlinkInfos addObject:@{kHyperlinkInfoCharacterRangeKey : [NSValue valueWithRange:range], kHyperlinkInfoURLKey : value, kHyperlinkInfoRectKey : [NSValue valueWithRect:rectArray[i]]}];
107 | }
108 | }
109 | }];
110 |
111 | return [hyperlinkInfos count] ? hyperlinkInfos : nil;
112 | }
113 |
114 |
115 | - (NSTextView *)textView
116 | {
117 | // Font used for displaying and frame calculations must match
118 | NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedStringValue];
119 | NSFont *font = [attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL];
120 |
121 | if (!font)
122 | [attributedString addAttribute:NSFontAttributeName value:self.font range:NSMakeRange(0, [attributedString length])];
123 |
124 | NSRect textViewFrame = [self.cell titleRectForBounds:self.bounds];
125 | NSTextView *tView = [[NSTextView alloc] initWithFrame:textViewFrame];
126 | [tView.textStorage setAttributedString:attributedString];
127 |
128 | return tView;
129 | }
130 |
131 |
132 | #pragma mark -
133 | #pragma mark Mouse Events
134 |
135 | - (void)mouseUp:(NSEvent *)theEvent
136 | {
137 | NSTextView *tView = self.textView;
138 | NSPoint localPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
139 | NSUInteger index = [tView.layoutManager characterIndexForPoint:localPoint inTextContainer:tView.textContainer fractionOfDistanceBetweenInsertionPoints:NULL];
140 |
141 | if (index != NSNotFound)
142 | {
143 | for (NSDictionary *info in self.hyperlinkInfos)
144 | {
145 | NSRange range = [[info objectForKey:kHyperlinkInfoCharacterRangeKey] rangeValue];
146 | if (NSLocationInRange(index, range))
147 | {
148 | NSURL *url = [info objectForKey:kHyperlinkInfoURLKey];
149 | [[NSWorkspace sharedWorkspace] openURL:url];
150 | }
151 | }
152 | }
153 | }
154 |
155 | @end
156 |
--------------------------------------------------------------------------------
/configure/configure.xcodeproj/xcshareddata/xcschemes/configure.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
57 |
63 |
64 |
65 |
66 |
67 |
72 |
73 |
74 |
75 |
81 |
82 |
83 |
84 |
85 |
86 |
96 |
98 |
104 |
105 |
106 |
107 |
108 |
109 |
115 |
116 |
122 |
123 |
124 |
125 |
127 |
128 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/mainApp/mainApp/3rdParty/HyperlinkTextField.m:
--------------------------------------------------------------------------------
1 | //
2 | // HyperlinkTextField.m
3 | // NSTextFieldHyperlinks
4 | //
5 | // Created by Toomas Vahter on 25.12.12.
6 | // Copyright (c) 2012 Toomas Vahter. All rights reserved.
7 | //
8 | // This content is released under the MIT License (http://www.opensource.org/licenses/mit-license.php).
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 |
28 | #import "HyperlinkTextField.h"
29 |
30 | @interface HyperlinkTextField ()
31 | @property (nonatomic, readonly) NSArray *hyperlinkInfos;
32 | @property (nonatomic, readonly) NSTextView *textView;
33 |
34 | - (void)_resetHyperlinkCursorRects;
35 | @end
36 |
37 | #define kHyperlinkInfoCharacterRangeKey @"range"
38 | #define kHyperlinkInfoURLKey @"url"
39 | #define kHyperlinkInfoRectKey @"rect"
40 |
41 | @implementation HyperlinkTextField
42 |
43 | - (void)_hyperlinkTextFieldInit
44 | {
45 | [self setEditable:NO];
46 | [self setSelectable:NO];
47 | }
48 |
49 |
50 | - (id)initWithFrame:(NSRect)frame
51 | {
52 | if ((self = [super initWithFrame:frame]))
53 | {
54 | [self _hyperlinkTextFieldInit];
55 | }
56 |
57 | return self;
58 | }
59 |
60 |
61 | - (id)initWithCoder:(NSCoder *)coder
62 | {
63 | if ((self = [super initWithCoder:coder]))
64 | {
65 | [self _hyperlinkTextFieldInit];
66 | }
67 |
68 | return self;
69 | }
70 |
71 |
72 | - (void)resetCursorRects
73 | {
74 | [super resetCursorRects];
75 | [self _resetHyperlinkCursorRects];
76 | }
77 |
78 |
79 | - (void)_resetHyperlinkCursorRects
80 | {
81 | for (NSDictionary *info in self.hyperlinkInfos)
82 | {
83 | [self addCursorRect:[[info objectForKey:kHyperlinkInfoRectKey] rectValue] cursor:[NSCursor pointingHandCursor]];
84 | }
85 | }
86 |
87 |
88 | #pragma mark -
89 | #pragma mark Accessors
90 |
91 | - (NSArray *)hyperlinkInfos
92 | {
93 | NSMutableArray *hyperlinkInfos = [[NSMutableArray alloc] init];
94 | NSRange stringRange = NSMakeRange(0, [self.attributedStringValue length]);
95 | __block NSTextView *textView = self.textView;
96 | [self.attributedStringValue enumerateAttribute:NSLinkAttributeName inRange:stringRange options:0 usingBlock:^(id value, NSRange range, BOOL *stop)
97 | {
98 | if (value)
99 | {
100 | NSUInteger rectCount = 0;
101 | NSRectArray rectArray = [textView.layoutManager rectArrayForCharacterRange:range withinSelectedCharacterRange:range inTextContainer:textView.textContainer rectCount:&rectCount];
102 | for (NSUInteger i = 0; i < rectCount; i++)
103 | {
104 | [hyperlinkInfos addObject:@{kHyperlinkInfoCharacterRangeKey : [NSValue valueWithRange:range], kHyperlinkInfoURLKey : value, kHyperlinkInfoRectKey : [NSValue valueWithRect:rectArray[i]]}];
105 | }
106 | }
107 | }];
108 |
109 | return [hyperlinkInfos count] ? hyperlinkInfos : nil;
110 | }
111 |
112 |
113 | - (NSTextView *)textView
114 | {
115 | // Font used for displaying and frame calculations must match
116 | NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedStringValue];
117 | NSFont *font = [attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL];
118 |
119 | if (!font)
120 | [attributedString addAttribute:NSFontAttributeName value:self.font range:NSMakeRange(0, [attributedString length])];
121 |
122 | NSRect textViewFrame = [self.cell titleRectForBounds:self.bounds];
123 | NSTextView *textView = [[NSTextView alloc] initWithFrame:textViewFrame];
124 | [textView.textStorage setAttributedString:attributedString];
125 |
126 | return textView;
127 | }
128 |
129 |
130 | #pragma mark -
131 | #pragma mark Mouse Events
132 |
133 | - (void)mouseUp:(NSEvent *)theEvent
134 | {
135 | NSTextView *textView = self.textView;
136 | NSPoint localPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
137 | NSUInteger index = [textView.layoutManager characterIndexForPoint:localPoint inTextContainer:textView.textContainer fractionOfDistanceBetweenInsertionPoints:NULL];
138 |
139 | if (index != NSNotFound)
140 | {
141 | for (NSDictionary *info in self.hyperlinkInfos)
142 | {
143 | NSRange range = [[info objectForKey:kHyperlinkInfoCharacterRangeKey] rangeValue];
144 | if (NSLocationInRange(index, range))
145 | {
146 | NSURL *url = [info objectForKey:kHyperlinkInfoURLKey];
147 | [[NSWorkspace sharedWorkspace] openURL:url];
148 | }
149 | }
150 | }
151 | }
152 |
153 | @end
154 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/FrameworkInterface.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: FrameworkInterface.m
3 | // project: DND (launch daemon)
4 | // description: interface to Digita Security's (swift) framework
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Logging.h"
12 | #import "Preferences.h"
13 | #import "FrameworkInterface.h"
14 |
15 | //global prefs obj
16 | extern Preferences* preferences;
17 |
18 | @implementation FrameworkInterface
19 |
20 | @synthesize identity;
21 |
22 | //initialize an identity for DND comms
23 | // generates client id, etc. and then creates identity
24 | -(BOOL)initIdentity:(BOOL)full
25 | {
26 | //flag
27 | BOOL initialized = NO;
28 |
29 | //path to digita CA
30 | NSString* digitaCAPath = nil;
31 |
32 | //path to csr
33 | NSString* csrPath = nil;
34 |
35 | //path to aws CA
36 | NSString* awsCAPath = nil;
37 |
38 | //client ID
39 | NSString* clientID = nil;
40 |
41 | //error
42 | NSError *error = nil;
43 |
44 | //csr identity
45 | DNDIdentity *csrIdentity = nil;
46 |
47 | //csr client
48 | DNDClientCsr *csrClient = nil;
49 |
50 | //current preferences
51 | NSDictionary* currentPrefs = nil;
52 |
53 | //dbg msg
54 | logMsg(LOG_DEBUG, @"initializing DND identity");
55 |
56 | //get all current prefs
57 | currentPrefs = [preferences get:nil];
58 |
59 | //init digita CA path
60 | digitaCAPath = [[NSBundle mainBundle] pathForResource:@"rootCA" ofType:@"pem"];
61 | if(nil == digitaCAPath)
62 | {
63 | //err msg
64 | logMsg(LOG_ERR, @"failed to locate Digita's CA path");
65 |
66 | //bail
67 | goto bail;
68 | }
69 |
70 | //init csr path
71 | csrPath = [[NSBundle mainBundle] pathForResource:@"deviceCSRRequest" ofType:@"p12"];
72 | if(nil == csrPath)
73 | {
74 | //err msg
75 | logMsg(LOG_ERR, @"failed to locate CSR path");
76 |
77 | //bail
78 | goto bail;
79 | }
80 |
81 | //init AWS CA path
82 | awsCAPath = [[NSBundle mainBundle] pathForResource:@"awsRootCA" ofType:@"pem"];
83 | if(nil == awsCAPath)
84 | {
85 | //err msg
86 | logMsg(LOG_ERR, @"failed to locate AWS CA path");
87 |
88 | //bail
89 | goto bail;
90 | }
91 |
92 | //try load client id
93 | clientID = currentPrefs[PREF_CLIENT_ID];
94 |
95 | //already have client id
96 | // go ahead and try to init identity here
97 | if(nil != clientID)
98 | {
99 | //dbg msg
100 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"using existing client id: %@", clientID]);
101 |
102 | //init
103 | self.identity = [[DNDIdentity alloc] init:clientID caPath:digitaCAPath error:&error];
104 | }
105 |
106 | //when not doing full init
107 | // if we don't have an identify here, bail
108 | if( (YES != full) &&
109 | (self.identity == nil) )
110 | {
111 | //err msg
112 | logMsg(LOG_ERR, @"failed to init *existing* DND identity (full init: false)");
113 |
114 | //bail
115 | goto bail;
116 | }
117 |
118 | //no client id
119 | // or (still) need to create identity
120 | if( (nil == clientID) ||
121 | (nil == self.identity) )
122 | {
123 | //generate
124 | clientID = [[[NSUUID UUID] UUIDString] lowercaseString];
125 |
126 | //alloc init csr identity
127 | csrIdentity = [[DNDIdentity alloc] init:[[NSUUID UUID] UUIDString] p12Path:csrPath passphrase:CSR_PASSPHRASE caPath:awsCAPath error:&error];
128 | if( (nil == csrIdentity) ||
129 | (nil != error) )
130 | {
131 | //err msg
132 | logMsg(LOG_ERR, @"failed to get/create CSR identity");
133 |
134 | //bail
135 | goto bail;
136 | }
137 |
138 | //alloc/init csr client
139 | csrClient = [[DNDClientCsr alloc] initWithDndIdentity:csrIdentity sendCA:NO background:YES taskable:NO];
140 | if(nil == csrClient)
141 | {
142 | //err msg
143 | logMsg(LOG_ERR, @"failed to get/create CSR client");
144 |
145 | //bail
146 | goto bail;
147 | }
148 |
149 | //get (or create) dnd identity
150 | identity = [csrClient getOrCreateIdentity:clientID caPath:digitaCAPath];
151 | if(nil == self.identity)
152 | {
153 | //err msg
154 | logMsg(LOG_ERR, @"failed to get/create DND identity");
155 |
156 | //bail
157 | goto bail;
158 | }
159 |
160 | //save client ID
161 | // also used as indicator that identity was generated
162 | if(nil == currentPrefs[PREF_CLIENT_ID])
163 | {
164 | //save
165 | [preferences update:@{PREF_CLIENT_ID:clientID}];
166 | }
167 | }
168 |
169 | //happy
170 | initialized = YES;
171 |
172 | bail:
173 |
174 | //don't need csr id anymore
175 | if(nil != csrIdentity)
176 | {
177 | //delete
178 | if(YES != [csrIdentity deleteIdentityWithDeleteAssociatedCA:YES])
179 | {
180 | //err msg
181 | logMsg(LOG_ERR, @"failed to delete CSR identity");
182 | }
183 | //deleted ok
184 | else
185 | {
186 | //dbg msg
187 | logMsg(LOG_DEBUG, @"deleted CSR identity");
188 | }
189 |
190 | //unset
191 | csrIdentity = nil;
192 | }
193 |
194 | return initialized;
195 | }
196 |
197 | @end
198 |
--------------------------------------------------------------------------------
/launchDaemon/launchDaemon/XPCListener.m:
--------------------------------------------------------------------------------
1 | //
2 | // file: XPCListener.h
3 | // project: DND (launch daemon)
4 | // description: XPC listener for connections from user components
5 | //
6 | // created by Patrick Wardle
7 | // copyright (c) 2018 Objective-See. All rights reserved.
8 | //
9 |
10 | #import "Consts.h"
11 | #import "Logging.h"
12 | #import "Utilities.h"
13 | #import "XPCDaemon.h"
14 | #import "XPCListener.h"
15 | #import "XPCUSERProto.h"
16 | #import "XPCDaemonProto.h"
17 |
18 | //signing auth
19 | #define SIGNING_AUTH @"Developer ID Application: Objective-See, LLC (VBG97UB4TA)"
20 |
21 | //interface for 'extension' to NSXPCConnection
22 | // allows us to access the 'private' auditToken iVar
23 | @interface ExtendedNSXPCConnection : NSXPCConnection
24 | {
25 | //private iVar
26 | audit_token_t auditToken;
27 | }
28 | //private iVar
29 | @property audit_token_t auditToken;
30 |
31 | @end
32 |
33 | //implementation for 'extension' to NSXPCConnection
34 | // allows us to access the 'private' auditToken iVar
35 | @implementation ExtendedNSXPCConnection
36 |
37 | //private iVar
38 | @synthesize auditToken;
39 |
40 | @end
41 |
42 | //function
43 | OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
44 |
45 | @implementation XPCListener
46 |
47 | @synthesize listener;
48 |
49 | //init
50 | // create XPC listener
51 | -(id)init
52 | {
53 | //init super
54 | self = [super init];
55 | if(nil != self)
56 | {
57 | //setup XPC listener
58 | if(YES != [self initListener])
59 | {
60 | //unset
61 | self = nil;
62 |
63 | //bail
64 | goto bail;
65 | }
66 | }
67 |
68 | bail:
69 |
70 | return self;
71 | }
72 |
73 | //setup XPC listener
74 | -(BOOL)initListener
75 | {
76 | //result
77 | BOOL result = NO;
78 |
79 | //init listener
80 | listener = [[NSXPCListener alloc] initWithMachServiceName:DAEMON_MACH_SERVICE];
81 | if(nil == self.listener)
82 | {
83 | //err msg
84 | logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to create mach service %@", DAEMON_MACH_SERVICE]);
85 |
86 | //bail
87 | goto bail;
88 | }
89 |
90 | //dbg msg
91 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"created mach service %@", DAEMON_MACH_SERVICE]);
92 |
93 | //set delegate
94 | self.listener.delegate = self;
95 |
96 | //ready to accept connections
97 | [self.listener resume];
98 |
99 | //happy
100 | result = YES;
101 |
102 | bail:
103 |
104 | return result;
105 | }
106 |
107 | #pragma mark -
108 | #pragma mark NSXPCConnection method overrides
109 |
110 | //automatically invoked
111 | // allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection
112 | // note: we only allow binaries signed by Objective-See to talk to this!
113 | -(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
114 | {
115 | //flag
116 | BOOL shouldAccept = NO;
117 |
118 | //task ref
119 | SecTaskRef taskRef = 0;
120 |
121 | //signing req string
122 | NSString* requirementString = nil;
123 |
124 | //path of connecting app
125 | NSString* path = nil;
126 |
127 | //dbg msg
128 | logMsg(LOG_DEBUG, @"received request to connect to XPC interface");
129 |
130 | //init signing req string
131 | requirementString = [NSString stringWithFormat:@"anchor trusted and certificate leaf [subject.CN] = \"%@\"", SIGNING_AUTH];
132 |
133 | //step 1: create task ref
134 | // uses NSXPCConnection's (private) 'auditToken' iVar
135 | taskRef = SecTaskCreateWithAuditToken(NULL, ((ExtendedNSXPCConnection*)newConnection).auditToken);
136 | if(NULL == taskRef)
137 | {
138 | //bail
139 | goto bail;
140 | }
141 |
142 | //step 2: validate
143 | // check that client is signed with Objective-See's dev cert
144 | if(0 != SecTaskValidateForRequirement(taskRef, (__bridge CFStringRef)(requirementString)))
145 | {
146 | //bail
147 | goto bail;
148 | }
149 |
150 | //set the interface that the exported object implements
151 | newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCDaemonProtocol)];
152 |
153 | //set object exported by connection
154 | newConnection.exportedObject = [[XPCDaemon alloc] init];
155 |
156 | //set type of remote object
157 | // user (login item/main app) will set this object
158 | newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol: @protocol(XPCUserProtocol)];
159 |
160 | //get path
161 | path = getProcessPath(newConnection.processIdentifier);
162 |
163 | //login item
164 | // save connection and notify that new client has connected
165 | if(YES == [path hasSuffix:LOGIN_ITEM_NAME])
166 | {
167 | //save
168 | self.loginItem = newConnection;
169 |
170 | //in background
171 | // notify that a new client connected
172 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
173 | ^{
174 | //notify
175 | [[NSNotificationCenter defaultCenter] postNotificationName:USER_NOTIFICATION object:nil userInfo:nil];
176 | });
177 | }
178 | //main app
179 | else
180 | {
181 | //save
182 | self.mainApp = newConnection;
183 | }
184 |
185 | //resume
186 | [newConnection resume];
187 |
188 | //dbg msg
189 | logMsg(LOG_DEBUG, [NSString stringWithFormat:@"allowed XPC connection from %@", path]);
190 |
191 | //happy
192 | shouldAccept = YES;
193 |
194 | bail:
195 |
196 | //release task ref object
197 | if(NULL != taskRef)
198 | {
199 | //release
200 | CFRelease(taskRef);
201 |
202 | //unset
203 | taskRef = NULL;
204 | }
205 |
206 | return shouldAccept;
207 | }
208 |
209 | @end
210 |
--------------------------------------------------------------------------------