[comp.unix.questions] Problem with getuid

smw@maxwell.concordia.ca ( Steven Winikoff ) (02/03/90)

I've encountered a problem using getuid(), on both a Sun 4/280 under
SunOS 4.0 and a MIPS M-120/5 under MIPS RISC/os 4.0.1 (SVR3 plus BSD
compatibility).  The following short program produces the same results 
on both systems, and replicates the behaviour I've experienced in the 
middle of a much larger application:

#include <stdio.h>
main()
{
   int getuid();
   printf("uid = %d\n", getuid());
}

When I log in as user "smw" (user index = 1000), the program does indeed
return "uid = 1000".

However, when I then execute the su command, I receive "uid = 0" instead
of the expected "uid = 1000".  

Am I missing something?  I thought that this was the expected behaviour
for geteuid() instead of getuid(), and that's why I used getuid() in the
first place!

Can anyone tell me if I'm just confused, or if I'm simply not doing it
right, or if there's actually a bug in the Sun and MIPS implementation 
of these calls?

Thanks very much in advance!

	Regards,

	   - Steven

------------------------------------------------------------------------
Steven Winikoff                                 smw@maxwell.concordia.ca
Software Analyst
Dept. of Computing services
Concordia University                            voice: (514) 848-7619
Montreal, Quebec, Canada                               (10:00-18:00 EST)  

tale@cs.rpi.edu (David C Lawrence) (02/03/90)

In <1836@clyde.concordia.ca> smw@maxwell.concordia.ca ( Steven Winikoff ):
> When I log in as user "smw" (user index = 1000), the program does indeed
> return "uid = 1000".

> However, when I then execute the su command, I receive "uid = 0" instead
> of the expected "uid = 1000".  

> Am I missing something?

Yes.

> I thought that this was the expected behaviour for geteuid() instead
> of getuid(),

No.

> and that's why I used getuid() in the first place!

You could use getlogin(), but be wary of it.  It can fail under a lot
of situations.

@opinionated sidebar
I personally loathe getlogin() and programmes that are concerned with
what userid I might have started out as on some pre-su level, so I
won't describe how to do it.  One thing you might want to reconsider
is why you are concerned with the userid of the login.  When I su to
someone else I want my userid to be that one, not the one that I was.
(On very rare occasion I might want it to be the original, but I can
deal with that in another way.)
@end opinionated sidebar

> Can anyone tell me if I'm just confused, or if I'm simply not doing it
> right, or if there's actually a bug in the Sun and MIPS implementation 
> of these calls?

If there was a bug in it then things would have been upchucking all
over the place and people would be up in arms about it.  geteuid() is
used to get the userid of a setuid executable.  getuid() is meant to
return the userid that invoked the programme.  For non-setuid
executables they will always return the same number.

Dave
-- 
   (setq mail '("tale@cs.rpi.edu" "tale@ai.mit.edu" "tale@rpitsmts.bitnet"))
               "Nice plant.  Looks like a table cloth."

smw@maxwell.Concordia.CA ( Steven Winikoff ) (02/03/90)

In article <?_3}%-@rpi.edu> tale@cs.rpi.edu (David C Lawrence) writes:

>@opinionated sidebar
>I personally loathe getlogin() and programmes that are concerned with
>what userid I might have started out as on some pre-su level, so I
>won't describe how to do it.  One thing you might want to reconsider
>is why you are concerned with the userid of the login.  When I su to
>someone else I want my userid to be that one, not the one that I was.

My problem is that there are several people at our site who are legitimately
able to su root, working on different projects at the same time (perhaps 
that's a bad idea, but it's not under my control).  In any case, the idea
is to find some way to identify our printed output, from within a local
customized print program.  Several hundred (ok, I'm exaggerating!) listings
all marked "root" are, IMHO, less useful than the same listings broken down
by our real user name.

Perhaps I'm going about this by trying to solve the wrong problem, but that's
what I'm looking for.  Thoughts?  Comments?  Ideas?  All would be appreciated.

>If there was a bug in it then things would have been upchucking all
>over the place and people would be up in arms about it.  

That does make sense, I suppose :-)

>geteuid() is
>used to get the userid of a setuid executable.  getuid() is meant to
>return the userid that invoked the programme.  For non-setuid
>executables they will always return the same number.

