Created
September 21, 2012 22:16
-
-
Save kbanman/3764255 to your computer and use it in GitHub Desktop.
adduser implementation for OSX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env php | |
<?php | |
function prompt($msg, $default = false) | |
{ | |
if ($default !== false) | |
{ | |
$msg .= ' ['.$default.']'; | |
} | |
echo $msg.': '; | |
$fh = fopen('php://stdin', 'r'); | |
$input = fgets($fh); | |
fclose($fh); | |
if ($default !== false && (empty($input) || $input == "\n")) | |
{ | |
return $default; | |
} | |
return trim($input); | |
} | |
function prompt_bool($msg, $default) | |
{ | |
do | |
{ | |
$input = strtolower(prompt($msg, $default)); | |
$valid = in_array($input, array('y', 'n', 'yes', 'no')); | |
if ( ! $valid) | |
{ | |
echo "Please enter either 'yes' or 'no'\n"; | |
} | |
} | |
while ( ! $valid); | |
return in_array($input, array('y', 'yes')); | |
} | |
function get_shells() | |
{ | |
if ( ! $fh = fopen('/etc/shells', 'r')) | |
{ | |
throw new Exception('Error reading shells. Make sure you have read permissions on /etc/shells'); | |
} | |
$shells = array(); | |
while ($shell = fgets($fh)) | |
{ | |
$shell = trim($shell); | |
if ( empty($shell) || substr($shell, 0, 1) == '#') | |
{ | |
continue; | |
} | |
$shells[substr($shell, strrpos($shell, '/')+1)] = trim($shell); | |
} | |
return $shells; | |
} | |
function get_groups() | |
{ | |
$group_data = shell_exec('dscl . readall /Groups'); | |
// @todo: This fails on records with linebreaks inside the value, for example: | |
/* | |
AppleMetaNodeLocation: /Local/Default | |
GeneratedUID: ABCDEFAB-CDEF-ABCD-EFAB-CDEF0000000A | |
Password: * | |
PrimaryGroupID: 10 | |
RealName: | |
Creator Owner | |
RecordName: | |
owner | |
BUILTIN\Creator Owner | |
RecordType: dsRecTypeStandard:Groups | |
SMBSID: S-1-3-0 | |
*/ | |
$pattern = '/Password: (.*?)[\n\r]+PrimaryGroupID: (\d+)[\n\r]+RealName:\s+(.*)[\n\r]+RecordName:\s+(.*)[\n\r]+RecordType/'; | |
preg_match_all($pattern, $group_data, $matches); | |
$groups = array(); | |
foreach ($matches[0] as $i => $match) | |
{ | |
//$passwd = trim($matches[1][$i]); | |
$gid = (int) $matches[2][$i]; | |
//$name = trim($matches[3][$i]); | |
$group = trim($matches[4][$i]); | |
$groups[$gid] = $group; | |
} | |
return $groups; | |
} | |
function get_uid($uid = 500) | |
{ | |
// We loop to find a numeric value which is not a users uniqueid or a groups | |
// primary group id starting at $uid | |
do | |
{ | |
$uid++; | |
$user = shell_exec("dscl . search Users UniqueID $uid"); | |
$group = shell_exec("dscl . search Groups PrimaryGroupID $uid"); | |
} | |
while ( ! empty($user) || ! empty($group)); | |
return $uid; | |
} | |
function user_exists($username) | |
{ | |
$user = shell_exec("dscl . search Users RecordName $username"); | |
return ! empty($user); | |
} | |
if (trim(shell_exec('whoami')) != 'root') | |
{ | |
die("This script must be run as root.\n"); | |
} | |
// Username | |
do | |
{ | |
$username = prompt('Username'); | |
if (user_exists($username)) | |
{ | |
echo "User exists!\n"; | |
} | |
} | |
while (user_exists($username)); | |
// Full name | |
$fullname = prompt('Full name'); | |
// UID | |
$uid = prompt('Uid', get_uid()); | |
// Login group | |
$groups = get_groups(); | |
$group = prompt('Login group', $username); | |
if ($group_exists = isset($groups[$group])) | |
{ | |
$group_name = $groups[$group]; | |
} | |
else | |
{ | |
echo "Will create new group '$group'\n"; | |
$group_name = ucfirst($group); | |
} | |
// Login shell | |
$shells = get_shells(); | |
$shell_names = array_keys($shells); | |
do | |
{ | |
$shell = prompt('Shell ('.implode(' ', $shell_names).')', reset($shell_names)); | |
} | |
while (empty($shells[$shell])); | |
$shell = $shells[$shell]; | |
// Home directory | |
$home_dir = prompt('Home directory', '/Users/'.$username); | |
// Password | |
if ($use_password = prompt_bool('Use password-based authentication?', 'yes')) | |
{ | |
do | |
{ | |
$password = prompt('Enter password'); | |
$confirm = prompt('Enter password again'); | |
if ($password !== $confirm) | |
{ | |
echo "Passwords did not match!\n"; | |
} | |
} | |
while ($password !== $confirm); | |
} | |
else | |
{ | |
$password = '*'; | |
} | |
// Add to home screen? | |
$hide_user = ! prompt_bool('Add user to login screen?', 'no'); | |
$create_user = <<<EOF | |
sudo dscl . create /Users/$username | |
sudo dscl . create /Users/$username UniqueID $uid | |
sudo dscl . create /Users/$username PrimaryGroupID $uid | |
sudo dscl . create /Users/$username NFSHomeDirectory $home_dir | |
sudo dscl . create /Users/$username Password '$password' | |
sudo dscl . create /Users/$username UserShell $shell | |
sudo dscl . create /Users/$username RealName '$fullname' | |
EOF; | |
echo passthru($create_user); | |
$create_group = <<<EOF | |
sudo dscl . create /Groups/$group | |
sudo dscl . create /Groups/$group PrimaryGroupID $uid | |
sudo dscl . create /Groups/$group RealName '$group_name' | |
EOF; | |
if ( ! $group_exists) | |
{ | |
echo passthru($create_group); | |
} | |
$create_dir = <<<EOF | |
if [[ ! -d $home_dir ]] ; then | |
sudo mkdir $home_dir | |
fi | |
sudo chown -R $username:$group $home_dir | |
EOF; | |
passthru($create_dir); | |
if ($hide_user) | |
{ | |
passthru("sudo defaults write /Library/Preferences/com.apple.loginwindow HiddenUsersList -array-add $username"); | |
} | |
echo "All done\n"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment