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