The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Why can't things be easy? Getting the login

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Daniel Berger

Posts: 1383
Nickname: djberg96
Registered: Sep, 2004

Daniel Berger is a Ruby Programmer who also dabbles in C and Perl
Why can't things be easy? Getting the login Posted: Jun 26, 2007 8:35 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Daniel Berger.
Original Post: Why can't things be easy? Getting the login
Feed Title: Testing 1,2,3...
Feed URL: http://djberg96.livejournal.com/data/rss
Feed Description: A blog on Ruby and other stuff.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Daniel Berger
Latest Posts From Testing 1,2,3...

Advertisement
You would think getting the process login would be a simple matter, right? I mean, seriously, just call getlogin() and be done with it.

Oh, if only things were that simple. The first issue is that some platforms, and by "some" I mean Linux, cannot rely on getlogin() because they muck around with the utmp file. I would use cuserid() but once again Linux rears its ugly head. Here's an amusing note from the Linux man page for getlogin():
"Nobody knows precisely what cuserid() does; avoid it in portable programs. Or avoid it altogether: use getpwuid(geteuid()) instead, if that is what you meant. DO NOT USE cuserid()."

Ah, a fine bit of cargo cult programming if there ever was one. How can they not know what what it does? Actually, I think I know the answer to that, but I don't feel like starting a flame war at the moment. Let's move on.

So, what does that leave us? Probably the best solution is to just use getpwuid(getuid()). If that fails, resort to getlogin(). If that fails, Linux be damned and resort to cuserid(). If that fails resort to ENV["LOGNAME"]. If that fails resort to ENV["USER"]. If that fails...you suck.

But, there's a subtle bug with this approach. Or rather, it's possible to get different results depending on how the program is run. Consider this bit of C code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>

int main(){
   uid_t uid, euid;
   char* cuser;
   char* euser;
   char* lognm;
   char* login;
   struct passwd* pwd;
   struct passwd* epwd;

   uid = getuid();
   euid = geteuid();

   cuser = cuserid(NULL);
   login = getlogin();
   pwd   = getpwuid(uid);
   epwd  = getpwuid(euid);
   euser = getenv("USER");
   lognm = getenv("LOGNAME");

   printf("cuserid(): %s\n", cuser);
   printf("getlogin(): %s\n", login);
   printf("getpwuid(uid): %s\n", pwd->pw_name);
   printf("getpwuid(euid): %s\n", epwd->pw_name);
   printf("ENV['USER']: %s\n", euser);
   printf("ENV['LOGNAME']: %s\n", lognm);
   
   return 0;
}

Running this as djberge (me) I get this:
cuserid(): djberge
getlogin(): djberge
getpwuid(uid): djberge
getpwuid(euid): djberge
ENV['USER']: djberge
ENV['LOGNAME']: djberge

But, if I run the same program as sudo, I get this:
cuserid(): djberge
getlogin(): djberge
getpwuid(uid): root
getpwuid(euid): root
ENV['USER']: root
ENV['LOGNAME']: root

Or, if I su to root first then run it, I get this:
cuserid(): djberge
getlogin(): djberge
getpwuid(uid): root
getpwuid(euid): root
ENV['USER']: djberge
ENV['LOGNAME']: djberge

Which means that the only reliable way to get the realy user login, and not the effective user, is to user getlogin() or cuserid(), the two functions that Linux tells you to avoid.

My temptation here is to scrap everything and use only getlogin() or cuserid(), Linux be damned. As far as I can tell, Perl just calls getlogin() and nothing else and I haven't heard any complaints.

The "satisfy everyone" solution is to allow the user to control whether or not to allow the euid to be returned like so:
Admin.get_login(euid=false)

So, if you set +euid+ to true, then the method would internally alter its strategy of getting the login, trying six different ways instead of two. It's more work, but it may be the road I take.

SIGH

Read: Why can't things be easy? Getting the login

Topic: Peel Slowly and See Previous Topic   Next Topic Topic: Scott Guthrie at Symphony Hall

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use