[GRASS-dev] Python script test

Glynn Clements glynn at gclements.plus.com
Mon Jul 21 05:17:31 EDT 2008


Michael Barton wrote:

> Init.sh is not updating PYTHONPATH on my Mac for some reason. I've  
> looked at the code and it seems fine. I DO have a PYTHONPATH. So I'm  
> not sure why it is not updating it. If I change it manually, by simply  
> pasting your code (export PYTHONPATH="$GISBASE/etc/python: 
> $PYTHONPATH") into the GRASS prompt, PYTHONPATH IS modified  
> appropriately and r_in_aster.py works fine with the new grass.py  
> library.

I suspect that /etc/profile resets PYTHONPATH. Init.sh creates a
.bashrc script in the mapset directory (which, at the point that the
session shell is started, is $HOME), and that script sources
/etc/profile.

That's almost certainly bogus. /etc/profile is only meant to be
sourced by login shells, not by subshells, largely for reasons such as
this. I have fixed this in SVN trunk.

AFAICT, you can get around this by setting the environment variable
PROFILEREAD (to anything) before starting GRASS (this looks backwards;
I would expect such a variable to cause /etc/profile to be read, not
inhibit it).

Really, Init.sh does way too much. Over the years, it has accumulated
all manner of "neat tricks" (where "neat" is from the perspective of
whoever decided to add them).

> The only odd difference that I notice is that the source file is  
> init.sh and the startup in the binary is Init.sh. This is especially  
> odd since case doesn't matter when running programs on a Mac. I'm  
> copying William Kyngesbury in case he has some insight.

Init.sh is generated from init.sh by substitution:

	$(ETC)/Init.sh: init.sh
		rm -f $@
		$(SHELL) -c "sed \
		-e \"s#GRASS_VERSION_NUMBER#$(GRASS_VERSION_NUMBER)#\" \
		-e \"s#GRASS_VERSION_DATE#$(GRASS_VERSION_DATE)#\" \
		-e \"s#GRASS_VERSION_UPDATE_PKG#$(GRASS_VERSION_UPDATE)#\" \
		-e \"s#LD_LIBRARY_PATH_VAR#$(LD_LIBRARY_PATH_VAR)#g\" \
		-e \"s#PERL_COMMAND#$(PERL)#\" \
		-e \"s#START_UP#$(START_UP)#\" \
		-e \"s#CONFIG_PROJSHARE#$(PROJSHARE)#\" \
		init.sh > $@"
		chmod +x $@

> With respect to the tempfile question, what happens on Windows when  
> you use g.tempfile vs. Python's tempfile.TemporaryFile()? Overall, it  
> seems like the Python tempfile module is easier to work with and  
> potentially more secure.

AFAICT, tempfile.TemporaryFile() won't suffice for most uses, as the
filename may be removed as soon as it is created. More below.

The main security risk is with temporary files is symlink attacks. You
choose a temporary filename, then open the file for write, but before
you have chance to do so, an attacker creates a symlink with the
chosen name, pointing at some existing file, which you then end up
overwriting.

That's only a risk because temporary files are traditionally created
in the /tmp directory, which is world-writable. If you create
temporary files in a directory for which only you have write
permission, it isn't a problem.

When tempfile functions are described as insecure, this is the issue
in question. The "secure" alternatives invariably open the temporary
file for write (without truncating the file); once the file is open,
the function re-checks whether the name refers to a file or to a
symlink. If it's a symlink, it immediately closes the file and tries
again.

Such functions often return a descriptor or FILE* rather than a
filename. Python's os.tmpfile() behaves like this. Unfortunately, this
is of no use if you need to pass a filename to another program (files
created by os.tmpfile() don't have a name, and will be automatically
deleted when closed).

os.tempnam() and os.tmpnam() both return names without creating the
file. os.tempnam() allows the directory to be specified, so you could
use e.g. /tmp/grass-<user>-<pid> or <mapset>/.tmp/<hostname> for the
files. os.tmpnam() doesn't allow the directory to be specified;
according to the documentation, the Windows implementation chooses a
name in the root directory of the current driver, where you may not
even have permission to create files.

I hadn't looked at the tempfile module before now.

TemporaryFile() and NamedTemporaryFile() produce files which may not
have a name or which may not be able to be re-opened (i.e. 
auto-deleted when closed), so they can't be used in the general case,
although they may be useful for scripts wanting to use temporary files
internally (although os.tmpfile() will suffice there).

mkstemp() would suffice for creating temporary files. It returns both
the handle (which you can close) and the filename, and the file isn't
autodeleted.

mktemp() is like mkstemp() but doesn't open the file, and just returns
a filename. This potentially suffers from symlink attackes, but that
isn't an issue if a private directory is used.

-- 
Glynn Clements <glynn at gclements.plus.com>


More information about the grass-dev mailing list