This file is indexed.

/usr/bin/wg-userImport is in webgui 7.10.28-1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 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
111
112
113
114
115
116
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
#!/usr/bin/perl

#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#-------------------------------------------------------------------
# http://www.plainblack.com                     info@plainblack.com
#-------------------------------------------------------------------

use strict;
use File::Basename ();
use File::Spec;

my $webguiRoot;
BEGIN {
    $webguiRoot = '/usr/share/webgui';
    unshift @INC, File::Spec->catdir($webguiRoot, 'lib');
}

use Digest::MD5;
use Getopt::Long;
use Pod::Usage;
use WebGUI::DateTime;
use WebGUI::Group;
use WebGUI::Session;
use WebGUI::User;
use WebGUI::Utility;

$|=1;

my $delimiter = "\t";
my $usersFile;
my $configFile;
my $defaultIdentifier = '123qwe';
my $help;
my $authMethod = 'WebGUI';
my $groups;
my $ldapUrl;
my $status = 'Active';
my $expireOffset;
my $expireUnits = 'seconds';
my $override;
my $quiet;
my $update;
my $updateAdd;
my $replaceGroups;
my $canChangePass;

GetOptions(
	'usersFile=s'=>\$usersFile,
	'configFile=s'=>\$configFile,
	'help'=>\$help,
	'authMethod:s'=>\$authMethod,
	'delimiter:s'=>\$delimiter,
	'password|identifier:s'=>\$defaultIdentifier,
	'groups:s'=>\$groups,
	'ldapUrl:s'=>\$ldapUrl,
	'quiet'=>\$quiet,
	'status:s'=>\$status,
	'expireOffset:i'=>\$expireOffset,
	'expireUnits:s'=>\$expireUnits,
	'override'=>\$override,
	'update'=>\$update,
	'updateAdd'=>\$updateAdd,
	'replaceGroups'=>\$replaceGroups,
	'canChangePass'=>\$canChangePass
);

pod2usage( verbose => 2 ) if $help;
pod2usage() unless ($usersFile && $configFile);

if (!($^O =~ /^Win/i) && $> != 0 && !$override) {
        print "You must be the super user to use this utility.\n";
        exit;
}



print "Starting up..." unless ($quiet);
my $session = WebGUI::Session->open($webguiRoot,$configFile);
$session->user({userId=>3});
open(FILE,"<".$usersFile) || die("Could not open $usersFile for reading: $!");
print "OK\n" unless ($quiet);

