#include <getopt.h>
#include <stdio.h>
#include <Security/AuthorizationPriv.h>
#include "authz.h"
#include "security.h"
AuthorizationRef
read_auth_ref_from_stdin()
{
AuthorizationRef auth_ref = NULL;
AuthorizationExternalForm extform;
size_t bytes_read;
while (kAuthorizationExternalFormLength != (bytes_read = read(STDIN_FILENO, &extform, kAuthorizationExternalFormLength)))
{
if ((bytes_read == -1) && ((errno != EAGAIN) || (errno != EINTR)))
break;
}
if (bytes_read != kAuthorizationExternalFormLength)
fprintf(stderr, "ERR: Failed to read authref\n");
else
if (AuthorizationCreateFromExternalForm(&extform, &auth_ref))
fprintf(stderr, "ERR: Failed to internalize authref\n");
close(0);
return auth_ref;
}
int
write_auth_ref_to_stdout(AuthorizationRef auth_ref)
{
AuthorizationExternalForm extform;
size_t bytes_written;
if (AuthorizationMakeExternalForm(auth_ref, &extform))
return -1;
while (kAuthorizationExternalFormLength != (bytes_written = write(STDOUT_FILENO, &extform, kAuthorizationExternalFormLength)))
{
if ((bytes_written == -1) && ((errno != EAGAIN) || (errno != EINTR)))
break;
}
if (bytes_written == kAuthorizationExternalFormLength)
return 0;
return -1;
}
void
write_dict_to_stdout(CFDictionaryRef dict)
{
if (!dict)
return;
CFDataRef right_definition_xml = CFPropertyListCreateXMLData(NULL, dict);
if (!right_definition_xml)
return;
write(STDOUT_FILENO, CFDataGetBytePtr(right_definition_xml), CFDataGetLength(right_definition_xml));
CFRelease(right_definition_xml);
}
CFDictionaryRef
read_dict_from_stdin()
{
int bytes_read = 0;
uint8_t buffer[4096];
CFMutableDataRef data = CFDataCreateMutable(NULL, sizeof(buffer));
if (!data)
return NULL;
while (bytes_read = read(STDIN_FILENO, &buffer, sizeof(buffer)))
{
if ((bytes_read == -1) && ((errno != EAGAIN) || (errno != EINTR)))
break;
else
CFDataAppendBytes(data, buffer, bytes_read);
}
CFDictionaryRef right_dict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL);
if (data)
CFRelease(data);
if (!right_dict)
return NULL;
if (CFGetTypeID(right_dict) != CFDictionaryGetTypeID())
{
CFRelease(right_dict);
return NULL;
}
return right_dict;
}
int
authorizationdb(int argc, char * const * argv)
{
AuthorizationRef auth_ref = NULL;
int ch;
while ((ch = getopt(argc, argv, "i")) != -1)
{
switch (ch)
{
case 'i':
auth_ref = read_auth_ref_from_stdin();
break;
case '?':
default:
return 2;
}
}
argc -= optind;
argv += optind;
if (argc == 0)
return 2;
OSStatus status;
if (argc > 1)
{
if (!auth_ref && AuthorizationCreate(NULL, NULL, 0, &auth_ref))
return -1;
if (!strcmp("read", argv[0]))
{
CFDictionaryRef right_definition;
status = AuthorizationRightGet(argv[1], &right_definition);
if (!status)
{
write_dict_to_stdout(right_definition);
CFRelease(right_definition);
}
}
else if (!strcmp("write", argv[0]))
{
if (argc == 2)
{
CFDictionaryRef right_definition = read_dict_from_stdin();
if (!right_definition)
return -1;
status = AuthorizationRightSet(auth_ref, argv[1], right_definition, NULL, NULL, NULL);
CFRelease(right_definition);
}
else if (argc == 3)
{
CFStringRef shortcut_definition = CFStringCreateWithCStringNoCopy(NULL, argv[2], kCFStringEncodingUTF8, kCFAllocatorNull);
if (!shortcut_definition)
return -1;
status = AuthorizationRightSet(auth_ref, argv[1], shortcut_definition, NULL, NULL, NULL);
CFRelease(shortcut_definition);
}
else
return 2;
}
else if (!strcmp("remove", argv[0]))
{
status = AuthorizationRightRemove(auth_ref, argv[1]);
}
else
return 2;
}
else
return 2;
if (auth_ref)
AuthorizationFree(auth_ref, 0);
if (!do_quiet)
fprintf(stderr, "%s (%d)\n", status ? "NO" : "YES", (int)status);
return (status ? -1 : 0);
}
int
authorize(int argc, char * const *argv)
{
int ch;
OSStatus status;
Boolean user_interaction_allowed = FALSE, extend_rights = TRUE;
Boolean partial_rights = FALSE, destroy_rights = FALSE;
Boolean pre_authorize = FALSE, internalize = FALSE, externalize = FALSE;
Boolean wait = FALSE, explicit_credentials = FALSE;
Boolean isolate_explicit_credentials = FALSE, least_privileged = FALSE;
char *login = NULL;
while ((ch = getopt(argc, argv, "ucC:EpdPieqwxl")) != -1)
{
switch (ch)
{
case 'u':
user_interaction_allowed = TRUE;
break;
case 'c':
explicit_credentials = TRUE;
break;
case 'C':
explicit_credentials = TRUE;
login = optarg;
break;
case 'e':
externalize = TRUE;
break;
case 'E':
extend_rights = FALSE;
break;
case 'p':
partial_rights = TRUE;
break;
case 'd':
destroy_rights = TRUE;
break;
case 'P':
pre_authorize = TRUE;
break;
case 'i':
internalize = TRUE;
break;
case 'w':
wait = TRUE;
externalize = TRUE;
break;
case 'x':
isolate_explicit_credentials = TRUE;
break;
case 'l':
least_privileged = TRUE;
break;
case '?':
default:
return 2;
}
}
argc -= optind;
argv += optind;
if (argc == 0)
return 2;
AuthorizationFlags flags = kAuthorizationFlagDefaults |
(user_interaction_allowed ? kAuthorizationFlagInteractionAllowed : 0) |
(extend_rights ? kAuthorizationFlagExtendRights : 0) |
(partial_rights ? kAuthorizationFlagPartialRights : 0) |
(pre_authorize ? kAuthorizationFlagPreAuthorize : 0) |
(least_privileged ? kAuthorizationFlagLeastPrivileged : 0);
AuthorizationItem rights[argc];
memset(rights, '\0', argc * sizeof(AuthorizationItem));
AuthorizationItemSet rightset = { argc, rights };
while (argc > 0)
rights[--argc].name = *argv++;
AuthorizationRef auth_ref = NULL;
if (internalize)
{
auth_ref = read_auth_ref_from_stdin();
if (!auth_ref)
return 1;
}
if (!auth_ref && AuthorizationCreate(NULL, NULL,
(least_privileged ? kAuthorizationFlagLeastPrivileged : 0),
&auth_ref))
return -1;
AuthorizationEnvironment *envp = NULL;
if (explicit_credentials) {
if (!login)
login = getlogin();
char *pass = getpass("Password:");
if (!(login && pass))
return 1;
static AuthorizationItem authenv[] = {
{ kAuthorizationEnvironmentUsername },
{ kAuthorizationEnvironmentPassword },
{ kAuthorizationEnvironmentShared } };
static AuthorizationEnvironment env = { 0, authenv };
authenv[0].valueLength = strlen(login);
authenv[0].value = login;
authenv[1].valueLength = strlen(pass);
authenv[1].value = pass;
if (isolate_explicit_credentials)
env.count = 2; else
env.count = 3; envp = &env;
}
AuthorizationRights *granted_rights = NULL;
status = AuthorizationCopyRights(auth_ref, &rightset, envp, flags, &granted_rights);
if (externalize)
write_auth_ref_to_stdout(auth_ref);
if (!do_quiet)
fprintf(stderr, "%s (%d) ", status ? "NO" : "YES", (int)status);
if (!do_quiet && !status && granted_rights)
{
uint32_t index;
fprintf(stderr, "{ %d: ", (int)granted_rights->count);
for (index = 0; index < granted_rights->count; index++)
{
fprintf(stderr, "\"%s\"%s %c ", granted_rights->items[index].name,
(kAuthorizationFlagCanNotPreAuthorize & granted_rights->items[index].flags) ? " (cannot-preauthorize)" : "",
(index+1 != granted_rights->count) ? ',' : '}');
}
AuthorizationFreeItemSet(granted_rights);
}
if (!do_quiet)
fprintf(stderr, "\n");
if (externalize && wait)
while (-1 != write(STDOUT_FILENO, NULL, 0))
usleep(100);
if (auth_ref)
AuthorizationFree(auth_ref, destroy_rights ? kAuthorizationFlagDestroyRights : 0);
return (status ? -1 : 0);
}
int
execute_with_privileges(int argc, char * const *argv)
{
AuthorizationRef auth_ref = NULL;
int ch;
while ((ch = getopt(argc, argv, "i")) != -1)
{
switch (ch)
{
case 'i':
auth_ref = read_auth_ref_from_stdin();
break;
case '?':
default:
return 2;
}
}
argc -= optind;
argv += optind;
if (argc == 0)
return 2;
OSStatus status;
if (!auth_ref && AuthorizationCreate(NULL, NULL, 0, &auth_ref))
return -1;
FILE *communications_pipe = NULL;
status = AuthorizationExecuteWithPrivileges(auth_ref,argv[0], 0, (argc > 1) ? &argv[1] : NULL, &communications_pipe);
if (!do_quiet)
fprintf(stderr, "%s (%d) ", status ? "NO" : "YES", (int)status);
if (!status)
{
int bytes_read = 0;
uint8_t buffer[4096];
while (bytes_read = read(STDIN_FILENO, &buffer, sizeof(buffer)))
{
if ((bytes_read == -1) && ((errno != EAGAIN) || (errno != EINTR)))
break;
else
while ((-1 == write(fileno(communications_pipe), buffer, bytes_read)) &&
((errno == EAGAIN) || (errno == EINTR)))
usleep(100);
}
}
return (status ? -1 : 0);
}