Version: 1:0
sudo: Sudo Command Processes in Racket
1 Introduction
This package adds automatic
sudo functionality to the Racket standard procedures for creating
processes on Unix-like systems. This can be used for running commands as
different user accounts, such as for running privileged programs for system
administration.
The procedures of this package wrap the Racket standard procedures,
to automatically use programs like sudo and gksudo when necessary. There are features for specifying which programs
to try, in which order.
For example, say you’re writing a system administration program in
Racket, which needs to call the do-stuff program, which can only be run as user root. Instead of using the Racket system* procedure, you use system*/sudo, like so:
(system*/sudo "/sbin/do-stuff" |
"remove" |
".*java.*" |
"costing" |
">" |
"$0") |
When Bob runs this Racket program on a system into which he has
only an SSH command-line interface, logged in as user bob, that system*/sudo call might effectively behave like:
(system* "/usr/bin/sudo" |
"-u" |
"root" |
"/sbin/do-stuff" |
"remove" |
".*java.*" |
"costing" |
">" |
"$0") |
As an aside, system*/sudo actually found the sudo program in "/usr/bin/sudo"; it would have looked a couple other likely places, if not found
there. For security reasons, it does not search the user’s own executable
search path, however.
Later, when Bob runs the Racket program when logged in as user root, that same system*/sudo call will not require a sudo, and instead be like:
(system* "/sbin/do-stuff" |
"remove" |
".*java.*" |
"costing" |
">" |
"$0") |
When Bob later runs the same Racket program on his workstation,
as user bob, where he’s using a graphical desktop, that same system*/sudo call might use the GUI gksudo program:
(system* "/usr/local/bin/gksudo" |
"-u" |
"root" |
"/sbin/do-stuff remove \".*java.*\" costing \">\" \"\\$0\"") |
This is a good time to mention a restriction that this package
imposes: notice in the example above that gksudo takes a single string as the command line to run, rather than the
safer individual arguments that are not re-parsed. This package has to use
quoting and escaping to sanitize the command line for re-parsing.
Additionally, to avoid potential problems in, say, shell scripts that might be
called by gksudo, this package limits commands and arguments used with gksudo to contain only printable ASCII characters in the range 32 to 126.
This prevents things like newlines that might be handled improperly in shell
scripts, and multi-byte character encodings that might defeat quoting and
escaping.
This package also supports users other than root, with the #:user optional keyword argument to each procedure. For example, to start a process running the PostgreSQL psql program as user postgres, you might do something like:
(subprocess/sudo #:user "postgres" |
#f |
#f |
#f |
"/usr/bin/psql" |
"-h" |
my-database-host |
"-d" |
my-database-name) |
Note: Even a properly administered sudo configuration can make it easier to compromise the reliability of
security of a system, accidentally or intentionally, in some cases. At the
same time, judicious configuration and use of sudo can conceivably reduce accidents and vulnerabilites. (Ask any
network administrator who, in lieu of sudo has had a root login window open, and accidentally hit the middle mouse button,
pasting a pile shell script text, which was then executed happily and
destructively as root.) Similarly, this package can be beneficial for reliability and
security, but must be used judiciously.
2 Interface
The interface to this package consists mainly of a set of
procedures that correspond to Racket standard process creation procedures, plus
a parameter that controls how a sudo program is found, by default.
(sudo? x) → boolean?
|
x : any/c |
Predicate for permissible values of the current-sudo parameter, and of the #:sudo keyword argument of the various procedures. This value
specifies how to select a sudo program whenever one is needed.
The values can be expressed by the contract:
(or/c 'sudo |
'gksudo |
absolute-path? |
(listof (or/c 'sudo |
'gksudo |
absolute-path?))) |
More specifically, the value may be either one of the following,
or a list of one or more of the following:
'sudo – The normal sudo program, in one of a few conventional places, if the executable
file exists.
'gksudo – The gksudo program, in one of a few conventional places, if the executable
file exists, and only if X is in use. Currently, X in use is determined by
whether or not the DISPLAY environment variable is set.
An absolute path, which is used if the executable file exists
there. It is then called with the syntax of normal sudo. Note that, since gksudo uses a different command line syntax than sudo, if you want to use gksudo, generally you must use the 'gksudo value instead of an absolute path.
When the value a list of the alternatives above, then they are
tried in order, until one succeeds.
(current-sudo) → sudo?
|
(current-sudo val) → void? |
val : sudo? |
Parameter for how to select a sudo program, if the #:sudo argument is not given. The default value is '(gksudo sudo), which means that, by default, gksudo will be used if it can be found and X is in use, and otherwise sudo will be used.
(subprocess/sudo | [ | #:user user | | | | | | | #:sudo sudo] | | | | | | | stdout | | | | | | | stdin | | | | | | | stderr | | | | | | | command | | | | | | | arg ...) | | → | | any |
|
user : string? = "root" |
sudo : sudo? = (current-sudo) |
stdout : any/c |
stdin : any/c |
stderr : any/c |
command : absolute-path? |
arg : any/c |
Wrapper for suprocess with sudo support.
(system*/sudo | [ | #:user user | | | | | | | #:sudo sudo] | | | | | | | command | | | | | | | arg ...) | | → | | any |
|
user : string? = "root" |
sudo : sudo? = (current-sudo) |
command : absolute-path? |
arg : any/c |
Wrapper for system* with sudo support.
(system*/exit-code/sudo | [ | #:user user | | | | | | | #:sudo sudo] | | | | | | | command | | | | | | | arg ...) | | → | | any |
|
user : string? = "root" |
sudo : sudo? = (current-sudo) |
command : absolute-path? |
arg : any/c |
Wrapper for system*/exit-code with sudo support.
(process*/sudo | [ | #:user user | | | | | | | #:sudo sudo] | | | | | | | command | | | | | | | arg ...) | | → | | any |
|
user : string? = "root" |
sudo : sudo? = (current-sudo) |
command : absolute-path? |
arg : any/c |
Wrapper for process* with sudo support.
(process*/ports/sudo | [ | #:user user | | | | | | | #:sudo sudo] | | | | | | | out | | | | | | | in | | | | | | | error-out | | | | | | | command | | | | | | | arg ...) | | → | | any |
|
user : string? = "root" |
sudo : sudo? = (current-sudo) |
out : any/c |
in : any/c |
error-out : any/c |
command : absolute-path? |
arg : any/c |
Wrapper for process*/ports with sudo support.
3 Known Issues
Add standard KdeSudo support. This is probably just a matter of
finding documentation or setting up a system on which to test, since we have
not yet seen clear documentation of syntax.
Permit sudo? to accept a value of a pair of an absolute path and a symbol
denoting syntax.
Determine any other conventional places in filesystem for the
executables to be found.
Possibly change the conservative quoting and escaping of 'gksudo, to permit more characters, without being unsafe.
4 History
5 Legal
Copyright 2012 Neil Van Dyke. This program is Free Software; you
can redistribute it and/or modify it under the terms of the GNU Lesser General
Public License as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version. This program is
distributed in the hope that it will be useful, but without any warranty;
without even the implied warranty of merchantability or fitness for a
particular purpose. See http://www.gnu.org/licenses/ for details. For other
licenses and consulting, please contact the author.