develooper Front page | perl.perl5.porters | Postings from March 2000

WHOA THERE! Somebody went and broke all the getpw functions!

Thread Next
From:
Tom Christiansen
Date:
March 18, 2000 06:47
Subject:
WHOA THERE! Somebody went and broke all the getpw functions!
Message ID:
23330.953390850@chthon
% grep '\$dir,\$shell' perl3.0/perl.man.?
perl.man.2: $quota,$comment,$gcos,$dir,$shell) = getpw.\|.\|.
% grep '\$dir,\$shell' perl4.036/man1/perl.1
           $quota,$comment,$gcos,$dir,$shell) = getpw.\|.\|.
% grep '\$dir,\$shell' perl5.001m/pod/perlfunc.pod
       $quota,$comment,$gcos,$dir,$shell) = getpw*
% grep '\$dir,\$shell' perl5.002/pod/perlfunc.pod
       $quota,$comment,$gcos,$dir,$shell) = getpw*
% grep '\$dir,\$shell' perl5.003/pod/perlfunc.pod
       $quota,$comment,$gcos,$dir,$shell) = getpw*
% grep '\$dir,\$shell' perl5.004/pod/perlfunc.pod
       $quota,$comment,$gcos,$dir,$shell) = getpw*
% grep '\$dir,\$shell' perl5.005/pod/perlfunc.pod
       $quota,$comment,$gcos,$dir,$shell,$expire) = getpw*
% grep '\$dir,\$shell' perl5.006/pod/perlfunc.pod
       $quota,$comment,$gcos,$dir,$shell,$expire) = getpw*

*NOW* I know why my sysadmin scripts have been mysteriously crapping
out.  You went and changed the last return value from getpw*()!
Hello?  Hello?  This code has worked for a *long* time:

    @pwent = getpwnam($whoever);
    $shell = pop(@pwent) || '/bin/sh';

So has this, although not for *quite* so long

    $shell = (getpwnam($whoever))[-1] || '/bin/sh';

Well, now it doesn't; it reports that all users on my system now
have a shell of '/bin/sh'.   Why?  I have pw_expire but I don't use
it, so my "expires" field is 0.

That perl3/perl.man.2 file is dated October 29th, 1989.  That's a
very, ver, very long long-standing behavior to just go breaking
like this.  I can't understand how this isn't a bug.   Yes, I
understand what you're trying to do, but I don't think you did the
right thing, because you broke old code.  And you didn't even tell
us about it!  It's not in the v5.4 perldelta page at all.

    #ifndef INCOMPLETE_TAINTS
	    /* pw_gecos is tainted because user himself can diddle with it. */
	    SvTAINTED_on(sv);
    #endif

	    PUSHs(sv = sv_mortalcopy(&PL_sv_no));
	    sv_setpv(sv, pwent->pw_dir);

	    PUSHs(sv = sv_mortalcopy(&PL_sv_no));
	    sv_setpv(sv, pwent->pw_shell);

    #ifdef PWEXPIRE
	    PUSHs(sv = sv_mortalcopy(&PL_sv_no));
	    sv_setiv(sv, (IV)pwent->pw_expire);
    #endif
	}

Lovely.  Just lovely.  Now, *how* many values do getpw*() return
in list context?  Answer: you don't know anymore!   Sometimes it's
there, sometimes it's not.  That means you cannot know (without
delightful probing %Config) what type of value the [-1] entry even
*contains*.  

(Notice also how pw_expire isn't in User::pwent.  Guess why?)

I don't have an excellent solution to this, but I do not one bit
like what's happened to a sysadmin-critical function used in mission
critical admin and security scripts run by the superuser.  I even
less care for the fact that nobody deigned to document this gratuitous
breakage in the appripriate impacts document (read: the proper
release's perldelta page).

So, just what are we now supposed to do about this?  

--tom

    PS: And pw_shell should be tainted!

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About