#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sysexits.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <pwd.h>
#include <dirent.h>
#include <syslog.h>
#include <DirectoryServiceCore/SharedConsts.h>
#include "PwdPolicyTool.h"
#include "dstools_version.h"
#define debug(A, args...) \
if (gVerbose) \
fprintf(stderr, (A), ##args);
#define kNodeNotFoundMsg "Cannot access directory node.\n"
#define kNotPasswordServerUserMsg "%s is not a password server account.\n"
#define kUserNotOnNodeMsg "%s is not a user on this directory node.\n"
#define kPasswordServerNodePrefix "/PasswordServer/"
static const char *sDatePolicyStr[] = {
"expirationDateGMT=",
"hardExpireDateGMT=",
"warnOfExpirationMinutes=",
"warnOfDisableMinutes=",
"projectedPasswordExpireDate=",
"projectedAccountDisableDate=",
NULL
};
typedef enum Command {
kCmdNone,
kCmdGetGlobalPolicy,
kCmdSetGlobalPolicy,
kCmdGetPolicy,
kCmdSetPolicy,
kCmdSetPolicyGlobal,
kCmdSetPassword,
kCmdEnableUser,
kCmdGetGlobalHashTypes,
kCmdSetGlobalHashTypes,
kCmdGetHashTypes,
kCmdSetHashTypes,
kCmdGetEffectivePolicy,
kCmdEnableWindowsSharing,
kCmdDisableWindowsSharing,
kCmdAppleVersion
} Command;
typedef struct CommandTableEntry {
const char *name;
Command cmd;
} CommandTableEntry;
typedef enum AuthAuthType {
kAuthTypeUnknown,
kAuthTypePasswordServer,
kAuthTypeShadowHash,
kAuthTypeKerberos,
kAuthTypeDisabled
};
Command get_command_id( const char *commandStr );
void PrintErrorMessage( long error, const char *username );
char *ConvertPolicyLongs(const char *inPolicyStr);
char *ConvertPolicyDates(const char *inPolicyStr);
Boolean PreflightDate(const char *theDateStr);
long GetAuthAuthority(
const char *inNodeName,
const char *inUsername,
const char *inRecordType,
AuthAuthType *outAuthAuthType,
char *inOutUserID,
char *inOutServerAddress,
char **outMetaNode,
char **outAAData );
long GetAuthAuthorityWithSearchNode(
const char *inUsername,
const char *inRecordType,
AuthAuthType *outAuthAuthType,
char *inOutUserID,
char *inOutServerAddress,
char **outMetaNode,
char **outAAData );
long GetAuthAuthorityWithNode(
const char *inNodeName,
const char *inUsername,
const char *inRecordType,
AuthAuthType *outAuthAuthType,
char *inOutUserID,
char *inOutServerAddress,
char **outAAData );
AuthAuthType ConvertTagToConstant( const char *inAuthAuthorityTag );
void GetPWServerAddresses(char *outAddressStr);
CommandTableEntry gCommandTable[] =
{
{ "-appleversion", kCmdAppleVersion },
{ "-getglobalpolicy", kCmdGetGlobalPolicy },
{ "-setglobalpolicy", kCmdSetGlobalPolicy },
{ "-getpolicy", kCmdGetPolicy },
{ "-setpolicy", kCmdSetPolicy },
{ "-setpolicyglobal", kCmdSetPolicyGlobal },
{ "-setpassword", kCmdSetPassword },
{ "-enableuser", kCmdEnableUser },
{ "-getglobalhashtypes", kCmdGetGlobalHashTypes },
{ "-setglobalhashtypes", kCmdSetGlobalHashTypes },
{ "-gethashtypes", kCmdGetHashTypes },
{ "-sethashtypes", kCmdSetHashTypes },
{ "--get-effective-policy", kCmdGetEffectivePolicy },
{ "--enable-windows-sharing", kCmdEnableWindowsSharing },
{ "--disable-windows-sharing", kCmdDisableWindowsSharing },
{ NULL, kCmdNone }
};
bool gVerbose = false;
bool sTerminateServer = false;
void DoHelp ( FILE *inFile, const char *inArgv0 );
void usage(void);
char *read_passphrase(const char *prompt, int from_stdin);
const UInt32 kMaxTestUsers = 150;
const UInt32 kStressTestUsers = 2000;
const UInt32 kAllTestUsers = 123;
PwdPolicyTool myClass;
int main ( int argc, char * const *argv )
{
char *p = NULL;
long siStatus = eDSNoErr;
char *authenticator = NULL;
char *username = NULL;
char *nodename = NULL;
char password[512] = {0};
Boolean bReadPassword = false;
tDirNodeReference nodeRef = 0;
Command commandNum = kCmdNone;
Command tmpCommandNum = kCmdNone;
int commandArgIndex = 0;
char serverAddress[1024] = {0};
char nodeName[1024] = {0};
char *tptr = NULL;
char authenticatorID[1024] = {0};
char userID[1024] = {0};
char *authResult = nodeName;
char *metaNode = NULL;
char *aaData = NULL;
AuthAuthType authType = kAuthTypeUnknown;
AuthAuthType userAuthType = kAuthTypeUnknown;
char **localNodeNameList = NULL;
bool useRootPrivileges = false;
bool authenticatorIsDefault = false;
bool userIsDefault = false;
const char *recordType = kDSStdRecordTypeUsers;
for ( int index = 1; index < argc; index++ )
{
tmpCommandNum = get_command_id( argv[index] );
switch ( tmpCommandNum )
{
case kCmdAppleVersion:
dsToolAppleVersionExit( argv[0] );
break;
case kCmdGetGlobalPolicy:
case kCmdGetPolicy:
case kCmdGetGlobalHashTypes:
case kCmdGetHashTypes:
case kCmdGetEffectivePolicy:
break;
case kCmdSetGlobalPolicy:
case kCmdSetPolicy:
case kCmdSetPolicyGlobal:
case kCmdSetPassword:
case kCmdEnableUser:
case kCmdSetGlobalHashTypes:
case kCmdSetHashTypes:
case kCmdEnableWindowsSharing:
case kCmdDisableWindowsSharing:
bReadPassword = true;
break;
default:
if ( argv[index][0] == '-' )
{
p = argv[index];
p++;
while (*p)
{
if ( *p == 'a' || *p == 'c' || *p == 'u' || *p == 'p' || *p == 'n' )
if ( index+1 >= argc )
{
usage();
exit(0);
}
switch(*p)
{
case 'a':
authenticator = argv[index+1];
bReadPassword = true;
break;
case 'c':
if ( username != NULL ) {
fprintf( stderr, "-u and -c are mutually exclusive and may only appear once.\n" );
exit( EX_USAGE );
}
username = argv[index+1];
recordType = kDSStdRecordTypeComputers;
break;
case 'h':
DoHelp( stderr, argv[0] );
exit( 1 );
break;
case 'n':
nodename = argv[index+1];
break;
case 'p':
strcpy( password, argv[index+1] );
bzero( argv[index+1], strlen(argv[index+1]) );
break;
case 'u':
if ( username != NULL ) {
fprintf( stderr, "-u and -c are mutually exclusive and may only appear once.\n" );
exit( EX_USAGE );
}
username = argv[index+1];
break;
case 'v':
gVerbose = true;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
tmpCommandNum = (Command)(*p - '0' + 1);
break;
default:
usage();
exit(0);
break;
}
p++;
}
}
}
if ( tmpCommandNum != kCmdNone && commandNum != kCmdNone )
{
usage();
exit(0);
}
else
if ( tmpCommandNum != kCmdNone )
{
commandNum = tmpCommandNum;
tmpCommandNum = kCmdNone;
commandArgIndex = index;
}
}
debug( "\npwpolicy tool, version 1.2.1\n\n" );
if ( commandNum == kCmdSetGlobalPolicy ||
commandNum == kCmdSetPolicy ||
commandNum == kCmdSetGlobalHashTypes ||
commandNum == kCmdSetHashTypes )
{
if ( argv[argc-1][0] == '-' )
{
usage();
exit(0);
}
}
if ( geteuid() == 0 && authenticator == NULL )
{
useRootPrivileges = true;
authType = kAuthTypeShadowHash;
}
else if ( username == NULL || authenticator == NULL )
{
struct passwd *userRec = getpwuid(geteuid());
if ( userRec != NULL && userRec->pw_name != NULL )
{
if ( username == NULL ) {
username = strdup( userRec->pw_name );
userIsDefault = true;
}
if ( authenticator == NULL ) {
authenticator = strdup( userRec->pw_name );
authenticatorIsDefault = true;
}
}
}
if ( bReadPassword && password[0] == '\0' && !useRootPrivileges )
{
char *passPtr;
passPtr = read_passphrase("Password:", 1);
if ( passPtr != NULL )
{
strcpy( password, passPtr );
memset( passPtr, 0, strlen(passPtr) );
free( passPtr );
}
}
if ( argc > 1 )
{
serverAddress[0] = '\0';
siStatus = myClass.Initialize();
if ( siStatus != eDSNoErr )
{
fprintf(stderr, "Could not initialize Open Directory.\n");
exit(1);
}
if ( username != NULL )
{
siStatus = GetAuthAuthority( nodename, username, recordType, &userAuthType, userID, serverAddress, &metaNode, &aaData );
if ( siStatus != eDSNoErr )
{
if ( userIsDefault ) {
free( username );
username = NULL;
siStatus = eDSNoErr;
}
else {
PrintErrorMessage( siStatus, username );
exit(0);
}
}
}
if ( authenticator != NULL )
{
siStatus = GetAuthAuthority( nodename, authenticator, kDSStdRecordTypeUsers, &authType, authenticatorID, serverAddress, NULL, NULL );
if ( siStatus != eDSNoErr )
{
if ( authenticatorIsDefault ) {
free( authenticator );
authenticator = NULL;
siStatus = eDSNoErr;
}
else {
PrintErrorMessage( siStatus, authenticator );
exit(0);
}
}
}
if ( userAuthType != authType && authenticatorIsDefault )
{
free( authenticator );
authenticator = NULL;
authType = kAuthTypeUnknown;
}
if ( userAuthType == kAuthTypeUnknown )
{
switch ( commandNum )
{
case kCmdGetPolicy:
case kCmdSetPolicy:
case kCmdSetPassword:
case kCmdGetEffectivePolicy:
usage();
break;
}
}
if ( authType == kAuthTypeUnknown &&
(commandNum == kCmdGetGlobalPolicy ||
commandNum == kCmdSetGlobalPolicy ||
commandNum == kCmdGetPolicy ||
commandNum == kCmdGetEffectivePolicy) )
{
authType = kAuthTypePasswordServer;
if ( nodename != NULL &&
myClass.FindDirectoryNodes(NULL, eDSLocalNodeNames, &localNodeNameList, false) == eDSNoErr &&
localNodeNameList != NULL )
{
if ( localNodeNameList[0] != NULL ) {
if ( strcmp(nodename, localNodeNameList[0]) == 0 ) {
authType = kAuthTypeShadowHash;
}
free( localNodeNameList[0] );
}
free( localNodeNameList );
}
}
if ( commandNum == kCmdGetGlobalPolicy && nodename == NULL && userIsDefault && authenticatorIsDefault )
authType = kAuthTypePasswordServer;
switch( commandNum )
{
case kCmdGetGlobalHashTypes:
case kCmdSetGlobalHashTypes:
username = strdup("");
authType = kAuthTypeShadowHash;
break;
case kCmdGetHashTypes:
case kCmdSetHashTypes:
case kCmdEnableWindowsSharing:
case kCmdDisableWindowsSharing:
if ( userAuthType != kAuthTypeShadowHash )
{
fprintf(stderr, "The hash types can be set only for ShadowHash accounts.\n");
exit(0);
}
break;
default:
break;
}
switch( authType )
{
case kAuthTypeUnknown:
PrintErrorMessage( siStatus, username );
exit(0);
break;
case kAuthTypePasswordServer:
if ( serverAddress[0] == '\0' )
{
GetPWServerAddresses(serverAddress);
tptr = strchr(serverAddress, ',');
if ( tptr != NULL )
*tptr = '\0';
}
if ( strlen(serverAddress) < 7 )
{
fprintf(stderr, "password server is not configured.\n");
exit(0);
}
strcpy(nodeName, kPasswordServerNodePrefix);
strcat(nodeName, serverAddress);
break;
case kAuthTypeShadowHash:
case kAuthTypeDisabled:
if ( myClass.FindDirectoryNodes( NULL, eDSLocalNodeNames, &localNodeNameList, false ) == eDSNoErr &&
localNodeNameList != NULL || localNodeNameList[0] != NULL )
{
strcpy( nodeName, localNodeNameList[0] );
free( localNodeNameList[0] );
free( localNodeNameList );
}
else
{
fprintf(stderr, "Error: could not resolve the name of the local node.\n");
exit(0);
}
break;
case kAuthTypeKerberos:
if ( nodename != NULL )
{
strcpy(nodeName, nodename);
}
else
{
PrintErrorMessage( eDSNullNodeName, username );
exit(0);
}
break;
}
switch ( commandNum )
{
case kCmdGetGlobalPolicy:
if ( myClass.OpenDirNode( nodeName, &nodeRef ) == eDSNoErr )
{
myClass.DoNodePWAuth(
nodeRef,
(username && !userIsDefault) ? username : "", "",
kDSStdAuthGetGlobalPolicy, "", NULL, recordType, authResult );
tptr = ConvertPolicyLongs( authResult );
printf("%s\n", tptr ? tptr : authResult);
free(tptr);
myClass.CloseDirectoryNode( nodeRef );
}
break;
case kCmdSetGlobalPolicy:
tptr = ConvertPolicyDates( argv[argc-1] );
if ( tptr != NULL )
{
if ( myClass.OpenDirNode( nodeName, &nodeRef ) == eDSNoErr )
{
myClass.DoNodePWAuth( nodeRef,
useRootPrivileges ? "" : authenticatorID,
useRootPrivileges ? "" : password,
kDSStdAuthSetGlobalPolicy,
tptr, NULL, recordType, NULL );
myClass.CloseDirectoryNode( nodeRef );
free( tptr );
}
}
else
{
usage();
}
break;
case kCmdGetPolicy:
case kCmdGetEffectivePolicy:
if ( username != NULL )
{
char *nodeToUse = metaNode ? metaNode : nodeName;
if ( strstr(nodeToUse, "/PasswordServer") == NULL )
strlcpy( userID, username, sizeof(userID) );
printf( "Getting policy for %s\n\n", username );
if ( myClass.OpenDirNode( nodeToUse, &nodeRef ) == eDSNoErr )
{
myClass.DoNodePWAuth( nodeRef,
useRootPrivileges ? "" : authenticatorID,
useRootPrivileges ? "" : password,
(commandNum == kCmdGetPolicy) ? kDSStdAuthGetPolicy : kDSStdAuthGetEffectivePolicy,
userID, NULL, recordType, authResult );
tptr = ConvertPolicyLongs( authResult );
printf("%s\n", tptr);
free(tptr);
myClass.CloseDirectoryNode( nodeRef );
}
}
else
{
usage();
}
break;
case kCmdSetPolicy:
tptr = ConvertPolicyDates( argv[argc-1] );
if ( (useRootPrivileges == true || (authenticatorID != NULL && password != NULL)) && username != NULL && tptr != NULL )
{
printf( "Setting policy for %s\n", username );
if ( myClass.OpenDirNode( nodeName, &nodeRef ) == eDSNoErr )
{
myClass.DoNodePWAuth( nodeRef,
useRootPrivileges ? "" : authenticatorID,
useRootPrivileges ? "" : password,
kDSStdAuthSetPolicy,
userID,
tptr, NULL, NULL );
free( tptr );
myClass.CloseDirectoryNode( nodeRef );
}
}
else
{
usage();
}
break;
case kCmdSetPolicyGlobal:
if ( authenticator != NULL && password != NULL && username != NULL )
{
if ( myClass.OpenDirNode( nodeName, &nodeRef ) == eDSNoErr )
{
myClass.DoNodePWAuth( nodeRef,
useRootPrivileges ? "" : authenticatorID,
useRootPrivileges ? "" : password,
kDSStdAuthSetPolicy,
userID,
"newPasswordRequired=0 usingHistory=0 usingExpirationDate=0 "
"usingHardExpirationDate=0 requiresAlpha=0 requiresNumeric=0 "
"maxMinutesUntilChangePassword=0 maxMinutesUntilDisabled=0 "
"maxMinutesOfNonUse=0 maxFailedLoginAttempts=0 "
"minChars=0 maxChars=0 resetToGlobalDefaults=1", recordType, NULL );
myClass.CloseDirectoryNode( nodeRef );
}
}
else
{
usage();
}
break;
case kCmdSetPassword:
if ( authenticator != NULL && username != NULL )
{
char *userPassPtr = NULL;
char *verifyPassPtr = NULL;
printf( "Setting password for %s\n", username );
if ( strcmp(argv[argc-1], "-setpassword") == 0 )
{
char prompt[256];
snprintf(prompt, sizeof(prompt), "Enter new password for %s:", username);
userPassPtr = read_passphrase( prompt, 1 );
verifyPassPtr = read_passphrase( "Verify new password:", 1 );
if ( strcmp(userPassPtr, verifyPassPtr) != 0 )
{
printf( "Password mismatch.\n" );
bzero( userPassPtr, strlen(userPassPtr) );
free( userPassPtr );
bzero( verifyPassPtr, strlen(verifyPassPtr) );
free( verifyPassPtr );
return EX_TEMPFAIL;
}
}
else
{
userPassPtr = strdup( argv[argc-1] );
}
if ( myClass.OpenDirNode( nodeName, &nodeRef ) == eDSNoErr )
{
if ( useRootPrivileges && password[0] == '\0' && userAuthType == kAuthTypeShadowHash )
{
myClass.DoNodePWAuth( nodeRef,
userID,
userPassPtr,
kDSStdAuthSetPasswdAsRoot,
NULL, NULL, NULL, NULL );
}
else
{
myClass.DoNodePWAuth( nodeRef,
userID,
userPassPtr,
kDSStdAuthSetPasswd,
authenticatorID,
password, NULL, NULL );
}
myClass.CloseDirectoryNode( nodeRef );
}
if ( userPassPtr != NULL )
{
bzero( userPassPtr, strlen(userPassPtr) );
free( userPassPtr );
}
}
else
{
usage();
}
break;
case kCmdEnableUser:
if ( authenticator != NULL && username != NULL )
{
printf( "Enabling account for user %s\n\n", username );
switch( userAuthType )
{
case kAuthTypeShadowHash:
printf( "User <%s> is not marked as disabled.\n", username );
break;
case kAuthTypeDisabled:
if ( myClass.OpenDirNode( metaNode ? metaNode : nodeName, &nodeRef ) == eDSNoErr )
{
tRecordReference recRef;
if ( myClass.DoNodeNativeAuth( nodeRef, authenticator, password ) == eDSNoErr )
{
if ( myClass.OpenRecord( nodeRef, recordType, username, &recRef ) == eDSNoErr )
{
myClass.ChangeAuthAuthorityToShadowHash( recRef );
dsCloseRecord( recRef );
}
else
{
printf( "Could not access account <%s>.\n", username );
}
}
else
{
printf( "Could not get write permission on directory node: %s\n", metaNode ? metaNode : nodeName );
}
myClass.CloseDirectoryNode( nodeRef );
}
break;
default:
printf( "User <%s> does not have a shadowhash account.\n", username );
}
}
else
{
usage();
}
break;
case kCmdGetGlobalHashTypes:
{
char *hashTypesStr;
if ( myClass.GetHashTypes( &hashTypesStr ) == eDSNoErr )
{
printf( "%s\n", hashTypesStr );
free( hashTypesStr );
}
}
break;
case kCmdSetGlobalHashTypes:
if ( (geteuid() == 0) || (authenticator != NULL && password != NULL) )
myClass.SetHashTypes( authenticator, useRootPrivileges ? NULL : password, commandArgIndex + 1, argc, argv );
else
usage();
break;
case kCmdGetHashTypes:
if ( aaData != NULL && aaData[0] != '\0' && strcasecmp(aaData, kDSTagAuthAuthorityBetterHashOnly) != 0 )
{
char *hashTypeStr = NULL;
char *hashListPtr = NULL;
char *hashListStr = strdup( aaData );
char *endPtr = NULL;
printf( "Getting hash types for user %s\n\n", username );
hashListPtr = hashListStr;
if ( strncasecmp( hashListPtr, kHashNameListPrefix, sizeof(kHashNameListPrefix)-1 ) == 0 )
{
hashListPtr += sizeof(kHashNameListPrefix) - 1;
endPtr = strchr( hashListPtr, '>' );
if ( endPtr == NULL || *hashListPtr++ != '<' )
{
printf( "Invalid hash list. Use the -sethashtypes switch to reset the list.\n" );
}
else
{
*endPtr = '\0';
while ( (hashTypeStr = strsep(&hashListPtr, ",")) != NULL )
printf( "%s\n", hashTypeStr );
}
}
free( hashListStr );
}
else
{
char *hashTypesStr;
if ( myClass.GetHashTypes( &hashTypesStr, (strcasecmp(aaData, kDSTagAuthAuthorityBetterHashOnly) == 0) ) == eDSNoErr )
{
printf( "%s\n", hashTypesStr );
free( hashTypesStr );
}
}
break;
case kCmdSetHashTypes:
if ( (geteuid() == 0) || (authenticator != NULL && password != NULL) )
{
printf( "Setting hash types for user %s\n", username );
if ( myClass.OpenDirNode( metaNode ? metaNode : nodeName, &nodeRef ) == eDSNoErr )
{
tRecordReference recRef;
int result = 0;
if ( authenticator != NULL )
siStatus = myClass.DoNodeNativeAuth( nodeRef, authenticator, password );
if ( siStatus == eDSNoErr )
{
if ( myClass.OpenRecord( nodeRef, recordType, username, &recRef ) == eDSNoErr )
{
result = myClass.SetUserHashList( recRef, commandArgIndex + 1, argc, argv );
dsCloseRecord( recRef );
}
else
{
printf( "Could not access account <%s>.\n", username );
}
}
else
{
printf( "Could not get write permission on directory node: %s\n", metaNode ? metaNode : nodeName );
}
myClass.CloseDirectoryNode( nodeRef );
if ( result == -1 )
usage();
}
}
else
usage();
break;
case kCmdEnableWindowsSharing:
case kCmdDisableWindowsSharing:
if ( (geteuid() == 0) || (authenticator != NULL && password != NULL) )
{
printf( "%s Windows sharing for user %s\n",
(commandNum == kCmdEnableWindowsSharing) ? "Enabling" : "Disabling",
username );
if ( myClass.OpenDirNode(metaNode ? metaNode : nodeName, &nodeRef) == eDSNoErr )
{
tRecordReference recRef;
int result = 0;
if ( authenticator != NULL )
siStatus = myClass.DoNodeNativeAuth( nodeRef, authenticator, password );
siStatus = myClass.DoNodePWAuth( nodeRef, username, argv[argc-1],
(commandNum == kCmdEnableWindowsSharing) ? kDSStdAuthSetShadowHashWindows : kDSStdAuthSetShadowHashSecure,
NULL, NULL, recordType, NULL );
myClass.CloseDirectoryNode( nodeRef );
}
if ( siStatus != eDSNoErr )
printf( "Could not access account <%s>.\n", username );
}
else
usage();
break;
}
myClass.Deinitialize();
}
else
{
DoHelp( stderr, argv[0] );
exit( 1 );
}
}
Command get_command_id( const char *commandStr )
{
for ( int index = 0; gCommandTable[index].name != NULL; index++ )
{
if ( strcmp(gCommandTable[index].name, commandStr) == 0 )
return gCommandTable[index].cmd;
}
return kCmdNone;
}
void PrintErrorMessage( long error, const char *username )
{
if ( username == NULL )
username = "";
switch( error )
{
case eDSRecordNotFound:
fprintf(stderr, kUserNotOnNodeMsg, username);
break;
case eDSNodeNotFound:
fprintf(stderr, kNodeNotFoundMsg);
break;
case eDSNullNodeName:
fprintf(stderr, "Kerberos authentication authorities require a specific node name (-n option).\n");
break;
default:
fprintf(stderr, kNotPasswordServerUserMsg, username);
}
}
typedef struct UsageLine {
const char *cmd;
const char *desc;
} UsageLine;
void DoHelp ( FILE *inFile, const char *inArgv0 )
{
const char *tmpToolName;
const char *toolName = inArgv0;
do
{
tmpToolName = strchr( toolName, '/' );
if ( tmpToolName != NULL )
toolName = tmpToolName + 1;
}
while ( tmpToolName != NULL );
static const char * _szpUsage =
"Usage: %s [-h]\n"
"Usage: %s [-v] [-a authenticator] [-p password] [-u username | -c computername]\n"
" [-n nodename] command command-arg\n"
"Usage: %s [-v] [-a authenticator] [-p password] [-u username | -c computername]\n"
" [-n nodename] command \"policy1=value1 policy2=value2 ...\"\n"
"\n"
" -a name of the authenticator\n"
" -c name of the computer account to modify\n"
" -p password (omit this option for a secure prompt)\n"
" -u name of the user account to modify\n"
" -h help\n"
" -n directory-node to search, uses search node by default\n"
" -v verbose\n"
"\n";
fprintf( inFile, _szpUsage, toolName, toolName, toolName );
static UsageLine usage_line[] = {
{"-getglobalpolicy", "Get global policies."},
{"", "Specify a user if the password server"},
{"", "is not configured locally."},
{"-setglobalpolicy", "Set global policies"},
{"-getpolicy", "Get policies for a user"},
{"--get-effective-policy", "Gets the combination of global and user policies that apply to the user."},
{"-setpolicy", "Set policies for a user"},
{"-setpolicyglobal", "Set a user account to use global policies"},
{"-setpassword", "Set a new password for a user"},
{"-enableuser", "Enable a shadowhash user account that was disabled"},
{"", "by a password policy event."},
{"-getglobalhashtypes", "Returns a list of password hashes stored on disk by default."},
{"-setglobalhashtypes", "Edits the list of password hashes stored on disk by default."},
{"-gethashtypes", "Returns a list of password hashes stored on disk for"},
{"", "a user account."},
{"-sethashtypes", "Edits the list of password hashes stored on disk for"},
{"", "a user account."},
{NULL, NULL}
};
for ( int idx = 0; usage_line[idx].cmd != NULL; idx++ )
fprintf( inFile, "%25s\t%s\n", usage_line[idx].cmd, usage_line[idx].desc );
}
void usage(void)
{
fprintf(stdout, "usage: [-v] [-a authenticator] [-p password] [-u username | -c computername] [-n nodename] command args\n");
exit(EX_USAGE);
}
volatile int intr;
void
intcatch(int dontcare)
{
intr = 1;
}
char *
read_passphrase(const char *prompt, int from_stdin)
{
char buf[1024], *p, ch;
struct termios tio, saved_tio;
sigset_t oset, nset;
struct sigaction sa, osa;
int input, output, echo = 0;
if (from_stdin) {
input = STDIN_FILENO;
output = STDERR_FILENO;
} else
input = output = open("/dev/tty", O_RDWR);
if (input == -1)
fprintf(stderr, "You have no controlling tty. Cannot read passphrase.\n");
sigemptyset(&nset);
sigaddset(&nset, SIGTSTP);
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = intcatch;
(void) sigaction(SIGINT, &sa, &osa);
intr = 0;
if (tcgetattr(input, &saved_tio) == 0 && (saved_tio.c_lflag & ECHO)) {
echo = 1;
tio = saved_tio;
tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
(void) tcsetattr(input, TCSANOW, &tio);
}
fflush(stdout);
(void)write(output, prompt, strlen(prompt));
for (p = buf; read(input, &ch, 1) == 1 && ch != '\n';) {
if (intr)
break;
if (p < buf + sizeof(buf) - 1)
*p++ = ch;
}
*p = '\0';
if (!intr)
(void)write(output, "\n", 1);
if (echo)
tcsetattr(input, TCSANOW, &saved_tio);
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
(void) sigaction(SIGINT, &osa, NULL);
if (intr) {
kill(getpid(), SIGINT);
sigemptyset(&nset);
sigsuspend(&nset);
}
if (!from_stdin)
(void)close(input);
p = (char *)malloc(strlen(buf)+1);
strcpy(p, buf);
memset(buf, 0, sizeof(buf));
return (p);
}
char *ConvertPolicyLongs(const char *inPolicyStr)
{
char *returnString = NULL;
char *value = NULL;
char *tempString = NULL;
struct tm *timerec;
time_t timeval;
char scratchStr[256];
tempString = (char *)malloc( strlen(inPolicyStr) + 100 );
if ( tempString == NULL )
return NULL;
returnString = (char *)malloc( strlen(inPolicyStr) + 100 );
if ( returnString == NULL ) {
free( tempString );
return NULL;
}
strcpy( returnString, inPolicyStr );
for ( int idx = 0; sDatePolicyStr[idx] != NULL; idx++ )
{
value = strstr( returnString, sDatePolicyStr[idx] );
if ( value != NULL )
{
value += strlen( sDatePolicyStr[idx] );
strlcpy( tempString, returnString, value - returnString + 1 );
timeval = 0;
sscanf( value, "%lu", &timeval );
timerec = ::gmtime( &timeval );
strftime( scratchStr, sizeof(scratchStr), "%m/%d/%y", timerec );
strcat( tempString, scratchStr );
value = strchr( value, ' ' );
if ( value != NULL )
strcat( tempString, value );
strcpy( returnString, tempString );
}
}
if ( tempString != NULL ) {
free( tempString );
tempString = NULL;
}
return returnString;
}
char *ConvertPolicyDates(const char *inPolicyStr)
{
char *returnString = NULL;
char *value = NULL;
char *tempString = NULL;
char *firstNonNeeded = NULL;
struct tm timerec;
int index;
char scratchStr[256];
tempString = (char *)malloc( strlen(inPolicyStr) + 100 );
if ( tempString == NULL )
return NULL;
try
{
returnString = (char *)malloc( strlen(inPolicyStr) + 100 );
if ( returnString == NULL )
throw(1);
strcpy( returnString, inPolicyStr );
for ( int idx = 0; sDatePolicyStr[idx] != NULL; idx++ )
{
value = strstr( returnString, sDatePolicyStr[idx] );
if ( value != NULL )
{
value += strlen( sDatePolicyStr[idx] );
strlcpy( tempString, returnString, value - returnString + 1 );
strlcpy( scratchStr, value, 9 );
for ( index = 0; index < 8; index++ )
{
if ( scratchStr[index] == ' ' )
{
scratchStr[index] = '\0';
break;
}
}
if ( ! PreflightDate(scratchStr) )
throw(1);
bzero(&timerec, sizeof(timerec));
firstNonNeeded = strptime(value, "%m/%d/%y", &timerec);
if ( firstNonNeeded == NULL )
throw(1);
sprintf( scratchStr, "%lu", mktime(&timerec) );
strcat( tempString, scratchStr );
value = strchr( value, ' ' );
if ( value != NULL )
strcat( tempString, value );
strcpy( returnString, tempString );
}
}
}
catch(...)
{
if ( returnString != NULL ) {
free( returnString );
returnString = NULL;
}
}
if ( tempString != NULL ) {
free( tempString );
tempString = NULL;
}
return returnString;
}
Boolean PreflightDate(const char *theDateStr)
{
const char *tptr;
int index, argLen;
int slashcount = 0;
bool success = false;
try
{
tptr = theDateStr;
argLen = strlen( theDateStr );
for ( index = 0; index < argLen; index++ )
{
if ( tptr[index] == '/' )
{
if ( index == 0 || index == argLen - 1 )
throw(-1);
slashcount++;
}
else
if ( tptr[index] < '0' )
throw(-1);
else
if ( tptr[index] > '9' )
throw(-1);
}
if ( slashcount != 2 )
throw(-1);
success = true;
}
catch(...)
{
}
return success;
}
long GetAuthAuthority(
const char *inNodeName,
const char *inUsername,
const char *inRecordType,
AuthAuthType *outAuthAuthType,
char *inOutUserID,
char *inOutServerAddress,
char **outMetaNode,
char **outAAData )
{
long result = -1;
if ( inNodeName == NULL )
result = GetAuthAuthorityWithSearchNode( inUsername, inRecordType, outAuthAuthType, inOutUserID, inOutServerAddress, outMetaNode, outAAData );
else
result = GetAuthAuthorityWithNode( inNodeName, inUsername, inRecordType, outAuthAuthType, inOutUserID, inOutServerAddress, outAAData );
if ( result == eDSNoErr && *outAuthAuthType == kAuthTypePasswordServer && (*inOutUserID == '\0' || *inOutServerAddress == '\0') )
result = -1;
return result;
}
long GetAuthAuthorityWithSearchNode(
const char *inUsername,
const char *inRecordType,
AuthAuthType *outAuthAuthType,
char *inOutUserID,
char *inOutServerAddress,
char **outMetaNode,
char **outAAData )
{
long status = eDSNoErr;
char *aaVersion = nil;
char *aaTag = nil;
char *aaData = nil;
char *authAuthorityStr = nil;
char *metaNodeStr = nil;
if ( inUsername == nil || inOutUserID == nil || inOutServerAddress == nil )
{
debug("GetAuthAuthority(): all parameters must be non-null\n");
exit(-1);
}
*inOutUserID = '\0';
*inOutServerAddress = '\0';
try
{
status = myClass.GetUserByName( myClass.GetSearchNodeRef(), inUsername, inRecordType, &authAuthorityStr, &metaNodeStr );
if ( status != eDSNoErr )
throw( status );
if ( outMetaNode != NULL )
*outMetaNode = metaNodeStr;
else
free( metaNodeStr );
status = dsParseAuthAuthority( authAuthorityStr, &aaVersion, &aaTag, &aaData );
if ( status != eDSNoErr )
throw( status );
*outAuthAuthType = ConvertTagToConstant( aaTag );
switch( *outAuthAuthType )
{
case kAuthTypePasswordServer:
{
char *endPtr = strchr( aaData, ':' );
if ( endPtr != NULL )
{
*endPtr++ = '\0';
strcpy( inOutUserID, aaData );
strcpy( inOutServerAddress, endPtr );
}
}
break;
default:
strcpy( inOutUserID, inUsername );
break;
}
if ( outAAData != NULL )
*outAAData = aaData;
}
catch( long errCode )
{
status = errCode;
}
if ( authAuthorityStr != NULL )
free( authAuthorityStr );
return status;
}
long GetAuthAuthorityWithNode(
const char *inNodeName,
const char *inUsername,
const char *inRecordType,
AuthAuthType *outAuthAuthType,
char *inOutUserID,
char *inOutServerAddress,
char **outAAData )
{
tDirReference dsRef = 0;
tDataBuffer *tDataBuff = 0;
tDirNodeReference nodeRef = 0;
long status = eDSNoErr;
tContextData context = nil;
tAttributeValueEntry *pExistingAttrValue = NULL;
UInt32 index = 0;
UInt32 nodeCount = 0;
UInt32 attrValIndex = 0;
UInt32 attrValCount = 0;
tDataList *nodeName = nil;
tRecordReference recordRef = 0;
tDataNode *attrTypeNode = nil;
tDataNodePtr recordTypeNode = nil;
tDataNodePtr recordNameNode = nil;
tAttributeEntryPtr pAttrEntry = nil;
char *aaVersion = nil;
char *aaTag = nil;
char *aaData = nil;
try
{
if ( inNodeName == nil || inUsername == nil || outAuthAuthType == nil || inOutUserID == nil || inOutServerAddress == nil )
throw(-1);
debug("\nGet AuthAuthority with nodename = %s and username = %s\n", inNodeName, inUsername);
*inOutUserID = '\0';
*inOutServerAddress = '\0';
dsRef = myClass.GetDirRef();
if (dsRef == 0)
throw((long)-1);
tDataBuff = dsDataBufferAllocate( dsRef, 4096 );
if (tDataBuff == 0)
throw((long)-1);
nodeName = ::dsBuildFromPath( dsRef, inNodeName, "/" );
if ( nodeName == nil )
throw((long)-1);
status = dsFindDirNodes( dsRef, tDataBuff, nodeName, eDSiExact, &nodeCount, &context );
debug("dsFindDirNodes = %ld, nodeCount = %ld\n", status, nodeCount);
if ( nodeCount < 1 ) {
status = eDSNodeNotFound;
debug("dsFindDirNodes returned 0 nodes\n");
}
dsDataListDeallocate( dsRef, nodeName );
free( nodeName );
nodeName = nil;
if (status != eDSNoErr)
throw(status);
for ( index = 1; index <= nodeCount; index++ )
{
pExistingAttrValue = nil;
status = dsGetDirNodeName( dsRef, tDataBuff, index, &nodeName );
debug("dsGetDirNodeName = %ld\n", status);
if (status != eDSNoErr) continue;
status = dsOpenDirNode( dsRef, nodeName, &nodeRef );
dsDataListDeallocate( dsRef, nodeName );
free( nodeName );
nodeName = nil;
debug("dsOpenDirNode = %ld\n", status);
if (status != eDSNoErr) continue;
recordTypeNode = dsDataNodeAllocateString( dsRef, inRecordType );
recordNameNode = dsDataNodeAllocateString( dsRef, inUsername );
status = dsOpenRecord( nodeRef, recordTypeNode, recordNameNode, &recordRef );
debug("dsOpenRecord = %ld\n", status);
if (status != eDSNoErr) continue;
attrTypeNode = dsDataNodeAllocateString( 0, kDSNAttrAuthenticationAuthority );
status = dsGetRecordAttributeInfo( recordRef, attrTypeNode, &pAttrEntry );
debug("dsGetRecordAttributeInfo = %ld\n", status);
if ( status == eDSNoErr )
{
attrValCount = pAttrEntry->fAttributeValueCount;
for ( attrValIndex = 1; attrValIndex <= attrValCount; attrValIndex++ )
{
status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, attrValIndex, &pExistingAttrValue );
debug("dsGetRecordAttributeValueByIndex = %ld\n", status);
if (status != eDSNoErr) continue;
status = dsParseAuthAuthority( pExistingAttrValue->fAttributeValueData.fBufferData, &aaVersion, &aaTag, &aaData );
if (status != eDSNoErr) continue;
if ( strstr(inNodeName, "/Local") != NULL &&
strcmp(aaTag, "Kerberosv5") == 0 )
continue;
*outAuthAuthType = ConvertTagToConstant( aaTag );
switch( *outAuthAuthType )
{
case kAuthTypePasswordServer:
{
char *endPtr = strchr( aaData, ':' );
if ( endPtr != NULL )
{
*endPtr++ = '\0';
strcpy( inOutUserID, aaData );
strcpy( inOutServerAddress, endPtr );
}
}
break;
default:
strcpy( inOutUserID, inUsername );
break;
}
if ( outAAData != NULL )
*outAAData = aaData;
}
}
if (recordRef != 0) {
dsCloseRecord( recordRef );
recordRef = 0;
}
if (nodeRef != 0) {
dsCloseDirNode(nodeRef);
nodeRef = 0;
}
}
}
catch( long errCode )
{
status = errCode;
}
if (recordRef != 0) {
dsCloseRecord( recordRef );
recordRef = 0;
}
if (tDataBuff != NULL) {
dsDataBufferDeAllocate( dsRef, tDataBuff );
tDataBuff = NULL;
}
if (nodeRef != 0) {
dsCloseDirNode(nodeRef);
nodeRef = 0;
}
return status;
}
void GetPWServerAddresses(char *outAddressStr)
{
tDirReference dsRef = 0;
tDataBuffer *tDataBuff = 0;
tDirNodeReference nodeRef = 0;
long status = eDSNoErr;
tContextData context = nil;
tAttributeValueEntry *pAttrValueEntry = NULL;
UInt32 index = 0;
UInt32 nodeCount = 0;
tDataList *nodeName = nil;
tRecordReference recordRef = 0;
tDataNode *attrTypeNode = nil;
tDataNodePtr recordTypeNode = nil;
tDataNodePtr recordNameNode = nil;
*outAddressStr = '\0';
do
{
status = dsOpenDirService( &dsRef );
if (status != eDSNoErr) break;
tDataBuff = dsDataBufferAllocate( dsRef, 4096 );
if (tDataBuff == 0) break;
status = dsFindDirNodes( dsRef, tDataBuff, nil, eDSLocalHostedNodes, &nodeCount, &context );
if (status != eDSNoErr) break;
if ( nodeCount < 1 ) {
status = eDSNodeNotFound;
break;
}
for ( index = 1; index <= nodeCount; index++ )
{
status = dsGetDirNodeName( dsRef, tDataBuff, index, &nodeName );
if (status != eDSNoErr) break;
status = dsOpenDirNode( dsRef, nodeName, &nodeRef );
dsDataListDeallocate( dsRef, nodeName );
free( nodeName );
nodeName = nil;
if (status != eDSNoErr) break;
recordTypeNode = dsDataNodeAllocateString( dsRef, kDSStdRecordTypeConfig );
recordNameNode = dsDataNodeAllocateString( dsRef, "passwordserver" );
status = dsOpenRecord( nodeRef, recordTypeNode, recordNameNode, &recordRef );
if (status != eDSNoErr) continue;
attrTypeNode = dsDataNodeAllocateString( 0, kDS1AttrPasswordServerLocation );
status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, 1, &pAttrValueEntry );
if (status != eDSNoErr) break;
if ( *outAddressStr != '\0' )
strcat( outAddressStr, "," );
strcat( outAddressStr, (char *)&(pAttrValueEntry->fAttributeValueData.fBufferData) );
if (recordRef != 0) {
dsCloseRecord( recordRef );
recordRef = 0;
}
if (nodeRef != 0) {
dsCloseDirNode(nodeRef);
nodeRef = 0;
}
}
}
while (false);
if ( status != eDSNoErr )
{
do
{
nodeName = ::dsBuildFromPath( dsRef, "/LDAPv3/127.0.0.1", "/" );
if ( nodeName == nil )
break;
status = dsFindDirNodes( dsRef, tDataBuff, nodeName, eDSiExact, &nodeCount, &context );
if (status != eDSNoErr) break;
if ( nodeCount < 1 ) {
status = eDSNodeNotFound;
break;
}
status = dsGetDirNodeName( dsRef, tDataBuff, 1, &nodeName );
if (status != eDSNoErr) break;
status = dsOpenDirNode( dsRef, nodeName, &nodeRef );
dsDataListDeallocate( dsRef, nodeName );
free( nodeName );
nodeName = nil;
if (status != eDSNoErr) break;
recordTypeNode = dsDataNodeAllocateString( dsRef, kDSStdRecordTypeConfig );
recordNameNode = dsDataNodeAllocateString( dsRef, "passwordserver" );
status = dsOpenRecord( nodeRef, recordTypeNode, recordNameNode, &recordRef );
if (status != eDSNoErr) break;
attrTypeNode = dsDataNodeAllocateString( 0, kDS1AttrPasswordServerLocation );
status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, 1, &pAttrValueEntry );
if (status != eDSNoErr) break;
if ( *outAddressStr != '\0' )
strcat( outAddressStr, "," );
strcat( outAddressStr, (char *)&(pAttrValueEntry->fAttributeValueData.fBufferData) );
}
while(false);
if (recordRef != 0) {
dsCloseRecord( recordRef );
recordRef = 0;
}
if (tDataBuff != NULL) {
dsDataBufferDeAllocate( dsRef, tDataBuff );
tDataBuff = NULL;
}
if (nodeRef != 0) {
dsCloseDirNode(nodeRef);
nodeRef = 0;
}
if (dsRef != 0) {
dsCloseDirService(dsRef);
dsRef = 0;
}
}
}
AuthAuthType ConvertTagToConstant( const char *inAuthAuthorityTag )
{
AuthAuthType returnType = kAuthTypeUnknown;
if ( strcasecmp( inAuthAuthorityTag, kDSTagAuthAuthorityPasswordServer ) == 0 )
{
returnType = kAuthTypePasswordServer;
}
else
if ( strcasecmp( inAuthAuthorityTag, kDSTagAuthAuthorityShadowHash ) == 0 )
{
returnType = kAuthTypeShadowHash;
}
else
if ( strcasecmp( inAuthAuthorityTag, kDSTagAuthAuthorityKerberosv5 ) == 0 )
{
returnType = kAuthTypeKerberos;
}
else
if ( strcasecmp( inAuthAuthorityTag, kDSTagAuthAuthorityDisabledUser ) == 0 )
{
returnType = kAuthTypeDisabled;
}
return returnType;
}