Check if a user is root - php

How can i verify if a user is root in a PHP script ? What is the command ?
I tried something like that :
exec("su -l login < `echo password`");
but the su command can not receive password...
Note that the machine is isolated from internet so I can run PHP as root if needed.
EDIT:
I don't want to know if the current user who run the script is root or not.
I have a list of users in my PHP script and I want to know for each login if he has root privileges.

How about posix_getuid()?
if (0 == posix_getuid()) {
echo "Running as root.";
} else {
echo "not root";
}

First, ask yourself what exactly defines a login "having root privileges". AFAICT there are 2 basic solutions.
The old-school way, where sysadmins create multiple accounts with uid 0, which I - and I'm certainly not alone in this - consider to be a nightmare. In this scenario you could check all users in your list using posix_getpwnam and see if their uid matches 0.
The following code snippet does just that, $privileged will contain the users with root privileges :
$logins = array('root', 'john', 'guest', 'foo');
$privileged = array();
foreach($logins as $login) {
$userInfo = posix_getpwnam($login);
if ($userInfo !== FALSE) {
if ($userInfo['uid'] == 0) {
$privileged[] = $login;
}
}
}
The other (and imho only sane) way to do this is to add all users with root/administrative privileges to a specific group (wheel or admin are already used in different Linux distributions, find out which one works for you). This scenario is even simpler, since you can use posix_getgrnam to fetch all members in a specific group.
The following code snippet will match an array of logins you provide, and see who's a member with specific privileges, again $privileged will contain the result (ie. the users in your list that are a member of the group you specified) :
$logins = array('root', 'john', 'guest', 'foo');
$privileged = array();
$groupInfo = posix_getgrnam('admins');
if ($groupInfo !== FALSE) {
$privileged = array_intersect($logins, $groupInfo['members']);
}

Try This .
<?php
if (posix_getuid() == 0){
echo "This is root !";
// add more for root
} else {
echo "This is non-root";
}
?>

If you really mean "is root", then you can just check for whoami, and see if it comes up 'root'
exec("whoami");
If it's a smart thing to do is a different question ;)

Rewritten after your comment
"I don't want to know if the user who
run the script is root or no. I have
to check in a PHP script for some
login/password if they are root or
not"
I now understood that you need to perform a root authentication in PHP.
I suggest to use pwauth instead of whoami/login, etc.
Here is an example on how to use it from PHP, while I believe there can be a simpler way of testing.

If you want to see if a certain system user (as opposed to a web-service user) has root priviliedges, you can use the posix_getpwnam() function:
<?php
$u = posix_getpwnam("username");
if ($u == FALSE) {
print "no-such-user";
} elseif ($u["uid"] == 0) {
print "root";
} else {
print "non-root";
};
?>
Keep in mind that this only checks the username. If you also need to check the password you actually have to try to authenticate with the system.

Related

cPanel Parked Domains Not returning array

