-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgetgrouplist.xs
71 lines (67 loc) · 1.89 KB
/
getgrouplist.xs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/*
* Copyright (C) 2007-2014 Collax GmbH
* (Bastian Friedrich <[email protected]>)
*/
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <pwd.h>
#include <unistd.h>
MODULE = User::getgrouplist PACKAGE = User::getgrouplist
PROTOTYPES: ENABLE
AV *
getgrouplist(username)
const char *username
PREINIT:
int count = 0;
int max; /* OpenBSD/darwin overwrite input value */
int i;
gid_t *groups = NULL;
struct passwd *pw;
PPCODE:
pw = getpwnam(username);
RETVAL = NULL;
if (pw != NULL) { /* Only execute when user exists */
#if defined __OpenBSD__ || defined __MACH__
/*
* The getgrouplist implementation in OpenBSD and MacOS X/
* darwin/MACH will not return the number of groups if it
* is larger than the input count argument.
* Thus, we need to find a list size. Start with an
* arbitrary number (32), and duplicate it on each iteration.
*
* 32 is a random number. NGROUPS_MAX defaults to 16 on my
* OpenBSD.
*/
max = 32;
count = max;
groups = (gid_t *) malloc(count * sizeof (gid_t));
while (groups && (getgrouplist(username, pw->pw_gid, groups, &count) < 0) && (count < sysconf(_SC_NGROUPS_MAX))) {
max *= 2;
count = max; /* Re-set. Was overwritten by last getgrouplist call */
groups = (gid_t *) realloc(groups, count * sizeof (gid_t));
if (!groups) {
count = 0;
continue;
}
}
#else
#if defined __CYGWIN__
/* Cygwin behaves differently than Linux -- will return count even if groups is NULL */
if (getgrouplist(username, pw->pw_gid, NULL, &count) > 0) {
#else
if (getgrouplist(username, pw->pw_gid, NULL, &count) < 0) {
#endif
groups = (gid_t *) malloc(count * sizeof (gid_t));
if (groups) {
getgrouplist(username, pw->pw_gid, groups, &count);
}
}
#endif
if (groups) {
for (i = 0; i < count; i++) {
XPUSHs(sv_2mortal(newSViv(groups[i])));
}
free(groups);
}
}