Thanks for the clarification!

------------------------------------------------------------------------
Steven Winikoff                                 smw@maxwell.concordia.ca
Software Analyst
Dept. of Computing services
Concordia University                            voice: (514) 848-7619
Montreal, Quebec, Canada                               (10:00-18:00 EST)  

maart@cs.vu.nl (Maarten Litmaath) (02/06/90)

In article <1837@clyde.concordia.ca>,
	smw@maxwell.Concordia.CA ( Steven Winikoff ) writes:
\In article <?_3}%-@rpi.edu> tale@cs.rpi.edu (David C Lawrence) writes:
\
\>@opinionated sidebar
\>I personally loathe getlogin() and programmes that are concerned with
\>what userid I might have started out as on some pre-su level, [...]
\...
\My problem is that there are several people at our site who are legitimately
\able to su root, working on different projects at the same time (perhaps 
\that's a bad idea, but it's not under my control).  In any case, the idea
\is to find some way to identify our printed output, [...]

But that's precisely what UCB's lpr does!  By means of getlogin()! :-(
Anyway, you could always replace lpr by something like this:

	#include	<pwd.h>
	#include	<stdio.h>

	char	My_lpr[] = "/path/of/my_lpr";

	main(argc, argv)
	int	argc;
	char	**argv;
	{
		char	*getenv(), *lprname = getenv("LPRNAME");
		struct	passwd	*pw;

		if (lprname) {
			if (!(pw = getpwnam(lprname)))
				fprintf(stderr,
					"You don't exist.  Go away.\n");
			else if (setuid(pw->pw_uid) != 0)
				perror("setuid");
		}
		argv[0] = My_lpr;
		execv(My_lpr, argv);
		perror(My_lpr);
		exit(1);
	}

...where `my_lpr' is:

	#!/bin/sh 

	exec 3>&1

	test -t 0 && exec < /dev/null

	(/usr/ucb/lpr ${1+"$@"} | cat >&3) 2>&1 | cat >&2
--
  The meek get the earth, Henry the moon, the rest of us have other plans.  |
  Maarten Litmaath @ VU Amsterdam:  maart@cs.vu.nl,  uunet!mcsun!botter!maart

smw@maxwell.Concordia.CA ( Steven Winikoff ) (02/08/90)

First, my apologies if this gets posted twice.  The first one apparently
vanished into the bit bucket.

In article <5315@star.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>In article <1837@clyde.concordia.ca>,
>	smw@maxwell.Concordia.CA ( Steven Winikoff ) writes:
>\My problem is that there are several people at our site who are legitimately
>\able to su root, working on different projects at the same time (perhaps 
>\that's a bad idea, but it's not under my control).  In any case, the idea
>\is to find some way to identify our printed output, [...]
>
>But that's precisely what UCB's lpr does!  By means of getlogin()! :-(

True.  But if I could use lpr in the first place, none of this would have
arisen... :-)     Fact is that the printer I'm trying to reach is connected
to a CDC Cyber under NOS (CDC's proprietary OS, for those unfamiliar with
Control Data).  The Cyber is connected to a VMS VAX 8550 via JNET, and my Unix
system is connected to the VAX via a MicroVAX running Ultrix!  Are you now as
confused as I am?  If not, all you have to do is reread the above paragraph a
couple of dozen times, and then your head will be spinning just like mine! :-)

No, there's no way I can get a printer closer than that.  :-(

And no, there's no way (at least none that our Powers That Be will agree to
finance!) to bridge the gap between Unix and the Cyber directly.  :-(

So I'm stuck with writing an application that wants to send a file to the VAX
via ftp, along with instructions re what to do with it when it gets there.
A client process on the VAX takes the file and automagically routes it over
the JNET link.  (The VAX/Cyber link is maintained by our local VMS guru.  My
personal VMS knowledge ranges between poor and non-existent.)

That's why I need some reliable way of determining who *really* sent a given
file, simply because I'd like to be able to recognize my own output when I
get it!

When I began all this, I naively thought that getuid would do it for me.
Now I know that it won't.  Based on the suggestions of all the kind people
who have so far responded to me, it seems that the best I can do in the case
where getuid returns 0 is a tiered approach which begins with getlogin and
falls back on logname (== value of $USER) when getlogin fails.

>Anyway, you could always replace lpr by something like this:
>
>	#include	<pwd.h>
>	#include	<stdio.h>
>
>	char	My_lpr[] = "/path/of/my_lpr";
>
>	main(argc, argv)
>	int	argc;
>	char	**argv;
>	{
>		char	*getenv(), *lprname = getenv("LPRNAME");
>		struct	passwd	*pw;
>
>		if (lprname) {
>			if (!(pw = getpwnam(lprname)))
>				fprintf(stderr,
>					"You don't exist.  Go away.\n");
>			else if (setuid(pw->pw_uid) != 0)
>				perror("setuid");
>		}
>		argv[0] = My_lpr;
>		execv(My_lpr, argv);
>		perror(My_lpr);
>		exit(1);
>	}
>
>...where `my_lpr' is:
>
>	#!/bin/sh 
>
>	exec 3>&1
>
>	test -t 0 && exec < /dev/null
>
>	(/usr/ucb/lpr ${1+"$@"} | cat >&3) 2>&1 | cat >&2

I'm not quite sure I understand your code.  Who sets LPRNAME?  In "my_lpr",
what gets exec'd in line 2?  Please excuse my ignorance, I'm only a wizard
wanna-be!

>--
>  The meek get the earth, Henry the moon, the rest of us have other plans.  |
>  Maarten Litmaath @ VU Amsterdam:  maart@cs.vu.nl,  uunet!mcsun!botter!maart

Love your .sig!

------------------------------------------------------------------------
Steven Winikoff                                 smw@maxwell.concordia.ca
Software Analyst
Concordia University Computer Centre            voice: (514) 848-7619
Montreal, Quebec, Canada                               (10:00-18:00 EST)  

maart@cs.vu.nl (Maarten Litmaath) (02/08/90)

In article <1844@clyde.concordia.ca>,
	smw@maxwell.Concordia.CA ( Steven Winikoff ) writes:
\...
\>		char	*getenv(), *lprname = getenv("LPRNAME");
\...
\>...where `my_lpr' is:
\>
\>	#!/bin/sh 
\>
\>	exec 3>&1

Dup(2) file descriptor 3 from 1.

\>	test -t 0 && exec < /dev/null

If stdin is a terminal, connect stdin to /dev/null.

\>	(/usr/ucb/lpr ${1+"$@"} | cat >&3) 2>&1 | cat >&2

Feed lpr's stdout to the first cat, whose stdout is dupped to the original
(saved) stdout; feed lpr's stderr to the second cat (mjum), whose droppings
go to the original stderr.  Now none of lpr's stdin/stdout/stderr points to
a terminal, so lpr will use getpwuid(getuid()), as getlogin() fails.
Piece of cake, right?

\I'm not quite sure I understand your code.  Who sets LPRNAME?  In "my_lpr",
\what gets exec'd in line 2?  Please excuse my ignorance, I'm only a wizard
\wanna-be!

Each user himself should set LPRNAME (.profile/.login) and change it
accordingly after a su (it's easy to write a wrapper for su which sets
LPRNAME beforehand).
You could use USER or LOGNAME, but beware: there are programs which expect
those to contain *login names* (e.g. inews). :-(

\...
\Love your .sig!

Thanks.
--
  The meek get the earth, Henry the moon, the rest of us have other plans.  |
  Maarten Litmaath @ VU Amsterdam:  maart@cs.vu.nl,  uunet!mcsun!botter!maart

les@chinet.chi.il.us (Leslie Mikesell) (02/09/90)

In article <1837@clyde.concordia.ca> smw@maxwell.Concordia.CA ( Steven Winikoff ) writes:

>My problem is that there are several people at our site who are legitimately
>able to su root, working on different projects at the same time (perhaps 
>that's a bad idea, but it's not under my control).  In any case, the idea
>is to find some way to identify our printed output, from within a local
>customized print program.

Since it's not really a security issue, why don't you just use the
environment variable LOGNAME?  If it's good enough for SysV mail to
identify the sender perhaps it will work for you as well.  You might
want to designate another variable to be checked first so you can
type something like:
PRID=some_else lp file
when you want a print job delivered to some else.

Les Mikesell
  les@chinet.chi.il.us