mkproj.in 7.93 KB
Newer Older
1
#!/usr/bin/perl -wT
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
4

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2000-2006 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
6
7
8
# All rights reserved.
#

9
10
11
12
13
14
15
16
17
18
19
use English;

#
# Make a project directory hierarchy. Must be called as tbroot.
# Creates a directory rooted /proj/pid. The directory is setuid
# to the project leader, and setgid to the project gid. We get
# this info from the database.
#
# usage: mkproj <pid>
#

20
21
sub fatal($);

22
23
24
25
26
27
#
# Configure variables
#
my $TB       = "@prefix@";
my $TBOPS    = "@TBOPSEMAIL@";
my $MKGROUP  = "$TB/sbin/mkgroup";
28
my $MODGROUPS= "$TB/sbin/modgroups";
29
my $MKACCT   = "$TB/sbin/tbacct add";
30
31
my $CVSBIN   = "/usr/bin/cvs";
my $CHOWN    = "/usr/sbin/chown";
32
my $GRANTTYPE= "$TB/sbin/grantnodetype -d";
33
34
my $WIKISUPPORT   = @WIKISUPPORT@;
my $BUGDBSUPPORT  = @BUGDBSUPPORT@;
35
my $OPSDBSUPPORT  = @OPSDBSUPPORT@;
36
37
my $CVSSUPPORT    = @CVSSUPPORT@;
my $MAILMANSUPPORT= @MAILMANSUPPORT@;
38
my $ADDWIKIPROJ = "$TB/sbin/addwikiproj";
39
my $ADDBUGDBPROJ= "$TB/sbin/addbugdbproj";
40
my $ADDMMLIST   = "$TB/sbin/addmmlist";
41
42
my $OPSDBCONTROL= "$TB/sbin/opsdb_control";
	  
43
my $PROJROOT = "/proj";
44
my $GRPROOT  = "/groups";
45
my $TFTPROOT = "/tftpboot";
46
my $CVSREPOS = "$PROJROOT/cvsrepos";
47
my @DIRLIST  = ("exp", "images", "logs", "deltas", "tarfiles", "rpms",
48
		"groups", "tiplogs", "images/sigs", "templates");
49
my $projhead;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

#
# 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";
66
use libaudit;
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
use libdb;
use libtestbed;

#
# 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");
}

#
# Check args.
#
if ($#ARGV < 0) {
    die("Usage: mkprojdir <pid>\n");
}
my $pid = $ARGV[0];

#
# Untaint the argument.
#
if ($pid =~ /^([-\@\w.]+)$/) {
    $pid = $1;
}
else {
    die("Invalid pid '$pid' contains illegal characters.\n");
}

#
# Figure out who called us. Only with admin status in the DB can run
# this script.
#
if (!TBAdmin($UID)) {
    die("*** $0:\n".
	"    You must be a TB administrator to run this script!\n");
}

#
# We need the project leader name.
#
if (! ($projhead = ProjLeader($pid))) {
    die("*** $0:\n".
	"    Could not get project leader for project $pid!\n");
}

122
123
124
125
126
127
128
129
130
131
#
# This script is always audited. Mail is sent automatically upon exit.
#
if (AuditStart(0)) {
    #
    # Parent exits normally
    #
    exit(0);
}

132
133
134
135
#
# Before we can proceed, we need to create the project (unix) group
# and then create an account for the project leader. We pass this off
# to sub scripts, but because they are also setuid, we need to flip
136
# our UID (perl sillyness).
137
#
138
$EUID = $UID;
139

140
141
system("$MKGROUP $pid $pid") == 0 or
    fatal("$MKGROUP $pid failed!");
142

143
144
145
146
if ($WIKISUPPORT) {
    system("$ADDWIKIPROJ $pid") == 0 or
	fatal("$ADDWIKIPROJ $pid failed!");
}
147
148
149
150
if ($BUGDBSUPPORT) {
    system("$ADDBUGDBPROJ $pid") == 0 or
	fatal("$ADDBUGDBPROJ $pid failed!");
}
151
152
153
154
if ($OPSDBSUPPORT) {
    system("$OPSDBCONTROL addproj $pid") == 0 or
	fatal("$OPSDBCONTROL addproj $pid failed!");
}
155
156
157
158
if ($MAILMANSUPPORT) {
    system("$ADDMMLIST -a ${pid}-users") == 0 or
	fatal("$ADDMMLIST -a ${pid}-users failed!");
}
159

160
161
162
system("$MKACCT $projhead") == 0 or
    fatal("$MKACCT $projhead failed!");

163
164
system("$MODGROUPS -a $pid:$pid:project_root $projhead") == 0 or
    fatal("$MODGROUPS -a $pid:$pid:project_root $projhead failed!");
165

166
$EUID = 0;
167
168
169
170
171
172
173
174
175
176
177
178
179

#
# This acts as check (and we need the numeric uid) in case mkacct failed!
# 
my (undef,undef,$uid) = getpwnam($projhead)
    or fatal("$projhead not in passwd file");

my (undef,undef,$gid) = getgrnam($pid)
    or fatal("$pid not in group file");

#
# Okay, do it.
#
180
181
182
183
if (! -e "$PROJROOT/$pid") {
    if (! mkdir("$PROJROOT/$pid", 0770)) {
	fatal("Could not make directory $PROJROOT/$pid: $!");
    }
184

185
186
187
    if (! chmod(0770, "$PROJROOT/$pid")) {
	fatal("Could not chmod directory $PROJROOT/$pid: $!");
    }
188

189
190
191
    if (! chown($uid, $gid, "$PROJROOT/$pid")) {
	fatal("Could not chown $PROJROOT/$pid to $uid/$gid: $!");
    }
192
193
194
195
196
197
}

