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

Hi Monks, I have wrote 2 scripts which will allow people to signup for accounts on my server from the web. This is how it works:
when the user fills in the username/password they require on the website the first perl script checks the input for invalid data, if it passes this test, it then writes the following line to account.log file located in the cgi-bin directory with the script:
myperlscript --username=bob --password=mypass --domain=foo.com
Cron then goes and runs the below every 10 minutes.
sh /home/httpd/www.foo.com/cgi-bin/account.log

This will run the contents of account.log. The myperlscript script then goes away and creates the account, sets up permissions, makes changes to postfix....
My question to the monks is: Is there a better way of doing this without going all round the houses like i have?
Or
Is there a way i can get the script to enter into the account.log file and delete the first line in there, thus clearing the command to create the account it has just created, so the next time cron runs account.log, it doesn't attempt to create the same account again?
Thanks

Replies are listed 'Best First'.
Re: Script run as a Cron Job
by Abigail-II (Bishop) on Aug 23, 2002 at 14:33 UTC
    I sure hope you check the username, password and domain names very very carefully, lest someone uses this trick to cause havoc on your system.

    But why are you doing it this way? Why don't you call myperlscript from your CGI program?

    Abigail

      would that work? wouldn't that mean that the myperlscript was being run by webd, which means that it would not have sufficinet rights to run the adduser command?
        Well, you can always make myperlscript suid, or use a setuid wrapper (in fact, you are now using cron to give you this wrapper).

        Otherwise, you could log the new usernames/passwords in a file or database and create a new program that is called from cron. The task of this program is to read the entries, call myperlscript and delete the entries from the file or database. If you use a file, make sure you properly flock it when modifying it.

        Abigail

Re: Script run as a Cron Job
by BrowserUk (Patriarch) on Aug 23, 2002 at 15:32 UTC

    Apart from the issue of creating user accounts on your server via a web form which I leave to your discretion now Abigail-II has warned you.

    The three ideas I tried to describe in the CB are:

    1. Write your own server process (another perlscript) that listens on a socket or a pipe and pass the data to the server process from your cgi script. No cron, actioned as soon as it is passed.

    2. Instead of using a single large file to pass the data between the cgi script and the cron job, use small ones. One per account creation. That way the cgi creates them and the cron job process and deletes them. No locking or race conditions. Use the datetime to name the files to avoid conflict. Use a seperate directory to hold the files.

    3. Use two data files and a sentinel file.

      When the cron job starts, it looks for the sentinel file(an empty file whos job is to act as a signal) if it exists it deletes the file and waits a minute or two to make sure that the cgi script has finished writing to datafile1.

      Then it opens, processes and empties datafile1 and dies.

      If the sentinel file doesn't exist, it creates and waits a minute or two to make sure the cgi script has finished writing to datafile2. It then opens, processes and empties datafile2 and the dies.

      When the cgi script is ready to add data to a datafile, it first checks for the existance of the sentinel file. If the sentinel exists, it writes to datafile1. If it doesn't, it writes to datafile2.

      That way, the two processes can never be attempting to read/write to the same file at the same time.

      The length of the delay that the processing script waits before open and processing a datafile will depend on how long the cgi script is likely to spend writing to it, but as you will want to respond to the person using the web page with a few seconds, 1 or 2 minutes should be ample.


    What's this about a "crooked mitre"? I'm good at woodwork!
      i like the idea of no.1 how would i go about that?

        Take a look at perlman:perlipc with particular reference to the Named-pipe or Unix-Domain TCP Clients and Servers for some simple client and server code samples. A bit further down there is a section on UDP: Message Passing, which would be ideal for your application.

        You could also read the IO::Sockets documentation.

        Essentially, your current cron job script would need to open a socket using the UDP protocol on localhost:someport, (where someport is probably >1024.)

        This would take the place of opening the file in your current script.

        You would then wrap an endless loop around the processing code in your current script and before where you are currently reading from a file you would block waiting for input. When the input arrives, read it, process it and loop back to listen again.

        Where you existing cgi script open and writes to the file, you would connect to localhost:someport (udp), send() the data and close the port.

        I don't recall seeing a UDP server example in perlman:perlipc but its not very different to the TCP server. Maybe there is a good example in IO::Socket docs.


        What's this about a "crooked mitre"? I'm good at woodwork!