firstuser.in 8.79 KB
Newer Older
1
#!/usr/bin/perl -w
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
#
3
# Copyright (c) 2000-2016 University of Utah and the Flux Group.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
23
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
24 25 26
#
# WARNING: See db/genelists.in for clause testing for protouser names.
#
27
use English;
28
use strict;
29
use Getopt::Std;
30 31 32

use lib '@prefix@/lib';
use libdb;
33
use libtestbed;
34
use User;
35
use emutil;
36

37 38
my $tbadmin    = '@TBADMINGROUP@';
my $ELABINELAB = @ELABINELAB@;
39 40
my $MINUID     = @MIN_UNIX_UID@;
my $MINGID     = @MIN_UNIX_GID@;
41

42 43 44
my $wap     = '@prefix@/sbin/withadminprivs';
my $mkproj  = '@prefix@/sbin/mkproj';
my $mkgroup = '@prefix@/sbin/mkgroup';
45
my $mkacct  = '@prefix@/sbin/tbacct';
46
my $modgrps = '@prefix@/sbin/modgroups';
47

48 49
my $acctproxy = '@prefix@/sbin/accountsetup';

50 51 52
my $protouser       = 'elabman';
my $protouser_name  = 'Emulab Manager';
my $protouser_email = '@TBOPSEMAIL@';
53
my $protouser_shell = 'tcsh';
54
my $protouser_notes = "DO NOT DELETE THIS ACCOUNT!";
55
my $HOMEDIR         = USERROOT();
56 57
my $protoproj       = 'emulab-ops';
my $protoproj_desc  = 'Operations Meta-Project';
58
my $batchmode       = 0;
59
my $pid_idx         = 1; # Initial IDX for protoproj.
60
my $trust           = "project_root";
61
my $binshell        = "/bin/nologin";
62 63
my $uid_uuid;
my $gid_uuid;
64
my $password;
65
my $encpass;
66
my %opts;
67
my $mailman_password;
68

69 70 71
my $CONTROL	= "@USERNODE@";
my $BOSSNODE	= "@BOSSNODE@";

72 73 74 75
#
# Handle command-line options
#
sub usage {
76
    print "Usage: firstuser [-b] [-p password] [-u user] [-n name] [-e email]\n";
77 78
    exit(1);
}
79
if (! getopts("bp:u:n:e:", \%opts)) {
80 81 82 83 84 85 86 87
    usage();
}
if (defined($opts{b})) {
    $batchmode = 1;
}
if (defined($opts{p})) {
    $password = $opts{p};
}
88 89 90 91 92 93 94 95 96 97
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};
}
98

99 100 101
my $user = User->Lookup('$protouser');
if (defined($user)) {
    die("This script has already been run, no need to run it again!\n");
102 103
}

104 105
if ($UID != 0) {
    die "Sorry, this must be run as root\n";
106 107
}

108 109 110 111 112
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";
}
113

114 115 116
# Need this for mailman support; harmless.
$mailman_password = substr(TBGenSecretKey(), 0, 10);

117
# Get a password for the user
118
if (!defined($password)) {
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    #
    # 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)) {
134
    $encpass = PassWordHash($password);
135
}
136

137
# Get uid for the user and a gid for the project
138 139

# For non-initial users, get the next available index.
140
my $result = DBQueryFatal("select idx from emulab_indicies ".
141 142 143 144 145
		       "where name='next_uid'");
if ($result->numrows() > 0) {
    ($MINUID) = $result->fetchrow_array();
}

146
my $uid = $MINUID;
147
while (getpwuid($uid)) { $uid++; }
148

149
my $gid = $MINGID;
150 151
while (getgrgid($gid)) { $gid++; }

152 153 154 155 156
# 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";
157
}
158 159
# And in the wheel group so elabman can sudo to root.
my $Ggid = "wheel";
160 161 162 163

if (defined($opts{u})) {
    $Ggid .= " $protoproj";
}
164
    
165 166 167 168 169
if (!$batchmode) {
    print "Creating user/project: Are you sure? (Y/N) ";
    if (<> !~ /Y/i) {
	die "Aborted\n";
    }
170 171
}

172 173 174 175 176 177 178 179
# 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!";
}

