From 652a7f0ed2e6d1749fd56cd951e5daea2a4b171a Mon Sep 17 00:00:00 2001 From: thomascube Date: Mon, 20 Apr 2009 15:43:54 +0000 Subject: A SASL password changing plugin inspired by the Squirrelmail Change SASL Password Plugin --- plugins/sasl_password/README | 65 ++++++++++++++ plugins/sasl_password/chgsaslpasswd.c | 27 ++++++ plugins/sasl_password/locale/de_CH.inc | 16 ++++ plugins/sasl_password/locale/en_US.inc | 16 ++++ plugins/sasl_password/sasl_password.js | 43 ++++++++++ plugins/sasl_password/sasl_password.php | 144 ++++++++++++++++++++++++++++++++ 6 files changed, 311 insertions(+) create mode 100644 plugins/sasl_password/README create mode 100644 plugins/sasl_password/chgsaslpasswd.c create mode 100644 plugins/sasl_password/locale/de_CH.inc create mode 100644 plugins/sasl_password/locale/en_US.inc create mode 100644 plugins/sasl_password/sasl_password.js create mode 100644 plugins/sasl_password/sasl_password.php (limited to 'plugins') diff --git a/plugins/sasl_password/README b/plugins/sasl_password/README new file mode 100644 index 000000000..3fbc448ff --- /dev/null +++ b/plugins/sasl_password/README @@ -0,0 +1,65 @@ ++-------------------------------------------------------------------------+ +| +| Author: Thomas Bruederli +| Source: Squirrelmail Change SASL Password Plugin by Galen Johnson +| Program: sasl_password +| Version: 1.0 +| Purpose: Change Cyrus Account Passwords +| ++-------------------------------------------------------------------------+ + + +Purpose +------- +Cyrus SASL database authentication allows your Cyrus+RoundCube +installation to host mail users without requiring a Unix Shell account! + +This plugin only covers the "sasldb" case when using Cyrus SASL. Kerberos +and PAM authentication mechanisms will require other techniques to enable +user password manipulations. + +Cyrus SASL includes a shell utility called "saslpasswd" for manipulating +user passwords in the "sasldb" database. This patch attempts to use +this utility to perform password manipulations required by your webmail +users without any administrative interaction. Unfortunately, this +scheme requires that the "saslpasswd" utility be run as the "cyrus" +user - kind of a security problem since we have chosen to SUID a small +script which will allow this to happen. + +This plugin is based on the Squirrelmail Change SASL Password Plugin. +See http://www.squirrelmail.org/plugin_view.php?id=107 for details. + + +Installation +------------ +Install just like any other plugin, just put it in the plugin directory +and activate it by adding 'sasl_password' to the list of active plugins +in config/main.inc.php + +Edit the chgsaslpasswd.c and chgsaslpasswd.sh files as is documented +within them. + +Compile the wrapper program: + gcc -o chgsaslpasswd chgsaslpasswd.c + +Chown the chgsaslpasswd and chgsaslpasswd.sh to the cyrus user and group +that your browser runs as, then chmod them to 4550. + +For example, if your cyrus user is 'cyrus' and the apache server group is +'nobody' (I've been told Redhat runs Apache as user 'apache'): + + chown cyrus:nobody chgsaslpasswd + chmod 4550 chgsaslpasswd + +Stephen Carr has suggested users should try to run the scripts on a test +account as the cyrus user eg; + + su cyrus -c "./chgsaslpasswd -p test_account" + +This will allow you to make sure that the script will work for your setup. +Should the script not work, make sure that: +1) the user the script runs as has access to the saslpasswd|saslpasswd2 + file and proper permissions +2) make sure the user in the chgsaslpasswd.c file is set correctly. + This could save you some headaches if you are the paranoid type. + diff --git a/plugins/sasl_password/chgsaslpasswd.c b/plugins/sasl_password/chgsaslpasswd.c new file mode 100644 index 000000000..17e20c67f --- /dev/null +++ b/plugins/sasl_password/chgsaslpasswd.c @@ -0,0 +1,27 @@ +#include +#include + +// set the UID this script will run as (cyrus user) +#define UID 96 +// set the path to saslpasswd or saslpasswd2 +#define CMD "/usr/sbin/saslpasswd2" + +/* INSTALLING: + gcc -o chgsaslpasswd chgsaslpasswd.c + chown root.apache chgsaslpasswd + strip chgsaslpasswd + chmod 4550 chgsaslpasswd +*/ + +main(int argc, char *argv[]) +{ + int rc,cc; + + cc = setuid(UID); + rc = execvp(CMD, argv); + if ((rc != 0) || (cc != 0)) + { + fprintf(stderr,"__ %s: failed %d %d\n",argv[0],rc,cc); + exit(1); + } +} diff --git a/plugins/sasl_password/locale/de_CH.inc b/plugins/sasl_password/locale/de_CH.inc new file mode 100644 index 000000000..399efda84 --- /dev/null +++ b/plugins/sasl_password/locale/de_CH.inc @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/plugins/sasl_password/locale/en_US.inc b/plugins/sasl_password/locale/en_US.inc new file mode 100644 index 000000000..42708b34f --- /dev/null +++ b/plugins/sasl_password/locale/en_US.inc @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/plugins/sasl_password/sasl_password.js b/plugins/sasl_password/sasl_password.js new file mode 100644 index 000000000..719dc8268 --- /dev/null +++ b/plugins/sasl_password/sasl_password.js @@ -0,0 +1,43 @@ +/* SASL pssword change interface (tab) */ + +function sasl_password_save() +{ + var input_curpasswd = $('#saslcurpasswd')[0]; + var input_newpasswd = $('#saslnewpasswd')[0]; + var input_confpasswd = $('#saslconfpasswd')[0]; + + if (input_curpasswd && input_curpasswd.value=='') { + alert(rcmail.gettext('nocurpassword', 'sasl_password')); + input_curpasswd.focus(); + } + else if (input_newpasswd && input_newpasswd.value=='') { + alert(rcmail.gettext('nopassword', 'sasl_password')); + input_newpasswd.focus(); + } + else if (input_confpasswd && input_confpasswd.value=='') { + alert(rcmail.gettext('nopassword', 'sasl_password')); + input_confpasswd.focus(); + } + else if ((input_newpasswd && input_confpasswd) && (input_newpasswd.value != input_confpasswd.value)) { + alert(rcmail.gettext('passwordinconsistency', 'sasl_password')); + input_newpasswd.focus(); + } + else { + rcmail.gui_objects.passform.submit(); + } +} + +if (window.rcmail) { + rcmail.addEventListener('init', function(evt) { + // + var tab = $('').attr('id', 'settingstabpluginsaslpassword').addClass('tablink'); + + var button = $('').attr('href', rcmail.env.comm_path+'&_action=plugin.saslpassword').html(rcmail.gettext('password')).appendTo(tab); + button.bind('click', function(e){ return rcmail.command('plugin.saslpassword', this) }); + + // add button and register commands + rcmail.add_element(tab, 'tabs'); + rcmail.register_command('plugin.saslpassword', function() { rcmail.goto_url('plugin.saslpassword') }, true); + rcmail.register_command('plugin.saslpassword-save', sasl_password_save, true); + }); +} diff --git a/plugins/sasl_password/sasl_password.php b/plugins/sasl_password/sasl_password.php new file mode 100644 index 000000000..3a23557e9 --- /dev/null +++ b/plugins/sasl_password/sasl_password.php @@ -0,0 +1,144 @@ +output->add_label('password'); + $this->register_action('plugin.saslpassword', array($this, 'password_init')); + $this->register_action('plugin.saslpassword-save', array($this, 'password_save')); + $this->register_handler('plugin.body', array($this, 'password_form')); + $this->include_script('sasl_password.js'); + } + + function password_init() + { + $this->add_texts('locale/'); + $rcmail = rcmail::get_instance(); + $rcmail->output->set_pagetitle($this->gettext('changepasswd')); + $rcmail->output->send('plugin'); + } + + function password_save() + { + $rcmail = rcmail::get_instance(); + + $this->add_texts('locale/'); + + if (!isset($_POST['_curpasswd']) || !isset($_POST['_newpasswd'])) { + $rcmail->output->command('display_message', $this->gettext('nopassword'), 'error'); + } + else { + $curpwd = get_input_value('_curpasswd', RCUBE_INPUT_POST); + $newpwd = get_input_value('_newpasswd', RCUBE_INPUT_POST); + + if ($_SESSION['password'] != $rcmail->encrypt_passwd($curpwd)) { + $rcmail->output->command('display_message', $this->gettext('passwordincorrect'), 'error'); + } + else if ($this->_save($newpwd)) { + $rcmail->output->command('display_message', $this->gettext('successfullysaved'), 'confirmation'); + $_SESSION['password'] = $rcmail->encrypt_passwd($newpwd); + } + else { + $rcmail->output->command('display_message', $this->gettext('errorsaving'), 'error'); + } + } + + rcmail_overwrite_action('plugin.saslpassword'); + rcmail::get_instance()->output->send('plugin'); + } + + function password_form() + { + $rcmail = rcmail::get_instance(); + + // add some labels to client + $rcmail->output->add_label( + 'sasl_password.nopassword', + 'sasl_password.nocurpassword', + 'sasl_password.passwordinconsistency', + 'sasl_password.changepasswd' + ); + + $table = new html_table(array('cols' => 2)); + + // show current password selection + $field_id = 'saslcurpasswd'; + $input_newpasswd = new html_passwordfield(array('name' => '_curpasswd', 'id' => $field_id, 'size' => 25)); + + $table->add('title', html::label($field_id, Q($this->gettext('curpasswd')))); + $table->add(null, $input_newpasswd->show()); + + // show new password selection + $field_id = 'saslnewpasswd'; + $input_newpasswd = new html_passwordfield(array('name' => '_newpasswd', 'id' => $field_id, 'size' => 25)); + + $table->add('title', html::label($field_id, Q($this->gettext('newpasswd')))); + $table->add(null, $input_newpasswd->show()); + + // show confirm password selection + $field_id = 'saslconfpasswd'; + $input_confpasswd = new html_passwordfield(array('name' => '_confpasswd', 'id' => $field_id, 'size' => 25)); + + $table->add('title', html::label($field_id, Q($this->gettext('confpasswd')))); + $table->add(null, $input_confpasswd->show()); + + $out = html::div(array('class' => "settingsbox", 'style' => "margin:0"), + html::div(array('id' => "userprefs-title"), $this->gettext('changepasswd')) . + html::div(array('style' => "padding:15px"), $table->show() . + html::p(null, + $rcmail->output->button(array( + 'command' => 'plugin.saslpassword-save', + 'type' => 'input', + 'class' => 'button mainaction', + 'label' => 'save' + ))) + ) + ); + + $rcmail->output->add_gui_object('passform', 'password-form'); + + return $rcmail->output->form_tag(array( + 'id' => 'password-form', + 'name' => 'password-form', + 'method' => 'post', + 'action' => './?_task=settings&_action=plugin.saslpassword-save', + ), $out); + } + + private function _save($passwd) + { + $curdir = realpath(dirname(__FILE__)); + $username = escapeshellcmd($_SESSION['username']); + $code = 1; + + if ($fh = popen("$curdir/chgsaslpasswd -p $username", 'w')) { + fwrite($fh, $passwd."\n"); + $code = pclose($fh); + } + + return ($code == 0); + } + +} + +?> -- cgit v1.2.3