A password was changed and cPanel broke. Fixed the password and it's still broken! I have to iterate over parked domains. I've verified the user / password combination is correct via PuTTY.
<?php
include_once('cpanel_api_xml.php');
$domain = 'example.com';
$pass = '';//etc
$user = '';//etc
$xmlapi = new xmlapi('127.0.0.1');
$xmlapi->password_auth($user,$pass);
$domains_parked = $xmlapi->listparkeddomains($user);
foreach ($domains_parked as $k1=>$v1)
{
if ($v1->domain == $domain) {$return = true; break;}
}
?>
That code generates the following error:
Invalid argument supplied for foreach()
Apparently $domains_parked is not even set! I've spent time looking at the function being called so without dumping all 86KB here is the cleaned up version of $xmlapi->listparkeddomains:
<?php
public function listparkeddomains($username, $domain = null)
{
$args = array();
if (!isset($username))
{
error_log("listparkeddomains requires that a user is passed to it");
return false;
}
if (isset($domain))
{
$args['regex'] = $domain;
return $this->api2_query($username, 'Park', 'listparkeddomains', $args);
}
return $this->api2_query($username, 'Park', 'listparkeddomains');
}
?>
I don't know what they're doing with setting a variable as the second parameter. I've called this function with and without and tested the reaction with a simple mail().
Next I tried calling the API in a more direct fashion:
$xmlapi->api2_query($username, 'Park', 'listparkeddomains')
That also does not work. Okay, let's try some really raw output testing:
echo "1:\n";
print_r($xmlapi);
echo "2:\n";
print_r($xmlapi->api2_query($user, 'Park', 'listparkeddomains'));
echo "3:\n";
$domains_parked = $xmlapi->listparkeddomains($user);
print_r($domains_parked);
die();
That outputs the following:
1: xmlapi Object (
[debug:xmlapi:private] =>
[host:xmlapi:private] => 127.0.0.1
[port:xmlapi:private] => 4099
[protocol:xmlapi:private] => https
[output:xmlapi:private] => simplexml
[auth_type:xmlapi:private] => pass
[auth:xmlapi:private] => <pass>
[user:xmlapi:private] => <user>
[http_client:xmlapi:private] => curl ) 2: 3:
I have never encountered such fragile code though I have no choice but to use it. Some help please?
So cPanel version 74 killed off the whole XML API and it doesn't frigin tell you with any error messages. I can not objectively say in the least that cPanel provides a stable platform to build anything reliable upon. You can either intentionally gimp your server from automatically updating (and potentially miss out on security updates) or every so X iterations of time completely rewrite the code again...and again...and again.

verifyLevel function is not working as I want, all levels are seeing my page content

Im trying to do a verify level function to use on top of my pages, to control access to each page depending on the level of administrator.
I did this function now for this purpose:
function verifyLevel($userId){
$pdo = start();
$read = $pdo->prepare("SELECT * FROM admins where id = :userId");
$read->bindValue(":userId", $userId);
$read->execute();
$result = $read->fetch(PDO::FETCH_ASSOC);
echo $result['level'];
}
And now Im trying to use this function.
Admins have level 1, 2 or 3.
In this page, I want to allow that users with level 1 and 3 can see the content.
Only admins with level 2 canĀ“t see content of this page and I want to show a message saying that they dont have permissions to admins with level 2.
Im trying like this:
if(function_exists('verifyLevel')){
if(verifyLevel($_SESSION['admin']['id'] == '2')){
echo 'Sorry, but you dont have permissions to acess this page.';
}
else{
//I show page content
}
}
But its not working, all levels are having acess to content of this page.
Do you see where is my error?
You're echoing the result from verifyLevel(), you need to return it for it to be comparable:
function verifyLevel($userId){
// ...
return $result['level'];
}
// bracket in wrong place -----------V--not--v
if(verifyLevel($_SESSION['admin']['id']) == '2') {
echo 'Sorry, but you dont have permissions to acess this page.';
}
As mentioned by Jeremy Miller, the way you had your function call set up, it would be passing in a boolean of either true or false, which is loosely equivalent to 0 or 1, so your user would probably not be returned correctly from the database either:
// incorrect comparison here, passing boolean instead (0 or 1)
var_dump(verifyLevel($_SESSION['admin']['id'] == '2'));
Should be:
// true representation of your function's processing and comparison
var_dump(verifyLevel($_SESSION['admin']['id']) == '2');
// verifyLevel($_SESSION['admin']['id']) will either be 1, 2 or 3

User tracking in CodeIgniter

