hdfs_connect_as_user.c

This application demonstrates how to create and write to files impersonating another user by using the API hdfsConnectAsUser().

Before running this application, ensure that you have access to a cluster running MapR file system.

To build and run it, download it from this page and copy it to a MapR client or to a system with the mapr-core package installed. Then, modify the run.sh script in Building and Running C Applications on MapR Filesystem Clients to point to this sample application. Run the script and then run the application.

The application includes these header files:

  • stdio.h
  • hdfs.h
  • stdlib.h
  • string.h
Note: The impersonation APIs are defined in hdfs.h.

The application performs the actions that are described in the following sections.

Takes two usernames and a hostname as input

After compiling the application, type the following command to launch the application and pass in the two usernames (to impersonate) and host name:

hdfs_connect_as_user <username1> <username2> <hostname>if (argc < 4) {
  fprintf (stderr, "Provide two usernames to impersonate and the host name\n");
  printf ("USAGE: ./hdfs_connect_as_user mapruser1 mapruser2 10.10.xx.xxx\n");
  exit(EXIT_FAILURE);
}
Stores the values of the arguments

The application stores the values of the arguments in character arrays. The application uses the port, 7222, to connect to the given host, and uses character arrays for user directory and file path.

char *impersonate_user1 = argv[1];
char *impersonate_user2 = argv[2];
char *host_addr = argv[3];
int port_num = 7222;
char user1_dir[100];
char writePath[100];
int ret_val;
Populates the directory path and file path

The application creates a default path for the user directory and file.

sprintf(user1_dir, "/tmp/%s_dir", impersonate_user1);
sprintf(writePath, "%s/test_file", user1_dir);
Sets an RPC timeout

The hdfsSetRpcTimeout() is specific to the libMapRClient version of libhdfs and takes a value that is specified in seconds. The default is 99 seconds. If you change this value, set it either to 0 (which eliminates timeouts) or to a value greater than 30.

int err = hdfsSetRpcTimeout(30);
if (err) {
  fprintf(stderr, "Failed to set rpc timeout!\n");
  exit(-1);
}
Connects to the filesystem as the impersonated user

The application connects to the filesystem as the impersonated user (<username1>) using hdfsConnectAsUser(). If successful, this operation returns a handle to the filesystem.

printf("Impersonate user: %s\n", impersonate_user1);
printf("Connecting using hdfsConnectAsUser() as user %s\n", impersonate_user1);
hdfsFS fs_handle = hdfsConnectAsUser(host_addr, port_num, impersonate_user1);
if (fs_handle == NULL) {
    printf("hdfsConnectAsUser() failed.\n");
    exit(EXIT_FAILURE);
}
Creates a directory as the impersonated user

The application creates a directory under /tmp as the impersonated user (<username1>).

printf("User1: Create a directory : %s\n", user1_dir);
ret_val = hdfsCreateDirectory(fs_handle, user1_dir);
if (ret_val != EXIT_SUCCESS) {
  printf("hdfsCreateDirectory() failed.\n");
  exit(EXIT_FAILURE);
}
Creates and opens a file
The application creates a file and opens the file, passing the following values to the hdfsOpenFile() function:
  • The handle to the filesystem.
  • A flag to indicate the mode in which to open the file. In this case, the flag is O_WRONLY|O_CREAT. This flag creates the file and opens it for writing.

For more details, see hdfsOpenFile() documentation.

printf("User1: Create and write to the file as user1 : %s\n", writePath);
hdfsFile writeFile = hdfsOpenFile(fs_handle, writePath, O_WRONLY|O_CREAT, 0, 0, 0);
if(!writeFile) {
  printf("hdfsOpenFile() failed.\n");
  exit(EXIT_FAILURE);
}
Writes to the open file

The application writes to the open file as the impersonated user (<username1>).

