2 # Author: Fletcher T. Penney
5 # NOTE: a functional cookies plugin is required. Apparently, it has to be named something like
6 # 9999cookies to work properly.
8 # Also, this plugin works by modifying the filter subroutine. You may need to rename your plugins to insure
9 # the proper order, but it works properly with exclude, and menu to my testing. I am sure there are possible
10 # conflicts with other plugins though.
15 # --- Configurable variables -----
17 # Where is the passwd file? Should not be in a public directory nor group/world writeable
18 # This file is created with the htpasswd command (Do a man htpasswd to figure it out - please don't ask
19 # me to explain how to do this - there are plenty of references on the web.
20 # I will work on updating this to allow a cgi program to maintain this file, but can't guarantee
21 # when that will occur. In the meantime, this provides for better security.
25 my $passwd_file = "$blosxom::datadir/passwd";
27 # Where is your excludefile - this controls which user is able to see which files
28 # the excludefile is built using regular expressions in the format:
30 # user is a regexp to match allowed user (.* matches all VALIDATED users)
31 # page is a regexp to match pages or directories (.* matches all pages)
34 # A blank or nonexistent file allows full access to anyone, logged in or not
36 # Only someone logged in as myusername can access any files on the web site
37 # (myuser1|myuser2)=private
38 # Only these two people can access a file or directory named private, private1, privatestuff, etc
40 # Any VALIDATED user can view the directory named priv, but this doesn't affect one named private
43 my $excludefile = "$blosxom::datadir/requireuser";
45 my $default_message = "Please log in.";
48 # This section for gui creation of accounts
50 my $pending_file = "$blosxom::plugin_state_dir/pendingaccounts";
53 # --------------------------------
55 # Ideas for improvement
56 # Option to log all succesful logins
57 # Ability to set a sort of exclude file to filter out entries by login name
59 use CGI qw/:standard/;
61 $username = ""; # users login name, if any - set only after password is validated
71 my ($submituser, $submitpass) = @_;
72 if (open(PASSWD, $passwd_file)) {
73 $message = "Password file open.";
76 ($testuser, $testpass) = split(':',$_);
77 if ($testuser eq $submituser) {
78 if (crypt($submitpass,$testpass) eq $testpass) {
79 $message = "Welcome, $submituser.";
80 $username = $submituser;
82 $loginform = $logoutform;
84 warn "blosxom : login plugin > Incorrect password for user $submituser.";
88 if ($validated eq 0) {
89 $message = "Login for user $submituser failed.";
90 warn "blosxom : login plugin > $message";
95 $message = "Unable to access password file.\n";
96 warn "blosxom : login plugin > $message";
106 $path_noflavour = $blosxom::path_info;
107 if ($path_noflavour !~ s/\.[^\.]*$//) {
108 $path_noflavour =~ s/\/$//;
109 $path_noflavour .= "\/index";
110 $path_noflavour =~ s/^([^\/])/$1/;
112 $path_noflavour =~ s/^\/*//;
114 open (REQUIRE, $excludefile);
115 @requiredlist = <REQUIRE>;
118 # HTML code for the login form to be displayed
119 # Converts to a logout button as well?
121 $loginform = qq!<form method="POST" action="$blosxom::url/$path_noflavour.$blosxom::flavour">
122 <table border=0 cellpadding=0 cellspacing=0>
124 <td align=right>Login:</td><td><input name="user" size="10" value="" ><br></td>
126 <td align=right>Password:</td><td><input name="pass" size="10" value="" type="password"><br></td>
128 <td colspan=2 align=center><input type="submit" value="Login"></td>
130 <input type="hidden" name="plugin" value="login">
131 <input type="hidden" name="task" value="login">
134 $logoutform = qq!<form method="POST" action="$blosxom::url/$path_noflavour.$blosxom::flavour">
135 <input type="submit" value="Logout">
136 <input type="hidden" name="plugin" value="login">
137 <input type="hidden" name="task" value="logout">
140 $signupform = qq!<form method="POST" action="$blosxom::url/$path_noflavour.$blosxom::flavour">
141 <table border=0 cellpadding=0 cellspacing=0>
143 <td align=right>Login(no spaces):</td><td><input name="user" size="10" value="" ><br></td>
145 <td align=right>Email:</td><td><input name="email" size="10" value=""><br></td>
147 <td align=right>Password:</td><td><input name="pass" size="10" value="" type="password"><br></td>
149 <td align=right>Verify:</td><td><input name="verifypass" size="10" value="" type="password"><br></td>
151 <td colspan=2 align=center><input type="submit" value="Sign Me Up"></td>
153 <input type="hidden" name="plugin" value="login">
154 <input type="hidden" name="task" value="signup">
162 my ($pkg, $files_ref) = @_;
163 my @files_list = keys %$files_ref;
165 # This handles login requests and creates a cookie, if valid
166 if ( request_method() eq 'POST' and (param('plugin') eq 'login')) {
167 if (param('task') eq 'logout') {
168 &cookies::remove('login'); # These don't seem to work
169 &cookies::clear('login'); # So I overwrite the cookie below
174 -domain=>$cookies::domain,
182 if (param('task') eq 'login') {
183 my $user = param('user');
184 my $pass = param('pass');
185 if ((validate($user,$pass)) and $blosxom::plugins{cookies} > 0) {
190 -value=>{ 'user' => $user, 'pass' => $pass},
191 -domain=>$cookies::domain,
192 -expires=>$cookies::expires
198 if (param('task') eq 'signup') {
199 my $user = param('user');
200 my $pass = param('pass');
201 my $verify = param('verifypass');
202 my $email = param('email');
207 if ($pass ne $verify) {
208 $message = "Your passwords were different. Please try again.";
210 if (length($pass) < 5) {
211 $message = "Come on.... Your password has to be at least 5 characters.";
213 if (length($email) <5) {
214 $message = "That's not a real email address... Try again.";
217 if ($message eq "") {
218 open(PENDING,">>$pending_file") || ($message = "Error submitting information. Please try again.");
219 if ($message eq "") {
220 my @salts = (a..z,A..Z,0..9,'.','/');
221 my $salt=$salts[rand @salts];
222 $salt.=$salts[rand @salts];
224 my $encrypted=crypt($pass,$salt);
226 my ($dw, $mo, $mo_num, $da, $ti, $yr) = &blosxom::nice_date(time());
227 print PENDING "$yr $mo $da $ti $user $email $encrypted\n";
229 $message="Request submitted. Don't call us... We'll call you... ;)";
235 # Now, read cookies to see if user is logged in
236 if ($blosxom::plugins{cookies} > 0 and my $cookie = &cookies::get('login') and $validated eq 0) {
237 my $user = $cookie->{'user'};
238 my $pass = $cookie->{'pass'};
240 validate($user,$pass);
243 $message = $default_message if ($message eq "");
245 # Now filter the files
246 foreach $file (@files_list) {
248 $localfile =~ s/\/\//\//g; #An improperly formatted url such as:
249 # /my/document/dir/secret//files would slip through
250 foreach $required (@requiredlist) {
251 if ($required =~ /(.*)=(.*)/) {
254 if ($localfile =~ /^$blosxom::datadir(\/)?$reqfile/) {
255 delete $files_ref->{$file} if (($username !~ /$requser/) or $username eq "");
271 Blosxom Plug-in: login
275 Login allows you to create a passwd file that defines usernames and passwords for your web site. Another file, $excludefile, defines which users can access certain parts of your site. The format for the files is explained above.
277 $login::username provides the users login, once it has been validated against the database. It remains "" if someone is not logged in.
279 $login::loginform provides the login/logout box. Place it in your templates wherever you like.
280 $login::message gives certain status messages.
282 By default, login provides logging messages when certain errors occur, and when a failed login attempt happens.
284 $login::signupform provides html code for a simple account sign up form. Once a user submits the information, it is added to a text file defined by $pending_file. If you want to add the account, simply copy the user and password hash to the defined password file in the format "user:hash" as defined by the htpasswd command.
287 PLEASE NOTE: I am not a security expert. I can't guarantee that there isn't a huge loophole in this somewhere. And note - any malicious plug-in could expose a whole by tampering with the $username variable - verify that other plugins do not attempt to manipulate $login::username or access the cookies. But this is more a matter of being careful which plugins you install.
289 Also, this plugin does not pretend to offer serious security. Someone could read a restricted file if they have read access to the location that the file is stored. This could occur if you datadir is in your web servers documentroot.
291 There are many issues to consider when securing a web site, and I don't pretend to address them all, nor do I guarantee that this plugin even works properly. It is simply a means to provide some form of control without much effort on your part. You get what you pay for. But I will continue to work with the community to improve it as security holes are noted.
295 None known; please send bug reports and feedback to the Blosxom
296 development mailing list <blosxom-devel@lists.sourceforge.net>.
300 Fletcher T. Penney - http://fletcher.freeshell.org
302 This plugin is now maintained by the Blosxom Sourceforge Team,
303 <blosxom-devel@lists.sourceforge.net>.
308 This source is submitted to the public domain. Feel free to use and modify it. If you like, a comment in your modified source attributing credit for my original work would be appreciated.
310 THIS SOFTWARE IS PROVIDED AS IS AND WITHOUT ANY WARRANTY OF ANY KIND. USE AT YOUR OWN RISK!