#
# Make project subdirs.
#
foreach my $dir (@DIRLIST) {
198
199
200
201
202
203
204
205
206
207
    if (! -e "$PROJROOT/$pid/$dir") {
	if (! mkdir("$PROJROOT/$pid/$dir", 0770)) {
	    fatal("Could not make directory $PROJROOT/$pid/$dir: $!");
	}
	if (! chmod(0770, "$PROJROOT/$pid/$dir")) {
	    fatal("Could not chmod directory $PROJROOT/$pid/$dir: $!");
	}
	if (! chown($uid, $gid, "$PROJROOT/$pid/$dir")) {
	    fatal("Could not chown $PROJROOT/$pid/$dir to $uid/$gid: $!");
	}
208
209
210
211
212
    }
}

#
# Create a tftp directory for oskit kernels.
213
214
215
216
217
218
219
220
221
222
223
#
if (! -e "$TFTPROOT/proj/$pid") {
    if (! mkdir("$TFTPROOT/proj/$pid", 0770)) {
	fatal("Could not make directory $TFTPROOT/proj/$pid: $!");
    }
    if (! chmod(0777, "$TFTPROOT/proj/$pid")) {
	fatal("Could not chmod directory $TFTPROOT/proj/$pid: $!");
    }
    if (! chown($uid, $gid, "$TFTPROOT/proj/$pid")) {
	fatal("Could not chown $TFTPROOT/proj/$pid to $uid/$gid: $!");
    }
224
225
}

226
227
228
#
# Do the CVS stuff if its turned on.
#
229
230
if ($CVSSUPPORT) {
    my $CVSDIR = "$CVSREPOS/$pid";
231

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
    if (! -e "$CVSDIR") {
	if (! mkdir("$CVSDIR", 0770)) {
	    fatal("Could not make directory $CVSDIR: $!");
	}
    }
    if (! chmod(0770, "$CVSDIR")) {
	fatal("Could not chmod directory $CVSDIR: $!");
    }
    if (! chown($uid, $gid, "$CVSDIR")) {
	fatal("Could not chown $CVSDIR to $uid/$gid: $!");
    }
    if (! -e "$CVSDIR/CVSROOT") {
	system("$CVSBIN -d $CVSDIR init");
	if ($?) {
	    fatal("Could not cvs init $CVSDIR!");
	}
248
249
250
251
252
253
254
255
    }
    # Chown the tree.
    system("$CHOWN -R ${uid}:${gid} $CVSDIR");
    if ($?) {
	fatal("Could not chown ${uid}:${gid} $CVSDIR!");
    }
}

256
257
#
# Create groups directory.
258
259
260
261
262
#
if (! -e "$GRPROOT/$pid") {
    if (! mkdir("$GRPROOT/$pid", 0770)) {
	fatal("Could not make directory $GRPROOT/$pid: $!");
    }
263
    if (! chmod(0770, "$GRPROOT/$pid")) {
264
265
266
267
268
	fatal("Could not chmod directory $GRPROOT/$pid: $!");
    }
    if (! chown($uid, $gid, "$GRPROOT/$pid")) {
	fatal("Could not chown $GRPROOT/$pid to $uid/$gid: $!");
    }
269
270
271
272
273
274
275

    # Create a group link for the default group.
    if (! -e "$GRPROOT/$pid/$pid") {    
	if (system("ln -s $PROJROOT/$pid $GRPROOT/$pid/$pid")) {
	    fatal("Could not symlink $PROJROOT/$pid to $GRPROOT/$pid/$pid");
	}
    }
276
277
}

278
279
280
#
# Create experiment working directory.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
281
my $workdir = TBDB_EXPT_WORKDIR() . "/$pid";
282

283
if (! -e $workdir) {
284
    if (! mkdir("$workdir", 0775)) {
285
286
	fatal("Could not make directory $workdir: $!");
    }
287
    if (! chmod(0775, "$workdir")) {
288
289
290
291
292
	fatal("Could not chmod directory $workdir: $!");
    }
    if (! chown($uid, $gid, "$workdir")) {
	fatal("Could not chown $workdir to $uid/$gid: $!");
    }
293
294
}

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
#
# If approved to use remote nodes, then grant permission to use the
# specific types of virtual nodes on those remote physical nodes.
# Unfortunately, the node_types table does not store a relationship
# between the phys type and the virtual types that are hosted on them.
# Need to add that I guess, but in the meantime we have just 3 remote
# phys types to worry about. 
#
my $query_result =
    DBQueryFatal("select pcremote_ok from projects where pid='$pid'");
if ($query_result->num_rows) {
    my ($pcremote) = $query_result->fetchrow_array();

    if (defined($pcremote)) {
	print "$pcremote\n";
	
	foreach my $type (split(",", $pcremote)) {
	    print "$type\n";
	    
	    if ($type eq "pcplabphys") {
		$type = "pcplab";
	    }
	    elsif ($type eq "pcron") {
		$type = "pcvwa";
	    }
	    elsif ($type eq "pcwa") {
		$type = "pcvwa";
	    }
	    else {
		fatal("Unknown remote type $type!");
	    }
	    print "$type\n";
327
328
329

	    $EUID = $UID;

330
331
	    system("$GRANTTYPE -p $pid $type") == 0 or
		fatal("Could not grant permission to use type $type!");
332
333

	    $EUID = 0;
334
335
336
337
	}
    }
}

338
print "Project Creation Completed!\n";
339
340
exit(0);

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

344
345
    die("*** $0:\n".
	"    $mesg\n");
346
}