(root)/
glibc-2.38/
grp/
compat-initgroups.c
       1  /* Prototype for the setgrent functions we use here.  */
       2  typedef enum nss_status (*set_function) (void);
       3  
       4  /* Prototype for the endgrent functions we use here.  */
       5  typedef enum nss_status (*end_function) (void);
       6  
       7  /* Prototype for the setgrent functions we use here.  */
       8  typedef enum nss_status (*get_function) (struct group *, char *,
       9  					 size_t, int *);
      10  
      11  
      12  static enum nss_status
      13  compat_call (nss_action_list nip, const char *user, gid_t group, long int *start,
      14  	     long int *size, gid_t **groupsp, long int limit, int *errnop)
      15  {
      16    struct group grpbuf;
      17    enum nss_status status;
      18    set_function setgrent_fct;
      19    get_function getgrent_fct;
      20    end_function endgrent_fct;
      21    gid_t *groups = *groupsp;
      22  
      23    getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
      24    if (getgrent_fct == NULL)
      25      return NSS_STATUS_UNAVAIL;
      26  
      27    setgrent_fct = __nss_lookup_function (nip, "setgrent");
      28    if (setgrent_fct)
      29      {
      30        status = DL_CALL_FCT (setgrent_fct, ());
      31        if (status != NSS_STATUS_SUCCESS)
      32  	return status;
      33      }
      34  
      35    endgrent_fct = __nss_lookup_function (nip, "endgrent");
      36  
      37    struct scratch_buffer tmpbuf;
      38    scratch_buffer_init (&tmpbuf);
      39    enum nss_status result = NSS_STATUS_SUCCESS;
      40  
      41    do
      42      {
      43        while ((status = DL_CALL_FCT (getgrent_fct,
      44  				     (&grpbuf, tmpbuf.data, tmpbuf.length,
      45  				      errnop)),
      46  	      status == NSS_STATUS_TRYAGAIN)
      47  	     && *errnop == ERANGE)
      48          {
      49  	  if (!scratch_buffer_grow (&tmpbuf))
      50  	    {
      51  	      result = NSS_STATUS_TRYAGAIN;
      52  	      goto done;
      53  	    }
      54          }
      55  
      56        if (status != NSS_STATUS_SUCCESS)
      57          goto done;
      58  
      59        if (grpbuf.gr_gid != group)
      60          {
      61            char **m;
      62  
      63            for (m = grpbuf.gr_mem; *m != NULL; ++m)
      64              if (strcmp (*m, user) == 0)
      65                {
      66  		/* Check whether the group is already on the list.  */
      67  		long int cnt;
      68  		for (cnt = 0; cnt < *start; ++cnt)
      69  		  if (groups[cnt] == grpbuf.gr_gid)
      70  		    break;
      71  
      72  		if (cnt == *start)
      73  		  {
      74  		    /* Matches user and not yet on the list.  Insert
      75  		       this group.  */
      76  		    if (__glibc_unlikely (*start == *size))
      77  		      {
      78  			/* Need a bigger buffer.  */
      79  			gid_t *newgroups;
      80  			long int newsize;
      81  
      82  			if (limit > 0 && *size == limit)
      83  			  /* We reached the maximum.  */
      84  			  goto done;
      85  
      86  			if (limit <= 0)
      87  			  newsize = 2 * *size;
      88  			else
      89  			  newsize = MIN (limit, 2 * *size);
      90  
      91  			newgroups = realloc (groups,
      92  					     newsize * sizeof (*groups));
      93  			if (newgroups == NULL)
      94  			  goto done;
      95  			*groupsp = groups = newgroups;
      96  			*size = newsize;
      97  		      }
      98  
      99  		    groups[*start] = grpbuf.gr_gid;
     100  		    *start += 1;
     101  		  }
     102  
     103                  break;
     104                }
     105          }
     106      }
     107    while (status == NSS_STATUS_SUCCESS);
     108  
     109   done:
     110    scratch_buffer_free (&tmpbuf);
     111  
     112    if (endgrent_fct)
     113      DL_CALL_FCT (endgrent_fct, ());
     114  
     115    return result;
     116  }