314 lines
5.3 KiB
C
Raw Normal View History

/*
* <grp.h> wrapper functions.
*
* Authors:
* Jonathan Pryor (jonpryor@vt.edu)
*
* Copyright (C) 2004-2005 Jonathan Pryor
*/
#include <sys/types.h>
#include <sys/param.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h> /* for setgroups on Mac OS X */
#include "map.h"
#include "mph.h"
G_BEGIN_DECLS
static void
count_members (char **gr_mem, int *count, size_t *mem)
{
char *cur;
*count = 0;
// ensure that later (*mem)+1 doesn't result in integer overflow
if (*mem > INT_MAX - 1)
return;
for (cur = *gr_mem; cur != NULL; cur = *++gr_mem) {
size_t len;
len = strlen (cur);
if (!(len < INT_MAX - ((*mem) + 1)))
break;
++(*count);
*mem += (len + 1);
}
}
static int
copy_group (struct Mono_Posix_Syscall__Group *to, struct group *from)
{
size_t nlen, plen, buflen;
int i, count;
char *cur, **to_mem;
to->gr_gid = from->gr_gid;
to->gr_name = NULL;
to->gr_passwd = NULL;
to->gr_mem = NULL;
to->_gr_buf_ = NULL;
nlen = strlen (from->gr_name);
plen = strlen (from->gr_passwd);
buflen = 2;
if (!(nlen < INT_MAX - buflen))
return -1;
buflen += nlen;
if (!(plen < INT_MAX - buflen))
return -1;
buflen += plen;
count = 0;
count_members (from->gr_mem, &count, &buflen);
to->_gr_nmem_ = count;
cur = to->_gr_buf_ = (char*) malloc (buflen);
to_mem = to->gr_mem = malloc (sizeof(char*)*(count+1));
if (to->_gr_buf_ == NULL || to->gr_mem == NULL) {
free (to->_gr_buf_);
free (to->gr_mem);
return -1;
}
to->gr_name = strcpy (cur, from->gr_name);
cur += (nlen + 1);
to->gr_passwd = strcpy (cur, from->gr_passwd);
cur += (plen + 1);
for (i = 0; i != count; ++i) {
to_mem [i] = strcpy (cur, from->gr_mem[i]);
cur += (strlen (from->gr_mem[i])+1);
}
to_mem [i] = NULL;
return 0;
}
gint32
Mono_Posix_Syscall_getgrnam (const char *name, struct Mono_Posix_Syscall__Group *gbuf)
{
struct group *_gbuf;
if (gbuf == NULL) {
errno = EFAULT;
return -1;
}
errno = 0;
_gbuf = getgrnam (name);
if (_gbuf == NULL)
return -1;
if (copy_group (gbuf, _gbuf) == -1) {
errno = ENOMEM;
return -1;
}
return 0;
}
gint32
Mono_Posix_Syscall_getgrgid (mph_gid_t gid, struct Mono_Posix_Syscall__Group *gbuf)
{
struct group *_gbuf;
if (gbuf == NULL) {
errno = EFAULT;
return -1;
}
errno = 0;
_gbuf = getgrgid (gid);
if (_gbuf == NULL)
return -1;
if (copy_group (gbuf, _gbuf) == -1) {
errno = ENOMEM;
return -1;
}
return 0;
}
#ifdef HAVE_GETGRNAM_R
gint32
Mono_Posix_Syscall_getgrnam_r (const char *name,
struct Mono_Posix_Syscall__Group *gbuf,
void **gbufp)
{
char *buf, *buf2;
size_t buflen;
int r;
struct group _grbuf;
if (gbuf == NULL) {
errno = EFAULT;
return -1;
}
buf = buf2 = NULL;
buflen = 2;
do {
buf2 = realloc (buf, buflen *= 2);
if (buf2 == NULL) {
free (buf);
errno = ENOMEM;
return -1;
}
buf = buf2;
errno = 0;
} while ((r = getgrnam_r (name, &_grbuf, buf, buflen, (struct group**) gbufp)) &&
recheck_range (r));
/* On Solaris, this function returns 0 even if the entry was not found */
if (r == 0 && !(*gbufp))
r = errno = ENOENT;
if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
r = errno = ENOMEM;
free (buf);
return r;
}
#endif /* ndef HAVE_GETGRNAM_R */
#ifdef HAVE_GETGRGID_R
gint32
Mono_Posix_Syscall_getgrgid_r (mph_gid_t gid,
struct Mono_Posix_Syscall__Group *gbuf,
void **gbufp)
{
char *buf, *buf2;
size_t buflen;
int r;
struct group _grbuf;
if (gbuf == NULL) {
errno = EFAULT;
return -1;
}
buf = buf2 = NULL;
buflen = 2;
do {
buf2 = realloc (buf, buflen *= 2);
if (buf2 == NULL) {
free (buf);
errno = ENOMEM;
return -1;
}
buf = buf2;
errno = 0;
} while ((r = getgrgid_r (gid, &_grbuf, buf, buflen, (struct group**) gbufp)) &&
recheck_range (r));
/* On Solaris, this function returns 0 even if the entry was not found */
if (r == 0 && !(*gbufp))
r = errno = ENOENT;
if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
r = errno = ENOMEM;
free (buf);
return r;
}
#endif /* ndef HAVE_GETGRGID_R */
#if HAVE_GETGRENT
gint32
Mono_Posix_Syscall_getgrent (struct Mono_Posix_Syscall__Group *grbuf)
{
struct group *gr;
if (grbuf == NULL) {
errno = EFAULT;
return -1;
}
errno = 0;
gr = getgrent ();
if (gr == NULL)
return -1;
if (copy_group (grbuf, gr) == -1) {
errno = ENOMEM;
return -1;
}
return 0;
}
#endif /* def HAVE_GETGRENT */
#ifdef HAVE_FGETGRENT
gint32
Mono_Posix_Syscall_fgetgrent (void *stream, struct Mono_Posix_Syscall__Group *grbuf)
{
struct group *gr;
if (grbuf == NULL) {
errno = EFAULT;
return -1;
}
errno = 0;
gr = fgetgrent ((FILE*) stream);
if (gr == NULL)
return -1;
if (copy_group (grbuf, gr) == -1) {
errno = ENOMEM;
return -1;
}
return 0;
}
#endif /* ndef HAVE_FGETGRENT */
#if HAVE_SETGROUPS
gint32
Mono_Posix_Syscall_setgroups (mph_size_t size, mph_gid_t *list)
{
mph_return_if_size_t_overflow (size);
return setgroups ((size_t) size, list);
}
#endif /* def HAVE_SETGROUPS */
#if HAVE_SETGRENT
int
Mono_Posix_Syscall_setgrent (void)
{
errno = 0;
do {
setgrent ();
} while (errno == EINTR);
mph_return_if_val_in_list5(errno, EIO, EMFILE, ENFILE, ENOMEM, ERANGE);
return 0;
}
#endif /* def HAVE_SETGRENT */
#if HAVE_ENDGRENT
int
Mono_Posix_Syscall_endgrent (void)
{
endgrent();
return 0;
}
#endif /* def HAVE_ENDGRENT */
G_END_DECLS
/*
* vim: noexpandtab
*/