Thursday, October 26, 2017

Use binding as an alternative to passing state around in Clojure

Let's say we have already existing functions (referred to as inner functions) called by another function (outer function) and the inner functions needs some state data so that when exception occurs, that data can be logged. However, this requires passing state around to all these inner functions and modifying the method signature. Which is fine, but depending on the taste, it might not look elegant. There is another way where the state can be bound using binding and does not have to be passed explicitly by the caller. Example follows.
(declare ^:dynamic state)

(defn err []
; does many other things
(println state)
; .. return response
)

(defn process []
(binding [state 1]
(err) ; 1
(set! state 2) ; update value of state
(err))) ; 2

(process)

; output
; 1
; 2
; nil
This however is an anti-pattern as the state var is being implicit to the function, but used wisely, it is an anti-anti-pattern.

Wednesday, October 25, 2017

Unbind Active Directory from OS X

When your enterprise uses Active Directory for identity management, the OS X user account by default will be bound to the AD service. The convenience it brings is that we can change the AD account password by changing the OS X user account password and all services like WiFi, printer authentication will be updated as it will update the keychain as well. If the OS X user account is not bounded, we will have to manually remove/update the necessary cached service password from keychain each time. However, it is problem that the AD will get information on local OS X account activity and will get synced when connected to the internal network. You cannot be a ghost then. Now comes the unbinding part.
1. Check current AD settings
sudo dsconfigad -show
If bounded, it will print something like,
Active Directory Domain          = stalker.weird.org
Computer Account = xxx

Advanced Options - User Experience
Create mobile account at login = Enabled|Disabled
Require confirmation = Enabled|Disabled
Force home to startup disk = Enabled|Disabled
Mount home as sharepoint = Enabled|Disabled
Use Windows UNC path for home = Enabled|Disabled
Network protocol to be used = smb
Default user Shell = /bin/bash

Advanced Options - Mappings
Mapping UID to attribute = xxx
Mapping user GID to attribute = xxx
Mapping group GID to attribute = xxx
Generate Kerberos authority = Enabled|Disabled

Advanced Options - Administrative
Preferred Domain controller = xxx
Allowed admin groups = xxx
Authentication from any domain = Enabled|Disabled
Packet signing = xxx
Packet encryption = xxx
Password change interval = 000
Restrict Dynamic DNS updates = xxx
Namespace mode = xxx
2. Install Enterprise Connect app from Apple that will help us to easily reconnect and change AD password. The org IT must support it. You won't find it in the App store.
3. Unbind AD.
dsconfigad -f -r -u <ad_username>
This above command will unbind the OS X user account from the AD server. Check if AD service is active by running the command in step 1 again. It should print nothing.
4. Next if we need to bind to AD, use Enterprise Connect -> Reconnect -> Change Password. Which is easy way. Else we can use dsconfigad utility to do the binding.

Enjoy stealth mode.

Monday, October 23, 2017

Data Flow Pipeline in Clojure

Error handling in Clojure requires some serious thought. There are many ways. Some gets the argument that it looks less functional, especially using exceptions as the basic mechanism to handle errors since it give a Java feel to the code. Monads and short circuiting (either monad, error monad, etc.) is also popular among functional programming practitioners. However, I hate monads with passion, apparently for no reason. Well, because it is a workaround to the purely typed functional programming languages like Haskell to handle state, side effects, compose, chain, which they brought upon themselves. Clojure being Lisp and Lisp being awesome, we really does not require all these complications. I have been thinking about core.async channels as a way to build data flow pipeline and handle errors, but it does not map very well, when in comparison with Erlang, its processes, supervisors and such. Modelling Erlang kind of systems on JVM without green threads and non-os scheduler is super hard, and less performant. It's all in the VM.

Now to the point. There is a very simple way to build data flow pipeline and handle errors by short circuiting and still keeping it elegant. The build blocks are reduce and reduction. And specifically, it is the reduction function that helps to break the recursion if error occurs. Example code follows.
;; pipeline.clj

#!/usr/bin/env boot

(defn deps [new-deps]
(merge-env! :dependencies new-deps))

