Programmatically Starting OS X's TFTP Server

Hey all,

I’m trying to programmatically start and utilize the built in TFTP server for OS X. But I’m having some problems. Here’s what I am doing. For anything requiring SUDO access, I’m using AuthorizationMBS shell objects.

1.) Copying the files I want to transfer to my SpecialFolders.Temporary location
2.) Setting permissions on SpecialFolders.Temporary to 777.
3.) Unloading the TFTP server in case it is already running using: launchctl unload -F /System/Library/LaunchDaemons/tftp.plist
4.) Creating a plist file with the file location specified as the SpecialFolders.Temporary location.
5.) Backing up the existing plist file in /System/Library/LaunchDaemons
6.) Copying the new plist file to /System/Library/LaunchDaemons
7.) Starting the TFTP server using:
launchctl load -F /System/Library/LaunchDaemons/tftp.plist
launchctl start com.apple.tftpd

All seems pretty good. However, when I try to start a transfer, I get the following error in the log:

11/20/14 8:01:10.385 AM tftpd[35573]: chroot: Operation not permitted
11/20/14 8:01:10.385 AM com.apple.xpc.launchd[1]: (com.apple.tftpd[35573]) Service exited with abnormal code: 1

I’ve tried numerous other things, but cannot get it to work properly. If someone can guide me to what I am doing wrong, I’d appreciate it. It seems like I’m being told I don’t have permissions to change the directory location to where the files are. But I don’t know.

Thanks,

Jon

Could be related to how you start it in the launchd script
But you’ve not posted those details here

The other thing is that the man page notes
tftpd will chroot(2) to directory on startup.
and that COULD be the cause of the chroot error

Not too that TFTP has to use publicly accessible files
Not sure what the permissions are all the way down the path to SpecialFolders.Temporary are but that certainly could do it if its not public all the way down the path. SpecialFolders.Temporary may not be.
You might try the users Shared folder which should be publicly readable

[quote=144698:@Norman Palardy]Could be related to how you start it in the launchd script
But you’ve not posted those details here
[/quote]

I’ve not messed with that. It’s whatever is standard in Apple’s settings…

[quote]
The other thing is that the man page notes
tftpd will chroot(2) to directory on startup.
and that COULD be the cause of the chroot error
[/quote}
OK. That might be it.

[quote]
Not too that TFTP has to use publicly accessible files
Not sure what the permissions are all the way down the path to SpecialFolders.Temporary are but that certainly could do it if its not public all the way down the path. SpecialFolders.Temporary may not be.
You might try the users Shared folder which should be publicly readable[/quote]

OK. I’ll try that. It’s pretty crazy that the default folder for TFTP is /private/tftpboot. But that folder certainly is not public!

Thanks, Norman…

This is all documented on the man page
Open terminal
Type in “man tftpd”

[quote=144700:@Norman Palardy]This is all documented on the man page
Open terminal
Type in “man tftpd”[/quote]
Yeah, I should have looked there. I got most of what I have been using from some knowledbase articles I’ve found on the web. I’m beginning to wonder if some are quite correct.

So what’s interesting is that if I start the TFTP server process by entering the EXACT same commands in a terminal window using sudo, it works beautifully. No problems. It’s when I do it programmatically from within an authorized shell that I have problems…

Not sure how the authorization mbs shell works but I know the one mike bailey did years ago relied on functionality thats been deprecated (not sure if its been removed in the latest OS X)

Are you getting any error messages ?

Terminal ? shell (as the shell doesn’t have all the same environment set up)

Or so I’ve found out. However, on the Nug, Tim Jones suggested the following:

  Dim authSh As New Shell
  authSh.Execute "sudo -K"
  authSh.Execute "echo " + pwEscaped + " | sudo -S /usr/bin/true"  // this starts the sudo timer
  authSh.Execute "sudo launchctl load -F /System/Library/LaunchDaemons/tftp.plist"
  authSh.Execute "sudo  launchctl start com.apple.tftpd"
  authSh.Execute "sudo -K" // clears the sudo state

Where pwEscaped is the user’s password. If I substitute my password in place of pWEscaped and run the code, it works PERFECTLY. And yes, I could create a dialog box and ask for the user’s password, but I really don’t want to do that. I’d much rather use the OS’s built in facilities…

I would as well I just know that the mechanism that was possible previously has been deprecated
https://developer.apple.com/library/mac/documentation/Security/Reference/authorization_ref/#//apple_ref/c/func/AuthorizationExecuteWithPrivileges

HOWEVER that reference does outline other mechanisms - you’d have to ask Christian which his plugin uses
That’s probably relevant here

Well, the authorization works for everything else I’ve tried. It just doesn’t seem to be starting the TFTPD process with root authentication…I’ve been hoping Christian is around reading the threads. I may just have to e-mail him directly…

I give up!

I cannot figure this out. I have looked further at Christian’s examples and documentation for AuthorizationMBS. I’ve confirmed that I’ve launched the process with elevated rights but yet when I try to access the server I get tons of failure messages about how chroot is not permitted.

TFTPd wants to chroot to whatever directory is specified as the TFTP directory. For some reason it just won’t do it when started in AuthorizationMBS. There’s got to be a way to do this.

So I’m pleading for some help here from someone who might know! :slight_smile:

I just don’t know what else to do or try…

post your tftpd launchd script ?

I’m not entirely sure what you mean. Do you mean the tftp plist file?

OK. As usual @jim mckay is a GENIUS! And the NUG still is a place where users can solve problems.

Jim had the suggestion to create a helper app to launch the TFTP server process. Then change the SETUID bit to root on the compiled helper app. Then launch the helper app from the AuthorizationMBS object. Doing that works PERFECTLY and it gives nice log entries in the console log too about what is going on.