char* buffer = "Hello, from user 1!";
tSize num_written_bytes = hdfsWrite(fs_handle, writeFile, (void*)buffer, strlen(buffer)+1);
if (hdfsFlush(fs_handle, writeFile)) {
  printf("failed to flush %s\n", writePath);
  exit(EXIT_FAILURE);
}
Closes the file

The application closes the file after successfully writing to the file as the impersonated user (<username1>).

printf("User1: Close file %s.\n", writePath);
hdfsCloseFile(fs_handle, writeFile);
Connects to the filesystem as the impersonating user

The application connects to the filesystem as the second user (<username2>) using hdfsConnectAsUser() and returns a handle to the filesystem.

printf("Impersonate user: %s\n", impersonate_user2);
printf("Connecting using hdfsConnectAsUser() as user %s\n", impersonate_user2);
hdfsFS fs_handle2 = hdfsConnectAsUser(host_addr, port_num, impersonate_user2);
if (fs_handle2 == NULL) {
  printf("hdfsConnectAsUser() failed.\n");
  exit(EXIT_FAILURE);
}
Tries to write to the file as the impersonating user

The application tries to open the file created by the impersonated user (<username1>) and write to the file as the impersonating user (<username2>). This operation fails as the impersonating user (<username2>) is denied access to the file created by the impersonated user (<username1>) and the application returns error EACCES.

printf("User2: Try opening file created by user1 for writing : %s\n", writePath); 
hdfsFile writeFile2 = hdfsOpenFile(fs_handle2, writePath, O_WRONLY, 0, 0, 0);
int errNum = errno; 
if(writeFile2) {
    printf("User2: hdfsOpenFile() should have failed for %s.\n", impersonate_user2);
    exit(EXIT_FAILURE);
} else {
    if (errNum == EACCES) {
        printf("User2: As expected hdfsOpenFile() with EACCES.\n"); 
    } else {
        printf("User2: hdfsOpenFile() failed with errno:%d expected %d.\n", errNum, EACCES);
        exit(EXIT_FAILURE);
    }
}
Deletes a directory

The application deletes a directory as the impersonated user (<username1>) using the filesystem handle created for this user.

printf("Delete directory : %s\n", user1_dir);
ret_val = hdfsDelete(fs_handle, user1_dir, 1);
if (ret_val != EXIT_SUCCESS) {
  printf("hdfsDelete() failed.\n");
  exit(EXIT_FAILURE);
}
Disconnects the impersonating user

The application disconnect the impersonating user (<username2>) from the filesystem.

printf("Disconnect the impersonation user2.\n");
ret_val = hdfsDisconnect(fs_handle2);
if (ret_val != EXIT_SUCCESS) {
  printf("hdfsDisconnect() failed.\n");
  exit(EXIT_FAILURE);
}
Disconnects the impersonated user

The application disconnect the impersonated user (<username1>) from the filesystem.

