1<?php 2/** 3 * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> 4 * This file is licensed under the Affero General Public License version 3 or 5 * later. 6 * See the COPYING-README file. 7 */ 8 9/** 10 * User authentication via samba (smbclient) 11 * 12 * @category Apps 13 * @package UserExternal 14 * @author Robin Appelman <icewind@owncloud.com> 15 * @license http://www.gnu.org/licenses/agpl AGPL 16 * @link http://github.com/owncloud/apps 17 */ 18class OC_User_SMB extends \OCA\user_external\Base { 19 private $host; 20 21 const SMBCLIENT = 'smbclient -L'; 22 const LOGINERROR = 'NT_STATUS_LOGON_FAILURE'; 23 24 /** 25 * Create new samba authentication provider 26 * 27 * @param string $host Hostname or IP of windows machine 28 */ 29 public function __construct($host) { 30 parent::__construct($host); 31 $this->host=$host; 32 } 33 34 /** 35 * @param string $uid 36 * @param string $password 37 * @return string|bool 38 */ 39 private function tryAuthentication($uid, $password) { 40 $uidEscaped = \escapeshellarg($uid); 41 $password = \escapeshellarg($password); 42 $command = self::SMBCLIENT.' '.\escapeshellarg('//' . $this->host . '/dummy').' -U'.$uidEscaped.'%'.$password; 43 $lastline = \exec($command, $output, $retval); 44 if ($retval === 127) { 45 OCP\Util::writeLog( 46 'user_external', 'ERROR: smbclient executable missing', 47 OCP\Util::ERROR 48 ); 49 return false; 50 } elseif (\strpos($lastline, self::LOGINERROR) !== false) { 51 //normal login error 52 return false; 53 } elseif (\strpos($lastline, 'NT_STATUS_BAD_NETWORK_NAME') !== false) { 54 //login on minor error 55 goto login; 56 } elseif ($retval != 0) { 57 //some other error 58 OCP\Util::writeLog( 59 'user_external', 'ERROR: smbclient error: ' . \trim($lastline), 60 OCP\Util::ERROR 61 ); 62 return false; 63 } else { 64 login: 65 return $uid; 66 } 67 } 68 69 /** 70 * Check if the password is correct without logging in the user 71 * 72 * @param string $uid The username 73 * @param string $password The password 74 * 75 * @return string|bool 76 */ 77 public function checkPassword($uid, $password) { 78 // Check with an invalid password, if the user authenticates then fail 79 $attemptWithInvalidPassword = $this->tryAuthentication($uid, \base64_encode($password)); 80 if (\is_string($attemptWithInvalidPassword)) { 81 return false; 82 } 83 84 // Check with valid password 85 $attemptWithValidPassword = $this->tryAuthentication($uid, $password); 86 if (\is_string($attemptWithValidPassword)) { 87 $this->storeUser($uid); 88 return $uid; 89 } 90 91 return false; 92 } 93} 94