Calling API from skin

CyberAlien

Verified User
Joined
Oct 28, 2003
Messages
229
Location
Mars
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

Administrator
Staff member
Joined
Feb 27, 2003
Messages
8,987
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

Verified User
Joined
Jun 22, 2003
Messages
1,471
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

Verified User
Joined
Oct 28, 2003
Messages
229
Location
Mars
l0rdphi1 said:
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

Verified User
Joined
Jun 22, 2003
Messages
1,471
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

Verified User
Joined
Jun 22, 2003
Messages
1,471
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

Administrator
Staff member
Joined
Feb 27, 2003
Messages
8,987
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

Verified User
Joined
Oct 28, 2003
Messages
229
Location
Mars
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.

Code:
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;
}
 

CyberAlien

Verified User
Joined
Oct 28, 2003
Messages
229
Location
Mars
Sorry, didn't see it. But with this function user has to type only one line instead of creating whole class.
 
Top