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

here is the basic problem, i have been assigned to develope a set of administration web tools at my job. it needs to be coded in perl because the language is so easy to maintain. but i have a very limited perl expirence so i offer up my humble (lousy) code here. the developement model I must follow is a web form (which will be secured some way.... any ideas?) will submit data to a perl script which will parse out what the form is doing. the perl script will then call a suid root C program to get enough permissions to do what it needs to. the C program will then call another perl script to do the dirty work.
with me? ok, my problem is that the my code works perfectly off of the command line and not at all off of the web. it just doesnt call the C program as near as i can figure it.
this is the source of perl program calling the C program
#!/usr/local/bin/perl -w use CGI; my $post_data=new CGI; my $username=$post_data->param('username'); my $on_off=$post_data->param('on_off'); my $message=$post_data->param('message'); &Command(); @junk = ("authorize", "vacation.pl", $username, $on_off, $message); #@junk = ("vacation.pl", $username, $on_off, $message); $runme = join (" ",@junk); &Header(); print $runme; $output=`$runme`; print $output; &Footer(); sub Command { $username=$ARGV[0]; $on_off=$ARGV[1]; $message = join (" ",@ARGV); $message =~ s/$username//; $message =~ s/$on_off//; } sub Header { print "Content-type: text/html\n\n"; print "<HTML>\n"; print " <HEAD>\n"; print " <TITLE>$username Vacation Message</TITLE>\n"; print " </HEAD>\n"; print " <BODY bgcolor=white link=black vlink=black alink=black>\n"; print " <TABLE border=0 width=100%>\n"; print " <TR>\n"; print " <TD align=left>"; print `date`; print " </TD>\n"; print " <TD width=30%> </TD>\n"; print " <TD align=right> Information Technologies </TD>\n"; print " </TR>\n"; print " </TABLE>\n"; print " <HR>\n"; print " <TABLE width=100% bgcolor=\"\#005533\">\n"; print " </TABLE>\n"; print " <HR>\n"; } sub Footer { print " <HR>\n"; print " <TABLE border=0 width=100% bgcolor=\"\#005533\">\n"; print " <TR><TD>\n"; print " <center><font color=white>IT </font></center>\n"; print " </TD></TR>\n"; print " </TABLE>\n"; print " <HR>\n"; print " </BODY>\n"; print "</HTML>\n"; }
this is the code for the C program, things being authorized must be in the ASCII text document named auth.dat and be delimited by a new line (authorize)
#include <stdio.h> #include <stdlib.h> int main(argc, argv) int argc; char *argv[]; { FILE *authfile; char runme[2000]; char allowed[50]; int temp; if ( 2 > argc) { printf("Usage: %s [script name] <options>\n", argv[0]); exit(1); } authfile = fopen ("auth.dat","r"); if (authfile == (FILE*) NULL) { printf ("** ERROR READING auth.dat, Access Denied\n"); } else { while (fgets(allowed,50,authfile)) { temp = strlen(allowed); allowed[temp-1]=NULL; if(strcmp(allowed,argv[1])==0) { runme[0]=46; runme[1]=47; for ( temp = 1; temp < argc; temp++) { strcat(runme,argv[temp]); strcat(runme, " "); } /*strcat("/usr/sbin/auth/",runme);*/ system(runme); exit(0); } } } printf ("** COMMAND NOT ALLOWED\n"); return 1; }
and this is the source for the first module so far (vacation.pl)
#!/usr/local/bin/perl -w sub on { open(FORWARD, ">/home/$username/.forward") || die ("Unable to open /h +ome/$username/.forward"); #.forward must look like #\username, "|/usr/bin/vacation username" $set_fwd="\\$username, \"|/usr/bin/vacation $username\""; print FORWARD $set_fwd; close(FORWARD); open(VMESSAGE, ">/home/$username/.vacation.msg") || die ("Unable to o +pen /home/$username/.vacation.msg"); print VMESSAGE $message; print VMESSAGE "\n"; close(VMESSAGE); open(VACATIONDIR, ">/home/$username/.vacation.dir") || die ("Unable t +o open /home/$username/.vacation.dir"); close(VACATIONDIR); open(VACATIONPAG, ">/home/$username/.vacation.pag") || die ("Unable t +o open /home/$username/.vacation.pag"); close(VACATIONPAG); `chmod 644 /home/$username/.forward /home/$username/.vacation.msg /ho +me/$username/.vacation.pag /home/$username/.vacation.dir`; `chown $username /home/$username/.forward /home/$username/.vacation.m +sg /home/$username/.vacation.pag /home/$username/.vacation.dir`; } sub off { `rm -f /home/$username/.vacation.msg`; `rm -f /home/$username/.vacation.pag`; `rm -f /home/$username/.vacation.dir`; `rm -f /home/$username/.forward`; } if (($#ARGV > 1) ||(($#ARGV == 1) && ($ARGV[1] eq "off"))) { $username=$ARGV[0]; $on_off=$ARGV[1]; if($on_off eq "on") { $message = join (" ",@ARGV); $message =~ s/$username//; $message =~ s/$on_off//; &on(); print " <div align=\"center\"> $username\'s vacation message has be +en \n"; print " <font color=red>activated</font>.</div><BR>\n"; print " <div align=\"center\">\n"; print " </div>\n"; print " <center><BR>Please E-Mail <a href=\"mailto:$username\@where +iwork.com\">$username\@whereiwork.com</a>\n"; print " to test this message. <BR> If you do not recieve an aut +omatic response with your\n"; print " vacation message please resubmit this form and try agai +n.</center>\n"; } elsif($on_off eq "off") { &off(); print " <div align=\"center\"> $username\'s vacation message has be +en \n"; print " <font color=red>deactivated</font>.</div><BR>\n"; print " <div align=\"center\">\n"; print " </div>\n"; print " <center><BR>Please E-Mail <a href=\"mailto:$username\@where +iwork\">$username\@whereiwork.com</a>\n"; print " to test this message. <BR> If you recieve an automatic +response with your\n"; print " vacation message please resubmit this form and try agai +n.</center>\n"; } } else { print "<b>Not all necessary values have been given.</b>\n"; }
well, i realize how bad this code is, but i would LOVE any ideas or suggestions, provided i have some clue as to what is being said

edited: Thu May 15 20:30:08 2003 by jeffa - readmore tag

Replies are listed 'Best First'.
Re: html->perl->c->perl...... work dang it
by hardburn (Abbot) on May 15, 2003 at 16:20 UTC

    Your global variables ($username, etc.) are being clobbered by the Command() subroutine after being set by the CGI input params. When called as a CGI, @ARGV will be blank. I suggest moving the CGI param fetching into a get_cgi_params() subrotine (or whatever you want to call it). Then check if @ARGV is defined. If it is, call Command(). If not, call get_cgi_params().

    Also, you'll want to check into getting a templating system. HTML::Template is a very popular choice, but hardly the only one.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

      wow, i totally didnt realize i did that thanks
      unfortunatly with the change (commenting out the command sub call) it still shows no signs of running the C program or the secondary script... any ideas beyond that as to why?
      i will post up my adjusted code once i have written the approprate functions per your instructions
      thanks
      this replaced the head of the first perl script... still no luck in the area of getting it to jump throught my C program though.......
      #!/usr/local/bin/perl -wT use strict; use CGI; if ($#ARGV==0) { my $post_data=new CGI; my $username=$post_data->param('username'); my $on_off=$post_data->param('on_off'); my $message=$post_data->param('message'); } else { &Command(); } @junk = ("authorize", "vacation.pl", $username, $on_off, $message); $runme = join (" ",@junk); &Header();

        If an array is empty, ($#ARRAY == 0) is false. $#ARRAY is -1 for an empty array, because $#ARRAY returns the index of the last valid element, not the number of elements in the array. An array with one element has a last element of index zero.

        You can do your check for an empty argument list with any of the following: (not @ARGV), (0 == @ARGV), or ($#ARGV < 0). I prefer the first, but it's a matter of style.

        --
        [ e d @ h a l l e y . c c ]

Re: html->perl->c->perl...... work dang it
by LameNerd (Hermit) on May 15, 2003 at 16:31 UTC
    Always use strict! I always wanted to say that :) And for CGI's use Taint too...
    #!/usr/local/bin/perl -wT use strict; ...
      thanks, have no idea what it does but i have implemented it per your instructions
      what do those things do, as now having implemented them, my program gives out about 15 lines of error messages and then refuses to run.... it gives things like
      Global symbol "$username" requires explicit package name at ./vacation +.pl line 60.
        strict will save your sanity in the long run. It will help you with things like redeclaring variables and such ...
        And for -T look here
        I know these things will seem like a pain at first but hopefully you'll thank me in the end? :)

        When strict rules are in effect, any global symbol must be accounted for. This helps find many typo problems, as well as accidental variable sharing.

        In almost all cases, before the first use of any given variable, declare the variable with a my $foo; or my @blah;.

        --
        [ e d @ h a l l e y . c c ]

Re: html->perl->c->perl...... work dang it
by MrYoya (Monk) on May 15, 2003 at 22:08 UTC
    You can also use a here document to replace all those prints. You just tell it what you want to be printed plus it'll also interpolate variables (e.g. turn $dog_name into "Fido")

    As an example, instead of
    print " <HR>\n"; print " <TABLE border=0 width=100% bgcolor=\"\#005533\">\n"; print " <TR><TD>\n"; print "$username\n";

    you can write

    print <<END; <HR> <TABLE border=0 width=100% bgcolor="#005533"> <TR><TD> $username END
    Instead of END, it can be any word and that word must appear alone to end the here document.