0

This is the setup:

  • OSX Yosemite
  • Java based service that is being started using a LaunchDaemon
  • The service is started with a custom user that is being created during installation
  • The user has a custom home directory to save certain information, like preferences

Here is how is the user created:

DEAMON_USER="{{daemonUser}}"
HOME_DIRECTORY="{{homeDirectory}}"
SERVICE_DESCRIPTION="{{displayName}}"

# find the next UID and GID that is below 500, so that we can create the service user
# if the user or group already exists, it will use this existing ID and still do the rest. We might have changes to commit.
NEXTUID=$(ID=`dscl . -read "/Users/${DEAMON_USER}" UniqueID 2> /dev/null | awk '{print $2}'` && [ ! -z "$ID" ] && echo "$ID" || dscl . -list /Users UniqueID | awk 'BEGIN{i=0}{if($2>i&&$2<500)i=$2}END{print i+1}')
NEXTGID=$(ID=`dscl . -read "/Groups/${DEAMON_USER}" PrimaryGroupID 2> /dev/null | awk '{print $2}'` && [ ! -z "$ID" ] && echo "$ID" || dscl . -list /Groups PrimaryGroupID | awk 'BEGIN{i=0}{if($2>i&&$2<500)i=$2}END{print i+1}')

echo "Will use '${NEXTUID}' as UserID and '${NEXTGID}' as group ID for User '${DEAMON_USER}'"

#########################################################################################################
dscl . -create "/Users/${DEAMON_USER}" UniqueID "${NEXTUID}"
dscl . -create "/Users/${DEAMON_USER}" PrimaryGroupID "${NEXTGID}"
dscl . -create "/Users/${DEAMON_USER}" NFSHomeDirectory "${HOME_DIRECTORY}"

# Can't login as standard user
dscl . -create "/Users/${DEAMON_USER}" UserShell /usr/bin/false
dscl . -create "/Users/${DEAMON_USER}" RealName "${SERVICE_DESCRIPTION} Administrator"

# Unusable password for standard users
dscl . -create "/Users/${DEAMON_USER}" Password \*
#########################################################################################################

#########################################################################################################
dscl . -create "/Groups/${DEAMON_USER}" PrimaryGroupID "${NEXTGID}"
# Unusable password for standard users
dscl . -create "/Groups/${DEAMON_USER}" Password \*
#########################################################################################################

# make home directory
mkdir -p "${HOME_DIRECTORY}/Library/Preferences" && chown -R "${DEAMON_USER}:${DEAMON_USER}" "${HOME_DIRECTORY}" || true

The service usually creates user preferences which are then stored in the ~/Library/Preferences directory - in a plist backed store.

But not with the user created above. The preferences are never saved. I know that there is a service that keeps the preferences in sync with memory and filesystem (it is not running for the new user).

The question is: what is wrong with either Java - what would it take to correct it - or with the way the system user is created.

Even a simple java program like the following does not trigger the preferences to be written:

import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
public class prefTest {
    public static void main( String[] args ) throws BackingStoreException {
        System.out.println( System.getProperty( "user.home" ) );
        Preferences userRoot = Preferences.userRoot();
        userRoot.put( "Test", "Value" );
        userRoot.flush();
        System.out.println( userRoot.get( "Test", "DEFAULT" ) );
    }
}

Running this program with the service user will result in the wrong output and will not create a Java preferences file for update an existing.

  • It looks like you are mixing human-users and system-users, and doing some stuff in Linux/BSD/Windows ways, and others in Mac OS X human user session ways. Choose one approach and stick with it for better results ;-) also, the method of launching your Java app matters. – John Keates Sep 21 '16 at 11:40
  • Ok, care to explain? Using dscl for a service user was recommended several times, creating the users home directory instead of using the Template should be OK. The Java example is just a minimal setup which should work nevertheless. The service is started via LaunchDaemon. Is there anything else I could add to narrow down the problem? – gamma Sep 21 '16 at 12:02
  • If you launch a Java program from the commandline without a Aqua user session it doesn't automatically get access to the user preferences etc. When you start a JAR archive form the Finder, the OS adds a lot of environment variables, commandline options for the launcher, and launchservices adds /var/private/folders entries and temp directories where Java's access is sandboxed. On exit, it then gets piped back to the user's profile. On next launch, it is reversed, a fresh folders and tmp entry is made, but the pre-persisted changes are available to the java app. – John Keates Sep 21 '16 at 12:07
1

Looks like I found a solution on my own. John Keates has made some good points which made me check the web a little more.

I solved it using the following two lines with the user-creation script:

dscl . -delete /Users/_helpdesk PasswordPolicyOptions
dscl . -delete /Users/_helpdesk AuthenticationAuthority

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .