On Tue, Feb 19, 2013 at 12:06:13AM +0800, Elias Martenson wrote:
> 
> You were right, the problem was in pname_to_uid.c. In it, the following
> code can be found:
> 
>         char lname[MAXLOGNAME + 1], buf[1024];
> 
>         /* some code snipped for brevity... */
> 
>         getpwnam_r(lname, &pwd, buf, sizeof(buf), &pw);
>         if (pw) {
>                 *uidp = pw->pw_uid;
>                 return (GSS_S_COMPLETE);
>         } else {
>                 return (GSS_S_FAILURE);
>         }
> 
> As it turns out, the getpwnam_r() call fails with ERANGE (I had to check
> the return value from getpwnam_r() in order to determine this, as pw is set
> to NULL both if there was an error or if the user name can't be found).
> 
> Now, increasing the size of buf to 1024 solved the problem, and now the
> lookup works correctly.
> 
> I wrote a small test program that issued the same call to getpwnam_r() and
> it worked. Until I su'ed to root, and then it failed.
> 
> It seems as though the buffer needs to be bigger if you're root. I have no
> idea why, but there you have it. Problem solved.

It can require bigger buffer, since root can get the pw_password field
in the struct passwd{}.

Since sysconf(_SC_GETPW_R_SIZE_MAX) does not work on FreeBSD, the buffer
for getpwnam_r() call should have at least (2 * MAXLOGNAME + 2 * MAXPATHLEN +
_PASSWORD_LEN + 1) bytes (it is unclear how much is required for pw_gecos).

This buffer can be dynamically reallocated until getpwnam_r() is not
return ERANGE error (the following code has not been compiled and verified):

#define PWBUF_SIZE_INI (2 * MAXLOGNAME + 2 * MAXPATHLEN + _PASSWORD_LEN + 1)
#define PWBUF_SIZE_INC 128

        size = PWBUF_SIZE_INI;
        for (;;) {
                size += PWBUF_SIZE_INC;
                buf = malloc(size);
                if (buf == NULL)
                        return (GSS_S_FAILURE);
                error = getpwnam_r(lname, &pwd, buf, size, &pw);
                free(buf);
                if (pw != NULL) {
                        *uidp = pw->pw_uid;
                        return (GSS_S_COMPLETE);
                } else {
                        if (error == ERANGE &&
                            size <= SIZE_MAX - PWBUF_SIZE_INC)
                                continue;
                        return (GSS_S_FAILURE);
                }
        }
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to