HADOOP-9439. JniBasedUnixGroupsMapping: fix some crash bugs (Colin Patrick McCabe)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1496112 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
87d67c8c55
commit
ca35235b04
|
@ -551,6 +551,9 @@ Release 2.1.0-beta - UNRELEASED
|
||||||
HADOOP-9624. TestFSMainOperationsLocalFileSystem failed when the Hadoop test
|
HADOOP-9624. TestFSMainOperationsLocalFileSystem failed when the Hadoop test
|
||||||
root path has "X" in its name. (Xi Fang via cnauroth)
|
root path has "X" in its name. (Xi Fang via cnauroth)
|
||||||
|
|
||||||
|
HADOOP-9439. JniBasedUnixGroupsMapping: fix some crash bugs (Colin Patrick
|
||||||
|
McCabe)
|
||||||
|
|
||||||
BREAKDOWN OF HADOOP-8562 SUBTASKS AND RELATED JIRAS
|
BREAKDOWN OF HADOOP-8562 SUBTASKS AND RELATED JIRAS
|
||||||
|
|
||||||
HADOOP-8924. Hadoop Common creating package-info.java must not depend on
|
HADOOP-8924. Hadoop Common creating package-info.java must not depend on
|
||||||
|
|
|
@ -180,7 +180,8 @@ add_dual_library(hadoop
|
||||||
${D}/net/unix/DomainSocket.c
|
${D}/net/unix/DomainSocket.c
|
||||||
${D}/security/JniBasedUnixGroupsMapping.c
|
${D}/security/JniBasedUnixGroupsMapping.c
|
||||||
${D}/security/JniBasedUnixGroupsNetgroupMapping.c
|
${D}/security/JniBasedUnixGroupsNetgroupMapping.c
|
||||||
${D}/security/getGroup.c
|
${D}/security/hadoop_group_info.c
|
||||||
|
${D}/security/hadoop_user_info.c
|
||||||
${D}/util/NativeCodeLoader.c
|
${D}/util/NativeCodeLoader.c
|
||||||
${D}/util/NativeCrc32.c
|
${D}/util/NativeCrc32.c
|
||||||
${D}/util/bulk_crc32.c
|
${D}/util/bulk_crc32.c
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class NativeIO {
|
||||||
|
|
||||||
static final String WORKAROUND_NON_THREADSAFE_CALLS_KEY =
|
static final String WORKAROUND_NON_THREADSAFE_CALLS_KEY =
|
||||||
"hadoop.workaround.non.threadsafe.getpwuid";
|
"hadoop.workaround.non.threadsafe.getpwuid";
|
||||||
static final boolean WORKAROUND_NON_THREADSAFE_CALLS_DEFAULT = false;
|
static final boolean WORKAROUND_NON_THREADSAFE_CALLS_DEFAULT = true;
|
||||||
|
|
||||||
private static long cacheTimeout = -1;
|
private static long cacheTimeout = -1;
|
||||||
|
|
||||||
|
|
|
@ -40,22 +40,44 @@ public class JniBasedUnixGroupsMapping implements GroupMappingServiceProvider {
|
||||||
|
|
||||||
private static final Log LOG =
|
private static final Log LOG =
|
||||||
LogFactory.getLog(JniBasedUnixGroupsMapping.class);
|
LogFactory.getLog(JniBasedUnixGroupsMapping.class);
|
||||||
|
|
||||||
native String[] getGroupForUser(String user);
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
if (!NativeCodeLoader.isNativeCodeLoaded()) {
|
if (!NativeCodeLoader.isNativeCodeLoaded()) {
|
||||||
throw new RuntimeException("Bailing out since native library couldn't " +
|
throw new RuntimeException("Bailing out since native library couldn't " +
|
||||||
"be loaded");
|
"be loaded");
|
||||||
}
|
}
|
||||||
|
anchorNative();
|
||||||
LOG.debug("Using JniBasedUnixGroupsMapping for Group resolution");
|
LOG.debug("Using JniBasedUnixGroupsMapping for Group resolution");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up our JNI resources.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if setup fails.
|
||||||
|
*/
|
||||||
|
native static void anchorNative();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the set of groups associated with a user.
|
||||||
|
*
|
||||||
|
* @param username The user name
|
||||||
|
*
|
||||||
|
* @return The set of groups associated with a user.
|
||||||
|
*/
|
||||||
|
native static String[] getGroupsForUser(String username);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an error message about a group. Used from JNI.
|
||||||
|
*/
|
||||||
|
static private void logError(int groupId, String error) {
|
||||||
|
LOG.error("error looking up the name of group " + groupId + ": " + error);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String user) throws IOException {
|
public List<String> getGroups(String user) throws IOException {
|
||||||
String[] groups = new String[0];
|
String[] groups = new String[0];
|
||||||
try {
|
try {
|
||||||
groups = getGroupForUser(user);
|
groups = getGroupsForUser(user);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("Error getting groups for " + user, e);
|
LOG.debug("Error getting groups for " + user, e);
|
||||||
|
|
|
@ -107,3 +107,12 @@ jthrowable newIOException(JNIEnv* env, const char *fmt, ...)
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return jthr;
|
return jthr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* terror(int errnum)
|
||||||
|
{
|
||||||
|
if ((errnum < 0) || (errnum >= sys_nerr)) {
|
||||||
|
return "unknown error.";
|
||||||
|
}
|
||||||
|
return sys_errlist[errnum];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,4 +79,12 @@ jthrowable newRuntimeException(JNIEnv* env, const char *fmt, ...)
|
||||||
jthrowable newIOException(JNIEnv* env, const char *fmt, ...)
|
jthrowable newIOException(JNIEnv* env, const char *fmt, ...)
|
||||||
__attribute__((format(printf, 2, 3)));
|
__attribute__((format(printf, 2, 3)));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread-safe strerror alternative.
|
||||||
|
*
|
||||||
|
* @param errnum Error number.
|
||||||
|
* @return Statically allocated error string.
|
||||||
|
*/
|
||||||
|
const char* terror(int errnum);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -59,7 +59,7 @@ static jmethodID nioe_ctor;
|
||||||
// the monitor used for working around non-threadsafe implementations
|
// the monitor used for working around non-threadsafe implementations
|
||||||
// of getpwuid_r, observed on platforms including RHEL 6.0.
|
// of getpwuid_r, observed on platforms including RHEL 6.0.
|
||||||
// Please see HADOOP-7156 for details.
|
// Please see HADOOP-7156 for details.
|
||||||
static jobject pw_lock_object;
|
jobject pw_lock_object;
|
||||||
|
|
||||||
// Internal functions
|
// Internal functions
|
||||||
static void throw_ioe(JNIEnv* env, int errnum);
|
static void throw_ioe(JNIEnv* env, int errnum);
|
||||||
|
|
|
@ -107,14 +107,6 @@ static jthrowable newSocketException(JNIEnv *env, int errnum,
|
||||||
return jthr;
|
return jthr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* terror(int errnum)
|
|
||||||
{
|
|
||||||
if ((errnum < 0) || (errnum >= sys_nerr)) {
|
|
||||||
return "unknown error.";
|
|
||||||
}
|
|
||||||
return sys_errlist[errnum];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flexible buffer that will try to fit data on the stack, and fall back
|
* Flexible buffer that will try to fit data on the stack, and fall back
|
||||||
* to the heap if necessary.
|
* to the heap if necessary.
|
||||||
|
|
|
@ -30,88 +30,173 @@
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "exception.h"
|
||||||
#include "org_apache_hadoop_security_JniBasedUnixGroupsMapping.h"
|
#include "org_apache_hadoop_security_JniBasedUnixGroupsMapping.h"
|
||||||
#include "org_apache_hadoop.h"
|
#include "org_apache_hadoop.h"
|
||||||
|
#include "hadoop_group_info.h"
|
||||||
|
#include "hadoop_user_info.h"
|
||||||
|
|
||||||
static jobjectArray emptyGroups = NULL;
|
static jmethodID g_log_error_method;
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL
|
static jclass g_string_clazz;
|
||||||
Java_org_apache_hadoop_security_JniBasedUnixGroupsMapping_getGroupForUser
|
|
||||||
(JNIEnv *env, jobject jobj, jstring juser) {
|
|
||||||
extern int getGroupIDList(const char *user, int *ngroups, gid_t **groups);
|
|
||||||
extern int getGroupDetails(gid_t group, char **grpBuf);
|
|
||||||
const char *cuser = NULL;
|
|
||||||
jobjectArray jgroups = NULL;
|
|
||||||
int error = -1;
|
|
||||||
|
|
||||||
if (emptyGroups == NULL) {
|
extern jobject pw_lock_object;
|
||||||
jobjectArray lEmptyGroups = (jobjectArray)(*env)->NewObjectArray(env, 0,
|
|
||||||
(*env)->FindClass(env, "java/lang/String"), NULL);
|
|
||||||
if (lEmptyGroups == NULL) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
emptyGroups = (*env)->NewGlobalRef(env, lEmptyGroups);
|
|
||||||
if (emptyGroups == NULL) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char *grpBuf = NULL;
|
|
||||||
cuser = (*env)->GetStringUTFChars(env, juser, NULL);
|
|
||||||
if (cuser == NULL) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Get the number of the groups, and their IDs, this user belongs to*/
|
JNIEXPORT void JNICALL
|
||||||
gid_t *groups = NULL;
|
Java_org_apache_hadoop_security_JniBasedUnixGroupsMapping_anchorNative(
|
||||||
int ngroups = 0;
|
JNIEnv *env, jclass clazz)
|
||||||
error = getGroupIDList(cuser, &ngroups, &groups);
|
{
|
||||||
if (error != 0) {
|
jobject string_clazz;
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
jgroups = (jobjectArray)(*env)->NewObjectArray(env, ngroups,
|
g_log_error_method = (*env)->GetStaticMethodID(env, clazz, "logError",
|
||||||
(*env)->FindClass(env, "java/lang/String"), NULL);
|
"(ILjava/lang/String;)V");
|
||||||
if (jgroups == NULL) {
|
if (!g_log_error_method) {
|
||||||
error = -1;
|
return; // an exception has been raised
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
string_clazz = (*env)->FindClass(env, "java/lang/String");
|
||||||
/*Iterate over the groupIDs and get the group structure for each*/
|
if (!string_clazz) {
|
||||||
int i = 0;
|
return; // an exception has been raised
|
||||||
for (i = 0; i < ngroups; i++) {
|
|
||||||
error = getGroupDetails(groups[i],&grpBuf);
|
|
||||||
if (error != 0) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
jstring jgrp = (*env)->NewStringUTF(env, ((struct group*)grpBuf)->gr_name);
|
|
||||||
if (jgrp == NULL) {
|
|
||||||
error = -1;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
(*env)->SetObjectArrayElement(env, jgroups,i,jgrp);
|
|
||||||
free(grpBuf);
|
|
||||||
grpBuf = NULL;
|
|
||||||
}
|
}
|
||||||
|
g_string_clazz = (*env)->NewGlobalRef(env, string_clazz);
|
||||||
cleanup:
|
if (!g_string_clazz) {
|
||||||
if (error == ENOMEM) {
|
jthrowable jthr = newRuntimeException(env,
|
||||||
THROW(env, "java/lang/OutOfMemoryError", NULL);
|
"JniBasedUnixGroupsMapping#anchorNative: failed to make "
|
||||||
}
|
"a global reference to the java.lang.String class\n");
|
||||||
if (error == ENOENT) {
|
(*env)->Throw(env, jthr);
|
||||||
THROW(env, "java/io/IOException", "No entry for user");
|
return;
|
||||||
}
|
|
||||||
if (groups != NULL) {
|
|
||||||
free(groups);
|
|
||||||
}
|
|
||||||
if (grpBuf != NULL) {
|
|
||||||
free(grpBuf);
|
|
||||||
}
|
|
||||||
if (cuser != NULL) {
|
|
||||||
(*env)->ReleaseStringUTFChars(env, juser, cuser);
|
|
||||||
}
|
|
||||||
if (error == 0) {
|
|
||||||
return jgroups;
|
|
||||||
} else {
|
|
||||||
return emptyGroups;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an error about a failure to look up a group ID
|
||||||
|
*
|
||||||
|
* @param env The JNI environment
|
||||||
|
* @param clazz JniBasedUnixGroupsMapping class
|
||||||
|
* @param gid The gid we failed to look up
|
||||||
|
* @param ret Failure code
|
||||||
|
*/
|
||||||
|
static void logError(JNIEnv *env, jclass clazz, jint gid, int ret)
|
||||||
|
{
|
||||||
|
jstring error_msg;
|
||||||
|
|
||||||
|
error_msg = (*env)->NewStringUTF(env, terror(ret));
|
||||||
|
if (!error_msg) {
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(*env)->CallStaticVoidMethod(env, clazz, g_log_error_method, gid, error_msg);
|
||||||
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(*env)->DeleteLocalRef(env, error_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL
|
||||||
|
Java_org_apache_hadoop_security_JniBasedUnixGroupsMapping_getGroupsForUser
|
||||||
|
(JNIEnv *env, jclass clazz, jstring jusername)
|
||||||
|
{
|
||||||
|
const char *username = NULL;
|
||||||
|
struct hadoop_user_info *uinfo = NULL;
|
||||||
|
struct hadoop_group_info *ginfo = NULL;
|
||||||
|
jstring jgroupname = NULL;
|
||||||
|
int i, ret, nvalid;
|
||||||
|
int pw_lock_locked = 0;
|
||||||
|
jobjectArray jgroups = NULL, jnewgroups = NULL;
|
||||||
|
|
||||||
|
if (pw_lock_object != NULL) {
|
||||||
|
if ((*env)->MonitorEnter(env, pw_lock_object) != JNI_OK) {
|
||||||
|
goto done; // exception thrown
|
||||||
|
}
|
||||||
|
pw_lock_locked = 1;
|
||||||
|
}
|
||||||
|
username = (*env)->GetStringUTFChars(env, jusername, NULL);
|
||||||
|
if (username == NULL) {
|
||||||
|
goto done; // exception thrown
|
||||||
|
}
|
||||||
|
uinfo = hadoop_user_info_alloc();
|
||||||
|
if (!uinfo) {
|
||||||
|
THROW(env, "java/lang/OutOfMemoryError", NULL);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ret = hadoop_user_info_fetch(uinfo, username);
|
||||||
|
if (ret == ENOENT) {
|
||||||
|
jgroups = (*env)->NewObjectArray(env, 0, g_string_clazz, NULL);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ginfo = hadoop_group_info_alloc();
|
||||||
|
if (!ginfo) {
|
||||||
|
THROW(env, "java/lang/OutOfMemoryError", NULL);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ret = hadoop_user_info_getgroups(uinfo);
|
||||||
|
if (ret) {
|
||||||
|
if (ret == ENOMEM) {
|
||||||
|
THROW(env, "java/lang/OutOfMemoryError", NULL);
|
||||||
|
} else {
|
||||||
|
char buf[128];
|
||||||
|
snprintf(buf, sizeof(buf), "getgrouplist error %d (%s)",
|
||||||
|
ret, terror(ret));
|
||||||
|
THROW(env, "java/lang/RuntimeException", buf);
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
jgroups = (jobjectArray)(*env)->NewObjectArray(env, uinfo->num_gids,
|
||||||
|
g_string_clazz, NULL);
|
||||||
|
for (nvalid = 0, i = 0; i < uinfo->num_gids; i++) {
|
||||||
|
ret = hadoop_group_info_fetch(ginfo, uinfo->gids[i]);
|
||||||
|
if (ret) {
|
||||||
|
logError(env, clazz, uinfo->gids[i], ret);
|
||||||
|
} else {
|
||||||
|
jgroupname = (*env)->NewStringUTF(env, ginfo->group.gr_name);
|
||||||
|
if (!jgroupname) { // exception raised
|
||||||
|
(*env)->DeleteLocalRef(env, jgroups);
|
||||||
|
jgroups = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
(*env)->SetObjectArrayElement(env, jgroups, nvalid++, jgroupname);
|
||||||
|
// We delete the local reference once the element is in the array.
|
||||||
|
// This is OK because the array has a reference to it.
|
||||||
|
// Technically JNI only mandates that the JVM allow up to 16 local
|
||||||
|
// references at a time (though many JVMs allow more than that.)
|
||||||
|
(*env)->DeleteLocalRef(env, jgroupname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nvalid != uinfo->num_gids) {
|
||||||
|
// If some group names could not be looked up, allocate a smaller array
|
||||||
|
// with just the entries that could be resolved. Java has no equivalent to
|
||||||
|
// realloc, so we have to do this manually.
|
||||||
|
jnewgroups = (jobjectArray)(*env)->NewObjectArray(env, nvalid,
|
||||||
|
(*env)->FindClass(env, "java/lang/String"), NULL);
|
||||||
|
if (!jnewgroups) { // exception raised
|
||||||
|
(*env)->DeleteLocalRef(env, jgroups);
|
||||||
|
jgroups = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
for (i = 0; i < nvalid; i++) {
|
||||||
|
jgroupname = (*env)->GetObjectArrayElement(env, jgroups, i);
|
||||||
|
(*env)->SetObjectArrayElement(env, jnewgroups, i, jgroupname);
|
||||||
|
(*env)->DeleteLocalRef(env, jgroupname);
|
||||||
|
}
|
||||||
|
(*env)->DeleteLocalRef(env, jgroups);
|
||||||
|
jgroups = jnewgroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (pw_lock_locked) {
|
||||||
|
(*env)->MonitorExit(env, pw_lock_object);
|
||||||
|
}
|
||||||
|
if (username) {
|
||||||
|
(*env)->ReleaseStringUTFChars(env, jusername, username);
|
||||||
|
}
|
||||||
|
if (uinfo) {
|
||||||
|
hadoop_user_info_free(uinfo);
|
||||||
|
}
|
||||||
|
if (ginfo) {
|
||||||
|
hadoop_group_info_free(ginfo);
|
||||||
|
}
|
||||||
|
if (jgroupname) {
|
||||||
|
(*env)->DeleteLocalRef(env, jgroupname);
|
||||||
|
}
|
||||||
|
return jgroups;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,13 @@
|
||||||
|
|
||||||
static jobjectArray emptyGroups = NULL;
|
static jobjectArray emptyGroups = NULL;
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_apache_hadoop_security_JniBasedUnixGroupsMapping_anchorNative(
|
||||||
|
JNIEnv *env, jclass clazz)
|
||||||
|
{
|
||||||
|
// no-op until full port of HADOOP-9439 to Windows is available
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Throw a java.IO.IOException, generating the message from errno.
|
* Throw a java.IO.IOException, generating the message from errno.
|
||||||
*/
|
*/
|
||||||
|
@ -57,8 +64,8 @@ static void throw_ioexception(JNIEnv* env, DWORD errnum)
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL
|
JNIEXPORT jobjectArray JNICALL
|
||||||
Java_org_apache_hadoop_security_JniBasedUnixGroupsMapping_getGroupForUser
|
Java_org_apache_hadoop_security_JniBasedUnixGroupsMapping_getGroupsForUser
|
||||||
(JNIEnv *env, jobject jobj, jstring juser) {
|
(JNIEnv *env, jclass clazz, jstring juser) {
|
||||||
const WCHAR *user = NULL;
|
const WCHAR *user = NULL;
|
||||||
jobjectArray jgroups = NULL;
|
jobjectArray jgroups = NULL;
|
||||||
DWORD dwRtnCode = ERROR_SUCCESS;
|
DWORD dwRtnCode = ERROR_SUCCESS;
|
||||||
|
|
|
@ -1,189 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 <grp.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/*Helper functions for the JNI implementation of unix group mapping service*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the group IDs for a given user. The groups argument is allocated
|
|
||||||
* internally, and it contains the list of groups. The ngroups is updated to
|
|
||||||
* the number of groups
|
|
||||||
* Returns 0 on success (on success, the caller must free the memory allocated
|
|
||||||
* internally)
|
|
||||||
*/
|
|
||||||
int getGroupIDList(const char *user, int *ngroups, gid_t **groups) {
|
|
||||||
int getPW(const char *user, char **pwbuf);
|
|
||||||
*ngroups = 0;
|
|
||||||
char *pwbuf = NULL;
|
|
||||||
*groups = NULL;
|
|
||||||
/*Look up the password database first*/
|
|
||||||
int error = getPW(user, &pwbuf);
|
|
||||||
if (error != 0) {
|
|
||||||
if (pwbuf != NULL) {
|
|
||||||
free(pwbuf);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
struct passwd *pw = (struct passwd*)pwbuf;
|
|
||||||
int ng = 0;
|
|
||||||
/*Get the groupIDs that this user belongs to*/
|
|
||||||
if (getgrouplist(user, pw->pw_gid, NULL, &ng) < 0) {
|
|
||||||
*ngroups = ng;
|
|
||||||
*groups = (gid_t *) malloc(ng * sizeof (gid_t));
|
|
||||||
if (!*groups) {
|
|
||||||
*ngroups = 0;
|
|
||||||
free(pwbuf);
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
if (getgrouplist(user, pw->pw_gid, *groups, &ng) < 0) {
|
|
||||||
*ngroups = 0;
|
|
||||||
free(pwbuf);
|
|
||||||
free(*groups);
|
|
||||||
*groups = NULL;
|
|
||||||
return ENOENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(pwbuf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the group structure for a given group ID.
|
|
||||||
* The grpBuf argument is allocated internally and it contains the
|
|
||||||
* struct group for the given group ID.
|
|
||||||
* Returns 0 on success (on success, the caller must free the memory allocated
|
|
||||||
* internally)
|
|
||||||
*/
|
|
||||||
int getGroupDetails(gid_t group, char **grpBuf) {
|
|
||||||
struct group * grp = NULL;
|
|
||||||
long currBufferSize = sysconf(_SC_GETGR_R_SIZE_MAX);
|
|
||||||
if (currBufferSize < 1024) {
|
|
||||||
currBufferSize = 1024;
|
|
||||||
}
|
|
||||||
*grpBuf = NULL;
|
|
||||||
char *buf = (char*)malloc(sizeof(char) * currBufferSize);
|
|
||||||
|
|
||||||
if (!buf) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
int error;
|
|
||||||
for (;;) {
|
|
||||||
error = getgrgid_r(group, (struct group*)buf,
|
|
||||||
buf + sizeof(struct group),
|
|
||||||
currBufferSize - sizeof(struct group), &grp);
|
|
||||||
if(error != ERANGE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
currBufferSize *= 2;
|
|
||||||
buf = malloc(sizeof(char) * currBufferSize);
|
|
||||||
if(!buf) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!grp && !error) {
|
|
||||||
free(buf);
|
|
||||||
return ENOENT;
|
|
||||||
} else if (error) {
|
|
||||||
free(buf);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
*grpBuf = buf;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the password database entry for a given user.
|
|
||||||
* The pwbuf argument is allocated internally and it contains the
|
|
||||||
* broken out fields for the password database entry
|
|
||||||
* Returns 0 on success (on success, the caller must free the memory allocated
|
|
||||||
* internally).
|
|
||||||
*/
|
|
||||||
int getPW(const char *user, char **pwbuf) {
|
|
||||||
struct passwd *pwbufp = NULL;
|
|
||||||
long currBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
|
|
||||||
if (currBufferSize < 1024) {
|
|
||||||
currBufferSize = 1024;
|
|
||||||
}
|
|
||||||
*pwbuf = NULL;
|
|
||||||
char *buf = (char*)malloc(sizeof(char) * currBufferSize);
|
|
||||||
|
|
||||||
if (!buf) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
int error;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
error = getpwnam_r(user, (struct passwd*)buf, buf + sizeof(struct passwd),
|
|
||||||
currBufferSize - sizeof(struct passwd), &pwbufp);
|
|
||||||
if (error != ERANGE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
currBufferSize *= 2;
|
|
||||||
buf = (char*)malloc(sizeof(char) * currBufferSize);
|
|
||||||
if (!buf) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pwbufp && !error) {
|
|
||||||
free(buf);
|
|
||||||
return ENOENT;
|
|
||||||
} else if (error) {
|
|
||||||
free(buf);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
*pwbuf = buf;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef TESTING
|
|
||||||
|
|
||||||
#ifdef TESTING
|
|
||||||
/**
|
|
||||||
* A main() is provided so that quick testing of this
|
|
||||||
* library can be done.
|
|
||||||
*/
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
int ngroups;
|
|
||||||
gid_t *groups = NULL;
|
|
||||||
char *user = "ddas";
|
|
||||||
if (argc == 2) user = argv[1];
|
|
||||||
int error = getGroupIDList(user, &ngroups, &groups);
|
|
||||||
if (error != 0) {
|
|
||||||
printf("Couldn't obtain grp for user %s", user);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < ngroups; i++) {
|
|
||||||
char *grpbuf = NULL;
|
|
||||||
error = getGroupDetails(groups[i], &grpbuf);
|
|
||||||
printf("grps[%d]: %s ",i, ((struct group*)grpbuf)->gr_name);
|
|
||||||
free(grpbuf);
|
|
||||||
}
|
|
||||||
free(groups);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
/**
|
||||||
|
* 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 "hadoop_group_info.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct hadoop_group_info *hadoop_group_info_alloc(void)
|
||||||
|
{
|
||||||
|
struct hadoop_group_info *ginfo;
|
||||||
|
size_t buf_sz;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
ginfo = calloc(1, sizeof(struct hadoop_group_info));
|
||||||
|
buf_sz = sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||||
|
if (buf_sz < 1024) {
|
||||||
|
buf_sz = 1024;
|
||||||
|
}
|
||||||
|
buf = malloc(buf_sz);
|
||||||
|
if (!buf) {
|
||||||
|
free(ginfo);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ginfo->buf_sz = buf_sz;
|
||||||
|
ginfo->buf = buf;
|
||||||
|
return ginfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hadoop_group_info_clear(struct hadoop_group_info *ginfo)
|
||||||
|
{
|
||||||
|
struct group *group = &ginfo->group;
|
||||||
|
|
||||||
|
group->gr_name = NULL;
|
||||||
|
group->gr_passwd = NULL;
|
||||||
|
group->gr_gid = 0;
|
||||||
|
group->gr_mem = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hadoop_group_info_free(struct hadoop_group_info *ginfo)
|
||||||
|
{
|
||||||
|
free(ginfo->buf);
|
||||||
|
free(ginfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Different platforms use different error codes to represent "group not found."
|
||||||
|
* So whitelist the errors which do _not_ mean "group not found."
|
||||||
|
*
|
||||||
|
* @param err The errno
|
||||||
|
*
|
||||||
|
* @return The error code to use
|
||||||
|
*/
|
||||||
|
static int getgrgid_error_translate(int err)
|
||||||
|
{
|
||||||
|
if ((err == EIO) || (err == EMFILE) || (err == ENFILE) ||
|
||||||
|
(err == ENOMEM) || (err == ERANGE)) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hadoop_group_info_fetch(struct hadoop_group_info *ginfo, gid_t gid)
|
||||||
|
{
|
||||||
|
struct group *group;
|
||||||
|
int err;
|
||||||
|
size_t buf_sz;
|
||||||
|
char *nbuf;
|
||||||
|
|
||||||
|
hadoop_group_info_clear(ginfo);
|
||||||
|
for (;;) {
|
||||||
|
do {
|
||||||
|
group = NULL;
|
||||||
|
err = getgrgid_r(gid, &ginfo->group, ginfo->buf,
|
||||||
|
ginfo->buf_sz, &group);
|
||||||
|
} while ((!group) && (err == EINTR));
|
||||||
|
if (group) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (err != ERANGE) {
|
||||||
|
return getgrgid_error_translate(errno);
|
||||||
|
}
|
||||||
|
buf_sz = ginfo->buf_sz * 2;
|
||||||
|
nbuf = realloc(ginfo->buf, buf_sz);
|
||||||
|
if (!nbuf) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
ginfo->buf = nbuf;
|
||||||
|
ginfo->buf_sz = buf_sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GROUP_TESTING
|
||||||
|
/**
|
||||||
|
* A main() is provided so that quick testing of this
|
||||||
|
* library can be done.
|
||||||
|
*/
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
char **groupname;
|
||||||
|
struct hadoop_group_info *ginfo;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ginfo = hadoop_group_info_alloc();
|
||||||
|
if (!ginfo) {
|
||||||
|
fprintf(stderr, "hadoop_group_info_alloc returned NULL.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
for (groupname = argv + 1; *groupname; groupname++) {
|
||||||
|
gid_t gid = atoi(*groupname);
|
||||||
|
if (gid == 0) {
|
||||||
|
fprintf(stderr, "won't accept non-parseable group-name or gid 0: %s\n",
|
||||||
|
*groupname);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
ret = hadoop_group_info_fetch(ginfo, gid);
|
||||||
|
if (!ret) {
|
||||||
|
fprintf(stderr, "gid[%lld] : gr_name = %s\n",
|
||||||
|
(long long)gid, ginfo->group.gr_name);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "group[%lld] : error %d (%s)\n",
|
||||||
|
(long long)gid, ret, strerror(ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hadoop_group_info_free(ginfo);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef HADOOP_GROUP_INFO_DOT_H
|
||||||
|
#define HADOOP_GROUP_INFO_DOT_H
|
||||||
|
|
||||||
|
#include <grp.h> /* for struct group */
|
||||||
|
#include <unistd.h> /* for size_t */
|
||||||
|
|
||||||
|
struct hadoop_group_info {
|
||||||
|
size_t buf_sz;
|
||||||
|
struct group group;
|
||||||
|
char *buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a hadoop group info context.
|
||||||
|
*
|
||||||
|
* @return NULL on OOM; the context otherwise.
|
||||||
|
*/
|
||||||
|
struct hadoop_group_info *hadoop_group_info_alloc(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a hadoop group info context.
|
||||||
|
*
|
||||||
|
* @param uinfo The hadoop group info context to free.
|
||||||
|
*/
|
||||||
|
void hadoop_group_info_free(struct hadoop_group_info *ginfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up information for a group id.
|
||||||
|
*
|
||||||
|
* @param uinfo The hadoop group info context.
|
||||||
|
* Existing data in this context will be cleared.
|
||||||
|
* @param gid The group id to look up.
|
||||||
|
*
|
||||||
|
* @return ENOENT if the group wasn't found;
|
||||||
|
* 0 on success;
|
||||||
|
* EIO, EMFILE, ENFILE, or ENOMEM if appropriate.
|
||||||
|
*/
|
||||||
|
int hadoop_group_info_fetch(struct hadoop_group_info *ginfo, gid_t gid);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,203 @@
|
||||||
|
/**
|
||||||
|
* 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 "hadoop_user_info.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define INITIAL_GIDS_SIZE 32
|
||||||
|
|
||||||
|
struct hadoop_user_info *hadoop_user_info_alloc(void)
|
||||||
|
{
|
||||||
|
struct hadoop_user_info *uinfo;
|
||||||
|
size_t buf_sz;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
uinfo = calloc(1, sizeof(struct hadoop_user_info));
|
||||||
|
buf_sz = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||||
|
if (buf_sz < 1024) {
|
||||||
|
buf_sz = 1024;
|
||||||
|
}
|
||||||
|
buf = malloc(buf_sz);
|
||||||
|
if (!buf) {
|
||||||
|
free(uinfo);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
uinfo->buf_sz = buf_sz;
|
||||||
|
uinfo->buf = buf;
|
||||||
|
return uinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hadoop_user_info_clear(struct hadoop_user_info *uinfo)
|
||||||
|
{
|
||||||
|
struct passwd *pwd = &uinfo->pwd;
|
||||||
|
|
||||||
|
pwd->pw_name = NULL;
|
||||||
|
pwd->pw_uid = 0;
|
||||||
|
pwd->pw_gid = 0;
|
||||||
|
pwd->pw_passwd = NULL;
|
||||||
|
pwd->pw_gecos = NULL;
|
||||||
|
pwd->pw_dir = NULL;
|
||||||
|
pwd->pw_shell = NULL;
|
||||||
|
free(uinfo->gids);
|
||||||
|
uinfo->gids = 0;
|
||||||
|
uinfo->num_gids = 0;
|
||||||
|
uinfo->gids_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hadoop_user_info_free(struct hadoop_user_info *uinfo)
|
||||||
|
{
|
||||||
|
free(uinfo->buf);
|
||||||
|
hadoop_user_info_clear(uinfo);
|
||||||
|
free(uinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Different platforms use different error codes to represent "user not found."
|
||||||
|
* So whitelist the errors which do _not_ mean "user not found."
|
||||||
|
*
|
||||||
|
* @param err The errno
|
||||||
|
*
|
||||||
|
* @return The error code to use
|
||||||
|
*/
|
||||||
|
static int getpwnam_error_translate(int err)
|
||||||
|
{
|
||||||
|
if ((err == EIO) || (err == EMFILE) || (err == ENFILE) ||
|
||||||
|
(err == ENOMEM) || (err == ERANGE)) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hadoop_user_info_fetch(struct hadoop_user_info *uinfo,
|
||||||
|
const char *username)
|
||||||
|
{
|
||||||
|
struct passwd *pwd;
|
||||||
|
int err;
|
||||||
|
size_t buf_sz;
|
||||||
|
char *nbuf;
|
||||||
|
|
||||||
|
hadoop_user_info_clear(uinfo);
|
||||||
|
for (;;) {
|
||||||
|
do {
|
||||||
|
pwd = NULL;
|
||||||
|
err = getpwnam_r(username, &uinfo->pwd, uinfo->buf,
|
||||||
|
uinfo->buf_sz, &pwd);
|
||||||
|
} while ((!pwd) && (errno == EINTR));
|
||||||
|
if (pwd) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (err != ERANGE) {
|
||||||
|
return getpwnam_error_translate(errno);
|
||||||
|
}
|
||||||
|
buf_sz = uinfo->buf_sz * 2;
|
||||||
|
nbuf = realloc(uinfo->buf, buf_sz);
|
||||||
|
if (!nbuf) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
uinfo->buf = nbuf;
|
||||||
|
uinfo->buf_sz = buf_sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int hadoop_user_info_getgroups(struct hadoop_user_info *uinfo)
|
||||||
|
{
|
||||||
|
int ret, ngroups;
|
||||||
|
gid_t *ngids;
|
||||||
|
|
||||||
|
if (!uinfo->pwd.pw_name) {
|
||||||
|
return EINVAL; // invalid user info
|
||||||
|
}
|
||||||
|
uinfo->num_gids = 0;
|
||||||
|
if (!uinfo->gids) {
|
||||||
|
uinfo->gids = malloc(sizeof(uinfo->gids[0]) * INITIAL_GIDS_SIZE);
|
||||||
|
if (!uinfo->gids) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
uinfo->gids_size = INITIAL_GIDS_SIZE;
|
||||||
|
}
|
||||||
|
ngroups = uinfo->gids_size;
|
||||||
|
ret = getgrouplist(uinfo->pwd.pw_name, uinfo->pwd.pw_gid,
|
||||||
|
uinfo->gids, &ngroups);
|
||||||
|
if (ret != -1) {
|
||||||
|
uinfo->num_gids = ngroups;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ngids = realloc(uinfo->gids, sizeof(uinfo->gids[0]) * ngroups);
|
||||||
|
if (!ngids) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
uinfo->gids = ngids;
|
||||||
|
uinfo->gids_size = ngroups;
|
||||||
|
ret = getgrouplist(uinfo->pwd.pw_name, uinfo->pwd.pw_gid,
|
||||||
|
uinfo->gids, &ngroups);
|
||||||
|
if (ret != -1) {
|
||||||
|
uinfo->num_gids = ngroups;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USER_TESTING
|
||||||
|
/**
|
||||||
|
* A main() is provided so that quick testing of this
|
||||||
|
* library can be done.
|
||||||
|
*/
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
char **username, *prefix;
|
||||||
|
struct hadoop_user_info *uinfo;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
uinfo = hadoop_user_info_alloc();
|
||||||
|
if (!uinfo) {
|
||||||
|
fprintf(stderr, "hadoop_user_info_alloc returned NULL.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
for (username = argv + 1; *username; username++) {
|
||||||
|
ret = hadoop_user_info_fetch(uinfo, *username);
|
||||||
|
if (!ret) {
|
||||||
|
fprintf(stderr, "user[%s] : pw_uid = %lld\n",
|
||||||
|
*username, (long long)uinfo->pwd.pw_uid);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "user[%s] : error %d (%s)\n",
|
||||||
|
*username, ret, strerror(ret));
|
||||||
|
}
|
||||||
|
ret = hadoop_user_info_getgroups(uinfo);
|
||||||
|
if (!ret) {
|
||||||
|
fprintf(stderr, " getgroups: ");
|
||||||
|
prefix = "";
|
||||||
|
for (i = 0; i < uinfo->num_gids; i++) {
|
||||||
|
fprintf(stderr, "%s%lld", prefix, (long long)uinfo->gids[i]);
|
||||||
|
prefix = ", ";
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, " getgroups: error %d\n", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hadoop_user_info_free(uinfo);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef HADOOP_USER_INFO_DOT_H
|
||||||
|
#define HADOOP_USER_INFO_DOT_H
|
||||||
|
|
||||||
|
#include <pwd.h> /* for struct passwd */
|
||||||
|
#include <unistd.h> /* for size_t */
|
||||||
|
|
||||||
|
struct hadoop_user_info {
|
||||||
|
size_t buf_sz;
|
||||||
|
struct passwd pwd;
|
||||||
|
char *buf;
|
||||||
|
gid_t *gids;
|
||||||
|
int num_gids;
|
||||||
|
int gids_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a hadoop user info context.
|
||||||
|
*
|
||||||
|
* @return NULL on OOM; the context otherwise.
|
||||||
|
*/
|
||||||
|
struct hadoop_user_info *hadoop_user_info_alloc(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a hadoop user info context.
|
||||||
|
*
|
||||||
|
* @param uinfo The hadoop user info context to free.
|
||||||
|
*/
|
||||||
|
void hadoop_user_info_free(struct hadoop_user_info *uinfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up information for a user name.
|
||||||
|
*
|
||||||
|
* @param uinfo The hadoop user info context.
|
||||||
|
* Existing data in this context will be cleared.
|
||||||
|
* @param username The user name to look up.
|
||||||
|
*
|
||||||
|
* @return ENOENT if the user wasn't found;
|
||||||
|
* 0 on success;
|
||||||
|
* EIO, EMFILE, ENFILE, or ENOMEM if appropriate.
|
||||||
|
*/
|
||||||
|
int hadoop_user_info_fetch(struct hadoop_user_info *uinfo,
|
||||||
|
const char *username);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up the groups this user belongs to.
|
||||||
|
*
|
||||||
|
* @param uinfo The hadoop user info context.
|
||||||
|
* uinfo->gids will be filled in on a successful
|
||||||
|
* return;
|
||||||
|
*
|
||||||
|
* @return 0 on success.
|
||||||
|
* ENOMEM if we ran out of memory.
|
||||||
|
* EINVAL if the uinfo was invalid.
|
||||||
|
*/
|
||||||
|
int hadoop_user_info_getgroups(struct hadoop_user_info *uinfo);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue