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

Greetings,

I'm testing the Perl file locking features against programs like useradd and Samba smbpasswd program to be sure that those programs won't mess the passwords files while my Perl CGI at working in them.

For my surprise, both programs were able to change the respective files while the script code below is running (and keeping the file locked).

#!/usr/bin/perl use strict; use warnings; use Fcntl qw(:DEFAULT :flock); my $sec = 30; print 'Please type the file that I should lock for $sec: '; my $file = <STDIN>; chomp $file; sysopen( FH, $file, O_RDWR ) or die "Cannot edit $file: $!\n"; flock( FH, LOCK_EX ) or die "Cannot lock $file: $!\n"; print 'Ok, holding the file for $sec seconds. I will not change anythingin the file', "\n"; sleep $sec; close(FH); print "Finished\n";

Any sugestion to solve this issue without having to checking the source code of these programs that are, for sure, written in C or C++ and probably are using flock or lockf or fcntl functions to get file locking features?

Thanks in advance.

Regards,

Alceu Rodrigues de Freitas Junior
--------------------------------------
glasswalk3r@yahoo.com.br
http://www.imortais.cjb.net
"You have enemies? Good. That means you've stood up for something, sometime in your life." - Sir Winston Churchill
  • Comment on How to make sure that non-Perl programs will respect Perl's file locking?
  • Download Code

Replies are listed 'Best First'.
Re: How to make sure that non-Perl programs will respect Perl's file locking?
by brian_d_foy (Abbot) on Jan 11, 2006 at 16:50 UTC

    On unix-like systems, file locking is advisory by default. This means that nobody else has to pay attention to anything you say about the file-lock state. Wikipedia has a nice entry on file locking that expands on the stuff already mentioned in perlfunc's entry for flock.

    You want a mandatory lock that the system enforces. You don't implement this yourself (either through semaphores or other schemes). The solution to your task is complicated by the particular operating system you use, your filesystem set-up, and so on.

    In your case, however, if the password changes, I think the CGI script should have to re-authenticate. That's the point of changing passwords. :)

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review
      You want a mandatory lock that the system enforces.
      No you don't. At least, not in general. Just suppose you have mandatory file locking. Consider a (user) program that opens /etc/passwd and acquires a read lock. You can't prevent that as /etc/passwd needs to be readable by all.

      As long as the program keeps the lock, noone could acquire an exclusive lock on /etc/passwd, so no modifications to the user of the machine are possible.

      Believe me, you don't want system-wide mandatory locking.

      Perl --((8:>*

        I never said anything about a read lock. I don't think a read lock would do any good here. :)

        --
        brian d foy <brian@stonehenge.com>
        Subscribe to The Perl Review
Re: How to make sure that non-Perl programs will respect Perl's file locking?
by McDarren (Abbot) on Jan 11, 2006 at 16:51 UTC
    The problem is that flock file locking is advisory only. Which means it's only good if everyone "plays by the rules".

    If you have a copy of the Camel (3rd Ed) handy, this is discussed in some detail in Chapters 16.2.1 and 23.2.2

    I believe that I have read somewhere that it is possible to get around this, but I can't recall the source.

    Cheers,
    Darren :)

Re: How to make sure that non-Perl programs will respect Perl's file locking?
by ruoso (Curate) on Jan 11, 2006 at 17:40 UTC

    I know that wasn't your question, but I'd like to warn you that it's pretty weird to have a CGI script manipulating /etc/passwd directly. This means that the CGI must have how to read this file (that's quite regular) and worse, the CGI script will have how to *write* to /etc/passwd. This means that:

    1. You have your /etc/passwd writeable for others that root
    2. Your script is running as root (gah)

    IMHO, this is absolutelly unacceptable, as one single failure in your script can exploit the entire system in a single act. The correct way of doing that, IMHO, is using the Unix PAM to change the password. This way you'll have how to say that your script, after authenticated with something (which can be any implemented PAM module), has the right to change the password for a *set of users*. Then PAM (something more people trust on) will change the passwords even if they aren't in /etc/passwd, which makes your CGI more portable...

    UPDATE: Reading better, I saw you just wanted to lock for reading, which is much safer, as you don't need to write on it after all.

    UPDATE 2: I was just thinking... why aren't you using getpwent() instead of reading /etc/passwd? This way you won't need to care about NIS, LDAP or such... and won't need to care about locking, as glibc will return a reasonable value...

    daniel

      That is an interesting point. But I'm not using neither of your options: the CGI uses the program Sudo (and a tight setup of it) to get the proper rights. Using Taint mode also helps regarding security breachs.

      The UNIX PAM recomendation is a good one but is not that portable: Slackware Linux, for example, doesn't use PAM AFAIK. Besides doing this helps to solve only part of the problem: the CGI still needs to update the smbpasswd file without anybody else doing it at the same time.

      Alceu Rodrigues de Freitas Junior
      ---------------------------------
      "You have enemies? Good. That means you've stood up for something, sometime in your life." - Sir Winston Churchill

        Hmmm... So you *do* are changing the smbpasswd in your CGI script... I wouldn't recommend it...

        The fact that Slackware doesn't support PAM is really a suprise to me... I've been using PAM for a long time and actually can't think how it can't be in Slackware...

        Anyway... If you were using PAM, you could place a pam module that reflects the changes on the user password to the smbpasswd file. (I know such module exists, just don't remeber its name).

        "Fixing" your Slackware to include PAM is possibly a good idea, or else you'll have to stick with this insecure approuch of changing this files directly...

        daniel
Re: How to make sure that non-Perl programs will respect Perl's file locking?
by wazzuteke (Hermit) on Jan 11, 2006 at 16:33 UTC
    From my understanding, flock is truely a syscall to the OS you are running the application on. So, in *nix, for example, if you man flock, you will get the manual for this specific function call.

    One thing I've always done, therefore avoiding any direct system calls, is create a 'lock file'. Creating a simple file, where nothing is allowed to do 'anything' until the file is removed.

    For example:
    sleep( 0.001 ) while ( -r '.lock' ); # You made it here, the file is gone
    Naturally, it's always easy to say something like this, however you may be stuck with using flock. In that case, I would research the man pages of the OS you are running to find out the exact behavior of the syscall you're using.

    ---hA||ta----
    print map{$_.' '}grep{/\w+/}@{[reverse(qw{Perl Code})]} or die while ( 'trying' );
      Don't write code like that. Polling when there's a perfectly good blocking system call is a huge waste of CPU and I/O resources. If you actually had an application with any non-trivial lock contention, this sort of code will probably cripple your server.
Re: How to make sure that non-Perl programs will respect Perl's file locking?
by jesuashok (Curate) on Jan 11, 2006 at 16:51 UTC
    Hi

    This is not like locking the file when the Othere program tries to modify the file.

    Please see the below definition

    LOCK_SH Place a shared lock. More than one process may hold a shared lock for a given file at a given time. LOCK_EX Place an exclusive lock. Only one process may + hold an exclusive lock for a given file at a given tim +e. LOCK_UN Remove an existing lock held by this process.
    The possible ways of checking the locks :-

    Having a ENVIRONMENT Variable that will check for the locking Mechanism. ( Set and Unset the Variable )

    Lock file Mechanism

    "Keep pouring your ideas"