lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / sal / osl / unx / security.cxx
blobcfa6ab470bca0234b928918d11f5a3c57cc0d21f
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 <cstddef>
23 #include <limits>
25 #ifdef IOS
26 #include <premac.h>
27 #import <Foundation/Foundation.h>
28 #include <postmac.h>
29 #endif
31 #include "system.hxx"
33 #include <osl/security.h>
34 #include <rtl/bootstrap.h>
35 #include <sal/log.hxx>
37 #include <osl/thread.h>
38 #include <osl/file.h>
40 #if defined LINUX || defined __sun
41 #include <crypt.h>
42 #endif
44 #if defined HAIKU
45 #include <fs_info.h>
46 #include <FindDirectory.h>
47 #endif
49 #include "secimpl.hxx"
51 #ifdef ANDROID
52 #define getpwuid_r(uid, pwd, buf, buflen, result) (*(result) = getpwuid(uid), (*(result) ? (memcpy (buf, *(result), sizeof (struct passwd)), 0) : errno))
53 #endif
55 static bool osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax);
56 static bool osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax);
57 static bool osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax);
59 static bool sysconf_SC_GETPW_R_SIZE_MAX(std::size_t * value) {
60 #if defined _SC_GETPW_R_SIZE_MAX
61 long m;
62 errno = 0;
63 m = sysconf(_SC_GETPW_R_SIZE_MAX);
64 if (m == -1) {
65 /* _SC_GETPW_R_SIZE_MAX has no limit; some platforms like certain
66 FreeBSD versions support sysconf(_SC_GETPW_R_SIZE_MAX) in a broken
67 way and always set EINVAL, so be resilient here: */
68 return false;
70 SAL_WARN_IF( m < 0 || static_cast<unsigned long>(m) >= std::numeric_limits<std::size_t>::max(), "sal.osl",
71 "m < 0 || (unsigned long) m >= std::numeric_limits<std::size_t>::max()");
72 *value = static_cast<std::size_t>(m);
73 return true;
74 #else
75 /* some platforms like Mac OS X 1.3 do not define _SC_GETPW_R_SIZE_MAX: */
76 return false;
77 #endif
80 static oslSecurityImpl * growSecurityImpl(
81 oslSecurityImpl * impl, std::size_t * bufSize)
83 std::size_t n = 0;
84 oslSecurityImpl * p = nullptr;
85 if (impl == nullptr) {
86 if (!sysconf_SC_GETPW_R_SIZE_MAX(&n)) {
87 /* choose something sensible (the callers of growSecurityImpl will
88 detect it if the allocated buffer is too small: */
89 n = 1024;
91 } else if (*bufSize <= std::numeric_limits<std::size_t>::max() / 2) {
92 n = 2 * *bufSize;
94 if (n != 0) {
95 if (n <= std::numeric_limits<std::size_t>::max()
96 - offsetof(oslSecurityImpl, m_buffer))
98 *bufSize = n;
99 n += offsetof(oslSecurityImpl, m_buffer);
100 } else {
101 *bufSize = std::numeric_limits<std::size_t>::max()
102 - offsetof(oslSecurityImpl, m_buffer);
103 n = std::numeric_limits<std::size_t>::max();
105 p = static_cast<oslSecurityImpl *>(realloc(impl, n));
106 memset (p, 0, n);
108 if (p == nullptr) {
109 free(impl);
111 return p;
114 static void deleteSecurityImpl(oslSecurityImpl * impl) {
115 free(impl);
118 oslSecurity SAL_CALL osl_getCurrentSecurity()
120 std::size_t n = 0;
121 oslSecurityImpl * p = nullptr;
122 for (;;) {
123 struct passwd * found;
124 p = growSecurityImpl(p, &n);
125 if (p == nullptr) {
126 return nullptr;
128 #if defined(IOS) && defined(X86_64)
129 // getpwuid_r() does not work in the iOS simulator
130 (void) found;
131 char * buffer = p->m_buffer;
132 assert(n >= 100);
133 strcpy(buffer, "mobile");
134 p->m_pPasswd.pw_name = buffer;
135 buffer += strlen(buffer) + 1;
136 strcpy(buffer, "*");
137 p->m_pPasswd.pw_passwd = buffer;
138 buffer += strlen(buffer) + 1;
139 p->m_pPasswd.pw_uid = geteuid();
140 p->m_pPasswd.pw_gid = getegid();
141 p->m_pPasswd.pw_change = 0;
142 strcpy(buffer, "");
143 p->m_pPasswd.pw_class = buffer;
144 buffer += strlen(buffer) + 1;
145 strcpy(buffer, "Mobile User");
146 p->m_pPasswd.pw_gecos = buffer;
147 buffer += strlen(buffer) + 1;
148 strcpy(buffer, "/var/mobile"); // ???
149 p->m_pPasswd.pw_dir = buffer;
150 buffer += strlen(buffer) + 1;
151 strcpy(buffer, "");
152 p->m_pPasswd.pw_shell = buffer;
153 buffer += strlen(buffer) + 1;
154 p->m_pPasswd.pw_expire = 0;
155 return p;
156 #else
157 switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) {
158 case ERANGE:
159 break;
160 case 0:
161 if (found != nullptr) {
162 return p;
164 SAL_FALLTHROUGH;
165 default:
166 deleteSecurityImpl(p);
167 return nullptr;
169 #endif
173 oslSecurityError SAL_CALL osl_loginUser(
174 SAL_UNUSED_PARAMETER rtl_uString *,
175 SAL_UNUSED_PARAMETER rtl_uString *,
176 SAL_UNUSED_PARAMETER oslSecurity *
179 return osl_Security_E_None;
182 oslSecurityError SAL_CALL osl_loginUserOnFileServer(
183 SAL_UNUSED_PARAMETER rtl_uString *,
184 SAL_UNUSED_PARAMETER rtl_uString *,
185 SAL_UNUSED_PARAMETER rtl_uString *,
186 SAL_UNUSED_PARAMETER oslSecurity *
189 return osl_Security_E_UserUnknown;
192 sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent)
194 bool bRet = false;
195 sal_Char pszIdent[1024];
197 pszIdent[0] = '\0';
199 bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent));
201 rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
202 SAL_WARN_IF(*ustrIdent == nullptr, "sal.osl", "*ustrIdent == NULL");
204 return bRet;
207 bool osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax)
209 sal_Char buffer[32];
210 sal_Int32 nChr;
212 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
214 if (pSecImpl == nullptr)
215 return false;
217 nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid);
218 if ( nChr < 0 || sal::static_int_cast<sal_uInt32>(nChr) >= sizeof(buffer)
219 || sal::static_int_cast<sal_uInt32>(nChr) >= nMax )
220 return false; /* leave *pszIdent unmodified in case of failure */
222 memcpy(pszIdent, buffer, nChr+1);
223 return true;
226 sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName)
228 bool bRet = false;
229 sal_Char pszName[1024];
231 pszName[0] = '\0';
233 bRet = osl_psz_getUserName(Security,pszName,sizeof(pszName));
235 rtl_string2UString( ustrName, pszName, rtl_str_getLength( pszName ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
236 SAL_WARN_IF(*ustrName == nullptr, "sal.osl", "ustrName == NULL");
238 return bRet;
241 sal_Bool SAL_CALL osl_getShortUserName(oslSecurity Security, rtl_uString **ustrName)
243 return osl_getUserName(Security, ustrName); // No domain name on unix
246 static bool osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax)
248 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
250 if (pSecImpl == nullptr || pSecImpl->m_pPasswd.pw_name == nullptr)
251 return false;
253 strncpy(pszName, pSecImpl->m_pPasswd.pw_name, nMax);
255 return true;
258 sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
260 bool bRet = false;
261 sal_Char pszDirectory[PATH_MAX];
263 pszDirectory[0] = '\0';
265 bRet = osl_psz_getHomeDir(Security,pszDirectory,sizeof(pszDirectory));
267 if ( bRet )
269 rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
270 SAL_WARN_IF(*pustrDirectory == nullptr, "sal.osl", "*pustrDirectory == NULL");
271 osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
274 return bRet;
277 static bool osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
279 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
281 if (pSecImpl == nullptr)
282 return false;
284 #ifdef HAIKU
285 dev_t volume = dev_for_path("/boot");
286 sal_Char homeDir[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
287 status_t result = find_directory(B_USER_DIRECTORY, volume, false, homeDir,
288 sizeof(homeDir));
289 if (result == B_OK && strlen(homeDir) < nMax) {
290 strcpy(pszDirectory, homeDir);
291 return true;
293 return false;
294 #endif
296 #ifdef ANDROID
298 sal_Bool bRet = sal_False;
299 rtl_uString *pName = 0, *pValue = 0;
301 rtl_uString_newFromAscii(&pName, "HOME");
303 if (rtl_bootstrap_get(pName, &pValue, NULL))
305 rtl_String *pStrValue = 0;
306 if (pValue && pValue->length > 0)
308 rtl_uString2String(&pStrValue, pValue->buffer,
309 pValue->length, RTL_TEXTENCODING_UTF8,
310 OUSTRING_TO_OSTRING_CVTFLAGS);
311 if (pStrValue && pStrValue->length > 0)
313 sal_Int32 nCopy = (sal_Int32)std::min<sal_uInt32>(nMax-1, pStrValue->length) ;
314 strncpy (pszDirectory, pStrValue->buffer, nCopy);
315 pszDirectory[nCopy] = '\0';
316 bRet = (std::size_t)pStrValue->length < nMax;
318 rtl_string_release(pStrValue);
320 rtl_uString_release(pName);
322 if (bRet)
323 return bRet;
325 #endif
327 #ifdef IOS
329 // Let's pretend the app-specific "Documents" directory is the home directory for now
330 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
331 NSString *userDirectory = [paths objectAtIndex:0];
332 if ([userDirectory length] < nMax)
334 strcpy(pszDirectory, [userDirectory UTF8String]);
335 return sal_True;
338 #endif
340 /* if current user, check also environment for HOME */
341 if (getuid() == pSecImpl->m_pPasswd.pw_uid)
343 sal_Char *pStr = nullptr;
344 #ifdef __sun
345 char buffer[8192];
347 struct passwd pwd;
348 struct passwd *ppwd;
350 #ifdef _POSIX_PTHREAD_SEMANTICS
351 if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) )
352 ppwd = NULL;
353 #else
354 ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) );
355 #endif
357 if ( ppwd )
358 pStr = ppwd->pw_dir;
359 #else
360 pStr = getenv("HOME");
361 #endif
363 if (pStr != nullptr && strlen(pStr) > 0 && access(pStr, 0) == 0)
364 strncpy(pszDirectory, pStr, nMax);
365 else if (pSecImpl->m_pPasswd.pw_dir != nullptr)
366 strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax);
367 else
368 return false;
370 else if (pSecImpl->m_pPasswd.pw_dir != nullptr)
371 strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax);
372 else
373 return false;
375 return true;
378 sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
380 bool bRet = false;
381 sal_Char pszDirectory[PATH_MAX];
383 pszDirectory[0] = '\0';
385 bRet = osl_psz_getConfigDir(Security,pszDirectory,sizeof(pszDirectory));
387 if ( bRet )
389 rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
390 SAL_WARN_IF(*pustrDirectory == nullptr, "sal.osl", "*pustrDirectory == NULL");
391 osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
394 return bRet;
397 #if defined HAIKU
399 static bool osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
401 (void) Security;
402 dev_t volume = dev_for_path("/boot");
403 sal_Char configDir[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
404 status_t result = find_directory(B_USER_SETTINGS_DIRECTORY, volume, false,
405 configDir, sizeof(configDir));
406 if (result == B_OK && strlen(configDir) < nMax) {
407 strcpy(pszDirectory, configDir);
408 return true;
410 return false;
413 #elif !defined(MACOSX) && !defined(IOS)
415 #define DOT_CONFIG "/.config"
417 static bool osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
419 sal_Char *pStr = getenv("XDG_CONFIG_HOME");
421 if (pStr == nullptr || strlen(pStr) == 0 || access(pStr, 0) != 0)
423 std::size_t n = 0;
425 // a default equal to $HOME/.config should be used.
426 if (!osl_psz_getHomeDir(Security, pszDirectory, nMax))
427 return false;
428 n = strlen(pszDirectory);
429 if (n + sizeof(DOT_CONFIG) < nMax)
431 strcpy(pszDirectory+n, DOT_CONFIG); // safe
433 // try to create dir if not present
434 bool dirOK = true;
435 if (mkdir(pszDirectory, S_IRWXU) != 0)
437 int e = errno;
438 if (e != EEXIST)
440 SAL_WARN(
441 "sal.osl",
442 "mkdir(" << pszDirectory << "): errno=" << e);
443 dirOK = false;
446 if (dirOK)
448 // check file type and permissions
449 struct stat st;
450 if (stat(pszDirectory, &st) != 0)
452 SAL_INFO("sal.osl","Could not stat $HOME/.config");
453 dirOK = false;
455 else
457 if (!S_ISDIR(st.st_mode))
459 SAL_INFO("sal.osl", "$HOME/.config is not a directory");
460 dirOK = false;
462 if (!(st.st_mode & S_IRUSR && st.st_mode & S_IWUSR && st.st_mode & S_IXUSR))
464 SAL_INFO("sal.osl", "$HOME/.config has bad permissions");
465 dirOK = false;
470 // resort to HOME
471 if (!dirOK)
472 pszDirectory[n] = '\0';
475 else
476 strncpy(pszDirectory, pStr, nMax);
478 return true;
481 #undef DOT_CONFIG
483 #else
486 * FIXME: rewrite to use more flexible
487 * NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)
488 * as soon as we can bump the baseline to Tiger (for NSApplicationSupportDirectory) and have
489 * support for Objective-C in the build environment
492 #define MACOSX_CONFIG_DIR "/Library/Application Support" /* Used on iOS, too */
493 static bool osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
495 if( osl_psz_getHomeDir(Security, pszDirectory, nMax - sizeof(MACOSX_CONFIG_DIR) + 1) )
497 strcat( pszDirectory, MACOSX_CONFIG_DIR );
498 return true;
501 return false;
504 #endif
506 sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
508 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
510 if (pSecImpl == nullptr)
511 return false;
513 if (pSecImpl->m_pPasswd.pw_uid != 0)
514 return false;
516 return true;
519 void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
521 deleteSecurityImpl(static_cast<oslSecurityImpl *>(Security));
524 sal_Bool SAL_CALL osl_loadUserProfile(SAL_UNUSED_PARAMETER oslSecurity)
526 return false;
529 void SAL_CALL osl_unloadUserProfile(SAL_UNUSED_PARAMETER oslSecurity) {}
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */