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 }