/ OSX / libsecurity_authorization / lib / Authorization.c
Authorization.c
  1  /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
  2  
  3  #include "Authorization.h"
  4  #include "authd_private.h"
  5  #include "authutilities.h"
  6  #include "debugging.h"
  7  
  8  #include <Security/AuthorizationPriv.h>
  9  #include <Security/AuthorizationDB.h>
 10  #include <Security/AuthorizationTags.h>
 11  #include <Security/AuthorizationTagsPriv.h>
 12  #include <utilities/SecDispatchRelease.h>
 13  #include <utilities/SecCFRelease.h>
 14  #include <xpc/xpc.h>
 15  #include <xpc/private.h>
 16  #include <mach/mach.h>
 17  #include <AssertMacros.h>
 18  #include <CoreFoundation/CFXPCBridge.h>
 19  #ifndef DARLING
 20  #include <CoreGraphics/CGWindow.h>
 21  #else
 22  typedef uint32_t CGWindowID;
 23  #endif
 24  #include <dlfcn.h>
 25  #include <os/log.h>
 26  
 27  static os_log_t AUTH_LOG_DEFAULT() {
 28      static dispatch_once_t once;
 29      static os_log_t log;
 30      dispatch_once(&once, ^{ log = os_log_create("com.apple.Authorization", "framework"); });
 31      return log;
 32  };
 33  
 34  #define AUTH_LOG AUTH_LOG_DEFAULT()
 35  
 36  static dispatch_queue_t
 37  get_authorization_dispatch_queue()
 38  {
 39      static dispatch_once_t onceToken = 0;
 40      static dispatch_queue_t connection_queue = NULL;
 41   
 42      dispatch_once(&onceToken, ^{
 43          connection_queue = dispatch_queue_create("authorization-connection-queue", DISPATCH_QUEUE_SERIAL);
 44      });
 45      
 46      return connection_queue;
 47  }
 48  
 49  static xpc_connection_t
 50  get_authorization_connection()
 51  {
 52      static xpc_connection_t connection = NULL;
 53      
 54      dispatch_sync(get_authorization_dispatch_queue(), ^{
 55          if (connection == NULL) {
 56              connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
 57  
 58              if (!connection) {
 59                  os_log_error(AUTH_LOG, "Failed to create xpc connection to %s", SECURITY_AUTH_NAME);
 60                  connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
 61              }
 62              
 63              if (connection == NULL) {
 64                  os_log_error(AUTH_LOG, "Still failed to create xpc connection to %s", SECURITY_AUTH_NAME);
 65                  return;
 66              }
 67              xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
 68                  if (xpc_get_type(event) == XPC_TYPE_ERROR) {
 69                      if (event == XPC_ERROR_CONNECTION_INVALID) {
 70                          os_log_error(AUTH_LOG, "Server not available");
 71                      }
 72                      // XPC_ERROR_CONNECTION_INTERRUPTED
 73                      // XPC_ERROR_TERMINATION_IMMINENT
 74                  } else {
 75                      char * desc = xpc_copy_description(event);
 76                      os_log_error(AUTH_LOG, "We should never get messages on this connection: %s", desc);
 77                      free(desc);
 78                  }
 79              });
 80              
 81              xpc_connection_resume(connection);
 82              
 83              // Send
 84              xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
 85              xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_SETUP);
 86              mach_port_t bootstrap = MACH_PORT_NULL;
 87              task_get_bootstrap_port(mach_task_self(), &bootstrap);
 88              xpc_dictionary_set_mach_send(message, AUTH_XPC_BOOTSTRAP, bootstrap);
 89              xpc_object_t reply = xpc_connection_send_message_with_reply_sync(connection, message);
 90              xpc_release_safe(message);
 91              xpc_release_safe(reply);
 92          }
 93      });
 94      
 95      return connection;
 96  }
 97  
 98  static void
 99  setItemSet(xpc_object_t message, const char * key, const AuthorizationItemSet * itemSet)
100  {
101      xpc_object_t serialized = SerializeItemSet(itemSet);
102      if (serialized) {
103          xpc_dictionary_set_value(message, key, serialized);
104          xpc_release(serialized);
105      }
106  }
107  
108  OSStatus AuthorizationCreate(const AuthorizationRights *rights,
109                      const AuthorizationEnvironment *environment,
110                      AuthorizationFlags flags,
111                      AuthorizationRef *authorization)
112  {
113      OSStatus status = errAuthorizationInternal;
114      xpc_object_t message = NULL;
115      xpc_object_t reply = NULL;
116  
117  //    require_action(!(rights == NULL && authorization == NULL), done, status = errAuthorizationInvalidSet);
118      
119      // Send
120      message = xpc_dictionary_create(NULL, NULL, 0);
121      require_action(message != NULL, done, status = errAuthorizationInternal);
122      
123      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE);
124      setItemSet(message, AUTH_XPC_RIGHTS, rights);
125      setItemSet(message, AUTH_XPC_ENVIRONMENT, environment);
126      xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags | (authorization ? 0 : kAuthorizationFlagNoData));
127      
128      // Reply
129      xpc_connection_t conn = get_authorization_connection();
130      require_action(conn != NULL, done, status = errAuthorizationInternal);
131      reply = xpc_connection_send_message_with_reply_sync(conn, message);
132      require_action_quiet(reply != NULL, done, status = errAuthorizationInternal);
133      require_action_quiet(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal;);
134  
135      // Status
136      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
137      
138      // Out
139      if (authorization && status == errAuthorizationSuccess) {
140          size_t len;
141          const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
142          require_action(data != NULL, done, status = errAuthorizationInternal);
143          require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
144          
145          AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
146          require_action(blob != NULL, done, status = errAuthorizationInternal);
147          *blob = *(AuthorizationBlob*)data;
148          
149          *authorization = (AuthorizationRef)blob;
150      }
151  
152  done:
153      xpc_release_safe(message);
154      xpc_release_safe(reply);
155      return status;
156  }
157  
158  OSStatus AuthorizationCreateWithAuditToken(audit_token_t token,
159                                   const AuthorizationEnvironment *environment,
160                                   AuthorizationFlags flags,
161                                   AuthorizationRef *authorization)
162  {
163      OSStatus status = errAuthorizationInternal;
164      xpc_object_t message = NULL;
165      xpc_object_t reply = NULL;
166      
167      require_action(authorization != NULL, done, status = errAuthorizationInvalidPointer);
168      
169      // Send
170      message = xpc_dictionary_create(NULL, NULL, 0);
171      require_action(message != NULL, done, status = errAuthorizationInternal);
172      
173      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_WITH_AUDIT_TOKEN);
174      xpc_dictionary_set_data(message, AUTH_XPC_DATA, &token, sizeof(token));
175      setItemSet(message, AUTH_XPC_ENVIRONMENT, environment);
176      xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
177      
178      // Reply
179      xpc_connection_t conn = get_authorization_connection();
180      require_action(conn != NULL, done, status = errAuthorizationInternal);
181      reply = xpc_connection_send_message_with_reply_sync(conn, message);
182      require_action(reply != NULL, done, status = errAuthorizationInternal);
183      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
184      
185      // Status
186      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
187      
188      // Out
189      if (status == errAuthorizationSuccess) {
190          size_t len;
191          const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
192          require_action(data != NULL, done, status = errAuthorizationInternal);
193          require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
194  
195          AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
196          require_action(blob != NULL, done, status = errAuthorizationInternal);
197          *blob = *(AuthorizationBlob*)data;
198          
199          *authorization = (AuthorizationRef)blob;
200      }
201      
202  done:
203      xpc_release_safe(message);
204      xpc_release_safe(reply);
205      return status;
206  }
207  
208  OSStatus AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags)
209  {
210      OSStatus status = errAuthorizationInternal;
211      xpc_object_t message = NULL;
212      xpc_object_t reply = NULL;
213      AuthorizationBlob *blob = NULL;
214  
215      require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
216      blob = (AuthorizationBlob *)authorization;
217      
218      // Send
219      message = xpc_dictionary_create(NULL, NULL, 0);
220      require_action(message != NULL, done, status = errAuthorizationInternal);
221      
222      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_FREE);
223      xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
224      xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
225  
226      // Reply
227      xpc_connection_t conn = get_authorization_connection();
228      require_action(conn != NULL, done, status = errAuthorizationInternal);
229      reply = xpc_connection_send_message_with_reply_sync(conn, message);
230      require_action(reply != NULL, done, status = errAuthorizationInternal);
231      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
232      
233      // Status
234      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
235      
236      // Free
237      free(blob);
238      
239  done:
240      xpc_release_safe(message);
241      xpc_release_safe(reply);
242      return status;
243  }
244  
245  OSStatus AuthorizationCopyRightProperties(const char *rightName, CFDictionaryRef *output)
246  {
247      OSStatus status = errAuthorizationInternal;
248      xpc_object_t reply = NULL;
249      CFDataRef data = NULL;
250      xpc_object_t message = NULL;
251      require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
252      
253      message = xpc_dictionary_create(NULL, NULL, 0);
254      require_action(message != NULL, done, status = errAuthorizationInternal);
255      
256      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHT_PROPERTIES);
257      xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
258      
259      xpc_connection_t conn = get_authorization_connection();
260      require_action(conn != NULL, done, status = errAuthorizationInternal);
261      reply = xpc_connection_send_message_with_reply_sync(conn, message);
262      require_action(reply != NULL, done, status = errAuthorizationInternal);
263      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
264      
265      // Status
266      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
267      if (output && status == errAuthorizationSuccess) {
268          size_t len;
269          const void *bytes = xpc_dictionary_get_data(reply, AUTH_XPC_OUT_ITEMS, &len);
270          data = CFDataCreate(kCFAllocatorDefault, bytes, len);
271          require_action(data != NULL, done, status = errAuthorizationInternal);
272          *output = CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, NULL);
273      }
274  done:
275  	xpc_release_safe(message);
276      xpc_release_safe(reply);
277      CFReleaseSafe(data);
278      
279  	return status;
280  }
281  
282  static OSStatus
283  _AuthorizationCopyRights_send_message(xpc_object_t message, AuthorizationRights **authorizedRights)
284  {
285      OSStatus status = errAuthorizationInternal;
286      xpc_object_t reply = NULL;
287  
288      // Send
289      require_action(message != NULL, done, status = errAuthorizationInternal);
290  
291      // Reply
292      xpc_connection_t conn = get_authorization_connection();
293      require_action(conn != NULL, done, status = errAuthorizationInternal);
294      reply = xpc_connection_send_message_with_reply_sync(conn, message);
295      require_action(reply != NULL, done, status = errAuthorizationInternal);
296      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
297  
298      // Status
299      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
300  
301      // Out
302      if (authorizedRights && status == errAuthorizationSuccess) {
303          xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS);
304          AuthorizationRights * grantedRights = DeserializeItemSet(tmpItems);
305          require_action(grantedRights != NULL, done, status = errAuthorizationInternal);
306  
307          *authorizedRights = grantedRights;
308      }
309  
310  done:
311      xpc_release_safe(reply);
312      return status;
313  }
314  
315  static OSStatus
316  _AuthorizationCopyRights_prepare_message(AuthorizationRef authorization, const AuthorizationRights *rights, const AuthorizationEnvironment *environment, AuthorizationFlags flags, xpc_object_t *message_out)
317  {
318      OSStatus status = errAuthorizationInternal;
319      AuthorizationBlob *blob = NULL;
320      xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
321      require_action(message != NULL, done, status = errAuthorizationInternal);
322  
323      require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
324      blob = (AuthorizationBlob *)authorization;
325  
326      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHTS);
327      xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
328      setItemSet(message, AUTH_XPC_RIGHTS, rights);
329      setItemSet(message, AUTH_XPC_ENVIRONMENT, environment);
330      xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
331  
332      *message_out = message;
333      message = NULL;
334      status = errAuthorizationSuccess;
335  
336  done:
337      xpc_release_safe(message);
338      return status;
339  }
340  
341  OSStatus AuthorizationCopyRights(AuthorizationRef authorization,
342                          const AuthorizationRights *rights,
343                          const AuthorizationEnvironment *environment,
344                          AuthorizationFlags flags,
345                          AuthorizationRights **authorizedRights)
346  {
347      OSStatus status = errAuthorizationInternal;
348      
349      if ((flags & kAuthorizationFlagSheet) && environment) {
350          // check if window ID is present in environment
351          CGWindowID window = 0;
352          for (UInt32 i = 0; i < environment->count; ++i) {
353              if (strncmp(environment->items[i].name, kAuthorizationEnvironmentWindowId, strlen(kAuthorizationEnvironmentWindowId)) == 0
354                  && (environment->items[i].valueLength = sizeof(window)) && environment->items[i].value) {
355                  window = *(CGWindowID *)environment->items[i].value;
356                  break;
357              }
358          }
359          if (window > 0) {
360              os_log_debug(AUTH_LOG, "Trying to use sheet version");
361              static OSStatus (*sheetAuthorizationWorker)(CGWindowID windowID, AuthorizationRef authorization,
362                                                          const AuthorizationRights *rights,
363                                                          const AuthorizationEnvironment *environment,
364                                                          AuthorizationFlags flags,
365                                                          AuthorizationRights **authorizedRights,
366                                                          Boolean *authorizationLaunched) = NULL;
367              static dispatch_once_t onceToken;
368              dispatch_once(&onceToken, ^{
369                  void *handle = dlopen("/System/Library/Frameworks/SecurityInterface.framework/SecurityInterface", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
370                  if (handle) {
371                      sheetAuthorizationWorker = dlsym(handle, "sheetAuthorizationWorker");
372                  }
373              });
374              
375              if (sheetAuthorizationWorker) {
376                  Boolean authorizationLaunched;
377                  status = sheetAuthorizationWorker(window, authorization, rights, environment, flags, authorizedRights, &authorizationLaunched);
378                  if (authorizationLaunched == true) {
379                      os_log_debug(AUTH_LOG, "Returning sheet result %d", (int)status);
380                      return status;
381                  }
382                  os_log(AUTH_LOG, "Sheet authorization cannot be used this time, falling back to the SecurityAgent UI");
383              } else {
384                  os_log_debug(AUTH_LOG, "Failed to find sheet support in SecurityInterface");
385              }
386              // fall back to the standard (windowed) version if sheets are not available
387              flags &= ~kAuthorizationFlagSheet;
388          }
389      }
390      
391      xpc_object_t message = NULL;
392  
393      require_noerr(status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message), done);
394      require_noerr(status = _AuthorizationCopyRights_send_message(message, authorizedRights), done);
395  
396  done:
397      xpc_release_safe(message);
398      return status;
399  }
400  
401  
402  void AuthorizationCopyRightsAsync(AuthorizationRef authorization,
403                           const AuthorizationRights *rights,
404                           const AuthorizationEnvironment *environment,
405                           AuthorizationFlags flags,
406                           AuthorizationAsyncCallback callbackBlock)
407  {
408      OSStatus prepare_status = errAuthorizationInternal;
409      __block xpc_object_t message = NULL;
410  
411      prepare_status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message);
412      if (prepare_status != errAuthorizationSuccess) {
413          callbackBlock(prepare_status, NULL);
414      }
415  
416      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
417  		AuthorizationRights *blockAuthorizedRights = NULL;
418          OSStatus status = _AuthorizationCopyRights_send_message(message, &blockAuthorizedRights);
419          callbackBlock(status, blockAuthorizedRights);
420          xpc_release_safe(message);
421  	});
422  }
423  
424  OSStatus AuthorizationDismiss()
425  {
426      OSStatus status = errAuthorizationInternal;
427      xpc_object_t message = NULL;
428      xpc_object_t reply = NULL;
429  
430      // Send
431      message = xpc_dictionary_create(NULL, NULL, 0);
432      require(message != NULL, done);
433      
434      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_DISMISS);
435      
436      // Reply
437      xpc_connection_t conn = get_authorization_connection();
438      require_action(conn != NULL, done, status = errAuthorizationInternal);
439      reply = xpc_connection_send_message_with_reply_sync(conn, message);
440      require_action(reply != NULL, done, status = errAuthorizationInternal);
441      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
442      
443      // Status
444      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
445      
446  done:
447      xpc_release_safe(message);
448      xpc_release_safe(reply);
449      return status;
450  }
451  
452  OSStatus AuthorizationCopyInfo(AuthorizationRef authorization,
453                        AuthorizationString tag,
454                        AuthorizationItemSet **info)
455  {
456      OSStatus status = errAuthorizationInternal;
457      xpc_object_t message = NULL;
458      xpc_object_t reply = NULL;
459      AuthorizationBlob *blob = NULL;
460      
461      require_action(info != NULL, done, status = errAuthorizationInvalidSet);
462      require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
463      blob = (AuthorizationBlob *)authorization;
464      
465      // Send
466      message = xpc_dictionary_create(NULL, NULL, 0);
467      require_action(message != NULL, done, status = errAuthorizationInternal);
468      
469      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_INFO);
470      xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
471      if (tag) {
472          xpc_dictionary_set_string(message, AUTH_XPC_TAG, tag);
473      }
474      
475      // Reply
476      xpc_connection_t conn = get_authorization_connection();
477      require_action(conn != NULL, done, status = errAuthorizationInternal);
478      reply = xpc_connection_send_message_with_reply_sync(conn, message);
479      require_action(reply != NULL, done, status = errAuthorizationInternal);
480      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
481      
482      // Status
483      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
484  
485      // Out
486      if (info && status == errAuthorizationSuccess) {
487          xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS);
488          AuthorizationRights * outInfo = DeserializeItemSet(tmpItems);
489          require_action(outInfo != NULL, done, status = errAuthorizationInternal);
490          
491          *info = outInfo;
492      }
493      
494  done:
495      xpc_release_safe(message);
496      xpc_release_safe(reply);
497      return status;
498  }
499  
500  OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization,
501                                AuthorizationExternalForm *extForm)
502  {
503      OSStatus status = errAuthorizationInternal;
504      xpc_object_t message = NULL;
505      xpc_object_t reply = NULL;
506      AuthorizationBlob *blob = NULL;
507      
508      require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer);
509      require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
510      blob = (AuthorizationBlob *)authorization;
511      
512      // Send
513      message = xpc_dictionary_create(NULL, NULL, 0);
514      require_action(message != NULL, done, status = errAuthorizationInternal);
515      
516      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_MAKE_EXTERNAL_FORM);
517      xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
518      
519      // Reply
520      xpc_connection_t conn = get_authorization_connection();
521      require_action(conn != NULL, done, status = errAuthorizationInternal);
522      reply = xpc_connection_send_message_with_reply_sync(conn, message);
523      require_action(reply != NULL, done, status = errAuthorizationInternal);
524      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
525      
526      // Status
527      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
528      
529      // out
530      if (status == errAuthorizationSuccess) {
531          size_t len;
532          const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_EXTERNAL, &len);
533          require_action(data != NULL, done, status = errAuthorizationInternal);
534          require_action(len == sizeof(AuthorizationExternalForm), done, status = errAuthorizationInternal);
535  
536          *extForm = *(AuthorizationExternalForm*)data;
537      }
538      
539  done:
540      xpc_release_safe(message);
541      xpc_release_safe(reply);
542      return status;
543  }
544  
545  OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *extForm,
546                                      AuthorizationRef *authorization)
547  {
548      OSStatus status = errAuthorizationInternal;
549      xpc_object_t message = NULL;
550      xpc_object_t reply = NULL;
551      
552      require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer);
553      require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
554      
555      // Send
556      message = xpc_dictionary_create(NULL, NULL, 0);
557      require_action(message != NULL, done, status = errAuthorizationInternal);
558      
559      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_FROM_EXTERNAL_FORM);
560      xpc_dictionary_set_data(message, AUTH_XPC_EXTERNAL, extForm, sizeof(AuthorizationExternalForm));
561      
562      // Reply
563      xpc_connection_t conn = get_authorization_connection();
564      require_action(conn != NULL, done, status = errAuthorizationInternal);
565      reply = xpc_connection_send_message_with_reply_sync(conn, message);
566      require_action(reply != NULL, done, status = errAuthorizationInternal);
567      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
568      
569      // Status
570      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
571      
572      // Out
573      if (authorization && status == errAuthorizationSuccess) {
574          size_t len;
575          const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
576          require_action(data != NULL, done, status = errAuthorizationInternal);
577          require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
578  
579          AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
580          require_action(blob != NULL, done, status = errAuthorizationInternal);
581          *blob = *(AuthorizationBlob*)data;
582          
583          *authorization = (AuthorizationRef)blob;
584      }
585      
586  done:
587      xpc_release_safe(message);
588      xpc_release_safe(reply);
589      return status;
590  }
591  
592  OSStatus AuthorizationFreeItemSet(AuthorizationItemSet *set)
593  {
594      FreeItemSet(set);
595      return errAuthorizationSuccess;
596  }
597  
598  OSStatus AuthorizationEnableSmartCard(AuthorizationRef authRef, Boolean enable)
599  {
600      OSStatus status = errAuthorizationInternal;
601      xpc_object_t message = NULL;
602      xpc_object_t reply = NULL;
603      AuthorizationBlob *blob = NULL;
604  
605      // Send
606      message = xpc_dictionary_create(NULL, NULL, 0);
607      require_action(message != NULL, done, status = errAuthorizationInternal);
608      require_action(authRef != NULL, done, status = errAuthorizationInvalidRef);
609      blob = (AuthorizationBlob *)authRef;
610      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_ENABLE_SMARTCARD);
611      xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
612      xpc_dictionary_set_bool(message, AUTH_XPC_DATA, enable);
613      
614      // Reply
615      xpc_connection_t conn = get_authorization_connection();
616      require_action(conn != NULL, done, status = errAuthorizationInternal);
617      reply = xpc_connection_send_message_with_reply_sync(conn, message);
618      require_action(reply != NULL, done, status = errAuthorizationInternal);
619      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
620      
621      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
622  
623  done:
624      xpc_release_safe(message);
625      xpc_release_safe(reply);
626      return status;
627  }
628  
629  
630  OSStatus AuthorizationRightGet(const char *rightName,
631                        CFDictionaryRef *rightDefinition)
632  {
633      OSStatus status = errAuthorizationInternal;
634      xpc_object_t message = NULL;
635      xpc_object_t reply = NULL;
636      
637      require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
638      
639      // Send
640      message = xpc_dictionary_create(NULL, NULL, 0);
641      require_action(message != NULL, done, status = errAuthorizationInternal);
642      
643      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_GET);
644      xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
645      
646      // Reply
647      xpc_connection_t conn = get_authorization_connection();
648      require_action(conn != NULL, done, status = errAuthorizationInternal);
649      reply = xpc_connection_send_message_with_reply_sync(conn, message);
650      require_action(reply != NULL, done, status = errAuthorizationInternal);
651      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
652      
653      // Status
654      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
655      
656      // Out
657      if (rightDefinition && status == errAuthorizationSuccess) {
658          xpc_object_t value = xpc_dictionary_get_value(reply, AUTH_XPC_DATA);
659          require_action(value != NULL, done, status = errAuthorizationInternal);
660          require_action(xpc_get_type(value) == XPC_TYPE_DICTIONARY, done, status = errAuthorizationInternal);
661          
662          CFTypeRef cfdict = _CFXPCCreateCFObjectFromXPCObject(value);
663          require_action(cfdict != NULL, done, status = errAuthorizationInternal);
664          
665          *rightDefinition = cfdict;
666      }
667      
668  done:
669      xpc_release_safe(message);
670      xpc_release_safe(reply);
671      return status;
672  }
673  
674  OSStatus AuthorizationRightSet(AuthorizationRef authRef,
675                        const char *rightName,
676                        CFTypeRef rightDefinition,
677                        CFStringRef descriptionKey,
678                        CFBundleRef bundle,
679                        CFStringRef tableName)
680  {
681      OSStatus status = errAuthorizationInternal;
682      xpc_object_t message = NULL;
683      xpc_object_t reply = NULL;
684      AuthorizationBlob *blob = NULL;
685      CFMutableDictionaryRef rightDict = NULL;
686      CFBundleRef clientBundle = bundle;
687      
688      if (bundle) {
689          CFRetain(bundle);
690      }
691      
692      require_action(rightDefinition != NULL, done, status = errAuthorizationInvalidPointer);
693      require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
694      require_action(authRef != NULL, done, status = errAuthorizationInvalidRef);
695      blob = (AuthorizationBlob *)authRef;
696      
697      // Send
698      message = xpc_dictionary_create(NULL, NULL, 0);
699      require_action(message != NULL, done, status = errAuthorizationInternal);
700      
701      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_SET);
702      xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
703      xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
704      
705      // Create rightDict
706      if (CFGetTypeID(rightDefinition) == CFStringGetTypeID()) {
707          rightDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
708          require_action(rightDict != NULL, done, status = errAuthorizationInternal);
709          
710          CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRightRule), rightDefinition);
711      
712      } else if (CFGetTypeID(rightDefinition) == CFDictionaryGetTypeID()) {
713          rightDict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, rightDefinition);
714          require_action(rightDict != NULL, done, status = errAuthorizationInternal);
715      
716      } else {
717          status = errAuthorizationInvalidPointer;
718          goto done;
719      }
720      
721      // Create locDict
722      if (descriptionKey) {
723          CFMutableDictionaryRef locDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
724          require_action(locDict != NULL, done, status = errAuthorizationInternal);
725          
726          if (clientBundle == NULL) {
727              clientBundle = CFBundleGetMainBundle();
728              CFRetain(clientBundle);
729          }
730          
731          if (clientBundle) {
732              CFArrayRef bundleLocalizations = CFBundleCopyBundleLocalizations(clientBundle);
733              if (bundleLocalizations) {
734                  // for every CFString in localizations do
735                  CFIndex locIndex, allLocs = CFArrayGetCount(bundleLocalizations);
736                  for (locIndex = 0; locIndex < allLocs; locIndex++)
737                  {
738                      CFStringRef oneLocalization = (CFStringRef)CFArrayGetValueAtIndex(bundleLocalizations, locIndex);
739                      
740                      if (!oneLocalization)
741                          continue;
742                      
743                      // @@@ no way to get "Localized" and "strings" as constants?
744                      CFURLRef locURL = CFBundleCopyResourceURLForLocalization(clientBundle, tableName ? tableName :  CFSTR("Localizable"), CFSTR("strings"), NULL /*subDirName*/, oneLocalization);
745                      
746                      if (!locURL)
747                          continue;
748                      
749                      CFDataRef tableData = NULL;
750                      SInt32 errCode;
751                      CFStringRef errStr = NULL;
752                      CFPropertyListRef stringTable = NULL;
753                      
754                      CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle), locURL, &tableData, NULL, NULL, &errCode);
755                      CFReleaseSafe(locURL);
756                      if (errCode)
757                      {
758                          CFReleaseSafe(tableData);
759                          continue;
760                      }
761                      
762                      stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle), tableData, kCFPropertyListImmutable, &errStr);
763                      CFReleaseSafe(errStr);
764                      CFReleaseSafe(tableData);
765                      
766                      CFStringRef value = (CFStringRef)CFDictionaryGetValue(stringTable, descriptionKey);
767                      if (value == NULL || CFEqual(value, CFSTR(""))) {
768                          CFReleaseSafe(stringTable);
769                          continue;
770                      } else {
771                          // oneLocalization/value into our dictionary 
772                          CFDictionarySetValue(locDict, oneLocalization, value);
773                          CFReleaseSafe(stringTable);
774                      }
775                  }
776                  CFReleaseSafe(bundleLocalizations);
777              }
778          }
779          
780          // add the description as the default localization into the dictionary
781  		CFDictionarySetValue(locDict, CFSTR(""), descriptionKey);
782  		
783  		// stuff localization table into right definition
784  		CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRuleParameterDefaultPrompt), locDict);
785          CFReleaseSafe(locDict);
786      }
787      
788      xpc_object_t value = _CFXPCCreateXPCObjectFromCFObject(rightDict);
789      xpc_dictionary_set_value(message, AUTH_XPC_DATA, value);
790      xpc_release_safe(value);
791      
792      // Reply
793      xpc_connection_t conn = get_authorization_connection();
794      require_action(conn != NULL, done, status = errAuthorizationInternal);
795      reply = xpc_connection_send_message_with_reply_sync(conn, message);
796      require_action(reply != NULL, done, status = errAuthorizationInternal);
797      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
798      
799      // Status
800      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
801      
802  done:
803      CFReleaseSafe(clientBundle);
804      CFReleaseSafe(rightDict);
805      xpc_release_safe(message);
806      xpc_release_safe(reply);
807      return status;
808  }
809  
810  OSStatus AuthorizationRightRemove(AuthorizationRef authorization,
811                           const char *rightName)
812  {
813      OSStatus status = errAuthorizationInternal;
814      xpc_object_t message = NULL;
815      xpc_object_t reply = NULL;
816      AuthorizationBlob *blob = NULL;
817      
818      require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
819      require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
820      blob = (AuthorizationBlob *)authorization;
821      
822      // Send
823      message = xpc_dictionary_create(NULL, NULL, 0);
824      require_action(message != NULL, done, status = errAuthorizationInternal);
825      
826      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_REMOVE);
827      xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
828      xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
829      
830      // Reply
831      xpc_connection_t conn = get_authorization_connection();
832      require_action(conn != NULL, done, status = errAuthorizationInternal);
833      reply = xpc_connection_send_message_with_reply_sync(conn, message);
834      require_action(reply != NULL, done, status = errAuthorizationInternal);
835      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
836      
837      // Status
838      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
839      
840  done:
841      xpc_release_safe(message);
842      xpc_release_safe(reply);
843      return status;
844  }
845  
846  OSStatus AuthorizationCopyPreloginUserDatabase(const char * _Nullable const volumeUuid, const UInt32 flags, CFArrayRef _Nonnull * _Nonnull output)
847  {
848      OSStatus status = errAuthorizationInternal;
849      xpc_object_t message = NULL;
850      xpc_object_t reply = NULL;
851  
852      require_action(output != NULL, done, status = errAuthorizationInvalidRef);
853      
854      // Send
855      message = xpc_dictionary_create(NULL, NULL, 0);
856      require_action(message != NULL, done, status = errAuthorizationInternal);
857      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_PRELOGIN_USERDB);
858      if (volumeUuid) {
859          xpc_dictionary_set_string(message, AUTH_XPC_TAG, volumeUuid);
860      }
861      xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
862  
863      // Reply
864      xpc_connection_t conn = get_authorization_connection();
865      require_action(conn != NULL, done, status = errAuthorizationInternal);
866      reply = xpc_connection_send_message_with_reply_sync(conn, message);
867      require_action(reply != NULL, done, status = errAuthorizationInternal);
868      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
869      
870      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
871      
872      // fill the output
873      if (status == errAuthorizationSuccess) {
874          *output = _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(reply, AUTH_XPC_DATA));
875      }
876  
877  done:
878      xpc_release_safe(message);
879      xpc_release_safe(reply);
880      return status;
881  }
882  
883  OSStatus AuthorizationCopyPreloginPreferencesValue(const char * _Nonnull const volumeUuid, const char * _Nullable const username, const char * _Nonnull const domain, const char * _Nullable const item, CFTypeRef _Nonnull * _Nonnull output)
884  {
885      OSStatus status = errAuthorizationInternal;
886      xpc_object_t message = NULL;
887      xpc_object_t reply = NULL;
888  
889      require_action(output != NULL, done, status = errAuthorizationInvalidRef);
890      
891      // Send
892      message = xpc_dictionary_create(NULL, NULL, 0);
893      require_action(message != NULL, done, status = errAuthorizationInternal);
894      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_PRELOGIN_PREFS);
895      if (volumeUuid) {
896          xpc_dictionary_set_string(message, AUTH_XPC_TAG, volumeUuid);
897      }
898      if (username) {
899          xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, username);
900      }
901      if (domain) {
902          xpc_dictionary_set_string(message, AUTH_XPC_HINTS_NAME, domain);
903      }
904      if (item) {
905          xpc_dictionary_set_string(message, AUTH_XPC_ITEM_NAME, item);
906      }
907  
908      // Reply
909      reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
910      require_action(reply != NULL, done, status = errAuthorizationInternal);
911      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
912      
913      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
914      
915      // fill the output
916      if (status == errAuthorizationSuccess) {
917          *output = _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(reply, AUTH_XPC_DATA));
918      }
919  
920  done:
921      xpc_release_safe(message);
922      xpc_release_safe(reply);
923      return status;
924  }
925  
926  OSStatus AuthorizationHandlePreloginOverride(const char * _Nonnull const volumeUuid, const char operation, Boolean * _Nullable result)
927  {
928      OSStatus status = errAuthorizationInternal;
929      xpc_object_t message = NULL;
930      xpc_object_t reply = NULL;
931      
932      // Send
933      message = xpc_dictionary_create(NULL, NULL, 0);
934      require_action(message != NULL, done, status = errAuthorizationInternal);
935      xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_PRELOGIN_SC_OVERRIDE);
936      if (volumeUuid) {
937          xpc_dictionary_set_string(message, AUTH_XPC_TAG, volumeUuid);
938      }
939      uint64_t op = operation;
940      xpc_dictionary_set_uint64(message, AUTH_XPC_ITEM_NAME, op);
941  
942      // Reply
943      reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
944      require_action(reply != NULL, done, status = errAuthorizationInternal);
945      require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
946      
947      status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
948      
949      // fill the output only if it is present in the dictionary and caller requested it
950      if (status == errAuthorizationSuccess && result && xpc_dictionary_get_value(reply, AUTH_XPC_ITEM_VALUE)) {
951          *result = xpc_dictionary_get_bool(reply, AUTH_XPC_ITEM_VALUE);
952      }
953  
954  done:
955      xpc_release_safe(message);
956      xpc_release_safe(reply);
957      return status;
958  }