I am littlebit new to the codeignitor framework.But love the simplicity.
I have a application requirement that the system need to log all the user activities.
Ex : if a user logged in :then i need something like <username> logged in <time>
If he edit his profile : then i need <username> <edited> <time>
or something like this .
So that the administrator can review all the activities ...
is there any libraries available ?or how can i achieve this with most perfect way in terms of performance?
Please suggest me some common methods .. and opinions .
Thank you.
For maximum flexibility write your own log function. When I need this functionality I include the following function/method in every framework that I use. Wordpress/Codeigniter, etc...
function log($msg = '', $level = 'INFO')
{
$debug_backtrace = debug_backtrace();
$time = date('c', time());
$filename = PATH_TO_YOUR_SCRIPT . '/log/error_log.txt'; // file perms: 0646
$output = "[$level] $time $msg\n";
$output .= "{$debug_backtrace[0]['file']} : {$debug_backtrace[0]['line']}\n";
if ( ! #file_put_contents($filename, $output, FILE_APPEND))
{
error_log("Failed to access log file [$filename] for writing: $msg");
}
}
debug-backtrace allow get the file and line where log function is called

How to strip subdomains to get valid root domain using PHP?

Ok, here's what I'm looking for: from a list of links, I'm stripping everything but the domains. The result is a mixed list of domains and domain-names which represent subdomains.
stackoverflow.com
security.stackexchange.com
whoknows.test.co.uk
you.get.it.by.now.dont.you.com
What I want to do is to trim all list entries down to their VALID (=only existing) root domains like this:
stackoverflow.com
security.stackexchange.com
test.co.uk
-fail-
Currently I explode each line into an array and work my list from back to front, using curl to check each potential root domain for it's existance... as soon as curl throws back a HTTP code >= 200 and < 400, I regard the root domain to be found. When the end of each potential domain lookup is done and no valid domain has been found at all, the domain is considered to be non-existant.
input: stackoverflow.com
test: stackoverflow.com - succeeds and is the root domain
result: stackoverflow.com - valid root domain
input: whoknows.test.co.uk
test: co.uk - fails
test: test.co.uk - succeeds (theoretically) and is the root domain
result: test.co.uk - valid root domain
input: you.get.it.by.now.dont.you.com
test: you.com - fails
test: dont.you.com - fails
test: now.dont.you.com - fails
test: by.now.dont.you.com - fails
test: it.by.now.dont.you.com - fails
test: get.it.by.now.dont.you.com - fails
test: you.get.it.by.now.dont.you.com - fails
result: you.get.it.by.now.dont.you.com - invalid domain
Is there any alternative way to do this? I would like to stop heating up my webserver's CPU with 2 to X (=near to unlimited) curl look-ups for every domain on my 100.000+ list. Also, all these lookups take a bunch of time. Maybe - so I hope - there is a quicker solution to do this.
The catch? It has to work with PHP.
There are a bunch of shortcuts to acheive what you need.
For example, you already know that .co.uk and .com are TLDs, so checking these you can obviously skip.
The problem is with all the other crazy TLDs.
I suggest you take a look at the source for ruby-domain-name
They have done a lot of work using RFCs and known data, to try and process it the right way.
So...
I've been fiddling around with this for a long time now, looking for the potential bottlenecks and after a few days of back and forth I discovered that it's actually CURL (that's waiting for the individual servers to respond with a HTTP code) that's making things slower than needed.
In the end, I opted in for a different "gethostbyname" function that takes IP6 into account to solve my problem(s).
function my_gethostbyname($host, $try_a = FALSE)
{
$dns = gethostbynamel6($host, $try_a);
if ($dns == FALSE)
{
return FALSE;
}
else
{
return $dns[0];
}
}
function gethostbynamel6($host, $try_a = FALSE)
{
$dns = array();
$dns6 = #dns_get_record($host, DNS_AAAA);
if($dns6!== FALSE)
{
$dns = array_merge($dns, $dns6);
}
if ($try_a == TRUE)
{
$dns4 = #dns_get_record($host, DNS_A);
if($dns4!== FALSE)
{
$dns = array_merge($dns, $dns4);
}
}
else
{
$dns = $dns6;
}
$ip6 = array();
$ip4 = array();
foreach ($dns as $record)
{
if ($record["type"] == "A")
{
$ip4[] = $record["ip"];
}
if ($record["type"] == "AAAA")
{
$ip6[] = $record["ipv6"];
}
}
if (count($ip6) < 1)
{
if ($try_a == TRUE)
{
if (count($ip4) < 1)
{
return FALSE;
}
else
{
return $ip4;
}
}
else
{
return FALSE;
}
}
else
{
return $ip6;
}
}
As soon as the first domain-part actually resolves to an IP, (a) the domain exists and (b) is the root domain.
This spares me major time and the trick of this is that you're only as slow as your DNS resolution and some microsecs. The curl option I used before took around 3 seconds per call (sometimes up to the full timeout range I had set to 20 secs), depending on the target server's response time - if any.
The path I now chose is easy to understand: I end up with a list of resolving domains and - when needed - I can check those using curl "on demand" or using one or more CRON jobs "on interval".
I know that it's kind of a workaround, but splitting the problem into two tasks (1 = pre-check for root domain, 2 = check if domain returns expected HTTP code) makes the whole thing faster than trying to do the complete job at once using curl.
What I've learned from this...
When checking domains, try to resolve them first so you can spare yourself the timeout burden that comes with curl.
Curl is great for many tasks, but it's not the smartest way to try to do everything with it.
When you think you can't solve a problem more than you've tried to do, split the problem in two or more parts and check again. Chances are big that you'll discover a whole new world of options to enhance what you've got.
I hope this spares someone the burden of fiddling around with an alike problem for weeks. ;)
class DomainUtils {
function __construct(){
//only these super domains
$this->superDomains = array(
'.com',
'.gov',
'.org',
'.co.uk',
'.info',
'.co',
'.net',
'.me',
'.tv',
'.mobi'
);
}
//get super domain
public function getMainDomain($domain = null){
$domainChunks = explode('.', str_ireplace($this->superDomains, '', $domain));
if(sizeof($domainChunks) == 0){
return false;
}
foreach($domainChunks as $key => $domainChunk){
if($key < sizeof($domainChunks) - 1){
$domain = str_ireplace($domainChunk . '.', '', $domain);
}
}
return $domain;
}
}

Restricting access to php scripts for limited access users

I have a php site which has multiple php scripts. I need to provide users from another site limited access into my system. I want to restrict what pages these ppl can access.
I am doing this in the following manner:
// $_SESSION['systemid'] is set with a value of say, '1'
$permissionArray = $objACCESS->getPermissions($_SESSION['systemid']);
// getPermissions returns an array like the following (for that systemid):
// 0 => {'systemid' => '1', 'permission_type' => 'createcontent' }
// 1 => {'systemid' => '1', 'permission_type' => 'invitecontacts' }
// the following contain a list of script names that should be
// restricted if permission is not allowed
$createcontent = array('createcontent.php');
$managecontent = array('managecontent.php');
$invitecontacts = array('invitecontacts.php');
$page_name=basename($_SERVER["SCRIPT_FILENAME"]);
if(is_array($permissionarray))
{
$haspermissions = false;
foreach($permissionarray as $permissions)
{
if(in_array($page_name,${"$permissions[permission_type]"}))
{
$haspermissions = true;
break;
}
}
}
if($haspermissions==false)
{
// - do not have permissions
echo "<meta http-equiv=\"refresh\" content=\"0;url=".$site_url."404.php\">";
die;
}
...
// rest of the code
...
Q1: Is there a better way of restricting user access?
Q2: If not, is there a way of making this method more efficient / optimal?
The underlying authentication mechanism here doesn't make sense to me. How is $_SESSION['systemid'] set? What is a "system"?
Anyway, I'm going to assume you've got this part of the problem figured out. Accordingly, I'd edit what you put above as follows:
Firstly, adjust getPermissions to return something like:
$perms = array(
'createcontact' => 1,
'invitecontacts' => 1
);
This array would only be populated with the permissions associated with that "system".
Then, check if the current "system" has the required permission for a page as follows:
$cur_page_perm_key = basename($_SERVER['SCRIPT_FILENAME'], '.php');
$has_permission = isset($perms[$cur_page_perm_key]);
if(!$has_permission) {
// No permission? Redirect to an unauthorized page
header('HTTP/1.0 401 Not Authorized');
header('Status: 401 Not Authorized');
header('Location: /unauthorized.php');
exit;
}
The simple "isset" check will be a lot faster than looping, particularly if the number of permissions / pages grows.
Hopefully this helps.

Categories