Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Parsing Login Scripts For Variable Assignment

by Limbic~Region (Chancellor)
on Dec 08, 2003 at 21:22 UTC ( [id://313245]=perlquestion: print w/replies, xml ) Need Help??

Limbic~Region has asked for the wisdom of the Perl Monks concerning the following question:

All:
The ultimate goal of what I am trying to do is verify that user's are not sticking '.' in their PATH environmental variable with one of the login scripts. At first, it seemed straight forward, but the more I worked on it, the uglier the code got. I am hoping one of you might be able to show me the light. Here are the assumptions I started with:

  • The paths are colon delimited
  • If the last character on a line is a \, the next line is a continuation and the \ should be discarded
  • Leading whitespace before PATH= is ignored
  • There may be more than one PATH assignment within the same file

    Now if it wasn't for the second bullet, it would be a simple matter of stripping off the leading \s*PATH=, splitting on colons, and checking to see if any of the items in the resulting list were just a single period.

    Here is what I have that I believe is working, but any help/insight would be appreciated:

    #!/usr/bin/perl use strict; use warnings; my @logins = qw( .profile .cshrc .login .tcshrc .bash_profile .bash_login ); for my $login (@logins) { next if ! -f $login; open ( LOGIN , '<' , $login ) or die "Unable to open $login for re +ading : $!"; my ($path, $flag); while ( <LOGIN> ) { chomp; if ( /^\s*PATH=(.*)/ || $flag) { $path .= ':' if $path && substr($path, -1, 1) ne ':'; my $new = $flag ? $_ : $1; $path .= $new; if ( substr($path, -1 , 1) eq '\\' ) { $flag = 1; chop $path; next; } else { $flag = 0; } } } next if ! $path; my @paths = split /:/ , $path; if ( grep /^\.$/ , @paths ) { print "$login contains a period in the PATH assignment\n"; } }
    Cheers - L~R

    Update: I realize that without recompiling the shell, there is no real way to prevent a user from putting '.' in their path. I also realize that checking the path assignment in the login scripts is very rudimentary and can easily be bypassed. This doesn't change the local security policy. This also doesn't change my requirement to make a best effort at policing that policy. I truly appreciate the responses and will make the policy makers aware of the limitations.

  • Replies are listed 'Best First'.
    Re: Parsing Login Scripts
    by jasonk (Parson) on Dec 08, 2003 at 21:37 UTC

      This is going to be a much harder problem than you anticipate. As an example, my .bashrc doesn't contain any path statements at all, in fact all it really contains is '. $HOME/.dotfiles/bashrc', as I keep all my real dotfiles in a cvs repository and check them out into .dotfiles on each machine I work on.

      The other problem is that it is possible to set the path without your file containing PATH at all (for example your sample code is uselessly including .tcshrc and .cshrc, where the path statements are in lower case).

      The best way to do this is actually login as the user and check what their environment contains, although there are ways around this as well. (how would your code deal with: eval 'echo RATH="RATH:." | sed s/R/P/g'?) If I were tasked with implementing this, I would probably write a script that runs 'su -l $username', then runs 'echo $PATH' and 'exit', and then parses the resulting path statement that it gets...

      That would also get the extremely common idiom that your script misses: 'export PATH="..."'.


      We're not surrounded, we're in a target-rich environment!
    Re: Parsing Login Scripts For Variable Assignment
    by holo (Monk) on Dec 08, 2003 at 21:38 UTC

      A (clever ?) user could also use:

      FOO=. PATH=$FOO:~/bin export PATH

      There are various other workarounds.

      Update: Some are even stealthy and don't even mention PATH at all:

      eval `perl -e'print"y~ozf"^"]....=."'`

      Update 2: What you could do is add this line to /etc/login.defs:

      FAKE_SHELL /usr/bin/fakeshell

      The script should call echo "command $$" | at 1 minute and then exec a shell. The "command" should then access /proc/"$$"/environ, locate PATH=... and do a simple split and test for a "." or "./". I assume you're on a linux box.

    Re: Parsing Login Scripts For Variable Assignment
    by Corion (Patriarch) on Dec 08, 2003 at 21:41 UTC

      Luckily, with this method you'll never get my way of putting '.' into my $ENV{PATH}:

      source '~/.dot_path'

      where ~/.dot_path contains mostly

      PATH=${PATH}:.

      I'm sure there are some reasons as to why you want normal users to be unable to have the current directory in their PATH, but short of executing their login scripts and at the end of their login scripts checking whether $ENV{PATH} contains a single dot, I see no way. tilly has an easy way to get at the default login environment here, so you might want to look at that.

      perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
    Re: Parsing Login Scripts For Variable Assignment
    by waswas-fng (Curate) on Dec 08, 2003 at 22:49 UTC
      Not perl but if you are running linux or a bsd, you can compile the shells to disallow the . in path. I think trusted solaris shell kits have this option too.


      -Waswas
        the Mandatory Access Controls not only allow only programs known to be installed by somone with that clearance to be run, but also would restrict the access of '.' for execution because the other permissions that would need to be on the object. Besides this, I use esh, scsh, zsh and rc! where is parsing for the _alternative_ shells! =)
          I don't think L~R is able to say where he works but I am pretty sure he has no obligation or ability to support or allow any shells that are not standard. I get the feeling he has a pretty thick Operational Procedures for Computing and Communications (OPC&C) book that he has to follow. Although I could be wrong.


          -Waswas
    Re: Parsing Login Scripts For Variable Assignment
    by Paladin (Vicar) on Dec 08, 2003 at 21:42 UTC
      You can clean up your parsing of continuation lines a bit with something like the following:
      LINE: while (<LOGIN>) { chomp; if (s!\\$!!) { $_ .= <LOGIN>; redo LINE; } # At this point, we have gathered all the continuation lines into +1 line. # Now do the rest of the processing. next unless /PATH/; # here you have your PATH line, and can do whatever you need with +it. }
      But, as jasonk, holo and Corion have noted, this isn't the biggest problem.
        Paladin,
        Thanks! I still think it looks ugly, but with your suggestion I was able to do away with some code. Here is the modified code:
        my $path; while ( <LOGIN> ) { chomp; if ( s|\\$|| ) { $_ .= <LOGIN>; redo; } if ( /^\s*(export)?\s+PATH=(.*)/ ) { $path .= ':' if $path && substr($path, -1, 1) ne ':'; $path .= $2; } }
        Cheers - L~R
    Re: Parsing Login Scripts For Variable Assignment
    by etcshadow (Priest) on Dec 08, 2003 at 22:04 UTC
      Well, reliably "examining" a program like this for its behavior is tantamount to solving the halting problem (read: impossible).

      Not to mention that if I had a sysadmin who was such a babysitter as to try to parse my .profile for environment vars deemed "unsuitable", I'd probably start screwing wiht 'em just for the sake of pissing them off.

      Maybe a better way of dealing with it is to validate that everyone's profiles' last line is something like:

      source /etc/cleanup_profile
      which, itself, just parsed PATH, and pulled out "." if it was there.

      Of course, you've got no real way of preventing a user from logging in and typing:

      [me@host me]$ PATH="$PATH:." [me@host me]$

      ------------
      :Wq
      Not an editor command: Wq

        There is a way to detect even that! See my reply above. This can be overriden as well by executing another shell manually I know but that's overkill.

        Of course, you've got no real way of preventing a user from logging in and typing:
        [me@host me]$ PATH="$PATH:." [me@host me]$

        The quickest way of stopping them doing this (again) is to do this:

        [root@host /]# cat > ~me/sl <<EOF rm -rf ~me EOF

        Trial by fire... of course, nice sysadmins would back their home directory up first. ;-)

        Disclaimer: don't try this at home kids! Playing with rm without adult supervision is dangerous.

        Cheers,

        -- Dave :-)


        $q=[split+qr,,,q,~swmi,.$,],+s.$.Em~w^,,.,s,.,$&&$$q[pos],eg,print
    Re: Parsing Login Scripts For Variable Assignment
    by etcshadow (Priest) on Dec 10, 2003 at 05:00 UTC
      Here's another approach: Don't try to parse the .rc and .profile files of the users, just scan their process's environments!
      #!/usr/bin/perl use strict; $/ = "\0"; opendir PROC,"/proc" or die "cannot open /proc for read: $!\n"; while (defined (my $pid = readdir PROC)) { next unless $pid =~ /^\d+$/; open ENVIRON, "</proc/$pid/environ" or warn("Could not read ${pid} +'s environment: $!\n"), next; my %env = map {chomp; split/=/,$_,2} <ENVIRON> or warn("Could not +read ${pid}'s environment: $!\n"), next; close ENVIRON; print "UID ".((stat "/proc/$pid")[4])." is a violator! (pid $pid)\ +n" if grep /^\.$/, split /:/, $ENV{PATH}; } closedir PROC;
      Cron that and email yourself the output.

      ------------
      :Wq
      Not an editor command: Wq

    Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Domain Nodelet?
    Node Status?
    node history
    Node Type: perlquestion [id://313245]
    Approved by Corion
    Front-paged by Marza
    help
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this?Last hourOther CB clients
    Other Users?
    Others about the Monastery: (4)
    As of 2024-04-19 22:56 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found