addwikiuser.in 5.67 KB
Newer Older
1
2
3
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
4
# Copyright (c) 2005, 2006, 2007, 2008 University of Utah and the Flux Group.
5
6
7
8
# All rights reserved.
#
use English;
use Getopt::Std;
9
use Fcntl ':flock';
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

#
# Add a user to the wiki on ops. Also allow update of password.
#
sub usage()
{
    print STDOUT "Usage: addwikiuser [-u] <uid>\n";
    exit(-1);
}
my $optlist = "ud";
my $update  = 0;
my $debug   = 0;

#
# Configure variables
#
my $TB		= "@prefix@";
my $TBOPS       = "@TBOPSEMAIL@";
my $CONTROL     = "@USERNODE@";
my $BOSSNODE	= "@BOSSNODE@";
my $WIKISUPPORT = @WIKISUPPORT@;
my $SSH         = "$TB/bin/sshtb";
my $WIKIPROXY   = "$TB/sbin/wikiproxy";
33
my $lockfile    = "/var/tmp/testbed_wikiuser_lockfile";
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

#
# 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;
52
use User;
53

54
55
56
# Protos
sub fatal($);

57
58
59
60
61
62
63
64
65
66
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
#
# 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");
}

#
# If no wiki support, just exit. 
#
if (! $WIKISUPPORT) {
    print "WIKI support is not enabled. Exit ...\n";
    exit(0);
}

#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
if (defined($options{"u"})) {
    $update = 1;
}
if (defined($options{"d"})) {
    $debug = 1;
}
if (@ARGV != 1) {
    usage();
}
my $user = $ARGV[0];

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

111
112
113
114
115
116
# Map target user to object.
my $target_user = User->Lookup($user);
if (! defined($target_user)) {
    fatal("$user does not exist!");
}

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#
# We need to serialize this script to avoid a trashed map file. Use
# a dummy file in /var/tmp, opened for writing and flock'ed. 
#
if (1) {
    open(LOCK, ">>$lockfile") || fatal("Couldn't open $lockfile\n");
    $count = 0;
    if (flock(LOCK, LOCK_EX|LOCK_NB) == 0) {
	#
	# If we don't get it the first time, we wait for:
	# 1) The lock to become free, in which case we do our thing
	# 2) The time on the lock to change, in which case we wait for that process
	#    to finish
	#
	my $oldlocktime = (stat(LOCK))[9];
	my $gotlock = 0;
	while (1) {
	    print "Another exports update in progress, ".
		"waiting for it to finish\n";
	    if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
		# OK, got the lock, we can do what we're supposed to
		$gotlock = 1;
		last;
	    }
	    $locktime = (stat(LOCK))[9];
	    if ($locktime != $oldlocktime) {
		$oldlocktime = $locktime;
		last;
	    }
	    if ($count++ > 20)  {
		fatal("Could not get the lock after a long time!\n");
	    }
	    sleep(1);
	}

	$count = 0;
	#
	# If we didn't get the lock, wait for the processes that did to finish
	#
	if (!$gotlock) {
	    while (1) {
		if ((stat(LOCK))[9] != $oldlocktime) {
		    exit(0);
		}
		if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
		    close(LOCK);
		    exit(0);
		}
		if ($count++ > 30)  {
		    fatal("Process with the lock did not finish ".
			  "after a long time!\n");
		}
		sleep(1); 
	    }
	}
    }
}

#
# Perl-style touch(1)
#
my $now = time;
utime $now, $now, $lockfile;

181
182
183
184
185
186
187
188
189
190
191
#
# This script always does the right thing, so no permission checks.
# In fact, all it does it call over to ops to run a script over there.
# Note that adduser will just update the password if the user already
# exist in the wiki. 
#

#
# Look in the DB to see if there is already a wikiname defined. If
# we use that. Otherwise have to form one from the user name. Ick.
#
192
193
194
195
my $wikiname  = $target_user->wikiname();
my $usr_name  = $target_user->name();
my $usr_email = $target_user->email();
my $usr_pswd  = $target_user->pswd();
196
197

if (!defined($wikiname)) {
198
199
200
201
    # In update mode, do nothing if no wikiname.
    exit(0)
	if ($update);
    
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
    my @tokens = split(/\s+|-/, $usr_name);

    #
    # Build a wikiname from the tokens. Lowercase each token, then
    # captialize it, then run them all together. Oh, get rid of any
    # non alphanum characters.
    #
    $wikiname = "";

    foreach my $token (@tokens) {
	$token = ucfirst(lc($token));
	$token =~ s/\.//g;
	$wikiname .= $token;
    }

    #
    # Check to make sure the wikiname does not violate the wikirules!
    # If it does, just skip. User will have to plug in a new name.
    #
    if (! ($wikiname =~ /^[A-Z]+[a-z]+[A-Z]+[A-Za-z0-9]*$/)) {
	fatal("Bad WikiName: $wikiname. Not setting up account");
    }

    #
226
    # Make sure that no other user has the same wikiname.
227
    #
228
229
    fatal("The wikiname for $user ($wikiname) is already in use!")
	if (User->LookupByWikiName($wikiname));
230
231
232

    print "Selecting wikiname '$wikiname' for user $user\n";

233
234
235
236
    my %update_args = ("wikiname" => $wikiname);

    fatal("Could not update wikiname for $target_user")
	if ($target_user->Update(\%update_args) != 0);
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
}

#
# For ssh.
#
$UID = $EUID;

if ($CONTROL ne $BOSSNODE) {
    my $optarg = ($debug ? "-d" : "");
	
    if ($update) {
	print "Updating $user wiki info on $CONTROL.\n";
    }
    else {
	print "Adding user $user to the wiki on $CONTROL.\n";
    }

254
255
    # shell escape.
    $usr_pswd  =~ s/\$/\\\$/g;
256
    $usr_pswd  =~ s/\*/\\\*/g;
257

258
    if (system("$SSH -host $CONTROL $WIKIPROXY ".
259
	       "  $optarg adduser $user $wikiname '$usr_pswd'")) {
260
261
262
263
264
265
266
267
268
269
270
271
	fatal("$WIKIPROXY failed on $CONTROL!");
    }
}
exit(0);

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

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