github.com/afumu/libc@v0.0.6/musl/src/passwd/getgr_a.c (about)

     1  #include <pthread.h>
     2  #include <byteswap.h>
     3  #include <string.h>
     4  #include <unistd.h>
     5  #include "pwf.h"
     6  #include "nscd.h"
     7  
     8  static char *itoa(char *p, uint32_t x)
     9  {
    10  	// number of digits in a uint32_t + NUL
    11  	p += 11;
    12  	*--p = 0;
    13  	do {
    14  		*--p = '0' + x % 10;
    15  		x /= 10;
    16  	} while (x);
    17  	return p;
    18  }
    19  
    20  int __getgr_a(const char *name, gid_t gid, struct group *gr, char **buf, size_t *size, char ***mem, size_t *nmem, struct group **res)
    21  {
    22  	FILE *f;
    23  	int rv = 0;
    24  	int cs;
    25  
    26  	*res = 0;
    27  
    28  	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
    29  	f = fopen("/etc/group", "rbe");
    30  	if (!f) {
    31  		rv = errno;
    32  		goto done;
    33  	}
    34  
    35  	while (!(rv = __getgrent_a(f, gr, buf, size, mem, nmem, res)) && *res) {
    36  		if (name && !strcmp(name, (*res)->gr_name)
    37  		|| !name && (*res)->gr_gid == gid) {
    38  			break;
    39  		}
    40  	}
    41  	fclose(f);
    42  
    43  	if (!*res && (rv == 0 || rv == ENOENT || rv == ENOTDIR)) {
    44  		int32_t req = name ? GETGRBYNAME : GETGRBYGID;
    45  		int32_t i;
    46  		const char *key;
    47  		int32_t groupbuf[GR_LEN] = {0};
    48  		size_t len = 0;
    49  		size_t grlist_len = 0;
    50  		char gidbuf[11] = {0};
    51  		int swap = 0;
    52  		char *ptr;
    53  
    54  		if (name) {
    55  			key = name;
    56  		} else {
    57  			if (gid < 0 || gid > UINT32_MAX) {
    58  				rv = 0;
    59  				goto done;
    60  			}
    61  			key = itoa(gidbuf, gid);
    62  		}
    63  
    64  		f = __nscd_query(req, key, groupbuf, sizeof groupbuf, &swap);
    65  		if (!f) { rv = errno; goto done; }
    66  
    67  		if (!groupbuf[GRFOUND]) { rv = 0; goto cleanup_f; }
    68  
    69  		if (!groupbuf[GRNAMELEN] || !groupbuf[GRPASSWDLEN]) {
    70  			rv = EIO;
    71  			goto cleanup_f;
    72  		}
    73  
    74  		if (groupbuf[GRNAMELEN] > SIZE_MAX - groupbuf[GRPASSWDLEN]) {
    75  			rv = ENOMEM;
    76  			goto cleanup_f;
    77  		}
    78  		len = groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN];
    79  
    80  		for (i = 0; i < groupbuf[GRMEMCNT]; i++) {
    81  			uint32_t name_len;
    82  			if (fread(&name_len, sizeof name_len, 1, f) < 1) {
    83  				rv = ferror(f) ? errno : EIO;
    84  				goto cleanup_f;
    85  			}
    86  			if (swap) {
    87  				name_len = bswap_32(name_len);
    88  			}
    89  			if (name_len > SIZE_MAX - grlist_len
    90  			|| name_len > SIZE_MAX - len) {
    91  				rv = ENOMEM;
    92  				goto cleanup_f;
    93  			}
    94  			len += name_len;
    95  			grlist_len += name_len;
    96  		}
    97  
    98  		if (len > *size || !*buf) {
    99  			char *tmp = realloc(*buf, len);
   100  			if (!tmp) {
   101  				rv = errno;
   102  				goto cleanup_f;
   103  			}
   104  			*buf = tmp;
   105  			*size = len;
   106  		}
   107  
   108  		if (!fread(*buf, len, 1, f)) {
   109  			rv = ferror(f) ? errno : EIO;
   110  			goto cleanup_f;
   111  		}
   112  
   113  		if (groupbuf[GRMEMCNT] + 1 > *nmem) {
   114  			if (groupbuf[GRMEMCNT] + 1 > SIZE_MAX/sizeof(char*)) {
   115  				rv = ENOMEM;
   116  				goto cleanup_f;
   117  			}
   118  			char **tmp = realloc(*mem, (groupbuf[GRMEMCNT]+1)*sizeof(char*));
   119  			if (!tmp) {
   120  				rv = errno;
   121  				goto cleanup_f;
   122  			}
   123  			*mem = tmp;
   124  			*nmem = groupbuf[GRMEMCNT] + 1;
   125  		}
   126  
   127  		if (groupbuf[GRMEMCNT]) {
   128  			mem[0][0] = *buf + groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN];
   129  			for (ptr = mem[0][0], i = 0; ptr != mem[0][0]+grlist_len; ptr++)
   130  				if (!*ptr) mem[0][++i] = ptr+1;
   131  			mem[0][i] = 0;
   132  
   133  			if (i != groupbuf[GRMEMCNT]) {
   134  				rv = EIO;
   135  				goto cleanup_f;
   136  			}
   137  		} else {
   138  			mem[0][0] = 0;
   139  		}
   140  
   141  		gr->gr_name = *buf;
   142  		gr->gr_passwd = gr->gr_name + groupbuf[GRNAMELEN];
   143  		gr->gr_gid = groupbuf[GRGID];
   144  		gr->gr_mem = *mem;
   145  
   146  		if (gr->gr_passwd[-1]
   147  		|| gr->gr_passwd[groupbuf[GRPASSWDLEN]-1]) {
   148  			rv = EIO;
   149  			goto cleanup_f;
   150  		}
   151  
   152  		if (name && strcmp(name, gr->gr_name)
   153  		|| !name && gid != gr->gr_gid) {
   154  			rv = EIO;
   155  			goto cleanup_f;
   156  		}
   157  
   158  		*res = gr;
   159  
   160  cleanup_f:
   161  		fclose(f);
   162  		goto done;
   163  	}
   164  
   165  done:
   166  	pthread_setcancelstate(cs, 0);
   167  	if (rv) errno = rv;
   168  	return rv;
   169  }