1 /* -*- Mode: C++; 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 <sal/config.h>
21
22 #include <cassert>
23 #include <cstddef>
24 #include <cstring>
25 #include <limits>
26
27 #ifdef IOS
28 #include <premac.h>
29 #import <Foundation/Foundation.h>
30 #include <postmac.h>
31 #endif
32
33 #include "system.hxx"
34
35 #include <osl/security.h>
36 #include <rtl/bootstrap.hxx>
37 #include <sal/log.hxx>
38
39 #include <osl/thread.h>
40 #include <osl/file.h>
41
42 #if defined LINUX || defined __sun
43 #include <crypt.h>
44 #endif
45
46 #if defined HAIKU
47 #include <fs_info.h>
48 #include <FindDirectory.h>
49 #endif
50
51 #include "secimpl.hxx"
52
53 #ifdef ANDROID
54 #define getpwuid_r(uid, pwd, buf, buflen, result) (*(result) = getpwuid(uid), (*(result) ? (memcpy (buf, *(result), sizeof (struct passwd)), 0) : errno))
55 #endif
56
57 static bool osl_psz_getHomeDir(oslSecurity Security, OString* pszDirectory);
58 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory);
59
sysconf_SC_GETPW_R_SIZE_MAX(std::size_t * value)60 static bool sysconf_SC_GETPW_R_SIZE_MAX(std::size_t * value) {
61 #if defined _SC_GETPW_R_SIZE_MAX
62 long m;
63 errno = 0;
64 m = sysconf(_SC_GETPW_R_SIZE_MAX);
65 if (m == -1) {
66 /* _SC_GETPW_R_SIZE_MAX has no limit; some platforms like certain
67 FreeBSD versions support sysconf(_SC_GETPW_R_SIZE_MAX) in a broken
68 way and always set EINVAL, so be resilient here: */
69 return false;
70 }
71 SAL_WARN_IF( m < 0 || static_cast<unsigned long>(m) >= std::numeric_limits<std::size_t>::max(), "sal.osl",
72 "m < 0 || (unsigned long) m >= std::numeric_limits<std::size_t>::max()");
73 *value = static_cast<std::size_t>(m);
74 return true;
75 #else
76 /* some platforms like macOS 1.3 do not define _SC_GETPW_R_SIZE_MAX: */
77 return false;
78 #endif
79 }
80
growSecurityImpl(oslSecurityImpl * impl,std::size_t * bufSize)81 static oslSecurityImpl * growSecurityImpl(
82 oslSecurityImpl * impl, std::size_t * bufSize)
83 {
84 std::size_t n = 0;
85 oslSecurityImpl * p = nullptr;
86 if (impl == nullptr) {
87 if (!sysconf_SC_GETPW_R_SIZE_MAX(&n)) {
88 /* choose something sensible (the callers of growSecurityImpl will
89 detect it if the allocated buffer is too small: */
90 n = 1024;
91 }
92 } else if (*bufSize <= std::numeric_limits<std::size_t>::max() / 2) {
93 n = 2 * *bufSize;
94 }
95 if (n != 0) {
96 if (n <= std::numeric_limits<std::size_t>::max()
97 - offsetof(oslSecurityImpl, m_buffer))
98 {
99 *bufSize = n;
100 n += offsetof(oslSecurityImpl, m_buffer);
101 } else {
102 *bufSize = std::numeric_limits<std::size_t>::max()
103 - offsetof(oslSecurityImpl, m_buffer);
104 n = std::numeric_limits<std::size_t>::max();
105 }
106 p = static_cast<oslSecurityImpl *>(realloc(impl, n));
107 memset (p, 0, n);
108 }
109 if (p == nullptr) {
110 free(impl);
111 }
112 return p;
113 }
114
deleteSecurityImpl(oslSecurityImpl * impl)115 static void deleteSecurityImpl(oslSecurityImpl * impl) {
116 free(impl);
117 }
118
osl_getCurrentSecurity()119 oslSecurity SAL_CALL osl_getCurrentSecurity()
120 {
121 std::size_t n = 0;
122 oslSecurityImpl * p = nullptr;
123 for (;;) {
124 struct passwd * found;
125 p = growSecurityImpl(p, &n);
126 if (p == nullptr) {
127 return nullptr;
128 }
129 #if defined(IOS) && defined(X86_64)
130 // getpwuid_r() does not work in the iOS simulator
131 (void) found;
132 char * buffer = p->m_buffer;
133 assert(n >= 100);
134 strcpy(buffer, "mobile");
135 p->m_pPasswd.pw_name = buffer;
136 buffer += strlen(buffer) + 1;
137 strcpy(buffer, "*");
138 p->m_pPasswd.pw_passwd = buffer;
139 buffer += strlen(buffer) + 1;
140 p->m_pPasswd.pw_uid = geteuid();
141 p->m_pPasswd.pw_gid = getegid();
142 p->m_pPasswd.pw_change = 0;
143 strcpy(buffer, "");
144 p->m_pPasswd.pw_class = buffer;
145 buffer += strlen(buffer) + 1;
146 strcpy(buffer, "Mobile User");
147 p->m_pPasswd.pw_gecos = buffer;
148 buffer += strlen(buffer) + 1;
149 strcpy(buffer, "/var/mobile"); // ???
150 p->m_pPasswd.pw_dir = buffer;
151 buffer += strlen(buffer) + 1;
152 strcpy(buffer, "");
153 p->m_pPasswd.pw_shell = buffer;
154 buffer += strlen(buffer) + 1;
155 p->m_pPasswd.pw_expire = 0;
156 return p;
157 #else
158 switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) {
159 case ERANGE:
160 break;
161 case 0:
162 if (found != nullptr) {
163 return p;
164 }
165 [[fallthrough]];
166 default:
167 deleteSecurityImpl(p);
168 return nullptr;
169 }
170 #endif
171 }
172 }
173
osl_loginUser(SAL_UNUSED_PARAMETER rtl_uString *,SAL_UNUSED_PARAMETER rtl_uString *,SAL_UNUSED_PARAMETER oslSecurity *)174 oslSecurityError SAL_CALL osl_loginUser(
175 SAL_UNUSED_PARAMETER rtl_uString *,
176 SAL_UNUSED_PARAMETER rtl_uString *,
177 SAL_UNUSED_PARAMETER oslSecurity *
178 )
179 {
180 return osl_Security_E_None;
181 }
182
osl_loginUserOnFileServer(SAL_UNUSED_PARAMETER rtl_uString *,SAL_UNUSED_PARAMETER rtl_uString *,SAL_UNUSED_PARAMETER rtl_uString *,SAL_UNUSED_PARAMETER oslSecurity *)183 oslSecurityError SAL_CALL osl_loginUserOnFileServer(
184 SAL_UNUSED_PARAMETER rtl_uString *,
185 SAL_UNUSED_PARAMETER rtl_uString *,
186 SAL_UNUSED_PARAMETER rtl_uString *,
187 SAL_UNUSED_PARAMETER oslSecurity *
188 )
189 {
190 return osl_Security_E_UserUnknown;
191 }
192
osl_getUserIdent(oslSecurity Security,rtl_uString ** ustrIdent)193 sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent)
194 {
195 bool bRet = false;
196 sal_Char pszIdent[1024];
197
198 pszIdent[0] = '\0';
199
200 bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent));
201
202 rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
203 SAL_WARN_IF(*ustrIdent == nullptr, "sal.osl", "*ustrIdent == NULL");
204
205 return bRet;
206 }
207
osl_psz_getUserIdent(oslSecurity Security,sal_Char * pszIdent,sal_uInt32 nMax)208 bool osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax)
209 {
210 sal_Char buffer[32];
211 sal_Int32 nChr;
212
213 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
214
215 if (pSecImpl == nullptr)
216 return false;
217
218 nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid);
219 if ( nChr < 0 || sal::static_int_cast<sal_uInt32>(nChr) >= sizeof(buffer)
220 || sal::static_int_cast<sal_uInt32>(nChr) >= nMax )
221 return false; /* leave *pszIdent unmodified in case of failure */
222
223 memcpy(pszIdent, buffer, nChr+1);
224 return true;
225 }
226
osl_getUserName(oslSecurity Security,rtl_uString ** ustrName)227 sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName)
228 {
229 bool bRet = false;
230 sal_Char * pszName;
231 sal_Int32 len;
232
233 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
234
235 if (pSecImpl != nullptr && pSecImpl->m_pPasswd.pw_name != nullptr) {
236 pszName = pSecImpl->m_pPasswd.pw_name;
237 auto const n = std::strlen(pszName);
238 if (n <= sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
239 len = n;
240 bRet = true;
241 }
242 }
243
244 if (!bRet) {
245 pszName = nullptr;
246 len = 0;
247 }
248
249 rtl_string2UString( ustrName, pszName, len, osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
250 SAL_WARN_IF(*ustrName == nullptr, "sal.osl", "ustrName == NULL");
251
252 return bRet;
253 }
254
osl_getShortUserName(oslSecurity Security,rtl_uString ** ustrName)255 sal_Bool SAL_CALL osl_getShortUserName(oslSecurity Security, rtl_uString **ustrName)
256 {
257 return osl_getUserName(Security, ustrName); // No domain name on unix
258 }
259
osl_getHomeDir(oslSecurity Security,rtl_uString ** pustrDirectory)260 sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
261 {
262 bool bRet = false;
263 OString pszDirectory;
264
265 bRet = osl_psz_getHomeDir(Security,&pszDirectory);
266
267 if ( bRet )
268 {
269 rtl_string2UString( pustrDirectory, pszDirectory.getStr(), pszDirectory.getLength(), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
270 SAL_WARN_IF(*pustrDirectory == nullptr, "sal.osl", "*pustrDirectory == NULL");
271 osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
272 }
273
274 return bRet;
275 }
276
osl_psz_getHomeDir(oslSecurity Security,OString * pszDirectory)277 static bool osl_psz_getHomeDir(oslSecurity Security, OString* pszDirectory)
278 {
279 assert(pszDirectory != nullptr);
280
281 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
282
283 if (pSecImpl == nullptr)
284 return false;
285
286 #ifdef HAIKU
287 dev_t volume = dev_for_path("/boot");
288 sal_Char homeDir[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
289 status_t result = find_directory(B_USER_DIRECTORY, volume, false, homeDir,
290 sizeof(homeDir));
291 if (result == B_OK) {
292 static_assert(
293 B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH <= std::numeric_limits<sal_Int32>::max());
294 *pszDirectory = OString(homeDir, std::strlen(homeDir));
295 return true;
296 }
297 return false;
298 #endif
299
300 #ifdef ANDROID
301 {
302 OUString pValue;
303
304 if (rtl::Bootstrap::get("HOME", pValue))
305 {
306 auto const pStrValue = OUStringToOString(pValue, RTL_TEXTENCODING_UTF8);
307 if (!pStrValue.isEmpty())
308 {
309 *pszDirectory = pStrValue;
310 return true;
311 }
312 }
313 }
314 #endif
315
316 #ifdef IOS
317 {
318 // Let's pretend the app-specific "Documents" directory is the home directory for now
319 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
320 NSString *userDirectory = [paths objectAtIndex:0];
321 auto const len = [userDirectory length];
322 if (len <= std::numeric_limits<sal_Int32>::max())
323 {
324 *pszDirectory = OString([userDirectory UTF8String], len);
325 return sal_True;
326 }
327 }
328 #endif
329
330 /* if current user, check also environment for HOME */
331 if (getuid() == pSecImpl->m_pPasswd.pw_uid)
332 {
333 sal_Char *pStr = nullptr;
334 #ifdef __sun
335 char buffer[8192];
336
337 struct passwd pwd;
338 struct passwd *ppwd;
339
340 #ifdef _POSIX_PTHREAD_SEMANTICS
341 if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) )
342 ppwd = NULL;
343 #else
344 ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) );
345 #endif
346
347 if ( ppwd )
348 pStr = ppwd->pw_dir;
349 #else
350 pStr = getenv("HOME");
351 #endif
352
353 if (pStr != nullptr && pStr[0] != '\0' && access(pStr, 0) == 0)
354 {
355 auto const len = std::strlen(pStr);
356 if (len > sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
357 return false;
358 }
359 *pszDirectory = OString(pStr, len);
360 return true;
361 }
362 }
363 if (pSecImpl->m_pPasswd.pw_dir != nullptr)
364 {
365 auto const len = std::strlen(pSecImpl->m_pPasswd.pw_dir);
366 if (len > sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
367 return false;
368 }
369 *pszDirectory = OString(pSecImpl->m_pPasswd.pw_dir, len);
370 }
371 else
372 return false;
373
374 return true;
375 }
376
osl_getConfigDir(oslSecurity Security,rtl_uString ** pustrDirectory)377 sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
378 {
379 bool bRet = false;
380 OString pszDirectory;
381
382 bRet = osl_psz_getConfigDir(Security,&pszDirectory);
383
384 if ( bRet )
385 {
386 rtl_string2UString( pustrDirectory, pszDirectory.getStr(), pszDirectory.getLength(), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
387 SAL_WARN_IF(*pustrDirectory == nullptr, "sal.osl", "*pustrDirectory == NULL");
388 osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
389 }
390
391 return bRet;
392 }
393
394 #if defined HAIKU
395
osl_psz_getConfigDir(oslSecurity Security,OString * pszDirectory)396 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
397 {
398 assert(pszDirectory != nullptr);
399 (void) Security;
400 dev_t volume = dev_for_path("/boot");
401 sal_Char configDir[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
402 status_t result = find_directory(B_USER_SETTINGS_DIRECTORY, volume, false,
403 configDir, sizeof(configDir));
404 if (result == B_OK) {
405 auto const len = strlen(configDir);
406 if (len <= sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
407 *pszDirectory = OString(configDir, len);
408 return true;
409 }
410 }
411 return false;
412 }
413
414 #elif !defined(MACOSX) && !defined(IOS)
415
osl_psz_getConfigDir(oslSecurity Security,OString * pszDirectory)416 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
417 {
418 assert(pszDirectory != nullptr);
419
420 sal_Char *pStr = getenv("XDG_CONFIG_HOME");
421
422 if (pStr == nullptr || pStr[0] == '\0' || access(pStr, 0) != 0)
423 {
424 // a default equal to $HOME/.config should be used.
425 OString home;
426 if (!osl_psz_getHomeDir(Security, &home))
427 return false;
428 auto const config = OString(home + "/.config");
429
430 // try to create dir if not present
431 bool dirOK = true;
432 if (mkdir(config.getStr(), S_IRWXU) != 0)
433 {
434 int e = errno;
435 if (e != EEXIST)
436 {
437 SAL_WARN(
438 "sal.osl",
439 "mkdir(" << config << "): errno=" << e);
440 dirOK = false;
441 }
442 }
443 if (dirOK)
444 {
445 // check file type and permissions
446 struct stat st;
447 if (stat(config.getStr(), &st) != 0)
448 {
449 SAL_INFO("sal.osl","Could not stat $HOME/.config");
450 dirOK = false;
451 }
452 else
453 {
454 if (!S_ISDIR(st.st_mode))
455 {
456 SAL_INFO("sal.osl", "$HOME/.config is not a directory");
457 dirOK = false;
458 }
459 if (!(st.st_mode & S_IRUSR && st.st_mode & S_IWUSR && st.st_mode & S_IXUSR))
460 {
461 SAL_INFO("sal.osl", "$HOME/.config has bad permissions");
462 dirOK = false;
463 }
464 }
465 }
466
467 // if !dirOK, resort to HOME
468 if (dirOK)
469 home = config;
470 *pszDirectory = home;
471 }
472 else
473 {
474 auto const len = std::strlen(pStr);
475 if (len > sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
476 return false;
477 }
478 *pszDirectory = OString(pStr, len);
479 }
480
481 return true;
482 }
483
484 #else
485
486 /*
487 * FIXME: rewrite to use more flexible
488 * NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)
489 * as soon as we can bump the baseline to Tiger (for NSApplicationSupportDirectory) and have
490 * support for Objective-C in the build environment
491 */
492
osl_psz_getConfigDir(oslSecurity Security,OString * pszDirectory)493 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
494 {
495 assert(pszDirectory != nullptr);
496
497 OString home;
498 if( osl_psz_getHomeDir(Security, &home) )
499 {
500 *pszDirectory = home + "/Library/Application Support"; /* Used on iOS, too */
501 return true;
502 }
503
504 return false;
505 }
506
507 #endif
508
osl_isAdministrator(oslSecurity Security)509 sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
510 {
511 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
512
513 if (pSecImpl == nullptr)
514 return false;
515
516 if (pSecImpl->m_pPasswd.pw_uid != 0)
517 return false;
518
519 return true;
520 }
521
osl_freeSecurityHandle(oslSecurity Security)522 void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
523 {
524 deleteSecurityImpl(static_cast<oslSecurityImpl *>(Security));
525 }
526
osl_loadUserProfile(SAL_UNUSED_PARAMETER oslSecurity)527 sal_Bool SAL_CALL osl_loadUserProfile(SAL_UNUSED_PARAMETER oslSecurity)
528 {
529 return false;
530 }
531
osl_unloadUserProfile(SAL_UNUSED_PARAMETER oslSecurity)532 void SAL_CALL osl_unloadUserProfile(SAL_UNUSED_PARAMETER oslSecurity) {}
533
534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
535