#!/usr/bin/perl -w # # # jabberd-authpipe-pam.pl version 0.1 # Allows Jabber authentication against PAM without running jabberd as root. # # Copyright 2006 Nicholas J Humfrey # This code is hereby placed into the public domain. # # # Configure jabberd2 by editing c2s.xml: # # pipe # # # # /usr/local/libexec/jabberd-authpipe-pam.pl # # # Place this script in /usr/local/libexec then run: # chown root jabberd-authpipe-pam.pl # chmod 4755 jabberd-authpipe-pam.pl # # This sets the script to run as suid root and gives it access to the # shadow password file. You man need to install perl-suid in order to # run perl scripts with the suid bit set. # # This script only implements the User-Exists and Check-Password routines. # See docs/dev/c2s-pipe-authenticator for details about the protocol. # # # To get this script to work with PSI, Ifound that I had to enable # "Allow Plaintext Login" in PSI. Please make sure that you use SSL # so that plain-text passwords aren't sent over the network. # # use strict; use MIME::Base64; use Authen::PAM qw(:constants); ### Start of Settings ### my $SERVICE_NAME = 'jabberd'; my $DEBUG = 0; ### End of Settings ##### open(STDERR, ">/tmp/jabber-authpipe.log") or die "Failed to open log"; # Flush output immediately. $| = 1; # On startup, we have to inform c2s of the functions we can deal with. print "OK USER-EXISTS CHECK-PASSWORD FREE\n"; # Our main loop my $buf; while(sysread (STDIN, $buf, 1024) > 0) { my ($cmd, @args) = split ' ', $buf; $cmd =~ tr/[a-z]/[A-Z]/; $cmd =~ tr/_/-/; if ($cmd eq 'USER-EXISTS') { print cmd_user_exists( @args ), "\n"; } elsif ($cmd eq 'CHECK-PASSWORD') { print cmd_check_password( @args ), "\n"; } elsif ($cmd eq 'FREE') { # c2s shutting down, do the same. last; } else { print STDERR "Unsupported command: '$cmd'\n" if ($DEBUG); print "NO\n"; } } # Determine if the requested user exists. sub cmd_user_exists { my ($user, $realm) = @_; my ($name,$passwd,$uid,$gid) = getpwnam($user); if (defined $name) { print STDERR "User '$user' exists with ID $uid.\n" if ($DEBUG); return "OK"; } else { print STDERR "User '$user' does not exist.\n" if ($DEBUG); return 'NO'; } } # Compare the given password with the stored password. sub cmd_check_password { my ($username, $encoded_pass, $realm) = @_; # Decode the password my $password = decode_base64($encoded_pass); return "NO" if not $password; my $handler = sub { my @response = (); while (@_) { my $code = shift; my $message = shift; my $answer = undef; if ( $code == PAM_PROMPT_ECHO_ON ) { $answer = $username; } if ( $code == PAM_PROMPT_ECHO_OFF ) { $answer = $password; } push( @response, PAM_SUCCESS, $answer ); } return ( @response, PAM_SUCCESS ); }; my $pam = Authen::PAM->new( $SERVICE_NAME, $username, $handler ); unless ( ref $pam ) { my $error = Authen::PAM->pam_strerror($pam); print STDERR "Failed to authenticate user '$username' using service '$SERVICE_NAME'. Reason: '$error'\n"; return 'NO'; } my $result = $pam->pam_authenticate; unless ( $result == PAM_SUCCESS ) { my $error = $pam->pam_strerror($result); print STDERR "Failed to authenticate user '$username' using service '$SERVICE_NAME'. Reason: '$error'\n"; return 'NO'; } $result = $pam->pam_acct_mgmt; unless ( $result == PAM_SUCCESS ) { my $error = $pam->pam_strerror($result); print STDERR "Failed to authenticate user '$username' using service '$SERVICE_NAME'. Reason: '$error'\n"; return 'NO'; } print STDERR "Successfully authenticated user '$username' using service '$SERVICE_NAME'.\n" if ($DEBUG); return 'OK'; } __END__ =head1 NAME jabberd-authpipe-pam - Allows Jabber authentication against PAM without running jabberd as root. =head1 VERSION This document describes version 0.1 of jabberd-authpipe-pam, released 25th December 2006. =head1 DESCRIPTION Configure jabberd2 by editing c2s.xml: pipe /usr/local/libexec/jabberd-authpipe-pam.pl Place this script in /usr/local/libexec then run: chown root jabberd-authpipe-pam.pl chmod 4755 jabberd-authpipe-pam.pl This sets the script to run as suid root and gives it access to the shadow password file. You man need to install perl-suid in order to run perl scripts with the suid bit set. This script only implements the User-Exists and Check-Password routines. See docs/dev/c2s-pipe-authenticator for details about the protocol. To get this script to work with PSI, Ifound that I had to enable "Allow Plaintext Login" in PSI. Please make sure that you use SSL so that plain-text passwords aren't sent over the network. =head1 README This script allows Jabber authentication against PAM without running jabberd as root. =head1 PREREQUISITES This script requires the Jabberd 2.0 server. It also requires the following other modules from CPAN: C and C. =pod OSNAMES Linux =pod SCRIPT CATEGORIES Misc =head1 AUTHOR Nicholas Humfrey Enjh@aelius.comE =head1 COPYRIGHT Copyright (c) 2006, Nicholas J Humfrey This code is hereby placed into the public domain. =cut