0
|
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 }
|