Author: omalley
Date: Fri Mar 4 04:33:04 2011
New Revision: 1077593
URL: http://svn.apache.org/viewvc?rev=1077593&view=rev
Log:
commit 64486412ecf7208467daec3244d87e9d0d6fe97e
Author: Erik Steffl <[email protected]>
Date: Fri Jul 23 12:02:57 2010 -0700
HADOOP:6864 from
https://issues.apache.org/jira/secure/attachment/12450342/HADOOP-6864-0.20.1xx-1.patch
+++ b/YAHOO-CHANGES.txt
+ HADOOP-6864. Add ability to get netgroups (as returned by getent
+ netgroup command) using native code (JNI) instead of forking. (Erik
Steffl)
+
Added:
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.java
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/NetgroupCache.java
hadoop/common/branches/branch-0.20-security-patches/src/native/src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c
Removed:
hadoop/common/branches/branch-0.20-security-patches/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java.orig
Modified:
hadoop/common/branches/branch-0.20-security-patches/build.xml
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsMapping.java
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/ShellBasedUnixGroupsNetgroupMapping.java
hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.am
hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.in
Modified: hadoop/common/branches/branch-0.20-security-patches/build.xml
URL:
http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/build.xml?rev=1077593&r1=1077592&r2=1077593&view=diff
==============================================================================
--- hadoop/common/branches/branch-0.20-security-patches/build.xml (original)
+++ hadoop/common/branches/branch-0.20-security-patches/build.xml Fri Mar 4
04:33:04 2011
@@ -562,6 +562,15 @@
<class name="org.apache.hadoop.security.JniBasedUnixGroupsMapping" />
</javah>
+ <javah
+ classpath="${build.classes}"
+ destdir="${build.native}/src/org/apache/hadoop/security"
+ force="yes"
+ verbose="yes"
+ >
+ <class
name="org.apache.hadoop.security.JniBasedUnixGroupsNetgroupMapping" />
+ </javah>
+
<exec dir="${build.native}" executable="sh" failonerror="true">
<env key="OS_NAME" value="${os.name}"/>
<env key="OS_ARCH" value="${os.arch}"/>
Modified:
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsMapping.java
URL:
http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsMapping.java?rev=1077593&r1=1077592&r2=1077593&view=diff
==============================================================================
---
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsMapping.java
(original)
+++
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsMapping.java
Fri Mar 4 04:33:04 2011
@@ -33,7 +33,8 @@ import org.apache.hadoop.util.NativeCode
*/
public class JniBasedUnixGroupsMapping implements GroupMappingServiceProvider {
- private static final Log LOG =
LogFactory.getLog(ShellBasedUnixGroupsMapping.class);
+ private static final Log LOG = LogFactory.getLog(
+ JniBasedUnixGroupsMapping.class);
native String[] getGroupForUser(String user);
Added:
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.java
URL:
http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.java?rev=1077593&view=auto
==============================================================================
---
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.java
(added)
+++
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.java
Fri Mar 4 04:33:04 2011
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.security;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.LinkedList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.util.NativeCodeLoader;
+
+import org.apache.hadoop.security.NetgroupCache;
+
+/**
+ * A JNI-based implementation of {@link GroupMappingServiceProvider}
+ * that invokes libC calls to get the group
+ * memberships of a given user.
+ */
+public class JniBasedUnixGroupsNetgroupMapping
+ extends JniBasedUnixGroupsMapping {
+
+ private static final Log LOG = LogFactory.getLog(
+ JniBasedUnixGroupsNetgroupMapping.class);
+
+ private static final NetgroupCache netgroupCache = new NetgroupCache();
+
+ native String[] getUsersForNetgroupJNI(String group);
+
+ /**
+ * Gets unix groups and netgroups for the user.
+ *
+ * It gets all unix groups as returned by id -Gn but it
+ * only returns netgroups that are used in ACLs (there is
+ * no way to get all netgroups for a given user, see
+ * documentation for getent netgroup)
+ */
+ @Override
+ public List<String> getGroups(String user) throws IOException {
+ // parent gets unix groups
+ List<String> groups = new LinkedList<String>(super.getGroups(user));
+ netgroupCache.getNetgroups(user, groups);
+ return groups;
+ }
+
+ @Override
+ public void cacheGroupsRefresh() throws IOException {
+ List<String> groups = netgroupCache.getNetgroupNames();
+ netgroupCache.clear();
+ cacheGroupsAdd(groups);
+ }
+
+ @Override
+ public void cacheGroupsAdd(List<String> groups) throws IOException {
+ for(String group: groups) {
+ if(group.length() == 0) {
+ // better safe than sorry (should never happen)
+ } else if(group.charAt(0) == '@') {
+ if(!netgroupCache.isCached(group)) {
+ netgroupCache.add(group, getUsersForNetgroup(group));
+ }
+ } else {
+ // unix group, not caching
+ }
+ }
+ }
+
+ /**
+ * Calls JNI function to get users for a netgroup, since C functions
+ * are not reentrant we need to make this synchronized (see
+ * documentation for setnetgrent, getnetgrent and endnetgrent)
+ */
+ protected synchronized List<String> getUsersForNetgroup(String netgroup) {
+ String[] users = null;
+ try {
+ // JNI code does not expect '@' at the begining of the group name
+ users = getUsersForNetgroupJNI(netgroup.substring(1));
+ } catch (Exception e) {
+ LOG.warn("Got exception while trying to obtain the users for netgroup ["
+ + netgroup + "] [" + e + "]");
+ }
+ if (users != null && users.length != 0) {
+ return Arrays.asList(users);
+ }
+ return new LinkedList<String>();
+ }
+}
Added:
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/NetgroupCache.java
URL:
http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/NetgroupCache.java?rev=1077593&view=auto
==============================================================================
---
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/NetgroupCache.java
(added)
+++
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/NetgroupCache.java
Fri Mar 4 04:33:04 2011
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.security;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Class that caches the netgroups and inverts group-to-user map
+ * to user-to-group map
+ */
+public class NetgroupCache {
+
+ private static final Log LOG = LogFactory.getLog(NetgroupCache.class);
+
+ private static boolean netgroupToUsersMapUpdated = true;
+ private static Map<String, Set<String>> netgroupToUsersMap =
+ new ConcurrentHashMap<String, Set<String>>();
+
+ private static Map<String, Set<String>> userToNetgroupsMap =
+ new ConcurrentHashMap<String, Set<String>>();
+
+
+ public void getNetgroups(final String user,
+ List<String> groups) {
+ if(netgroupToUsersMapUpdated) {
+ netgroupToUsersMapUpdated = false; // at the beginning to avoid race
+ //update userToNetgroupsMap
+ for(String netgroup : netgroupToUsersMap.keySet()) {
+ for(String netuser : netgroupToUsersMap.get(netgroup)) {
+ // add to userToNetgroupsMap
+ if(!userToNetgroupsMap.containsKey(netuser)) {
+ userToNetgroupsMap.put(netuser, new HashSet<String>());
+ }
+ userToNetgroupsMap.get(netuser).add(netgroup);
+ }
+ }
+ }
+ if(userToNetgroupsMap.containsKey(user)) {
+ for(String netgroup : userToNetgroupsMap.get(user)) {
+ groups.add(netgroup);
+ }
+ }
+ }
+
+ public List<String> getNetgroupNames() {
+ return new LinkedList<String>(netgroupToUsersMap.keySet());
+ }
+
+ public boolean isCached(String group) {
+ return netgroupToUsersMap.containsKey(group);
+ }
+
+ public void clear() {
+ netgroupToUsersMap.clear();
+ }
+
+ public void add(String group, List<String> users) {
+ if(!isCached(group)) {
+ netgroupToUsersMap.put(group, new HashSet<String>());
+ for(String user: users) {
+ netgroupToUsersMap.get(group).add(user);
+ }
+ }
+ netgroupToUsersMapUpdated = true; // at the end to avoid race
+ }
+}
Modified:
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/ShellBasedUnixGroupsNetgroupMapping.java
URL:
http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/ShellBasedUnixGroupsNetgroupMapping.java?rev=1077593&r1=1077592&r2=1077593&view=diff
==============================================================================
---
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/ShellBasedUnixGroupsNetgroupMapping.java
(original)
+++
hadoop/common/branches/branch-0.20-security-patches/src/core/org/apache/hadoop/security/ShellBasedUnixGroupsNetgroupMapping.java
Fri Mar 4 04:33:04 2011
@@ -40,11 +40,11 @@ public class ShellBasedUnixGroupsNetgrou
private static final Log LOG =
LogFactory.getLog(ShellBasedUnixGroupsNetgroupMapping.class);
- private static boolean netgroupToUsersMapUpdated = true;
- private static Map<String, Set<String>> netgroupToUsersMap =
+ protected static boolean netgroupToUsersMapUpdated = true;
+ protected static Map<String, Set<String>> netgroupToUsersMap =
new ConcurrentHashMap<String, Set<String>>();
- private static Map<String, Set<String>> userToNetgroupsMap =
+ protected static Map<String, Set<String>> userToNetgroupsMap =
new ConcurrentHashMap<String, Set<String>>();
@Override
@@ -76,7 +76,7 @@ public class ShellBasedUnixGroupsNetgrou
}
}
- private void cacheNetgroup(String group) throws IOException {
+ protected void cacheNetgroup(String group) throws IOException {
if(netgroupToUsersMap.containsKey(group)) {
return;
} else {
@@ -123,7 +123,7 @@ public class ShellBasedUnixGroupsNetgrou
}
}
- private void getNetgroups(final String user,
+ protected void getNetgroups(final String user,
List<String> groups) throws IOException {
if(netgroupToUsersMapUpdated) {
netgroupToUsersMapUpdated = false; // at the beginning to avoid race
@@ -161,7 +161,9 @@ public class ShellBasedUnixGroupsNetgrou
throws IOException {
String result = "";
try {
- result = Shell.execCommand(Shell.getUsersForNetgroupCommand(netgroup));
+ // shell command does not expect '@' at the begining of the group name
+ result = Shell.execCommand(
+ Shell.getUsersForNetgroupCommand(netgroup.substring(1)));
} catch (ExitCodeException e) {
// if we didn't get the group - just return empty list;
LOG.warn("error while getting users for netgroup " + netgroup, e);
Modified:
hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.am
URL:
http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.am?rev=1077593&r1=1077592&r2=1077593&view=diff
==============================================================================
--- hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.am
(original)
+++ hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.am
Fri Mar 4 04:33:04 2011
@@ -41,7 +41,8 @@ lib_LTLIBRARIES = libhadoop.la
libhadoop_la_SOURCES = src/org/apache/hadoop/io/compress/zlib/ZlibCompressor.c
\
src/org/apache/hadoop/io/compress/zlib/ZlibDecompressor.c \
src/org/apache/hadoop/security/getGroup.c \
-
src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c
+
src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c \
+
src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c
libhadoop_la_LDFLAGS = -version-info 1:0:0
libhadoop_la_LIBADD = -ldl -ljvm
Modified:
hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.in
URL:
http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.in?rev=1077593&r1=1077592&r2=1077593&view=diff
==============================================================================
--- hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.in
(original)
+++ hadoop/common/branches/branch-0.20-security-patches/src/native/Makefile.in
Fri Mar 4 04:33:04 2011
@@ -93,7 +93,7 @@ libLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(lib_LTLIBRARIES)
libhadoop_la_DEPENDENCIES =
am_libhadoop_la_OBJECTS = ZlibCompressor.lo ZlibDecompressor.lo \
- getGroup.lo JniBasedUnixGroupsMapping.lo
+ getGroup.lo JniBasedUnixGroupsMapping.lo
JniBasedUnixGroupsNetgroupMapping.lo
libhadoop_la_OBJECTS = $(am_libhadoop_la_OBJECTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
depcomp = $(SHELL) $(top_srcdir)/config/depcomp
@@ -230,7 +230,8 @@ lib_LTLIBRARIES = libhadoop.la
libhadoop_la_SOURCES = src/org/apache/hadoop/io/compress/zlib/ZlibCompressor.c
\
src/org/apache/hadoop/io/compress/zlib/ZlibDecompressor.c \
src/org/apache/hadoop/security/getGroup.c \
-
src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c
+
src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c \
+
src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c
libhadoop_la_LDFLAGS = -version-info 1:0:0
libhadoop_la_LIBADD = -ldl -ljvm
@@ -326,6 +327,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@
@am__quote@./$(DEPDIR)/JniBasedUnixGroupsMapping.Plo@am__quote@
+@AMDEP_TRUE@@am__include@
@am__quote@./$(DEPDIR)/JniBasedUnixGroupsNetgroupMapping.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ZlibCompressor.Plo@am__quote@
@AMDEP_TRUE@@am__include@
@am__quote@./$(DEPDIR)/ZlibDecompressor.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getGroup.Plo@am__quote@
@@ -379,6 +381,13 @@ JniBasedUnixGroupsMapping.lo: src/org/ap
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE)
$(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS)
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS)
$(CFLAGS) -c -o JniBasedUnixGroupsMapping.lo `test -f
'src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c' || echo
'$(srcdir)/'`src/org/apache/hadoop/security/JniBasedUnixGroupsMapping.c
+JniBasedUnixGroupsNetgroupMapping.lo:
src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS)
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS)
$(CFLAGS) -MT JniBasedUnixGroupsNetgroupMapping.lo -MD -MP -MF
"$(DEPDIR)/JniBasedUnixGroupsNetgroupMapping.Tpo" -c -o
JniBasedUnixGroupsNetgroupMapping.lo `test -f
'src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c' || echo
'$(srcdir)/'`src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c;
\
+@am__fastdepCC_TRUE@ then mv -f
"$(DEPDIR)/JniBasedUnixGroupsNetgroupMapping.Tpo"
"$(DEPDIR)/JniBasedUnixGroupsNetgroupMapping.Plo"; else rm -f
"$(DEPDIR)/JniBasedUnixGroupsNetgroupMapping.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@
source='src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c'
object='JniBasedUnixGroupsNetgroupMapping.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE)
$(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS)
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS)
$(CFLAGS) -c -o JniBasedUnixGroupsNetgroupMapping.lo `test -f
'src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c' || echo
'$(srcdir)/'`src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c
+
mostlyclean-libtool:
-rm -f *.lo
Added:
hadoop/common/branches/branch-0.20-security-patches/src/native/src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c
URL:
http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/native/src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c?rev=1077593&view=auto
==============================================================================
---
hadoop/common/branches/branch-0.20-security-patches/src/native/src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c
(added)
+++
hadoop/common/branches/branch-0.20-security-patches/src/native/src/org/apache/hadoop/security/JniBasedUnixGroupsNetgroupMapping.c
Fri Mar 4 04:33:04 2011
@@ -0,0 +1,138 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <jni.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <string.h>
+
+#include <netdb.h>
+
+#include "org_apache_hadoop_security_JniBasedUnixGroupsNetgroupMapping.h"
+#include "org_apache_hadoop.h"
+
+struct listElement {
+ char * string;
+ struct listElement * next;
+};
+
+typedef struct listElement UserList;
+
+JNIEXPORT jobjectArray JNICALL
+Java_org_apache_hadoop_security_JniBasedUnixGroupsNetgroupMapping_getUsersForNetgroupJNI
+(JNIEnv *env, jobject jobj, jstring jgroup) {
+
+ // pointers to free at the end
+ const char *cgroup = NULL;
+ jobjectArray jusers = NULL;
+
+ // do we need to end the group lookup?
+ int setnetgrentCalledFlag = 0;
+
+ // if not NULL then THROW exception
+ char *errorMessage = NULL;
+
+ cgroup = (*env)->GetStringUTFChars(env, jgroup, NULL);
+ if (cgroup == NULL) {
+ goto END;
+ }
+
+ //--------------------------------------------------
+ // get users
+ // see man pages for setnetgrent, getnetgrent and endnetgrent
+
+ UserList *userListHead = NULL;
+ int userListSize = 0;
+
+ // set the name of the group for subsequent calls to getnetgrent
+ // note that we want to end group lokup regardless whether setnetgrent
+ // was successfull or not (as long as it was called we need to call
+ // endnetgrent)
+ setnetgrentCalledFlag = 1;
+ if(setnetgrent(cgroup) == 1) {
+ UserList *current = NULL;
+ // three pointers are for host, user, domain, we only care
+ // about user now
+ char *p[3];
+ while(getnetgrent(p, p + 1, p + 2)) {
+ if(p[1]) {
+ current = (UserList *)malloc(sizeof(UserList));
+ current->string = malloc(strlen(p[1]) + 1);
+ strcpy(current->string, p[1]);
+ current->next = userListHead;
+ userListHead = current;
+ userListSize++;
+ }
+ }
+ }
+
+ //--------------------------------------------------
+ // build return data (java array)
+
+ jusers = (jobjectArray)(*env)->NewObjectArray(env,
+ userListSize,
+ (*env)->FindClass(env, "java/lang/String"),
+ NULL);
+ if (jusers == NULL) {
+ errorMessage = "java/lang/OutOfMemoryError";
+ goto END;
+ }
+
+ UserList * current = NULL;
+
+ // note that the loop iterates over list but also over array (i)
+ int i = 0;
+ for(current = userListHead; current != NULL; current = current->next) {
+ jstring juser = (*env)->NewStringUTF(env, current->string);
+ if (juser == NULL) {
+ errorMessage = "java/lang/OutOfMemoryError";
+ goto END;
+ }
+ (*env)->SetObjectArrayElement(env, jusers, i++, juser);
+ }
+
+
+END:
+
+ // cleanup
+ if(cgroup) { (*env)->ReleaseStringUTFChars(env, jgroup, cgroup); }
+ if(setnetgrentCalledFlag) { endnetgrent(); }
+ while(userListHead) {
+ UserList *current = userListHead;
+ userListHead = userListHead->next;
+ if(current->string) { free(current->string); }
+ free(current);
+ }
+
+ // return results or THROW
+ if(errorMessage) {
+ THROW(env, errorMessage, NULL);
+ return NULL;
+ } else {
+ return jusers;
+ }
+}