Script to run locally while not in SelfService?

macdsl
New Contributor III

So, I'm not sure this is possible, or i'm asking it right...

I have 2 scripts that I want Users to be able to run. One resets the SSID's and the other resets Keychain.
The scripts work fine over ARD, and show up in SelfService as expected, and work.
But,
The user has to be connected to SelfService for it to work, if the user is not on the local network, They can't get the scripts. Our JSS is internal only.

I'm looking for a way for users to be able to run the scripts while NOT on any network. I thought about just putting the scripts on the local machine, but that won't work because the scripts have to run as Admin or Root, which none of my users are. And if SelfService can't connect in, it won't show the scripts.

But there's gotta be a way to do this. I want local users to be able to run a couple of scripts that require Admin access. Even if it's completely outside Self-Service.
Any ideas?

16 REPLIES 16

mm2270
Legendary Contributor III

What you're asking for is quite tough. No admin rights, no Self Service to elevate rights, but you want them to be able to run scripts with admin or root privileges? The OS simply doesn't work this way, generally speaking. If it did, it wouldn't be very secure.

The only thing I can come up with would be to create and deploy a LaunchDaemon that uses a WatchPath script file. The script file can be something in a normally writable location that the user would have rights to make changes to, such as /Users/Shared/.
You can then create either a local script or .app that would pipe the contents of the script or scripts you want them to be able to run, into the file being watched by the LaunchDaemon. The LaunchDaemon can be using the script file itself as its Program to run. When it sees the change to the file, it will fire the launchd job, and run the script, but with root privileges.