my $lineNumber = 0;
my @field;
my @profileFields = $session->db->buildArray("select fieldName from userProfileField");
while(my $line = <FILE>) {
    $lineNumber++;

    chomp $line;
    next
        if $line eq '';
    my @row = split($delimiter, $line);
    use Data::Dumper ();
    chomp @row;
    if ($lineNumber == 1) {
        @field = @row;
        next;
    }
    # parse fields
    my %user;
    foreach my $item (@row) {
        $item =~ s/\s+$//;
    }
    @user{@field} = @row;
    if ($user{username} eq "" && $user{firstName} ne "" && $user{lastName} ne "") {
        $user{username} = $user{firstName}.".".$user{lastName};
    }
    elsif ($user{username} eq '') {
        print "Skipping line ${lineNumber}: No username.\n" unless ($quiet);
        next;
    }

    $user{identifier} ||= $user{password}
        if $user{password};
    $user{ldapUrl} ||= $ldapUrl
        if $ldapUrl;
    $user{authMethod} ||= $authMethod
        if $authMethod;
    $user{groups} ||= $groups
        if $groups;
    $user{status} ||= $status
        if $status;
    $user{expireOffset} ||= $expireOffset
        if $expireOffset;
    $user{expireOffset} = calculateExpireOffset($user{expireOffset},$expireUnits)
        if $user{expireOffset};
    $user{birthdate} = WebGUI::DateTime->new($user{birthdate}." 00:00:00")->epoch()
        if $user{birthdate};
    $user{changePassword} ||= $canChangePass
        if $user{changePassword} == '';
    # process user
    my $u;
    my ($userId) = $session->db->quickArray("select userid from users where username=?",[$user{username}]);
    if (($update || $updateAdd) && $userId) {
        # Allowed to update, and user exists
        print "Updating user '$user{username}'\n" unless ($quiet);
        $u = WebGUI::User->new($session, $userId);
        if ($replaceGroups && $user{groups}) {
            my $groups = $u->getGroups;
            $u->deleteFromGroups(@$groups);
        }
    }
    elsif ($update) {
        # Can only update, user doesn't exist
        print "User '$user{username}' not found. Skipping.\n" unless ($quiet);
        next;
    }
    elsif ($userId) {
        print "User '$user{username}' already exists. Skipping.\n" unless ($quiet);
        next;
    }
    else {
        # Allowed to add, user doesn't exist
        print "Adding user '$user{username}'\n" unless ($quiet);
        $u = WebGUI::User->new($session, "new");
        $user{identifier} ||= $defaultIdentifier
    }
    $user{identifier} = Digest::MD5::md5_base64($user{identifier})
        if ($user{identifier});
    if ($u) {
        $u->username($user{username});
        $u->authMethod($user{authMethod})
            if $user{authMethod};
        $u->status($user{status})
            if $user{status};
        my $class = "WebGUI::Auth::".$authMethod;
        (my $mod = "$class.pm") =~ s{::|'}{/}g;
        if (! eval { require $mod; 1 } ) {
            $session->log->fatal("Authentication module failed to compile: $mod.".$@) if($@);
            exit;
        }
        my $auth = $class->new($session, $authMethod,$u->userId);
        $auth->saveParams($u->userId,"WebGUI",{identifier=>$user{identifier}})
            if $user{identifier};
        $auth->saveParams($u->userId,"LDAP",{ldapUrl=>$user{ldapUrl}})
            if $user{ldapUrl};
        $auth->saveParams($u->userId,"LDAP",{connectDN=>$user{connectDN}})
            if $user{connectDN};
        $auth->saveParams($u->userId,"WebGUI",{changePassword=>$user{changePassword}});
        foreach my $field (keys %user) {
            if (isIn($field, @profileFields)) {
                $u->profileField($field,$user{$field});
            }
        }
        if ($user{groups}) {
            my @groups = split(/,/,$user{groups});
            # Groups that have : in them have unique expiration dates
            $u->addToGroups([grep { !/:/ } @groups],$user{expireOffset});
            for my $groupDef ( grep { /:/ } @groups ) {
                my ( $groupId, $expireDate ) = split /:/, $groupDef, 2;

                # Calculate expiration offset
                my $dtparse = DateTime::Format::Strptime->new(
                    pattern     => '%F %T',
                    on_error    => 'croak',
                );

                eval { 
                    my $expireOffset = $dtparse->parse_datetime( $expireDate )->epoch - time;
                    $u->addToGroups( [$groupId], $expireOffset );
                };
                if ( $@ ) {
                    print "Could not add user $user{username} to group $groupId: $@";
                }
            }
        }
    }
}
print "Cleaning up..." unless ($quiet);
close(FILE);
$session->var->end;
$session->close;
print "OK\n" unless ($quiet);


#-------------------------------------------------
# calculateExpireOffset(expireOffset,expireUnits)
# return: offsetInSeconds
sub calculateExpireOffset {
    my ($offset, $units) = @_;
    return undef if ($offset < 1);
    if ($units eq "epoch") {
        my $seconds = ($offset);
        if ($seconds < 1) {
            return undef;
        }
        else {
            return $seconds;
        }
    }
    if ($units eq "fixed") {
        my $seconds = (($offset - time()));
        if ($seconds < 1) {
            return undef;
        }
        else {
            return int($seconds);
        }
    }
    return $session->datetime->intervalToSeconds($offset, $units)
}

__END__

=head1 NAME

userImport - Bulk load users into WebGUI database

=head1 SYNOPSIS

 userImport --configFile config.conf --usersFile pathname
            [--authMethod method]
            [--canChangePass]
            [--delimiter string]
            [--expireOffset integer [--expireUnits string]]
            [--groups groupid,...]
            [--ldapUrl uri]
            [--password text]
            [--status status]
            [--override]
            [--quiet]
            [--update | --updateAdd]
            [--replaceGroups]

 userImport --help

=head1 DESCRIPTION

This WebGUI utility script reads user information from a text file
and loads them into the specified WebGUI database. Default user
parameters can be specified through command line options, taking
overriding values from the file.

This utility is designed to be run as a superuser on Linux systems,
since it needs to be able to put files into WebGUI's data directories
and change ownership of files. If you want to run this utility without
superuser privileges, use the B<--override> option described below.

The user information is given in a simple TAB-delimited text file,
that describes both the field names and field data for each user. You
can change de actual delimiter with the B<--delimiter> option (see below).

The first line of the file contains the field names whose values are
going to be loaded. From then on, all non-blank lines in the file must have
the same number of fields. All-blank lines are ignored. The valid field
names are:

=over

=item B<username>

=item B<password>

=item B<authMethod>

=item B<status>

=item B<ldapUrl>

=item B<connectDN>

=item B<groups>

=item B<expireOffset>

=item Any valid User Profile field name available in WebGUI's database, e.g. B<firstName>, B<lastName>, B<email>, etc.

=back

If you use the field B<groups>, each following line  should contain a comma
separated list of WebGUI Group Ids; note that this could be a problem
if you chose to use comma as a delimiter for fields.

If no username is specified it will default to B<firstName.lastName>. If
no B<username> is specified, nor B<firstName> and B<lastName>, then the
user will B<not> be loaded.

If you specify the B<userId> field for import on any record, that B<userId>
will be used instead of generating a new one automatically. If you do this,
be careful not to insert duplicates!

If you use an invalid field name, its values will be ignored.

=over

=item B<--configFile config.conf>

The WebGUI config file to use. Only the file name needs to be specified,
since it will be looked up inside WebGUI's configuration directory.
This parameter is required.

=item B<--usersFile pathname>

Pathname to the file containing users information for bulk loading.

=item B<--authMethod method>

Specify the default authentication method to set for each loaded user.
It can be overridden in the import file for specific users.
If left unspecified, it defaults to B<WebGUI>.

=item B<--canChangePass>

Set loaded users to be able to change their passwords. If left
unspecified, loaded users will B<NOT> be able to change their
passwords until and administrator grants them the privilege.

=item B<--delimiter string>

Specify the string delimiting fields in the import file. If left
unspecified, it defaults to a single TAB (ASCII 9).

=item B<--expireOffset integer>

Specify the default amount of time before the loaded user will be
expired from the groups they are added to. The units are specified
by B<--expireUnits> (see below). It can be overridden in the import
file for specific users. If left unspecified, it defaults to the
expire offset set in the group definition within WebGUI.

=item B<--expireUnits unidades>

Specify the units for B<--expireOffset> (see above). Valid values
are B<seconds>, B<minutes>, B<hours>, B<days>, B<weeks>, B<months>,
B<years>, B<epoch>, or B<fixed>. If set to B<epoch> the system will
assume that the expire offset should be taken as an epoch date
(absolute number of seconds since January 1, 1970) rather than an
interval. If set to B<fixed> the system will assume that the
B<--expireOffset> is a fixed date. If left unspecified, it defaults
to B<seconds>.

=item B<--groups groupid,...>

Specify a comma separated list of WebGUI Group Ids that each loaded
user will be set to. It can be overridden in the import file for
specific users.

You can specify a unique expiration date for a group by adding it
after the group ID, separated by a colon. The date/time should be in
"YYYY-MM-DD HH:NN:SS" format.

 groupId:2000-01-01 01:00:00,groupId2:2001-01-02 02:00:00

=item B<--ldapUrl uri>

Specify the URI used to connect to the LDAP server for authentication.
The URI must conform to what L<Net::LDAP> uses for connecting.
It can be overridden in the import file for specific users.

=item B<--password string>
=item B<--identifier string>

Specify the default password to use for loaded users. It can (and should)
be overridden in the import file for specific users. If left unspecified,
it defaults to B<123qwe>.

=item B<--status status>

Specify the default account status for loaded users. Valid values are
B<Active> and B<Deactivated>. If left unspecified, it defaults to
B<Active>.

=item B<--update>

Search WebGUI's database for each user listed in the import file, and
update its information using the provided fields. Users in the import
file that are B<not> found in the database are B<ignored>. See
B<--updateAdd> below if you want to add the extra users.

=item B<--updateAdd>

Search WebGUI's database for each user listed in the import file, and
update its information using the provided fields. Users in the import
file that are B<not> found in the database are B<added>. See
B<--update> above if you do not want to add the extra users.

=item B<--replaceGroups>

If the user being updated with B<--update> or B<--updateAdd> already
belongs to some other groups, remove the user from them.

=item B<--override>

This flag will allow you to run this utility without being the super user,
but note that it may not work as intended.

=item B<--quiet>

Disable all output unless there's an error.

=item B<--help>

Shows this documentation, then exits.

=back

=head1 AUTHOR

Copyright 2001-2009 Plain Black Corporation.

=cut