1/*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 *  authz.c
24 */
25
26#include <getopt.h>
27#include <stdio.h>
28#include <Security/AuthorizationPriv.h>
29
30#include "authz.h"
31#include "security.h"
32
33// AEWP?
34
35AuthorizationRef
36read_auth_ref_from_stdin()
37{
38	AuthorizationRef auth_ref = NULL;
39	AuthorizationExternalForm extform;
40	size_t bytes_read;
41
42	while (kAuthorizationExternalFormLength != (bytes_read = read(STDIN_FILENO, &extform, kAuthorizationExternalFormLength)))
43	{
44		if ((bytes_read == -1) && ((errno != EAGAIN) || (errno != EINTR)))
45			break;
46	}
47	if (bytes_read != kAuthorizationExternalFormLength)
48		fprintf(stderr, "ERR: Failed to read authref\n");
49	else
50		if (AuthorizationCreateFromExternalForm(&extform, &auth_ref))
51			fprintf(stderr, "ERR: Failed to internalize authref\n");
52
53	close(0);
54
55	return auth_ref;
56}
57
58int
59write_auth_ref_to_stdout(AuthorizationRef auth_ref)
60{
61	AuthorizationExternalForm extform;
62	size_t bytes_written;
63
64	if (AuthorizationMakeExternalForm(auth_ref, &extform))
65		return -1;
66
67	while (kAuthorizationExternalFormLength != (bytes_written = write(STDOUT_FILENO, &extform, kAuthorizationExternalFormLength)))
68	{
69		if ((bytes_written == -1) && ((errno != EAGAIN) || (errno != EINTR)))
70			break;
71	}
72
73	if (bytes_written == kAuthorizationExternalFormLength)
74		return 0;
75
76	return -1;
77}
78
79void
80write_dict_to_stdout(CFDictionaryRef dict)
81{
82	if (!dict)
83		return;
84
85	CFDataRef right_definition_xml = CFPropertyListCreateXMLData(NULL, dict);
86
87	if (!right_definition_xml)
88		return;
89
90	write(STDOUT_FILENO, CFDataGetBytePtr(right_definition_xml), CFDataGetLength(right_definition_xml));
91	CFRelease(right_definition_xml);
92}
93
94CFDictionaryRef
95read_dict_from_stdin()
96{
97	int bytes_read = 0;
98	uint8_t buffer[4096];
99	CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
100	CFErrorRef err = NULL;
101
102	if (!data)
103		return NULL;
104
105	while (bytes_read = read(STDIN_FILENO, (void *)buffer, sizeof(buffer)))
106	{
107		if (bytes_read == -1)
108			break;
109		else
110			CFDataAppendBytes(data, buffer, bytes_read);
111	}
112
113	CFDictionaryRef right_dict = (CFDictionaryRef)CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, &err);
114	CFRelease(data);
115
116	if (NULL == right_dict) {
117		CFShow(err);
118		return NULL;
119	}
120
121	if (CFGetTypeID(right_dict) != CFDictionaryGetTypeID())
122	{
123		fprintf(stderr, "This is not a dictionary.\n");
124		CFRelease(right_dict);
125		return NULL;
126	}
127	return right_dict;
128}
129
130CFPropertyListRef
131read_plist_from_file(CFStringRef filePath)
132{
133	CFTypeRef         property = NULL;
134	CFPropertyListRef propertyList = NULL;
135	CFURLRef          fileURL = NULL;
136	CFErrorRef       errorString = NULL;
137	CFDataRef         resourceData = NULL;
138	Boolean           status = FALSE;
139	SInt32            errorCode = -1;
140
141	// Convert the path to a URL.
142	fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false);
143	if (NULL == fileURL) {
144		goto bail;
145	}
146	property = CFURLCreatePropertyFromResource(kCFAllocatorDefault, fileURL, kCFURLFileExists, NULL);
147	if (NULL == property) {
148		goto bail;
149	}
150	status = CFBooleanGetValue(property);
151	if (!status) {
152		fprintf(stderr, "The file does not exist.\n");
153		goto bail;
154	}
155
156	// Read the XML file.
157	status = CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode);
158	if (!status) {
159		fprintf(stderr, "Error (%d) reading the file.\n", (int)errorCode);
160		goto bail;
161	}
162
163	// Reconstitute the dictionary using the XML data.
164	propertyList = CFPropertyListCreateWithData(kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, NULL, &errorString);
165	if (NULL == propertyList) {
166		CFShow(errorString);
167		goto bail;
168	}
169
170	// Some error checking.
171	if (!CFPropertyListIsValid(propertyList, kCFPropertyListXMLFormat_v1_0) || CFGetTypeID(propertyList) != CFDictionaryGetTypeID()) {
172		fprintf(stderr, "The file is invalid.\n");
173		CFRelease(propertyList);
174		propertyList = NULL;
175		goto bail;
176	}
177
178bail:
179	if (NULL != fileURL)
180		CFRelease(fileURL);
181	if (NULL != property)
182		CFRelease(property);
183	if (NULL != resourceData)
184		CFRelease(resourceData);
185
186	return propertyList;
187}
188
189Boolean
190write_plist_to_file(CFPropertyListRef propertyList, CFStringRef filePath)
191{
192	CFTypeRef   property = NULL;
193	CFURLRef	fileURL = NULL;
194	CFDataRef	xmlData = NULL;
195	Boolean		status = FALSE;
196	SInt32		errorCode = -1;
197	CFErrorRef	errorRef = NULL;
198
199	// Convert the path to a URL.
200	fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false);
201	if (NULL == fileURL) {
202		goto bail;
203	}
204	property = CFURLCreatePropertyFromResource(kCFAllocatorDefault, fileURL, kCFURLFileExists, NULL);
205	if (NULL == property) {
206		goto bail;
207	}
208	if (!CFBooleanGetValue(property)) {
209		fprintf(stderr, "The file does not exist.\n");
210		goto bail;
211	}
212
213	// Convert the property list into XML data.
214	xmlData = CFPropertyListCreateData(kCFAllocatorDefault, propertyList, kCFPropertyListXMLFormat_v1_0, 0, &errorRef);
215	if (errorRef) {
216		fprintf(stderr, "The file could not be written.\n");
217		goto bail;
218	}
219
220	// Write the XML data to the file.
221	if (!CFURLWriteDataAndPropertiesToResource(fileURL, xmlData, NULL, &errorCode)) {
222		fprintf(stderr, "The file could not be written.\n");
223		goto bail;
224	}
225
226	status = TRUE;
227bail:
228	if (NULL != xmlData)
229		CFRelease(xmlData);
230	if (NULL != fileURL)
231		CFRelease(fileURL);
232
233	return status;
234}
235
236static void merge_dictionaries(const void *key, const void *value, void *mergeDict)
237{
238	CFDictionarySetValue(mergeDict, key, value);
239}
240
241int
242authorizationdb(int argc, char * const * argv)
243{
244	AuthorizationRef auth_ref = NULL;
245	int ch;
246    while ((ch = getopt(argc, argv, "i")) != -1)
247	{
248		switch  (ch)
249		{
250		case 'i':
251			auth_ref = read_auth_ref_from_stdin();
252			break;
253		case '?':
254		default:
255			return 2;
256		}
257	}
258
259	argc -= optind;
260	argv += optind;
261
262	if (argc == 0)
263		return 2; // required right parameter(s)
264
265	OSStatus status;
266
267	if (argc > 1)
268	{
269		if (!auth_ref && AuthorizationCreate(NULL, NULL, 0, &auth_ref))
270			return -1;
271
272		if (!strcmp("read", argv[0]))
273		{
274			CFDictionaryRef right_definition;
275			status = AuthorizationRightGet(argv[1], &right_definition);
276			if (!status)
277			{
278				write_dict_to_stdout(right_definition);
279				CFRelease(right_definition);
280			}
281		}
282		else if (!strcmp("write", argv[0]))
283		{
284			if (argc == 2)
285			{
286				CFDictionaryRef right_definition = read_dict_from_stdin();
287				if (!right_definition)
288					return -1;
289				status = AuthorizationRightSet(auth_ref, argv[1], right_definition, NULL, NULL, NULL);
290				CFRelease(right_definition);
291			}
292			else if (argc == 3)
293			{
294				// argv[2] is shortcut string
295				CFStringRef shortcut_definition = CFStringCreateWithCStringNoCopy(NULL, argv[2], kCFStringEncodingUTF8, kCFAllocatorNull);
296				if (!shortcut_definition)
297					return -1;
298				status = AuthorizationRightSet(auth_ref, argv[1], shortcut_definition, NULL, NULL, NULL);
299				CFRelease(shortcut_definition);
300			}
301			else
302				return 2; // take one optional argument - no more
303
304		}
305		else if (!strcmp("remove", argv[0]))
306		{
307			status = AuthorizationRightRemove(auth_ref, argv[1]);
308		}
309		else if (!strcmp("smartcard", argv[0]))
310		{
311			if (argc == 2)
312            {
313                if(!strcmp("status", argv[1]))
314                {
315                    const CFStringRef SMARTCARD_LINE = CFSTR("builtin:smartcard-sniffer,privileged");
316                    const CFStringRef MECHANISMS = CFSTR("mechanisms");
317                    const CFStringRef BUILTIN_LINE = CFSTR("builtin:policy-banner");
318                    const char* SYSTEM_LOGIN_CONSOLE = "system.login.console";
319                    const char* AUTHENTICATE = "authenticate";
320
321                    CFIndex requiredLine1 = -1;
322                    CFIndex requiredLine2 = -1;
323
324                    CFDictionaryRef right_definition;
325                    status = AuthorizationRightGet(SYSTEM_LOGIN_CONSOLE, &right_definition);
326                    if(!status)
327                    {
328                        CFArrayRef mechanisms;
329
330                        Boolean res = CFDictionaryGetValueIfPresent(right_definition, MECHANISMS, (void*)&mechanisms);
331                        if(res)
332                        {
333                            // now parse all array elements until "builtin:policy-banner" is found
334                            CFIndex c = CFArrayGetCount(mechanisms);
335                            CFStringRef mechanismName;
336
337                            for (CFIndex i = 0; i < c; ++i)
338                            {
339                                mechanismName = CFArrayGetValueAtIndex(mechanisms, i);
340                                if(CFStringCompare(mechanismName, BUILTIN_LINE, 0) == kCFCompareEqualTo)
341                                {
342                                    if(i + 1 < c)
343                                    {
344                                        mechanismName = CFArrayGetValueAtIndex(mechanisms, i + 1);
345                                        if(CFStringCompare(mechanismName, SMARTCARD_LINE, 0) == kCFCompareEqualTo)
346                                        {
347                                            requiredLine1 = i + 1;
348                                        }
349                                        break;
350                                    }
351                                }
352                            }
353                        }
354                    CFRelease(right_definition);
355                    }
356                    status = AuthorizationRightGet(AUTHENTICATE, &right_definition);
357                    if(!status)
358                    {
359                        CFArrayRef mechanisms;
360
361                        Boolean res = CFDictionaryGetValueIfPresent(right_definition, MECHANISMS, (void*)&mechanisms);
362                        if(res)
363                        {
364                            // now parse all array elements until "builtin:policy-banner" is found
365                            CFIndex c = CFArrayGetCount(mechanisms);
366                            CFStringRef mechanismName;
367
368                            if(c > 0)
369                            {
370                                mechanismName = CFArrayGetValueAtIndex(mechanisms, 0);
371                                if(CFStringCompare(mechanismName, SMARTCARD_LINE, 0) == kCFCompareEqualTo)
372                                {
373                                    requiredLine2 = 0;
374                                }
375                            }
376                        }
377                        CFRelease(right_definition);
378                    }
379                    printf("Current smartcard login state: %s (system.login.console %s, authentication rule %s)\n", requiredLine1 != -1 && requiredLine2 != -1 ?"enabled":"disabled", requiredLine1 != -1 ? "enabled":"disabled", requiredLine2 != -1 ? "enabled":"disabled");
380
381                }
382                else if(!strcmp("disable", argv[1]))
383                    status = AuthorizationEnableSmartCard(auth_ref, FALSE);
384                else if(!strcmp("enable", argv[1]))
385                    status = AuthorizationEnableSmartCard(auth_ref, TRUE);
386                else
387                   return 2; // unrecognized parameter
388            }
389            else
390                return 2; // required parameter missing
391		}
392		else if (!strcmp("merge", argv[0])) {
393			status = 1;
394			CFStringRef sourcePath = NULL;
395			CFStringRef destPath = NULL;
396			CFPropertyListRef sourcePlist = NULL;
397			CFPropertyListRef destPlist = NULL;
398			CFDictionaryRef sourceRights = NULL;
399			CFDictionaryRef sourceRules = NULL;
400			CFDictionaryRef destRights = NULL;
401			CFDictionaryRef destRules = NULL;
402			CFIndex rightsCount = 0;
403			CFIndex rulesCount = 0;
404			CFMutableDictionaryRef mergeRights = NULL;
405			CFMutableDictionaryRef mergeRules = NULL;
406			CFMutableDictionaryRef outDict = NULL;
407
408			if (argc < 2 || argc > 3)
409				return 2;
410
411			if (!strcmp("-", argv[1])) {
412				// Merging from <STDIN>.
413				sourcePlist = read_dict_from_stdin();
414			} else {
415				sourcePath = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8);
416				if (NULL == sourcePath) {
417					goto bail;
418				}
419				sourcePlist = read_plist_from_file(sourcePath);
420			}
421			if (NULL == sourcePlist)
422				goto bail;
423			if (argc == 2) {
424				// Merging to /etc/authorization.
425				destPath = CFStringCreateWithCString(kCFAllocatorDefault, "/etc/authorization", kCFStringEncodingUTF8);
426			} else {
427				destPath = CFStringCreateWithCString(kCFAllocatorDefault, argv[2], kCFStringEncodingUTF8);
428			}
429			if (NULL == destPath) {
430				goto bail;
431			}
432			destPlist = read_plist_from_file(destPath);
433			if (NULL == destPlist)
434				goto bail;
435
436			sourceRights = CFDictionaryGetValue(sourcePlist, CFSTR("rights"));
437			sourceRules = CFDictionaryGetValue(sourcePlist, CFSTR("rules"));
438			destRights = CFDictionaryGetValue(destPlist, CFSTR("rights"));
439			destRules = CFDictionaryGetValue(destPlist, CFSTR("rules"));
440			if (sourceRights)
441				rightsCount += CFDictionaryGetCount(sourceRights);
442			if (destRights)
443				rightsCount += CFDictionaryGetCount(destRights);
444			mergeRights = CFDictionaryCreateMutable(NULL, rightsCount, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
445			if (NULL == mergeRights) {
446				goto bail;
447			}
448			if (sourceRules)
449				rulesCount += CFDictionaryGetCount(sourceRules);
450			if (destRules)
451				rulesCount += CFDictionaryGetCount(destRules);
452			mergeRules = CFDictionaryCreateMutable(NULL, rulesCount, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
453			if (NULL == mergeRules) {
454				goto bail;
455			}
456
457			if (destRights)
458				CFDictionaryApplyFunction(destRights, merge_dictionaries, mergeRights);
459			if (destRules)
460				CFDictionaryApplyFunction(destRules, merge_dictionaries, mergeRules);
461			if (sourceRights)
462				CFDictionaryApplyFunction(sourceRights, merge_dictionaries, mergeRights);
463			if (sourceRules)
464				CFDictionaryApplyFunction(sourceRules, merge_dictionaries, mergeRules);
465
466			outDict = CFDictionaryCreateMutable(NULL, 3, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
467			if (NULL == outDict) {
468				goto bail;
469			}
470			if (CFDictionaryContainsKey(sourcePlist, CFSTR("comment")))
471				CFDictionaryAddValue(outDict, CFSTR("comment"), CFDictionaryGetValue(sourcePlist, CFSTR("comment")));
472			else if (CFDictionaryContainsKey(destPlist, CFSTR("comment")))
473				CFDictionaryAddValue(outDict, CFSTR("comment"), CFDictionaryGetValue(destPlist, CFSTR("comment")));
474			CFDictionaryAddValue(outDict, CFSTR("rights"), mergeRights);
475			CFDictionaryAddValue(outDict, CFSTR("rules"), mergeRules);
476			if (!write_plist_to_file(outDict, destPath))
477				goto bail;
478
479			status = noErr;
480bail:
481			if (sourcePath)
482				CFRelease(sourcePath);
483			if (destPath)
484				CFRelease(destPath);
485			if (sourcePlist)
486				CFRelease(sourcePlist);
487			if (destPlist)
488				CFRelease(destPlist);
489			if (outDict)
490				CFRelease(outDict);
491		}
492		else
493			return 2;
494	}
495	else
496		return 2;
497
498	if (auth_ref)
499		AuthorizationFree(auth_ref, 0);
500
501	if (!do_quiet)
502		fprintf(stderr, "%s (%d)\n", status ? "NO" : "YES", (int)status);
503
504	return (status ? -1 : 0);
505}
506
507int
508authorize(int argc, char * const *argv)
509{
510	int ch;
511	OSStatus status;
512
513	Boolean user_interaction_allowed = FALSE, extend_rights = TRUE;
514	Boolean partial_rights = FALSE, destroy_rights = FALSE;
515	Boolean pre_authorize = FALSE, internalize = FALSE, externalize = FALSE;
516	Boolean wait = FALSE, explicit_credentials = FALSE;
517	Boolean isolate_explicit_credentials = FALSE, least_privileged = FALSE;
518	char *login = NULL;
519
520    while ((ch = getopt(argc, argv, "ucC:EpdPieqwxl")) != -1)
521	{
522		switch  (ch)
523		{
524		case 'u':
525			user_interaction_allowed = TRUE;
526			break;
527		case 'c':
528			explicit_credentials = TRUE;
529			break;
530		case 'C':
531			explicit_credentials = TRUE;
532			login = optarg;
533			break;
534		case 'e':
535			externalize = TRUE;
536			break;
537		case 'E':
538			extend_rights = FALSE;
539			break;
540		case 'p':
541			partial_rights = TRUE;
542			break;
543		case 'd':
544			destroy_rights = TRUE;
545			break;
546		case 'P':
547			pre_authorize = TRUE;
548			break;
549		case 'i':
550			internalize = TRUE;
551			break;
552		case 'w':
553			wait = TRUE;
554			externalize = TRUE;
555			break;
556		case 'x':
557			isolate_explicit_credentials = TRUE;
558			break;
559		case 'l':
560			least_privileged = TRUE;
561			break;
562		case '?':
563		default:
564			return 2; /* @@@ Return 2 triggers usage message. */
565		}
566	}
567
568	argc -= optind;
569	argv += optind;
570
571	if (argc == 0)
572		return 2; // required right parameter(s)
573
574// set up AuthorizationFlags
575	AuthorizationFlags flags = kAuthorizationFlagDefaults |
576		(user_interaction_allowed ? kAuthorizationFlagInteractionAllowed : 0) |
577		(extend_rights ? kAuthorizationFlagExtendRights : 0) |
578		(partial_rights ? kAuthorizationFlagPartialRights : 0) |
579		(pre_authorize ? kAuthorizationFlagPreAuthorize : 0) |
580		(least_privileged ? kAuthorizationFlagLeastPrivileged : 0);
581
582// set up AuthorizationRightSet
583	AuthorizationItem rights[argc];
584	memset(rights, '\0', argc * sizeof(AuthorizationItem));
585	AuthorizationItemSet rightset = { argc, rights };
586	while (argc > 0)
587		rights[--argc].name = *argv++;
588
589	AuthorizationRef auth_ref = NULL;
590
591// internalize AuthorizationRef
592	if (internalize)
593	{
594		auth_ref = read_auth_ref_from_stdin();
595		if (!auth_ref)
596			return 1;
597	}
598
599	if (!auth_ref && AuthorizationCreate(NULL, NULL,
600				(least_privileged ? kAuthorizationFlagLeastPrivileged : 0),
601				&auth_ref))
602		return -1;
603
604// prepare environment if needed
605	AuthorizationEnvironment *envp = NULL;
606	if (explicit_credentials) {
607		if (!login)
608			login = getlogin();
609		char *pass = getpass("Password:");
610		if (!(login && pass))
611			return 1;
612		static AuthorizationItem authenv[] = {
613			{ kAuthorizationEnvironmentUsername },
614			{ kAuthorizationEnvironmentPassword },
615			{ kAuthorizationEnvironmentShared }			// optional (see below)
616		};
617		static AuthorizationEnvironment env = { 0, authenv };
618		authenv[0].valueLength = strlen(login);
619		authenv[0].value = login;
620		authenv[1].valueLength = strlen(pass);
621		authenv[1].value = pass;
622		if (isolate_explicit_credentials)
623			env.count = 2;		// do not send kAuthorizationEnvironmentShared
624		else
625			env.count = 3;		// do send kAuthorizationEnvironmentShared
626		envp = &env;
627	}
628
629// perform Authorization
630	AuthorizationRights *granted_rights = NULL;
631	status = AuthorizationCopyRights(auth_ref, &rightset, envp, flags, &granted_rights);
632
633// externalize AuthorizationRef
634	if (externalize)
635		write_auth_ref_to_stdout(auth_ref);
636
637	if (!do_quiet)
638		fprintf(stderr, "%s (%d) ", status ? "NO" : "YES", (int)status);
639
640	if (!do_quiet && !status && granted_rights)
641	{
642		uint32_t index;
643		fprintf(stderr, "{ %d: ", (int)granted_rights->count);
644		for (index = 0; index < granted_rights->count; index++)
645		{
646			fprintf(stderr, "\"%s\"%s %c ", granted_rights->items[index].name,
647				(kAuthorizationFlagCanNotPreAuthorize & granted_rights->items[index].flags) ? " (cannot-preauthorize)" : "",
648				(index+1 != granted_rights->count) ? ',' : '}');
649		}
650		AuthorizationFreeItemSet(granted_rights);
651	}
652
653	if (!do_quiet)
654		fprintf(stderr, "\n");
655
656// wait for client to pick up AuthorizationRef
657	if (externalize && wait)
658		while (-1 != write(STDOUT_FILENO, NULL, 0))
659			usleep(100);
660
661// drop AuthorizationRef
662	if (auth_ref)
663		AuthorizationFree(auth_ref, destroy_rights ? kAuthorizationFlagDestroyRights : 0);
664
665	return (status ? -1 : 0);
666}
667
668
669int
670execute_with_privileges(int argc, char * const *argv)
671{
672	AuthorizationRef auth_ref = NULL;
673	int ch;
674    while ((ch = getopt(argc, argv, "i")) != -1)
675	{
676		switch  (ch)
677		{
678		case 'i':
679			auth_ref = read_auth_ref_from_stdin();
680			break;
681		case '?':
682		default:
683			return 2;
684		}
685	}
686
687	argc -= optind;
688	argv += optind;
689
690	if (argc == 0)
691		return 2; // required tool parameter(s)
692
693	OSStatus status;
694
695	if (!auth_ref && AuthorizationCreate(NULL, NULL, 0, &auth_ref))
696		return -1;
697
698	FILE *communications_pipe = NULL;
699
700	status = AuthorizationExecuteWithPrivileges(auth_ref,argv[0], 0, (argc > 1) ? &argv[1] : NULL, &communications_pipe);
701
702	if (!do_quiet)
703		fprintf(stderr, "%s (%d) ", status ? "NO" : "YES", (int)status);
704
705	if (!status)
706	{
707		int bytes_read = 0;
708		uint8_t buffer[4096];
709
710		while (bytes_read = read(STDIN_FILENO, &buffer, sizeof(buffer)))
711		{
712			if ((bytes_read == -1) && ((errno != EAGAIN) || (errno != EINTR)))
713				break;
714			else
715				while ((-1 == write(fileno(communications_pipe), buffer, bytes_read)) &&
716						((errno == EAGAIN) || (errno == EINTR)))
717							usleep(100);
718		}
719	}
720
721	return (status ? -1 : 0);
722}
723
724