lists.arthurdejong.org
RSS feed

[PATCH] Do not truncate large UID/GID values on 32bit architectures

[Date Prev][Date Next] [Thread Prev][Thread Next]

[PATCH] Do not truncate large UID/GID values on 32bit architectures



nslcd used strtol() for converting UID/GID attributes into their numeric
form. The conversion does not work correctly on 32bit architectures because
large UID/GIDs values do not fit into LONG_MAX there.

The attached patch uses a new function strtouint32() to convert strings
to IDs. This way, even large ID values can be converted safely and also
IDs that overflow the UINT32_MAX value are detected.

Please see https://bugzilla.redhat.com/show_bug.cgi?id=720230#c3 for a
reproducer, for example.
>From ba032bbc664cf553bbb4b4bbe6db98c2d3a0e15d Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Fri, 26 Aug 2011 13:02:26 +0200
Subject: [PATCH] Do not truncate big UID/GID numbers

---
 nslcd/cfg.c    |    8 ++++----
 nslcd/common.c |   14 ++++++++++++++
 nslcd/common.h |    4 ++++
 nslcd/group.c  |    7 ++++---
 nslcd/passwd.c |   21 ++++++++++++---------
 5 files changed, 38 insertions(+), 16 deletions(-)

diff --git a/nslcd/cfg.c b/nslcd/cfg.c
index 1b8a31d..b6ed51a 100644
--- a/nslcd/cfg.c
+++ b/nslcd/cfg.c
@@ -430,8 +430,8 @@ static void get_uid(const char *filename,int lnr,
   char *tmp;
   
check_argumentcount(filename,lnr,keyword,get_token(line,token,sizeof(token))!=NULL);
   /* check if it is a valid numerical uid */
-  *var=(uid_t)strtol(token,&tmp,0);
-  if ((*token!='\0')&&(*tmp=='\0'))
+  *var=(uid_t)strtouint32(token,&tmp,0);
+  if ((*token!='\0')&&(*tmp=='\0')&&(errno==0))
     return;
   /* find by name */
   pwent=getpwnam(token);
@@ -455,8 +455,8 @@ static void get_gid(const char *filename,int lnr,
   char *tmp;
   
check_argumentcount(filename,lnr,keyword,get_token(line,token,sizeof(token))!=NULL);
   /* check if it is a valid numerical gid */
-  *var=(gid_t)strtol(token,&tmp,0);
-  if ((*token!='\0')&&(*tmp=='\0'))
+  *var=(gid_t)strtouint32(token,&tmp,0);
+  if ((*token!='\0')&&(*tmp=='\0')&&(errno==0))
     return;
   /* find by name */
   grent=getgrnam(token);
diff --git a/nslcd/common.c b/nslcd/common.c
index cb94c2f..7e90395 100644
--- a/nslcd/common.c
+++ b/nslcd/common.c
@@ -269,3 +269,17 @@ long int binsid2id(const char *binsid)
   return (((long int)binsid[i])&0xff)|((((long int)binsid[i+1])&0xff)<<8)|
          ((((long int)binsid[i+2])&0xff)<<16)|((((long 
int)binsid[i+3])&0xff)<<24);
 }
+
+uint32_t strtouint32(const char *nptr, char **endptr, int base)
+{
+  unsigned long long val;
+  errno = 0;
+  val = strtoull(nptr, endptr, base);
+  if (val > UINT32_MAX)
+  {
+    errno = ERANGE;
+    return UINT32_MAX;
+  }
+  /* If errno was set by strtoull, we'll pass it back as-is */
+  return (uint32_t)val;
+}
diff --git a/nslcd/common.h b/nslcd/common.h
index a998bff..5608f08 100644
--- a/nslcd/common.h
+++ b/nslcd/common.h
@@ -25,6 +25,7 @@
 #define NSLCD__COMMON_H 1
 
 #include <errno.h>
+#include <stdint.h>
 
 #include "nslcd.h"
 #include "common/nslcd-prot.h"
@@ -95,6 +96,9 @@ MUST_USE long int binsid2id(const char *binsid);
 /* checks to see if the specified string is a valid user or group name */
 MUST_USE int isvalidname(const char *name);
 
+/* Converts a string to uint32_t with overflow checks */
+MUST_USE uint32_t strtouint32(const char *nptr, char **endptr, int base);
+
 /* Perform an LDAP lookup to translate the DN into a uid.
    This function either returns NULL or a strdup()ed string. */
 MUST_USE char *lookup_dn2uid(MYLDAP_SESSION *session,const char *dn,int 
*rcp,char *buf,size_t buflen);
diff --git a/nslcd/group.c b/nslcd/group.c
index 4274842..9bf7528 100644
--- a/nslcd/group.c
+++ b/nslcd/group.c
@@ -280,10 +280,11 @@ static int write_group(TFILE *fp,MYLDAP_ENTRY 
*entry,const char *reqname,
         gids[numgids]=(gid_t)binsid2id(gidvalues[numgids]);
       else
       {
-        gids[numgids]=(gid_t)strtol(gidvalues[numgids],&tmp,0);
-        if ((*(gidvalues[numgids])=='\0')||(*tmp!='\0'))
+        gids[numgids]=(gid_t)strtouint32(gidvalues[numgids],&tmp,0);
+        if ((*(gidvalues[numgids])=='\0')||(*tmp!='\0')||(errno!=0))
         {
-          log_log(LOG_WARNING,"group entry %s contains non-numeric %s value",
+          log_log(LOG_WARNING,"group entry %s contains non-numeric %s value"
+                              "value or the value is out of range",
                               myldap_get_dn(entry),attmap_group_gidNumber);
           return 0;
         }
diff --git a/nslcd/passwd.c b/nslcd/passwd.c
index 035d0e8..26024f1 100644
--- a/nslcd/passwd.c
+++ b/nslcd/passwd.c
@@ -194,10 +194,11 @@ static int entry_has_valid_uid(MYLDAP_ENTRY *entry)
       uid=(uid_t)binsid2id(values[i]);
     else
     {
-      uid=(uid_t)strtol(values[i],&tmp,0);
-      if ((*(values[i])=='\0')||(*tmp!='\0'))
+      uid=(uid_t)strtouint32(values[i],&tmp,0);
+      if ((*(values[i])=='\0')||(*tmp!='\0')||(errno!=0))
       {
-        log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
+        log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s "
+                            "value or the value is out of range",
                             myldap_get_dn(entry),attmap_passwd_uidNumber);
         continue;
       }
@@ -481,10 +482,11 @@ static int write_passwd(TFILE *fp,MYLDAP_ENTRY 
*entry,const char *requser,
         uids[numuids]=(uid_t)binsid2id(tmpvalues[numuids]);
       else
       {
-        uids[numuids]=(uid_t)strtol(tmpvalues[numuids],&tmp,0);
-        if ((*(tmpvalues[numuids])=='\0')||(*tmp!='\0'))
+        uids[numuids]=(uid_t)strtouint32(tmpvalues[numuids],&tmp,0);
+        if ((*(tmpvalues[numuids])=='\0')||(*tmp!='\0')||(errno!=0))
         {
-          log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
+          log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s "
+                              "value or the value is out of range",
                               myldap_get_dn(entry),attmap_passwd_uidNumber);
           return 0;
         }
@@ -512,10 +514,11 @@ static int write_passwd(TFILE *fp,MYLDAP_ENTRY 
*entry,const char *requser,
                           myldap_get_dn(entry),attmap_passwd_gidNumber);
       return 0;
     }
-    gid=(gid_t)strtol(gidbuf,&tmp,0);
-    if ((gidbuf[0]=='\0')||(*tmp!='\0'))
+    gid=(gid_t)strtouint32(gidbuf,&tmp,0);
+    if ((gidbuf[0]=='\0')||(*tmp!='\0')||(errno!=0))
     {
-      log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
+      log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s "
+                          "value or the value is out of range",
                           myldap_get_dn(entry),attmap_passwd_gidNumber);
       return 0;
     }
-- 
1.7.6

-- 
To unsubscribe send an email to
nss-pam-ldapd-users-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/nss-pam-ldapd-users