├── 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 | 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 | 44 | 45 | 46 | 47 | 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 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 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 | --------------------------------------------------------------------------------