Line data Source code
1 : /* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <config_features.h>
21 :
22 : #include "uunxapi.hxx"
23 : #include "system.hxx"
24 : #include <limits.h>
25 : #include <rtl/ustring.hxx>
26 : #include <osl/thread.h>
27 :
28 : #ifdef ANDROID
29 : #include <osl/detail/android-bootstrap.h>
30 : #endif
31 :
32 301430 : inline rtl::OString OUStringToOString(const rtl_uString* s)
33 : {
34 : return rtl::OUStringToOString(rtl::OUString(const_cast<rtl_uString*>(s)),
35 301430 : osl_getThreadTextEncoding());
36 : }
37 :
38 : #if HAVE_FEATURE_MACOSX_SANDBOX
39 :
40 : #include <Foundation/Foundation.h>
41 : #include <Security/Security.h>
42 : #include <mach-o/dyld.h>
43 :
44 : static NSUserDefaults *userDefaults = NULL;
45 : static bool isSandboxed = false;
46 :
47 : static void do_once()
48 : {
49 : SecCodeRef code;
50 : OSStatus rc = SecCodeCopySelf(kSecCSDefaultFlags, &code);
51 :
52 : SecStaticCodeRef staticCode;
53 : if (rc == errSecSuccess)
54 : rc = SecCodeCopyStaticCode(code, kSecCSDefaultFlags, &staticCode);
55 :
56 : CFDictionaryRef signingInformation;
57 : if (rc == errSecSuccess)
58 : rc = SecCodeCopySigningInformation(staticCode, kSecCSRequirementInformation, &signingInformation);
59 :
60 : CFDictionaryRef entitlements = NULL;
61 : if (rc == errSecSuccess)
62 : entitlements = (CFDictionaryRef) CFDictionaryGetValue(signingInformation, kSecCodeInfoEntitlementsDict);
63 :
64 : if (entitlements != NULL)
65 : if (CFDictionaryGetValue(entitlements, CFSTR("com.apple.security.app-sandbox")) != NULL)
66 : isSandboxed = true;
67 :
68 : if (isSandboxed)
69 : userDefaults = [NSUserDefaults standardUserDefaults];
70 : }
71 :
72 : typedef struct {
73 : NSURL *scopeURL;
74 : NSAutoreleasePool *pool;
75 : } accessFilePathState;
76 :
77 : static accessFilePathState *
78 : prepare_to_access_file_path( const char *cpFilePath )
79 : {
80 : static pthread_once_t once = PTHREAD_ONCE_INIT;
81 : pthread_once(&once, &do_once);
82 : NSURL *fileURL = nil;
83 : NSData *data = nil;
84 : BOOL stale;
85 : accessFilePathState *state;
86 :
87 : if (!isSandboxed)
88 : return NULL;
89 :
90 : // If malloc() fails we are screwed anyway
91 : state = (accessFilePathState*) malloc(sizeof(accessFilePathState));
92 :
93 : state->pool = [[NSAutoreleasePool alloc] init];
94 : state->scopeURL = nil;
95 :
96 : if (userDefaults != nil)
97 : fileURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:cpFilePath]];
98 :
99 : if (fileURL != nil)
100 : data = [userDefaults dataForKey:[@"bookmarkFor:" stringByAppendingString:[fileURL absoluteString]]];
101 :
102 : if (data != nil)
103 : state->scopeURL = [NSURL URLByResolvingBookmarkData:data
104 : options:NSURLBookmarkResolutionWithSecurityScope
105 : relativeToURL:nil
106 : bookmarkDataIsStale:&stale
107 : error:nil];
108 : if (state->scopeURL != nil)
109 : [state->scopeURL startAccessingSecurityScopedResource];
110 :
111 : return state;
112 : }
113 :
114 : static void
115 : done_accessing_file_path( const char * /*cpFilePath*/, accessFilePathState *state )
116 : {
117 : if (!isSandboxed)
118 : return;
119 :
120 : int saved_errno = errno;
121 :
122 : if (state->scopeURL != nil)
123 : [state->scopeURL stopAccessingSecurityScopedResource];
124 : [state->pool release];
125 : free(state);
126 :
127 : errno = saved_errno;
128 : }
129 :
130 : #else
131 :
132 : typedef void accessFilePathState;
133 :
134 : #define prepare_to_access_file_path( cpFilePath ) NULL
135 :
136 : #define done_accessing_file_path( cpFilePath, state ) ((void) cpFilePath, (void) state)
137 :
138 : #endif
139 :
140 : #ifdef MACOSX
141 : /*
142 : * Helper function for resolving Mac native alias files (not the same as unix alias files)
143 : * and to return the resolved alias as rtl::OString
144 : */
145 : static rtl::OString macxp_resolveAliasAndConvert(rtl::OString const & p)
146 : {
147 : sal_Char path[PATH_MAX];
148 : if (p.getLength() < PATH_MAX)
149 : {
150 : strcpy(path, p.getStr());
151 : macxp_resolveAlias(path, PATH_MAX);
152 : return rtl::OString(path);
153 : }
154 : return p;
155 : }
156 : #endif /* MACOSX */
157 :
158 212909 : int access_u(const rtl_uString* pustrPath, int mode)
159 : {
160 212909 : rtl::OString fn = OUStringToOString(pustrPath);
161 : #ifdef ANDROID
162 : if (fn == "/assets" || fn.startsWith("/assets/"))
163 : {
164 : struct stat stat;
165 : if (lo_apk_lstat(fn.getStr(), &stat) == -1)
166 : return -1;
167 : if (mode & W_OK)
168 : {
169 : errno = EACCES;
170 : return -1;
171 : }
172 : return 0;
173 : }
174 : #endif
175 :
176 : #ifdef MACOSX
177 : fn = macxp_resolveAliasAndConvert(fn);
178 : #endif
179 :
180 212909 : accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
181 :
182 212909 : int result = access(fn.getStr(), mode);
183 :
184 212909 : done_accessing_file_path(fn.getStr(), state);
185 :
186 212909 : return result;
187 : }
188 :
189 2165 : bool realpath_u(const rtl_uString* pustrFileName, rtl_uString** ppustrResolvedName)
190 : {
191 2165 : rtl::OString fn = OUStringToOString(pustrFileName);
192 : #ifdef ANDROID
193 : if (fn == "/assets" || fn.startsWith("/assets/"))
194 : {
195 : if (access_u(pustrFileName, F_OK) == -1)
196 : return false;
197 :
198 : rtl_uString silly(*pustrFileName);
199 : rtl_uString_assign(ppustrResolvedName, &silly);
200 :
201 : return true;
202 : }
203 : #endif
204 :
205 : #ifdef MACOSX
206 : fn = macxp_resolveAliasAndConvert(fn);
207 : #endif
208 :
209 2165 : accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
210 :
211 : char rp[PATH_MAX];
212 2165 : bool bRet = realpath(fn.getStr(), rp);
213 :
214 2165 : done_accessing_file_path(fn.getStr(), state);
215 :
216 2165 : if (bRet)
217 : {
218 : rtl::OUString resolved = rtl::OStringToOUString(rtl::OString(static_cast<sal_Char*>(rp)),
219 2165 : osl_getThreadTextEncoding());
220 :
221 2165 : rtl_uString_assign(ppustrResolvedName, resolved.pData);
222 : }
223 2165 : return bRet;
224 : }
225 :
226 4616 : int stat_c(const char* cpPath, struct stat* buf)
227 : {
228 : #ifdef ANDROID
229 : if (strncmp(cpPath, "/assets", sizeof("/assets")-1) == 0 &&
230 : (cpPath[sizeof("/assets")-1] == '\0' ||
231 : cpPath[sizeof("/assets")-1] == '/'))
232 : return lo_apk_lstat(cpPath, buf);
233 : #endif
234 :
235 4616 : accessFilePathState *state = prepare_to_access_file_path(cpPath);
236 :
237 4616 : int result = stat(cpPath, buf);
238 :
239 : done_accessing_file_path(cpPath, state);
240 :
241 4616 : return result;
242 : }
243 :
244 119322 : int lstat_c(const char* cpPath, struct stat* buf)
245 : {
246 : #ifdef ANDROID
247 : if (strncmp(cpPath, "/assets", sizeof("/assets")-1) == 0 &&
248 : (cpPath[sizeof("/assets")-1] == '\0' ||
249 : cpPath[sizeof("/assets")-1] == '/'))
250 : return lo_apk_lstat(cpPath, buf);
251 : #endif
252 :
253 119322 : accessFilePathState *state = prepare_to_access_file_path(cpPath);
254 :
255 119322 : int result = lstat(cpPath, buf);
256 :
257 : done_accessing_file_path(cpPath, state);
258 :
259 119322 : return result;
260 : }
261 :
262 83014 : int lstat_u(const rtl_uString* pustrPath, struct stat* buf)
263 : {
264 83014 : rtl::OString fn = OUStringToOString(pustrPath);
265 :
266 : #ifdef MACOSX
267 : fn = macxp_resolveAliasAndConvert(fn);
268 : #endif
269 :
270 83014 : return lstat_c(fn.getStr(), buf);
271 : }
272 :
273 1671 : int mkdir_u(const rtl_uString* path, mode_t mode)
274 : {
275 1671 : rtl::OString fn = OUStringToOString(path);
276 :
277 1671 : accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
278 :
279 1671 : int result = mkdir(OUStringToOString(path).getStr(), mode);
280 :
281 1671 : done_accessing_file_path(fn.getStr(), state);
282 :
283 1671 : return result;
284 : }
285 :
286 133443 : int open_c(const char *cpPath, int oflag, int mode)
287 : {
288 133443 : accessFilePathState *state = prepare_to_access_file_path(cpPath);
289 :
290 133443 : int result = open(cpPath, oflag, mode);
291 :
292 : #if HAVE_FEATURE_MACOSX_SANDBOX
293 : if (isSandboxed && result != -1 && (oflag & O_CREAT) && (oflag & O_EXCL))
294 : {
295 : // A new file was created. Check if it is outside the sandbox.
296 : // (In that case it must be one the user selected as export or
297 : // save destination in a file dialog, otherwise we wouldn't
298 : // have been able to create it.) Create and store a security
299 : // scoped bookmark for it so that we can access the file in
300 : // the future, too. (For the "Recent Files" functionality.)
301 : const char *sandbox = [NSHomeDirectory() UTF8String];
302 : if (!(strncmp(sandbox, cpPath, strlen(sandbox)) == 0 &&
303 : cpPath[strlen(sandbox)] == '/'))
304 : {
305 : NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:cpPath]];
306 : NSData *data = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
307 : includingResourceValuesForKeys:nil
308 : relativeToURL:nil
309 : error:nil];
310 : if (data != NULL)
311 : {
312 : [userDefaults setObject:data
313 : forKey:[@"bookmarkFor:" stringByAppendingString:[url absoluteString]]];
314 : }
315 : }
316 : }
317 : #endif
318 :
319 : done_accessing_file_path(cpPath, state);
320 :
321 133443 : return result;
322 : }
323 :
324 0 : int utime_c(const char *cpPath, struct utimbuf *times)
325 : {
326 0 : accessFilePathState *state = prepare_to_access_file_path(cpPath);
327 :
328 0 : int result = utime(cpPath, times);
329 :
330 : done_accessing_file_path(cpPath, state);
331 :
332 0 : return result;
333 : }
334 :
335 1939 : int ftruncate_with_name(int fd, sal_uInt64 uSize, rtl_String* path)
336 : {
337 : /* When sandboxed on OS X, ftruncate(), even if it takes an
338 : * already open file descriptor which was retuned from an open()
339 : * call already checked by the sandbox, still requires a security
340 : * scope bookmark for the file to be active in case the file is
341 : * one that the sandbox doesn't otherwise allow access to. Luckily
342 : * LibreOffice usually calls ftruncate() through the helpful C++
343 : * abstraction layer that keeps the pathname around.
344 : */
345 :
346 1939 : rtl::OString fn = rtl::OString(path);
347 :
348 : #ifdef MACOSX
349 : fn = macxp_resolveAliasAndConvert(fn);
350 : #endif
351 :
352 1939 : accessFilePathState *state = prepare_to_access_file_path(fn.getStr());
353 :
354 1939 : int result = ftruncate(fd, uSize);
355 :
356 1939 : done_accessing_file_path(fn.getStr(), state);
357 :
358 1939 : return result;
359 : }
360 :
361 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|