will...@25thandclement.com writes:

>>Synopsis:     Bad return value for getpwnam_r et al
>>Category:     42
>>Environment:
>       System      : OpenBSD 5.4
>       Details     : OpenBSD 5.4 (GENERIC.MP) #41: Tue Jul 30 15:30:02 MDT 2013
>                        
> dera...@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>
>       Architecture: OpenBSD.amd64
>       Machine     : amd64
>>Description:
>       POSIX says "[t]he getpwnam_r() function shall return zero on success
>       or if the requested entry was not found and no error has occurred.
>       If an error has occurred, an error number shall be returned to
>       indicate the error."
>
>       However, OpenBSD returns 0 on success or 1 on failure; it doesn't
>       return an error number. Linux, OS X, Solaris, FreeBSD, and NetBSD
>       all return an error number, and in particular return ERANGE when the
>       provided buffer is too small.

The following diff seems to be enough (at least for pwd.db):

Index: getpwent.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/getpwent.c,v
retrieving revision 1.48
diff -u -p -p -u -r1.48 getpwent.c
--- getpwent.c  15 Nov 2013 22:32:55 -0000      1.48
+++ getpwent.c  30 Jan 2014 10:24:15 -0000
@@ -867,8 +867,10 @@ __hashpw(DBT *key, char *buf, size_t buf
        if ((_pw_db->get)(_pw_db, key, &data, 0))
                return (0);
        p = (char *)data.data;
-       if (data.size > buflen)
+       if (data.size > buflen) {
+               errno = ERANGE;
                return (0);
+       }
 
        t = buf;
 #define        EXPAND(e)       e = t; while ((*t++ = *p++));


>       Background: I was looping over getpwnam_r so I wouldn't have to use
>       sysconf() to get _SC_GETPW_R_SIZE_MAX. Linux/glibc has an annoying
>       habit of setting some limits to INT_MAX. It doesn't in this case,
>       but I'm not confident they won't do something stupid down the line.
>
>>How-To-Repeat:
>       #include <stdlib.h>
>       #include <stdio.h>
>       #include <string.h>
>       #include <unistd.h>
>       #include <pwd.h>
>
>
>       int main(void) {
>               struct passwd ent, *found;
>               char *buf = NULL;
>               size_t bufsiz = 1;
>               int error;
>
>               found = NULL;
>
>               buf = malloc(bufsiz);
>
>               while ((error = getpwnam_r("root", &ent, buf, bufsiz, &found))) 
> {
>                       fprintf(stderr, "bufsiz:%zu error:%s\n", bufsiz, 
> strerror(error));
                                                                                
  ^^^^^
I think you mean errno, not error.

>                       bufsiz <<= 1;
>                       buf = realloc(buf, bufsiz);
>                       found = NULL;
>               }
>
>               printf("pw_dir:   %s\n", ent.pw_dir);
>               printf("pw_shell: %s\n", ent.pw_shell);
>
>               return 0;
>       }
>
>>Fix:
>       No easy fix. The supporting routines _pwhashbyname, _pwhashbyuid,
>       etc in lib/libc/gen/getpwent.c don't propogate error values.

They do (but through errno).  Of course there may be other places where
the internal functions clobber errno before returning to the user code,
but some fixes have been applied already (eg. rev 1.43 of getpwent.c).

-- 
jca | PGP: 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE
(previous: 0x06A11494 / 61DB D9A0 00A4 67CF 2A90  8961 6191 8FBF 06A1 1494)

Reply via email to