6 #include "authd_private.h"
10 #include <Security/SecCode.h>
11 #include <libkern/OSAtomic.h>
12 #include <AssertMacros.h>
16 fprintf(stdout, "[BEGIN] %s\n", __FUNCTION__); \
19 #define INFO(fmt, ...) \
21 fprintf(stdout, fmt "\n", ##__VA_ARGS__); \
24 #define PASS(fmt, ...) \
26 fprintf(stdout, "[PASS] %s " fmt "\n", __FUNCTION__, ##__VA_ARGS__); \
29 #define FAIL(fmt, ...) \
31 fprintf(stdout, "[FAIL] %s " fmt "\n", __FUNCTION__, ##__VA_ARGS__); \
34 #define SAFE_RELEASE(x) \
42 enum xpcConnectionStates
{
43 kXPCConnectionStateNotCancelled
= 0,
44 kXPCConnectionStateCancelled
,
45 kXPCConnectionStateOkayToExit
,
46 kXPCConnectionStateServerNotAvailable
,
50 _validatePathFromSecCode(SecCodeRef processRef
, const char *path
)
54 SecStaticCodeRef staticProcessRef
= NULL
;
55 CFURLRef pathURL
= NULL
;
56 CFStringRef pathString
= NULL
;
58 /* Get the StaticCodeRef for this SecCodeRef */
59 status
= SecCodeCopyStaticCode(processRef
, kSecCSDefaultFlags
, &staticProcessRef
);
60 require_noerr_action(status
, exit
, ret
= -1);
62 INFO("Successfully created a SecStaticCodeRef");
64 /* Copy the path of requested service */
65 status
= SecCodeCopyPath(staticProcessRef
, kSecCSDefaultFlags
, &pathURL
);
66 require_noerr_action(status
, exit
, ret
= -1);
68 INFO("Successfully created a CFURLRef");
70 /* Get the CFStringRef from the CFURLRef */
71 pathString
= CFURLGetString(pathURL
);
72 require_action(pathString
, exit
, ret
= -1);
74 INFO("Successfully created a CFStingRef");
76 if (!strncmp(path
, CFStringGetCStringPtr(pathString
, kCFStringEncodingUTF8
), strlen(path
))) {
77 INFO("Successfully confirmed the location of requested service");
80 INFO("Location of service incorrect: %s", CFStringGetCStringPtr(pathString
, kCFStringEncodingUTF8
));
85 SAFE_RELEASE(pathURL
);
86 SAFE_RELEASE(staticProcessRef
);
92 CheckCreateWithXPCMessage(void)
98 xpc_connection_t connection
= NULL
;
99 xpc_object_t message
= NULL
, reply
= NULL
;
100 SecCodeRef processRef
= NULL
;
101 volatile static int xpcState
= kXPCConnectionStateNotCancelled
;
103 connection
= xpc_connection_create(SECURITY_AUTH_NAME
, NULL
);
104 if (NULL
== connection
) {
105 FAIL("Unable to create an XPC connection with %s", SECURITY_AUTH_NAME
);
109 INFO("XPC Connection with %s created", SECURITY_AUTH_NAME
);
111 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
112 if (xpc_get_type(event
) == XPC_TYPE_ERROR
&& event
== XPC_ERROR_CONNECTION_INVALID
) {
113 if (OSAtomicCompareAndSwapInt(kXPCConnectionStateCancelled
, kXPCConnectionStateOkayToExit
, &xpcState
)) {
114 INFO("XPC Connection Cancelled");
116 xpcState
= kXPCConnectionStateServerNotAvailable
;
117 FAIL("Authorization server not available");
122 xpc_connection_resume(connection
);
124 INFO("XPC Connection resumed");
126 /* Create an empty dictionary */
127 message
= xpc_dictionary_create(NULL
, NULL
, 0);
130 * Set _type to something invalid. This is done because authd will simply
131 * return an "invalid type" for this case, which means no state changes in
134 xpc_dictionary_set_uint64(message
, AUTH_XPC_TYPE
, AUTHORIZATION_COPY_RIGHT_PROPERTIES
+512);
136 /* Send object and wait for response */
137 reply
= xpc_connection_send_message_with_reply_sync(connection
, message
);
138 xpc_release(message
);
140 INFO("XPC Message received");
142 /* Create a SecCode using the XPC Message */
143 status
= SecCodeCreateWithXPCMessage(reply
, kSecCSDefaultFlags
, &processRef
);
145 FAIL("Unable to create a SecCodeRef from message reply [%d]", status
);
151 INFO("Successfully created a SecCodeRef");
153 const char *authdLocation
= "file:///System/Library/Frameworks/Security.framework/Versions/A/XPCServices/authd.xpc/";
154 if (_validatePathFromSecCode(processRef
, authdLocation
)) {
155 FAIL("Unable to verify authd location");
158 PASS("authd location successfully verified");
162 SAFE_RELEASE(processRef
);
164 // Potential race condition in getting an actual XPC_TYPE_ERROR vs getting
165 // a connection cancelled. We are okay with this since this is extremely unlikely...
166 if (OSAtomicCompareAndSwapInt(kXPCConnectionStateNotCancelled
, kXPCConnectionStateCancelled
, &xpcState
)) {
167 xpc_connection_cancel(connection
);
170 while (xpcState
!= kXPCConnectionStateOkayToExit
) {
171 if (xpcState
== kXPCConnectionStateServerNotAvailable
) {
181 CheckCreateWithXPCMessage_invalidXPCObject(void)
186 xpc_object_t invalidObject
= NULL
;
187 SecCodeRef processRef
= NULL
;
189 /* Create an NULL object */
190 invalidObject
= xpc_null_create();
192 INFO("Created a NULL object");
194 /* Try and acquire a SecCodeRef through the NULL object -- should fail with errSecCSInvalidObjectRef */
195 status
= SecCodeCreateWithXPCMessage(invalidObject
, kSecCSDefaultFlags
, &processRef
);
196 if (status
!= errSecCSInvalidObjectRef
) {
197 FAIL("Return code unexpected [%d]", status
);
201 PASS("Got expected return code");
206 CheckCreateWithXPCMessage_NULLConnectionInObject(void)
211 xpc_object_t emptyDictionary
= NULL
;
212 SecCodeRef processRef
= NULL
;
214 /* Create an empty dictionary object */
215 emptyDictionary
= xpc_dictionary_create_empty();
217 INFO("Created an empty dictionary object");
219 /* Try and acquire a SecCodeRef through the empty dictionary -- should fail with errSecCSInvalidObjectRef */
220 status
= SecCodeCreateWithXPCMessage(emptyDictionary
, kSecCSDefaultFlags
, &processRef
);
221 if (status
!= errSecCSInvalidObjectRef
) {
222 FAIL("Return code unexpected [%d]", status
);
226 PASS("Got expected return code");
232 fprintf(stdout
, "[TEST] secseccodeapitest\n");
235 int (*testList
[])(void) = {
236 CheckCreateWithXPCMessage
,
237 CheckCreateWithXPCMessage_invalidXPCObject
,
238 CheckCreateWithXPCMessage_NULLConnectionInObject
240 const int numberOfTests
= sizeof(testList
) / sizeof(*testList
);
241 int testResults
[numberOfTests
] = {0};
243 for (i
= 0; i
< numberOfTests
; i
++) {
244 testResults
[i
] = testList
[i
]();
247 fprintf(stdout
, "[SUMMARY]\n");
248 for (i
= 0; i
< numberOfTests
; i
++) {
249 fprintf(stdout
, "%d. %s\n", i
+1, testResults
[i
] == 0 ? "Passed" : "Failed");