1/*
2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <CoreFoundation/CoreFoundation.h>
37
38#include "UserEventAgentInterface.h"
39
40#include <sys/types.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <asl.h>
44
45#include "kcm.h"
46
47typedef struct {
48    UserEventAgentInterfaceStruct *agentInterface;
49    CFUUIDRef factoryID;
50    UInt32 refCount;
51
52    CFRunLoopRef rl;
53
54    CFNotificationCenterRef darwin;
55    CFNotificationCenterRef distributed;
56
57} GSSNotificationForwarder;
58
59static void
60GSSNotificationForwarderDelete(GSSNotificationForwarder *instance) {
61
62    CFUUIDRef factoryID = instance->factoryID;
63
64    asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "UserEventAgentFactory: %s", __func__);
65
66    /* XXX */
67
68    if (instance->darwin)
69	CFRelease(instance->darwin);
70    if (instance->distributed)
71	CFRelease(instance->distributed);
72    if (instance->rl)
73	CFRelease(instance->rl);
74
75    if (factoryID) {
76	CFPlugInRemoveInstanceForFactory(factoryID);
77	CFRelease(factoryID);
78    }
79    free(instance);
80}
81
82
83static void
84cc_changed(CFNotificationCenterRef center,
85	   void *observer,
86	   CFStringRef name,
87	   const void *object,
88	   CFDictionaryRef userInfo)
89{
90    GSSNotificationForwarder *instance = observer;
91
92    CFNotificationCenterPostNotification(instance->distributed,
93					 CFSTR(kCCAPICacheCollectionChangedNotification),
94					 NULL,
95					 NULL,
96					 false);
97}
98
99static void
100GSSNotificationForwarderInstall(void *pinstance)
101{
102    GSSNotificationForwarder *instance = pinstance;
103
104    asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "UserEventAgentFactory: %s", __func__);
105
106    instance->darwin = CFNotificationCenterGetDarwinNotifyCenter();
107    instance->distributed = CFNotificationCenterGetDistributedCenter();
108
109    CFNotificationCenterAddObserver(instance->darwin,
110				    instance,
111				    cc_changed,
112				    CFSTR(KRB5_KCM_NOTIFY_CACHE_CHANGED),
113				    NULL,
114				    CFNotificationSuspensionBehaviorHold);
115
116}
117
118
119static HRESULT
120GSSNotificationForwarderQueryInterface(void *pinstance, REFIID iid, LPVOID *ppv)
121{
122    CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(NULL, iid);
123    GSSNotificationForwarder *instance = pinstance;
124
125    asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "UserEventAgentFactory: %s", __func__);
126
127    if (CFEqual(interfaceID, kUserEventAgentInterfaceID) || CFEqual(interfaceID, IUnknownUUID)) {
128	instance->agentInterface->AddRef(instance);
129	*ppv = instance;
130	CFRelease(interfaceID);
131	return S_OK;
132    }
133
134    *ppv = NULL;
135    CFRelease(interfaceID);
136    return E_NOINTERFACE;
137}
138
139static ULONG
140GSSNotificationForwarderAddRef(void *pinstance)
141{
142    GSSNotificationForwarder *instance = pinstance;
143    return ++instance->refCount;
144}
145
146static ULONG
147GSSNotificationForwarderRelease(void *pinstance)
148{
149    GSSNotificationForwarder *instance = pinstance;
150    if (instance->refCount == 1) {
151	GSSNotificationForwarderDelete(instance);
152	return 0;
153    }
154    return --instance->refCount;
155}
156
157
158
159static UserEventAgentInterfaceStruct UserEventAgentInterfaceFtbl = {
160    NULL,
161    GSSNotificationForwarderQueryInterface,
162    GSSNotificationForwarderAddRef,
163    GSSNotificationForwarderRelease,
164    GSSNotificationForwarderInstall
165};
166
167
168static GSSNotificationForwarder *
169GSSNotificationForwarderCreate(CFAllocatorRef allocator, CFUUIDRef factoryID)
170{
171    GSSNotificationForwarder *instance;
172
173    asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "UserEventAgentFactory: %s", __func__);
174
175    instance = calloc(1, sizeof(*instance));
176    if (instance == NULL)
177	return NULL;
178
179    instance->agentInterface = &UserEventAgentInterfaceFtbl;
180    if (factoryID) {
181	instance->factoryID = (CFUUIDRef)CFRetain(factoryID);
182	CFPlugInAddInstanceForFactory(factoryID);
183    }
184
185    instance->rl = CFRunLoopGetCurrent();
186    CFRetain(instance->rl);
187
188    instance->refCount = 1;
189    return instance;
190}
191
192
193void *
194UserEventAgentFactory(CFAllocatorRef allocator, CFUUIDRef typeID);
195
196
197void *
198UserEventAgentFactory(CFAllocatorRef allocator, CFUUIDRef typeID)
199{
200    asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "UserEventAgentFactory: %s", __func__);
201
202    if (CFEqual(typeID, kUserEventAgentTypeID))
203	return GSSNotificationForwarderCreate(allocator, kUserEventAgentFactoryID);
204
205    return NULL;
206}
207