PDA

View Full Version : Calling API from skin



CyberAlien
04-03-2004, 04:19 PM
Hello,

I tried to call API from skin. Instead of authorization i tried to use cookie from current session (used $_ENV['HTTP_COOKIE']) and of course it didn't work because remote ip is different (i got "HTTP/1.1 401 Unauthorized" in reply).

Is there a way to run API commands from skin without knowing user's password?

DirectAdmin Support
04-04-2004, 01:25 PM
Hello,

Php isn't run like it is via apache. DA is runing the php binary as a person would when using a shell script. DA does pass a few env variables (DOCUMENT_ROOT, USERNAME, USER (same as USERNAME), HOME and SCRIPT_FILENAME), but that's it. You can however get other data from the standard tokens. (|SESSION_ID|)

I believe that CMD_API_GET_SESSION is the only way to get a password right now, and no, there is no way to do it without the password.

John

l0rdphi1
04-04-2004, 01:31 PM
I had asked for a login key we could use in place of a users password. This key would obviously only work when the APIs are used in a skin (when the user has an active session), and the key needs to change for every session.

You'd do something like:

$fsock->set_login($_SERVER['USER'],$_SERVER['LOGINKEY']);

Whereby 'LOGINKEY' is the ENV variable containing our login key.

CyberAlien
04-04-2004, 02:46 PM
Originally posted by l0rdphi1
I had asked for a login key we could use in place of a users password. This key would obviously only work when the APIs are used in a skin (when the user has an active session), and the key needs to change for every session.

You'd do something like:

$fsock->set_login($_SERVER['USER'],$_SERVER['LOGINKEY']);

Whereby 'LOGINKEY' is the ENV variable containing our login key.
Great idea :)
But instead of using it as password it should be used as some other HTTP header to avoid confusion. And for security reasons i suggest to make it valid for only a minute or so after it was added to ENV and accept it only from localhost.

l0rdphi1
04-04-2004, 03:21 PM
I like the expiration idea. That's good.

But, I don't see why it'd need to be a different header: [pseudocode]

if ( enc(incomging_password) == stored_encpassword )
{ return PASS; }
else if ( enc(incoming_password) == stored_encloginkey )
{ return PASS; }
else { reuturn FAIL; }

There's no case where that breaks.

l0rdphi1
04-04-2004, 04:20 PM
Also, John, can I have an 'SSL' ENV, so I can easily determine whether the user is running DA over an SSL connection?

Can be as simple as: [pseudocode]
%ENV{SSL} = 0 // no ssl
%ENV{SSL} = 1 // ssl

Thanks. ;)

DirectAdmin Support
04-05-2004, 10:18 AM
Hello,

I just added the SSL=1 or SSL=0 into the env for skins.

I'll look into adding some sort of key system where the key will be passed through the env, and then you pass the session id/key back through the headers. It would only be valid through 127.0.0.1. Not sure how the expiry would work. If it was 1 key per session, then we'd just leave it till the session died. If it were a list of keys, one per command, then we could more easily just expire them as needed (becomes an issue if you have more than 1 command running at once through a few people).

http://www.directadmin.com/features.php?id=362

John

CyberAlien
04-05-2004, 10:21 AM
Thanks :)

l0rdphi1
04-05-2004, 11:03 AM
Yes. Thank you John :D

CyberAlien
04-20-2004, 01:46 AM
Works perfectly with DirectAdmin 1.21.3. Thanks a lot for this feature!

And for people who are interested in using this feature here is simple php function that will do it. First parameter is command like '/CMD_API_SHOW_DOMAINS' (should start with /). Second parameter is array of POST data or false if request is GET. Function will return false on error or message text on success.


function api_get($cmd, $post = false)
{
// check post
if(is_array($post))
{
$is_post = true;
$str = '';
foreach($post as $var => $value)
{
if(strlen($str) > 0)
{
$str .= '&';
}
$str .= $var . '=' . urlencode($value);
}
$post = $str;
}
else
{
$is_post = false;
}
// set headers
$headers = array();
$headers['Host'] = '127.0.0.1:' . $_ENV['SERVER_PORT'];
$headers['Cookie'] = 'session=' . $_ENV['SESSION_ID'] . '; key=' . $_ENV['SESSION_KEY'];
// add get/post header
if($is_post)
{
$headers['Content-type'] = 'application/x-www-form-urlencoded';
$headers['Content-length'] = strlen($post);
}
// prepare headers
$send = ($is_post ? 'POST ' : 'GET ') . $cmd . " HTTP/1.1\r\n";
foreach($headers as $var => $value)
{
$send .= $var . ': ' . $value . "\r\n";
}
$send .= "\r\n";
if($is_post && strlen($post) > 0)
{
$send .= $post . "\r\n\r\n";
}
// connect
$res = @fsockopen('127.0.0.1', $_SERVER['SERVER_PORT'], &$sock_errno, &$sock_errstr, 3);
if($sock_errno || $sock_errstr)
{
return false;
}
// send query
fputs($res, $send, strlen($send));
// get reply
$result = '';
while(!feof($res))
{
$result .= fgets($res, 32768);
}
@fclose($res);
// remove header
$data = explode("\r\n\r\n", $result, 2);
if(count($data) == 2)
{
return $data[1];
}
return false;
}

l0rdphi1
04-20-2004, 04:54 AM
Of course, I've updated this (http://www.directadmin.com/forum/showthread.php?s=&threadid=258&perpage=20&pagenumber=3#post17632) yesterday. But whatever; that looks like it'll work too :)

CyberAlien
04-20-2004, 04:56 AM
Sorry, didn't see it. But with this function user has to type only one line instead of creating whole class.