I have cobbled together a working AuthcNDS module that allows me to authenticate users against the netware NDS tree within our office. My apache server is running on a RH5.2 box with some of the Caldera netware RPMs installed. Server Version: Apache/1.3.9 (Unix) mod_fastcgi/2.2.2 PHP/3.0.12 mod_perl/1.21 The module doesn't communicate directly with the NDS, but instead uses a command line tool (nwlogin) to do the password checking. Unfortunately spawning that process is rather time consuming so once the user is authenticated, the module sets a cookie based on the username, IP, a 'secret' and MD5 hashes it. The module, when asked to authenticate a user, first checks for that cookie. If it doesn't exist, it then goes to the NDS. I used one of the Apache auth-cookie modules as a starting point. I need to fix up the spawning of the nwlogin process as i think the users password would be visible in the output from 'ps auxw'. Perhaps i should pipe the password to nwlogin instead of passing it as a command line arguement. Any other suggestions for tidying it up? Have i made any glaring mistakes? (this is my first mod_perl effort) Unfortunately it is not self contained and is reliant upon the nwlogin tool that comes with the Caldera RPMs. ======================================================= package Apache::AuthcNDS; # # file: Apache/AuthcNDS.pm # # performs authentication against the NDS and makes use of cookies to cache # authentication info so that we dont have to reauth for every single hit # which can be quite time consuming as the auth process requires the use of # an external shell program. # use strict; use MD5; use CGI::Cookie; use Apache::Constants qw(:common); my $r; sub handler { $r = shift; my ($cookie , $user, $auth_cookie , $authstring, $md5check, $newcookie , $cookie_text); my ($res, $sent_pw) = $r->get_basic_auth_pw; return $res if $res != OK; $user = $r->connection->user; # # the secret is the only bit of text not derived from the user # this stops them from creating a fake cookie ( i hope ) # my $secret = 'elegiac'; # # search thru the cookies for ours... # if our cookie shows up, they must have already authenticated # if so i can avoid the expensive NDS lookup # ($auth_cookie) = ( ($r->header_in("Cookie") || "") =~ /Auth_NDS_ID=([^;]+)/); if ($auth_cookie) { $md5check = join('-', $user , &MakeHash($user , $r->auth_type , $r->auth_name , $secret)); if ($md5check eq $auth_cookie) { return OK; } } # failing that we have to actually check their credentials # against the NDS if (!&auth_nds ( $user , $sent_pw )) { # authentication failed ! # log that and clear the cookie on the users machine $r->note_basic_auth_failure; $r->log_reason("Authentication of [$user] against NDS failed.", $r->filename); $r->err_headers_out->{'Set-Cookie'} = "Auth_NDS_ID="; return AUTH_REQUIRED; } else { # authentication succeeded, so let them know, and set the cookie for future reference $cookie_text = join('-', $user , &MakeHash($user , $r->auth_type , $r->auth_name , $secret)); $newcookie = new CGI::Cookie(-name => 'Auth_NDS_ID', -value => $cookie_text); $r->err_headers_out->{'Set-Cookie'} = $newcookie; return OK; } } #================================== # make up the hash to be placed in the cookie (hash cookies? ;) #================================== sub MakeHash() { my ($u , $at , $an , $d) = @_; my $authstring = $u . $at . $an . $d; return MD5->hexhash($authstring) } #================================== # check the username and password against the NDS #================================== sub auth_nds() { my ($user_abs , $current, $authenticated); my ($user,$pass) = @_; # dont process if username or password is blank if (!$user || !$pass) { return 0;} # check to see if someone else is logged in $current = `nwwhoami`; # if someone else is currently logged in then note that and wait 1 second if ($current) { $r->log_reason ("someone already logged in. sleeping for 1s." , $r->filename) ; sleep 1; } # clear all current connections (for the NOBODY user) system ('nwlogout -a > /dev/null 2> /dev/null'); # # trim the username passed to us so that we have one form that starts with a DOT and one that doesnt # i.e .sf.tr.bne and sf.tr.bne # $user_abs = $user; unless ($user_abs =~ /^\./) { $user_abs = '.' . $user_abs;} $user =~ s/^\.//; # # now try to login using that username and password # and rely on the exit status to determine whether it failed or not # $authenticated = system("nwlogin -u $user_abs -p $pass > /dev/null 2> /dev/null"); # tidy up after ourselves by logging out the NOBODY user system("nwlogout --all > /dev/null 2> /dev/null"); # and return a status return !$authenticated; } #================================== 1; __END__