firstuser.in 7.61 KB
Newer Older
1
#!/usr/bin/perl -w
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
#
# EMULAB-COPYRIGHT
4
# Copyright (c) 2000-2008 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
5
6
# All rights reserved.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
7
8
9
#
# WARNING: See db/genelists.in for clause testing for protouser names.
#
10
use English;
11
use strict;
12
use Getopt::Std;
13
14
15

use lib '@prefix@/lib';
use libdb;
16
use libtestbed;
17
use User;
18

19
20
my $tbadmin    = '@TBADMINGROUP@';
my $ELABINELAB = @ELABINELAB@;
21
22
my $MINUID     = @MIN_UNIX_UID@;
my $MINGID     = @MIN_UNIX_GID@;
23

24
25
26
my $wap     = '@prefix@/sbin/withadminprivs';
my $mkproj  = '@prefix@/sbin/mkproj';
my $mkgroup = '@prefix@/sbin/mkgroup';
27
my $mkacct  = '@prefix@/sbin/tbacct';
28
my $modgrps = '@prefix@/sbin/modgroups';
29

30
31
32
my $protouser       = 'elabman';
my $protouser_name  = 'Emulab Manager';
my $protouser_email = '@TBOPSEMAIL@';
33
my $protouser_shell = 'tcsh';
34
my $protouser_notes = "DO NOT DELETE THIS ACCOUNT!";
35
my $HOMEDIR         = USERROOT();
36
37
my $protoproj       = 'emulab-ops';
my $protoproj_desc  = 'Operations Meta-Project';
38
my $batchmode       = 0;
39
my $pid_idx         = 1; # Initial IDX for protoproj.
Timothy Stack's avatar
   
Timothy Stack committed
40
my $trust           = "project_root";
41
my $binshell        = "/bin/nologin";
42
43
my $uid_uuid;
my $gid_uuid;
44
my $password;
45
my $encpass;
46
my %opts;
47
my $mailman_password;
48

Timothy Stack's avatar
   
Timothy Stack committed
49
50
51
my $CONTROL	= "@USERNODE@";
my $BOSSNODE	= "@BOSSNODE@";

52
53
54
55
#
# Handle command-line options
#
sub usage {
Timothy Stack's avatar
   
Timothy Stack committed
56
    print "Usage: firstuser [-b] [-p password] [-u user] [-n name] [-e email]\n";
57
58
    exit(1);
}
Timothy Stack's avatar
   
Timothy Stack committed
59
if (! getopts("bp:u:n:e:", \%opts)) {
60
61
62
63
64
65
66
67
    usage();
}
if (defined($opts{b})) {
    $batchmode = 1;
}
if (defined($opts{p})) {
    $password = $opts{p};
}
Timothy Stack's avatar
   
Timothy Stack committed
68
69
70
71
72
73
74
75
76
77
if (defined($opts{u})) {
    $protouser = $opts{u};
    $trust = "local_root";
}
if (defined($opts{n})) {
    $protouser_name = $opts{n};
}
if (defined($opts{e})) {
    $protouser_email = $opts{e};
}
78

79
80
81
my $user = User->Lookup('$protouser');
if (defined($user)) {
    die("This script has already been run, no need to run it again!\n");
82
83
}

84
85
if ($UID != 0) {
    die "Sorry, this must be run as root\n";
86
87
}

Timothy Stack's avatar
   
Timothy Stack committed
88
89
90
91
92
if (!defined($opts{u})) {
    print "This script will create the 'proto-user' $protouser, which you will\n";
    print "use to bootstrap other users. It also creates the emulab-ops\n";
    print "meta-project.\n\n";
}
93

94
95
96
# Need this for mailman support; harmless.
$mailman_password = substr(TBGenSecretKey(), 0, 10);

97
# Get a password for the user
98
if (!defined($password)) {
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    #
    # In batch mode, we get it from the root user password entry.
    # Otherwise prompt user for it.
    #
    if ($batchmode) {
	(undef,$encpass) = getpwnam("root") or
	    die("No root user!\n");
    }
    else {
	print "Pick a password for $protouser (warning, will be echoed): ";
	$password = <>;
	chomp($password);
    }
}
if (!defined($encpass)) {
    my @salt_chars = ('a'..'z','A'..'Z','0'..'9');
    my $salt = $salt_chars[rand(@salt_chars)] .
	       $salt_chars[rand(@salt_chars)];
    $encpass = crypt($password, "\$1\$${salt}");
118
}
119

120
# Get uid for the user and a gid for the project
121
122

# For non-initial users, get the next available index.
123
my $result = DBQueryFatal("select idx from emulab_indicies ".
124
125
126
127
128
		       "where name='next_uid'");
if ($result->numrows() > 0) {
    ($MINUID) = $result->fetchrow_array();
}

129
my $uid = $MINUID;
130
while (getpwuid($uid)) { $uid++; }
131

132
my $gid = $MINGID;
133
134
while (getgrgid($gid)) { $gid++; }

135
136
137
138
139
# We put the proto-user in the tbadmin group, because the emulab-ops
# group does not exist yet
my $agid = (getgrnam($tbadmin))[2];
if (!defined $agid) {
    die "Unable to get group ID for $tbadmin\n";
140
}
141
142
# And in the wheel group so elabman can sudo to root.
my $Ggid = "wheel";
Timothy Stack's avatar
   
Timothy Stack committed
143
144
145
146

if (defined($opts{u})) {
    $Ggid .= " $protoproj";
}
147
    
148
149
150
151
152
if (!$batchmode) {
    print "Creating user/project: Are you sure? (Y/N) ";
    if (<> !~ /Y/i) {
	die "Aborted\n";
    }
153
154
}

155
156
157
158
159
160
161
162
# Initial protouser gets a real shell until actively frozen later.
# Also setup a notes entry.
if (!defined($opts{u})) {
    $binshell = "/bin/tcsh";
    $protouser_notes = "This account can be frozen after your Emulab ".
	"is fully setup and running. DO NOT DELETE THIS ACCOUNT!";
}

163
print "Creating user on boss...\n";
164
165
166
167
168
if (system("/usr/sbin/pw useradd $protouser -u $uid -g $agid ".
	   "-G \"$Ggid\" -h - " .
	   "-m -d $HOMEDIR/$protouser -s $binshell ".
	   "-c \"$protouser_name\"")) {
    die "Unable to add user to the password file!\n";
169
170
}

Timothy Stack's avatar
   
Timothy Stack committed
171
172
173
if ($CONTROL ne $BOSSNODE) {
    print "Creating user on ops...\n";
    
174
    if (system("ssh -2 $CONTROL ".
Timothy Stack's avatar
   
Timothy Stack committed
175
	       "'/usr/sbin/pw useradd $protouser -u $uid -g $agid ".
176
	       "-G \"$Ggid\" -h - -d $HOMEDIR/$protouser -s $binshell ".
Timothy Stack's avatar
   
Timothy Stack committed
177
178
179
180
181
	       "-c \"$protouser_name\"'")) {
	die "Unable to add user to the ops password file!\n";
    }
}

182
183
184
# These users do not really need a uuid, but give them one anyway.
$uid_uuid = NewUUID();

185
# Initialize the index value;
186
DBQueryFatal("replace into emulab_indicies set name='next_uid',idx=$uid+1");
187

188
print "Creating user in database...\n";
189
DBQueryFatal("insert into users set uid='$protouser', usr_created=now(), " .
190
	     "usr_name='$protouser_name', uid_uuid='$uid_uuid', ".
191
192
193
194
195
	     "usr_addr='DO NOT DELETE THIS ACCOUNT', ".
	     "usr_pswd='$encpass', unix_uid=$uid, notes='$protouser_notes', ".
	     "usr_modified=now(), admin=1, webonly=0, status='active',".
	     "usr_shell='$protouser_shell', usr_email='$protouser_email', ".
	     "mailman_password='$mailman_password',uid_idx=$uid");
196
197
DBQueryFatal("insert into user_stats set ".
	     "  uid='$protouser', uid_idx=$uid, uid_uuid='$uid_uuid'");
198

Timothy Stack's avatar
   
Timothy Stack committed
199
if (!defined($opts{u})) {
200
    $gid_uuid = NewUUID();
Timothy Stack's avatar
   
Timothy Stack committed
201
202
203
204
    
    print "Creating project in database...\n";
    DBQueryFatal("insert into projects set pid='$protoproj', created=now(), " .
		 "name='$protoproj_desc', head_uid='$protouser', ".
205
		 "head_idx=$uid, unix_gid=$gid,approved=1,pid_idx=$pid_idx");
206
    DBQueryFatal("insert into project_stats set ".
207
		 "pid='$protoproj',pid_idx=$pid_idx");
Timothy Stack's avatar
   
Timothy Stack committed
208
209
210

    print "Creating group in database...\n";
    DBQueryFatal("insert into groups set pid='$protoproj', gid='$protoproj', ".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
211
		 "leader='$protouser', leader_idx=$uid, created=now(), ".
Timothy Stack's avatar
   
Timothy Stack committed
212
		 "description='Default Group', " .
213
		 "unix_gid=$gid, gid_idx=$pid_idx, pid_idx=$pid_idx, ".
214
		 "unix_name='$protoproj', gid_uuid='$gid_uuid'");
215
    DBQueryFatal("insert into group_stats set ".
216
217
		 "   pid='$protoproj',gid='$protoproj', ".
		 "   gid_idx=$pid_idx, gid_uuid='$gid_uuid'");
218

219
220
    DBQueryFatal("replace into emulab_indicies set name='next_gid',idx=10000");
}
221

222
223
224
225
226
# Flip UID to the new user so that the mk* scripts are happy - they can't
# be run as root for accountability reasons
$EUID = $UID = $uid;
$EGID = $GID = $gid;

227
228
229
230
231
232
233
234
if (defined($opts{u})) {
    #
    # Creating specific user; it is implied that the user will go into
    # the proto project, which must already exist of course.
    #
    print "Running mkacct...\n";
    if (system "$wap $mkacct -b add $protouser") {
	die "Unable to create account for initial user $protouser\n";
Timothy Stack's avatar
   
Timothy Stack committed
235
    }
236

237
238
239
    print "Running modgroups...\n";
    if (system "$wap $modgrps -a $protoproj:$protoproj:$trust $protouser") {
	die "Unable to add initial user $protouser to project $protoproj\n";
Timothy Stack's avatar
   
Timothy Stack committed
240
    }
Mike Hibler's avatar
Mike Hibler committed
241
}
242
243
244
245
246
247
248
249
else {
    #
    # Creating the initial project. This handles everything.
    #
    print "Running mkproj...\n";
    if (system "$wap $mkproj $protoproj") {
	die "Unable to create initial project $protoproj\n";
    }
Mike Hibler's avatar
Mike Hibler committed
250
}
251

Timothy Stack's avatar
   
Timothy Stack committed
252
253
254
255
if (defined($opts{u})) {
    exit(0);
}

256
257
258
259
260
261
262
263
#
# Okay, if not ELABINELAB, then set the firstinitstate so that the web
# interface will take the user through his first project setup.
#
if (!$ELABINELAB) {
    TBSetSiteVar("general/firstinit/state", "createproject");
}

264
print "User created. Once the web page is up, you should be able to log in\n";
265
266
267
print "as '$protouser' with the password you just entered. Refer to\n";
print "setup-db.txt for instructions on creating a 'real' user account for\n";
print "yourself.\n";