#!/bin/sh # # Short: Create Mac OS X NetInfo users from a text file # Version: 2.07, 12-09-02 # Author: Mark J Swift, msw AT blackpool.ac.uk # Long: This script will create Mac OS X netinfo entries for every # user specified in a given text file. The text file must # have a line for every user that gives the following # information': user_shortname,user_fullname,password,group # Note, the script requires that the netinfo group definition # contains the 3 group properties realname, home_loc and # home_loc_owner (introduced in OS X 10.2) # # # 1. Log in as root # # 2. Copy this script into roots home directory # (/private/var/root/Documents). # # 3. Start a new shell process and change directory to roots home. # # cd ~/Documents # # 4. Set the execute flag is set on the script, type: # # chmod u+x mkusers.sh # # 5. Create a text file containing a line for every user # that gives the following information': # # short_name,full_name,group,password ...i.e: # # dwa,duncan waketch,art-staff,ectonger # kqu,kevin quington,art-staff,croferes # 20013141,oliver mcapman,art-ba-gd-2003,decier # 20015926,grant winson,art-ba-gd-2003,plamme # 20029793,benjamin brockson,art-ba-gd-2004,cabloste # 20022384,william alkine,art-ba-gd-2004,teurvant # 20013383,jakob croucks,art-ba-ph-2003,decrite # 20012795,kathryn dallind,art-ba-ph-2003,phystion # 20024197,patrick burris,art-ba-ph-2004,permient # 20021693,craig stocks,art-ba-ph-2004,affraie # # Note, if no password is specified on the line - i.e: # # short_name,full_name,group # # ...then the user's password is generated using the # command line utility babelpass. babelpass requires a # language template file (see script). # # If babelpass or the required language template file is not # available, then the password is set to be the short name. # # 6. Save the file as "users.txt" in root's home directory # # 7. Consider changing the value of "home_long_names" in the # "mkusers.sh" script depending on whether you want user home # folders to be named after the user's short name (0) or # long name (1). The default is 0. # # 8. Execute the "mkusers.sh" script and pass it the users file # "users.txt" with the following command: # # ~/Documents/mkusers.sh users.txt # # The script creates the user, sets the password, adds the # user to the group, sets user home properties and more. # It also creates a text file called "mkusers.txt" that # contains "short_name,full_name,group,password" for every # user created (useful where passwords have been generated). # -------------------------------- # NOW WE BEGIN... # -------------------------------- # -------------------------------- # quit if wrong number of parameters NPARAMS=$# if [ $NPARAMS -ne 1 ] then echo " USAGE: $0 \" exit 0 fi # check if user import file exists INFILE=$1 if ! ( test -r $INFILE ) then echo file not found: $INFILE exit 0 fi # -------------------------------- # CHANGE: 0 if you want home folder # to be named after user's short name, # 1 if you want home folder to be # named after user's long name. home_long_names=1 # -------------------------------- # CHANGE: if you are letting this script # generate passwords # a language template file lng="language.txt" # a file of bad passwords bad="badpasswd.txt" # the number of unique passwords to generate gen="100000" # if files are not available, use short name as password passgen="sed -n -e h -e s/,.*$// -e x -e G -e s/\n/,/ -e p" if test -f "babelpass" then chmod u+x babelpass if test -f "$lng" then if test -f "$bad" then # generate passwords, exclude bad ones. passgen="`pwd`/babelpass -t $lng -x $bad -c $gen -u" else # generate passwords. passgen="`pwd`/babelpass -t $lng -c $gen -u" fi fi fi # -------------------------------- # Set the host id based on the first broadcast interface's IP address # -------------------------------- node_ip=`ifconfig -a | sed -n '/inet/p' | sed -n '/broadcast/p' | head -1 | cut -d' ' -f2` if test -z "$node_ip" then node_ip="127.0.0.1" fi # get the name of this workstation node_name=`uname -n` # -------------------------------- # debug - print host details to screen # -------------------------------- # echo " node_ip:$node_ip" # echo " node_name:$node_name" # -------------------------------- # NetInfo: are we sharing, are we master? # -------------------------------- ni_notshared=`niutil -rparent . | grep -c -y "[.]*no parent"` if [ $ni_notshared -eq 1 ] then ni_isshared=0 ni_ismaster=0 ni_host_name=$node_name else ni_isshared=1 ni_ismaster=`niutil -rparent . | grep -c -y "^$node_name[]*/[]*"` ni_host_name=`niutil -rparent . | cut -d/ -f1 | cut -d. -f1 ` fi if [ $ni_isshared -eq 0 -o $ni_ismaster -eq 1 ] then ni_canmodify=1 else ni_canmodify=0 fi # -------------------------------- # debug - print host NetInfo details to screen # -------------------------------- # echo " ni_is_shared:$ni_isshared" # echo " ni_is_master:$ni_ismaster" # echo " ni_canmodify:$ni_canmodify" # echo " ni_host_name:$ni_host_name" # is the machine defined in NetInfo? count=`nireport / /machines name | grep -c -y "^$ni_host_name\b"` if [ $count -eq 0 ] then ni_host_ip=$node_ip else ni_host_ip=`niutil -read / /machines/$ni_host_name | grep -y "^ip_address: " | cut -d: -f2 | tr -d "\040"` fi # is IP valid? count=`echo "$ni_host_ip" | grep -c -y "^127.0.0.1\b"` if [ $count -ne 0 ] then ni_host_ip=$node_ip fi # -------------------------------- # debug - print host NetInfo details to screen # -------------------------------- # echo " ni_host_ip:$ni_host_ip" # -------------------------------- # find a user id that is free # -------------------------------- uidcount=`nireport / /users uid | sort -n | tail -n 1` uidcount=`echo $uidcount + 1 | bc` if [ $uidcount -lt 1025 ] then uidcount=1025 fi if [ $ni_canmodify -eq 0 ] then echo " ERROR: Script must be run on $ni_host_name" else # -------------------------------- # read from file, line-by-line # -------------------------------- line_count=0 tr -s "\015" "\012" < "$1" | $passgen | while read whole_line do line_count=`expr $line_count + 1` # -------------------------------- # get user/group details from file # -------------------------------- # extract (lower-case) user details and strip extra spaces fi_user_name=`echo $whole_line | tr [A-Z] [a-z] | tr -d "\040" | cut -d, -f1` fi_user_realname=`echo $whole_line | tr [A-Z] [a-z] | tr -s "\040" | cut -d, -f2` # extract user group name fi_grup_realname=`echo $whole_line | tr -d "\040" | cut -d, -f3` # extract password fi_user_passwd=`echo $whole_line | tr -d "\040" | cut -d, -f4` # strip full name down to first and last name only count=`echo "$fi_user_realname" | wc -w` if [ $count -ne 1 ] then user_givenname=`echo "$fi_user_realname" | cut -f1 -d" "` user_lastname=`echo "$fi_user_realname" | cut -f$count -d" "` fi_user_realname=`echo "$user_givenname $user_lastname"` fi # -------------------------------- # encrypt the plain text password # -------------------------------- user_cryptpass=`openssl passwd $fi_user_passwd` # -------------------------------- # debug - print user details to screen # -------------------------------- # echo " name: $fi_user_name" # echo " realname: $fi_user_realname" # echo " password: $fi_user_passwd" # echo " crypt passwd: $user_cryptpass" # echo " group: $fi_grup_realname" # does the group realname exist count=`nireport / /groups realname | grep -c -y "^$fi_grup_realname\b"` if [ $count -ne 0 ] then # get name of group with this realname ni_grup_name=`nireport / /groups realname name | tr "\t" ":" | grep -y "^$fi_grup_realname\b" | cut -d: -f2 ` else # group with this realname doesn't exist, does the group name exist? count=`nireport / /groups name | grep -c -y "^$fi_grup_realname\b"` if [ $count -ne 0 ] then # group name specified in file ni_grup_name=$fi_grup_realname else # group with this name doesn't yet exist echo " ERROR: cannot create user $fi_user_name. Create group $fi_grup_realname first." ni_grup_name="" fi fi if test -n $ni_grup_name then # -------------------------------- # get groups NETINFO details # -------------------------------- ni_grup_id=`niutil -read / /groups/$ni_grup_name | grep -y "^gid: " | cut -d: -f2 | tr -d "\040"` ni_grup_host=`niutil -read / /groups/$ni_grup_name | grep -y "^home_loc: " | cut -d">" -f3 | cut -d"<" -f1 | cut -d/ -f3 ` ni_grup_share_fldr=`niutil -read / /groups/$ni_grup_name | grep -y "^home_loc: " | cut -d">" -f3 | cut -d"<" -f1 | cut -d/ -f4 ` ni_grup_home_fldr=`niutil -read / /groups/$ni_grup_name | grep -y "^home_loc: " | cut -d">" -f5 | cut -d"<" -f1 ` # -------------------------------- # debug - print user home details to screen # -------------------------------- # echo " ni_grup_name: $ni_grup_name" # echo " ni_grup_id: $ni_grup_id" # echo " ni_grup_host: $ni_grup_host" # echo " ni_grup_share_fldr: $ni_grup_share_fldr" # echo " ni_grup_home_fldr: $ni_grup_home_fldr" if test -z $ni_grup_share_fldr then echo " ERROR: cannot create user $fi_user_name. Group $ni_grup_name missing home_loc properties." else # is the mount defined in NetInfo? count=`nireport / /mounts opts | grep -c -y "^[^.]*$ni_grup_host/$ni_grup_share_fldr\b"` if [ $count -eq 0 ] then echo " ERROR: cannot create user $fi_user_name. Create automount $ni_grup_share_fldr first." else # -------------------------------- # get mounts NETINFO details # -------------------------------- ni_dirid=`nigrep "$ni_grup_host/$ni_grup_share_fldr$" / /mounts | cut -d ' ' -f1 | tail -n 1` ni_mount_host_name=`niutil -read / $ni_dirid | grep -y "^name: " | cut -d: -f2 | cut -c2-` ni_mount_host_ip=`niutil -read / $ni_dirid | grep -y "^opts: " | cut -d@ -f2 | cut -d/ -f1` ni_mount_share_fldr=`niutil -read / $ni_dirid | grep -y "^opts: " | cut -d@ -f2 | cut -d/ -f2-` ni_mount_share_pnt=`niutil -read / $ni_dirid | grep -y "^dir: " | cut -d: -f2 | cut -c2-` ni_mount_share_path=`niutil -read / $ni_dirid | grep -y "^name: " | cut -d: -f3` # -------------------------------- # debug - print user home details to screen # -------------------------------- # echo " ni_mount_host_name: $ni_mount_host_name" # echo " ni_mount_host_ip: $ni_mount_host_ip" # echo " ni_mount_share_fldr: $ni_mount_share_fldr" # echo " ni_mount_share_pnt: $ni_mount_share_pnt" # echo " ni_mount_share_path: $ni_mount_share_path" # -------------------------------- # create users NETINFO details # -------------------------------- # does the user already exist count=`nireport / /users name | grep -c -y "^$fi_user_name\b"` if [ $count -eq 0 ] then # user doesn't yet exist echo " : creating user $fi_user_name" # create user while [ `niutil 2>&1 -create / /users/"$fi_user_name" | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done # create/overwrite uid property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" uid $uidcount | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done uidcount=`echo $uidcount + 1 | bc` # check if there is already a user with netinfo realname eq fi_user_realname count2=`nidump passwd / | grep -c -y "^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:$fi_user_realname"` if [ $count2 -ne 0 ] then # muliple users with specified realname, so tag with a count fi_user_realname=`echo "$fi_user_realname $count2"` fi # create/overwrite "realname" property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" realname "$fi_user_realname" | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done else # Everything is fine, user already exists echo " : updating user $fi_user_name" fi # -------------------------------- # get users NETINFO details # -------------------------------- ni_user_uid=`niutil -read / /users/$fi_user_name | grep -y "^uid: " | cut -d: -f2 | tr -d "\040"` # create/overwrite "_writers_passwd" property (don't know what its for) while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" _writers_passwd $fi_user_name | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done # create/overwrite "passwd" property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" passwd $user_cryptpass | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done # create/overwrite "gid" property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" gid $ni_grup_id | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done # create/overwrite "homedirstyletype" property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" homedirstyletype 1131639917 | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done if [ $home_long_names -eq 0 ] then # create/overwrite "home" property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" home "$ni_mount_share_pnt/$ni_mount_host_name$ni_mount_share_path/$ni_grup_home_fldr/$fi_user_name" | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done # create/overwrite "home_loc" property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" home_loc "afp://$ni_grup_host/$ni_grup_share_fldr$ni_grup_home_fldr/$fi_user_name" | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done else # create/overwrite "home" property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" home "$ni_mount_share_pnt/$ni_mount_host_name$ni_mount_share_path/$ni_grup_home_fldr/$fi_user_realname" | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done # create/overwrite "home_loc" property while [ `niutil 2>&1 -createprop / /users/"$fi_user_name" home_loc "afp://$ni_grup_host/$ni_grup_share_fldr$ni_grup_home_fldr/$fi_user_realname" | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done fi echo >>mkusers.txt "$fi_user_name,$fi_user_realname,$fi_grup_realname,$fi_user_passwd" # -------------------------------- # add user to group # -------------------------------- # is user already a member? count=`niutil -read / /groups/$ni_grup_name | grep -c -y "^users:[^.]* $fi_user_name\b"` if [ $count -eq 0 ] then # ...let me know what's going on echo " : adding user $fi_user_name to group $ni_grup_name" # merge into groups "users" property while [ `niutil 2>&1 -mergeprop / /groups/"$ni_grup_name" users $fi_user_name | grep -y -c " *Permission denied"` -ne 0 ]; do sleep 2 ; done fi fi fi fi done fi