1/*
2 * Copyright (c) 2000, 2001, 2004-2010 Apple 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
24/*
25 * Modification History
26 *
27 * June 1, 2001			Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * November 9, 2000		Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34#include <SystemConfiguration/SystemConfiguration.h>
35#include <SystemConfiguration/SCPrivate.h>
36#include "SCPreferencesInternal.h"
37#include "SCHelper_client.h"
38
39#include <unistd.h>
40#include <pthread.h>
41
42static Boolean
43__SCPreferencesUnlock_helper(SCPreferencesRef prefs)
44{
45	Boolean			ok;
46	SCPreferencesPrivateRef	prefsPrivate	= (SCPreferencesPrivateRef)prefs;
47	uint32_t		status		= kSCStatusOK;
48
49	if (prefsPrivate->helper_port == MACH_PORT_NULL) {
50		// if no helper
51		goto fail;
52	}
53
54	// have the helper "unlock" the prefs
55//	status = kSCStatusOK;
56	ok = _SCHelperExec(prefsPrivate->helper_port,
57			   SCHELPER_MSG_PREFS_UNLOCK,
58			   NULL,
59			   &status,
60			   NULL);
61	if (!ok) {
62		goto fail;
63	}
64
65	if (status != kSCStatusOK) {
66		goto error;
67	}
68
69	prefsPrivate->locked = FALSE;
70	return TRUE;
71
72    fail :
73
74	// close helper
75	if (prefsPrivate->helper_port != MACH_PORT_NULL) {
76		_SCHelperClose(&prefsPrivate->helper_port);
77	}
78
79	status = kSCStatusAccessError;
80
81    error :
82
83	// return error
84	_SCErrorSet(status);
85	return FALSE;
86}
87
88
89static void
90reportDelay(SCPreferencesRef prefs, struct timeval *delay)
91{
92	aslmsg			m;
93	SCPreferencesPrivateRef	prefsPrivate	= (SCPreferencesPrivateRef)prefs;
94	char			str[256];
95
96	m = asl_new(ASL_TYPE_MSG);
97	asl_set(m, "com.apple.message.domain", "com.apple.SystemConfiguration.SCPreferencesUnlock");
98	(void) _SC_cfstring_to_cstring(prefsPrivate->name, str, sizeof(str), kCFStringEncodingUTF8);
99	asl_set(m, "com.apple.message.signature", str);
100	(void) _SC_cfstring_to_cstring(prefsPrivate->prefsID, str, sizeof(str), kCFStringEncodingUTF8);
101	asl_set(m, "com.apple.message.signature2", str);
102	(void) snprintf(str, sizeof(str),
103			"%d.%3.3d",
104			(int)delay->tv_sec,
105			delay->tv_usec / 1000);
106	asl_set(m, "com.apple.message.value", str);
107	SCLOG(NULL, m, ASL_LEVEL_DEBUG,
108	      CFSTR("SCPreferences(%@:%@) lock held for %d.%3.3d seconds"),
109	      prefsPrivate->name,
110	      prefsPrivate->prefsID,
111	      (int)delay->tv_sec,
112	      delay->tv_usec / 1000);
113	asl_free(m);
114
115	return;
116}
117
118
119Boolean
120SCPreferencesUnlock(SCPreferencesRef prefs)
121{
122	struct timeval		lockElapsed;
123	struct timeval		lockEnd;
124	SCPreferencesPrivateRef	prefsPrivate	= (SCPreferencesPrivateRef)prefs;
125
126	if (prefs == NULL) {
127		/* sorry, you must provide a session */
128		_SCErrorSet(kSCStatusNoPrefsSession);
129		return FALSE;
130	}
131
132	if (!prefsPrivate->locked) {
133		/* sorry, you don't have the lock */
134		_SCErrorSet(kSCStatusNeedLock);
135		return FALSE;
136	}
137
138	if (prefsPrivate->authorizationData != NULL) {
139		return __SCPreferencesUnlock_helper(prefs);
140	}
141
142	pthread_mutex_lock(&prefsPrivate->lock);
143
144	if (prefsPrivate->sessionKeyLock != NULL) {
145		SCDynamicStoreRemoveValue(prefsPrivate->session,
146					  prefsPrivate->sessionKeyLock);
147	}
148
149	if (prefsPrivate->lockFD != -1)	{
150		if (prefsPrivate->lockPath != NULL) {
151			unlink(prefsPrivate->lockPath);
152		}
153		close(prefsPrivate->lockFD);
154		prefsPrivate->lockFD = -1;
155	}
156
157	(void)gettimeofday(&lockEnd, NULL);
158	timersub(&lockEnd, &prefsPrivate->lockTime, &lockElapsed);
159	if (lockElapsed.tv_sec > 0) {
160		// if we held the lock for more than 1 second
161		reportDelay(prefs, &lockElapsed);
162	}
163
164	prefsPrivate->locked = FALSE;
165
166	pthread_mutex_unlock(&prefsPrivate->lock);
167	return TRUE;
168}
169