Link to home
Start Free TrialLog in
Avatar of projects
projects

asked on

bash send variable to php using curl

I am using curl to get a file from the remote server as such;

On workstation side;
curl -s -k --key some.key --cert some.crt https://someserver/fileupdate.php -u "$USERNAME:$PASSWD" -o $UPDATE

Open in new window


On php side;

        if($_SERVER['REQUEST_METHOD'] === 'GET'){
        // open the update file and retrieve
                $file = fopen("updates/file-YC8268D.txt","r");

                if (!$file) trigger_error('UNABLE TO OPEN updates/file-YC8268D.txt FOR READ', E_USER_ERROR);
                while (!feof($file)){
                        echo fread($file,1024);
                }

                fclose($file);
        }

Open in new window



I have the name of the file I want as a variable but could I send the file name I am wanting from curl to the PHP app?

Also, once file is downloaded, delete it from server side.
Avatar of Randy Poole
Randy Poole
Flag of United States of America image

on the client side pass the filename as id in the url
curl -s -k --key some.key --cert some.crt https://someserver/fileupdate.php?id=file-YC8268D.txt -u "$USERNAME:$PASSWD" -o $UPDATE

Open in new window

server side:
if($_SERVER['REQUEST_METHOD'] === 'GET')
{
	// get the filename passed as id
	$fn=isset($_REQUEST["id"])?$_REQUEST["id"]:"";
	//if no filename was passed raise the error
	if ($fn=="")
	{
		trigger_error('No filename was specified', E_USER_ERROR);
	}
	else
	{
		//prefix the file with the path
		$fn="updates/".$fn
		//open the file
		$file = fopen($fn,"r");
	
		if (!$file) 
		{
			trigger_error('UNABLE TO OPEN updates/file-YC8268D.txt FOR READ', E_USER_ERROR);
		}
		else
		{
			while (!feof($file))
			{
      	                         echo fread($file,1024);
			}
			fclose($file);
			//delete the file
			unlink($fn);
		}
        }
}

Open in new window

Avatar of projects
projects

ASKER