180
print "Creating user on boss...\n";
181 182 183 184
my $makeopt = "";
if ($CONTROL eq $BOSSNODE) {
    $makeopt = "-m";
}
185 186
if (system("/usr/sbin/pw useradd $protouser -u $uid -g $agid ".
	   "-G \"$Ggid\" -h - " .
187
	   "$makeopt -d $HOMEDIR/$protouser -s $binshell ".
188 189
	   "-c \"$protouser_name\"")) {
    die "Unable to add user to the password file!\n";
190 191
}

192 193 194
if ($CONTROL ne $BOSSNODE) {
    print "Creating user on ops...\n";
    
195
    if (system("ssh -2 $CONTROL ".
196 197 198 199
	       "'$acctproxy adduser $protouser $uid \"$protouser_name\" ".
	       "$HOMEDIR/$protouser $agid $binshell'") ||
	system("ssh -2 $CONTROL ".
	       "'$acctproxy setgroups $protouser $agid $Ggid'")) {
200 201 202 203
	die "Unable to add user to the ops password file!\n";
    }
}

204 205 206
# These users do not really need a uuid, but give them one anyway.
$uid_uuid = NewUUID();

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

210
print "Creating user in database...\n";
211
DBQueryFatal("insert into users set uid='$protouser', usr_created=now(), " .
212
	     "usr_name='$protouser_name', uid_uuid='$uid_uuid', ".
213
	     "usr_addr='DO NOT DELETE THIS ACCOUNT', ".
214
	     "nocollabtools=1, ".
215 216 217 218
	     "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");
219 220
DBQueryFatal("insert into user_stats set ".
	     "  uid='$protouser', uid_idx=$uid, uid_uuid='$uid_uuid'");
221

222
if (!defined($opts{u})) {
223
    $gid_uuid = NewUUID();
224 225 226 227
    
    print "Creating project in database...\n";
    DBQueryFatal("insert into projects set pid='$protoproj', created=now(), " .
		 "name='$protoproj_desc', head_uid='$protouser', ".
228
		 "head_idx=$uid, unix_gid=$gid,approved=1,pid_idx=$pid_idx");
229
    DBQueryFatal("insert into project_stats set ".
230
		 "pid='$protoproj',pid_idx=$pid_idx");
231 232 233

    print "Creating group in database...\n";
    DBQueryFatal("insert into groups set pid='$protoproj', gid='$protoproj', ".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
234
		 "leader='$protouser', leader_idx=$uid, created=now(), ".
235
		 "description='Default Group', " .
236
		 "unix_gid=$gid, gid_idx=$pid_idx, pid_idx=$pid_idx, ".
237
		 "unix_name='$protoproj', gid_uuid='$gid_uuid'");
238
    DBQueryFatal("insert into group_stats set ".
239 240
		 "   pid='$protoproj',gid='$protoproj', ".
		 "   gid_idx=$pid_idx, gid_uuid='$gid_uuid'");
241

242
    DBQueryFatal("replace into emulab_indicies set name='next_gid',idx=10000");
243 244 245 246 247 248 249 250 251 252 253

    #
    # Do this, cause after mkproj below, the extra groups are going to
    # be removed. 
    #
    DBQueryFatal("insert into unixgroup_membership set ".
		 " uid='$protouser', uid_idx='$uid', gid='$tbadmin' ");
    DBQueryFatal("insert into unixgroup_membership set ".
		 " uid='$protouser', uid_idx='$uid', gid='wheel' ");
    DBQueryFatal("insert into unixgroup_membership set ".
		 " uid='$protouser', uid_idx='$uid', gid='mysql' ");
254
}
255

256 257 258 259 260
# 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;

261 262 263 264 265 266 267 268
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";
269
    }
270

271 272 273
    print "Running modgroups...\n";
    if (system "$wap $modgrps -a $protoproj:$protoproj:$trust $protouser") {
	die "Unable to add initial user $protouser to project $protoproj\n";
274
    }
Mike Hibler's avatar
Mike Hibler committed
275
}
276 277 278 279 280 281 282 283
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
284
}
285

286 287 288 289
if (defined($opts{u})) {
    exit(0);
}

290 291 292 293 294 295 296 297
#
# 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");
}

298
print "User created. Once the web page is up, you should be able to log in\n";
299 300 301
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";