1<?php 2// must be run within Dokuwiki 3if(!defined('DOKU_INC')) die(); 4 5/** 6 * Plaintext authentication backend 7 * 8 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 9 * @author Todd Switzer <toddswitzer@gmail.com> 10 */ 11 12if(!extension_loaded('radius')) { 13 if (preg_match('/windows/i', getenv('OS'))) { 14 dl('php_radius.dll'); 15 } else { 16 dl('radius.so'); 17 } 18} 19 20class auth_plugin_authradius extends DokuWiki_Auth_Plugin { 21 22 protected $radius = null; 23 24 protected $classes; 25 26 /** 27 * Constructor 28 * 29 * Carry out sanity checks to ensure the object is 30 * able to operate. Set capabilities. 31 * 32 */ 33 public function __construct() { 34 parent::__construct(); 35 global $config_cascade; 36 37 if(!function_exists('radius_add_server')) { 38 msg("Radius err: PHP radius extension not found.",-1,__LINE__,__FILE__); 39 $this->success = false; 40 return; 41 } 42 $host = $this->getConf('host'); 43 $port = $this->getConf('port'); 44 $secret = $this->getConf('secret'); 45 $timeout = $this->getConf('timeout'); 46 $tries = $this->getConf('tries'); 47 48 $hosts = explode(",", $host); 49 for($i = 0; $i<count($hosts); $i++){ 50 $hosts[$i] = trim($hosts[$i]); 51 } 52 //create handle and add server 53 $this->radius = radius_auth_open(); 54 55 //Setup radius servers 56 for($i = 0; $i<count($hosts); $i++){ 57 if (!radius_add_server($this->radius,$hosts[$i],$port,$secret,$timeout,$tries)){ 58 msg("Radius err: ". radius_strerror($this->radius),-1,__LINE__,__FILE__); 59 $this->success = false; 60 return; 61 } 62 } 63 } 64 65 /** 66 * Check user+password 67 * 68 * Checks if the given user exists and the given 69 * plaintext password is correct 70 * 71 */ 72 public function checkPass($user, $pass) { 73 if (! radius_create_request($this->radius,RADIUS_ACCESS_REQUEST)) { 74 msg("Radius err: ". radius_strerror($this->radius),-1,__LINE__,__FILE__); 75 } 76 77 radius_put_attr($this->radius,RADIUS_USER_NAME,$user); 78 79 $auth_type = $this->getConf('auth_type'); 80 81 switch ($auth_type) { 82 case 'PAP': 83 radius_put_attr($this->radius,RADIUS_USER_PASSWORD,$pass); 84 break; 85 86 case 'MSCHAPV2': 87 include_once('mschap.php'); 88 $auth_Challenge = GenerateChallenge(16); 89 90 if (!radius_put_vendor_attr($this->radius, RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP_CHALLENGE, $auth_Challenge)) { 91 msg("RadiusError: RADIUS_MICROSOFT_MS_CHAP_CHALLENGE:" . radius_strerror($this->radius)); 92 exit; 93 } 94 95 $peer_Challenge = GeneratePeerChallenge(); 96 97 $ntresp = GenerateNTResponse($auth_Challenge, $peer_Challenge, $user, $pass); 98 99 $reserved = str_repeat ("\0", 8); 100 101 $resp = pack('CCa16a8a24', 1 , 1, $peer_Challenge, $reserved, $ntresp); 102 103 if (!radius_put_vendor_attr($this->radius, RADIUS_VENDOR_MICROSOFT, RADIUS_MICROSOFT_MS_CHAP2_RESPONSE, $resp)) { 104 msg("RadiusError: RADIUS_MICROSOFT_MS_CHAP2_RESPONSE:" . radius_strerror($this->radius)); 105 exit; 106 } 107 108 break; 109 default: 110 radius_put_attr($this->radius,RADIUS_USER_PASSWORD,$pass); 111 break; 112 } 113 114 //send the actual request and return result 115 switch (radius_send_request($this->radius)) { 116 case RADIUS_ACCESS_ACCEPT: 117 $data = $this->getUserData($user); 118 119 // Use class as group 120 $this->classes[$user] = null; 121 while ($resa = radius_get_attr($this->radius)) { 122 if (!is_array($resa)) { 123 msg("Error getting attribute: %s\n", radius_strerror($this->radius)); 124 exit; 125 } 126 $attr = $resa['attr']; 127 $data = $resa['data']; 128 if($attr == RADIUS_CLASS){ 129 $this->classes[$user] = strtolower($data); 130 } 131 } 132 133 return true; 134 break; 135 case RADIUS_ACCESS_REJECT: 136 msg("Radius Error: " . radius_strerror($this->radius)); 137 return false; 138 break; 139 case RADIUS_ACCESS_CHALLENGE: 140 msg("Radius: Challenge not supported by auth_radius.",-1); 141 return false; 142 break; 143 default: 144 msg('Radius Error: ('.$user.') ' . radius_strerror($this->radius),-1,__LINE__,__FILE__); 145 } 146 return false; 147 } 148 149 /** 150 * Return user info 151 * 152 * Returns info about the given user needs to contain 153 * at least these fields: 154 * 155 * name string full name of the user 156 * mail string email addres of the user 157 * grps array list of groups the user is in 158 * 159 * @param string $user 160 * @return array|bool 161 */ 162 public function getUserData($user) { 163 $data['mail'] = $user.'@'.$this->getConf('mailhost'); 164 $data['name'] = $user; 165 //Check for a cached group from when the password was checked 166 if($this->classes[$user] != null) { 167 msg("Radius provided group(s) " . $this->classes[$user]); 168 $data['grps'] = split('!:|;|,!', strtolower($this->classes[$user])); 169 } else { 170 $data['grps'] = array($this->getConf('defaultgroup')); 171 } 172 return $data; 173 } 174} 175