File_SMBPasswd
[ class tree: File_SMBPasswd ] [ index: File_SMBPasswd ] [ all elements ]

Source for file SMBPasswd.php

Documentation is available at SMBPasswd.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. /*
  4. Copyright (c) 2003, Michael Bretterklieber <michael@bretterklieber.com>
  5. All rights reserved.
  6.  
  7. Redistribution and use in source and binary forms, with or without 
  8. modification, are permitted provided that the following conditions 
  9. are met:
  10.  
  11. 1. Redistributions of source code must retain the above copyright 
  12.    notice, this list of conditions and the following disclaimer.
  13. 2. Redistributions in binary form must reproduce the above copyright 
  14.    notice, this list of conditions and the following disclaimer in the 
  15.    documentation and/or other materials provided with the distribution.
  16. 3. The names of the authors may not be used to endorse or promote products 
  17.    derived from this software without specific prior written permission.
  18.  
  19. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
  20. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
  21. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
  22. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
  23. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
  24. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
  25. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
  26. OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
  27. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
  28. EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  
  30. This code cannot simply be copied and put under the GNU Public License or 
  31. any other GPL-like (LGPL, GPL2) License.
  32.  
  33.     $Id: SMBPasswd.php,v 1.4 2005/05/08 09:10:32 mbretter Exp $
  34. */
  35.  
  36. require_once 'PEAR.php';
  37. require_once 'Crypt/CHAP.php';
  38.  
  39. /**
  40.  * Class to manage SAMBA smbpasswd-style files
  41.  *
  42.  * Example 1 (modifying existing file):
  43.  *
  44.  * $f = new File_SMBPasswd('./smbpasswd');
  45.  * $f->load();
  46.  * $f->addAccount('sepp3', 12, 'MyPw');
  47.  * $f->modAccount('sepp', '', 'MyPw');
  48.  * $f->delAccount('karli');
  49.  * $f->printAccounts();
  50.  * $f->save();
  51.  * 
  52.  * Example 2 (creating a new file):
  53.  *
  54.  * $f = new File_SMBPasswd('./smbpasswdnew');
  55.  * $f->addAccount('sepp1', 12, 'MyPw');
  56.  * $f->addAccount('sepp3', 1000, 'MyPw');
  57.  * $f->save();
  58.  *
  59.  * Example 3 (authentication):
  60.  *
  61.  * $f = new File_SMBPasswd('./smbpasswdnew');
  62.  * $f->load();
  63.  * if ($f->verifyAccount('sepp', 'MyPw')) {
  64.  *     echo "Account valid";
  65.  * } else {
  66.  *     echo "Account invalid or disabled";
  67.  * }
  68.  *
  69.  * @author Michael Bretterklieber <mbretter@jawa.at>
  70.  * @access  public
  71.  * @version 0.9.0
  72.  * @package File_SMBPasswd
  73.  * @category File
  74.  */
  75. class File_SMBPasswd extends PEAR {
  76.     
  77.     /**
  78.      * Multidimensional array of accounts
  79.      * @var array 
  80.      */
  81.     var $accounts = array();    
  82.  
  83.     /**
  84.      * Path to the smbpasswd file
  85.      * @var string 
  86.      */
  87.     var $file;
  88.  
  89.     /**
  90.      * Class who generates the NT-Hash and LAN-Manager-Hash
  91.      * @var object 
  92.      */
  93.     var $cryptEngine;
  94.  
  95.     /**
  96.      * Filehandle, of locked File
  97.      * @var resource 
  98.      */
  99.     var $fplock;
  100.     
  101.     /**
  102.      * Constructor
  103.      *
  104.      * @access public
  105.      * @param  string $file 
  106.      * @return object File_SMBPasswd 
  107.      */
  108.     function File_SMBPasswd($file 'smbpasswd'
  109.     {
  110.         $this->file = $file;
  111.         $this->cryptEngine = new Crypt_CHAP_MSv1;
  112.     }     
  113.  
  114.     /**
  115.      * Load the given smbpasswd file
  116.      *
  117.      * @access public
  118.      * @return mixed   true on success, PEAR_Error on failure
  119.      */    
  120.     function load()
  121.     {
  122.         $fd fopen($this->getFile()'r';
  123.         if (!$fd{
  124.             return $this->raiseError('Could not open ' $this->getFile(
  125.                                     ' for reading.');
  126.         }
  127.         
  128.         while (!feof($fd)) {
  129.             $line fgets($fd4096);
  130.             if (preg_match('/^#|^$/'trim($line))) {
  131.                 continue;
  132.             }
  133.             @list($user$userid$lmhash$nthash$flags$lct$commentexplode(':'$line);
  134.             if (strlen($user)) {
  135.                 $this->accounts[$user= array(
  136.                     'userid'    => trim($userid),
  137.                     'lmhash'    => trim($lmhash),
  138.                     'nthash'    => trim($nthash),
  139.                     'flags'     => trim($flags),
  140.                     'lct'       => trim($lct),
  141.                     'comment'   => trim($comment)
  142.                     );
  143.             }
  144.         }
  145.         
  146.         fclose($fd);   
  147.         return true; 
  148.     }
  149.     
  150.     /**
  151.      * Get the value of file property
  152.      *
  153.      * @access public
  154.      * @return string 
  155.      */
  156.     function getFile({
  157.         return $this->file;
  158.     }
  159.  
  160.     /**
  161.      * Get the value of accounts property
  162.      *
  163.      * @access public
  164.      * @return array 
  165.      */
  166.     function &getAccounts({
  167.         return $this->accounts;
  168.     
  169.     
  170.     /**
  171.      * Adds an account, with pre-encrypted passwords
  172.      *
  173.      * @param $user new username
  174.      * @param $userid new userid
  175.      * @param $lmhash LAN-Manager-Hash
  176.      * @param $nthash NT-Hash
  177.      * @param $comment Comment
  178.      * @param $flags Account-flags (see man 5 smbpasswd)
  179.      *
  180.      * @return mixed returns PEAR_Error, if the user already exists
  181.      * @access public
  182.      */
  183.     function addAccountEncrypted($user$userid$lmhash ''$nthash ''$comment ''$flags '[U          ]'
  184.     {
  185.         if (empty($lmhash)) $lmhash str_repeat('X'32);
  186.         if (empty($nthash)) $nthash str_repeat('X'32);
  187.                 
  188.         if (!isset($this->accounts[$user])) {
  189.             $this->accounts[$user= array(
  190.                 'userid'    => trim($userid),
  191.                 'lmhash'    => trim($lmhash),
  192.                 'nthash'    => trim($nthash),
  193.                 'flags'     => trim($flags),
  194.                 'lct'       => sprintf('LCT-%08s'strtoupper(dechex(time()))),
  195.                 'comment'   => trim($comment)
  196.                 );
  197.             
  198.             return true;
  199.         else {
  200.             return $this->raiseError"Couldn't add user '$user', because the user already exists!");
  201.         }
  202.     }
  203.  
  204.     /**
  205.      * Adds an account
  206.      *
  207.      * @param $user new username
  208.      * @param $userid new userid
  209.      * @param $pass Plaintext password
  210.      * @param $comment Comment
  211.      * @param $flags Account-flags (see man 5 smbpasswd)
  212.      *
  213.      * @return mixed returns PEAR_Error, if the user already exists
  214.      * @access public
  215.      */
  216.     function addAccount($user$userid$pass$comment ''$flags '[U          ]'
  217.     {
  218.         if (empty($pass)) {
  219.             return $this->addAccountEncrypted($user$userid''''$comment$flags;
  220.         else {
  221.             return $this->addAccountEncrypted(
  222.                         $user
  223.                         $userid
  224.                         strtoupper(bin2hex($this->cryptEngine->lmPasswordHash($pass))),
  225.                         strtoupper(bin2hex($this->cryptEngine->ntPasswordHash($pass)))
  226.                         $comment,
  227.                         $flags);
  228.         }
  229.                         
  230.     }
  231.  
  232.     /**
  233.      * Adds a user-account
  234.      *
  235.      * @param $user new username
  236.      * @param $userid new userid
  237.      * @param $pass Plaintext password
  238.      * @param $comment Comment
  239.      *
  240.      * @return mixed returns PEAR_Error, if the user already exists
  241.      * @access public
  242.      */
  243.     function addUser($user$userid$pass$comment '')
  244.     {
  245.         return $this->addAccount($user$userid$pass$comment'[U          ]');
  246.     }
  247.  
  248.     /**
  249.      * Adds a machine-account
  250.      *
  251.      * @param $machine new username
  252.      * @param $userid new userid
  253.      * @param $comment Comment
  254.      *
  255.      * @return mixed returns PEAR_Error, if the user already exists
  256.      * @access public
  257.      */
  258.     function addMachine($machine$userid$comment '')
  259.     {
  260.         return $this->addAccount($machine '$'$userid$machine$comment'[W          ]');
  261.     }
  262.     
  263.     /**
  264.      * Modifies an account with the pre-encrypted Hashes
  265.      *
  266.      * @param $user new username
  267.      * @param $userid new userid
  268.      * @param $lmhash LAN-Manager-Hash
  269.      * @param $nthash NT-Hash
  270.      * @param $comment Comment
  271.      * @param $flags Account-flags (see man 5 smbpasswd)
  272.      *
  273.      * @return mixed returns PEAR_Error, if the user doesen't exists
  274.      * @access public
  275.      */
  276.     function modAccountEncrypted($user$userid ''$lmhash ''$nthash ''$comment ''$flags ''
  277.     {
  278.         $account $this->accounts[$user];
  279.         if (is_array($account)) {
  280.             if ($userid === ''$userid   $account['userid'];
  281.             if (empty($lmhash)) $lmhash   $account['lmhash'];
  282.             if (empty($nthash)) $nthash   $account['nthash'];
  283.             if (empty($flags))  $flags    $account['flags'];
  284.             if (empty($comment)) $comment $account['comment'];
  285.  
  286.             $this->accounts[$user= array(
  287.                 'userid'    => trim($userid),
  288.                 'lmhash'    => trim($lmhash),
  289.                 'nthash'    => trim($nthash),
  290.                 'flags'     => trim($flags),
  291.                 'lct'       => sprintf('LCT-%08s'strtoupper(dechex(time()))),
  292.                 'comment'   => trim($comment)
  293.                 );
  294.             
  295.             return true;
  296.         else {
  297.             return $this->raiseError"Couldn't modify user '$user', because the user doesn't exists!";
  298.         }
  299.     }
  300.     
  301.     /**
  302.      * Modifies an account with given plaintext password
  303.      *
  304.      * @param $user new username
  305.      * @param $userid new userid
  306.      * @param $pass Plaintext password
  307.      * @param $comment Comment
  308.      * @param $flags Account-flags (see man 5 smbpasswd)
  309.      *
  310.      * @return mixed returns PEAR_Error, if the user doesen't exists
  311.      * @access public
  312.      */
  313.     function modAccount($user$userid ''$pass ''$comment ''$flags ''
  314.     {
  315.         if (empty($pass)) {
  316.             return $this->modAccountEncrypted($user$userid''''$comment$flags;
  317.         else {
  318.             return $this->modAccountEncrypted(
  319.                         $user
  320.                         $userid
  321.                         strtoupper(bin2hex($this->cryptEngine->lmPasswordHash($pass))),
  322.                         strtoupper(bin2hex($this->cryptEngine->ntPasswordHash($pass)))
  323.                         $comment
  324.                         $flags);
  325.         }
  326.     }
  327.  
  328.     /**
  329.      * This is an alias for modAccount
  330.      *
  331.      * @see File_SMBPasswd::modAccount
  332.      */
  333.     function modUser($user$userid ''$pass ''$comment ''$flags ''
  334.     {
  335.        return $this->modAccount($user$userid$pass$comment$flags);
  336.     }
  337.  
  338.     /**
  339.      * Deletes an account
  340.      *
  341.      * @param $user username
  342.      *
  343.      * @return mixed returns PEAR_Error, if the user doesn't exists
  344.      * @access public
  345.      */
  346.     function delAccount($name
  347.     {
  348.         if (isset($this->accounts[$name])) {
  349.             unset($this->accounts[$name]);
  350.             return true;
  351.         else {
  352.             return $this->raiseError"Couldn't delete account '$name', because the account doesn't exists!"
  353.         }
  354.     }   
  355.  
  356.     /**
  357.      * This is an alias for delAccount
  358.      *
  359.      * @see File_SMBPasswd::delAccount
  360.      */
  361.     function delUser($user
  362.     {
  363.        return $this->delAccount($user);
  364.     }
  365.  
  366.     
  367.     /**
  368.      * Verifies a user's password
  369.      * Prefer NT-Hash instead of weak LAN-Manager-Hash
  370.      *
  371.      * @param $user username
  372.      * @param $nthash NT-Hash in hex
  373.      * @param $lmhash LAN-Manager-Hash in hex
  374.      *
  375.      * @return boolean true if password is ok
  376.      * @access public
  377.      */
  378.     function verifyAccountEncrypted($user$nthash$lmhash ''
  379.     {
  380.         $account $this->accounts[$user];
  381.         if (is_array($account)) {
  382.             
  383.             // checking wether account is disabled
  384.             if (preg_match('/D/'$account['flags'])) {
  385.                 return false;
  386.             }
  387.             if (!empty($lmhash)) {
  388.                 return $account['lmhash'== strtoupper($lmhash);
  389.             else {
  390.                 return $account['nthash'== strtoupper($nthash);
  391.             }
  392.         }
  393.         return false;
  394.     }
  395.  
  396.     /**
  397.      * Verifies an account with the given plaintext password
  398.      *
  399.      * @param $user username
  400.      * @param $pass The plaintext password
  401.      *
  402.      * @return boolean true if password is ok
  403.      * @access public
  404.      */
  405.     function verifyAccount($user$pass
  406.     {
  407.         return $this->verifyAccountEncrypted(
  408.                         $user
  409.                         strtoupper(bin2hex($this->cryptEngine->ntPasswordHash($pass)))
  410.                         strtoupper(bin2hex($this->cryptEngine->lmPasswordHash($pass))));
  411.     }
  412.  
  413.     /**
  414.      * Locks the given file
  415.      *
  416.      * @return mixed PEAR_Error, true on succes
  417.      * @access public
  418.      */
  419.     function lock(
  420.     {
  421.         if (!is_resource($this->fplock)) {
  422.             $this->fplock = @fopen($this->getFile()'w');
  423.         }
  424.  
  425.         if (!is_resource($this->fplock)) {
  426.             return $this->raiseError('Could not open ' $this->getFile(
  427.                                     ' for writing.');
  428.         }
  429.  
  430.         if (!flock($this->fplockLOCK_EX)) {
  431.             return $this->raiseError('Could not open lock file ' $this->getFile());
  432.         }
  433.  
  434.         return true;
  435.     }
  436.  
  437.     /**
  438.      * Unlocks the given file
  439.      *
  440.      * @return mixed PEAR_Error, true on succes
  441.      * @access public
  442.      */
  443.     function unlock(
  444.     {
  445.         if (is_resource($this->fplock)) {
  446.             if (!flock($this->fplockLOCK_UN)) {
  447.                 return $this->raiseError('Could not open unlock file ' $this->getFile());
  448.             }
  449.         }
  450.  
  451.         return true;
  452.     }
  453.  
  454.     /**
  455.      * Writes changes to smbpasswd file and locks, unlocks and closes it
  456.      *
  457.      * @param $file Filename
  458.      *
  459.      * @return mixed returns PEAR_Error, if the file is not writeable
  460.      * @access public
  461.      */
  462.     function save($file ''
  463.     {
  464.         if (!empty($file)) {
  465.             $this->file = $file;
  466.         }
  467.  
  468.         $ret $this->lock();
  469.         if ($ret !== true{
  470.             return $ret;
  471.         }
  472.         
  473.         foreach ($this->accounts as $user => $userdata{
  474.             fputs($this->fplocksprintf("%s:%s:%s:%s:%s:%s:%s\n"
  475.                     $user
  476.                     $userdata['userid']
  477.                     $userdata['lmhash']
  478.                     $userdata['nthash']
  479.                     $userdata['flags'],
  480.                     $userdata['lct'],
  481.                     $userdata['comment']));
  482.         }
  483.  
  484.         $this->unlock();
  485.         fclose($this->fplock);
  486.         return true;
  487.     }    
  488.     
  489.     /**
  490.      * Print all accounts from smbpasswd file
  491.      *
  492.      * @access public
  493.      * @return void 
  494.      */
  495.     function printAccounts({
  496.         foreach ($this->accounts as $user => $userdata{
  497.             printf("%s:%s:%s:%s:%s:%s:%s\n"
  498.                 $user
  499.                 $userdata['userid']
  500.                 $userdata['lmhash']
  501.                 $userdata['nthash']
  502.                 $userdata['flags'],
  503.                 $userdata['lct'],
  504.                 $userdata['comment']);
  505.         }
  506.     }
  507.  
  508. }
  509. ?>

Documentation generated on Mon, 11 Mar 2019 15:28:55 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.