printf("Disconnect the impersonation user1.\n");
ret_val = hdfsDisconnect(fs_handle);
if (ret_val != EXIT_SUCCESS) {
  printf("hdfsDisconnect() failed.\n");
  exit(EXIT_FAILURE);
}
/**
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hdfs.h" 

int main(int argc, char *argv[]) {
    if (argc < 4) {
	fprintf (stderr, "Provide two usernames to impersonate and the host name\n");
	printf ("USAGE: ./connectAsUser mapruser1 mapruser2 10.10.xx.xxx\n");
	exit(EXIT_FAILURE);
    }

    char *impersonate_user1 = argv[1];
    char *impersonate_user2 = argv[2];
    char *host_addr = argv[3];
    int port_num = 7222;
    char user1_dir[100];
    char writePath[100];
    int ret_val;

    /* Populate the directory patha nd file path */
    sprintf(user1_dir, "/tmp/%s_dir", impersonate_user1);
    sprintf(writePath, "%s/test_file", user1_dir);

    /* Impersonate as user1 using hdfsConnectAsUser(). */
    printf("Impersonate user: %s\n", impersonate_user1);
    printf("Connecting using hdfsConnectAsUser() as user %s\n", impersonate_user1);
    hdfsFS fs_handle = hdfsConnectAsUser(host_addr, port_num, impersonate_user1);
    if (fs_handle == NULL) {
        printf("hdfsConnectAsUser() failed.\n");
	exit(EXIT_FAILURE);
    }

    /* Create a directory under /tmp. This is done as the impersonated user1. */
    printf("User1: Create a directory : %s\n", user1_dir);
    ret_val = hdfsCreateDirectory(fs_handle, user1_dir);
    if (ret_val != EXIT_SUCCESS) {
        printf("hdfsCreateDirectory() failed.\n");
        exit(EXIT_FAILURE);
    }

    /* 
     * Create and write a file using the filesystem
     * handle from impersonate_user1.
     */
    printf("User1: Create and write to the file as user1 : %s\n", writePath);
    hdfsFile writeFile = hdfsOpenFile(fs_handle, writePath, O_WRONLY|O_CREAT, 0, 0, 0);
    if(!writeFile) {
        printf("hdfsOpenFile() failed.\n");
        exit(EXIT_FAILURE);
    }
   
    char* buffer = "Hello, from user 1!";
    tSize num_written_bytes = hdfsWrite(fs_handle, writeFile, (void*)buffer, strlen(buffer)+1);
    if (hdfsFlush(fs_handle, writeFile)) {
	printf("failed to flush %s\n", writePath);
	exit(EXIT_FAILURE);
    }
    printf("User1: Close file %s.\n", writePath);
    hdfsCloseFile(fs_handle, writeFile);

    /*
     * Impersonate as user 2 and try to write the file create by user1.
     * Writing to the file created by user1 will be denied with error EACCES.
     */ 
    printf("Impersonate user: %s\n", impersonate_user2);
    printf("Connecting using hdfsConnectAsUser() as user %s\n", impersonate_user2);
    hdfsFS fs_handle2 = hdfsConnectAsUser(host_addr, port_num, impersonate_user2);
    if (fs_handle2 == NULL) {
        printf("hdfsConnectAsUser() failed.\n");
        exit(EXIT_FAILURE);
    } 
   
    printf("User2: Try opening file created by user1 for writing : %s\n", writePath); 
    hdfsFile writeFile2 = hdfsOpenFile(fs_handle2, writePath, O_WRONLY, 0, 0, 0);
    int errNum = errno; 
    if(writeFile2) {
        printf("User2: hdfsOpenFile() should have failed for %s.\n", impersonate_user2);
        exit(EXIT_FAILURE);
    } else {
	if (errNum == EACCES) {
		printf("User2: As expected hdfsOpenFile() with EACCES.\n"); 
	} else {
		printf("User2: hdfsOpenFile() failed with errno:%d expected %d.\n", errNum, EACCES);
		exit(EXIT_FAILURE);
	}
   }

    /* Delete the directory. This is done using the fliesystem handle creatd for user1. */
    printf("Delete directory : %s\n", user1_dir);
    ret_val = hdfsDelete(fs_handle, user1_dir, 1);
    if (ret_val != EXIT_SUCCESS) {
	printf("hdfsDelete() failed.\n");
	exit(EXIT_FAILURE);
    }	

    /* Disconnect the impersonation user1 */ 
    printf("Disconnect the impersonation user1.\n");
    ret_val = hdfsDisconnect(fs_handle);
    if (ret_val != EXIT_SUCCESS) {
	printf("hdfsDisconnect() failed.\n");
	exit(EXIT_FAILURE);
    }

    /* Disconnect the impersonation user2 */
    printf("Disconnect the impersonation user2.\n");
    ret_val = hdfsDisconnect(fs_handle2);
    if (ret_val != EXIT_SUCCESS) {
        printf("hdfsDisconnect() failed.\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}