korpenkraxar has asked for the wisdom of the Perl Monks concerning the following question:

Dear Wise Monks,

Having lurked around here for a while and learned a lot from various topics and questions, I've just stumbled across a programming problem having to do with security that is new to me and I would be very happy to get some general design input before I actually start messing around too much with the code.

My goal is to write a daemon that collects information (or "clues") about where a laptop may be located and (automatically or semi-automatically) tries to connect to the LAN and/or WLAN at that location according to predefined rules and priorities. This is meant to run on my Linux system and I expect to use standard tools like udev, ifplugd, wpa_supplicant, ifconfig, iwconfig, ethtool, iwlist, /proc and /sys to get information about surrounding networks. Perl is the glue that surrounds and binds everything.

However, to be able to actually swap network interfaces and set different configurations the daemon needs to have super-user access at some point. This is where big red warning lights started blinking. So, at last, here are my questions:

* At what point should the daemon be granted authority to change network settings? Run it as root all the time? Run it as special user with restriced password-less sudo access? What is the general recommendation for a daemon like this to keep security at a "reasonable" level? Are there any perl gotchas I should be aware of in this case?

* The daemon can in principle monitor and use any clues, not only network information, but perhaps some aspects of user behavior or even GPS data, to conclude where the computer is and what to do. While the rules are set when the daemon starts, clues are updated continuously. But it would be nice as a user to be able to force the daemon to activate some specific network configuration or just to "inject" location clues ("roaming", "home", "work"). The simplest way to inform a running perl program about this is perhaps having a small temporary text file in /tmp, but this way of interacting with a daemon that have super-user privileges feels neither very secure or elegant. How can I make a perl program to listen to/detect this kind of input?

I am mainly developing this program out of curiosity and I realize that the concept may have flaws, but instead of telling me to forget it, please give me some suggestions on how to deal with these security issues in a good (or better) way.

Replies are listed 'Best First'.
Re: Perl as a daemon... as root?
by shmem (Chancellor) on Jul 30, 2007 at 05:30 UTC
    At what point should the daemon be granted authority to change network settings? Run it as root all the time? Run it as special user with restriced password-less sudo access? What is the general recommendation for a daemon like this to keep security at a "reasonable" level? Are there any perl gotchas I should be aware of in this case?

    If your daemon is well behaved, there's no reason to not run it as root. Well behaved means at least:

    • runs under -T
    • doesn't eval other than as use or require
    • doesn't accept bogus input
    • is safely coded to not hog any resource
    • closes STDIN and STDOUT and re-opens STDERR to syslog
    • has a well-defined interface to process input
    • can be killed any time without leaving a mess
    • ...

    Dropping privileges is good for daemons exposed to the AB (anonymous bastard), like web- and mail servers. Your daemon doesn't seem to be exposed in that way; it is running on the local system and might accept input from a local user (only). So there's no point in dropping privs and re-gaining them later to do the tasks the daemon is written for: you would only make more "red lights blink" (e.g. passwordless sudo) elsewhere.

    How can I make a perl program to listen to/detect this kind of input?

    Your daemon, apart from setting up an initial state at startup, seems to be event driven, so I'd look up things by that keyword (Super Search). A socket interface might be the way to go for user input. Have a look at POE.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      ...So there's no point in dropping privs and re-gaining them later to do the tasks the daemon is written for: you would only make more "red lights blink" (e.g. passwordless sudo) elsewhere.

      If the system supports setreuid() (Linux does), you don't need sudo to switch the userid. Start the script under root (or another privileged id), then drop privileges immediately. When an action needs root privileges again, that can be done with a local change to the effective uid $>:

      print "real: $<, effective $>\n"; $> = 1000; # drop privileges print "real: $<, effective $>\n"; { # locally regain privileges local $> = 0; $> == 0 or die "Insufficient privileges, run script as root"; print "real: $<, effective $>\n"; } # unprivileged again print "real: $<, effective $>\n";
      That works without compromising security in any way.

      Anno

Re: Perl as a daemon... as root?
by tirwhan (Abbot) on Jul 30, 2007 at 11:17 UTC

    In cases such as these (when a daemon absolutely has to perform certain tasks as root) it is usually best to use privilege separation. Fork your process into two daemons and drop privileges on one of them. The privileged process (i.e. the one running as root) is used to only perform those tasks that require root access. The other process is used for all other tasks (especially for potentially dangerous IO tasks such as sniffing the network or accepting user input). Communication between the two can be done via any of the various IPC means available.

    The way you describe your goal it might even be sufficient for the unprivileged process to gather information only when the user tells it to, so it doesn't even have to be a daemon. This would mean you'd run the daemon as root all the time but have a user-run script sitting in the front, which accepts user input, gathers the necessary information and then sends this to the daemon for taking action (i.e. activate and configure the network interface). This, AFAIK, is how network-manager works, which does a lot of what you're describing (though not everything, so don't let its existence discourage you from this).

    One simple way of communicating with the privileged daemon is for it to open a named pipe, which a user process/daemon can write to. By making this pipe group- and not world-writable you can limit the users who can communicate with the daemon to a given group. Or, if you only want one user to be able to communicate with the daemon, you can just make it writable for that user.


    All dogma is stupid.
Re: Perl as a daemon... as root?
by korpenkraxar (Sexton) on Dec 31, 2007 at 02:58 UTC
    Hi all! Sorry for not answering until now, but thanx for your feedback! I started writing some code a little while ago based around a client-server fork where the server drops privileges until it needs to perform system configuration.