#!/usr/bin/perl # # This is a sample implementation of a UID/GID GPFS remapping helper # application pair, provided for testing and illustrative purposes. It uses # the Full Name (a.k.a. gecos) field in /etc/passwd as the globally unique user # name. No name-based GID remapping is done in this implementation. When # remapping for the purposes of credentials checking (intent is 'credentials'), # we do remapping for the UID based on the symbolic name, and replace the # entire list of GIDs with the GIDs of the user on the home cluster. $debug = 0; if ($#ARGV != 3) { die("Usage: mmname2uid domain intent nUids nGids\n"); } $domain = $ARGV[0]; $intent = $ARGV[1]; $nUids = $ARGV[2]; $nGids = $ARGV[3]; # Do basic argument sanity checking if ( ($intent ne "credentials") && ($intent ne "stat") && ($intent ne "acl") ) { die("Invalid intent value: $intent\n"); } if ( ($intent eq "credentials") && ($nUids == 0) ) { die("The number of UIDs to be remapped cannot be zero\n"); } if ( ($intent eq "credentials") && ($nUids != 1) ) { die("Only one UID is allowed for credentials remapping\n"); } # In this sample implementation, we replace the entire list of GIDs # with a new list when remapping for credentials checking. The matching # mmuid2name never outputs any GIDs, so we should not be expecting any # (a different implementation may handle this differently) if ($intent eq "credentials") { $nGids = 0; } # Read the list of UIDs and GIDs. Note that the interface conventions # stipulate that when the intent is 'stat', two lines of input will be # provided for each ID: symbolic name and original numeric ID. for ($i = 0; $i < $nUids; $i++) { $name = ; print(STDERR $name) if $debug; chop($name); $gcoss{$name} = $i; $uids[$i] = "UNKNOWN USER"; if ($intent eq "stat") { $id = ; print(STDERR $id) if $debug; chop($id); $orig_uids[$i] = $id; } } for ($i = 0; $i < $nGids; $i++) { $gname = ; print(STDERR $gname) if $debug; chop($gname); $gnames{$gname} = $i; if ($intent eq "stat") { $id = ; print(STDERR $id) if $debug; chop($id); $orig_gids[$i] = $id; } } # Go though the list of users, as returned by getpwent (normally it's the # list from /etc/passwd or NIS), and find users who have their Full Name # matching to one of the input names. $nFound = 0; while(true) { @pwent = getpwent(); if ($#pwent == -1){ last; } $username = $pwent[0]; $uid = $pwent[2]; $gid = $pwent[3]; $gcos = $pwent[6]; if (exists $gcoss{$gcos}) { $uids[$gcoss{$gcos}] = $uid; if ($intent eq "credentials") { $gids[$gcoss{$gcos}] = $gid; $usernames[$gcoss{$gcos}] = $username; } $nFound++; last if $nFound >= $nUids; } } endpwent(); # Get UID/GID of 'nobody'. In this implementation, we return those when the # symbolic name is not found in our /etc/passwd. @a = getpwnam("nobody"); $nobody_uid = $a[2]; $nobody_gid = $a[3]; # In this implementation, the convention is to use "UNKNOWN USER" string # to denote a name that has not been found. for ($i = 0; $i < $nUids; $i++) { # if the user is not found, print ids of nobody if ($uids[$i] eq "UNKNOWN USER") { printf("%u\n", $nobody_uid); printf("%u\n", $nobody_gid) if ($intent eq "credentials"); next; } printf("%u\n", $uids[$i]); # if we are remapping for credentials checking, get a list of groups # that the user belongs to if ($intent eq "credentials") { # primary gid printf("%u\n", $gids[$i]); # supplementary groups while(true) { ($name, $passwd, $gid, $members) = getgrent(); last if $name eq ""; # skip group if it's user's primary group next if $gid == $gids[$i]; @memberlist = split(' ', $members); foreach(@memberlist) { if ($_ eq $usernames[$i]) { printf("%u\n", $gid); last; } } } } } # In this example, we don't do remapping for gids for stat. We choose not # to remap gids at all, i.e. return the same gid that was supplied to us. An # alternative would be to return gid of 'nobody' for all gids, but that is # hardly useful. for ($i = 0; $i < $nGids; $i++) { printf("%u\n", $orig_gids[$i]); }