/* * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ * * authz.c */ #include #include #include #include "authz.h" #include "security.h" // AEWP? 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; // required right parameter(s) 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) { // argv[2] is shortcut string 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; // take one optional argument - no more } 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; /* @@@ Return 2 triggers usage message. */ } } argc -= optind; argv += optind; if (argc == 0) return 2; // required right parameter(s) // set up AuthorizationFlags AuthorizationFlags flags = kAuthorizationFlagDefaults | (user_interaction_allowed ? kAuthorizationFlagInteractionAllowed : 0) | (extend_rights ? kAuthorizationFlagExtendRights : 0) | (partial_rights ? kAuthorizationFlagPartialRights : 0) | (pre_authorize ? kAuthorizationFlagPreAuthorize : 0) | (least_privileged ? kAuthorizationFlagLeastPrivileged : 0); // set up AuthorizationRightSet AuthorizationItem rights[argc]; memset(rights, '\0', argc * sizeof(AuthorizationItem)); AuthorizationItemSet rightset = { argc, rights }; while (argc > 0) rights[--argc].name = *argv++; AuthorizationRef auth_ref = NULL; // internalize AuthorizationRef 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; // prepare environment if needed 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 } // optional (see below) }; 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; // do not send kAuthorizationEnvironmentShared else env.count = 3; // do send kAuthorizationEnvironmentShared envp = &env; } // perform Authorization AuthorizationRights *granted_rights = NULL; status = AuthorizationCopyRights(auth_ref, &rightset, envp, flags, &granted_rights); // externalize AuthorizationRef 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"); // wait for client to pick up AuthorizationRef if (externalize && wait) while (-1 != write(STDOUT_FILENO, NULL, 0)) usleep(100); // drop AuthorizationRef 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; // required tool parameter(s) 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); }