El Capitan System Integrity Protection Issues

Hey guys,

I just discovered an issue in one of my apps with El Capitan’s System Integrity Protection feature. I basically use the following code to temporarily replace the default TFTPD plist file with one of my own:

[code]
Dim s as new shell

Dim f as FolderItem = App.ExecutableFile.Parent.Parent.Child("Resources")

If f <> Nil and f.Exists Then
  
  // Set up plistFile
  SetUpOSXPlist
  
  Dim ftmp as FolderItem = SpecialFolder.Temporary.child("tftp.plist")
  
  If ftmp = Nil or Not ftmp.Exists Then Return
  Dim MyScript as String
  Dim MyParams as String =""
  
  Dim filepath as FolderItem = SpecialFolder.SharedDocuments
  
  MyScript = "#! /bin/sh"+endofline.unix+endofline.unix+"chmod 777 "+f.shellpath+EndOfLine.UNIX+ _
  "launchctl unload -F /System/Library/LaunchDaemons/tftp.plist"+endofline.unix+ _
  "mv -f  /System/Library/LaunchDaemons/tftp.plist /System/Library/LaunchDaemons/tftp.bak"+EndOfLine.UNIX+_
  "cp "+ftmp.nativepath+" /System/Library/LaunchDaemons/tftp.plist"+EndOfLine.UNIX
  
  If RunAuthShellOSX(MyScript,MyParams) Then
    
    MyScript = "#! /bin/sh"+endofline.unix+endofline.unix+f.ShellPath+"/TFTPStartHelper True"
    MyParams = ""
    
    If RunAuthShellOSX(MyScript,MyParams) Then
      'System.DebugLog("TFTP Server Started")
      Return
    End IF
  End If
End If
[/code]

The SetupOSXPlist method looks like:

