mkgroup.in 6.67 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
2
3
4
5
#!/usr/bin/perl -wT
use English;
use Getopt::Std;

#
6
7
8
# Create a group on the control/ops nodes and any tipservers. This does
# not create accounts, or add users to groups; it just creates the group
# entries and the group directory.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
9
#
10
11
# XXX - /proj wired in
#       control node wired in.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
12
13
14
#
sub usage()
{
15
    print STDOUT "Usage: mkgroup [-b | -a] <pid> <gid>\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
16
17
    exit(-1);
}
18
my  $optlist = "ba";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
19
20
21
22
23
24
25
26
27
28
29
30
31

#
# Configure variables
#
my $TB		= "@prefix@";
my $TBOPS       = "@TBOPSEMAIL@";
my $TBLOGS      = "@TBLOGSEMAIL@";
my $CONTROL     = "@USERNODE@";
my $PROJROOT    = "/proj";
my $SSH         = "$TB/bin/sshtb";
my $GROUPADD    = "/usr/sbin/pw groupadd";

my $batchmode   = 0;
32
my $auditmode   = 0;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
33
34
35
36
37
38
39
40
my $dbuid;
my @db_row;
my $query_result;
my $leader;
my $groupdir;
my $logname;
my $user_name;
my $user_email;
41
42
43
my $unix_gid;
my $unix_name;
my @tipservers;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

#
# Note hardwired control node. 
# 
my $control_node = $CONTROL;

#
# Untaint the path
# 
$ENV{'PATH'} = "/bin:/usr/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

#
# Turn off line buffering on output
#
$| = 1;

#
# Load the Testbed support stuff. 
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#
# We don't want to run this script unless its the real version.
#
if ($EUID != 0) {
    die("*** $0:\n".
	"    Must be setuid! Maybe its a development version?\n");
}

