-
Notifications
You must be signed in to change notification settings - Fork 55
/
Copy pathaddgroup.sh
217 lines (166 loc) · 4.59 KB
/
addgroup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#!/bin/bash
# Usage:
#
# addgroup <GROUPNAME> <LONGNAME> [<GID> ]
#
# GROUPNAME: The Mac OS X "short name", e.g. admin
# LONGNAME: The Mac OS X "real name", e.g. "Administrators"
# GID: The group ID for the new group. Leave blank for the script to automatically
# choose the first unused ID at or above MINGID (currently 501).
#
GROUPNAME="$1"
LONGNAME="$2"
NEWGID="$3" # Optional
MINGID=501
DOMAIN="."
# Must have newline here.
IFS="
"
ADDGROUP="./addgroup.sh"
if [ -f "/usr/local/bin/addgroup" ] ; then
ADDGROUP="/usr/local/bin/addgroup"
fi
# /*!
# @abstract Checks to see if a group long name is reasonable.
# @discussion
# Checking for non-empty strings is good enough for now,
# but ideally, this should also check for duplicates.
# The code doesn't do this because there's no good way
# that doesn't involve a huge file and grep.
# */
valid_longname()
{
local NAME="$1"
if [ "$NAME" = "" ] ; then
return 1;
fi
return 0;
}
# /*!
# @abstract Checks to see if a group name is reasonable.
# @discussion Ideally, this should do more checks.
# */
valid_groupname()
{
local NAME="$1"
if [ "$NAME" = "" ] ; then
return 1;
fi
return 0
}
# /*!
# @abstract Checks to see if a (numeric) group ID is reasonable.
# */
valid_gid()
{
local NEWGID="$1"
# Empty primary GID means "choose one for me"
if [ "$NEWGID" = "" ] ; then
return 0;
fi
local NEWGIDSTR="$(printf "%d" "$NEWGID" 2> /dev/null)"
if [ "$NEWGIDSTR" != "$NEWGID" ] ; then
return 1;
fi
return 0;
}
# /*!
# @abstract Creates an associative pseudo-array for GID to username mapping.
# */
initGIDMap()
{
local SKIPGROUP="$1"
# GROUPS is BASH reserved word
local ALLGROUPS="$(dscl "$DOMAIN" -list /Groups)"
for i in $ALLGROUPS ; do
if [ "$i" != "$SKIPGROUP" ] ; then
eval "GID_$(dscl "$DOMAIN" -read /Groups/"$i" PrimaryGroupID 2>/dev/null | sed 's/PrimaryGroupID: //' | sed 's/-/MINUS/')=\"$i\""
fi
done
}
# /*!
# @abstract Looks up a GID in the pseudo-array and maps it to a group name
# */
gidToName()
{
local CHECKGID="$1"
local CHECKGID_ENCODED="$(echo "$CHECKGID" | sed 's/-/MINUS/')"
eval echo '$GID_'$CHECKGID_ENCODED
}
# /*!
# @abstract Finds the next unused UID.
# */
assignGID()
{
initGIDMap
# An error here means somebody screwed up MINGID.
local POS=$MINGID
while true ; do
# echo "Trying $POS" 1>&2
local TEMPNAME="$(gidToName $POS)"
if [ "$TEMPNAME" = "" ] ; then
echo $POS
return;
fi
POS="$(expr $POS '+' 1)"
done
}
# /*!
# @abstract Returns success if no other group has the chosen GID.
# */
gid_not_conflicting()
{
local NEWGID="$1"
local NEWGROUP="$2"
initGIDMap "$NEWGROUP"
local TEMPNAME="$(gidToName "$NEWGID")"
if [ "$TEMPNAME" != "" ] ; then
return 1;
fi
return 0
}
while ! valid_groupname "$GROUPNAME" ; do
printf "Enter group name: "
read GROUPNAME
done
while ! valid_gid "$NEWGID" ; do
printf "Invalid or no group ID specified. Enter desired GID: "
read NEWGID
done
while ! valid_longname "$LONGNAME" ; do
printf "Invalid long name specified. Enter desired long name: "
read LONGNAME
done
# Test code
# echo "GID Conflict check:"
# gid_not_conflicting "80" "admin" # Test this first or else.
# echo "$? should be 0"
# gid_not_conflicting "80" "Schlomo"
# echo "$? should be 1"
echo "First free GID is $(assignGID)"
dscl $DOMAIN -read /Groups/"$GROUPNAME" > /dev/null 2>&1
if [ $? = 0 ] ; then
echo "Failed. A group with that name already exists.." 1>&2
exit -1
fi
dscl $DOMAIN -create /Groups/"$GROUPNAME"
if [ $? != 0 ] ; then
echo "Failed. Group could not be created." 1>&2
exit -1
fi
dscl $DOMAIN -create /Groups/"$GROUPNAME" RealName "$LONGNAME"
if [ "$NEWGID" = "" ] ; then
NEWGID="$(assignGID)"
fi
dscl $DOMAIN -create /Groups/"$GROUPNAME" PrimaryGroupID $NEWGID
while ! gid_not_conflicting "$NEWGID" "$GROUPNAME"; do
echo "A user with ID $NEWGID exists already. Assigning a new GID." 1>&2
OLDGID="$NEWGID"
NEWGID="$(assignGID)"
dscl $DOMAIN -change /Groups/"$GROUPNAME" PrimaryGroupID "$OLDGID" "$NEWGID"
done
UUID="$(/usr/bin/uuidgen)"
dscl $DOMAIN -create /Groups/"$GROUPNAME" GeneratedUID "$UUID";
# Legacy UNIX group password
dscl $DOMAIN -create /Groups/"$GROUPNAME" Password "*"
echo "Added $GROUPNAME with ID $NEWGID and UUID $UUID. Please remember to set a password for the user."