4 * DirectAdmin Password Driver
6 * Driver to change passwords via DirectAdmin Control Panel
9 * @author Victor Benincasa <vbenincasa@gmail.com>
14 function password_save($curpass, $passwd){
16 $rcmail = rcmail::get_instance();
17 $Socket = new HTTPSocket;
19 $da_user = $_SESSION['username'];
20 $da_curpass = $curpass;
21 $da_newpass = $passwd;
22 $da_host = $rcmail->config->get('password_directadmin_host');
23 $da_port = $rcmail->config->get('password_directadmin_port');
25 if(strpos($da_user, '@') === false) return array('code' => PASSWORD_ERROR, 'message' => 'Change the SYSTEM user password through control panel!');
27 $da_host = str_replace('%h', $_SESSION['imap_host'], $da_host);
28 $da_host = str_replace('%d', $rcmail->user->get_username('domain'), $da_host);
30 $Socket->connect($da_host,$da_port);
31 $Socket->set_method('POST');
32 $Socket->query('/CMD_CHANGE_EMAIL_PASSWORD',
35 'oldpassword' => $da_curpass,
36 'password1' => $da_newpass,
37 'password2' => $da_newpass,
40 $response = $Socket->fetch_parsed_body();
43 //console("Password Plugin: [USER: $da_user] [HOST: $da_host] - Response: [SOCKET: ".$Socket->result_status_code."] [DA ERROR: ".strip_tags($response['error'])."] [TEXT: ".$response[text]."]");
45 if($Socket->result_status_code != 200)
46 return array('code' => PASSWORD_CONNECT_ERROR, 'message' => $Socket->error[0]);
47 elseif($response['error'] == 1)
48 return array('code' => PASSWORD_ERROR, 'message' => strip_tags($response['text']));
50 return PASSWORD_SUCCESS;
56 * Socket communication class.
58 * Originally designed for use with DirectAdmin's API, this class will fill any HTTP socket need.
60 * Very, very basic usage:
61 * $Socket = new HTTPSocket;
62 * echo $Socket->get('http://user:pass@somesite.com/somedir/some.file?query=string&this=that');
64 * @author Phi1 'l0rdphi1' Stier <l0rdphi1@liquenox.net>
66 * @version 2.7 (Updated by Victor Benincasa <vbenincasa@gmail.com>)
72 /* all vars are private except $error, $query_cache, and $doFollowLocationHeader */
84 var $result_status_code;
86 var $lastTransferSpeed;
92 var $query_cache = array();
94 var $doFollowLocationHeader = TRUE;
97 var $extra_headers = array();
100 * Create server "connection".
103 function connect($host, $port = '' )
105 if (!is_numeric($port))
110 $this->remote_host = $host;
111 $this->remote_port = $port;
114 function bind( $ip = '' )
118 $ip = $_SERVER['SERVER_ADDR'];
121 $this->bind_host = $ip;
125 * Change the method being used to communicate.
127 * @param string|null request method. supports GET, POST, and HEAD. default is GET
129 function set_method( $method = 'GET' )
131 $this->method = strtoupper($method);
135 * Specify a username and password.
137 * @param string|null username. defualt is null
138 * @param string|null password. defualt is null
140 function set_login( $uname = '', $passwd = '' )
142 if ( strlen($uname) > 0 )
144 $this->remote_uname = $uname;
147 if ( strlen($passwd) > 0 )
149 $this->remote_passwd = $passwd;
157 * @param string containing properly formatted server API. See DA API docs and examples. Http:// URLs O.K. too.
158 * @param string|array query to pass to url
159 * @param int if connection KB/s drops below value here, will drop connection
161 function query( $request, $content = '', $doSpeedCheck = 0 )
163 $this->error = $this->warn = array();
164 $this->result_status_code = NULL;
166 // is our request a http:// ... ?
167 if (preg_match('!^http://!i',$request))
169 $location = parse_url($request);
170 $this->connect($location['host'],$location['port']);
171 $this->set_login($location['user'],$location['pass']);
173 $request = $location['path'];
174 $content = $location['query'];
176 if ( strlen($request) < 1 )
183 $array_headers = array(
184 'User-Agent' => "HTTPSocket/$this->version",
185 'Host' => ( $this->remote_port == 80 ? $this->remote_host : "$this->remote_host:$this->remote_port" ),
187 'Connection' => 'Close' );
189 foreach ( $this->extra_headers as $key => $value )
191 $array_headers[$key] = $value;
194 $this->result = $this->result_header = $this->result_body = '';
196 // was content sent as an array? if so, turn it into a string
197 if (is_array($content))
201 foreach ( $content as $key => $value )
203 $pairs[] = "$key=".urlencode($value);
206 $content = join('&',$pairs);
212 // instance connection
213 if ($this->bind_host)
215 $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
216 socket_bind($socket,$this->bind_host);
218 if (!@socket_connect($socket,$this->remote_host,$this->remote_port))
226 $socket = @fsockopen( $this->remote_host, $this->remote_port, $sock_errno, $sock_errstr, 10 );
229 if ( !$socket || !$OK )
231 $this->error[] = "Can't create socket connection to $this->remote_host:$this->remote_port.";
235 // if we have a username and password, add the header
236 if ( isset($this->remote_uname) && isset($this->remote_passwd) )
238 $array_headers['Authorization'] = 'Basic '.base64_encode("$this->remote_uname:$this->remote_passwd");
241 // for DA skins: if $this->remote_passwd is NULL, try to use the login key system
242 if ( isset($this->remote_uname) && $this->remote_passwd == NULL )
244 $array_headers['Cookie'] = "session={$_SERVER['SESSION_ID']}; key={$_SERVER['SESSION_KEY']}";
247 // if method is POST, add content length & type headers
248 if ( $this->method == 'POST' )
250 $array_headers['Content-type'] = 'application/x-www-form-urlencoded';
251 $array_headers['Content-length'] = strlen($content);
253 // else method is GET or HEAD. we don't support anything else right now.
258 $request .= "?$content";
263 $query = "$this->method $request HTTP/1.0\r\n";
264 foreach ( $array_headers as $key => $value )
266 $query .= "$key: $value\r\n";
270 // if POST we need to append our content
271 if ( $this->method == 'POST' && $content )
273 $query .= "$content\r\n\r\n";
277 if ($this->bind_host)
279 socket_write($socket,$query);
282 while ( $out = socket_read($socket,2048) )
284 $this->result .= $out;
289 fwrite( $socket, $query, strlen($query) );
292 $this->lastTransferSpeed = 0;
293 $status = socket_get_status($socket);
297 while ( !feof($socket) && !$status['timed_out'] )
299 $chunk = fgets($socket,1024);
300 $length += strlen($chunk);
301 $this->result .= $chunk;
303 $elapsedTime = time() - $startTime;
305 if ( $elapsedTime > 0 )
307 $this->lastTransferSpeed = ($length/1024)/$elapsedTime;
310 if ( $doSpeedCheck > 0 && $elapsedTime > 5 && $this->lastTransferSpeed < $doSpeedCheck )
312 $this->warn[] = "kB/s for last 5 seconds is below 50 kB/s (~".( ($length/1024)/$elapsedTime )."), dropping connection...";
313 $this->result_status_code = 503;
319 if ( $this->lastTransferSpeed == 0 )
321 $this->lastTransferSpeed = $length/1024;
326 list($this->result_header,$this->result_body) = preg_split("/\r\n\r\n/",$this->result,2);
328 if ($this->bind_host)
330 socket_close($socket);
337 $this->query_cache[] = $query;
340 $headers = $this->fetch_header();
342 // what return status did we get?
343 if (!$this->result_status_code)
345 preg_match("#HTTP/1\.. (\d+)#",$headers[0],$matches);
346 $this->result_status_code = $matches[1];
349 // did we get the full file?
350 if ( !empty($headers['content-length']) && $headers['content-length'] != strlen($this->result_body) )
352 $this->result_status_code = 206;
355 // now, if we're being passed a location header, should we follow it?
356 if ($this->doFollowLocationHeader)
358 if ($headers['location'])
360 $this->redirectURL = $headers['location'];
361 $this->query($headers['location']);
367 function getTransferSpeed()
369 return $this->lastTransferSpeed;
373 * The quick way to get a URL's content :)
376 * @param boolean return as array? (like PHP's file() command)
377 * @return string result body
379 function get($location, $asArray = FALSE )
381 $this->query($location);
383 if ( $this->get_status_code() == 200 )
387 return preg_split("/\n/",$this->fetch_body());
390 return $this->fetch_body();
397 * Returns the last status code.
402 * @return int status code
404 function get_status_code()
406 return $this->result_status_code;
410 * Adds a header, sent with the next query.
412 * @param string header name
413 * @param string header value
415 function add_header($key,$value)
417 $this->extra_headers[$key] = $value;
421 * Clears any extra headers.
424 function clear_headers()
426 $this->extra_headers = array();
430 * Return the result of a query.
432 * @return string result
434 function fetch_result()
436 return $this->result;
440 * Return the header of result (stuff before body).
442 * @param string (optional) header to return
443 * @return array result header
445 function fetch_header( $header = '' )
447 $array_headers = preg_split("/\r\n/",$this->result_header);
449 $array_return = array( 0 => $array_headers[0] );
450 unset($array_headers[0]);
452 foreach ( $array_headers as $pair )
454 list($key,$value) = preg_split("/: /",$pair,2);
455 $array_return[strtolower($key)] = $value;
460 return $array_return[strtolower($header)];
463 return $array_return;
467 * Return the body of result (stuff after header).
469 * @return string result body
471 function fetch_body()
473 return $this->result_body;
477 * Return parsed body in array format.
479 * @return array result parsed
481 function fetch_parsed_body()
483 parse_str($this->result_body,$x);