Rewriting search_gid to use POSIX getgrnam_r
authorZbigniew Jasinski <z.jasinski@samsung.com>
Mon, 27 May 2013 13:10:02 +0000 (15:10 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Thu, 6 Feb 2014 16:09:36 +0000 (17:09 +0100)
[Issue#]       N/A
[Bug]          N/A
[Cause]        Instead of opening /etc/group and search for group name and ID we can
               use POSIX getgrnam_r
[Solution]     Rewriting function to use POSIX getgrnam_r.
[Verification] Build. Run all security-server tests.

Change-Id: Ia3591db1e11c013229ffd0a725697be797e0a2f1

src/server/security-server-main.c

index 63a10a6..5e4b472 100644 (file)
@@ -36,6 +36,7 @@
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <poll.h>
+#include <grp.h>
 
 #include <privilege-control.h>
 #include <security-server-system-observer.h>
@@ -204,85 +205,69 @@ error:
        return ret;
 }
 
-/* Search GID from group name *
- * This function opens /etc/group and search group name by given gid */
+/*
+ * Searches for group ID by given group name
+ */
+
 int search_gid(const char *obj)
 {
-       FILE *fp = NULL;
-       char *linebuf = NULL, *token = NULL, *token2, *tempstr = NULL;
-       int ret = SECURITY_SERVER_ERROR_NO_SUCH_OBJECT, tmp_gid, bufsize;
-
-       SEC_SVR_DBG("Searching for object %s", obj);
-
-       fp = fopen("/etc/group", "r");
-       if(fp == NULL)
-       {
-               /* cannot open /etc/group */
-               SEC_SVR_ERR("%s", "cannot open /etc/group");
-               return SECURITY_SERVER_ERROR_FILE_OPERATION;
-       }
-
-       linebuf = malloc(128);
-       bufsize = 128;
-       if(linebuf == NULL)
-       {
-               ret = SECURITY_SERVER_ERROR_OUT_OF_MEMORY;
-               SEC_SVR_ERR("%s", "Out Of Memory");
-               goto error;
-       }
-
-       bzero(linebuf, bufsize);
-       while(fgets(linebuf, bufsize, fp) != NULL)
-       {
-               while(linebuf[bufsize -2] != 0 )
-               {
-                       linebuf[bufsize -1] = (char) fgetc(fp);
-                       tempstr = realloc(linebuf, bufsize + 128);
-                       if(tempstr == NULL)
-                       {
-                               ret = SECURITY_SERVER_ERROR_OUT_OF_MEMORY;
-                               goto error;
-                       }
-                       linebuf = tempstr;
-                       bzero(linebuf + bufsize, 128);
-                       fgets(linebuf + bufsize, 128, fp);
-                       bufsize += 128;
-               }
+        int ret = 0;
+        struct group *grpbuf = NULL;
+        struct group grp;
+        char *buf = NULL;
+       char *bigger_buf = NULL;
+        long int max_buf_size = 0;
+
+        /*
+         * The maximum needed size for buf can be found using sysconf(3) with the argument _SC_GETGR_R_SIZE_MAX
+        * If _SC_GETGR_R_SIZE_MAX is not returned we set max_buf_size to 1024 bytes. Enough to store few groups.
+         */
+        max_buf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+        if(max_buf_size == -1)
+                max_buf_size = 1024;
+
+        buf = malloc((size_t)max_buf_size);
+        if(buf == NULL)
+        {
+                ret = SECURITY_SERVER_ERROR_OUT_OF_MEMORY;
+                SEC_SVR_ERR("Out Of Memory");
+                goto error;
+        }
 
-               token = strtok(linebuf, ":");   /* group name */
-               token2 = strtok(NULL, ":");     /* group password */
-               token2 = strtok(NULL, ":");     /* gid */
-               if(token2 == NULL)
-               {
-                       SEC_SVR_ERR("/etc/group is not valid. cannot find gid: [%s]", linebuf);
-                       ret = SECURITY_SERVER_ERROR_SERVER_ERROR;
-                       goto error;
-               }
-               errno = 0;
-               tmp_gid = strtoul(token2, 0, 10);
-               if ( errno != 0 )
-               {
-                       SEC_SVR_ERR("cannot change string to integer [%s]", token2);
-                       ret = SECURITY_SERVER_ERROR_SERVER_ERROR;
+        /*
+         * There can be some corner cases when for example user is assigned to a lot of groups.
+         * In that case if buffer is to small getgrnam_r will return ERANGE error.
+         * Solution could be calling getgrnam_r with bigger buffer until it's enough big.
+         */
+       while((ret = getgrnam_r(obj, &grp, buf, (size_t)max_buf_size, &grpbuf)) == ERANGE) {
+               max_buf_size *= 2;
+
+               bigger_buf = realloc(buf, (size_t)max_buf_size);
+               if(bigger_buf == NULL) {
+                       ret = SECURITY_SERVER_ERROR_OUT_OF_MEMORY;
+                       SEC_SVR_ERR("Out Of Memory");
                        goto error;
                }
 
-               if(strcmp(obj, token) == 0)
-               {
-                       /* We found it */
-                       ret = tmp_gid;
-                       SEC_SVR_DBG("GID of %s is found: %d", obj, ret);
-                       break;
-               }
-               bzero(linebuf, bufsize);
+               buf = bigger_buf;
        }
 
+        if(ret != 0)
+        {
+                ret = SECURITY_SERVER_ERROR_SERVER_ERROR;
+                SEC_SVR_ERR("getgrnam_r failed with error %s\n", strerror(errno));
+                goto error;
+        } else if (grpbuf == NULL) {
+                ret =  SECURITY_SERVER_ERROR_NO_SUCH_OBJECT;
+                SEC_SVR_ERR("Cannot find gid for group %s\n", obj);
+                goto error;
+        }
+
+        ret = grpbuf->gr_gid;
+
 error:
-       if(linebuf != NULL)
-               free(linebuf);
-       if(fp != NULL)
-               fclose(fp);
-       return ret;
+       free(buf);
+        return ret;
 }
 
 /* Signal handler for processes */