Re: trying to learn systems programming, fear I have not understood and thus messed up

2011-10-22 Thread Christopher J. Ruwe
On Fri, 21 Oct 2011 18:53:33 +0200
Christopher J. Ruwe c...@cruwe.de wrote:

 [...]
 
 I have tried to follow the suggestion from the comment by modifiying
 the else-statement thus:
 
 } else {
   struct passwd *trgpwd;
   if (!(trgpwd = GETPWNAM(arg-val)))
  errx(EX_DATAERR, User %s does not exist, arg-val);

if (strcmp(a_name-val,root) == 0)
   errx(EX_DATAERR, can't change uid of `root' account);
if (strcmp(trgpwd-pw_name, root) == 0)
   warnx(WARNING: account `%s' will have a uid of 0 (superuser
 access!), pwd-pw_name);
 
pwd-pw_uid = (uid_t) (trgpwd-pw_uid);
edited = 1;
 } 
 
 What happens is not what I intended. I invoke as sudo ./pw usermod
 testuser1 -u testuser2. I can get testuser2's pwd-entry by GETPWNAM
 allright, but when I assign the pw_uid, so as to make testuser2's uid
 the same as testuser1's and imgaining to retain all other values, ./pw
 reports pw: user 'testuser2' disappeared during update and the
 testuser2's /etc/passwd entry is replaced by testuser1's.
 
 I fear I have not understood GETPWNAM correctly, as it seems to
 replace the struct pwd as some sort of sideeffect. I could manually
 set all pwd-members to the correct ones (those of testuser2), but I
 fear that I have messed something up beforehand.
 
 I am grateful for any suggestions and/or correction. 

It seems I have indeed not understood GETPWNAM correctly. I have worked
out a method which works by calling GETPWNAM twice:

   else {
   /*
* operation as follows:
* a_name-val is passed as usermod uname
* arg-val is passed as -u uname
*
* first check if we do someting stupid, i.e., want
* to set root uid to some other users uid or
* to set some user accout's uid to root uid.
* then get pwd to that of uname passed as -u uname.
* store uid from that pwdent.
* get pwd to that of uname passed as usermod uname
* change uid of that latter uid to the one stored
*/

if(strcmp(a_name-val,root) == 0)
  errx(EX_DATAERR, can't change uid of `root' account);

if(strcmp(arg-val, root) == 0)
  warnx(WARNING: account `%s' will have a uid of 0 (superuser
access!), pwd-pw_name);

if(!(pwd = GETPWNAM(arg-val))) /* -u uname*/
  errx(EX_DATAERR, User %s does not exist, arg-val);
int alias_uid = pwd-pw_uid; 

if(!(pwd = GETPWNAM(a_name-val))) /*usermod uname*/
  errx(EX_DATAERR, User %s does not exist, a_name-val);

pwd-pw_uid = (uid_t) alias_uid;
warnx(User %s's uid changed to %d, pwd-pw_name, pwd-pw_uid);
edited = 1;
  }

As I stil do not know why the latter variant of my code worked and the
former does not, I would still appreciate any comment or explanation which 
would help me understanding GETPWNAM and getpwnam.

Thanks and cheers,
-- 
Christopher J. Ruwe
TZ GMT + 2



signature.asc
Description: PGP signature


Re: trying to learn systems programming, fear I have not understood and thus messed up

2011-10-22 Thread Fabian Keil
Christopher J. Ruwe c...@cruwe.de wrote:

 On Fri, 21 Oct 2011 18:53:33 +0200
 Christopher J. Ruwe c...@cruwe.de wrote:
 
  [...]
  
  I have tried to follow the suggestion from the comment by modifiying
  the else-statement thus:
  
  } else {
struct passwd *trgpwd;
if (!(trgpwd = GETPWNAM(arg-val)))
   errx(EX_DATAERR, User %s does not exist, arg-val);
 
 if (strcmp(a_name-val,root) == 0)
errx(EX_DATAERR, can't change uid of `root' account);
 if (strcmp(trgpwd-pw_name, root) == 0)
warnx(WARNING: account `%s' will have a uid of 0 (superuser
  access!), pwd-pw_name);
  
 pwd-pw_uid = (uid_t) (trgpwd-pw_uid);  
 edited = 1;
  } 
  
  What happens is not what I intended. I invoke as sudo ./pw usermod
  testuser1 -u testuser2. I can get testuser2's pwd-entry by GETPWNAM
  allright, but when I assign the pw_uid, so as to make testuser2's uid
  the same as testuser1's and imgaining to retain all other values, ./pw
  reports pw: user 'testuser2' disappeared during update and the
  testuser2's /etc/passwd entry is replaced by testuser1's.
  
  I fear I have not understood GETPWNAM correctly, as it seems to
  replace the struct pwd as some sort of sideeffect. I could manually
  set all pwd-members to the correct ones (those of testuser2), but I
  fear that I have messed something up beforehand.
  
  I am grateful for any suggestions and/or correction. 
 
 It seems I have indeed not understood GETPWNAM correctly. I have worked
 out a method which works by calling GETPWNAM twice:
 
else {
/*
 * operation as follows:
 * a_name-val is passed as usermod uname
 * arg-val is passed as -u uname
 *
 * first check if we do someting stupid, i.e., want
 * to set root uid to some other users uid or
 * to set some user accout's uid to root uid.
 * then get pwd to that of uname passed as -u uname.
 * store uid from that pwdent.
 * get pwd to that of uname passed as usermod uname
 * change uid of that latter uid to the one stored
 */
   
 if(strcmp(a_name-val,root) == 0)
   errx(EX_DATAERR, can't change uid of `root' account);
 
 if(strcmp(arg-val, root) == 0)
   warnx(WARNING: account `%s' will have a uid of 0 (superuser
 access!), pwd-pw_name);
 
 if(!(pwd = GETPWNAM(arg-val))) /* -u uname*/
   errx(EX_DATAERR, User %s does not exist, arg-val);
 int alias_uid = pwd-pw_uid; 
 
 if(!(pwd = GETPWNAM(a_name-val))) /*usermod uname*/
   errx(EX_DATAERR, User %s does not exist, a_name-val);
 
 pwd-pw_uid = (uid_t) alias_uid;
 warnx(User %s's uid changed to %d, pwd-pw_name, pwd-pw_uid);
 edited = 1;
   }
 
 As I stil do not know why the latter variant of my code worked and the
 former does not, I would still appreciate any comment or explanation
 which would help me understanding GETPWNAM and getpwnam.

I'm not familiar with the code you're working with,
but according to the man page getpwnam() isn't thread
safe so you probably shouldn't mess with the returned
pointer in the first place and only treat the one
returned by the last call as valid.

Did you try using getpwnam_r() instead?

Fabian


signature.asc
Description: PGP signature


Re: trying to learn systems programming, fear I have not understood and thus messed up

2011-10-22 Thread Christopher J. Ruwe
On Sat, 22 Oct 2011 16:45:08 +0200
Fabian Keil freebsd-lis...@fabiankeil.de wrote:

 Christopher J. Ruwe c...@cruwe.de wrote:
 
  On Fri, 21 Oct 2011 18:53:33 +0200
  Christopher J. Ruwe c...@cruwe.de wrote:
  
   [...]
   
   I have tried to follow the suggestion from the comment by
   modifiying the else-statement thus:
   
   } else {
 struct passwd *trgpwd;
 if (!(trgpwd = GETPWNAM(arg-val)))
errx(EX_DATAERR, User %s does not exist, arg-val);
  
  if (strcmp(a_name-val,root) == 0)
 errx(EX_DATAERR, can't change uid of `root' account);
  if (strcmp(trgpwd-pw_name, root) == 0)
 warnx(WARNING: account `%s' will have a uid of 0 (superuser
   access!), pwd-pw_name);
   
  pwd-pw_uid = (uid_t) (trgpwd-pw_uid);
  edited = 1;
   } 
   
   What happens is not what I intended. I invoke as sudo ./pw
   usermod testuser1 -u testuser2. I can get testuser2's pwd-entry
   by GETPWNAM allright, but when I assign the pw_uid, so as to make
   testuser2's uid the same as testuser1's and imgaining to retain
   all other values, ./pw reports pw: user 'testuser2' disappeared
   during update and the testuser2's /etc/passwd entry is replaced
   by testuser1's.
   
   I fear I have not understood GETPWNAM correctly, as it seems to
   replace the struct pwd as some sort of sideeffect. I could
   manually set all pwd-members to the correct ones (those of
   testuser2), but I fear that I have messed something up beforehand.
   
   I am grateful for any suggestions and/or correction. 
  
  It seems I have indeed not understood GETPWNAM correctly. I have
  worked out a method which works by calling GETPWNAM twice:
  
 else {
 /*
  * operation as follows:
  * a_name-val is passed as usermod uname
  * arg-val is passed as -u uname
  *
  * first check if we do someting stupid, i.e., want
  * to set root uid to some other users uid or
  * to set some user accout's uid to root uid.
  * then get pwd to that of uname passed as -u uname.
  * store uid from that pwdent.
  * get pwd to that of uname passed as usermod uname
  * change uid of that latter uid to the one stored
  */
  
  if(strcmp(a_name-val,root) == 0)
errx(EX_DATAERR, can't change uid of `root' account);
  
  if(strcmp(arg-val, root) == 0)
warnx(WARNING: account `%s' will have a uid of 0 (superuser
  access!), pwd-pw_name);
  
  if(!(pwd = GETPWNAM(arg-val))) /* -u uname*/
errx(EX_DATAERR, User %s does not exist, arg-val);
  int alias_uid = pwd-pw_uid; 
  
  if(!(pwd = GETPWNAM(a_name-val))) /*usermod uname*/
errx(EX_DATAERR, User %s does not exist, a_name-val);
  
  pwd-pw_uid = (uid_t) alias_uid;
  warnx(User %s's uid changed to %d, pwd-pw_name,
  pwd-pw_uid); edited = 1;
}
  
  As I stil do not know why the latter variant of my code worked and
  the former does not, I would still appreciate any comment or
  explanation which would help me understanding GETPWNAM and getpwnam.
 
 I'm not familiar with the code you're working with,
 but according to the man page getpwnam() isn't thread
 safe so you probably shouldn't mess with the returned
 pointer in the first place and only treat the one
 returned by the last call as valid.
 
 Did you try using getpwnam_r() instead?
 
 Fabian

You are quite right, GETPWNAM() is a macro to getpwnam(), which is not
thread safe. GETPWNAM() is called throughout the code of pw and pw
itself is not threaded, so it should not matter whether the functions
called are thread-safe or not. I am not completely sure on my last
statement though. Do you have other experience regarding this topic?

Anyways, thanks and cheers,
-- 
Christopher J. Ruwe
TZ GMT + 2



signature.asc
Description: PGP signature


Re: trying to learn systems programming, fear I have not understood and thus messed up

2011-10-22 Thread Fabian Keil
Christopher J. Ruwe c...@cruwe.de wrote:

 On Sat, 22 Oct 2011 16:45:08 +0200
 Fabian Keil freebsd-lis...@fabiankeil.de wrote:
 
  Christopher J. Ruwe c...@cruwe.de wrote:
  
   On Fri, 21 Oct 2011 18:53:33 +0200
   Christopher J. Ruwe c...@cruwe.de wrote:

   As I stil do not know why the latter variant of my code worked and
   the former does not, I would still appreciate any comment or
   explanation which would help me understanding GETPWNAM and getpwnam.
  
  I'm not familiar with the code you're working with,
  but according to the man page getpwnam() isn't thread
  safe so you probably shouldn't mess with the returned
  pointer in the first place and only treat the one
  returned by the last call as valid.
  
  Did you try using getpwnam_r() instead?

 You are quite right, GETPWNAM() is a macro to getpwnam(), which is not
 thread safe. GETPWNAM() is called throughout the code of pw and pw
 itself is not threaded, so it should not matter whether the functions
 called are thread-safe or not. I am not completely sure on my last
 statement though. Do you have other experience regarding this topic?

My point is that if getpwnam() isn't thread safe because
separate calls are using the same static buffer to return
their result (which I didn't verify), and you do something
like:

pwd = GETPWNAM(...)
[...]
trgpwd = GETPWNAM(...)
pwd-pw_uid = (uid_t) (trgpwd-pw_uid);

the second getpwnam() call is going to reuse the memory
pointed to by pwd. While I assume your intention was to
only change pwd-pw_uid, the second getpwnam() call already
had the side effect of overwriting all the other members as
well.

This would happen in a single-threaded application as well.

Fabian


signature.asc
Description: PGP signature


Re: trying to learn systems programming, fear I have not understood and thus messed up

2011-10-22 Thread Frank Shute
On Fri, Oct 21, 2011 at 06:53:33PM +0200, Christopher J. Ruwe wrote:

 To improve on my C and to learn something about systems programming, I
 have begun to pick out bite-size bits from the bin-PRs. Currently, I
 am dispairing about bin/149972, which is about 1) adding error handling
 to pw being invoced pw -u username and 2) trying to get a uid from
 the (incorrectly) passed username. Currently, I cannot accomplish want
 I wanted to do, so I turn here for hints or help.
 

[snip]

Christopher, you're probably best off posting to hackers@ for
programming problems pertaining to FreeBSD.


Regards,

-- 

 Frank

 Contact info: http://www.shute.org.uk/misc/contact.html




pgpMvw7dgrm0F.pgp
Description: PGP signature


trying to learn systems programming, fear I have not understood and thus messed up

2011-10-21 Thread Christopher J. Ruwe
To improve on my C and to learn something about systems programming, I
have begun to pick out bite-size bits from the bin-PRs. Currently, I
am dispairing about bin/149972, which is about 1) adding error handling
to pw being invoced pw -u username and 2) trying to get a uid from
the (incorrectly) passed username. Currently, I cannot accomplish want
I wanted to do, so I turn here for hints or help.

Three developers which I have failed to reach by mail (gpf@, kibab@,
bcr@) have added the necessary code


if ((arg = getarg(args, 'u')) != NULL) {
   if(isdigit((unsigned char)*arg-val)) {
   pwd-pw_uid = (uid_t) atol(arg-val);
   edited = 1;
   if (pwd-pw_uid != 0  strcmp(pwd-pw_name, root) == 0)
  errx(EX_DATAERR, can't change uid of `root' account);
   if (pwd-pw_uid == 0  strcmp(pwd-pw_name, root) != 0)
  warnx(WARNING: account `%s' will have a uid of 0 (superuser
access!), pwd-pw_name); } else {
  /* Found something, but not a number */
  /*
   * XXX Shouldn't we try to map the passed string to the username?
   * man page however says that we're expecting numeric uid...
   */
  errx(EX_DATAERR, Expected numeric user id as an argument to -u\n);
  }
}

I have tried to follow the suggestion from the comment by modifiying
the else-statement thus:

} else {
  struct passwd *trgpwd;
  if (!(trgpwd = GETPWNAM(arg-val)))
 errx(EX_DATAERR, User %s does not exist, arg-val);
   
   if (strcmp(a_name-val,root) == 0)
  errx(EX_DATAERR, can't change uid of `root' account);
   if (strcmp(trgpwd-pw_name, root) == 0)
  warnx(WARNING: account `%s' will have a uid of 0 (superuser
access!), pwd-pw_name);

   pwd-pw_uid = (uid_t) (trgpwd-pw_uid);  
   edited = 1;
} 

What happens is not what I intended. I invoke as sudo ./pw usermod
testuser1 -u testuser2. I can get testuser2's pwd-entry by GETPWNAM
allright, but when I assign the pw_uid, so as to make testuser2's uid
the same as testuser1's and imgaining to retain all other values, ./pw
reports pw: user 'testuser2' disappeared during update and the
testuser2's /etc/passwd entry is replaced by testuser1's.

I fear I have not understood GETPWNAM correctly, as it seems to replace
the struct pwd as some sort of sideeffect. I could manually set all
pwd-members to the correct ones (those of testuser2), but I fear that I
have messed something up beforehand.

I am grateful for any suggestions and/or correction. 
-- 
Christopher J. Ruwe
TZ GMT + 2



signature.asc
Description: PGP signature