#!/usr/bonsaitools/bin/perl -w # -*- Mode: perl; indent-tabs-mode: nil -*- # # The contents of this file are subject to the Mozilla Public # License Version 1.1 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or # implied. See the License for the specific language governing # rights and limitations under the License. # # The Original Code is mozilla.org code. # # The Initial Developer of the Original Code is Holger # Schurig. Portions created by Holger Schurig are # Copyright (C) 1999 Holger Schurig. All # Rights Reserved. # # Contributor(s): Holger Schurig # Dave Miller # Joe Robins # Dan Mosedale # # Direct any questions on this source code to # # Holger Schurig use diagnostics; use strict; use lib "."; require "CGI.pl"; require "globals.pl"; # Shut up misguided -w warnings about "used only once". "use vars" just # doesn't work for me. sub sillyness { my $zz; $zz = $::userid; $zz = $::superusergroupset; } my $editall; my $opblessgroupset = '9223372036854775807'; # This is all 64 bits. # TestUser: just returns if the specified user does exists # CheckUser: same check, optionally emit an error text sub TestUser ($) { my $user = shift; # does the product exist? SendSQL("SELECT login_name FROM profiles WHERE login_name=" . SqlQuote($user)); return FetchOneColumn(); } sub CheckUser ($) { my $user = shift; # do we have a product? unless ($user) { print "Sorry, you haven't specified a user."; PutTrailer(); exit; } unless (TestUser $user) { print "Sorry, user '$user' does not exist."; PutTrailer(); exit; } } sub EmitElement ($$) { my ($name, $value) = (@_); $value = value_quote($value); if ($editall) { print qq{\n}; } else { print qq{$value\n}; } } # # Displays the form to edit a user parameters # sub EmitFormElements ($$$$$) { my ($user, $realname, $groupset, $blessgroupset, $disabledtext) = @_; print " Login name:\n"; EmitElement("user", $user); print "\n"; print " Real name:\n"; EmitElement("realname", $realname); if ($editall) { print "\n"; print " Password:\n"; if(Param('useLDAP')) { print " This site is using LDAP for authentication!\n"; } else { print qq|
(enter new password to change) |; } print "\n"; print " Disable text:\n"; print " \n"; print " \n"; print "\n"; print " If non-empty, then the account will\n"; print "be disabled, and this text should explain why.\n"; } if($user ne "") { print "Group Access:"; SendSQL("SELECT bit,name,description,bit & $groupset != 0, " . " bit & $blessgroupset " . "FROM groups " . "WHERE bit & $opblessgroupset != 0 AND isbuggroup " . "ORDER BY name"); if (MoreSQLData()) { if ($editall) { print "\n"; print "\n\n"; } print "\n"; while (MoreSQLData()) { my ($bit,$name,$description,$checked,$blchecked) = FetchSQLData(); print "\n"; if ($editall) { $blchecked = ($blchecked) ? "CHECKED" : ""; print ""; } $checked = ($checked) ? "CHECKED" : ""; print ""; print "\n"; } } print "
Can turn this bit on for other users
|User is a member of these groups
" . ucfirst($name) . ": $description
\n"; print "Privileges:"; SendSQL("SELECT bit,name,description,bit & $groupset != 0, " . " bit & $blessgroupset " . "FROM groups " . "WHERE bit & $opblessgroupset != 0 AND !isbuggroup " . "ORDER BY name"); if (MoreSQLData()) { if ($editall) { print "\n"; print "\n\n"; } print "\n"; while (MoreSQLData()) { my ($bit,$name,$description,$checked,$blchecked) = FetchSQLData(); print "\n"; if ($editall) { $blchecked = ($blchecked) ? "CHECKED" : ""; print ""; } $checked = ($checked) ? "CHECKED" : ""; print ""; print "\n"; } } } else { print "\n"; } # # Displays a text like "a.", "a or b.", "a, b or c.", "a, b, c or d." # sub PutTrailer (@) { my (@links) = ("Back to the index", "Add a new user", @_); my $count = $#links; my $num = 0; print "

\n"; foreach (@links) { print $_; if ($num == $count) { print ".\n"; } elsif ($num == $count-1) { print " or "; } else { print ", "; } $num++; } PutFooter(); } # # Preliminary checks: # confirm_login(); print "Content-type: text/html\n\n"; $editall = UserInGroup("editusers"); if (!$editall) { SendSQL("SELECT blessgroupset FROM profiles WHERE userid = $::userid"); $opblessgroupset = FetchOneColumn(); if (!$opblessgroupset) { PutHeader("Not allowed"); print "Sorry, you aren't a member of the 'editusers' group, and you\n"; print "don't have permissions to put people in or out of any group.\n"; print "And so, you aren't allowed to add, modify or delete users.\n"; PutTrailer(); exit; } } # # often used variables # my $user = trim($::FORM{user} || ''); my $action = trim($::FORM{action} || ''); my $localtrailer = "edit more users"; my $candelete = Param('allowuserdeletion'); # # action='' -> Ask for match string for users. # unless ($action) { PutHeader("Select match string"); print qq{
List users with login name matching:
}; PutTrailer(); exit; } # # action='list' -> Show nice list of matching users # if ($action eq 'list') { PutHeader("Select user"); my $query = ""; my $matchstr = $::FORM{'matchstr'}; if (exists $::FORM{'matchtype'}) { $query = "SELECT login_name,realname,disabledtext " . "FROM profiles WHERE login_name "; if ($::FORM{'matchtype'} eq 'substr') { $query .= "like"; $matchstr = '%' . $matchstr . '%'; } elsif ($::FORM{'matchtype'} eq 'regexp') { $query .= "regexp"; $matchstr = '.' unless $matchstr; } elsif ($::FORM{'matchtype'} eq 'notregexp') { $query .= "not regexp"; $matchstr = '.' unless $matchstr; } else { die "Unknown match type"; } $query .= SqlQuote($matchstr) . " ORDER BY login_name"; } elsif (exists $::FORM{'query'}) { $query = "SELECT login_name,realname,disabledtext " . "FROM profiles WHERE " . $::FORM{'query'} . " ORDER BY login_name"; } else { die "Missing parameters"; } SendSQL($query); my $count = 0; my $header = "

