_SC_GETPW_R_SIZE_MAX undefined in sysconf.c, what is correct value?

Dan Nelson dnelson at allantgroup.com
Mon Oct 24 20:42:11 UTC 2011


In the last episode (Oct 24), Christopher J. Ruwe said:
> On Sun, 23 Oct 2011 19:10:34 -0500
> Dan Nelson <dnelson at allantgroup.com> wrote:
> > In the last episode (Oct 23), Christopher J. Ruwe said:
> > > I need to get the maximum size of an pwd-entry to determine the
> > > correct buffersize for calling getpwnam_r("uname",&pwd, buf, bufsize,
> > > &pwdp).  I would like to use sysconf(_SC_GETPW_R_SIZE_MAX) to
> > > determine bufsize, which unfornutately fails (returns -1).  Currently,
> > > I used 16384, which seems to be too much, bit works for the time
> > > being.
[..]
> > From looking at the libc/gen/getpwent.c file, it looks like a maximum
> > size might be 1MB.  The wrapper functions that convert getpw*_r
> > functions into ones that simply return a pointer to malloced data all
> > use the getpw() helper function, which starts with a 1k buffer and keeps
> > doubling its size until the data fits or it hits PWD_STORAGE_MAX (1MB). 
> > PWD_STORAGE_MAX is only checked within that getpw() function, though, so
> > it's possible that an nss library might return an even longer string to
> > a get*_r call.  It's up to you to decide what your own limit is :)
>
> Uh ... it's just that I hoped I had not to decide ;-)
> 
> However, 1M seems to be rather large to me. Let's see (pwd.h):
> 
>     116 struct passwd {
>     117 	char	*pw_name;	/* user name */
>     118 	char	*pw_passwd;	/* encrypted password */
>     119 	uid_t	pw_uid;		/* user uid */
>     120 	gid_t	pw_gid;		/* user gid */
>     121 	time_t	pw_change;	/* password change time */
>     122 	char	*pw_class;	/* user access class */
>     123 	char	*pw_gecos;	/* Honeywell login info */
>     124 	char	*pw_dir;	/* home directory */
>     125 	char	*pw_shell;	/* default shell */
>     126 	time_t	pw_expire;	/* account expiration */
>     127 	int	pw_fields;	/* internal: fields filled in */
>     128 };
> 
> So pw_name -> MAXLOGNAME (from param.h) = 17. pw_passwd ->
> http://www.freebsd.org/doc/handbook/one-time-passwords.html = 129.  pw_uid
> & pw_gid each sizeof(__uint32_t) ?= 32b.  time_t -> sizeof(__int64_t) ?=
> 64b.
> 
> At some point, I would just sum it up and reach some size which might be
> machine dependant, but should be somewhere (guessing/estimating now)
> between 4k and 16k.  I am short on time just now, am I on the right track
> or am I missing something which should be obvious to someone with
> experience, but is not to me (lacking experience)?

The getpwnam_r function needs enough space to store the "struct passwd"
itself (which has a constant size) plus the strings pointed to by pw_name,
pw_class, pw_gecos, pw_dir, and pw_shell.  If you have enough control over
your environment that you can guarantee that the sum of those strings won't
be larger than 4k, then you can just used a fixed buffer of that size.  Even
1k is probably large enough for 99.999% of all systems.  That's a really
long home directory or shell path :) On the other hand, the GECOS field is
theoretially free-form and could contain a lot of data.  I've never see it
hold more than an office number myself, though.

-- 
	Dan Nelson
	dnelson at allantgroup.com


More information about the freebsd-hackers mailing list