]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c
47cba02ac07fd1ef39f97de71a534041aaaaee1c
[apple/security.git] / Security / sec / SOSCircle / SecureObjectSync / SOSAccountCircles.c
1 //
2 // SOSAccountCircles.c
3 // sec
4 //
5
6 #include "SOSAccountPriv.h"
7 #include <SecureObjectSync/SOSTransport.h>
8 #include <SecureObjectSync/SOSTransportKeyParameterKVS.h>
9 #include <SecureObjectSync/SOSTransportCircleKVS.h>
10 #include <SecureObjectSync/SOSTransportMessageKVS.h>
11
12 void SOSAccountForEachCircle(SOSAccountRef account, void (^process)(SOSCircleRef circle))
13 {
14 CFDictionaryForEach(account->circles, ^(const void* key, const void* value) {
15 assert(value);
16 process((SOSCircleRef)value);
17 });
18 }
19
20
21 void SOSAccountForEachKnownCircle(SOSAccountRef account,
22 void (^handle_incompatible)(CFStringRef name),
23 void (^handle_no_peer)(SOSCircleRef circle),
24 void (^handle_peer)(SOSCircleRef circle, SOSFullPeerInfoRef full_peer)) {
25 CFDictionaryForEach(account->circles, ^(const void *key, const void *value) {
26 if (isNull(value)) {
27 if (handle_incompatible)
28 handle_incompatible((CFStringRef)key);
29 } else {
30 SOSCircleRef circle = (SOSCircleRef) value;
31 CFRetainSafe(circle);
32 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(circle), NULL);
33 if (!fpi) {
34 if (handle_no_peer)
35 handle_no_peer(circle);
36 } else {
37 CFRetainSafe(fpi);
38 if (handle_peer)
39 handle_peer(circle, fpi);
40 CFReleaseSafe(fpi);
41 }
42 CFReleaseSafe(circle);
43 }
44 });
45 }
46
47 //
48 // MARK: Circle management
49 //
50
51 int SOSAccountCountCircles(SOSAccountRef a) {
52 assert(a);
53 assert(a->circle_identities);
54 assert(a->circles);
55 return (int)CFDictionaryGetCount(a->circles);
56 }
57
58
59
60 SOSCircleRef SOSAccountFindCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error)
61 {
62 CFTypeRef entry = CFDictionaryGetValue(a->circles, name);
63
64 require_action_quiet(!isNull(entry), fail,
65 SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Incompatible circle in KVS"), NULL, error));
66
67 require_action_quiet(entry, fail,
68 SOSCreateError(kSOSErrorNoCircle, CFSTR("No circle found"), NULL, error));
69
70
71 return (SOSCircleRef) entry;
72
73 fail:
74 return NULL;
75 }
76
77
78 static bool SOSAccountInflateTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){
79 bool success = false;
80 SOSTransportKeyParameterRef tKey = NULL;
81 SOSTransportCircleRef tCircle = NULL;
82 SOSTransportMessageRef tMessage = NULL;
83 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamed(account, circleName, error);
84 require_quiet(fpi, fail);
85 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
86 require_quiet(myPeer, fail);
87 CFStringRef type = SOSPeerInfoGetTransportType(myPeer);
88 if(CFStringCompare(type, CFSTR("KVS"), 0) == kCFCompareEqualTo){
89 tKey = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(account, error);
90 tCircle = (SOSTransportCircleRef)SOSTransportCircleKVSCreate(account, circleName, error);
91 tMessage = (SOSTransportMessageRef)SOSTransportMessageKVSCreate(account, circleName, error);
92 require_quiet(tKey, fail);
93 require_quiet(tCircle, fail);
94 require_quiet(tMessage, fail);
95
96 CFRetainAssign(account->key_transport, (SOSTransportKeyParameterRef)tKey);
97 CFDictionarySetValue(account->circle_transports, circleName, tCircle);
98 CFDictionarySetValue(account->message_transports, circleName, tMessage);
99 }
100
101 success = true;
102 fail:
103 CFReleaseNull(tKey);
104 CFReleaseNull(tCircle);
105 CFReleaseNull(tMessage);
106 return success;
107 }
108
109 SOSCircleRef SOSAccountEnsureCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error)
110 {
111 CFErrorRef localError = NULL;
112
113 SOSCircleRef circle = SOSAccountFindCircle(a, name, &localError);
114
115 require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail,
116 if (error) { *error = localError; localError = NULL; });
117
118 if(NULL == circle){
119 circle = SOSCircleCreate(NULL, name, NULL);
120 if (circle){
121 CFDictionaryAddValue(a->circles, name, circle);
122 CFRelease(circle);
123 circle = SOSAccountFindCircle(a, name, &localError);
124 }
125
126 SOSUpdateKeyInterest();
127 }
128
129 require_quiet(SOSAccountInflateTransportsForCircle(a, name, error), fail);
130
131 fail:
132 CFReleaseNull(localError);
133 return circle;
134 }
135
136
137 bool SOSAccountUpdateCircleFromRemote(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error)
138 {
139 return SOSAccountHandleUpdateCircle(account, newCircle, false, error);
140 }
141
142 bool SOSAccountUpdateCircle(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error)
143 {
144 return SOSAccountHandleUpdateCircle(account, newCircle, true, error);
145 }
146
147 bool SOSAccountModifyCircle(SOSAccountRef account,
148 CFStringRef circleName,
149 CFErrorRef* error,
150 bool (^action)(SOSCircleRef circle))
151 {
152 bool success = false;
153
154 SOSCircleRef circle = NULL;
155 SOSCircleRef accountCircle = SOSAccountFindCircle(account, circleName, error);
156 require_quiet(accountCircle, fail);
157
158 circle = SOSCircleCopyCircle(kCFAllocatorDefault, accountCircle, error);
159 require_quiet(circle, fail);
160
161 success = true;
162 require_quiet(action(circle), fail);
163
164 success = SOSAccountUpdateCircle(account, circle, error);
165
166 fail:
167 CFReleaseSafe(circle);
168 return success;
169 }
170