#
# This script is setuid, so please do not run it as root. Hard to track
# what has happened.
# 
if ($UID == 0) {
    die("*** $0:\n".
	"    Please do not run this as root! Its already setuid!\n");
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
if (@ARGV != 2) {
    usage();
}
if (defined($options{"b"})) {
    $batchmode = 1;
}
99
100
101
102
103
if (defined($options{"a"})) {
    $auditmode = 1;
}
my $pid = shift(@ARGV);
my $gid = shift(@ARGV);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

#
# Untaint args.
#
if ($pid =~ /^([-\@\w]+)$/) {
    $pid = $1;
}
else {
    die("Bad data in pid: $pid.");
}
if ($gid =~ /^([-\@\w]+)$/) {
    $gid = $1;
}
else {
    die("Bad data in gid: $gid.");
}

#
# Get user DB uid.
#
if (! UNIX2DBUID($UID, \$dbuid)) {
125
126
    die("*** $0:\n".
        "    You do not exist in the Emulab Database!\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
127
128
129
130
131
132
}

#
# Get email info for mail.
#
if (! UserDBInfo($dbuid, \$user_name, \$user_email)) {
133
134
    die("*** $0:\n".
        "    Cannot determine email info for you!\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
135
136
137
138
139
140
141
142
143
144
145
146
147
}

#
# This script always does the right thing, so it does not matter who
# calls it. But we guard it anyway in the case where ops/boss are the
# same.
# 
if (!TBAdmin($UID)) {
    #
    # Must be project root for the project or group root for the group.
    #
    $query_result =
	DBQueryFatal("select trust from group_membership ".
148
		     "where pid='$pid' and uid='$dbuid' and pid=gid and ".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
149
150
151
152
153
154
155
156
157
		     "trust='project_root'");
    
    if ($query_result->numrows == 0) {
	$query_result =
	    DBQueryFatal("select trust from group_membership ".
			 "where pid='$pid' and uid='$dbuid' and gid='$gid' ".
			 "and trust='group_root'");

	if ($query_result->numrows == 0) {
158
159
	    die("*** $0:\n".
		"    $dbuid does not have permission to update groups!\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
160
161
162
163
164
	}
    }
}

if (! ($leader = GroupLeader($pid, $gid))) {
165
166
    die("*** $0:\n".
	"    Could not determine group leader for $pid/$gid!\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
167
168
}

169
170
171
172
173
#
# The group directory lives here.
# 
$groupdir = "$PROJROOT/$pid/groups/$gid";

Leigh B. Stoller's avatar
Leigh B. Stoller committed
174
175
176
177
#
# Unix info for the group
#
if (! TBGroupUnixInfo($pid, $gid, \$unix_gid, \$unix_name)) {
178
179
    die("*** $0:\n".
	"    No info for project/group $pid/$gid!");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
180
181
182
183
184
}

#
# In batch mode, go to background and send email later.
# 
185
186
187
if ($batchmode || $auditmode) {
    my $childpid;
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
188
189
190
    #
    # Create a temporary name for a log file.
    #
191
    $logname = TBMakeLogname("mkgroup");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
192
    
193
194
195
196
197
198
    if ($childpid = TBBackGround($logname)) {
	if ($auditmode) {
	    waitpid($childpid, 0);
	    exit($? >> 8);
	}
	    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
	#
	# Parent exits normally
	#
	print STDOUT
	    "Creating/Updating project/group $pid/$gid\n".
	    "You will be notified via email when the update is complete.\n";
	exit(0);
    }
}

# 
# Create group locally if it does not exist. egrep returns 1 when
# no matches are found.
#
if (system("egrep -q -s '^${unix_name}:' /etc/group")) {
    print "Adding group $unix_name to local node ...\n";

    if (system("$GROUPADD $unix_name -g $unix_gid")) {
	fatal("*** Could not add $unix_gid ($unix_gid) to local node!\n");
    }
}

#
# Perl and ssh Sillyness!
#
$UID = $EUID;

#
# Create group on the control node if it does not exist.
#
if (system("$SSH $control_node egrep -q -s '^${unix_name}:' /etc/group")) {
    print "Adding group $unix_name to $control_node.\n";

    if (system("$SSH $control_node $GROUPADD $unix_name -g $unix_gid")) {
	fatal("*** Could not add $unix_name ($unix_gid) to $control_node!\n");
    }
}

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#
# Create group on the tip servers. 
#
$query_result =
    DBQueryFatal("select * from tipservers");

while (@db_row = $query_result->fetchrow_array() ) {
    push(@tipservers, $db_row[0]);
}

foreach my $tipserver ( @tipservers ) {
    if (system("$SSH $tipserver egrep -q -s '^${unix_name}:' /etc/group")) {
	print "Adding group $unix_name to $tipserver\n";

	if (system("$SSH $tipserver $GROUPADD $unix_name -g $unix_gid")) {
252
	    fatal("*** Could not add $unix_name ($unix_gid) to $tipserver!\n");
253
254
255
256
	}
    }
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
257
#
258
259
# Create the group directory if it does not already exist, but not for
# the default group of the project.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
260
#
261
262
263
if (! -e $groupdir && $pid ne $gid) {
    print "Creating group directory: $groupdir.\n";
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
    if (! mkdir("$groupdir", 0770)) {
	fatal("*** Could not make directory $groupdir: $!");
    }

    if (! chmod(0770, "$groupdir")) {
	fatal("*** Could not chmod directory $groupdir: $!");
    }

    $unix_uid = getpwnam($leader);

    if (! chown($unix_uid, $unix_gid, "$groupdir")) {
	fatal("*** Could not chown $groupdir to $leader/$gid: $!");
    }
}

279
280
281
282
print "Group Creation Completed!\n";
if ($batchmode || $auditmode) {
    donotify("Group Creation Completed!\n", 0);
    unlink($logname);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
283
284
285
286
287
288
289
}
exit(0);

sub fatal($)
{
    my($mesg) = $_[0];

290
    print STDOUT "$mesg\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
291

292
293
294
295
    if ($batchmode || $auditmode) {
	donotify($mesg, 1);
	unlink($logname);
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
296
297
298
    exit(-1);
}

299
sub donotify($$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
300
{
301
    my($mesg, $iserr) = @_;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
302
303
304
305
306
307
308
309
310
311
312
    my($subject, $from, $to, $hdrs);
    my $MAIL;

    $from    = $TBOPS;
    $hdrs    = "Reply-To: $TBOPS";
    
    #
    # An error goes just to Testbed Operations. Normal status messages go
    # to the user and to the Testbed Logs address.
    # 
    if ($iserr) {
313
314
	$subtext = "Failure";
	$to      = "$TBOPS";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
315
316
    }
    else {
317
318
319
	$subtext = "Success";
	$to      = "$user_name <$user_email>";
	$hdrs    = "Bcc: $TBLOGS\n" . "$hdrs";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
320
321
    }

322
323
324
325
    SENDMAIL($to,
	     "TESTBED: Group Creation " . $subtext . ": $pid/$gid",
	     $mesg, $from, $hdrs,
	     ($logname));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
326
327
328
}