Can turn this bit on for other users
|User has these privileges
" . ucfirst($name) . ": $description
Groups and
Privileges:
"; print "\n"; } print "
The new user will be inserted into groups " . "based on their userregexps.
To change the group " . "permissions for this user, you must edit the account after ". "creating it.
"; if ($candelete) { $header .= "\n"; } $header .= "\n"; print $header; while ( MoreSQLData() ) { $count++; if ($count % 100 == 0) { print "
Edit user ... Real nameAction
$header"; } my ($user, $realname, $disabledtext) = FetchSQLData(); my $s = ""; my $e = ""; if ($disabledtext) { $s = ""; $e = ""; } $realname ||= "missing"; print "\n"; print " $s$user$e\n"; print " $s$realname$e\n"; if ($candelete) { print " Delete\n"; } print ""; } if ($editall && !Param('useLDAP')) { print "\n"; my $span = $candelete ? 3 : 2; print qq{ Add a new user }; print ""; } print "\n"; print "$count users found.\n"; PutTrailer($localtrailer); exit; } # # action='add' -> present form for parameters for new user # # (next action will be 'new') # if ($action eq 'add') { PutHeader("Add user"); if (!$editall) { print "Sorry, you don't have permissions to add new users."; PutTrailer(); exit; } if(Param('useLDAP')) { print "This site is using LDAP for authentication. To add a new user, "; print "please contact the LDAP administrators."; PutTrailer(); exit; } print "
\n"; print "\n"; EmitFormElements('', '', 0, 0, ''); print "
\n
\n"; print "\n"; print "\n"; print "
"; my $other = $localtrailer; $other =~ s/more/other/; PutTrailer($other); exit; } # # action='new' -> add user entered in the 'action=add' screen # if ($action eq 'new') { PutHeader("Adding new user"); if (!$editall) { print "Sorry, you don't have permissions to add new users."; PutTrailer(); exit; } if(Param('useLDAP')) { print "This site is using LDAP for authentication. To add a new user, "; print "please contact the LDAP administrators."; PutTrailer(); exit; } # Cleanups and valididy checks my $realname = trim($::FORM{realname} || ''); # We don't trim the password since that could falsely lead the user # to believe a password with a space was accepted even though a space # is an illegal character in a Bugzilla password. my $password = $::FORM{'password'}; my $disabledtext = trim($::FORM{disabledtext} || ''); my $emailregexp = Param("emailregexp"); unless ($user) { print "You must enter a name for the new user. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } unless ($user =~ m/$emailregexp/) { print "The user name entered must be a valid e-mail address. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } if (!ValidateNewUser($user)) { print "The user '$user' does already exist. Please press\n"; print "Back and try again.\n"; PutTrailer($localtrailer); exit; } my $passworderror = ValidatePassword($password); if ( $passworderror ) { print $passworderror; PutTrailer($localtrailer); exit; } # For new users, we use the regexps from the groups table to determine # their initial group membership. # We also keep a list of groups the user was added to for display on the # confirmation page. my $bits = "0"; my @grouplist = (); SendSQL("select bit, name, userregexp from groups where userregexp != ''"); while (MoreSQLData()) { my @row = FetchSQLData(); if ($user =~ m/$row[2]/i) { $bits .= "+ $row[0]"; # Silly hack to let MySQL do the math, # not Perl, since we're dealing with 64 # bit ints here, and I don't *think* Perl # does that. push(@grouplist, $row[1]); } } # Add the new user SendSQL("INSERT INTO profiles ( " . "login_name, cryptpassword, realname, groupset, " . "disabledtext" . " ) VALUES ( " . SqlQuote($user) . "," . SqlQuote(Crypt($password)) . "," . SqlQuote($realname) . "," . $bits . "," . SqlQuote($disabledtext) . ")" ); #+++ send e-mail away print "OK, done.
\n"; if($#grouplist > -1) { print "New user added to these groups based on group regexps:\n"; print "
    \n"; foreach (@grouplist) { print "
  • $_
  • \n"; } print "