While the above would work, I can tell you that this is pretty dangerous unless you take some precautions to make sure the end users cannot see a) which local file is being changed, b) what the local script or app they run is piping into the script to be run by the LaunchDaemon (a run only Applescript perhaps?) and c) that you make sure after the LaunchDaemon runs the script, it empties the contents of the WatchPath script file.
If not, you may as well be handing over admin rights to some of your more technically savvy users, if you have any. If they figure out which local script file the LaunchDaemon is using as its program, they can simply make their own edits to it, and have the LaunchDaemon do their bidding. While its not the same as giving them full admin rights, the sky is kind of the limit on what they can do with that. Install unapproved applications, remove Configuration Profiles, make changes to various protected locations on the OS (El Capitan's SIP protection not withstanding)
So be careful with this.

macdsl
New Contributor III

Yeah, I had a feeling this would be difficult...
Ok, Pipe the script to a File that Launch Daemon watches, and then runs it..
Would it be possible to just have the launch daemon watch the script itself? that when a user runs it, it just does its thing?
Wait, can I create a Applescript that runs as root? Instead of a .sh script? Maybe they are the same thing. Been doing this 20 years, but Scripting is where I really suck...

P.S. None of the users here are coders, and none are savvy enough to get into the scripts, and none are really savvy enough to tweak the scripts to get it to run something nefarious. So, I think i'm ok there...

mm2270
Legendary Contributor III

You cannot create an Applescript that runs as root, at least not one that a non admin user double clicks to run.

If you feel confident that your end users won't be able to figure out what's going on under the hood, then here is a general outline of the process you could use.

Create a LaunchDaemon that would look something like the below. I recommend not just copying/pasting what I have, but instead using something like LaunchControl or Lingon to create it, and use the below as a guide.

<?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>Label</key>
    <string>com.system.utilities</string>
    <key>Program</key>
    <string>/Users/Shared/runner.sh</string>
    <key>RunAtLoad</key>
    <false/>
    <key>WatchPaths</key>
    <array>
        <string>/Users/Shared/runner.sh</string>
    </array>
</dict>
</plist>

As you can see, the Program (what the LaunchDaemon runs) and the WathPath (what triggers it to run) are one and the same, which is a local script file in /Users/Shared/runner.sh. This actually does work, as odd as it may look. I've done it with LaunchAgents though, not LaunchDaemons, but the same principle should work (unless Apple has changed something recently)
The RunAtLoad key being set to false will prevent any running of the launchd job at startup or otherwise. It should only trigger when the script file gets modified.

Now, you can have a script that is run by the user, preferably within an Applescript or something, that would do something along these lines. The below is a bash script though, just as an example.
I have no idea what root level commands you are looking to have run by the non admin users, since you didn't post anything about that. Nevermind. I see now the basic idea of what you're looking to have them do.

#!/bin/sh

echo '#!/bin/sh

fdesetup status

echo "" > /Users/Shared/runner.sh

exit' > /Users/Shared/runner.sh

Now, there's very little happening in this script. All I'm doing is checking the current FileVault status with fdesetup, which requires root to run. The script itself is contained between the starting and ending single quotes, so the final script contents for /Users/Shared/runner.sh would look like this

#!/bin/sh

fdesetup status

echo "" > /Users/Shared/runner.sh

It runs the fdesetup status command, as root, since the LaunchDaemon will run it, then removes the contents of the script file with the echo line. This is only so it won't get accidentally run at another time, though it shouldn't technically be necessary to do that. Just a precaution.
You mentioned you need them to be able to run a few different scripts that require admin/root. I'm guessing you would just need to create a few different local scripts or apps that would modify the contents of the runner.sh file then.

There's more you can be doing here to make this all easier, but I'm not going to dive any deeper on it at the moment. Hopefully the above will get you started in the right direction.

macdsl
New Contributor III

Wow, thanks so much for the help on this, learning a lot..

Ok, what i need to do:
There are 2 wireless SSID's here, a Group and a Guest.
Group is Internal, and Guest is... a Guest...
When a user changes their AD password, because of the configuration of the Cisco ICE network, their Internal Wireless often starts failing after an hour or so after changing their AD password.
The only fix so far for this has been to Go into System Prefs--Network and remove the SSID (i have set the Network Prefs Panel as unlocked for everyone) And remove the Guest SSID, turn the wireless off/on, and reconnect.

So, with about 100 users, ever single time one of them changes their password, they end up having to come to my desk and get their SSID removed and then turned off/on and reconnect to the network. Now, I could probably teach everyone how to do this with videos/instructions. But. I figure there's gotta be a better way.

I have this that works fine over ARD as root:

!/bin/bash

#Script to remove the Group and Guest Preferred Networks#

{
networksetup -removepreferredwirelessnetwork airport Group
networksetup -removepreferredwirelessnetwork airport Group-Guest

networksetup -setairportnetwork airport Group
sleep 5
networksetup -setairportpower airport off sleep 2
networksetup -setairportpower airport on
} &> /dev/null

I also have it in Casper's Self-Service
But i'm looking for a way to have a user be able to run this as a one-step process... Because when their wireless fails they can't get Self Service to connect, so it won't help.
Ethernet is no help, That's a whole different set of problems.

Hey, thanks again for taking a look at this, and I really do appreciate the info...

macdsl
New Contributor III

And the second one,
That's just going to be a script that deletes their Keychain and restarts the machine.
Quite often after changing their AD password their Keychain starts freaking out and asking them to authenticate with a password from 3 or 4 versions back that the user does not know. So it's easier to just rm -f the folder and restart the machine, That one might be easier as it's only removing a folder in the user's Library and restarting.. But that can be explored in a different topic...

mm2270
Legendary Contributor III

OK, so basically only 1 command needs to be run with admin rights. The only item I see from the first scenario that would require root is the -removepreferredwirelessnetwork command. Turning Wi-Fi off and on shouldn't need admin unless you've specifically set the wireless preferences to require admin to turn Wi-Fi on or off (under the Advanced button)

As for removing their login.keychain, I don't think this requires admin either. Its their keychain and they have the right to modify or delete it, so it shouldn't need root for that. If it does, something's messed up I'm sorry to say, since the user should always be able to affect their own account keychain, admin or not.
Also, there are definitely better ways of fixing users keychains. Deleting them is kind of a hammer approach to me. Take a look at @bentoms' ADPassMon fork for starters. It may be just what you need to avoid these issues.

macdsl
New Contributor III

Yup all correct, so all i need is a way for a local user to run the -removepreferredwirelessnetwork portion...
I'll work on the launchdaemon suggestions and see if i can get that going next week.

mm2270
Legendary Contributor III

@macdsl Are the two scenarios you mentioned intended to be run at once by a user, or were you thinking that they could run a script/app that would remove the Guest SSID, OR one that would remove their keychain (assuming you still want to do that, which I'm not a fan of)?

bpavlov
Honored Contributor

I'm not sure if you already tried this or thought of this, but why not create a Self Service policy that is Ongoing and check the box under it that says "Make Available Offline - Cache the policy to ensure it runs when the JSS is unavailable".

mm2270
Legendary Contributor III

Ah, but unfortunately that won't help much, or at all. Since Self Service is essentially a webpage loaded from the JSS, when its launched while disconnected from any network, it just shows an error page that it can't contact the server. It won't show any cached offline policies. If I'm not mistaken there is an existing features request to have any offline SS policies show up in the app when its actually offline, which would be nice.
You can run offline policies (that have run at least once under normal conditions) by doing a sudo jamf policy while off the network, but then you're back to the same problem - inability to run a sudo command unless you're an admin. I suppose if you used the Network State change trigger for the offline policy it might run when the Mac changes networks, like as in, when it goes off the main network, but that seems like relying on too many conditions to be "just right" for it to fix the problem. Maybe it would work, but I don't know.

bentoms
Release Candidate Programs Tester

@macdsl As @mm2270 advised, ADPassMon should be able to help with the keychain (login & local items).

So the guest wireless issue. I guess the JSS is not accessible via the Guest Wireless?? Would the users only be connected to the wireless or also a cabled network?

If the JSS is accessible via the Guest nw... You could have a policy with the trigger "network stage change" targeting a network segment that's the Guest SSID's VLAN, this policy would remove the network. I'm not sure if this policy would also work in offline mode if the JSS is inaccessible.

Otherwise, the JSS can be hooked into your Cisco ISE.. So maybe that could manage the connection?

macdsl
New Contributor III

Thanks for all the responses over the weekend!.
Since Guest is shared between about 7 distinct companies, it can't see the JSS.
I'll research using ADPassMon to assist in the resetting the the keychain (right now we just blow it all away when it's a problem) I've used it before, but not for resetting Keychain.
I'll work on what @mm2270 suggested and see if i can get that going..

Thanks all for the ideas and assistance! Have a great week!

mm2270
Legendary Contributor III

@macdsl Here's a script that would basically do your commands for either fixing Wi-Fi or their keychain, but prompt the user to select which operation they want to do, assuming you'd want to allow them to do each type of operation separately. It just sends up an Applescript "choose from list" window.

#!/bin/sh

selection=$(/usr/bin/osascript << EOF
tell application "Finder"
activate
choose from list {"Repair Wi-Fi connections", "Reset login.keychain"} ¬
with prompt "Choose the action you would like to perform from the items below:"
end tell
EOF)

function WIFI ()
{

echo '#!/bin/bash
#Script to remove the Group and Guest Preferred Networks#

{
networksetup -removepreferredwirelessnetwork airport Group
networksetup -removepreferredwirelessnetwork airport Group-Guest

networksetup -setairportnetwork airport Group
sleep 5
networksetup -setairportpower airport off sleep 2
networksetup -setairportpower airport on
} &> /dev/null

echo "" > /Users/Shared/runner.sh' > /Users/Shared/runner.sh

}

function KEYCHAIN ()
{

<do some stuff here to fix/remove the keychains and reboot>

}

case "$selection" in
    "Repair Wi-Fi connections")
    WIFI ;;
    "Reset login.keychain")
    KEYCHAIN ;;
esac

You'd really only need to pipe out the script for the network/Wi-Fi operations, and have the LaunchDaemon watch that file. The keychain stuff doesn't need root if its being run by the user.
I still don't agree with just blowing away user keychains since as admins we shouldn't be touching that stuff in general. The login.keychain can contain more than just passwords, which in itself is not fun to lose. It can also store certificates that may have been installed, so you can lose that stuff as well.

Alright, I'll get off my soapbox now...

macdsl
New Contributor III

Wow, I was working on getting it going, got the lingo thing going, and was about to test, but yours looks a ton better..

And I'm in for not just blowing away the keychain, but I have no idea how to get the Local Items reset without the user knowing their old password from 3 or 5 back. If there's a way to reset it to the current password, I'm all in..

mm2270
Legendary Contributor III

The Local Items keychain? If its just that, blow it away. There's no way to reset that that I know of. I'll point once again to @bentoms, this time his blog, for a good read on the keychain and Local Items Keychain.

There are also existing posts here on the forum on Local Items Keychain directories and how to figure out what it is and delete it, since the folder is named (usually) with the Mac's UUID, so it will be different on every Mac.

macdsl
New Contributor III

test