Sub SetUpOSXPlist()
  #If TargetMacOS Then
    
    Dim f as FolderItem = App.ExecutableFile.Parent.Parent.Child("Resources")
    If f = Nil Then Return
    
    Dim path as string = f.NativePath
    
    Dim TempPath as FolderItem = SpecialFolder.Temporary
    Dim f1 as FolderItem = SpecialFolder.Temporary.Child("tftp.plist")
    
    Dim filepath as FolderItem = SpecialFolder.SharedDocuments
    
    If f1 = Nil Then Return
    
    Dim bs as BinaryStream = BinaryStream.Create(f1,true)
    
    bs.write("<?xml version=""1.0"" encoding=""UTF-8""?>"+EndOfLine.Unix)
    bs.Write("<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">"+EndOfLine.Unix)
    bs.write("<plist version=""1.0"">"+EndOfLine.Unix)
    bs.write("<dict>"+EndOfLine.Unix)
    bs.write("<key>Disabled</key>"+EndOfLine.Unix)
    bs.write("<true/>"+EndOfLine.Unix)
    bs.write("<key>InitGroups</key>"+EndOfLine.Unix)
    bs.write("<true/>"+EndOfLine.Unix)
    bs.write("<key>Label</key>"+EndOfLine.Unix)
    bs.write("<string>com.apple.tftpd</string>"+EndOfLine.Unix)
    bs.write("<key>ProgramArguments</key>"+EndOfLine.Unix)
    bs.write("<array>"+EndOfLine.Unix)
    bs.write("<string>/usr/libexec/tftpd</string>"+EndOfLine.Unix)
    bs.write("<string>-d</string>"+EndOfLine.Unix)
    bs.write("<string>-i</string>"+EndOfLine.Unix)
    bs.write("<string>-s</string>"+EndOfLine.Unix)
    'bs.write("<string>"+path+"</string>"+EndOfLine.Unix)
// Here's the all important line to change the path with TFTPD serves the files...
    bs.write("<string>"+f.nativepath+"</string>"+EndOfLine.Unix)

    bs.Write("<string>-u</string>"+EndOfLine.Unix)
    bs.Write("<string>root</string>"+EndOfLine.Unix)
    bs.write("</array>"+EndOfLine.Unix)
    bs.write("<key>Sockets</key>"+EndOfLine.Unix)
    bs.write("<dict>"+EndOfLine.Unix)
    bs.write("<key>Listeners</key>"+EndOfLine.Unix)
    bs.write("<dict>"+EndOfLine.Unix)
    bs.write("<key>SockServiceName</key>"+EndOfLine.Unix)
    bs.write("<string>tftp</string>"+EndOfLine.Unix)
    bs.write("<key>SockType</key>"+EndOfLine.Unix)
    bs.write("<string>dgram</string>"+EndOfLine.Unix)
    bs.write("</dict>"+EndOfLine.Unix)
    bs.write("</dict>"+EndOfLine.Unix)
    bs.write("<key>inetdCompatibility</key>"+EndOfLine.Unix)
    bs.write("<dict>"+EndOfLine.Unix)
    bs.write("<key>Wait</key>"+EndOfLine.Unix)
    bs.write("<true/>"+EndOfLine.Unix)
    bs.write("</dict>"+EndOfLine.Unix)
    bs.write("</dict>"+EndOfLine.Unix)
    bs.write("</plist>"+EndOfLine.Unix)
    
    
  #Endif
End Sub

Well, El Capitan does not like me doing this one bit. Throws errors saying the copying into the system files is not allowed.

So, how do I do this now days? I also found that the following code in the run event of a helper app is not appearing to work either. The setuid function is always returning -1. I’m afraid this is another limitation of El Capitan.

  Dim s as new shell
  
  soft declare function setuid lib "/usr/lib/libc.dylib" (uid as Integer) as Integer
  
  dim setuid_result as Integer = setuid(0)
  if setuid_result = -1 then
    system.debuglog "Couldn't raise root setuid"
    return 1
  end if
  
  Try
    
    If args(1) = "True" Then
      s.Execute("launchctl load -F /System/Library/LaunchDaemons/tftp.plist")
      s.Execute("launchctl start com.apple.tftpd")
    else
      s.Execute("launchctl stop com.apple.tftpd")
      s.Execute("launchctl unload -F /System/Library/LaunchDaemons/tftp.plist")
    End If
    
  Catch
    
    s.Execute("launchctl stop com.apple.tftpd")
    s.Execute(" launchctl unload -F /System/Library/LaunchDaemons/tftp.plist")
    
  End Try

So I want to use OS X’s built in TFTP server, but what’s the way you can do that in El Capitan. I hate how Apple changes things that breaks code. ARGH!

As far as I know you have to avoid writing/changing stuff in the apps content from within your app. It breakes code sign and will introduce issues with SIP

Ignore this: you don’t seem to do this :slight_smile:

[quote=255408:@Jon Ogden]

dim setuid_result as Integer = setuid(0) if setuid_result = -1 then system.debuglog "Couldn't raise root setuid" return 1 end if[/quote]
This will always return -1 unless the current user is root. From the OS X man pages:

[quote]The setuid() function sets the real and effective user IDs and the saved set-user-ID of the current
process to the specified value. The setuid() function is permitted if the effective user ID is that of
the super user, or if the specified user ID is the same as the effective user ID. If not, but the
specified user ID is the same as the real user ID, setuid() will set the effective user ID to the real
user ID.[/quote]

I would use libcurl for TFTP.

Until 10.11 unprotects certain files in /System/Library or allows you to do it yourself, the only way without disabling SIP would be to make a different service by coping the file somewhere else, like

sudo cp /System/Library/LaunchDaemons/tftp.plist /Library/LaunchDaemons/tftp.plist

And then instead of using the Sharing panel in System Preferences, you would manage the service yourself…
Be sure to change the filename and the Label key inside the file, in order to avoid conflicts with the original launchd item
Best solution to change the plist file is too move in another folder and launch it from there like.
copy the plist in a user’s home folder and launch tftpd like:

sudo launchctl load -F /Users/userhomefolder/etc/tftp.plist ; sudo /bin/launchctl start com.apple.tftpd

i forget it this
OLD plist

[code]<?xml version="1.0" encoding="UTF-8"?>

Disabled InitGroups Label com.apple.tftpd ProgramArguments /usr/libexec/tftpd -s /private/tftpboot Sockets Listeners SockServiceName tftp SockType dgram inetdCompatibility Wait [/code] [b]New tftpd.plist[/b] [code]<?xml version="1.0" encoding="UTF-8"?> Disabled InitGroups Label com.apple.tftpd ProgramArguments /usr/libexec/tftpd -s /private/tftpboot Sockets Listeners SockFamily IPv4 SockServiceName tftp SockType dgram inetdCompatibility Wait [/code]

[quote=255420:@Eli Ott]This will always return -1 unless the current user is root. From the OS X man pages:

I would use libcurl for TFTP.[/quote]

Thanks for the insight on the setuid.

As far as libcurl, no can do. I’m using the Mac as a TFTP server. Hence the use of TFTPD.

Loannis,

Thank you for your response. I will try that. I don’t need to manage anything from the sharing pane. This is a completely temporary operation used just within the app. So your idea just may work.

I wouldn’t call it “breaking code”. It increases security, which is important for common users I think. But as a developer you might turn SIP off on your own machines.

Maybe this will help you:
Custom TFTP Server path in Mac OS X El Capitan

[quote=255443:@Jon Ogden]Loannis,

Thank you for your response. I will try that. I don’t need to manage anything from the sharing pane. This is a completely temporary operation used just within the app. So your idea just may work.[/quote]
You don’t need to mess with sharing pane,my previous post was just example…
Because of the SIP you don’t have rights to modify the original Plist file,so just copy the plist file to your preferred folder and there make the changes.
and run the demon again with the new Plist file sudo launchctl load -F /Users/userhomefolder/MyNewFolder/tftp.plist
Remember you need to include in your plist this two new

<key>SockFamily</key> <key>SockFamily</key> <string>IPv4</string>

[quote=255421:@Loannis Kolliageorgas]
copy the plist in a user’s home folder and launch tftpd like:

sudo launchctl load -F /Users/userhomefolder/etc/tftp.plist ; sudo /bin/launchctl start com.apple.tftpd

So I’m getting a Path had bad ownership/permissions error. I’ve made it read/write for everyone…What am I doing wrong?

Without knowing too much about the service, I would imagine that it needs to be in a folder that your application can read & write from by default, such as it’s own application support folder.

Or within the application bundle, /Contents/Library/LaunchDaemons/

But of course having it within the application bundle, means it cannot be adjusted at run time, only launched.

[quote=255593:@Jon Ogden][quote=255421:@Loannis Kolliageorgas]
copy the plist in a user’s home folder and launch tftpd like:

sudo launchctl load -F /Users/userhomefolder/etc/tftp.plist ; sudo /bin/launchctl start com.apple.tftpd

So I’m getting a Path had bad ownership/permissions error. I’ve made it read/write for everyone…What am I doing wrong?[/quote]
Have you stop the server and relaunch ?

Stopped and unloaded tftpd

root# sudo launchctl stop com.apple.tftpd root# sudo launchctl unload -F /System/Library/LaunchDaemons/com.apple.syslogd.plist
Loaded and started tftpd:

root# sudo launchctl load -F /System/Library/LaunchDaemons/com.apple.syslogd.plist root# sudo launchctl start com.apple.tftpd

System log >syslogd.plist
Other thinks you need to change…

<key>Label</key> <string>com.apple.tftpd</string> <---- change because conflict with original
And the filename…

[quote=255626:@Loannis Kolliageorgas][quote=255593:@Jon Ogden]
Have you stop the server and relaunch ?
[/quote]

Yeah. No matter what I do, I get that same error.

MacBook-Pro-2:/ Jon$ sudo launchctl load -F /Library/Application\\ Support/JustAddSoftware/tftp.plist
/Library/Application Support/JustAddSoftware/tftp.plist: Path had bad ownership/permissions

Check the folder and the file for permissions /JustAddSoftware/tftp.plist

JustAddSoftware <folder permissions
Jon(me) = Read&Write staff =Read Only everyone=Read Only
the same as above for the file…
Tip
go to the folder >Library/Application\ Support/JustAddSoftware/ < and on terminal put “ls -la” to see the owner and permissions
then
change the ownership

sudo chown -Rv username directory

to fix permissions in el capitan i use the Onyx,for me is the best utility Onyx

OK. It still isn’t working. Here is the output of the file from ls -la:

-rw-r--r--@  1 Jon   staff    1105 Mar 25 23:19 jastftp.plist

I have done the chown command and tried everything possible. Staff was not originally the group the file was under (it was under the admin group) so I changed that to staff, but I still get the same error.

Is it something in the plist file perhaps? I’m stuck and really need to get this working…

<?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>Disabled</key>
        <true/>
        <key>InitGroups</key>
        <true/>
        <key>Label</key>
        <string>com.jas.tftpd</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/libexec/tftpd</string>
                <string>-s</string>
                <string>/Library/Application Support/JustAddSoftware</string>
        </array>
        <key>Sockets</key>
        <dict>
                <key>Listeners</key>
                <dict>                
                        <key>SockFamily</key>
                        <string>IPv4</string>
                        <key>SockServiceName</key>
                        <string>tftp</string>
                        <key>SockType</key>
                        <string>dgram</string>
                </dict>
        </dict>
        <key>inetdCompatibility</key>
        <dict>
                <key>Wait</key>
                <true/>
        </dict>
</dict>
</plist>

have you set it up manually using these steps ?
I’d start there on a 10.11 machine and see what errors / issues you encounter

[quote=255939:@Norman Palardy]have you set it up manually using these steps ?
I’d start there on a 10.11 machine and see what errors / issues you encounter[/quote]

That’s what I am trying to do. I’m trying to get it started in terminal but am not having any luck.

So to re-cap I want to start OS X’s TFTP daemon but with a different plist file than the default. But I can’t get it to load. Keeps giving me bad ownership errors…

Most folders i have in application Support is…
Owner: my Name Group :Staff
Folder is RWX - R-X R-X
For my files is 644 like yours.
BUT the folder is 755 ?

[quote=255942:@Loannis Kolliageorgas]Most folders i have in application Support is…
Owner: my Name Group :Staff
Folder is RWX - R-X R-X
For my files is 644 like yours.
BUT the folder is 755 ?[/quote]

drwxrwxrwx 15 Jon staff 510 Mar 28 11:38 JustAddSoftware

777

I used Onyx to correct permissions as well.

Try this…
sudo chown root /Your folder/jastftp.plist
sudo chgrp wheel /Your folder/jastftp.plist

For me is working fine…

192:Desktop ioannis$ sudo launchctl load -w /Users/ioannis/Desktop/tftp.plist /Users/ioannis/Desktop/tftp.plist: service already loaded 192:Desktop ioannis$