Search code examples
macosshellsudopassword-protection

Restarting the video assistant with a simple command


Original problem: on my MacBook Pro, the video camera keeps freezing. Found the solution is to type

sudo killall VDCAssistant

in a terminal, and provide my password (I have admin privileges).

Now I would like to make this a single command (that doesn't need a password). I found that it is possible to use visudo to edit a file that tells sudo what commands might be run without requiring a password. Obviously it would be too dangerous to make killall itself "password free", so I was hoping I could wrap the specific command inside another script; make that script "password free"; and get on with my life. So here is what I did:

Create a file called video, which contains

!#/bin/bash
sudo killall VDCAssistant

Put it in /usr/local/bin, give permissions chmod 700 video, and rehash. When I type video, I get prompted for my password. So far so good.

Next, I ran visudo and added the lines

User_Alias USERS = myusername
CMND_Alias CMDS = /usr/local/bin/video
USERS ALL = (ALL) NOPASSWD: CMDS

But that doesn't have the desired effect. I am still prompted for the password. If I make root the owner of the script, it doesn't change things. If I leave out the sudo part of the command, it tells me "No matching processes belonging to you were found".

Does anyone have a trick that I missed - how do I achieve my goal (using a single-word command to perform the killall for a process I do not own, without having to type my password)?

I have read the answers to how to run script as another user without password but could not find anything that applied here; I also read the answers to sudo with password in one command line - that is where the inspiration to use visudo came from - but again it didn't give me the answer I was looking for. Obviously I can't save my password in plain text, and I don't want to remove the "normal" protections from killall.

Is there a way to do this?


Solution

  • If you have an actual binary executable, you can set the setuid bit on it using chmod 4755, and then the binary will always execute as whichever user owns it (most useful if it is root, obviously). However, this doesn't work on shell scripts, for security reasons. I'm not 100% sure that this is the case, but it is possible that visudo may also be ignoring shell scripts for the same reasons.

    If you've got Xcode installed, though, you can build an actual binary program to run the killall command, and then you can set the setuid bit on it. This Swift program should do the trick:

    import Foundation
    
    guard setuid(0) == 0 else {
        print("Couldn't set UID 0: error \(errno)")
        exit(-1)
    }
    
    let killall = Process()
    
    killall.launchPath = "/usr/bin/killall"
    killall.arguments = ["VDCAssistant"]
    
    killall.launch()
    killall.waitUntilExit()
    

    Save the above in a text file called video.swift. Run the following command:

    swiftc video.swift -framework Foundation
    

    This will create a file called video in that directory. Move the file to /usr/local/bin, change the owner to root and setuid that sucker:

    mv video /usr/local/bin
    sudo chown root:wheel /usr/local/bin/video
    sudo chmod 4755 /usr/local/bin/video
    

    Now it should work.

    If you want to get fancier, it would probably also be possible to rig up a plist in /Library/LaunchDaemons and get launchd to automatically kill the process every so often.