stronger typing for SwClient::GetRegisteredIn" and fix SwIterator cast
[LibreOffice.git] / sal / osl / unx / security.cxx
blob733aa0dfc6bf2c6aaffe14ffd7d99ec1b106fcd8
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>
26 #include <sys/stat.h>
27 #include <unistd.h>
29 #ifdef IOS
30 #include <premac.h>
31 #import <Foundation/Foundation.h>
32 #include <postmac.h>
33 #endif
35 #include <o3tl/safeint.hxx>
36 #include <osl/security.h>
37 #include <rtl/string.hxx>
38 #include <sal/log.hxx>
40 #include <osl/thread.h>
41 #include <osl/file.h>
43 #if defined HAIKU
44 #include <fs_info.h>
45 #include <FindDirectory.h>
46 #endif
48 #include "secimpl.hxx"
50 #ifdef ANDROID
51 #define getpwuid_r(uid, pwd, buf, buflen, result) (*(result) = getpwuid(uid), (*(result) ? (memcpy (buf, *(result), sizeof (struct passwd)), 0) : errno))
52 #include <rtl/bootstrap.hxx>
53 #endif
55 static bool osl_psz_getHomeDir(oslSecurity Security, OString* pszDirectory);
56 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory);
58 static bool sysconf_SC_GETPW_R_SIZE_MAX(std::size_t * value) {
59 #if defined _SC_GETPW_R_SIZE_MAX
60 long m;
61 errno = 0;
62 m = sysconf(_SC_GETPW_R_SIZE_MAX);
63 if (m == -1) {
64 /* _SC_GETPW_R_SIZE_MAX has no limit; some platforms like certain
65 FreeBSD versions support sysconf(_SC_GETPW_R_SIZE_MAX) in a broken
66 way and always set EINVAL, so be resilient here: */
67 return false;
69 SAL_WARN_IF( m < 0 || o3tl::make_unsigned(m) >= std::numeric_limits<std::size_t>::max(), "sal.osl",
70 "m < 0 || (unsigned long) m >= std::numeric_limits<std::size_t>::max()");
71 *value = static_cast<std::size_t>(m);
72 return true;
73 #else
74 /* some platforms like macOS 1.3 do not define _SC_GETPW_R_SIZE_MAX: */
75 return false;
76 #endif
79 static oslSecurityImpl * growSecurityImpl(
80 oslSecurityImpl * impl, std::size_t * bufSize)
82 std::size_t n = 0;
83 oslSecurityImpl * p = nullptr;
84 if (impl == nullptr) {
85 if (!sysconf_SC_GETPW_R_SIZE_MAX(&n)) {
86 /* choose something sensible (the callers of growSecurityImpl will
87 detect it if the allocated buffer is too small: */
88 n = 1024;
90 } else if (*bufSize <= std::numeric_limits<std::size_t>::max() / 2) {
91 n = 2 * *bufSize;
93 if (n != 0) {
94 if (n <= std::numeric_limits<std::size_t>::max()
95 - offsetof(oslSecurityImpl, m_buffer))
97 *bufSize = n;
98 n += offsetof(oslSecurityImpl, m_buffer);
99 } else {
100 *bufSize = std::numeric_limits<std::size_t>::max()
101 - offsetof(oslSecurityImpl, m_buffer);
102 n = std::numeric_limits<std::size_t>::max();
104 p = static_cast<oslSecurityImpl *>(realloc(impl, n));
105 if (p != nullptr) {
106 // coverity[overrun-buffer-arg] - theoretically massive n is not due to
107 // a negative parameter being interpreted as unsigned
108 memset (p, 0, n);
111 if (p == nullptr) {
112 free(impl);
114 return p;
117 static void deleteSecurityImpl(oslSecurityImpl * impl) {
118 free(impl);
121 oslSecurity SAL_CALL osl_getCurrentSecurity()
123 std::size_t n = 0;
124 oslSecurityImpl * p = nullptr;
125 for (;;) {
126 struct passwd * found;
127 p = growSecurityImpl(p, &n);
128 if (p == nullptr) {
129 return nullptr;
131 #if (defined(IOS) && defined(X86_64)) || defined(EMSCRIPTEN)
132 // getpwuid_r() does not work in the iOS simulator
133 (void) found;
134 char * buffer = p->m_buffer;
135 assert(n >= 100);
136 strcpy(buffer, "mobile");
137 p->m_pPasswd.pw_name = buffer;
138 buffer += strlen(buffer) + 1;
139 strcpy(buffer, "*");
140 p->m_pPasswd.pw_passwd = buffer;
141 buffer += strlen(buffer) + 1;
142 p->m_pPasswd.pw_uid = geteuid();
143 p->m_pPasswd.pw_gid = getegid();
144 #if !defined(EMSCRIPTEN)
145 p->m_pPasswd.pw_change = 0;
146 strcpy(buffer, "");
147 p->m_pPasswd.pw_class = buffer;
148 buffer += strlen(buffer) + 1;
149 p->m_pPasswd.pw_expire = 0;
150 #endif
151 strcpy(buffer, "Mobile User");
152 p->m_pPasswd.pw_gecos = buffer;
153 buffer += strlen(buffer) + 1;
154 strcpy(buffer, "/var/mobile"); // ???
155 p->m_pPasswd.pw_dir = buffer;
156 buffer += strlen(buffer) + 1;
157 strcpy(buffer, "");
158 p->m_pPasswd.pw_shell = buffer;
159 buffer += strlen(buffer) + 1;
160 return p;
161 #else
162 switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) {
163 case ERANGE:
164 break;
165 case 0:
166 if (found != nullptr) {
167 return p;
169 [[fallthrough]];
170 default:
171 deleteSecurityImpl(p);
172 return nullptr;
174 #endif
178 oslSecurityError SAL_CALL osl_loginUser(
179 SAL_UNUSED_PARAMETER rtl_uString *,
180 SAL_UNUSED_PARAMETER rtl_uString *,
181 SAL_UNUSED_PARAMETER oslSecurity *
184 return osl_Security_E_None;
187 oslSecurityError SAL_CALL osl_loginUserOnFileServer(
188 SAL_UNUSED_PARAMETER rtl_uString *,
189 SAL_UNUSED_PARAMETER rtl_uString *,
190 SAL_UNUSED_PARAMETER rtl_uString *,
191 SAL_UNUSED_PARAMETER oslSecurity *
194 return osl_Security_E_UserUnknown;
197 sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent)
199 bool bRet = false;
200 char pszIdent[1024];
202 pszIdent[0] = '\0';
204 bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent));
206 rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
207 SAL_WARN_IF(*ustrIdent == nullptr, "sal.osl", "*ustrIdent == NULL");
209 return bRet;
212 bool osl_psz_getUserIdent(oslSecurity Security, char *pszIdent, sal_uInt32 nMax)
214 char buffer[32];
215 sal_Int32 nChr;
217 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
219 if (pSecImpl == nullptr)
220 return false;
222 nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid);
223 if ( nChr < 0 || sal::static_int_cast<sal_uInt32>(nChr) >= sizeof(buffer)
224 || sal::static_int_cast<sal_uInt32>(nChr) >= nMax )
225 return false; /* leave *pszIdent unmodified in case of failure */
227 memcpy(pszIdent, buffer, nChr+1);
228 return true;
231 sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName)
233 bool bRet = false;
234 char * pszName;
235 sal_Int32 len;
237 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
239 if (pSecImpl != nullptr && pSecImpl->m_pPasswd.pw_name != nullptr) {
240 pszName = pSecImpl->m_pPasswd.pw_name;
241 auto const n = std::strlen(pszName);
242 if (n <= o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max())) {
243 len = n;
244 bRet = true;
248 if (!bRet) {
249 pszName = nullptr;
250 len = 0;
253 rtl_string2UString( ustrName, pszName, len, osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
254 SAL_WARN_IF(*ustrName == nullptr, "sal.osl", "ustrName == NULL");
256 return bRet;
259 sal_Bool SAL_CALL osl_getShortUserName(oslSecurity Security, rtl_uString **ustrName)
261 return osl_getUserName(Security, ustrName); // No domain name on unix
264 sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
266 bool bRet = false;
267 OString pszDirectory;
269 bRet = osl_psz_getHomeDir(Security,&pszDirectory);
271 if ( bRet )
273 rtl_string2UString( pustrDirectory, pszDirectory.getStr(), pszDirectory.getLength(), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
274 SAL_WARN_IF(*pustrDirectory == nullptr, "sal.osl", "*pustrDirectory == NULL");
275 osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
278 return bRet;
281 static bool osl_psz_getHomeDir(oslSecurity Security, OString* pszDirectory)
283 assert(pszDirectory != nullptr);
285 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
287 if (pSecImpl == nullptr)
288 return false;
290 #ifdef HAIKU
291 dev_t volume = dev_for_path("/boot");
292 char homeDir[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
293 status_t result = find_directory(B_USER_DIRECTORY, volume, false, homeDir,
294 sizeof(homeDir));
295 if (result == B_OK) {
296 static_assert(
297 B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH <= std::numeric_limits<sal_Int32>::max());
298 *pszDirectory = OString(homeDir, std::strlen(homeDir));
299 return true;
301 return false;
302 #endif
304 #ifdef ANDROID
306 OUString pValue;
308 if (rtl::Bootstrap::get("HOME", pValue))
310 auto const pStrValue = OUStringToOString(pValue, RTL_TEXTENCODING_UTF8);
311 if (!pStrValue.isEmpty())
313 *pszDirectory = pStrValue;
314 return true;
318 #endif
320 #ifdef IOS
322 // Let's pretend the app-specific "Documents" directory is the home directory for now
323 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
324 NSString *userDirectory = [paths objectAtIndex:0];
325 auto const len = [userDirectory length];
326 if (len <= std::numeric_limits<sal_Int32>::max())
328 *pszDirectory = OString([userDirectory UTF8String], len);
329 return sal_True;
332 #endif
334 /* if current user, check also environment for HOME */
335 if (getuid() == pSecImpl->m_pPasswd.pw_uid)
337 char *pStr = nullptr;
338 #ifdef __sun
339 char buffer[8192];
341 struct passwd pwd;
342 struct passwd *ppwd;
344 #ifdef _POSIX_PTHREAD_SEMANTICS
345 if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) )
346 ppwd = NULL;
347 #else
348 ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) );
349 #endif
351 if ( ppwd )
352 pStr = ppwd->pw_dir;
353 #else
354 pStr = getenv("HOME");
355 #endif
357 if (pStr != nullptr && pStr[0] != '\0' && access(pStr, 0) == 0)
359 auto const len = std::strlen(pStr);
360 if (len > o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max())) {
361 return false;
363 *pszDirectory = OString(pStr, len);
364 return true;
367 if (pSecImpl->m_pPasswd.pw_dir != nullptr)
369 auto const len = std::strlen(pSecImpl->m_pPasswd.pw_dir);
370 if (len > o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max())) {
371 return false;
373 *pszDirectory = OString(pSecImpl->m_pPasswd.pw_dir, len);
375 else
376 return false;
378 return true;
381 sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
383 bool bRet = false;
384 OString pszDirectory;
386 bRet = osl_psz_getConfigDir(Security,&pszDirectory);
388 if ( bRet )
390 rtl_string2UString( pustrDirectory, pszDirectory.getStr(), pszDirectory.getLength(), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
391 SAL_WARN_IF(*pustrDirectory == nullptr, "sal.osl", "*pustrDirectory == NULL");
392 osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
395 return bRet;
398 #if defined HAIKU
400 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
402 assert(pszDirectory != nullptr);
403 (void) Security;
404 dev_t volume = dev_for_path("/boot");
405 char configDir[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
406 status_t result = find_directory(B_USER_SETTINGS_DIRECTORY, volume, false,
407 configDir, sizeof(configDir));
408 if (result == B_OK) {
409 auto const len = strlen(configDir);
410 if (len <= sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
411 *pszDirectory = OString(configDir, len);
412 return true;
415 return false;
418 #elif !defined(MACOSX) && !defined(IOS)
420 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
422 assert(pszDirectory != nullptr);
424 char *pStr = getenv("XDG_CONFIG_HOME");
426 if (pStr == nullptr || pStr[0] == '\0' || access(pStr, 0) != 0)
428 // a default equal to $HOME/.config should be used.
429 OString home;
430 if (!osl_psz_getHomeDir(Security, &home))
431 return false;
432 auto const config = OString(home + "/.config");
434 // try to create dir if not present
435 bool dirOK = true;
436 if (mkdir(config.getStr(), S_IRWXU) != 0)
438 int e = errno;
439 if (e != EEXIST)
441 SAL_WARN(
442 "sal.osl",
443 "mkdir(" << config << "): errno=" << e);
444 dirOK = false;
447 if (dirOK)
449 // check file type and permissions
450 struct stat st;
451 if (stat(config.getStr(), &st) != 0)
453 SAL_INFO("sal.osl","Could not stat $HOME/.config");
454 dirOK = false;
456 else
458 if (!S_ISDIR(st.st_mode))
460 SAL_INFO("sal.osl", "$HOME/.config is not a directory");
461 dirOK = false;
463 if (!(st.st_mode & S_IRUSR && st.st_mode & S_IWUSR && st.st_mode & S_IXUSR))
465 SAL_INFO("sal.osl", "$HOME/.config has bad permissions");
466 dirOK = false;
471 // if !dirOK, resort to HOME
472 if (dirOK)
473 home = config;
474 *pszDirectory = home;
476 else
478 auto const len = std::strlen(pStr);
479 if (len > o3tl::make_unsigned(std::numeric_limits<sal_Int32>::max())) {
480 return false;
482 *pszDirectory = OString(pStr, len);
485 return true;
488 #else
491 * FIXME: rewrite to use more flexible
492 * NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)
493 * as soon as we can bump the baseline to Tiger (for NSApplicationSupportDirectory) and have
494 * support for Objective-C in the build environment
497 static bool osl_psz_getConfigDir(oslSecurity Security, OString* pszDirectory)
499 assert(pszDirectory != nullptr);
501 OString home;
502 if( osl_psz_getHomeDir(Security, &home) )
504 *pszDirectory = home + "/Library/Application Support"; /* Used on iOS, too */
505 return true;
508 return false;
511 #endif
513 sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
515 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
517 if (pSecImpl == nullptr)
518 return false;
520 if (pSecImpl->m_pPasswd.pw_uid != 0)
521 return false;
523 return true;
526 void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
528 deleteSecurityImpl(static_cast<oslSecurityImpl *>(Security));
531 sal_Bool SAL_CALL osl_loadUserProfile(SAL_UNUSED_PARAMETER oslSecurity)
533 return false;
536 void SAL_CALL osl_unloadUserProfile(SAL_UNUSED_PARAMETER oslSecurity) {}
538 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */