Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
/**
5
 * File::Passwd::Smb
6
 *
7
 * PHP versions 4 and 5
8
 *
9
 * LICENSE: This source file is subject to version 3.0 of the PHP license
10
 * that is available through the world-wide-web at the following URI:
11
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
12
 * the PHP License and are unable to obtain it through the web, please
13
 * send a note to license@php.net so we can mail you a copy immediately.
14
 *
15
 * @category   FileFormats
16
 * @package    File_Passwd
17
 * @author     Michael Wallner <mike@php.net>
18
 * @author     Michael Bretterklieber <michael@bretterklieber.com>
19
 * @copyright  2003-2005 Michael Wallner
20
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
21
 * @version    CVS: $Id: Smb.php,v 1.18 2005/05/06 10:22:48 mike Exp $
22
 * @link       http://pear.php.net/package/File_Passwd
23
 */
24
 
25
/**
26
* Requires File::Passwd::Common
27
*/
28
require_once 'File/Passwd/Common.php';
29
 
30
/**
31
* Requires Crypt::CHAP
32
*/
33
require_once 'Crypt/CHAP.php';
34
 
35
/**
36
* Manipulate SMB server passwd files.
37
*
38
* # Usage Example 1 (modifying existing file):
39
* <code>
40
* $f = &File_Passwd::factory('SMB');
41
* $f->setFile('./smbpasswd');
42
* $f->load();
43
* $f->addUser('sepp3', 'MyPw', array('userid' => 12));
44
* $f->changePasswd('sepp', 'MyPw');
45
* $f->delUser('karli');
46
* foreach($f->listUser() as $user => $data) {
47
*   echo $user . ':' . implode(':', $data) ."\n";
48
* }
49
* $f->save();
50
* </code>
51
*
52
* # Usage Example 2 (creating a new file):
53
* <code>
54
* $f = &File_Passwd::factory('SMB');
55
* $f->setFile('./smbpasswd');
56
* $f->addUser('sepp1', 'MyPw', array('userid'=> 12));
57
* $f->addUser('sepp3', 'MyPw', array('userid' => 1000));
58
* $f->save();
59
* </code>
60
*
61
* # Usage Example 3 (authentication):
62
* <code>
63
* $f = &File_Passwd::factory('SMB');
64
* $f->setFile('./smbpasswd');
65
* $f->load();
66
* if (true === $f->verifyPasswd('sepp', 'MyPw')) {
67
*     echo "User valid";
68
* } else {
69
*     echo "User invalid or disabled";
70
* }
71
* </code>
72
*
73
* @author   Michael Bretterklieber <michael@bretterklieber.com>
74
* @author   Michael Wallner <mike@php.net>
75
* @package  File_Passwd
76
* @version  $Revision: 1.18 $
77
* @access   public
78
*/
79
class File_Passwd_Smb extends File_Passwd_Common
80
{
81
    /**
82
    * Object which generates the NT-Hash and LAN-Manager-Hash passwds
83
    *
84
    * @access protected
85
    * @var object
86
    */
87
    var $msc;
88
 
89
    /**
90
    * Constructor
91
    *
92
    * @access public
93
    * @param  string $file  SMB passwd file
94
    */
95
    function File_Passwd_Smb($file = 'smbpasswd')
96
    {
97
        File_Passwd_Smb::__construct($file);
98
    }
99
 
100
    /**
101
    * Constructor (ZE2)
102
    *
103
    * Rewritten because we want to init our crypt engine.
104
    *
105
    * @access public
106
    * @param  string $file  SMB passwd file
107
    */
108
    function __construct($file = 'smbpasswd')
109
    {
110
        $this->setFile($file);
111
        $this->msc = &new Crypt_CHAP_MSv1;
112
    }
113
 
114
    /**
115
    * Fast authentication of a certain user
116
    *
117
    * Returns a PEAR_Error if:
118
    *   o file doesn't exist
119
    *   o file couldn't be opened in read mode
120
    *   o file couldn't be locked exclusively
121
    *   o file couldn't be unlocked (only if auth fails)
122
    *   o file couldn't be closed (only if auth fails)
123
    *   o invalid encryption method <var>$nt_or_lm</var> was provided
124
    *
125
    * @static   call this method statically for a reasonable fast authentication
126
    * @access   public
127
    * @return   mixed   true if authenticated, false if not or PEAR_Error
128
    * @param    string  $file       path to passwd file
129
    * @param    string  $user       user to authenticate
130
    * @param    string  $pass       plaintext password
131
    * @param    string  $nt_or_lm   encryption mode to use (NT or LM hash)
132
    */
133
    function staticAuth($file, $user, $pass, $nt_or_lm = 'nt')
134
    {
135
        $line = File_Passwd_Common::_auth($file, $user);
136
        if (!$line || PEAR::isError($line)) {
137
            return $line;
138
        }
139
        @list(,,$lm,$nt) = explode(':', $line);
140
        $chap            = &new Crypt_CHAP_MSv1;
141
 
142
        switch(strToLower($nt_or_lm)){
143
        	case FILE_PASSWD_NT:
144
                $real       = $nt;
145
                $crypted    = $chap->ntPasswordHash($pass);
146
                break;
147
        	case FILE_PASSWD_LM:
148
                $real       = $lm;
149
                $crypted    = $chap->lmPasswordHash($pass);
150
                break;
151
        	default:
152
                return PEAR::raiseError(
153
                    sprintf(FILE_PASSWD_E_INVALID_ENC_MODE_STR, $nt_or_lm),
154
                    FILE_PASSWD_E_INVALID_ENC_MODE
155
                );
156
        }
157
        return (strToUpper(bin2hex($crypted)) === $real);
158
    }
159
 
160
    /**
161
    * Parse smbpasswd file
162
    *
163
    * Returns a PEAR_Error if passwd file has invalid format.
164
    *
165
    * @access public
166
    * @return mixed   true on success or PEAR_Error
167
    */
168
    function parse()
169
    {
170
        foreach ($this->_contents as $line){
171
            $info = explode(':', $line);
172
            if (count($info) < 4) {
173
                return PEAR::raiseError(
174
                    FILE_PASSWD_E_INVALID_FORMAT_STR,
175
                    FILE_PASSWD_E_INVALID_FORMAT
176
                );
177
            }
178
            $user = array_shift($info);
179
            if (!empty($user)) {
180
                array_walk($info, 'trim');
181
                $this->_users[$user] = @array(
182
                    'userid'    => $info[0],
183
                    'lmhash'    => $info[1],
184
                    'nthash'    => $info[2],
185
                    'flags'     => $info[3],
186
                    'lct'       => $info[4],
187
                    'comment'   => $info[5]
188
                );
189
            }
190
        }
191
        $this->_contents = array();
192
        return true;
193
    }
194
 
195
    /**
196
    * Add a user
197
    *
198
    * Returns a PEAR_Error if:
199
    *   o user already exists
200
    *   o user contains illegal characters
201
    *
202
    * @throws PEAR_Error
203
    * @return mixed true on success or PEAR_Error
204
    * @access public
205
    * @param  string    $user       the user to add
206
    * @param  string    $pass       the new plaintext password
207
    * @param  array     $params     additional properties of user
208
    *                                + userid
209
    *                                + comment
210
    * @param  boolean   $isMachine  whether to add an machine account
211
    */
212
    function addUser($user, $pass, $params, $isMachine = false)
213
    {
214
        if ($this->userExists($user)) {
215
            return PEAR::raiseError(
216
                sprintf(FILE_PASSWD_E_EXISTS_ALREADY_STR, 'User ', $user),
217
                FILE_PASSWD_E_EXISTS_ALREADY
218
            );
219
        }
220
        if (!preg_match($this->_pcre, $user)) {
221
            return PEAR::raiseError(
222
                sprintf(FILE_PASSWD_E_INVALID_CHARS_STR, 'User ', $user),
223
                FILE_PASSWD_E_INVALID_CHARS
224
            );
225
        }
226
        if ($isMachine) {
227
            $flags = '[W          ]';
228
            $user .= '$';
229
        } else {
230
            $flags = '[U          ]';
231
        }
232
        $this->_users[$user] = array(
233
            'flags'     => $flags,
234
            'userid'    => (int)@$params['userid'],
235
            'comment'   => trim(@$params['comment']),
236
            'lct'       => 'LCT-' . strToUpper(dechex(time()))
237
        );
238
        return $this->changePasswd($user, $pass);
239
    }
240
 
241
    /**
242
    * Modify a certain user
243
    *
244
    * <b>You should not modify the password with this method
245
    * unless it is already encrypted as nthash and lmhash!</b>
246
    *
247
    * Returns a PEAR_Error if:
248
    *   o user doesn't exist
249
    *   o an invalid property was supplied
250
    *
251
    * @throws PEAR_Error
252
    * @access public
253
    * @return mixed true on success or PEAR_Error
254
    * @param  string    $user   the user to modify
255
    * @param  array     $params an associative array of properties to change
256
    */
257
    function modUser($user, $params)
258
    {
259
        if (!$this->userExists($user)) {
260
            return PEAR::raiseError(
261
                sprintf(FILE_PASSWD_E_EXISTS_NOT_STR, 'User ', $user),
262
                FILE_PASSWD_E_EXISTS_NOT
263
            );
264
        }
265
        if (!preg_match($this->_pcre, $user)) {
266
            return PEAR::raiseError(
267
                sprintf(FILE_PASSWD_E_INVALID_CHARS_STR, 'User ', $user),
268
                FILE_PASSWD_E_INVALID_CHARS
269
            );
270
        }
271
        foreach ($params as $key => $value){
272
            $key = strToLower($key);
273
            if (!isset($this->_users[$user][$key])) {
274
                return PEAR::raiseError(
275
                    sprintf(FILE_PASSWD_E_INVALID_PROPERTY_STR, $key),
276
                    FILE_PASSWD_E_INVALID_PROPERTY
277
                );
278
            }
279
            $this->_users[$user][$key] = trim($value);
280
            $this->_users[$user]['lct']= 'LCT-' . strToUpper(dechex(time()));
281
        }
282
        return true;
283
    }
284
 
285
    /**
286
    * Change the passwd of a certain user
287
    *
288
    * Returns a PEAR_Error if <var>$user</var> doesn't exist.
289
    *
290
    * @throws PEAR_Error
291
    * @access public
292
    * @return mixed true on success or PEAR_Error
293
    * @param  string    $user   the user whose passwd should be changed
294
    * @param  string    $pass   the new plaintext passwd
295
    */
296
    function changePasswd($user, $pass)
297
    {
298
        if (!$this->userExists($user)) {
299
            return PEAR::raiseError(
300
                sprintf(FILE_PASSWD_E_EXISTS_NOT_STR, 'User ', $user),
301
                FILE_PASSWD_E_EXISTS_NOT
302
            );
303
        }
304
        if (empty($pass)) {
305
            $nthash = $lmhash = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
306
        } else {
307
            $nthash = strToUpper(bin2hex($this->msc->ntPasswordHash($pass)));
308
            $lmhash = strToUpper(bin2hex($this->msc->lmPasswordHash($pass)));
309
        }
310
        $this->_users[$user]['nthash'] = $nthash;
311
        $this->_users[$user]['lmhash'] = $lmhash;
312
        return true;
313
    }
314
 
315
    /**
316
    * Verifies a user's password
317
    *
318
    * Prefer NT-Hash instead of weak LAN-Manager-Hash
319
    *
320
    * Returns a PEAR_Error if:
321
    *   o user doesn't exist
322
    *   o user is disabled
323
    *
324
    * @return mixed true if passwds equal, false if they don't or PEAR_Error
325
    * @access public
326
    * @param string $user       username
327
    * @param string $nthash     NT-Hash in hex
328
    * @param string $lmhash     LAN-Manager-Hash in hex
329
    */
330
    function verifyEncryptedPasswd($user, $nthash, $lmhash = '')
331
    {
332
        if (!$this->userExists($user)) {
333
            return PEAR::raiseError(
334
                sprintf(FILE_PASSWD_E_EXISTS_NOT_STR, 'User ', $user),
335
                FILE_PASSWD_E_EXISTS_NOT
336
            );
337
        }
338
        if (strstr($this->_users[$user]['flags'], 'D')) {
339
            return PEAR::raiseError("User '$user' is disabled.", 0);
340
        }
341
        if (!empty($nthash)) {
342
            return $this->_users[$user]['nthash'] === strToUpper($nthash);
343
        }
344
        if (!empty($lmhash)) {
345
            return $this->_users[$user]['lm'] === strToUpper($lmhash);
346
        }
347
        return false;
348
    }
349
 
350
    /**
351
    * Verifies an account with the given plaintext password
352
    *
353
    * Returns a PEAR_Error if:
354
    *   o user doesn't exist
355
    *   o user is disabled
356
    *
357
    * @throws PEAR_Error
358
    * @return mixed     true if passwds equal, false if they don't or PEAR_Error
359
    * @access public
360
    * @param  string    $user username
361
    * @param  string    $pass the plaintext password
362
    */
363
    function verifyPasswd($user, $pass)
364
    {
365
        $nthash = bin2hex($this->msc->ntPasswordHash($pass));
366
        $lmhash = bin2hex($this->msc->lmPasswordHash($pass));
367
        return $this->verifyEncryptedPasswd($user, $nthash, $lmhash);
368
    }
369
 
370
    /**
371
    * Apply changes and rewrite CVS passwd file
372
    *
373
    * Returns a PEAR_Error if:
374
    *   o directory in which the file should reside couldn't be created
375
    *   o file couldn't be opened in write mode
376
    *   o file couldn't be locked exclusively
377
    *   o file couldn't be unlocked
378
    *   o file couldn't be closed
379
    *
380
    * @throws PEAR_Error
381
    * @access public
382
    * @return mixed true on success or PEAR_Error
383
    */
384
    function save()
385
    {
386
        $content = '';
387
        foreach ($this->_users as $user => $userdata) {
388
            $content .= $user . ':' .
389
                        $userdata['userid'] . ':' .
390
                        $userdata['lmhash'] . ':' .
391
                        $userdata['nthash'] . ':' .
392
                        $userdata['flags']  . ':' .
393
                        $userdata['lct']    . ':' .
394
                        $userdata['comment']. "\n";
395
        }
396
        return $this->_save($content);
397
    }
398
 
399
    /**
400
    * Generate Password
401
    *
402
    * @static
403
    * @access   public
404
    * @return   string  The crypted password.
405
    * @param    string  $pass The plaintext password.
406
    * @param    string  $mode The encryption mode to use (nt|lm).
407
    */
408
    function generatePasswd($pass, $mode = 'nt')
409
    {
410
        $chap = &new Crypt_CHAP_MSv1;
411
        $hash = strToLower($mode) == 'nt' ?
412
            $chap->ntPasswordHash($pass) :
413
            $chap->lmPasswordHash($pass);
414
        return strToUpper(bin2hex($hash));
415
    }
416
 
417
    /**
418
     * @ignore
419
     * @deprecated
420
     */
421
    function generatePassword($pass, $mode = 'nt')
422
    {
423
        return File_Passwd_Smb::generatePasswd($pass, $mode);
424
    }
425
}
426
?>