6 Replies
      Latest reply: Feb 9, 2017 2:38 PM by eskimo RSS
      jackseraph Level 1 Level 1 (0 points)

        I had an application that needs to do very frequent privileged work. I used to achieve these work by AuthorizationExecuteWithPrivileges(). And I would like to follow the recommended way by using SMJobBless with XPC (a privileged helper over XPC communication). However, I got 2 questions about the unstalling the privileged helper (helper for short below).

        I noticed that SMJobRemove had been marked as deprecated and there is no other API as replacement of it now. So I would like to understand what is the supposed or recommended approach to unstall the helper now?

         

        More background of this question:

        My application can be installed by a simple drag from with the dmg packege. And the uninstall process is also just by draging to the Trash.

        The first time the app starts, it will try to bless the helper with asking the authentication/authorization from a user. Subsequently, it will not bother users next time startup or when communicating with the helper for privileged works.

        The reason that I need to uninstall the helper is for the helper version compatibility. There could be multiple versions of the application with potential different version of helpers co-existing in a user's system. So an idea is that each application with an exactly version number will install and communicate with a helper with a specified version as well (i.e. application 1.0.0 <-> helper-100 / application 2.0.1 <-> helper-201 ...). Therefore, to avoid leaking such a number of helpers in the disk when the applications are removed, I would like to unstall (remove) the helper[ver_num] when a specific version of applications are removed.

         

        Furthermore, when to trigger the uninstall process?

        My current idea is that when the first time the application starts, it will register the folder path where the application is in in the helper (over XPC) plist. The helper will then watch the folder change over the paths (if there are multi applications with that version exists). Once all the applications of that version with different paths registered in helper are removed, the helper will fork a subprocess to uninstall the helper (by SMJobRemove??).

        If the above thinking are not on a correct direction, could you have any suggestion about these 2 questions?

        • Re: How to and When to uninstall a privileged helper
          eskimo Apple Staff Apple Staff (6,470 points)

          I noticed that SMJobRemove had been marked as deprecated and there is no other API as replacement of it now.

          SMJobRemove is not the logical opposite of SMJobBless:

          • SMJobBless copies the privileged helper tool, creates a launchd property list file in /Library/LaunchDaemons/, and loads the job into launchd

          • SMJobRemove unloads the job from launchd

          As such, SMJobRemove is the logical opposite of SMJobSubmit.

          There is, alas, no logical opposite of SMJobBless )-:

          Furthermore, when to trigger the uninstall process?

          There isn’t a good way to do this automatically.

          My current idea is that when the first time the application starts, it will register the folder path where the application is in in the helper (over XPC) plist.

          This approach is unlikely to yield a reliable solution.  There are just too many ways that things can go wrong.  For example, what if the user launches your app off a removable drive and then removes the drive?  You can’t work out whether that’s a permanent or temporary removal, and thus whether your privileged helper tool should self immolate or not.

          I recommend that you offer the user the option of manually uninstalling the privileged helper tool.  Users who care will do the manual uninstall.  Users who don’t care won’t notice the leftover helper.

          For this to be acceptable you have to ensure that any leftover helpers have a minimal impact on the system.  If they do all the usual launchd daemon things (launch on demand, exit on pressure), the cost to the user should be negligible.


          Obviously the above is less than ideal.  It would be nice if macOS had a better mechanism for escalating privileges in a coherent and controlled manner.  Please do file an enhancement request describing your requirements in this space, then post the bug number here, just for the record.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: How to and When to uninstall a privileged helper
              jackseraph Level 1 Level 1 (0 points)

              Thank you for the suggestions. And here is the Bug number 29038737.

              "This approach is unlikely to yield a reliable solution.  There are just too many ways that things can go wrong. "

              This is also what I am quite concerned about the idea. The removable disk example is a very good one that can be considered as one of the cases that the helper is unexpectedly removed. For these cases, I can have the application check and re-install (re-bless) the helper with prompt the auth at the startup though this bothers the user for the auth again. Are there any other side effects about this idea? The most important thing I was worried about is that whether the solution could have any undefined behavior since it is not a standard approach.

                • Re: How to and When to uninstall a privileged helper
                  eskimo Apple Staff Apple Staff (6,470 points)

                  Are there any other side effects about this idea?

                  My example was just that, an example.  I can’t think of any other specific cases of where you’ll see problems but I still strongly recommend you adopt the simplest possible solution (explicit uninstall by the user) rather than the complex scheme you propose.

                  I’ve worked with a bunch of developers who’ve created SMJobBless-based solutions and my experience is that, while things work really well for the vast majority of users, a small fraction of users will have mysterious issues.  Your complex scheme for daemon self immolation is likely to cause more problems like this, and make it harder to debug those problems.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                • Re: How to and When to uninstall a privileged helper
                  mkeiser Level 1 Level 1 (0 points)

                  I recommend that you offer the user the option of manually uninstalling the privileged helper tool.

                   

                  What would be a practical and acceptable way to do this in a GUI application?

                   

                  I know that the uninstalling task itself is trivial, i.e.:

                   

                  #! /bin/sh
                  
                  sudo launchctl unload /Library/LaunchDaemons/com.foo.bar.plist
                  sudo rm /Library/LaunchDaemons/com.foo.bar.plist
                  sudo rm /Library/PrivilegedHelperTools/com.foo.bar
                  

                   

                  However, how should I call this code, without resorting to tell the user she must open the terminal?

                   

                  Specific problems I'm having:

                   

                  1. Most solutions I can think of require the use of AuthorizationExecuteWithPrivileges, however this function is deprecated. Should I still use it for the uninstaller?
                  2. When executing launchctl unload programmatically with AuthorizationExecuteWithPrivileges (either by launching a script or via NSTask), I can't use sudo. But for the life of me, I can't figure out how to use launchctl to unload a system daemon without sudo. I tried to use the -D and -S options, but I obviously did that wrong.
                  3. Any solutions that make use of sudo (like ugly AppleScript hacks) only work with the current user is an administrator.
                  4. Uninstalling the tool from within the tool itself (to avoid AuthorizationExecuteWithPrivileges) seems to pose a chicken-and-egg problem: launchctl unload needs the plist to be present, but presumbably exists the process before the plist can be removed.
                    • Re: How to and When to uninstall a privileged helper
                      eskimo Apple Staff Apple Staff (6,470 points)
                      1. Uninstalling the tool from within the tool itself (…) seems to pose a chicken-and-egg problem …

                      The trick here is to use launchctl remove.

                      Share and Enjoy

                      Quinn “The Eskimo!”
                      Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                      let myEmail = "eskimo" + "1" + "@apple.com"