[Pkg-shadow-devel] A historical curiosity in su(1)

Chris Sinjakli chris at sinjakli.co.uk
Tue Mar 21 22:52:09 UTC 2017


Hi folks,

I'm doing some digging for a talk I'm working on for PGConf US[1].

The talk is one I've given before[2], and last time I gave it I left an open
question right near the end. This time, I'd love to be able to answer it!

The open question revolves around the way su(1) determines the user it is being
invoked by. Specifically, it does this using a combination of the result of
getuid and getlogin[3][4].

If calling getpwnam on the result of getlogin returns a passwd struct, and the
uid in that struct matches the uid returned by getuid, it returns that passwd
struct.

If the getpwnam approach fails for either reason, it falls back to using the
result of getpwuid on the result of getuid.

The thing I'm curious about is why it goes to the trouble of trying to use the
result of getpwnam/getlogin at all. The only time it will return something
different from getpwuid/getuid is if there are two users with the same uid but
different information in the rest of their passwd entry.

Are there cases where you might want to set up a system this way? I've always
avoided assigning the same uid to multiple users - it seems like a bad idea!

Jumping back to the point I made in the talk, the result of getlogin can often
be surprising. For example, a daemon restarted by a supervisor (e.g. upstart)
will be associated with the user that issued the restart (i.e. getlogin would
return "chris" if I restarted it, rather than something like "daemon-user"). Any
daemon that calls su will run into this behaviour.

If, as we do at my current employer, you store your human users in LDAP and your
system users locally, that means a network round-trip every time su is called,
just because a human happened to restart a daemon!

For what it's worth, this isn't new behaviour. You can find extremely similar
code in FreeBSD's su implementation, and it's been there since at least 1994[5],
with something similar existing in the current code[6].

It seems likely to me that all of this behaviour needs to be preserved because
somewhere out there, something will depend on it in a strange way. That said, if
someone knows why it behaves like this, I'd be really interested to know, and to
share the answer as part of my talk!

Many thanks for reading this, and entertaining a historical itch.

Chris


[1]: http://www.pgconf.us/conferences/2017

[2]: https://www.youtube.com/watch?v=Tu-cf-Jki60

[3]:
https://github.com/shadow-maint/shadow/blob/db57db52cfd99069c33604eb4a0fee56eb659133/src/su.c#L731

[4]:
https://github.com/shadow-maint/shadow/blob/db57db52cfd99069c33604eb4a0fee56eb659133/libmisc/myname.c#L44

[5]:
https://github.com/freebsd/freebsd/blob/f9ab90d9d6d02989a075d0f0074496d5b1045e4b/usr.bin/su/su.c#L125

[6]:
https://github.com/freebsd/freebsd/blob/d8179bc9ec98d230e00546e4afa2a244e2f123ed/usr.bin/su/su.c#L255



More information about the Pkg-shadow-devel mailing list