\n"; } else { print "New user not added to any groups.

\n"; } print "To change ${user}'s permissions, go back and edit this user"; print "

\n"; PutTrailer($localtrailer, "add another user."); exit; } # # action='del' -> ask if user really wants to delete # # (next action would be 'delete') # if ($action eq 'del') { PutHeader("Delete user"); if (!$candelete) { print "Sorry, deleting users isn't allowed."; PutTrailer(); exit; } if (!$editall) { print "Sorry, you don't have permissions to delete users."; PutTrailer(); exit; } CheckUser($user); # display some data about the user SendSQL("SELECT realname, groupset FROM profiles WHERE login_name=" . SqlQuote($user)); my ($realname, $groupset) = FetchSQLData(); $realname ||= "missing"; print "\n"; print "\n"; print " \n"; print " \n"; print "\n"; print " \n"; print " \n"; print "\n"; print " \n"; print " \n"; print "\n"; print " \n"; print " \n"; # Check if the user is an initialowner my $nodelete = ''; SendSQL("SELECT program, value FROM components WHERE initialowner=" . DBname_to_id($user)); $found = 0; while (MoreSQLData()) { if ($found) { print "
\n"; } else { print "\n"; print " \n"; print " \n" if $found; # Check if the user is an initialqacontact SendSQL("SELECT program, value FROM components WHERE initialqacontact=" . DBname_to_id($user)); $found = 0; while (MoreSQLData()) { if ($found) { print "
\n"; } else { print "\n"; print " \n"; print " \n" if $found; print "
PartValue
Login name:$user
Real name:$realname
Group set:"; SendSQL("SELECT name FROM groups WHERE bit & $groupset = bit ORDER BY isbuggroup, name"); my $found = 0; while ( MoreSQLData() ) { my ($name) = FetchSQLData(); print "
\n" if $found; print ucfirst $name; $found = 1; } print "none" unless $found; print "
Initial owner:"; } my ($product, $component) = FetchSQLData(); print "$product: $component"; $found = 1; $nodelete = 'initial bug owner'; } print "
Initial QA contact:"; } my ($product, $component) = FetchSQLData(); print "$product: $component"; $found = 1; $nodelete = 'initial QA contact'; } print "
\n"; if ($nodelete) { print "

You can't delete this user because '$user' is an $nodelete ", "for at least one product."; PutTrailer($localtrailer); exit; } print "

Confirmation

\n"; print "

Do you really want to delete this user?

\n"; print "

