tdf#154546 skip dispatch when presenter controller is not set
[LibreOffice.git] / sal / osl / unx / security.cxx
blobb15ec9e773b006c220aac7ffc7b58b90754dddc2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <cassert>
23 #include <cstddef>
24 #include <cstring>
25 #include <limits>
27 #ifdef IOS
28 #include <premac.h>
29 #import <Foundation/Foundation.h>
30 #include <postmac.h>
31 #endif
33 #include "system.hxx"
35 #include <o3tl/safeint.hxx>
36 #include <osl/security.h>
37 #include <rtl/bootstrap.hxx>
38 #include <sal/log.hxx>
40 #include <osl/thread.h>
41 #include <osl/file.h>
43 #if defined LINUX || defined __sun
44 #include <crypt.h>
45 #endif
47 #if defined HAIKU
48 #include <fs_info.h>
49 #include <FindDirectory.h>
50 #endif
52 #include "secimpl.hxx"
54 #ifdef ANDROID
55 #define getpwuid_r(uid, pwd, buf, buflen, result) (*(result) = getpwuid(uid), (*(result) ? (memcpy (buf, *(result), sizeof (struct passwd)), 0) : errno))
56 #endif
58 static bool osl_psz_getHomeDir(oslSecurity Security, OString* pszDirectory);
59 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory);
61 static bool sysconf_SC_GETPW_R_SIZE_MAX(std::size_t * value) {
62 #if defined _SC_GETPW_R_SIZE_MAX
63 long m;
64 errno = 0;
65 m = sysconf(_SC_GETPW_R_SIZE_MAX);
66 if (m == -1) {
67 /* _SC_GETPW_R_SIZE_MAX has no limit; some platforms like certain
68 FreeBSD versions support sysconf(_SC_GETPW_R_SIZE_MAX) in a broken
69 way and always set EINVAL, so be resilient here: */
70 return false;
72 SAL_WARN_IF( m < 0 || o3tl::make_unsigned(m) >= std::numeric_limits<std::size_t>::max(), "sal.osl",
73 "m < 0 || (unsigned long) m >= std::numeric_limits<std::size_t>::max()");
74 *value = static_cast<std::size_t>(m);
75 return true;
76 #else
77 /* some platforms like macOS 1.3 do not define _SC_GETPW_R_SIZE_MAX: */
78 return false;
79 #endif
82 static oslSecurityImpl * growSecurityImpl(
83 oslSecurityImpl * impl, std::size_t * bufSize)
85 std::size_t n = 0;
86 oslSecurityImpl * p = nullptr;
87 if (impl == nullptr) {
88 if (!sysconf_SC_GETPW_R_SIZE_MAX(&n)) {
89 /* choose something sensible (the callers of growSecurityImpl will
90 detect it if the allocated buffer is too small: */
91 n = 1024;
93 } else if (*bufSize <= std::numeric_limits<std::size_t>::max() / 2) {
94 n = 2 * *bufSize;
96 if (n != 0) {
97 if (n <= std::numeric_limits<std::size_t>::max()
98 - offsetof(oslSecurityImpl, m_buffer))
100 *bufSize = n;
101 n += offsetof(oslSecurityImpl, m_buffer);
102 } else {
103 *bufSize = std::numeric_limits<std::size_t>::max()
104 - offsetof(oslSecurityImpl, m_buffer);
105 n = std::numeric_limits<std::size_t>::max();
107 p = static_cast<oslSecurityImpl *>(realloc(impl, n));
108 if (p != nullptr) {
109 // coverity[overrun-buffer-arg] - theoretically massive n is not due to
110 // a negative parameter being interpreted as unsigned
111 memset (p, 0, n);
114 if (p == nullptr) {
115 free(impl);
117 return p;
120 static void deleteSecurityImpl(oslSecurityImpl * impl) {
121 free(impl);
124 oslSecurity SAL_CALL osl_getCurrentSecurity()
126 std::size_t n = 0;
127 oslSecurityImpl * p = nullptr;
128 for (;;) {
129 struct passwd * found;
130 p = growSecurityImpl(p, &n);
131 if (p == nullptr) {
132 return nullptr;
134 #if (defined(IOS) && defined(X86_64)) || defined(EMSCRIPTEN)
135 // getpwuid_r() does not work in the iOS simulator
136 (void) found;
137 char * buffer = p->m_buffer;
138 assert(n >= 100);
139 strcpy(buffer, "mobile");
140 p->m_pPasswd.pw_name = buffer;
141 buffer += strlen(buffer) + 1;
142 strcpy(buffer, "*");
143 p->m_pPasswd.pw_passwd = buffer;
144 buffer += strlen(buffer) + 1;
145 p->m_pPasswd.pw_uid = geteuid();
146 p->m_pPasswd.pw_gid = getegid();
147 #if !defined(EMSCRIPTEN)
148 p->m_pPasswd.pw_change = 0;
149 strcpy(buffer, "");
150 p->m_pPasswd.pw_class = buffer;
151 buffer += strlen(buffer) + 1;
152 p->m_pPasswd.pw_expire = 0;
153 #endif
154 strcpy(buffer, "Mobile User");
155 p->m_pPasswd.pw_gecos = buffer;
156 buffer += strlen(buffer) + 1;
157 strcpy(buffer, "/var/mobile"); // ???
158 p->m_pPasswd.pw_dir = buffer;
159 buffer += strlen(buffer) + 1;
160 strcpy(buffer, "");
161 p->m_pPasswd.pw_shell = buffer;
162 buffer += strlen(buffer) + 1;
163 return p;
164 #else
165 switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) {
166 case ERANGE:
167 break;
168 case 0:
169 if (found != nullptr) {
170 return p;
172 [[fallthrough]];
173 default:
174 deleteSecurityImpl(p);
175 return nullptr;
177 #endif
181 oslSecurityError SAL_CALL osl_loginUser(
182 SAL_UNUSED_PARAMETER rtl_uString *,
183 SAL_UNUSED_PARAMETER rtl_uString *,
184 SAL_UNUSED_PARAMETER oslSecurity *
187 return osl_Security_E_None;
190 oslSecurityError SAL_CALL osl_loginUserOnFileServer(
191 SAL_UNUSED_PARAMETER rtl_uString *,
192 SAL_UNUSED_PARAMETER rtl_uString *,
193 SAL_UNUSED_PARAMETER rtl_uString *,
194 SAL_UNUSED_PARAMETER oslSecurity *
197 return osl_Security_E_UserUnknown;
200 sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent)
202 bool bRet = false;
203 char pszIdent[1024];
205 pszIdent[0] = '\0';
207 bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent));
209 rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
210 SAL_WARN_IF(*ustrIdent == nullptr, "sal.osl", "*ustrIdent == NULL");
212 return bRet;
215 bool osl_psz_getUserIdent(oslSecurity Security, char *pszIdent, sal_uInt32 nMax)
217 char buffer[32];
218 sal_Int32 nChr;
220 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
222 if (pSecImpl == nullptr)
223 return false;
225 nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid);
226 if ( nChr < 0 || sal::static_int_cast<sal_uInt32>(nChr) >= sizeof(buffer)
227 || sal::static_int_cast<sal_uInt32>(nChr) >= nMax )
228 return false; /* leave *pszIdent unmodified in case of failure */
230 memcpy(pszIdent, buffer, nChr+1);
231 return true;
234 sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName)
236 bool bRet = false;
237 char * pszName;
238 sal_Int32 len;
240 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
242 if (pSecImpl != nullptr && pSecImpl->m_pPasswd.pw_name != nullptr) {
243 pszName = pSecImpl->m_pPasswd.pw_name;
244 auto const n = std::strlen(pszName);
245 if (n <= o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max())) {
246 len = n;
247 bRet = true;
251 if (!bRet) {
252 pszName = nullptr;
253 len = 0;
256 rtl_string2UString( ustrName, pszName, len, osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
257 SAL_WARN_IF(*ustrName == nullptr, "sal.osl", "ustrName == NULL");
259 return bRet;
262 sal_Bool SAL_CALL osl_getShortUserName(oslSecurity Security, rtl_uString **ustrName)
264 return osl_getUserName(Security, ustrName); // No domain name on unix
267 sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
269 bool bRet = false;
270 OString pszDirectory;
272 bRet = osl_psz_getHomeDir(Security,&pszDirectory);
274 if ( bRet )
276 rtl_string2UString( pustrDirectory, pszDirectory.getStr(), pszDirectory.getLength(), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
277 SAL_WARN_IF(*pustrDirectory == nullptr, "sal.osl", "*pustrDirectory == NULL");
278 osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
281 return bRet;
284 static bool osl_psz_getHomeDir(oslSecurity Security, OString* pszDirectory)
286 assert(pszDirectory != nullptr);
288 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
290 if (pSecImpl == nullptr)
291 return false;
293 #ifdef HAIKU
294 dev_t volume = dev_for_path("/boot");
295 char homeDir[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
296 status_t result = find_directory(B_USER_DIRECTORY, volume, false, homeDir,
297 sizeof(homeDir));
298 if (result == B_OK) {
299 static_assert(
300 B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH <= std::numeric_limits<sal_Int32>::max());
301 *pszDirectory = OString(homeDir, std::strlen(homeDir));
302 return true;
304 return false;
305 #endif
307 #ifdef ANDROID
309 OUString pValue;
311 if (rtl::Bootstrap::get("HOME", pValue))
313 auto const pStrValue = OUStringToOString(pValue, RTL_TEXTENCODING_UTF8);
314 if (!pStrValue.isEmpty())
316 *pszDirectory = pStrValue;
317 return true;
321 #endif
323 #ifdef IOS
325 // Let's pretend the app-specific "Documents" directory is the home directory for now
326 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
327 NSString *userDirectory = [paths objectAtIndex:0];
328 auto const len = [userDirectory length];
329 if (len <= std::numeric_limits<sal_Int32>::max())
331 *pszDirectory = OString([userDirectory UTF8String], len);
332 return sal_True;
335 #endif
337 /* if current user, check also environment for HOME */
338 if (getuid() == pSecImpl->m_pPasswd.pw_uid)
340 char *pStr = nullptr;
341 #ifdef __sun
342 char buffer[8192];
344 struct passwd pwd;
345 struct passwd *ppwd;
347 #ifdef _POSIX_PTHREAD_SEMANTICS
348 if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) )
349 ppwd = NULL;
350 #else
351 ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) );
352 #endif
354 if ( ppwd )
355 pStr = ppwd->pw_dir;
356 #else
357 pStr = getenv("HOME");
358 #endif
360 if (pStr != nullptr && pStr[0] != '\0' && access(pStr, 0) == 0)
362 auto const len = std::strlen(pStr);
363 if (len > o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max())) {
364 return false;
366 *pszDirectory = OString(pStr, len);
367 return true;
370 if (pSecImpl->m_pPasswd.pw_dir != nullptr)
372 auto const len = std::strlen(pSecImpl->m_pPasswd.pw_dir);
373 if (len > o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max())) {
374 return false;
376 *pszDirectory = OString(pSecImpl->m_pPasswd.pw_dir, len);
378 else
379 return false;
381 return true;
384 sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
386 bool bRet = false;
387 OString pszDirectory;
389 bRet = osl_psz_getConfigDir(Security,&pszDirectory);
391 if ( bRet )
393 rtl_string2UString( pustrDirectory, pszDirectory.getStr(), pszDirectory.getLength(), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
394 SAL_WARN_IF(*pustrDirectory == nullptr, "sal.osl", "*pustrDirectory == NULL");
395 osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
398 return bRet;
401 #if defined HAIKU
403 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
405 assert(pszDirectory != nullptr);
406 (void) Security;
407 dev_t volume = dev_for_path("/boot");
408 char configDir[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
409 status_t result = find_directory(B_USER_SETTINGS_DIRECTORY, volume, false,
410 configDir, sizeof(configDir));
411 if (result == B_OK) {
412 auto const len = strlen(configDir);
413 if (len <= sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
414 *pszDirectory = OString(configDir, len);
415 return true;
418 return false;
421 #elif !defined(MACOSX) && !defined(IOS)
423 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
425 assert(pszDirectory != nullptr);
427 char *pStr = getenv("XDG_CONFIG_HOME");
429 if (pStr == nullptr || pStr[0] == '\0' || access(pStr, 0) != 0)
431 // a default equal to $HOME/.config should be used.
432 OString home;
433 if (!osl_psz_getHomeDir(Security, &home))
434 return false;
435 auto const config = OString(home + "/.config");
437 // try to create dir if not present
438 bool dirOK = true;
439 if (mkdir(config.getStr(), S_IRWXU) != 0)
441 int e = errno;
442 if (e != EEXIST)
444 SAL_WARN(
445 "sal.osl",
446 "mkdir(" << config << "): errno=" << e);
447 dirOK = false;
450 if (dirOK)
452 // check file type and permissions
453 struct stat st;
454 if (stat(config.getStr(), &st) != 0)
456 SAL_INFO("sal.osl","Could not stat $HOME/.config");
457 dirOK = false;
459 else
461 if (!S_ISDIR(st.st_mode))
463 SAL_INFO("sal.osl", "$HOME/.config is not a directory");
464 dirOK = false;
466 if (!(st.st_mode & S_IRUSR && st.st_mode & S_IWUSR && st.st_mode & S_IXUSR))
468 SAL_INFO("sal.osl", "$HOME/.config has bad permissions");
469 dirOK = false;
474 // if !dirOK, resort to HOME
475 if (dirOK)
476 home = config;
477 *pszDirectory = home;
479 else
481 auto const len = std::strlen(pStr);
482 if (len > o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max())) {
483 return false;
485 *pszDirectory = OString(pStr, len);
488 return true;
491 #else
494 * FIXME: rewrite to use more flexible
495 * NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)
496 * as soon as we can bump the baseline to Tiger (for NSApplicationSupportDirectory) and have
497 * support for Objective-C in the build environment
500 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
502 assert(pszDirectory != nullptr);
504 OString home;
505 if( osl_psz_getHomeDir(Security, &home) )
507 *pszDirectory = home + "/Library/Application Support"; /* Used on iOS, too */
508 return true;
511 return false;
514 #endif
516 sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
518 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
520 if (pSecImpl == nullptr)
521 return false;
523 if (pSecImpl->m_pPasswd.pw_uid != 0)
524 return false;
526 return true;
529 void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
531 deleteSecurityImpl(static_cast<oslSecurityImpl *>(Security));
534 sal_Bool SAL_CALL osl_loadUserProfile(SAL_UNUSED_PARAMETER oslSecurity)
536 return false;
539 void SAL_CALL osl_unloadUserProfile(SAL_UNUSED_PARAMETER oslSecurity) {}
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */