[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: ITS#98 'user' patch for BSD systems

 > Of course, we could just say "Don't do that".  Or "If you specify
> > a uid number with no groups, we'll use getpwuid() to get the user
> > name.  This may cause unexpected, and possibly even non-deterministic
> > results if there is more than one passwd entry with that uid."
> Until I read this, I always thought multiple users with the same uid
> meant a misconfigured system...
> Can't we just mimic what the documentation of commands like 'ps' or 'ls'
> say about aliased users on your host?  They too translate uids to names.

Hmmm.  I just did a quick scan of the man pages for ps and ls, and
didn't see anything appropriate.  But it did highlight another reason
that we can't depend on uid->name translation.  There may not be a
passwd entry for that uid.

I'll admit that multiple usernames with one uid (and different group
sets), and valid uids with no associated passwd entry are probably
rare pathological cases.  I was taking the paranoid cover-all-bases
approach; but I'm not particularly married to it.  (After all, if
someone does have either of those situations, they can ensure the
right result by either specifying the user by name or by listing
the group(s) on the user command.)

> > It turns out that initgroups(3) didn't seem to do quite what we want.
> > (Since it is based on the current uid, we'd have to change the uid
> > first.  And then we might not have all of the right permissions...)
> Not here.  initgroups() on Solaris and Alpha is
>      int initgroups(const char *name, gid_t basegid);
> It sets the supplementary group access list to that users' groups.
> As you pointed out, it's getgroups() which is based on the current uid.

Oops, you're right.  I wrote that in haste.  Initgroups(3) does appear
to do the right thing if you have a username and the base group from
the passwd entry.

> So I don't see why you need getgrouplist() when you have initgroups();
> I think this should work, plus error checking --
> vars:
>     ...

That looks reasonable.  You might be able to simplify a little by
leaving ngids==0 for the initgroups case and making that final part:

    if ( run_uid != 0 ) {
        if ( ngids > 0 )
            setgroups( ngids, run_gids);
            initgroups( run_username, run_gids[0] );
        setgid( run_gids[0] );
        setegid( run_gids[0] );

        setuid( run_uid );
        seteuid( run_uid );

But your version is better if we assume the possible addition of
separate -u and -g command-line options; and we allow -g to be
specified without -u.  Separate options seems likely since that
provides the easiest way of parsing multiple groups.

If command-line options are added, specifying a user on the command
line should probably override the entire user config command (and
possibly bypass parsing its values.)  Otherwise, there is no convienient
way to request initgroups() processing for the command-line-specified
user.  But if a group (or set of groups) is specified on the command
line, the user should still be taken from the user config command.

> > (It is only by a herculean effort of will that I'm avoiding starting a
> > rant about isdigit(), et. al., not being able to handle whatever char
> > type is native to that compiler.
> That's unfixable on hosts where char is signed and EOF == -1, since
> isXXX() are specified to recognize EOF.

I'm not sure I quite follow.  If EOF is a valid value for the char
type, then the isXXX() routines should be able to handle the full
range of the char type and still recognize EOF.  And if EOF isn't
a valid value for the char type, then you have other type mismatch
problems to worry about.

>                                          I'm sure it was nice to be able
> to feed the output of getchar() directly to isXXX(), and nobody had
> heard about 8-bit character sets...

I started programming in 1972, and I've -never- understood the reasons
for the 7-bit char myopia.  And it -still- doesn't explain why C didn't
define whether char was signed or not.  (Of course, part of the problem
is that C really should have had separate char and int8 types from the

> > Or the extreme brain damage that defined 'char' without specifying
> > whether it was to be treated as a signed value or not.)
> Nah.  C was designed so signedness and sizes could be chosen as whatever
> was most efficient on the architecture it was running on.  The brain
> damage is that we are _still_ using C (and C++) as The Language Which
> Everything Supports.  It should have been possible to demote it to be a
> kind of "super-assember" by now.

I agree that still using C (and C++) is severe brain damage; but I
stand by my position that the signedness/size flexability of the C
language was a bit of severe wrong-headedness.  They would have been
doing much better to have defined type names for each size/sign
combinations and then allowed a typedef for convienient native sizes.

Of course, part of the problem was attempting to use the same type
for both 8-bit integers and characters.  There really should have
been a separate 'int8' type (and 'unsigned int8') so that char could
be considered a non-arithmetic ordered 8-bit value.

But all of that pales in relation to the mistake of pointer/array