\n"; print "\n"; print "\n"; print "\n"; print "
"; PutTrailer($localtrailer); exit; } # # action='delete' -> really delete the user # if ($action eq 'delete') { PutHeader("Deleting user"); if (!$candelete) { print "Sorry, deleting users isn't allowed."; PutTrailer(); exit; } if (!$editall) { print "Sorry, you don't have permissions to delete users."; PutTrailer(); exit; } CheckUser($user); SendSQL("SELECT userid FROM profiles WHERE login_name=" . SqlQuote($user)); my $userid = FetchOneColumn(); SendSQL("DELETE FROM profiles WHERE login_name=" . SqlQuote($user)); SendSQL("DELETE FROM logincookies WHERE userid=" . $userid); print "User deleted.
\n"; PutTrailer($localtrailer); exit; } # # action='edit' -> present the user edit from # # (next action would be 'update') # if ($action eq 'edit') { PutHeader("Edit user"); CheckUser($user); # get data of user SendSQL("SELECT realname, groupset, blessgroupset, disabledtext FROM profiles WHERE login_name=" . SqlQuote($user)); my ($realname, $groupset, $blessgroupset, $disabledtext) = FetchSQLData(); print "
\n"; print "\n"; EmitFormElements($user, $realname, $groupset, $blessgroupset, $disabledtext); print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
"; my $x = $localtrailer; $x =~ s/more/other/; PutTrailer($x); exit; } # # action='update' -> update the user # if ($action eq 'update') { PutHeader("Updated user"); my $userold = trim($::FORM{userold} || ''); my $realname = trim($::FORM{realname} || ''); my $realnameold = trim($::FORM{realnameold} || ''); my $password = $::FORM{password} || ''; my $disabledtext = trim($::FORM{disabledtext} || ''); my $disabledtextold = trim($::FORM{disabledtextold} || ''); my $groupsetold = trim($::FORM{groupsetold} || '0'); my $blessgroupsetold = trim($::FORM{blessgroupsetold} || '0'); my $groupset = "0"; foreach (keys %::FORM) { next unless /^bit_/; #print "$_=$::FORM{$_}
\n"; detaint_natural($::FORM{$_}) || die "Groupset field tampered with"; $groupset .= " + $::FORM{$_}"; } my $blessgroupset = "0"; foreach (keys %::FORM) { next unless /^blbit_/; #print "$_=$::FORM{$_}
\n"; detaint_natural($::FORM{$_}) || die "Blessgroupset field tampered with"; $blessgroupset .= " + $::FORM{$_}"; } CheckUser($userold); # Note that the order of this tests is important. If you change # them, be sure to test for WHERE='$product' or WHERE='$productold' if ($groupset ne $groupsetold) { SendSQL("SELECT groupset FROM profiles WHERE login_name=" . SqlQuote($userold)); $groupsetold = FetchOneColumn(); # Updated, 5/7/00, Joe Robins # We don't want to change the groupset of a superuser. if($groupsetold eq $::superusergroupset) { print "Cannot change permissions of superuser.\n"; } else { SendSQL("UPDATE profiles SET groupset = groupset - (groupset & $opblessgroupset) + (($groupset) & $opblessgroupset) WHERE login_name=" . SqlQuote($userold)); # I'm paranoid that someone who I give the ability to bless people # will start misusing it. Let's log who blesses who (even though # nothing actually uses this log right now). my $fieldid = GetFieldID("groupset"); SendSQL("SELECT userid, groupset FROM profiles WHERE login_name=" . SqlQuote($userold)); my $u; ($u, $groupset) = (FetchSQLData()); if ($groupset ne $groupsetold) { SendSQL("INSERT INTO profiles_activity " . "(userid,who,profiles_when,fieldid,oldvalue,newvalue) " . "VALUES " . "($u, $::userid, now(), $fieldid, " . " $groupsetold, $groupset)"); } print "Updated permissions.\n"; } } if ($editall && $blessgroupset ne $blessgroupsetold) { SendSQL("UPDATE profiles SET blessgroupset=" . $blessgroupset . " WHERE login_name=" . SqlQuote($userold)); print "Updated ability to tweak permissions of other users.\n"; } # Update the database with the user's new password if they changed it. if ( !Param('useLDAP') && $editall && $password ) { my $passworderror = ValidatePassword($password); if ( !$passworderror ) { my $cryptpassword = SqlQuote(Crypt($password)); my $loginname = SqlQuote($userold); SendSQL("UPDATE profiles SET cryptpassword = $cryptpassword WHERE login_name = $loginname"); SendSQL("SELECT userid FROM profiles WHERE login_name=" . SqlQuote($userold)); my $userid = FetchOneColumn(); InvalidateLogins($userid); print "Updated password.
\n"; } else { print "Did not update password: $passworderror
\n"; } } if ($editall && $realname ne $realnameold) { SendSQL("UPDATE profiles SET realname=" . SqlQuote($realname) . " WHERE login_name=" . SqlQuote($userold)); print "Updated real name.
\n"; } if ($editall && $disabledtext ne $disabledtextold) { SendSQL("UPDATE profiles SET disabledtext=" . SqlQuote($disabledtext) . " WHERE login_name=" . SqlQuote($userold)); SendSQL("SELECT userid FROM profiles WHERE login_name=" . SqlQuote($userold)); my $userid = FetchOneColumn(); InvalidateLogins($userid); print "Updated disabled text.
\n"; } if ($editall && $user ne $userold) { unless ($user) { print "Sorry, I can't delete the user's name."; PutTrailer($localtrailer); exit; } if (TestUser($user)) { print "Sorry, user name '$user' is already in use."; PutTrailer($localtrailer); exit; } SendSQL("UPDATE profiles SET login_name=" . SqlQuote($user) . " WHERE login_name=" . SqlQuote($userold)); print "Updated user's name.
\n"; } PutTrailer($localtrailer); exit; } # # No valid action found # PutHeader("Error"); print "I don't have a clue what you want.
\n"; foreach ( sort keys %::FORM) { print "$_: $::FORM{$_}
\n"; }