Mercurial > hg > rc1
comparison plugins/password/drivers/directadmin.php @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
| author | Charlie Root |
|---|---|
| date | Thu, 04 Jan 2018 15:50:29 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:1e000243b222 |
|---|---|
| 1 <?php | |
| 2 | |
| 3 /** | |
| 4 * DirectAdmin Password Driver | |
| 5 * | |
| 6 * Driver to change passwords via DirectAdmin Control Panel | |
| 7 * | |
| 8 * @version 2.1 | |
| 9 * @author Victor Benincasa <vbenincasa@gmail.com> | |
| 10 * | |
| 11 * Copyright (C) 2005-2013, The Roundcube Dev Team | |
| 12 * | |
| 13 * This program is free software: you can redistribute it and/or modify | |
| 14 * it under the terms of the GNU General Public License as published by | |
| 15 * the Free Software Foundation, either version 3 of the License, or | |
| 16 * (at your option) any later version. | |
| 17 * | |
| 18 * This program is distributed in the hope that it will be useful, | |
| 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 21 * GNU General Public License for more details. | |
| 22 * | |
| 23 * You should have received a copy of the GNU General Public License | |
| 24 * along with this program. If not, see http://www.gnu.org/licenses/. | |
| 25 */ | |
| 26 | |
| 27 class rcube_directadmin_password | |
| 28 { | |
| 29 public function save($curpass, $passwd) | |
| 30 { | |
| 31 $rcmail = rcmail::get_instance(); | |
| 32 $Socket = new HTTPSocket; | |
| 33 | |
| 34 $da_user = $_SESSION['username']; | |
| 35 $da_curpass = $curpass; | |
| 36 $da_newpass = $passwd; | |
| 37 $da_host = $rcmail->config->get('password_directadmin_host'); | |
| 38 $da_port = $rcmail->config->get('password_directadmin_port'); | |
| 39 | |
| 40 if (strpos($da_user, '@') === false) { | |
| 41 return array('code' => PASSWORD_ERROR, 'message' => 'Change the SYSTEM user password through control panel!'); | |
| 42 } | |
| 43 | |
| 44 $da_host = str_replace('%h', $_SESSION['imap_host'], $da_host); | |
| 45 $da_host = str_replace('%d', $rcmail->user->get_username('domain'), $da_host); | |
| 46 | |
| 47 $Socket->connect($da_host,$da_port); | |
| 48 $Socket->set_method('POST'); | |
| 49 $Socket->query('/CMD_CHANGE_EMAIL_PASSWORD', | |
| 50 array( | |
| 51 'email' => $da_user, | |
| 52 'oldpassword' => $da_curpass, | |
| 53 'password1' => $da_newpass, | |
| 54 'password2' => $da_newpass, | |
| 55 'api' => '1' | |
| 56 )); | |
| 57 $response = $Socket->fetch_parsed_body(); | |
| 58 | |
| 59 //DEBUG | |
| 60 //rcube::console("Password Plugin: [USER: $da_user] [HOST: $da_host] - Response: [SOCKET: ".$Socket->result_status_code."] [DA ERROR: ".strip_tags($response['error'])."] [TEXT: ".$response[text]."]"); | |
| 61 | |
| 62 if($Socket->result_status_code != 200) | |
| 63 return array('code' => PASSWORD_CONNECT_ERROR, 'message' => $Socket->error[0]); | |
| 64 elseif($response['error'] == 1) | |
| 65 return array('code' => PASSWORD_ERROR, 'message' => strip_tags($response['text'])); | |
| 66 else | |
| 67 return PASSWORD_SUCCESS; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 | |
| 72 /** | |
| 73 * Socket communication class. | |
| 74 * | |
| 75 * Originally designed for use with DirectAdmin's API, this class will fill any HTTP socket need. | |
| 76 * | |
| 77 * Very, very basic usage: | |
| 78 * $Socket = new HTTPSocket; | |
| 79 * echo $Socket->get('http://user:pass@somehost.com:2222/CMD_API_SOMEAPI?query=string&this=that'); | |
| 80 * | |
| 81 * @author Phi1 'l0rdphi1' Stier <l0rdphi1@liquenox.net> | |
| 82 * @updates 2.7 and 2.8 by Victor Benincasa <vbenincasa @ gmail.com> | |
| 83 * @package HTTPSocket | |
| 84 * @version 2.8 | |
| 85 */ | |
| 86 class HTTPSocket { | |
| 87 | |
| 88 var $version = '2.8'; | |
| 89 | |
| 90 /* all vars are private except $error, $query_cache, and $doFollowLocationHeader */ | |
| 91 | |
| 92 var $method = 'GET'; | |
| 93 | |
| 94 var $remote_host; | |
| 95 var $remote_port; | |
| 96 var $remote_uname; | |
| 97 var $remote_passwd; | |
| 98 | |
| 99 var $result; | |
| 100 var $result_header; | |
| 101 var $result_body; | |
| 102 var $result_status_code; | |
| 103 | |
| 104 var $lastTransferSpeed; | |
| 105 | |
| 106 var $bind_host; | |
| 107 | |
| 108 var $error = array(); | |
| 109 var $warn = array(); | |
| 110 var $query_cache = array(); | |
| 111 | |
| 112 var $doFollowLocationHeader = TRUE; | |
| 113 var $redirectURL; | |
| 114 | |
| 115 var $extra_headers = array(); | |
| 116 | |
| 117 /** | |
| 118 * Create server "connection". | |
| 119 * | |
| 120 */ | |
| 121 function connect($host, $port = '' ) | |
| 122 { | |
| 123 if (!is_numeric($port)) | |
| 124 { | |
| 125 $port = 2222; | |
| 126 } | |
| 127 | |
| 128 $this->remote_host = $host; | |
| 129 $this->remote_port = $port; | |
| 130 } | |
| 131 | |
| 132 function bind( $ip = '' ) | |
| 133 { | |
| 134 if ( $ip == '' ) | |
| 135 { | |
| 136 $ip = $_SERVER['SERVER_ADDR']; | |
| 137 } | |
| 138 | |
| 139 $this->bind_host = $ip; | |
| 140 } | |
| 141 | |
| 142 /** | |
| 143 * Change the method being used to communicate. | |
| 144 * | |
| 145 * @param string|null request method. supports GET, POST, and HEAD. default is GET | |
| 146 */ | |
| 147 function set_method( $method = 'GET' ) | |
| 148 { | |
| 149 $this->method = strtoupper($method); | |
| 150 } | |
| 151 | |
| 152 /** | |
| 153 * Specify a username and password. | |
| 154 * | |
| 155 * @param string|null username. default is null | |
| 156 * @param string|null password. default is null | |
| 157 */ | |
| 158 function set_login( $uname = '', $passwd = '' ) | |
| 159 { | |
| 160 if ( strlen($uname) > 0 ) | |
| 161 { | |
| 162 $this->remote_uname = $uname; | |
| 163 } | |
| 164 | |
| 165 if ( strlen($passwd) > 0 ) | |
| 166 { | |
| 167 $this->remote_passwd = $passwd; | |
| 168 } | |
| 169 | |
| 170 } | |
| 171 | |
| 172 /** | |
| 173 * Query the server | |
| 174 * | |
| 175 * @param string containing properly formatted server API. See DA API docs and examples. Http:// URLs O.K. too. | |
| 176 * @param string|array query to pass to url | |
| 177 * @param int if connection KB/s drops below value here, will drop connection | |
| 178 */ | |
| 179 function query( $request, $content = '', $doSpeedCheck = 0 ) | |
| 180 { | |
| 181 $this->error = $this->warn = array(); | |
| 182 $this->result_status_code = NULL; | |
| 183 | |
| 184 // is our request a http(s):// ... ? | |
| 185 if (preg_match('/^(http|https):\/\//i',$request)) | |
| 186 { | |
| 187 $location = parse_url($request); | |
| 188 $this->connect($location['host'],$location['port']); | |
| 189 $this->set_login($location['user'],$location['pass']); | |
| 190 | |
| 191 $request = $location['path']; | |
| 192 $content = $location['query']; | |
| 193 | |
| 194 if ( strlen($request) < 1 ) | |
| 195 { | |
| 196 $request = '/'; | |
| 197 } | |
| 198 | |
| 199 } | |
| 200 | |
| 201 $array_headers = array( | |
| 202 'User-Agent' => "HTTPSocket/$this->version", | |
| 203 'Host' => ( $this->remote_port == 80 ? parse_url($this->remote_host,PHP_URL_HOST) : parse_url($this->remote_host,PHP_URL_HOST).":".$this->remote_port ), | |
| 204 'Accept' => '*/*', | |
| 205 'Connection' => 'Close' ); | |
| 206 | |
| 207 foreach ( $this->extra_headers as $key => $value ) | |
| 208 { | |
| 209 $array_headers[$key] = $value; | |
| 210 } | |
| 211 | |
| 212 $this->result = $this->result_header = $this->result_body = ''; | |
| 213 | |
| 214 // was content sent as an array? if so, turn it into a string | |
| 215 if (is_array($content)) | |
| 216 { | |
| 217 $pairs = array(); | |
| 218 | |
| 219 foreach ( $content as $key => $value ) | |
| 220 { | |
| 221 $pairs[] = "$key=".urlencode($value); | |
| 222 } | |
| 223 | |
| 224 $content = join('&',$pairs); | |
| 225 unset($pairs); | |
| 226 } | |
| 227 | |
| 228 $OK = TRUE; | |
| 229 | |
| 230 // instance connection | |
| 231 if ($this->bind_host) | |
| 232 { | |
| 233 $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); | |
| 234 socket_bind($socket,$this->bind_host); | |
| 235 | |
| 236 if (!@socket_connect($socket,$this->remote_host,$this->remote_port)) | |
| 237 { | |
| 238 $OK = FALSE; | |
| 239 } | |
| 240 | |
| 241 } | |
| 242 else | |
| 243 { | |
| 244 $socket = @fsockopen( $this->remote_host, $this->remote_port, $sock_errno, $sock_errstr, 10 ); | |
| 245 } | |
| 246 | |
| 247 if ( !$socket || !$OK ) | |
| 248 { | |
| 249 $this->error[] = "Can't create socket connection to $this->remote_host:$this->remote_port."; | |
| 250 return 0; | |
| 251 } | |
| 252 | |
| 253 // if we have a username and password, add the header | |
| 254 if ( isset($this->remote_uname) && isset($this->remote_passwd) ) | |
| 255 { | |
| 256 $array_headers['Authorization'] = 'Basic '.base64_encode("$this->remote_uname:$this->remote_passwd"); | |
| 257 } | |
| 258 | |
| 259 // for DA skins: if $this->remote_passwd is NULL, try to use the login key system | |
| 260 if ( isset($this->remote_uname) && $this->remote_passwd == NULL ) | |
| 261 { | |
| 262 $array_headers['Cookie'] = "session={$_SERVER['SESSION_ID']}; key={$_SERVER['SESSION_KEY']}"; | |
| 263 } | |
| 264 | |
| 265 // if method is POST, add content length & type headers | |
| 266 if ( $this->method == 'POST' ) | |
| 267 { | |
| 268 $array_headers['Content-type'] = 'application/x-www-form-urlencoded'; | |
| 269 $array_headers['Content-length'] = strlen($content); | |
| 270 } | |
| 271 // else method is GET or HEAD. we don't support anything else right now. | |
| 272 else | |
| 273 { | |
| 274 if ($content) | |
| 275 { | |
| 276 $request .= "?$content"; | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 // prepare query | |
| 281 $query = "$this->method $request HTTP/1.0\r\n"; | |
| 282 foreach ( $array_headers as $key => $value ) | |
| 283 { | |
| 284 $query .= "$key: $value\r\n"; | |
| 285 } | |
| 286 $query .= "\r\n"; | |
| 287 | |
| 288 // if POST we need to append our content | |
| 289 if ( $this->method == 'POST' && $content ) | |
| 290 { | |
| 291 $query .= "$content\r\n\r\n"; | |
| 292 } | |
| 293 | |
| 294 // query connection | |
| 295 if ($this->bind_host) | |
| 296 { | |
| 297 socket_write($socket,$query); | |
| 298 | |
| 299 // now load results | |
| 300 while ( $out = socket_read($socket,2048) ) | |
| 301 { | |
| 302 $this->result .= $out; | |
| 303 } | |
| 304 } | |
| 305 else | |
| 306 { | |
| 307 fwrite( $socket, $query, strlen($query) ); | |
| 308 | |
| 309 // now load results | |
| 310 $this->lastTransferSpeed = 0; | |
| 311 $status = socket_get_status($socket); | |
| 312 $startTime = time(); | |
| 313 $length = 0; | |
| 314 while ( !feof($socket) && !$status['timed_out'] ) | |
| 315 { | |
| 316 $chunk = fgets($socket,1024); | |
| 317 $length += strlen($chunk); | |
| 318 $this->result .= $chunk; | |
| 319 | |
| 320 $elapsedTime = time() - $startTime; | |
| 321 | |
| 322 if ( $elapsedTime > 0 ) | |
| 323 { | |
| 324 $this->lastTransferSpeed = ($length/1024)/$elapsedTime; | |
| 325 } | |
| 326 | |
| 327 if ( $doSpeedCheck > 0 && $elapsedTime > 5 && $this->lastTransferSpeed < $doSpeedCheck ) | |
| 328 { | |
| 329 $this->warn[] = "kB/s for last 5 seconds is below 50 kB/s (~".( ($length/1024)/$elapsedTime )."), dropping connection..."; | |
| 330 $this->result_status_code = 503; | |
| 331 break; | |
| 332 } | |
| 333 | |
| 334 } | |
| 335 | |
| 336 if ( $this->lastTransferSpeed == 0 ) | |
| 337 { | |
| 338 $this->lastTransferSpeed = $length/1024; | |
| 339 } | |
| 340 | |
| 341 } | |
| 342 | |
| 343 list($this->result_header,$this->result_body) = preg_split("/\r\n\r\n/",$this->result,2); | |
| 344 | |
| 345 if ($this->bind_host) | |
| 346 { | |
| 347 socket_close($socket); | |
| 348 } | |
| 349 else | |
| 350 { | |
| 351 fclose($socket); | |
| 352 } | |
| 353 | |
| 354 $this->query_cache[] = $query; | |
| 355 | |
| 356 | |
| 357 $headers = $this->fetch_header(); | |
| 358 | |
| 359 // what return status did we get? | |
| 360 if (!$this->result_status_code) | |
| 361 { | |
| 362 preg_match("#HTTP/1\.. (\d+)#",$headers[0],$matches); | |
| 363 $this->result_status_code = $matches[1]; | |
| 364 } | |
| 365 | |
| 366 // did we get the full file? | |
| 367 if ( !empty($headers['content-length']) && $headers['content-length'] != strlen($this->result_body) ) | |
| 368 { | |
| 369 $this->result_status_code = 206; | |
| 370 } | |
| 371 | |
| 372 // now, if we're being passed a location header, should we follow it? | |
| 373 if ($this->doFollowLocationHeader) | |
| 374 { | |
| 375 if ($headers['location']) | |
| 376 { | |
| 377 $this->redirectURL = $headers['location']; | |
| 378 $this->query($headers['location']); | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 function getTransferSpeed() | |
| 384 { | |
| 385 return $this->lastTransferSpeed; | |
| 386 } | |
| 387 | |
| 388 /** | |
| 389 * The quick way to get a URL's content :) | |
| 390 * | |
| 391 * @param string URL | |
| 392 * @param boolean return as array? (like PHP's file() command) | |
| 393 * @return string result body | |
| 394 */ | |
| 395 function get($location, $asArray = FALSE ) | |
| 396 { | |
| 397 $this->query($location); | |
| 398 | |
| 399 if ( $this->get_status_code() == 200 ) | |
| 400 { | |
| 401 if ($asArray) | |
| 402 { | |
| 403 return preg_split("/\n/",$this->fetch_body()); | |
| 404 } | |
| 405 | |
| 406 return $this->fetch_body(); | |
| 407 } | |
| 408 | |
| 409 return FALSE; | |
| 410 } | |
| 411 | |
| 412 /** | |
| 413 * Returns the last status code. | |
| 414 * 200 = OK; | |
| 415 * 403 = FORBIDDEN; | |
| 416 * etc. | |
| 417 * | |
| 418 * @return int status code | |
| 419 */ | |
| 420 function get_status_code() | |
| 421 { | |
| 422 return $this->result_status_code; | |
| 423 } | |
| 424 | |
| 425 /** | |
| 426 * Adds a header, sent with the next query. | |
| 427 * | |
| 428 * @param string header name | |
| 429 * @param string header value | |
| 430 */ | |
| 431 function add_header($key,$value) | |
| 432 { | |
| 433 $this->extra_headers[$key] = $value; | |
| 434 } | |
| 435 | |
| 436 /** | |
| 437 * Clears any extra headers. | |
| 438 * | |
| 439 */ | |
| 440 function clear_headers() | |
| 441 { | |
| 442 $this->extra_headers = array(); | |
| 443 } | |
| 444 | |
| 445 /** | |
| 446 * Return the result of a query. | |
| 447 * | |
| 448 * @return string result | |
| 449 */ | |
| 450 function fetch_result() | |
| 451 { | |
| 452 return $this->result; | |
| 453 } | |
| 454 | |
| 455 /** | |
| 456 * Return the header of result (stuff before body). | |
| 457 * | |
| 458 * @param string (optional) header to return | |
| 459 * @return array result header | |
| 460 */ | |
| 461 function fetch_header( $header = '' ) | |
| 462 { | |
| 463 $array_headers = preg_split("/\r\n/",$this->result_header); | |
| 464 $array_return = array( 0 => $array_headers[0] ); | |
| 465 unset($array_headers[0]); | |
| 466 | |
| 467 foreach ( $array_headers as $pair ) | |
| 468 { | |
| 469 list($key,$value) = preg_split("/: /",$pair,2); | |
| 470 $array_return[strtolower($key)] = $value; | |
| 471 } | |
| 472 | |
| 473 if ( $header != '' ) | |
| 474 { | |
| 475 return $array_return[strtolower($header)]; | |
| 476 } | |
| 477 | |
| 478 return $array_return; | |
| 479 } | |
| 480 | |
| 481 /** | |
| 482 * Return the body of result (stuff after header). | |
| 483 * | |
| 484 * @return string result body | |
| 485 */ | |
| 486 function fetch_body() | |
| 487 { | |
| 488 return $this->result_body; | |
| 489 } | |
| 490 | |
| 491 /** | |
| 492 * Return parsed body in array format. | |
| 493 * | |
| 494 * @return array result parsed | |
| 495 */ | |
| 496 function fetch_parsed_body() | |
| 497 { | |
| 498 parse_str($this->result_body,$x); | |
| 499 return $x; | |
| 500 } | |
| 501 | |
| 502 } |
