I wrote an automation program which logs in to a website to perform a certain task. The .py file will be given to a number of users but I don't want them to be able to read the code and see the password used for logging in. How do I make sure that they can only execute the file but not read it?
To lock a Python script so it cannot be edited, you compile the PY file into a PYC file. This ensures that the users are unable to make any changes to the existing code within the scripts. A PYC file is binary in nature and cannot be read directly. Below is code that compiles a PY file into a PYC file:
import py_compile
script = "C:\\temp\\myscript.py"
py_compile.compile(script)
That code would make myscript.pyc. PYC files run even if the PY files are not present.
Source : https://support.esri.com/en/technical-article/000010321
You can't do it. If you give a password to your users, no matter how much you try to hide it, it's always possible to find it out.
You can make it slightly more difficult to find out with encryption and obfuscation, but that only stops non-tech-savvy users. And those users probably wouldn't think to read through a bunch of code looking for a plaintext password anyways.
The correct way is to make it so that it's OK if users know their own passwords. Make the server side bit block people from doing things they're not supposed to do (if you don't have one, you need to make one). Use separate accounts for each user so you can separate deactivate them if needed.
Include this in your code:
import py_compile
if not '.pyc' in __file__:
TheNewPathGoesHear=__file__.replace('file.py', 'file.pyc')
py_compile.compile(__file__, TheNewPathGoesHear)
this if statment ensures that this is not a pyc before compiling, if you compile with out this if statment thy will be a new file for the uses each time thy open the pyc file.
NOTE: there must be a '.pyc' in the format of the new file path, you can not to define the new path and that will send it to the __pycache__ folder in your main folder.
One possibility is to have a daemon (service) running which holds the password. That would be running under a restricted user to which normal security has been applied. The users should not be able to access anything under the daemon's user.
Users have a python program which communicates a login request to the daemon via an IPC mechanism, you could use a socket, named-pipe, etc. The daemon performs the task on behalf of the user and communicates the results back.
How practical that is depends on the amount of communication between the user and the server. There would be performance issues if this was an interactive task.
The daemon would probably have to be multi-threaded, depending on volumes, so this could be a lot of work.
A similar possibility is that the daemon could be a web server (using, say, Apache), and then the users access using a browser. That could be easier to program and maintain, but it depends on your environment if that is feasible.
Best way to do that would be as #cdarke offered, but a faster way would be to store the .py file in a hidden, password-protected folder.
Related
Files are being pushed to my server via FTP. I process them with PHP code in a Drupal module. O/S is Ubuntu and the FTP server is vsftp.
At regular intervals I will check for new files, process them with SimpleXML and move them to a "Done" folder. How do I avoid processing a partially uploaded file?
vsftp has lock_upload_files defaulted to yes. I thought of attempting to move the files first, expecting the move to fail on a currently uploading file. That doesn't seem to happen, at least on the command line. If I start uploading a large file and move, it just keeps growing in the new location. I guess the directory entry is not locked.
Should I try fopen with mode 'a' or 'r+' just to see if it succeeds before attempting to load into SimpleXML or is there a better way to do this? I guess I could just detect SimpleXML load failing but... that seems messy.
I don't have control of the sender. They won't do an upload and rename.
Thanks
Using the lock_upload_files configuration option of vsftpd leads to locking files with the fcntl() function. This places advisory lock(s) on uploaded file(s) which are in progress. Other programs don't need to consider advisory locks, and mv for example does not. Advisory locks are in general just an advice for programs that care about such locks.
You need another command line tool like lockrun which respects advisory locks.
Note: lockrun must be compiled with the WAIT_AND_LOCK(fd) macro to use the lockf() and not the flock() function in order to work with locks that are set by fcntl() under Linux. So when lockrun is compiled with using lockf() then it will cooperate with the locks set by vsftpd.
With such features (lockrun, mv, lock_upload_files) you can build a shell script or similar that moves files one by one, checking if the file is locked beforehand and holding an advisory lock on it as long as the file is moved. If the file is locked by vsftpd then lockrun can skip the call to mv so that running uploads are skipped.
If locking doesn't work, I don't know of a solution as clean/simple as you'd like. You could make an educated guess by not processing files whose last modified time (which you can get with filemtime()) is within the past x minutes.
If you want a higher degree of confidence than that, you could check and store each file's size (using filesize()) in a simple database, and every x minutes check new size against its old size. If the size hasn't changed in x minutes, you can assume nothing more is being sent.
The lsof linux command lists opened files on your system. I suggest executing it with shell_exec() from PHP and parsing the output to see what files are still being used by your FTP server.
Picking up on the previous answer, you could copy the file over and then compare the sizes of the copied file and the original file at a fixed interval.
If the sizes match, the upload is done, delete the copy, work with the file.
If the sizes do not match, copy the file again.
repeat.
Here's another idea: create a super (but hopefully not root) FTP user that can access some or all of the upload directories. Instead of your PHP code reading uploaded files right off the disk, make it connect to the local FTP server and download files. This way vsftpd handles the locking for you (assuming you leave lock_upload_files enabled). You'll only be able to download a file once vsftp releases the exclusive/write lock (once writing is complete).
You mentioned trying flock in your comment (and how it fails). It does indeed seem painful to try to match whatever locking vsftpd is doing, but dio_fcntl might be worth a shot.
I guess you've solved your problem years ago but still.
If you use some pattern to find the files you need you can ask the party uploading the file to use different name and rename the file once the upload has completed.
You should check the Hidden Stores in proftp, more info here:
http://www.proftpd.org/docs/directives/linked/config_ref_HiddenStores.html
Note: I don't know how the Python virtual machine works
If Python has a vm, it wouldn't be possible to register every generic input (like standard input, socket reading, file reading) into a log file in order to replay it to get a very similar results?
I was thinking about this possibility because I imagine that a user, who has found a bug in my program, could send to me this log file, which contains everything he has done.
It could be useful or is my thought faulty? If not, how it could be achieved? Does exist something similar?
Sorry wasn't sure how to best word this question.
My scenario is that I have some python code (on a linux machine) that uses an xml file to acquire its arguements to perform a task, on completion of the task it disposes of the xml file and waits for another xml file to arrive to do it all over again.
I'm trying to find out the best way to be alerted an xml file has arrived in a specified folder.
On way would be to continually monitor the folder in the Python code, but that would mean a lot of excess resourses used while waiting for something to turn up (which may be as little as a few times a day). Another way, would be to set up a cronjob, but it's efficiency would't be any better than monitoring from within the code. An option I was hoping was possible would be to set up some sort of interrupt that would alert the code when an xml file appeared.
Any thoughts?
Thanks.
If you're looking for something "easy" to just run a specific script when new files arrive, the incron daemon provides a very handy combination of inotify(7) and cron(8)-like support for executing programs on demand.
If you want something a little better integrated into your application, or if you can't afford the constant fork(2) and execve(2) of the incron approach, then you should probably use the inotify(7) interface directly in your script. The pyinotify module can integrate with the underlying inotify(7) interfaces.
I work off a server along with a number of other people, who, because of unexplained occurrences, change files, symlinks, etc. Unfortunately, all have the same level of file system rights. Is there a straightforward way to capture activity: login/logout time (I know the 'last' command shows this), files changed (deleted, added, etc.), and symlinks created, changed or deleted? I'm wondering if it's more straight forward to do something like this in bash or Python, and which direction to go? Thanks for all help.
First, you really should lock your user accounts down on your server. But if you really want to monitor activity within the file system, you've got a couple of options.
Write a script to parse their bash history on logout, and save the log out time (poor)
Install iwatch, then point it at the locations to monitor, and write a script to record pertinent information whenever something changes to a log file.
If you want to monitor user activity, as if you are watching over their shoulder, that's a little harder. Especially because some things, such as sftp, don't actually make any entries in bash_history. It's an entirely different subsystem.
The best thing to do is just monitor the areas of the filesystem that the users have access to for changes and log them, which is another reason to lock down your users. Linux has user folders for a reason. Everybody gets their own sandbox so that they don't touch each other.
I have a program that creates a bunch of movie files. I runs as a cron job and every time it runs the movies from the previous iteration are moved to a 'previous' folder so that there is always a previous version to look at.
These movie files are accessed across a network by various users and that's where I'm running into a problem.
When the script runs and tries to move the files it throws a resource busy error because the files are open by various users. Is there a way in Python to force close these files before I attempt to move them?
Further clarification:
JMax is correct when he mentions it is server level problem. I can access our windows server through Administrative Tools > Computer Management > Shared Folders > Open Files and manually close the files there, but I am wondering whether there is a Python equivalent which will achieve the same result.
something like this:
try:
shutil.move(src, dst)
except OSError:
# Close src file on all machines that are currently accessing it and try again.
This question has nothing to do with Python, and everything to do with the particular operating system and file system you're using. Could you please provide these details?
At least in Windows you can use Sysinternals Handle to force a particular handle to a file to be closed. Especially as this file is opened by another user over a network this operation is extremely destabilising and will probably render the network connection subsequently useless. You're looking for the "-c" command-line argument, where the documentation reads:
Closes the specified handle (interpreted as a hexadecimal number). You
must specify the process by its PID.
WARNING: Closing handles can cause application or system instability.
And if you're force-closing a file mounted over Samba in Linux, speaking from experience this is an excruciating experience in futility. However, others have tried with mixed success; see Force a Samba process to close a file.
As far as I know you have to end the processes which access the file. At least on Windows
The .close() method doesn't work on your object file?
See dive into Python for more information on file objects
[EDIT] I've re-read your question. Your problem is that users do open the same file from the network and you want them to close the file? But can you access to their OS?
[EDIT2] The problem is more on a server level to disconnect the user that access the file. See this example for Windows servers.