Back to index

glibc  2.9
compat-initgroups.c
Go to the documentation of this file.
00001 /* Prototype for the setgrent functions we use here.  */
00002 typedef enum nss_status (*set_function) (void);
00003 
00004 /* Prototype for the endgrent functions we use here.  */
00005 typedef enum nss_status (*end_function) (void);
00006 
00007 /* Prototype for the setgrent functions we use here.  */
00008 typedef enum nss_status (*get_function) (struct group *, char *,
00009                                     size_t, int *);
00010 
00011 static enum nss_status
00012 compat_call (service_user *nip, const char *user, gid_t group, long int *start,
00013             long int *size, gid_t **groupsp, long int limit, int *errnop)
00014 {
00015   struct group grpbuf;
00016   size_t buflen = __sysconf (_SC_GETGR_R_SIZE_MAX);
00017   char *tmpbuf;
00018   enum nss_status status;
00019   set_function setgrent_fct;
00020   get_function getgrent_fct;
00021   end_function endgrent_fct;
00022   gid_t *groups = *groupsp;
00023 
00024   getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
00025   if (getgrent_fct == NULL)
00026     return NSS_STATUS_UNAVAIL;
00027 
00028   setgrent_fct = __nss_lookup_function (nip, "setgrent");
00029   if (setgrent_fct)
00030     {
00031       status = DL_CALL_FCT (setgrent_fct, ());
00032       if (status != NSS_STATUS_SUCCESS)
00033        return status;
00034     }
00035 
00036   endgrent_fct = __nss_lookup_function (nip, "endgrent");
00037 
00038   tmpbuf = __alloca (buflen);
00039 
00040   do
00041     {
00042       while ((status = DL_CALL_FCT (getgrent_fct,
00043                                  (&grpbuf, tmpbuf, buflen, errnop)),
00044              status == NSS_STATUS_TRYAGAIN)
00045             && *errnop == ERANGE)
00046         {
00047           buflen *= 2;
00048           tmpbuf = __alloca (buflen);
00049         }
00050 
00051       if (status != NSS_STATUS_SUCCESS)
00052         goto done;
00053 
00054       if (grpbuf.gr_gid != group)
00055         {
00056           char **m;
00057 
00058           for (m = grpbuf.gr_mem; *m != NULL; ++m)
00059             if (strcmp (*m, user) == 0)
00060               {
00061               /* Check whether the group is already on the list.  */
00062               long int cnt;
00063               for (cnt = 0; cnt < *start; ++cnt)
00064                 if (groups[cnt] == grpbuf.gr_gid)
00065                   break;
00066 
00067               if (cnt == *start)
00068                 {
00069                   /* Matches user and not yet on the list.  Insert
00070                      this group.  */
00071                   if (__builtin_expect (*start == *size, 0))
00072                     {
00073                      /* Need a bigger buffer.  */
00074                      gid_t *newgroups;
00075                      long int newsize;
00076 
00077                      if (limit > 0 && *size == limit)
00078                        /* We reached the maximum.  */
00079                        goto done;
00080 
00081                      if (limit <= 0)
00082                        newsize = 2 * *size;
00083                      else
00084                        newsize = MIN (limit, 2 * *size);
00085 
00086                      newgroups = realloc (groups,
00087                                         newsize * sizeof (*groups));
00088                      if (newgroups == NULL)
00089                        goto done;
00090                      *groupsp = groups = newgroups;
00091                      *size = newsize;
00092                     }
00093 
00094                   groups[*start] = grpbuf.gr_gid;
00095                   *start += 1;
00096                 }
00097 
00098                 break;
00099               }
00100         }
00101     }
00102   while (status == NSS_STATUS_SUCCESS);
00103 
00104  done:
00105   if (endgrent_fct)
00106     DL_CALL_FCT (endgrent_fct, ());
00107 
00108   return NSS_STATUS_SUCCESS;
00109 }