The file seems to be hard coded in your trigger statement. I am sending a variable from curl.
elaborate please
Avatar of Bernard Savonet
@projects:
- Randy's code is hard-coded at line 19 only, so mou cant probably place $fn at this line
- note that since you are relying on the data provided by the user to determine what to transfer, you MUST sanitize the data (eg, you probably don't want that some script kiddies asks the source code of the php file where you have stored the password of your database)... at the bare minimum you should run a test on file extension requested and see that it is in some "whitelist", eg .txt, .pdf, .gif
Just change that line to:
trigger_error('UNABLE TO OPEN '.$fn.' FOR READ', E_USER_ERROR);

Open in new window

I don't know enough about scripting to understand @Fibo.

Randy, this does nothing at all.
I rain this without the file in the directory then added the file into the directory.
The script never saw the file and never knew it was there.

The file name is being generated on the script side so it sends the file name to php.
Php should check in that directory to see if such a file name exists, if so, script downloads it then the file is deleted. If no file, keep looking and check again the next day.
show me the curl command you ran to execute the script
curl -s -k --key some.key --cert some.crt https://server/fileupdate.php?id=open-$USERNAME.txt -u "$USERNAME:$PASSWD" -o $UPDATE
and did you try to run that url from a browser as well?
No because the script makes up the file name. But, I'll give it a try manually and report.
Works from the command line but doesn't pick up the file, no errors at all.
Hmm, there was an error...
HTTP/1.0 500 Internal Server Error
[01-Aug-2014 11:32:41 PHP Parse error:  syntax error, unexpected '$file' (T_VARIABLE) in fileupdate.php on line 57

Line 57 is

            $file = fopen($fn,"r");
line above it
$fn="updates/".$fn

Open in new window

is missing the ending ;
$fn="updates/".$fn;

Open in new window

Seems to work as advertised.

Only two things.

1: When the file doesn't exist in the directory, it is generating a php error which would be a lot of unnecessary logging. However, if someone was hacking, I'd like to know about it so is there some way of not logging if authenticated, otherwise log?

2: Fibo's command about script kiddies?
Is this safe as it is written now?
I am not sure what kind of authentication you are using.  Also to correct issue with someone trying to grab files in another directory change:
$fn="updates/".$fn;

Open in new window

to
$fn="updates/".str_replace("..","**",$fn);

Open in new window

this will produce an error if someone is trying to pass a file name like ?id=../../../somefilename to resend your directory tree
The authentication is shown in my original message. It's a curl https connection using name/passwd.

But, how do I prevent the logs from being created each time the script checks unless it is an authorized connection?

PHP Warning:  ... failed to open stream: No such file or directory
PHP Fatal error:  UNABLE TO OPEN ... FOR READ
I cannot accept a solution until I know it is a safe one. The constant logging is an issue also as this will created lots of useless activity and make it difficult to find actual problems.

Here is what I have so far;

Sender;
function firm_check()
{
        # Check for new file
        echo "Checking for update"
        curl -s -k --key sum.key --cert sum.crt https://server/update.php?id=$USERNAME.bin -u "$USERNAME:$PASSWD" -o
 $UPDATE

        for filename in $(ls /tmp); do
        if [ -e $filename ]
            then
                if [[ $filename =~ .bin$ ]]
                then
#                real command goes here
echo "There is an update"
                fi
            fi
        done
}

Open in new window


PHP Side;
if($_SERVER['REQUEST_METHOD'] === 'GET')
{
        // get the filename passed as id
        $fn=isset($_REQUEST["id"])?$_REQUEST["id"]:"";
        //if no filename was passed raise the error
        if ($fn=="")
        {
                trigger_error('No filename was specified', E_USER_ERROR);
        }
        else
        {
                //prefix the file with the path
                $fn="updates/".str_replace("..","**",$fn);
                //open the file
                $file = fopen($fn,"r");

                if (!$file)
                {
                        trigger_error('UNABLE TO OPEN '.$fn.' FOR READ', E_USER_ERROR);
                }
                else
                {
                        while (!feof($file))
                        {
                                 echo fread($file,1024);
                        }
                        fclose($file);
                        //delete the file
                        unlink($fn);
                }
        }
}

Open in new window


And of course, the non stop error in logs;
fopen(updates/0412E6A.txt): failed to open stream: No such file or directory in fileupdate.php on line 57
PHP Fatal error:  UNABLE TO OPEN updates/0412E6A.txt FOR READ in fileupdate.php on line 61

Open in new window


I may have missed something or edited a word/name incorrectly in my attempt to obfuscate but otherwise, everything is at it should be. It all works, other than I am not sure how safe this is nor how to get rid of the log for legitimate checks.
- If you test that the file exists before opening it, then this will not raise an error. See http://php.net/manual/en/function.file-exis

- At line 4 I would use my usual shortcut:
$fn= trim( ' ' . @$_GET['id'] );
which works in all cases.

- checking rhat the filename has an authorized extension:
$okTypes = array( 'txt' , 'gif', 'pdf');
...
$fn=...
$fileOk=true;
$dotPos=strrpos($fn, '.');
If ( !$dotPos OR (0 == $dotPos) ) $fileOk=false;

if ($fileOk) {
$fileType=substr($fn, ($dotPos + 1));
$fileOk = in_array($fileType, $okTypes);
}
- Sorry, typing from my phone creates errors. The correct link is
http://fr2.php.net/manual/en/function.file-exists.php 

- Also
$fileOk=true;
 $dotPos=strrpos($fn, '.');
 If ( !$dotPos OR (0 == $dotPos) ) $fileOk=false;

Open in new window

would be smarter as
$dotPos=strrpos($fn, '.');
$fileOk = $dotPos AND (1 <= $dotPos);

Open in new window

Any chance you could just write this as my final output should look? I don't want to make any errors and I'm not 100% sure of some of the things you mention above.
Complete code base would be something like
if($_SERVER['REQUEST_METHOD'] === 'GET')
{
        // get the filename passed as id
        $fn= trim( ' ' . @$_GET['id'] ); // use GET since this is what we selected
        //if no filename was passed raise the error
        if ( '' == $fn)
        {
                trigger_error('No filename was specified', E_USER_ERROR);
        } else
        {
                //sanitize filename
                // check extension
                $okTypes = array( 'txt' , 'gif', 'pdf'); // adapt to your case
                $dotPos=strrpos($fn, '.'); // strRpos; CAUTION:  we decide that file requests MUST have an extension
                $fileOk= //combined AND: will stop on first false
                	!(!$dotPos) //make it true or false
                	AND (1 <= $dotPos) ) 
                	AND in_array($substr($fn, ($dotPos + 1)), $okTypes)
                	AND ( '.' <> substr($fn, 0, 1) ) // if start with a '.' possible hack attempt
                	AND !strpos($fn, '/') // no / allowed in filename
                	;
                if !$fileOk { 
                	trigger_error("Illegal filename [$fn], possible hack attempt", E_USER_ERROR);
                } else {
	                //prefix the file with the path
	                $fn="updates/$fn";
	                //test file exists AND openable
	                if !file_exists($fn) {
	                	trigger_error("File $fn does not exist or cannot be accessesd", E_USER_ERROR);
	                } else {
	                	//open the file
		                $file = fopen($fn,"r");
		
		                if (!$file)
		                {
		                        trigger_error('UNABLE TO OPEN '.$fn.' FOR READ', E_USER_ERROR);
		                } else {
		                        while (!feof($file))
		                        {
		                                 echo fread($file,1024);
		                        } //while
		                        fclose($file);
		                        //delete the file
		                        unlink($fn);
		                } //else file
		              } // else exists
                } //else FileOK
        } //fn
} // GET

Open in new window

Something like or actually safe to use? :)


PHP Parse error:  syntax error, unexpected ')' in fileupdate.php on line 58

AND (1 <= $dotPos) )                                    < Line 58
Sorry for the extra )
Remove it!
I hav placed additional tests to enhance security.
No problem.

I did remove it before posting but then I got this error;

PHP Parse error:  syntax error, unexpected '!', expecting '(' in fileupdate.php on line 63

            if !$fileOk {               < Line 63
Are we going to complete this?
Sorry, on the love with no Access to my computer.
Missing some () there.. I will check then post the correct answer
I'd love to accept the solution and close this question so thanks.
The correct program is
if($_SERVER['REQUEST_METHOD'] === 'GET')
{
        // get the filename passed as id
        $fn= trim( ' ' . @$_GET['id'] ); // use GET since this is what we selected
        //if no filename was passed raise the error
        if ( '' == $fn)
        {
                trigger_error('No filename was specified', E_USER_ERROR);
        } else
        {
                //sanitize filename
                // check extension
                $okTypes = array( 'txt' , 'gif', 'pdf'); // adapt to your case
                $dotPos=strrpos($fn, '.'); // strRpos; CAUTION:  we decide that file requests MUST have an extension
                $fileOk= //combined AND: will stop on first false
                	!(!$dotPos) //ensure it has one of the 2 values true or false
                	AND (1 <= $dotPos)
                	AND in_array($substr($fn, ($dotPos + 1)), $okTypes)
                	AND ( '.' <> substr($fn, 0, 1) ) // if start with a '.' possible hack attempt
                	AND !strpos($fn, '/') // no / allowed in filename
                	;
                if (!$fileOk) { 
                	trigger_error("Illegal filename [$fn], possible hack attempt", E_USER_ERROR);
                } else {
	                //prefix the file with the path
	                $fn="updates/$fn";
	                //test file exists AND openable
	                if (!file_exists($fn)) {
	                	trigger_error("File $fn does not exist or cannot be accessesd", E_USER_ERROR);
	                } else {
	                	//open the file
		                $file = fopen($fn,"r");
		
		                if (!$file)
		                {
		                        trigger_error('UNABLE TO OPEN '.$fn.' FOR READ', E_USER_ERROR);
		                } else {
		                        while (!feof($file))
		                        {
		                                 echo fread($file,1024);
		                        } //while
		                        fclose($file);
		                        //delete the file
		                        unlink($fn);
		                } //else file
		              } // else exists
                } //else FileOK
        } //else fn
} // GET

Open in new window

Wonderful. Here is the result;

PHP Notice:  Undefined variable: substr in fileupdate.php on line 59
PHP Fatal error:  Function name must be a string in fileupdate.php on line 59

                      AND in_array($substr($fn, ($dotPos + 1)), $okTypes)  < Line 59
Being unable to access my susal PHP checker lets me fail to spot all these typos.
This should do it now
<?php
if($_SERVER['REQUEST_METHOD'] === 'GET')
{
        // get the filename passed as id
        $fn= trim( ' ' . @$_GET['id'] ); // use GET since this is what we selected
        //if no filename was passed raise the error
        if ( '' == $fn)
        {
                trigger_error('No filename was specified', E_USER_ERROR);
        } else
        {
                //sanitize filename
                // check extension
                $okTypes = array( 'txt' , 'gif', 'pdf'); // adapt to your case
                $dotPos=strrpos($fn, '.'); // strRpos; CAUTION:  we decide that file requests MUST have an extension
                $fileOk= //combined AND: will stop on first false
                	!(!$dotPos) //ensure it has one of the 2 values true or false
                	AND (1 <= $dotPos)
                	AND in_array(substr($fn, ($dotPos + 1)), $okTypes)
                	AND ( '.' <> substr($fn, 0, 1) ) // if start with a '.' possible hack attempt
                	AND (!strpos($fn, '/')) // no / allowed in filename
                	;
                if (!$fileOk) { 
                	trigger_error("Illegal filename [$fn], possible hack attempt", E_USER_ERROR);
                } else {
	                //prefix the file with the path
	                $fn="updates/$fn";
	                //test file exists AND openable
	                if (!file_exists($fn)) {
	                	trigger_error("File $fn does not exist or cannot be accessesd", E_USER_ERROR);
	                } else {
	                	//open the file
		                $file = fopen($fn,"r");
		
		                if (!$file)
		                {
		                        trigger_error('UNABLE TO OPEN '.$fn.' FOR READ', E_USER_ERROR);
		                } else {
		                        while (!feof($file))
		                        {
		                                 echo fread($file,1024);
		                        } //while
		                        fclose($file);
		                        //delete the file
		                        unlink($fn);
		                } //else file
		              } // else exists
                } //else FileOK
        } //else fn
} // GET
?>

Open in new window

It works!
The only problem which still remains is this error in the php logs which I need to to filter out when it is a legitimate check by an authorized user. The remote script is using an authenticated curl connection to check for the update. I need to not have error logs for legit connections and only for someone trying to do something nefarious :)
 

PHP Fatal error:  File update/68DDB672.txt does not exist or cannot be accessesd in fileupdate.php on line 70

Line 70 is your line 30.
1 - As you guessed you could comment out this lifting instruction

2 - However, I would probably keep this logging. If a user tries to open a non-existent file, this hints at some problem that should be addressed
1 Instead of commenting it out, what would be best is to not log if this is an authenticated connection. Otherwise, log because it means someone is messing around.

2
The problem is that many remotes are checking for this update many times daily so it is filling the logs up very quickly.
1 - Code change would be to replace
                if (!$file)
                {
                        trigger_error('UNABLE TO OPEN '.$fn.' FOR READ', E_USER_ERROR);
                }
                else

Open in new window

with
                if ($file)

Open in new window


1bis - Regarding the check for "an authenticated connection"?
Your initial question just mentions the connection thru https. You can check that before any other code by inserting a test like
if ('' == @$_SERVER['HTTPS']) {
	trigger_error('Uncorrect protocol requested', E_USER_ERROR);
	exit();
}

Open in new window

which will generate the error message then stop execution

2 - Disk space is cheap, so logfile volume is not really a problem.
However, if you have that many errors that log volume is huge, this shows some problem somewhere: who is asking for inexistent files? why? which docs are they given?
This however is out of the scope of your initial question.
There was one extra }  at
} // GET
Removing that fixed it.

However, I am still getting the error in the php logs.

PHP Fatal error:  File updates/8DDGEJU.txt does not exist or cannot be accessesd in fileupdate.php on line 70

Also, the command is changed?

 if (!$file)
to
 if ($file)

Lose the exclamation?
This is how things look at this point. The only way I could get rid of the php error upon checking for a file which didn't exist, even by an authenticated curl connection was to disable the error message as seen in the code.

if($_SERVER['REQUEST_METHOD'] === 'GET')

                if ('' == @$_SERVER['HTTPS']) {
                trigger_error('Incorrect protocol requested', E_USER_ERROR);
                exit();
                }
{
        // get the filename passed as id
        $fn= trim( ' ' . @$_GET['id'] ); // use GET since this is what we selected
        //if no filename was passed raise the error
        if ( '' == $fn)
        {
                trigger_error('No filename was specified', E_USER_ERROR);
        } else
        {
                //sanitize filename
                // check extension
                $okTypes = array( 'txt' , 'gif', 'pdf'); // adapt to your case
                $dotPos=strrpos($fn, '.'); // strRpos; CAUTION:  we decide that file requests MUST have an extension
                $fileOk=  //combined AND: will stop on first false
                        !(!$dotPos) //ensure it has one of the 2 values true or false
                        AND (1 <= $dotPos)
                        AND in_array(substr($fn, ($dotPos + 1)), $okTypes)
                        AND ( '.' <> substr($fn, 0, 1) ) // if start with a '.' possible hack attempt
                        AND (!strpos($fn, '/')) // no / allowed in filename
                        ;
                if (!$fileOk) {
                        trigger_error("Illegal filename [$fn], possible hack attempt", E_USER_ERROR);
                } else {
                        //prefix the file with the path
                        $fn="updates/$fn";
                        //test file exists AND openable
                        if (!file_exists($fn)) {
//                              trigger_error("File $fn does not exist or cannot be accessed", E_USER_ERROR);
                        } else {
                                //open the file
                                $file = fopen($fn,"r");

                                if ($file)
                                        while (!feof($file))
                                        {
                                                 echo fread($file,1024);
                                        } //while
                                        fclose($file);
                                        //delete the file
                                        unlink($fn);
                                } //else file
                              } // else exists
                } //else FileOK
        } //else fn
// GET

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Bernard Savonet
Bernard Savonet
Flag of France image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I so appreciate people who stick to something until it's done! Thank you very much.

By the way, the only thing that was still wrong with the solution was an extra exclamation mark which I removed.