Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
emulab
emulab-devel
Commits
e5e03b1a
Commit
e5e03b1a
authored
Jun 05, 2001
by
Leigh B. Stoller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rewrite this piece of you know what. It was barely readable as it was.
parent
f8c96138
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
257 additions
and
256 deletions
+257
-256
tbsetup/mkacct-ctrl.in
tbsetup/mkacct-ctrl.in
+257
-256
No files found.
tbsetup/mkacct-ctrl.in
View file @
e5e03b1a
#!/usr/local/bin/perl -wT
use
English
;
use
Mysql
;
#
# Create accounts.
#
# XXX - The control node is hardwired. Look for $CONTROL.
#
# usage: mkacct-ctrl <userid>
#
#
# Configure variables
#
my
$TB
=
"
@prefix
@
";
my
$
DBNAME
=
"
@TB
DBNAME
@
";
my
$
TBOPS
=
"
@TB
OPSEMAIL
@
";
my
$HOMEDIR
=
"
/users
";
my
$PBAG
=
"
$TB
/sbin/paperbag
";
my
$
ssh
=
"
ssh
";
my
$
SSH
=
"
ssh
";
my
$CONTROL
=
"
users.emulab.net
";
my
$GROUPADD
=
"
/usr/sbin/pw groupadd
";
my
$USERADD
=
"
/usr/sbin/pw useradd
";
my
$USERMOD
=
"
/usr/sbin/pw usermod
";
my
$CHPASS
=
"
/usr/bin/chpass
";
my
$me
;
# alphanumeric username of $UID
my
$user
;
my
@db_row
;
my
$query_result
;
my
$user
;
# kwright
my
$pid
;
# 6009
#
# We don't want to run this script unless its the real version.
#
if
(
$EUID
!=
0
)
{
die
("
Must be root! Maybe its a development version?
");
}
my
$dbh
;
# database handle
my
$sth
;
# statement handle
my
@db_row
;
my
$db_query
;
#
# Untaint the path
#
$ENV
{'
PATH
'}
=
"
/bin:/usr/bin
";
delete
@ENV
{'
IFS
',
'
CDPATH
',
'
ENV
',
'
BASH_ENV
'};
sanitize
();
dbsetup
();
check_credentials
();
dowork
();
print
"
$0 finished sucessfully.
\n
";
exit
(
0
);
#
# Turn off line buffering on output
#
$|
=
1
;
#
# Load the Testbed support stuff.
#
push
(
@INC
,
"
$TB
/lib
");
require
libtestbed
;
require
libdb
;
sub
dbsetup
()
{
$dbh
=
Mysql
->
connect
("
localhost
",
$DBNAME
,
"
script
",
"
none
");
#
# Check args.
#
if
(
$#ARGV
<
0
)
{
die
("
Usage: mkacct-ctrl <userid>
\n
");
}
$user
=
$ARGV
[
0
];
#
#
Figure out who called us. There are 3 possible scenarios:
#
Untaint the argument.
#
# 1) Called from web UI as some TB admin user from the database
# to create a project head's
# account for a new project (called from approveproject.php3).
if
(
$user
=~
/^([a-z0-9]+)$/i
)
{
$user
=
$
1
;
}
else
{
die
("
Invalid uid '
$user
' contains illegal characters.
\n
");
}
#
# Figure out who called us. Possible scenarios:
#
# 1) Called from web UI as some TB admin user to create a project head's
# account for a new project.
#
# 2) Called as user with group_root for project to create a user
# account
(from approveuser.php3)
.
# account.
#
# 3) Called from command line as user with group_root for project
# to create a user account.
#
# 4) Called from command line as root.
#
sub
check_credentials
()
{
print
"
Credential check:
";
#
# Make sure the UID is a valid UID in this machine's passwd file
#
my
(
$me
)
=
getpwuid
(
$UID
)
or
die
"
$0:
$UID
not in passwd file
";
print
"
$UID
\n
";
#
# Check if we're root
#
if
(
$UID
==
0
)
{
print
"
Root user allowed.
\n
";
return
;
}
if
(
$UID
&&
!
TBAdmin
(
$UID
))
{
my
(
$me
)
=
getpwuid
(
$UID
)
or
fatal
("
$UID
not in passwd file
");
#
#
User could be an admin user
.
#
Check if group_root for the project
.
#
$sth
=
$dbh
->
query
("
select admin from users where uid='
$me
' and admin=1
");
if
(
got_tuples
(
$sth
))
{
print
"
Testbed admin user allowed.
\n
";
return
;
}
#
# Last resort: check if group_root for $project
#
$db_query
=
"
select p1.trust from proj_memb as p1
"
.
$query_result
=
DBQueryFatal
("
select p1.trust from proj_memb as p1
"
.
"
left join proj_memb as p2 on p2.pid=p1.pid
"
.
"
where p1.uid='
$me
' and p2.uid='
$user
' and p1.trust='group_root'
";
$sth
=
$dbh
->
query
(
$db_query
);
if
(
got_tuples
(
$sth
))
{
print
"
Group_root privileges allowed.
\n
";
return
;
}
"
where p1.uid='
$me
' and
"
.
"
p2.uid='
$user
' and p1.trust='group_root'
");
#
# If we're here, we do not have the correct credentials
#
print
"
Not root, a TB admin user, or group_root for
${user}
's project. Failed.
\n
";
exit
(
1
);
if
(
$query_result
->
numrows
==
0
)
{
die
("
$0:
$me
does not have enough permission in
${user}
's project
");
}
}
###
### Find the right control node. Create an account for given
### user with correct user info.
###
sub
dowork
()
{
#
# Get the user info (the the user being created).
#
$query_result
=
DBQueryFatal
("
select usr_pswd,unix_uid,usr_name,usr_email
"
.
"
from users where uid='
$user
'
");
if
(
$query_result
->
numrows
==
0
)
{
fatal
("
$user
is not in the DB. This is bad.
\n
");
}
@db_row
=
$query_result
->
fetchrow_array
();
my
$pswd
=
$db_row
[
0
];
my
$user_number
=
$db_row
[
1
];
my
$fullname
=
$db_row
[
2
];
my
$user_email
=
$db_row
[
3
];
my
$control_node
;
my
$pswd
;
my
$user_number
;
# 1025
my
$user_email
;
# foo@bar
my
$fullname
;
# Kristin Wright
my
@groupnames
;
# lkwbox (same as projects)
my
%groupnumbers
;
# 6001
#
# Get the group (projects user belongs to) names and numbers.
#
my
@groupnames
;
my
%groupnumbers
;
my
@grouplist
;
#
# Find control node.
# Note: In the end, I simply assign to 'plastic' as control nodes
# not yet set in the database. 11/30/00 -lkw
#
#$db_query = "select control_node from projects where pid='$project'";
#$sth = $dbh->query($db_query);
#got_tuples($sth) or die "$0: Error selecting control_node.\n";
#@db_row = $sth->fetchrow_array();
#$control_node = $db_row[0];
$control_node
=
$CONTROL
;
# see note above
# get user info
$db_query
=
"
select usr_pswd,unix_uid,usr_name,usr_email
"
.
"
from users where uid='
$user
'
";
$sth
=
$dbh
->
query
(
$db_query
);
got_tuples
(
$sth
)
or
die
"
$0: Error selecting user fields.
\n
";
@db_row
=
$sth
->
fetchrow_array
();
$pswd
=
$db_row
[
0
];
$user_number
=
$db_row
[
1
];
$fullname
=
$db_row
[
2
];
$user_email
=
$db_row
[
3
];
# get group names
$db_query
=
"
select pid from proj_memb where uid='
$user
'
"
.
"
and trust!='none'
";
$sth
=
$dbh
->
query
(
$db_query
);
got_tuples
(
$sth
)
or
die
"
$0: Error selecting group names.
\n
";
while
(
@db_row
=
$sth
->
fetchrow_array
()
)
{
#
# Form a list project membership names.
#
$query_result
=
DBQueryFatal
("
select pid from proj_memb where
"
.
"
uid='
$user
' and trust!='none'
");
if
(
$query_result
->
numrows
==
0
)
{
fatal
("
$user
is not in any groups!
\n
");
}
while
(
@db_row
=
$query_result
->
fetchrow_array
()
)
{
push
(
@groupnames
,
$db_row
[
0
]);
}
my
@grouplist
=
map
(
"
pid='
$_
'
",
@groupnames
);
}
# get group numbers
$db_query
=
"
select pid,unix_gid from projects where
"
.
join
("
or
",
@grouplist
);
$sth
=
$dbh
->
query
(
$db_query
);
got_tuples
(
$sth
)
or
die
"
$0: Error selecting group numbers.
\n
";
while
(
@db_row
=
$sth
->
fetchrow_array
())
{
$groupnumbers
{
$db_row
[
0
]}
=
$db_row
[
1
];
}
#
# Now join that list with the projects information to the unix gids.
#
$query_result
=
DBQueryFatal
("
select pid,unix_gid from projects where
"
.
join
("
or
",
map
(
"
pid='
$_
'
",
@groupnames
)));
if
(
$query_result
->
numrows
==
0
)
{
fatal
("
Could not get the unix GIDs for the projects!
\n
");
}
# Should probably check to make sure the counts match.
while
(
@db_row
=
$query_result
->
fetchrow_array
())
{
$groupnumbers
{
$db_row
[
0
]}
=
$db_row
[
1
];
}
# Add some special cases for developers/admins
$sth
=
$dbh
->
query
("
select admin from users where uid='
$user
' and admin=1
");
if
(
got_tuples
(
$sth
))
{
# I'm an admin, so add me to some groups:
#
# Add some special cases for admin types. Note hardwired gids!
#
if
(
TBAdmin
(
$user
))
{
push
(
@groupnames
,
"
wheel
",
"
flux
");
$groupnumbers
{"
wheel
"}
=
0
;
$groupnumbers
{"
flux
"}
=
601
;
}
$groupnumbers
{"
wheel
"}
=
0
;
$groupnumbers
{"
flux
"}
=
601
;
}
# Assume FreeBSD for both nodes, since we control them.
#
# Note hardwired control node.
#
my
$control_node
=
$CONTROL
;
# The following user/group creation commands must be done as root.
$UID
=
$EUID
;
#
# Create groups on both the control and operations nodes. We assume
# FreeBSD for both.
#
# All this stuff must be done as root (ssh).
#
$UID
=
$EUID
;
foreach
my
$group
(
@groupnames
)
{
my
$group_number
=
$groupnumbers
{
$group
};
print
"
Processing group
$group
(gid
$group_number
)
\n
";
foreach
$group
(
@groupnames
)
{
$group_number
=
$groupnumbers
{
$group
};
print
"
Checking for group
$group
(gid
$group_number
)
\n
";
#
# Create groups on paper if they don't exist.
# Create group locally if it does not exist. egrep returns 1 when
# no matches are found.
#
if
(
`
egrep
'^
${group}
:' /etc/group
`
eq
"
")
{
if
(
system
("
egrep -q -s
'^
${group}
:' /etc/group
"
)
)
{
print
"
Adding group
$group
to paper
\n
";
system
("
/usr/sbin/pw groupadd
$group
-g
$group_number
")
==
0
or
print
STDERR
"
Could not add group
$group
with gid
$group_number
to paper
\n
";
}
else
{
print
"
Group
$group
already exists on paper.
\n
";
}
if
(
system
("
$GROUPADD
$group
-g
$group_number
"))
{
fatal
("
Could not add
$group
(
$group_number
) to local node!
\n
");
}
}
#
# Mak
e group
s
on control node if
they don'
t exist.
# Creat
e group on
the
control node if
it does no
t exist.
#
if
(
`
$ssh
$control_node
egrep '^
${group}
:' /etc/group
`
eq
"
")
{
if
(
system
("
$SSH
$control_node
egrep
-q -s
'^
${group}
:' /etc/group
")
)
{
print
"
Adding group
$group
to
$control_node
.
\n
";
system
("
$ssh
$control_node
/usr/sbin/pw groupadd
$group
-g
"
.
"
$group_number
")
==
0
or
print
STDERR
"
Could not add group
$group
with gid
$group_number
to
$control_node
\n
";
}
else
{
print
"
Group
$group
already exists on
$control_node
.
\n
";
}
}
# Main project is first on list, rest go into new list
$project
=
shift
@groupnames
;
$grouplist
=
join
("
,
",
@groupnames
);
if
(
$grouplist
)
{
$groupargument
=
"
-G
$grouplist
";
if
(
system
("
$SSH
$control_node
$GROUPADD
$group
-g
$group_number
"))
{
fatal
("
Could not add
$group
(
$group_number
) to
$control_node
!
\n
");
}
else
{
$groupargument
=
"
";
}
}
#
# Make user on paper. We don't give them a password.
#
if
(`
egrep '^
${user}
:' /etc/passwd
`
eq
"")
{
print
"
Adding user
$user
to paper.
\n
";
system
("
/usr/sbin/pw useradd
$user
-u
$user_number
-c
\"
$fullname
\"
"
.
"
-k /usr/share/skel -m -d /users/
$user
"
.
"
-g
$project
$groupargument
-s
$PBAG
")
==
0
or
print
STDERR
"
Could not add user
$user
to paper
\n
";
}
else
{
print
"
User
$user
already exists on paper. Updating record.
\n
";
# MAKE SURE not to update the shell... if its someone who gets tcsh on
# paper, we don't want to paperbag them...
system
("
/usr/sbin/pw usermod
$user
-u
$user_number
-c
\"
$fullname
\"
"
.
"
-g
$project
$groupargument
")
==
0
or
print
STDERR
"
Could not modify user
$user
on paper
\n
";
}
#
# Construct an appropriate group list for the pw commands. Main project
# is the first on the list, and that becomes the primary group. The rest
# (if any) of the groups become a comma separated list for the -G option.
#
my
$groupargument
=
"
";
my
$project
=
shift
@groupnames
;
my
$grouplist
=
join
("
,
",
@groupnames
);
#
# Make user on control node. Note that we cannot get back any output from
# a command that we open for input so we divide acct creation into two
# pieces to maximize feedback. First we add the user account. Then we
# change the password.
#
# Quote special chars for ssh and the shell on the other side
$fullname
=~
s/\"/\'/g
;
$fullname
=~
s/([^\\])([\'\"\(\)])/$1\\$2/g
;
if
(`
$ssh
$control_node
egrep '^
${user}
:' /etc/passwd
`
eq
"")
{
print
"
Adding user
$user
to
$control_node
.
\n
";
$str
=
"
$ssh
$control_node
"
.
"
'/usr/sbin/pw useradd
$user
-u
$user_number
-c
\"
$fullname
\"
"
.
"
-k /usr/share/skel -m -d /users/
$user
-g
$project
"
.
"
$groupargument
-s /bin/tcsh'
";
system
(
$str
)
==
0
or
print
STDERR
"
Could not add user
$user
to
$control_node
.
\n
";
system
("
$ssh
$control_node
"
.
"
/usr/bin/chpass -p
$pswd
$user
")
==
0
or
print
STDERR
"
Could not change password for user
$user
on
$control_node
.
\n
";
}
else
{
print
"
User
$user
already exists on
$control_node
. Updating record.
\n
";
# DO NOT mess with the quoting... you have to escape all the escapes,
# because perl does the escapes once, then ssh takes them again,
# so \\\" becomes " by the time the shell gets it.
$str
=
"
$ssh
$control_node
"
.
"
'/usr/sbin/pw usermod
$user
-u
$user_number
"
.
"
-c
\"
$fullname
\"
-g
$project
$groupargument
'
";
system
(
$str
)
==
0
or
print
STDERR
"
Could not modify user
$user
on
$control_node
.
\n
";
system
("
$ssh
$control_node
"
.
"
/usr/bin/chpass -p
$pswd
$user
")
==
0
or
print
STDERR
"
Could not change password for user
$user
on
$control_node
.
\n
";
}
if
(
$grouplist
)
{
$groupargument
=
"
-G
$grouplist
";
}
#
# Set up the ssh key
#
#
# Make user on local. We don't give them a password since they are not
# allowed to log in, except via paperbaf. Be sure not overwrite the shell
# for a user who has a real shell.
#
if
(
system
("
egrep -q -s '^
${user}
:' /etc/passwd
"))
{
print
"
Adding user
$user
(
$user_number
) to local node.
\n
";
if
(
!
-
e
"
/users/
$user
/.ssh/
"
)
{
# Only do this if its not been done before.
print
"
Setting up ssh data...
\n
";
mkdir
("
/users/
$user
/.ssh
",
0700
);
chown
(
$user_number
,
$group_number
,
"
/users/
$user
/.ssh
");
# Run commands below as the user
$EUID
=
$user_number
;
$UID
=
$EUID
;
print
"
EUID:
$EUID
UID:
$UID
\n
";
open
(
KEYGEN
,
"
/usr/bin/ssh-keygen -P '' -f /users/
$user
/.ssh/identity 2>&1 |
");
while
(
<
KEYGEN
>
)
{
print
$_
;
}
close
(
KEYGEN
);
open
(
CP
,
"
/bin/cp /users/
$user
/.ssh/identity.pub /users/
$user
/.ssh/authorized_keys 2>&1 |
");
while
(
<
CP
>
)
{
print
$_
;
}
close
(
CP
);
chmod
(
0600
,
"
/users/
$user
/.ssh/authorized_keys
");
}
else
{
print
"
SSH data in /users/
$user
/.ssh/ appears to exist. Skipping.
\n
";
if
(
system
("
$USERADD
$user
-u
$user_number
-c
\"
$fullname
\"
"
.
"
-k /usr/share/skel -m -d
$HOMEDIR
/
$user
"
.
"
-g
$project
$groupargument
-s
$PBAG
"))
{
fatal
("
Could not add user
$user
to local node.
");
}
}
else
{
print
"
Updating user
$user
(
$user_number
) record on local node.
\n
";
#
#
Set up a .forward file so that any email to them gets forwarded off.
#
MAKE SURE not to update the shell
#
if
(
!
-
e
"
/users/
$user
/.forward
"
)
{
print
"
Setting up .forward file ...
\n
";
open
(
FOR
,
"
>/users/
$user
/.forward
");
print
FOR
"
$user_email
\n
";
close
(
FOR
);
chmod
(
0644
,
"
/users/
$user
/.forward
");
}
else
{
print
"
There appears to be a .forward file in /users/
$user
. Skipping.
\n
";
if
(
system
("
$USERMOD
$user
-u
$user_number
-c
\"
$fullname
\"
"
.
"
-g
$project
$groupargument
"))
{
fatal
("
Could not modify user
$user
on local node.
");
}
}
sub
sanitize
()
{
#
# Make user account on control node. We do the password setup as separate
# step since thats easier than trying to both via ssh.
#
# Quote special chars for ssh and the shell on the other side
#
$fullname
=~
s/\"/\'/g
;
$fullname
=~
s/([^\\])([\'\"\(\)])/$1\\$2/g
;
## un-taint path
$ENV
{'
PATH
'}
=
'
/bin:/usr/bin
';
delete
@ENV
{'
IFS
',
'
CDPATH
',
'
ENV
',
'
BASH_ENV
'};
if
(
system
("
$SSH
$control_node
egrep -q -s '^
${user}
:' /etc/passwd
"))
{
print
"
Adding user
$user
(
$user_number
) to
$control_node
.
\n
";
## check usage
if
(
$#ARGV
<
0
)
{
die
("
Usage: mkacct-ctrl <username>
\n
"
.
"
\t
Creates given user account on appropriate control nodes.
\n
");
if
(
system
("
$SSH
$control_node
'
$USERADD
"
.
"
$user
-u
$user_number
-c
\"
$fullname
\"
"
.
"
-k /usr/share/skel -m -d
$HOMEDIR
/
$user
-g
$project
"
.
"
$groupargument
-s /bin/tcsh'
"))
{
fatal
("
Could not add user
$user
(
$user_number
) to
$control_node
.
\n
");
}
}
else
{
print
"
Updating user
$user
record on
$control_node
.
\n
";
## sanitize user
if
(
$ARGV
[
0
]
=~
/^([a-z0-9]+)$/i
)
{
$user
=
$
1
;
}
else
{
die
"
$0: User argument
$ARGV
[0] has invalid characters.
\n
";
if
(
system
("
$SSH
$control_node
'
$USERMOD
"
.
"
$user
-u
$user_number
"
.
"
-c
\"
$fullname
\"
-g
$project
$groupargument
'
"))
{
fatal
("
Could not modify user
$user
record on
$control_node
.
");
}
}
if
(
system
("
$SSH
$control_node
$CHPASS
-p
$pswd
$user
"))
{
fatal
("
Could not change password for user
$user
on
$control_node
.
\n
");
}
## effective uid must be root
if
(
$EUID
!=
0
)
{
die
("
$0: Must have an EUID of 0 to create an account.
\n
");
}
#
# Set up the ssh key, but only if not done so already.
#
if
(
!
-
e
"
$HOMEDIR
/
$user
/.ssh/
"
)
{
print
"
Setting up ssh configuration for
$user
.
\n
";
mkdir
("
$HOMEDIR
/
$user
/.ssh
",
0700
)
or
fatal
("
Could not mkdir
$HOMEDIR
/
$user
/.ssh: $!
");
chown
(
$user_number
,
$groupnumbers
{
$project
},
"
$HOMEDIR
/
$user
/.ssh
")
or
fatal
("
Could not chown
$HOMEDIR
/
$user
/.ssh: $!
");
# Run commands below as the user
$EUID
=
$user_number
;
$UID
=
$EUID
;
if
(
system
("
/usr/bin/ssh-keygen -P '' -f
$HOMEDIR
/
$user
/.ssh/identity
"))
{
fatal
("
Failure in ssh-keygen
");
}
if
(
system
("
/bin/cp
$HOMEDIR
/
$user
/.ssh/identity.pub
"
.
"
$HOMEDIR
/
$user
/.ssh/authorized_keys
"))
{
fatal
("
Copying over
$HOMEDIR
/
$user
/.ssh/identity.pub to auth keys
");
}
chmod
(
0600
,
"
$HOMEDIR
/
$user
/.ssh/authorized_keys
")
or
fatal
("
Could not chown
$HOMEDIR
/
$user
/.ssh/authorized_keys: $!
");
}
#
# Set up a .forward file so that any email to them gets forwarded off.
#
if
(
!
-
e
"
$HOMEDIR
/
$user
/.forward
"
)
{
print
"
Setting up .forward file for
$user
.
\n
";
###
### Return non-zero if we got tuples; 0 if not.
###
sub
got_tuples
()
{
return
$_
[
0
]
->
numrows
;
if
(
system
("
echo
\"
$user_email
\"
>
$HOMEDIR
/
$user
/.forward
"))
{
fatal
("
Could not create
$HOMEDIR
/
$user
/.forward
");
}
chmod
(
0644
,
"
$HOMEDIR
/
$user
/.forward
")
or
fatal
("
Could not chown
$HOMEDIR
/
$user
/.forward
")
;
}
exit
(
0
);
sub
fatal
{
local
(
$msg
)
=
$_
[
0
];
SENDMAIL
(
$TBOPS
,
"
TESTBED: mkacct-ctrl Failed
",
$msg
);
die
("
$0:
$msg
");
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment