0

I need to launch a terminal command to xcode. This is the command:

sudo xattr -d -r com.test.exemple /Desktop/file.extension

I tried so

   let task = Process()
        task.launchPath = "/usr/sbin/xattr"
        task.arguments = ["-d","-r", "com.test.exemple"," /Desktop/file.extension"]
        let pipe = Pipe()
        task.standardOutput = pipe
        task.standardError = pipe
        task.launch()
        task.waitUntilExit()
        let data = pipe.fileHandleForReading.readDataToEndOfFile()
        let output : String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
        print(output)
vadian
  • 274,689
  • 30
  • 353
  • 361

3 Answers3

1

Here's one way to do it using a pipe between commands. I verified that when I use the arguments in the commented out line that the file gets created by the super user.

What it is doing is this:

echo 'password' | sudo -S /usr/bin/xattr -d -r com.test.exemple /Desktop/file.extension

func doTask(_ password:String) {
    let taskOne = Process()
    taskOne.launchPath = "/bin/echo"
    taskOne.arguments = [password]

    let taskTwo = Process()
    taskTwo.launchPath = "/usr/bin/sudo"
    taskTwo.arguments = ["-S", "/usr/bin/xattr", "-d", "-r", "com.test.exemple", " /Desktop/file.extension"]
    //taskTwo.arguments = ["-S", "/usr/bin/touch", "/tmp/foo.bar.baz"]

    let pipeBetween:Pipe = Pipe()
    taskOne.standardOutput = pipeBetween
    taskTwo.standardInput = pipeBetween

    let pipeToMe = Pipe()
    taskTwo.standardOutput = pipeToMe
    taskTwo.standardError = pipeToMe

    taskOne.launch()
    taskTwo.launch()

    let data = pipeToMe.fileHandleForReading.readDataToEndOfFile()
    let output : String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
    print(output)
}
David S.
  • 6,567
  • 1
  • 25
  • 45
1

I came across this question after reading this newer question. Just in case somebody arrives here via search, here's the code from my answer to that question.

There's no real need to pipe through echo; the following works just fine: The following more direct approach is tested and working:

import Foundation

let password = "äëïöü"
let passwordWithNewline = password + "\n"
let sudo = Process()
sudo.launchPath = "/usr/bin/sudo"
sudo.arguments = ["-S", "/bin/ls"]
let sudoIn = Pipe()
let sudoOut = Pipe()
sudo.standardOutput = sudoOut
sudo.standardError = sudoOut
sudo.standardInput = sudoIn
sudo.launch()

// Show the output as it is produced
sudoOut.fileHandleForReading.readabilityHandler = { fileHandle in
    let data = fileHandle.availableData
    if (data.count == 0) { return }
    print("read \(data.count)")
    print("\(String(bytes: data, encoding: .utf8) ?? "<UTF8 conversion failed>")")

}
// Write the password
sudoIn.fileHandleForWriting.write(passwordWithNewline.data(using: .utf8)!)

// Close the file handle after writing the password; avoids a
// hang for incorrect password.
try? sudoIn.fileHandleForWriting.close()

// Make sure we don't disappear while output is still being produced.
sudo.waitUntilExit()
print("Process did exit")

The crux is that you must add a newline after the password.

idz
  • 12,825
  • 1
  • 29
  • 40
  • When I tried this code, it says 'expressions are not allowed at top level' – alex Jan 05 '23 at 22:09
  • @alex your best bet is to open a new question explaining a bit more about what you were doing and a reproducible example. If sounds like you copied and pasted the code into a file that was not the main Swift file. – idz Jan 11 '23 at 20:00
1
  1. In Xcode's "Signing & Capabilities" tab, disable "App Sandbox"
  2. Use AppleScript:
func runScriptThatNeedsSudo() {
    let myAppleScript = """
do shell script \"sudo touch /Library/hello
sudo launchctl kickstart -k system/com.apple.audio.coreaudiod" with administrator privileges
"""
    var error: NSDictionary?
    let scriptObject = NSAppleScript(source: myAppleScript)!
    scriptObject.executeAndReturnError(&error)
}

This will prompt the user for their password.

Consider this a security issue because it will indiscriminately run any tool or application, severely increasing the user's security risk. Always inform the user about what your application is about to do. You should avoid the use of this functionality if possible.

Eric
  • 16,003
  • 15
  • 87
  • 139