[imp] Contrib: Integrated LDAP Change Password Page

Lee lee@disinfo.com
Thu, 27 Jun 2002 22:51:04 -0400


This message is in MIME format.

---------------------- multipart/mixed attachment
I made a page (integrated as best I could with horde/imp) that allows the user 
to change thier password (assumes user accounts are stored in ldap directory). 
To install simple drop the changepass.php file in the imp directory, change the 
config variables at the top of changepass.php, and add 
the lines in the attached menu.php file to imp's config/menu.php (this will 
create an imp menu icon that points to the change password page). 

Please note that I have only tested this on my system that uses imp to handle 
authentication, but it should work for everyone.

Lee



-----------------------------------
changepass.php
-----------------------------------

<?php


// Created By Lee (lee@disinfo.com)

define('IMP_BASE', dirname(__FILE__));
require_once IMP_BASE . '/lib/base.php';
require_once HORDE_BASE . '/lib/Registry.php';

if (($reason = IMP::authenticate(OP_HALFOPEN, true)) !== true) {
  header('Location: ' . Horde::applicationUrl(IMP::logoutUrl('login.php?url=' . 
Horde::selfUrl(), $reason), true));
  exit;
}

$usermail=Auth::getAuth();
$uid = preg_replace('|@.*|i', '', $usermail);
$password=Auth::getCredential('password');

$support_address = 'support@domain.com';

$ldap_pass_config = array(
     'server' => 'ldap.domainname.com',
     'port' => 389,
     'root' => 'ou=users,dc=domain,dc=com',
     /*BIND AS USER NOT AS ROOT    */
     'bind_dn' => 'uid=' . $uid . ',ou=users,dc=domain,dc=com',
     'bind_password' => $password,
     'dn' => 'uid',
     'dn_value' => $uid,
     'password_field' => 'userPassword',
     );

if (isset($HTTP_POST_VARS['not_first_load'])) // Not First load

     // Get messages
     $Messages = change_ldappass_check();

     // Error
     if (isset($Messages) && count($Messages) && ($Messages[0] != 'success')) {
       
       $msg_string = "";
       
       $i = 0;

       foreach ($Messages as $line) {
	 if ($i == 0)
	   $msg_string .= $line . "<br>\n";
	 else
	   $msg_string .= Horde::img('folders/spacer.gif', 'alt="" height="1" 
width="16"') . "&nbsp;&nbsp;" . $line . "<br>\n";
	 $i++;
       }

       Horde::raiseMessage(_($msg_string), HORDE_ERROR);
       
     }

     // Success
     else if (isset($Messages) && count($Messages) && ($Messages[0] 
== 'success')){
  
       Horde::raiseMessage(_("Password Changed Successfully! You will now be 
logged out."), HORDE_SUCCESS);

       // Redirect to logout
       $refresh_time = 3;

       if ($registry->getMethod('auth/logout') == 'imp') {
	 $refresh_url = Horde::url($registry->getInitialPage
('imp') . 'login.php?reason=logout');
       } 
       else {
	 $refresh_url = Horde::url($registry->getParam
('webroot', 'horde') . '/login.php?reason=logout');
       }


     }

     $title = _("Change Account Password");

     $js_onLoad = null;
     require IMP_TEMPLATES . '/common-header.inc';
     require IMP_BASE . '/menu.php';
     require IMP_BASE . '/status.php';

?>

<form method=post action="<?php print $_SERVER['PHP_SELF'] ?>">
<table border="0" align="center" width="100%" cellspacing="0" cellpadding="3">
<tr><td class="header" align="left"><b>Change Account Password</b></td></tr>
<tr><td class="item"><table border="0"><tr valign="top"><td class="item">

<table align=center cellpadding=2 cellspacing=2 border=0>

<tr><td align="left">

    <input type=hidden name=not_first_load value=true>

        Old Password:<br>
        <input type=password name=cp_oldpass value=""  size=50><br>

        New Password:<br>
        <input type=password name=cp_newpass value="" size=50><br>

        Verify New Password:<br>
        <input type=password name=cp_verify value="" size=50><br>

</td></tr>
</tr></table>

</td></tr></table></td></tr></table>

<p><input type=submit class="button" value="Change" 
name="plugin_change_ldappass">
</form>

</body></html>
<?php


include IMP_TEMPLATES . '/common-footer.inc';

function change_ldappass_check($debug = 0) {

   global $HTTP_POST_VARS, $ldap_pass_config;

   $Messages = array();
	
   if ((!isset($HTTP_POST_VARS['cp_oldpass'])) || $HTTP_POST_VARS['cp_oldpass']
=="")
       array_push($Messages, 'You must type in your old password.');
   if ((!isset($HTTP_POST_VARS['cp_newpass'])) || $HTTP_POST_VARS['cp_newpass']
=="")
       array_push($Messages, 'You must type in a new password.');
   if ((!isset($HTTP_POST_VARS['cp_verify'])) || $HTTP_POST_VARS['cp_verify']
=="")
       array_push($Messages,
           'You must also type in your new password in the verify box.');
   if ($HTTP_POST_VARS['cp_newpass'] != '' && $HTTP_POST_VARS['cp_verify'] != 
$HTTP_POST_VARS['cp_newpass'])
       array_push($Messages,
           'Your new passwords don\'t match.');
   if ($HTTP_POST_VARS['cp_oldpass'] != '' && $HTTP_POST_VARS['cp_oldpass'] != 
$ldap_pass_config['bind_password'])
       array_push($Messages, 'Your old password is not correct.');
   if ((strlen($HTTP_POST_VARS['cp_newpass'])<6) || (strlen($HTTP_POST_VARS
['cp_newpass'])>16))
	array_push($Messages, 'Your new password must be between 6 and 16 
characters.');
   if (!(ereg("^([0-9]|[a-z]|[A-Z]|_)*$", $HTTP_POST_VARS['cp_newpass'])))
	array_push($Messages, 'Your new password may only contain characters: a-
z, A-Z, 0-9 and _');

   if (count($Messages))
       return $Messages;

   return change_ldappass_go();
}


function change_ldappass_go() {

    global $HTTP_POST_VARS, $ldap_pass_config, $support_address;

    $Messages = array();
    
    $ds=ldap_connect($ldap_pass_config['server'], $ldap_pass_config['port']);
    if (! $ds) {
      array_push($Messages,'Can\'t connect to Directory Server, please 
email ' . $support_address . '!');
      return $Messages;
    }

    $r=ldap_bind($ds,$ldap_pass_config['bind_dn'],$ldap_pass_config
['bind_password']);
    
    if (! $r) {
      array_push($Messages,'Can\'t authenticate to Directory Server, please ' . 
$support_address . '!');
      return $Messages;
    }

    $sr=ldap_search($ds,$ldap_pass_config['root'], $ldap_pass_config
['dn']."=".$ldap_pass_config['dn_value']); 
    
    if (ldap_count_entries($ds,$sr)!=1) {  //make sure we only have 1 uid
      array_push($Messages,'Duplicate login entries detected, cannot change 
password!');
      return $Messages;
    }

    $resinfo = ldap_get_entries($ds, $sr);
    $to_change_dn=$resinfo[0]["dn"];

    // Update the password
    
    $ldap_info[$ldap_pass_config['password_field']]=$HTTP_POST_VARS
['cp_newpass'];


    if (ldap_modify($ds,$to_change_dn,$ldap_info)) {

      $Messages[0] = 'success'; // Success
      return $Messages;

    } 
	
    else {
      array_push($Messages,'Password change was not successful!');
      return $Messages;
    }

    @ldap_close($ds);
	       
    }
    
?>


---------------------------------
menu.php
---------------------------------

<?php
/*
 * $Horde: imp/config/menu.php.dist,v 1.2.2.1 2002/03/10 03:05:58 chuck Exp $
 *
 * This file lets you extend IMP's menu with your own items.
 *
 * To add a new menu item, simply add a new entry to the $_menu array.
 * Valid attributes for a new menu item are:
 *
 *  'url'       The URL value for the menu item.
 *  'text'      The text to accompany the menu item.
 *
 * These attributes are optional:
 *
 *  'icon'      The filename of an icon to use for the menu item.
 *  'icon_path' The path to the icon if it doesn't exist in the graphics/
 *              directory.
 *  'target'    The "target" of the link (e.g. '_top', '_blank').
 *  'onclick'   Any JavaScript to execute on the "onclick" event.
 *
 * Here's an example entry:
 *
 *  $_menu[] = array(   
 *      'url' =>        'http://www.example.com/',
 *      'text' =>       'Example, Inc.',
 *      'icon' =>       'example.gif',
 *      'icon_path' =>  'http://www.example.com/images/',
 *      'target' =>     '_blank',
 *      'onclick' =>    ''
 *  );
 *
 * You can also add a "separator" (a spacer) between menu items.  To add a
 * separator, simply add a new string to the $_menu array set to the text
 * 'separator'.  It should look like this:
 *
 *  $_menu[] = 'separator';
 */

/* Add your custom entries below this line. */

$_menu[] = array(

	       'url' => Horde::url($registry->getInitialPage
('imp') . 'changepass.php'),
               'text' => 'Change Password',
               'icon' => 'lock.gif',
               'icon_path' => Horde::url($registry->getInitialPage
('imp') . 'graphics/'),
               'target' => '',
               'onclick' => ''

	       );


---------------------- multipart/mixed attachment
PD9waHANCi8qDQogKiAkSG9yZGU6IGltcC9jb25maWcvbWVudS5waHAuZGlzdCx2IDEuMi4yLjEg
MjAwMi8wMy8xMCAwMzowNTo1OCBjaHVjayBFeHAgJA0KICoNCiAqIFRoaXMgZmlsZSBsZXRzIHlv
dSBleHRlbmQgSU1QJ3MgbWVudSB3aXRoIHlvdXIgb3duIGl0ZW1zLg0KICoNCiAqIFRvIGFkZCBh
IG5ldyBtZW51IGl0ZW0sIHNpbXBseSBhZGQgYSBuZXcgZW50cnkgdG8gdGhlICRfbWVudSBhcnJh
eS4NCiAqIFZhbGlkIGF0dHJpYnV0ZXMgZm9yIGEgbmV3IG1lbnUgaXRlbSBhcmU6DQogKg0KICog
ICd1cmwnICAgICAgIFRoZSBVUkwgdmFsdWUgZm9yIHRoZSBtZW51IGl0ZW0uDQogKiAgJ3RleHQn
ICAgICAgVGhlIHRleHQgdG8gYWNjb21wYW55IHRoZSBtZW51IGl0ZW0uDQogKg0KICogVGhlc2Ug
YXR0cmlidXRlcyBhcmUgb3B0aW9uYWw6DQogKg0KICogICdpY29uJyAgICAgIFRoZSBmaWxlbmFt
ZSBvZiBhbiBpY29uIHRvIHVzZSBmb3IgdGhlIG1lbnUgaXRlbS4NCiAqICAnaWNvbl9wYXRoJyBU
aGUgcGF0aCB0byB0aGUgaWNvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGluIHRoZSBncmFwaGljcy8N
CiAqICAgICAgICAgICAgICBkaXJlY3RvcnkuDQogKiAgJ3RhcmdldCcgICAgVGhlICJ0YXJnZXQi
IG9mIHRoZSBsaW5rIChlLmcuICdfdG9wJywgJ19ibGFuaycpLg0KICogICdvbmNsaWNrJyAgIEFu
eSBKYXZhU2NyaXB0IHRvIGV4ZWN1dGUgb24gdGhlICJvbmNsaWNrIiBldmVudC4NCiAqDQogKiBI
ZXJlJ3MgYW4gZXhhbXBsZSBlbnRyeToNCiAqDQogKiAgJF9tZW51W10gPSBhcnJheSggICANCiAq
ICAgICAgJ3VybCcgPT4gICAgICAgICdodHRwOi8vd3d3LmV4YW1wbGUuY29tLycsDQogKiAgICAg
ICd0ZXh0JyA9PiAgICAgICAnRXhhbXBsZSwgSW5jLicsDQogKiAgICAgICdpY29uJyA9PiAgICAg
ICAnZXhhbXBsZS5naWYnLA0KICogICAgICAnaWNvbl9wYXRoJyA9PiAgJ2h0dHA6Ly93d3cuZXhh
bXBsZS5jb20vaW1hZ2VzLycsDQogKiAgICAgICd0YXJnZXQnID0+ICAgICAnX2JsYW5rJywNCiAq
ICAgICAgJ29uY2xpY2snID0+ICAgICcnDQogKiAgKTsNCiAqDQogKiBZb3UgY2FuIGFsc28gYWRk
IGEgInNlcGFyYXRvciIgKGEgc3BhY2VyKSBiZXR3ZWVuIG1lbnUgaXRlbXMuICBUbyBhZGQgYQ0K
ICogc2VwYXJhdG9yLCBzaW1wbHkgYWRkIGEgbmV3IHN0cmluZyB0byB0aGUgJF9tZW51IGFycmF5
IHNldCB0byB0aGUgdGV4dA0KICogJ3NlcGFyYXRvcicuICBJdCBzaG91bGQgbG9vayBsaWtlIHRo
aXM6DQogKg0KICogICRfbWVudVtdID0gJ3NlcGFyYXRvcic7DQogKi8NCg0KLyogQWRkIHlvdXIg
Y3VzdG9tIGVudHJpZXMgYmVsb3cgdGhpcyBsaW5lLiAqLw0KDQokX21lbnVbXSA9IGFycmF5KA0K
DQoJICAgICAgICd1cmwnID0+IEhvcmRlOjp1cmwoJHJlZ2lzdHJ5LT5nZXRJbml0aWFsUGFnZSgn
aW1wJykgLiAnY2hhbmdlcGFzcy5waHAnKSwNCiAgICAgICAgICAgICAgICd0ZXh0JyA9PiAnQ2hh
bmdlIFBhc3N3b3JkJywNCiAgICAgICAgICAgICAgICdpY29uJyA9PiAnbG9jay5naWYnLA0KICAg
ICAgICAgICAgICAgJ2ljb25fcGF0aCcgPT4gSG9yZGU6OnVybCgkcmVnaXN0cnktPmdldEluaXRp
YWxQYWdlKCdpbXAnKSAuICdncmFwaGljcy8nKSwNCiAgICAgICAgICAgICAgICd0YXJnZXQnID0+
ICcnLA0KICAgICAgICAgICAgICAgJ29uY2xpY2snID0+ICcnDQoNCgkgICAgICAgKTs=

---------------------- multipart/mixed attachment
PD9waHANCg0KDQovLyBDcmVhdGVkIEJ5IExlZSAobGVlQGRpc2luZm8uY29tKQ0KDQpkZWZpbmUo
J0lNUF9CQVNFJywgZGlybmFtZShfX0ZJTEVfXykpOw0KcmVxdWlyZV9vbmNlIElNUF9CQVNFIC4g
Jy9saWIvYmFzZS5waHAnOw0KcmVxdWlyZV9vbmNlIEhPUkRFX0JBU0UgLiAnL2xpYi9SZWdpc3Ry
eS5waHAnOw0KDQppZiAoKCRyZWFzb24gPSBJTVA6OmF1dGhlbnRpY2F0ZShPUF9IQUxGT1BFTiwg
dHJ1ZSkpICE9PSB0cnVlKSB7DQogIGhlYWRlcignTG9jYXRpb246ICcgLiBIb3JkZTo6YXBwbGlj
YXRpb25VcmwoSU1QOjpsb2dvdXRVcmwoJ2xvZ2luLnBocD91cmw9JyAuIEhvcmRlOjpzZWxmVXJs
KCksICRyZWFzb24pLCB0cnVlKSk7DQogIGV4aXQ7DQp9DQoNCiR1c2VybWFpbD1BdXRoOjpnZXRB
dXRoKCk7DQokdWlkID0gcHJlZ19yZXBsYWNlKCd8QC4qfGknLCAnJywgJHVzZXJtYWlsKTsNCiRw
YXNzd29yZD1BdXRoOjpnZXRDcmVkZW50aWFsKCdwYXNzd29yZCcpOw0KDQokc3VwcG9ydF9hZGRy
ZXNzID0gJ3N1cHBvcnRAZG9tYWluLmNvbSc7DQoNCiRsZGFwX3Bhc3NfY29uZmlnID0gYXJyYXko
DQogICAgICdzZXJ2ZXInID0+ICdsZGFwLmRvbWFpbm5hbWUuY29tJywNCiAgICAgJ3BvcnQnID0+
IDM4OSwNCiAgICAgJ3Jvb3QnID0+ICdvdT11c2VycyxkYz1kb21haW4sZGM9Y29tJywNCiAgICAg
LypCSU5EIEFTIFVTRVIgTk9UIEFTIFJPT1QgICAgKi8NCiAgICAgJ2JpbmRfZG4nID0+ICd1aWQ9
JyAuICR1aWQgLiAnLG91PXVzZXJzLGRjPWRvbWFpbixkYz1jb20nLA0KICAgICAnYmluZF9wYXNz
d29yZCcgPT4gJHBhc3N3b3JkLA0KICAgICAnZG4nID0+ICd1aWQnLA0KICAgICAnZG5fdmFsdWUn
ID0+ICR1aWQsDQogICAgICdwYXNzd29yZF9maWVsZCcgPT4gJ3VzZXJQYXNzd29yZCcsDQogICAg
ICk7DQoNCmlmIChpc3NldCgkSFRUUF9QT1NUX1ZBUlNbJ25vdF9maXJzdF9sb2FkJ10pKSAvLyBO
b3QgRmlyc3QgbG9hZA0KDQogICAgIC8vIEdldCBtZXNzYWdlcw0KICAgICAkTWVzc2FnZXMgPSBj
aGFuZ2VfbGRhcHBhc3NfY2hlY2soKTsNCg0KICAgICAvLyBFcnJvcg0KICAgICBpZiAoaXNzZXQo
JE1lc3NhZ2VzKSAmJiBjb3VudCgkTWVzc2FnZXMpICYmICgkTWVzc2FnZXNbMF0gIT0gJ3N1Y2Nl
c3MnKSkgew0KICAgICAgIA0KICAgICAgICRtc2dfc3RyaW5nID0gIiI7DQogICAgICAgDQogICAg
ICAgJGkgPSAwOw0KDQogICAgICAgZm9yZWFjaCAoJE1lc3NhZ2VzIGFzICRsaW5lKSB7DQoJIGlm
ICgkaSA9PSAwKQ0KCSAgICRtc2dfc3RyaW5nIC49ICRsaW5lIC4gIjxicj5cbiI7DQoJIGVsc2UN
CgkgICAkbXNnX3N0cmluZyAuPSBIb3JkZTo6aW1nKCdmb2xkZXJzL3NwYWNlci5naWYnLCAnYWx0
PSIiIGhlaWdodD0iMSIgd2lkdGg9IjE2IicpIC4gIiZuYnNwOyZuYnNwOyIgLiAkbGluZSAuICI8
YnI+XG4iOw0KCSAkaSsrOw0KICAgICAgIH0NCg0KICAgICAgIEhvcmRlOjpyYWlzZU1lc3NhZ2Uo
XygkbXNnX3N0cmluZyksIEhPUkRFX0VSUk9SKTsNCiAgICAgICANCiAgICAgfQ0KDQogICAgIC8v
IFN1Y2Nlc3MNCiAgICAgZWxzZSBpZiAoaXNzZXQoJE1lc3NhZ2VzKSAmJiBjb3VudCgkTWVzc2Fn
ZXMpICYmICgkTWVzc2FnZXNbMF0gPT0gJ3N1Y2Nlc3MnKSl7DQogIA0KICAgICAgIEhvcmRlOjpy
YWlzZU1lc3NhZ2UoXygiUGFzc3dvcmQgQ2hhbmdlZCBTdWNjZXNzZnVsbHkhIFlvdSB3aWxsIG5v
dyBiZSBsb2dnZWQgb3V0LiIpLCBIT1JERV9TVUNDRVNTKTsNCg0KICAgICAgIC8vIFJlZGlyZWN0
IHRvIGxvZ291dA0KICAgICAgICRyZWZyZXNoX3RpbWUgPSAzOw0KDQogICAgICAgaWYgKCRyZWdp
c3RyeS0+Z2V0TWV0aG9kKCdhdXRoL2xvZ291dCcpID09ICdpbXAnKSB7DQoJICRyZWZyZXNoX3Vy
bCA9IEhvcmRlOjp1cmwoJHJlZ2lzdHJ5LT5nZXRJbml0aWFsUGFnZSgnaW1wJykgLiAnbG9naW4u
cGhwP3JlYXNvbj1sb2dvdXQnKTsNCiAgICAgICB9IA0KICAgICAgIGVsc2Ugew0KCSAkcmVmcmVz
aF91cmwgPSBIb3JkZTo6dXJsKCRyZWdpc3RyeS0+Z2V0UGFyYW0oJ3dlYnJvb3QnLCAnaG9yZGUn
KSAuICcvbG9naW4ucGhwP3JlYXNvbj1sb2dvdXQnKTsNCiAgICAgICB9DQoNCg0KICAgICB9DQoN
CiAgICAgJHRpdGxlID0gXygiQ2hhbmdlIEFjY291bnQgUGFzc3dvcmQiKTsNCg0KICAgICAkanNf
b25Mb2FkID0gbnVsbDsNCiAgICAgcmVxdWlyZSBJTVBfVEVNUExBVEVTIC4gJy9jb21tb24taGVh
ZGVyLmluYyc7DQogICAgIHJlcXVpcmUgSU1QX0JBU0UgLiAnL21lbnUucGhwJzsNCiAgICAgcmVx
dWlyZSBJTVBfQkFTRSAuICcvc3RhdHVzLnBocCc7DQoNCj8+DQoNCjxmb3JtIG1ldGhvZD1wb3N0
IGFjdGlvbj0iPD9waHAgcHJpbnQgJF9TRVJWRVJbJ1BIUF9TRUxGJ10gPz4iPg0KPHRhYmxlIGJv
cmRlcj0iMCIgYWxpZ249ImNlbnRlciIgd2lkdGg9IjEwMCUiIGNlbGxzcGFjaW5nPSIwIiBjZWxs
cGFkZGluZz0iMyI+DQo8dHI+PHRkIGNsYXNzPSJoZWFkZXIiIGFsaWduPSJsZWZ0Ij48Yj5DaGFu
Z2UgQWNjb3VudCBQYXNzd29yZDwvYj48L3RkPjwvdHI+DQo8dHI+PHRkIGNsYXNzPSJpdGVtIj48
dGFibGUgYm9yZGVyPSIwIj48dHIgdmFsaWduPSJ0b3AiPjx0ZCBjbGFzcz0iaXRlbSI+DQoNCjx0
YWJsZSBhbGlnbj1jZW50ZXIgY2VsbHBhZGRpbmc9MiBjZWxsc3BhY2luZz0yIGJvcmRlcj0wPg0K
DQo8dHI+PHRkIGFsaWduPSJsZWZ0Ij4NCg0KICAgIDxpbnB1dCB0eXBlPWhpZGRlbiBuYW1lPW5v
dF9maXJzdF9sb2FkIHZhbHVlPXRydWU+DQoNCiAgICAgICAgT2xkIFBhc3N3b3JkOjxicj4NCiAg
ICAgICAgPGlucHV0IHR5cGU9cGFzc3dvcmQgbmFtZT1jcF9vbGRwYXNzIHZhbHVlPSIiICBzaXpl
PTUwPjxicj4NCg0KICAgICAgICBOZXcgUGFzc3dvcmQ6PGJyPg0KICAgICAgICA8aW5wdXQgdHlw
ZT1wYXNzd29yZCBuYW1lPWNwX25ld3Bhc3MgdmFsdWU9IiIgc2l6ZT01MD48YnI+DQoNCiAgICAg
ICAgVmVyaWZ5IE5ldyBQYXNzd29yZDo8YnI+DQogICAgICAgIDxpbnB1dCB0eXBlPXBhc3N3b3Jk
IG5hbWU9Y3BfdmVyaWZ5IHZhbHVlPSIiIHNpemU9NTA+PGJyPg0KDQo8L3RkPjwvdHI+DQo8L3Ry
PjwvdGFibGU+DQoNCjwvdGQ+PC90cj48L3RhYmxlPjwvdGQ+PC90cj48L3RhYmxlPg0KDQo8cD48
aW5wdXQgdHlwZT1zdWJtaXQgY2xhc3M9ImJ1dHRvbiIgdmFsdWU9IkNoYW5nZSIgbmFtZT0icGx1
Z2luX2NoYW5nZV9sZGFwcGFzcyI+DQo8L2Zvcm0+DQoNCjwvYm9keT48L2h0bWw+DQo8P3BocA0K
DQoNCmluY2x1ZGUgSU1QX1RFTVBMQVRFUyAuICcvY29tbW9uLWZvb3Rlci5pbmMnOw0KDQpmdW5j
dGlvbiBjaGFuZ2VfbGRhcHBhc3NfY2hlY2soJGRlYnVnID0gMCkgew0KDQogICBnbG9iYWwgJEhU
VFBfUE9TVF9WQVJTLCAkbGRhcF9wYXNzX2NvbmZpZzsNCg0KICAgJE1lc3NhZ2VzID0gYXJyYXko
KTsNCgkNCiAgIGlmICgoIWlzc2V0KCRIVFRQX1BPU1RfVkFSU1snY3Bfb2xkcGFzcyddKSkgfHwg
JEhUVFBfUE9TVF9WQVJTWydjcF9vbGRwYXNzJ109PSIiKQ0KICAgICAgIGFycmF5X3B1c2goJE1l
c3NhZ2VzLCAnWW91IG11c3QgdHlwZSBpbiB5b3VyIG9sZCBwYXNzd29yZC4nKTsNCiAgIGlmICgo
IWlzc2V0KCRIVFRQX1BPU1RfVkFSU1snY3BfbmV3cGFzcyddKSkgfHwgJEhUVFBfUE9TVF9WQVJT
WydjcF9uZXdwYXNzJ109PSIiKQ0KICAgICAgIGFycmF5X3B1c2goJE1lc3NhZ2VzLCAnWW91IG11
c3QgdHlwZSBpbiBhIG5ldyBwYXNzd29yZC4nKTsNCiAgIGlmICgoIWlzc2V0KCRIVFRQX1BPU1Rf
VkFSU1snY3BfdmVyaWZ5J10pKSB8fCAkSFRUUF9QT1NUX1ZBUlNbJ2NwX3ZlcmlmeSddPT0iIikN
CiAgICAgICBhcnJheV9wdXNoKCRNZXNzYWdlcywNCiAgICAgICAgICAgJ1lvdSBtdXN0IGFsc28g
dHlwZSBpbiB5b3VyIG5ldyBwYXNzd29yZCBpbiB0aGUgdmVyaWZ5IGJveC4nKTsNCiAgIGlmICgk
SFRUUF9QT1NUX1ZBUlNbJ2NwX25ld3Bhc3MnXSAhPSAnJyAmJiAkSFRUUF9QT1NUX1ZBUlNbJ2Nw
X3ZlcmlmeSddICE9ICRIVFRQX1BPU1RfVkFSU1snY3BfbmV3cGFzcyddKQ0KICAgICAgIGFycmF5
X3B1c2goJE1lc3NhZ2VzLA0KICAgICAgICAgICAnWW91ciBuZXcgcGFzc3dvcmRzIGRvblwndCBt
YXRjaC4nKTsNCiAgIGlmICgkSFRUUF9QT1NUX1ZBUlNbJ2NwX29sZHBhc3MnXSAhPSAnJyAmJiAk
SFRUUF9QT1NUX1ZBUlNbJ2NwX29sZHBhc3MnXSAhPSAkbGRhcF9wYXNzX2NvbmZpZ1snYmluZF9w
YXNzd29yZCddKQ0KICAgICAgIGFycmF5X3B1c2goJE1lc3NhZ2VzLCAnWW91ciBvbGQgcGFzc3dv
cmQgaXMgbm90IGNvcnJlY3QuJyk7DQogICBpZiAoKHN0cmxlbigkSFRUUF9QT1NUX1ZBUlNbJ2Nw
X25ld3Bhc3MnXSk8NikgfHwgKHN0cmxlbigkSFRUUF9QT1NUX1ZBUlNbJ2NwX25ld3Bhc3MnXSk+
MTYpKQ0KCWFycmF5X3B1c2goJE1lc3NhZ2VzLCAnWW91ciBuZXcgcGFzc3dvcmQgbXVzdCBiZSBi
ZXR3ZWVuIDYgYW5kIDE2IGNoYXJhY3RlcnMuJyk7DQogICBpZiAoIShlcmVnKCJeKFswLTldfFth
LXpdfFtBLVpdfF8pKiQiLCAkSFRUUF9QT1NUX1ZBUlNbJ2NwX25ld3Bhc3MnXSkpKQ0KCWFycmF5
X3B1c2goJE1lc3NhZ2VzLCAnWW91ciBuZXcgcGFzc3dvcmQgbWF5IG9ubHkgY29udGFpbiBjaGFy
YWN0ZXJzOiBhLXosIEEtWiwgMC05IGFuZCBfJyk7DQoNCiAgIGlmIChjb3VudCgkTWVzc2FnZXMp
KQ0KICAgICAgIHJldHVybiAkTWVzc2FnZXM7DQoNCiAgIHJldHVybiBjaGFuZ2VfbGRhcHBhc3Nf
Z28oKTsNCn0NCg0KDQpmdW5jdGlvbiBjaGFuZ2VfbGRhcHBhc3NfZ28oKSB7DQoNCiAgICBnbG9i
YWwgJEhUVFBfUE9TVF9WQVJTLCAkbGRhcF9wYXNzX2NvbmZpZywgJHN1cHBvcnRfYWRkcmVzczsN
Cg0KICAgICRNZXNzYWdlcyA9IGFycmF5KCk7DQogICAgDQogICAgJGRzPWxkYXBfY29ubmVjdCgk
bGRhcF9wYXNzX2NvbmZpZ1snc2VydmVyJ10sICRsZGFwX3Bhc3NfY29uZmlnWydwb3J0J10pOw0K
ICAgIGlmICghICRkcykgew0KICAgICAgYXJyYXlfcHVzaCgkTWVzc2FnZXMsJ0NhblwndCBjb25u
ZWN0IHRvIERpcmVjdG9yeSBTZXJ2ZXIsIHBsZWFzZSBlbWFpbCAnIC4gJHN1cHBvcnRfYWRkcmVz
cyAuICchJyk7DQogICAgICByZXR1cm4gJE1lc3NhZ2VzOw0KICAgIH0NCg0KICAgICRyPWxkYXBf
YmluZCgkZHMsJGxkYXBfcGFzc19jb25maWdbJ2JpbmRfZG4nXSwkbGRhcF9wYXNzX2NvbmZpZ1sn
YmluZF9wYXNzd29yZCddKTsNCiAgICANCiAgICBpZiAoISAkcikgew0KICAgICAgYXJyYXlfcHVz
aCgkTWVzc2FnZXMsJ0NhblwndCBhdXRoZW50aWNhdGUgdG8gRGlyZWN0b3J5IFNlcnZlciwgcGxl
YXNlICcgLiAkc3VwcG9ydF9hZGRyZXNzIC4gJyEnKTsNCiAgICAgIHJldHVybiAkTWVzc2FnZXM7
DQogICAgfQ0KDQogICAgJHNyPWxkYXBfc2VhcmNoKCRkcywkbGRhcF9wYXNzX2NvbmZpZ1sncm9v
dCddLCAkbGRhcF9wYXNzX2NvbmZpZ1snZG4nXS4iPSIuJGxkYXBfcGFzc19jb25maWdbJ2RuX3Zh
bHVlJ10pOyANCiAgICANCiAgICBpZiAobGRhcF9jb3VudF9lbnRyaWVzKCRkcywkc3IpIT0xKSB7
ICAvL21ha2Ugc3VyZSB3ZSBvbmx5IGhhdmUgMSB1aWQNCiAgICAgIGFycmF5X3B1c2goJE1lc3Nh
Z2VzLCdEdXBsaWNhdGUgbG9naW4gZW50cmllcyBkZXRlY3RlZCwgY2Fubm90IGNoYW5nZSBwYXNz
d29yZCEnKTsNCiAgICAgIHJldHVybiAkTWVzc2FnZXM7DQogICAgfQ0KDQogICAgJHJlc2luZm8g
PSBsZGFwX2dldF9lbnRyaWVzKCRkcywgJHNyKTsNCiAgICAkdG9fY2hhbmdlX2RuPSRyZXNpbmZv
WzBdWyJkbiJdOw0KDQogICAgLy8gVXBkYXRlIHRoZSBwYXNzd29yZA0KICAgIA0KICAgICRsZGFw
X2luZm9bJGxkYXBfcGFzc19jb25maWdbJ3Bhc3N3b3JkX2ZpZWxkJ11dPSRIVFRQX1BPU1RfVkFS
U1snY3BfbmV3cGFzcyddOw0KDQoNCiAgICBpZiAobGRhcF9tb2RpZnkoJGRzLCR0b19jaGFuZ2Vf
ZG4sJGxkYXBfaW5mbykpIHsNCg0KICAgICAgJE1lc3NhZ2VzWzBdID0gJ3N1Y2Nlc3MnOyAvLyBT
dWNjZXNzDQogICAgICByZXR1cm4gJE1lc3NhZ2VzOw0KDQogICAgfSANCgkNCiAgICBlbHNlIHsN
CiAgICAgIGFycmF5X3B1c2goJE1lc3NhZ2VzLCdQYXNzd29yZCBjaGFuZ2Ugd2FzIG5vdCBzdWNj
ZXNzZnVsIScpOw0KICAgICAgcmV0dXJuICRNZXNzYWdlczsNCiAgICB9DQoNCiAgICBAbGRhcF9j
bG9zZSgkZHMpOw0KCSAgICAgICANCiAgICB9DQogICAgDQo/Pg0K

---------------------- multipart/mixed attachment--