(deps '[[org.clojure/clojure "1.8.0"]])

(defn validate-true [x]
(println "validate-true")
{:status true :state {:id 123 :foo "bar"}})

(defn validate-false [x]
(println "validate-false")
{:status false :code 1 :msg "anti gravity"})

(defn validate-false-1 [x]
(println "validate-false")
{:status false :code 1 :msg "heisenbug"})

(defn pipeline [fns]
(reduce (fn [x fun]
(if (:status x)
(fun (:state x))
(reduced x)))
{:status true}
fns))

(println "pipeline 0")
(println (pipeline [validate-false validate-true validate-false validate-true validate-true]))

(println "\npipeline 1")
(println (pipeline [validate-true validate-false-1 validate-true validate-false validate-true]))

(println "\npipeline 2")
(println (pipeline [validate-true validate-true validate-false validate-true validate-true]))

(println "\npipeline")
(println (pipeline [validate-true validate-true validate-true]))
# output
pipeline 0
validate-false
{:status false, :code 1, :msg anti gravity}

pipeline 1
validate-true
validate-false
{:status false, :code 1, :msg heisenbug}

pipeline 2
validate-true
validate-true
validate-false
{:status false, :code 1, :msg anti gravity}

pipeline
validate-true
validate-true
validate-true
{:status true}
# boot.properties
#https://github.com/boot-clj/boot
BOOT_CLOJURE_NAME=org.clojure/clojure
BOOT_VERSION=2.7.1
BOOT_CLOJURE_VERSION=1.8.0
The pipeline accepts a list of functions and chains them together. Each reduction can pass in the required arguments necessary for the next function in the chain. These functions must be composable to make this work. The reduced function checks for a recursion termination condition apart from the reduction termination. When the condition which is the {:status false ..} is met, it short circuits the evaluation and exits the recursion, returning the value of the computation. This value can then be matched and responded accordingly. In case of web app, a suitable ring response can be generated. Simple!

The pipeline can be modified to accept a collection of [ok-fn err-fn] so that instead of having a generic one error handler, we can have two different paths and localised handling of errors.
(defn pipeline [fns]
(reduce (fn [x fun]
(if (:status x)
(if (= (type fun) clojure.lang.PersistentVector) (((first fun) (:state x))) (fun (:state x)))
(if (= (type fun) clojure.lang.PersistentVector) (reduced ((second fun) x)) (reduced x))))
{:status true}
fns))
(defn validate-false-s1 [x]
(println "special error handling fun in pipeline")
{:status false :code -1 :msg "nop"})

(println "\npipeline separate flows")
(println (pipeline [validate-true validate-false [validate-true validate-false-s1] validate-true]))
; output
pipeline separate flows
validate-true
validate-false
special error handling fun in pipeline
{:status false, :code -1, :msg nop}

The pipeline is very flexible and can be modified to suite variety of use cases. The contract does not always have to be a map with :status. We can use core.match to do various types of conditional branching.

Update: Using try..catch exceptions are fine. It does not make code any less functional as long as you return values. Plus using functional language does not mean that whole code will be functional. There will be a few parts that are less functional, and that is totally fine. The point here is to be pragmatic. The main use of monad is to sequence code.

Thursday, October 19, 2017

Lock BlackBerry KEYone With Password When Using Fingerprint

BlackBerry KEYone, an advancement from BlackBerry Passport, which however uses Android, an OS not so great when compared to QNX, but still fine given the fact that it can be hardened and there are apps that makes business get done. Getting required apps on BlackBerry 10 is really a pain, no matter how great the device and OS is. Plus developers like me can program KEYone using any of the supported JVM languages instead of banging my head against C/C++, a pain for any functional programmer accustomed to living in the JVM world.

So, now to the point. BlackBerry KEYone has fingerprint sensor on the spacebar. However, we know fingerprint is a security issue. When confiscated, we are legally required to unlock the phone if the finger is still on the hand. But, that is not the case with passwords. There are a lot of defences against providing authorities with your password. So KEYone can lock the device which will then require you to enter the password even if it is configured to unlock using fingerprint. For that, long press the key K, which opens BlackBerry Launcher and initially it asks whether you need to enable the app to administer the device. Allow access and the device will be locked using that keyboard shortcut, which then requires the password to unlock. Rest of the time, unlock using fingerprint. Makes life easier without compromising security. BlackBerry rocks!

Tuesday, October 10, 2017

jamf equals no privacy

jamf is used for managing Apple devices in the enterprise. However it is a nasty little piece of software. It always sends online, offline status to enterprise JSS endpoint. Few excerpts from /var/log/jamf.log.
Tue Oct 03 15:26:03 purgatory jamf[52]: Daemon starting
Tue Oct 03 15:26:05 purgatory jamf[363]:
There was an error.

Connection failure: "The Internet connection appears to be offline."

Tue Oct 03 15:26:06 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:26:06 purgatory jamf[407]: Could not connect to the JSS. Looking for cached policies...
Tue Oct 03 15:26:07 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:26:10 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:26:13 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:26:29 purgatory jamf[52]: Informing the JSS about login for user castiel
Tue Oct 03 15:26:38 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:27:12 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:27:17 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:27:38 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:27:56 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:28:03 purgatory jamf[52]: Network state changed, checking for policies...
Tue Oct 03 15:28:04 purgatory jamf[2573]: Checking for policies triggered by "networkStateChange" for user "castiel"...
Tue Oct 03 15:28:04 purgatory jamf[2356]: Checking for policies triggered by "networkStateChange" for user "castiel"...
Tue Oct 03 15:28:04 purgatory jamf[2087]: Checking for policies triggered by "networkStateChange" for user "castiel"...
Tue Oct 03 15:28:07 purgatory jamf[2573]: Could not connect to the JSS. Looking for cached policies...
Tue Oct 03 15:28:07 purgatory jamf[2087]: Could not connect to the JSS. Looking for cached policies...
***
Wed Oct 04 20:02:06 purgatory jamf[13815]: Checking for policies triggered by "recurring check-in" for user "castiel"...
Wed Oct 04 20:02:10 purgatory jamf[13815]: Could not connect to the JSS. Looking for cached policies...
Wed Oct 04 20:05:33 purgatory jamf[52]: Network state changed, checking for policies...
***
Thu Oct 05 09:26:25 purgatory jamf[99672]: Checking for policies triggered by "networkStateChange"...
Thu Oct 05 10:04:40 purgatory jamf[52]: Informing the JSS about login for user root
***
Sat Oct 07 07:51:30 purgatory jamf[64843]: Checking for policies triggered by "networkStateChange" for user "castiel"...
Sat Oct 07 08:02:52 purgatory jamf[69647]: Checking for policies triggered by "recurring check-in" for user "castiel"...
Sat Oct 07 08:02:55 purgatory jamf[69647]: Executing Policy Enable local firewall
Sat Oct 07 08:02:56 purgatory jamf[69647]: Executing Policy Inventory Daily
Sat Oct 07 08:02:57 purgatory jamf[69647]: Executing Policy Update Username Field in Inventory
Sat Oct 07 08:29:25 purgatory jamf[52]: Network state changed, checking for policies...
Sat Oct 07 08:30:27 purgatory jamf[87635]: Checking for policies triggered by "networkStateChange" for user "castiel"...
Sat Oct 07 08:30:28 purgatory jamf[87262]: Checking for policies triggered by "recurring check-in" for user "castiel"...
Sat Oct 07 08:31:45 purgatory jamf[87635]: Could not connect to the JSS. Looking for cached policies...
Sat Oct 07 08:31:46 purgatory jamf[87262]: Could not connect to the JSS. Looking for cached policies...
Sat Oct 07 08:31:46 purgatory jamf[87262]: Executing Offline Policy Enable local firewall
Sat Oct 07 08:49:57 purgatory jamf[97458]: Checking for policies triggered by "recurring check-in" for user "castiel"...
Sat Oct 07 08:51:15 purgatory jamf[97458]: Could not connect to the JSS. Looking for cached policies...
Sat Oct 07 08:51:15 purgatory jamf[97458]: Executing Offline Policy Enable local firewall
Sat Oct 07 09:09:24 purgatory jamf[8836]: Checking for policies triggered by "recurring check-in" for user "castiel"...
Sat Oct 07 09:10:41 purgatory jamf[8836]: Could not connect to the JSS. Looking for cached policies...
Sat Oct 07 09:10:41 purgatory jamf[8836]: Executing Offline Policy Enable local firewall
***
Mon Oct 09 10:27:46 purgatory jamf[20026]: Checking for policies triggered by "recurring check-in" for user "castiel"...
Mon Oct 09 13:45:26 purgatory jamf[28409]: Checking for policies triggered by "recurring check-in" for user "castiel"...
Mon Oct 09 13:45:29 purgatory jamf[28409]: Executing Policy Inventory Daily
Mon Oct 09 14:16:56 purgatory jamf[28409]: Error running recon: Connection failure: "The request timed out."
Mon Oct 09 14:20:26 purgatory jamf[52]: Daemon shutdown completed
Mon Oct 09 14:20:26 purgatory jamf[52]: Daemon exiting
So every time the jamf infected computer goes online or offline, changed to root etc., the Sauron will be notified about it. More interesting part comes next.

It tracks all applications used by the users and the amount of time spend with it. That treasure is in /Library/Application Support/JAMF/Usage folder. There will be folders like 2017-10-07, 2017-10-08, 2017-10-09. Looking at one of those folders will give logs like (null).plist, idle.plist, castiel.plist, etc.

Let us see what castiel.plist has to offer.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>/Applications/Calendar.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>968</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>58112</string>
<key>version</key>
<string>9.0</string>
</dict>
<key>/Applications/Cisco/Cisco AnyConnect Secure Mobility Client.app</key>
<dict>
<key>foremost</key>
<string>1</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>55</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>4.1.08005</string>
</dict>
<key>/Applications/GIMP.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>2.8.18</string>
</dict>
<key>/Applications/GitHub Desktop.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>Hasty Things Done Hastily</string>
</dict>
<key>/Applications/Google Chrome.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>63.0.3223.8</string>
</dict>
<key>/Applications/Mail.app</key>
<dict>
<key>foremost</key>
<string>2</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>134</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>10.3</string>
</dict>
<key>/Applications/Notes.app</key>
<dict>
<key>foremost</key>
<string>1</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>27</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>4.4</string>
</dict>
<key>/Applications/Photos.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>2.0</string>
</dict>
<key>/Applications/Postman.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>5.2.1</string>
</dict>
<key>/Applications/Preview.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>9.0</string>
</dict>
<key>/Applications/Reminders.app</key>
<dict>
<key>foremost</key>
<string>1</string>
<key>open</key>
<string>54</string>
<key>secondsforemost</key>
<string>31</string>
<key>secondsopen</key>
<string>3272</string>
<key>version</key>
<string>4.0</string>
</dict>
<key>/Applications/Safari Technology Preview.app</key>
<dict>
<key>foremost</key>
<string>65</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>3920</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>11.1</string>
</dict>
<key>/Applications/Slack.app</key>
<dict>
<key>foremost</key>
<string>56</string>
<key>open</key>
<string>1892</string>
<key>secondsforemost</key>
<string>3381</string>
<key>secondsopen</key>
<string>113558</string>
<key>version</key>
<string>2.8.1</string>
</dict>
<key>/Applications/Sublime Text.app</key>
<dict>
<key>foremost</key>
<string>33</string>
<key>open</key>
<string>1662</string>
<key>secondsforemost</key>
<string>2026</string>
<key>secondsopen</key>
<string>99735</string>
<key>version</key>
<string>Build 3143</string>
</dict>
<key>/Applications/Utilities/Keychain Access.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>9.0</string>
</dict>
<key>/Applications/Utilities/Terminal.app</key>
<dict>
<key>foremost</key>
<string>1</string>
<key>open</key>
<string>1908</string>
<key>secondsforemost</key>
<string>9</string>
<key>secondsopen</key>
<string>114527</string>
<key>version</key>
<string>2.7.3</string>
</dict>
<key>/Applications/VLC.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>2.2.6</string>
</dict>
<key>/Applications/[...snip..]Crypt.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>1.xx</string>
</dict>
<key>/Applications/Xcode.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>9.0</string>
</dict>
<key>/Applications/iTunes.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>12.7</string>
</dict>
<key>/System/Library/CoreServices/CoreServicesUIAgent.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>168.3</string>
</dict>
<key>/System/Library/CoreServices/Finder.app</key>
<dict>
<key>foremost</key>
<string>1</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>55</string>
<key>secondsopen</key>
<string>114685</string>
<key>version</key>
<string>10.12.5</string>
</dict>
<key>/System/Library/CoreServices/SystemUIServer.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>1.7</string>
</dict>
<key>/System/Library/CoreServices/UserNotificationCenter.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>3.3.0</string>
</dict>
<key>/System/Library/CoreServices/loginwindow.app</key>
<dict>
<key>foremost</key>
<string>1685</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>101144</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>9.0</string>
</dict>
<key>/System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>5.0</string>
</dict>
<key>/System/Library/Frameworks/Security.framework/Versions/A/MachServices/SecurityAgent.bundle</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>9.0</string>
</dict>
<key>/System/Library/Frameworks/WebKit.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc</key>
<dict>
<key>foremost</key>
<string>0</string>
<key>open</key>
<string>1911</string>
<key>secondsforemost</key>
<string>0</string>
<key>secondsopen</key>
<string>114686</string>
<key>version</key>
<string>12603</string>
</dict>
<key>/private/var/folders/9m/_fh0czw947g8q7pdhxbfbjdh0000gn/T/AppTranslocation/AB999B43-95BD-4B9E-880D-6C59DFD81558/d/Base64.app</key>
<dict>
<key>foremost</key>
<string>1</string>
<key>open</key>
<string>72</string>
<key>secondsforemost</key>
<string>7</string>
<key>secondsopen</key>
<string>4344</string>
<key>version</key>
<string>1.0</string>
</dict>
</dict>
</plist>
Oops, now the pointy honchos knows which applications I am using and for how long in a day. New age micro-management.

The cure
The cure is very simple however. Turn off the jamf service. And next time when we want to turn it on, say to see if IT has pushed some clever software, clear all the logs before hand, close all apps. Then load the daemon back.
sudo launchctl load /Library/LaunchDaemons/com.jamfsoftware.jamf.daemon.plist 
sudo launchctl load /Library/LaunchDaemons/com.jamfsoftware.task.1.plist #com.jamfsoftware.task.{n}.plist check the folder for correct number
Let the update get pushed to the system, then turn it off.
Also as per policy, we cannot set the OS X firewall in stealth mode, blocking all connections. It automatically changes to "on" mode as the policy will be forced down the throat.

Turn off jamf
sudo launchctl unload /Library/LaunchDaemons/com.jamfsoftware.jamf.daemon.plist 
sudo launchctl unload /Library/LaunchDaemons/com.jamfsoftware.task.1.plist #com.jamfsoftware.task.{n}.plist check the folder for correct number

Also jamf can do screen sharing, with or without user consent if configured so. It is a RAT as well.


Update
After the daemon being dead for a week, it is back up running again. Mostly the above commands will alone not stop jamf daemon. I doubt it is because of the com.jamfsoftware.startupItem.plist and /Library/LaunchAgents/com.jamfsoftware.jamf.agent.plist. We can check if this malware is running using
ps aux | grep jamf
# root 48968 0.0 0.0 xxx xxx ?? SN 0:00 0:00.11 /usr/local/jamf/bin/jamfAgent
# root 48834 0.0 0.1 xxx xxx ?? SNs 0:00 0:00.37 /usr/local/jamf/bin/jamf launchDaemon -monitorUsage -enforceRestrictions -monitorNetworkStateChanges
So to get rid of this, rename jamf and not delete because we need it. Or remove the plists.
sudo su
cd /usr/local/bin
mv jamfAgent ripjamfAgent
mv jamf ripjamf
RIP jamf.