"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

Attachment: signature.asc
Description: PGP signature

Reply via email to