1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
29 #import <Foundation/Foundation.h>
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>
43 #if defined LINUX || defined __sun
49 #include <FindDirectory.h>
52 #include "secimpl.hxx"
55 #define getpwuid_r(uid, pwd, buf, buflen, result) (*(result) = getpwuid(uid), (*(result) ? (memcpy (buf, *(result), sizeof (struct passwd)), 0) : errno))
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
65 m
= sysconf(_SC_GETPW_R_SIZE_MAX
);
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: */
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
);
77 /* some platforms like macOS 1.3 do not define _SC_GETPW_R_SIZE_MAX: */
82 static oslSecurityImpl
* growSecurityImpl(
83 oslSecurityImpl
* impl
, std::size_t * bufSize
)
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: */
93 } else if (*bufSize
<= std::numeric_limits
<std::size_t>::max() / 2) {
97 if (n
<= std::numeric_limits
<std::size_t>::max()
98 - offsetof(oslSecurityImpl
, m_buffer
))
101 n
+= offsetof(oslSecurityImpl
, m_buffer
);
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
));
109 // coverity[overrun-buffer-arg] - theoretically massive n is not due to
110 // a negative parameter being interpreted as unsigned
120 static void deleteSecurityImpl(oslSecurityImpl
* impl
) {
124 oslSecurity SAL_CALL
osl_getCurrentSecurity()
127 oslSecurityImpl
* p
= nullptr;
129 struct passwd
* found
;
130 p
= growSecurityImpl(p
, &n
);
134 #if (defined(IOS) && defined(X86_64)) || defined(EMSCRIPTEN)
135 // getpwuid_r() does not work in the iOS simulator
137 char * buffer
= p
->m_buffer
;
139 strcpy(buffer
, "mobile");
140 p
->m_pPasswd
.pw_name
= buffer
;
141 buffer
+= strlen(buffer
) + 1;
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;
150 p
->m_pPasswd
.pw_class
= buffer
;
151 buffer
+= strlen(buffer
) + 1;
152 p
->m_pPasswd
.pw_expire
= 0;
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;
161 p
->m_pPasswd
.pw_shell
= buffer
;
162 buffer
+= strlen(buffer
) + 1;
165 switch (getpwuid_r(getuid(), &p
->m_pPasswd
, p
->m_buffer
, n
, &found
)) {
169 if (found
!= nullptr) {
174 deleteSecurityImpl(p
);
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
)
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");
215 bool osl_psz_getUserIdent(oslSecurity Security
, char *pszIdent
, sal_uInt32 nMax
)
220 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
222 if (pSecImpl
== nullptr)
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);
234 sal_Bool SAL_CALL
osl_getUserName(oslSecurity Security
, rtl_uString
**ustrName
)
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())) {
256 rtl_string2UString( ustrName
, pszName
, len
, osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS
);
257 SAL_WARN_IF(*ustrName
== nullptr, "sal.osl", "ustrName == NULL");
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
)
270 OString pszDirectory
;
272 bRet
= osl_psz_getHomeDir(Security
,&pszDirectory
);
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
);
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)
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
,
298 if (result
== B_OK
) {
300 B_PATH_NAME_LENGTH
+ B_FILE_NAME_LENGTH
<= std::numeric_limits
<sal_Int32
>::max());
301 *pszDirectory
= OString(homeDir
, std::strlen(homeDir
));
311 if (rtl::Bootstrap::get("HOME", pValue
))
313 auto const pStrValue
= OUStringToOString(pValue
, RTL_TEXTENCODING_UTF8
);
314 if (!pStrValue
.isEmpty())
316 *pszDirectory
= pStrValue
;
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
);
337 /* if current user, check also environment for HOME */
338 if (getuid() == pSecImpl
->m_pPasswd
.pw_uid
)
340 char *pStr
= nullptr;
347 #ifdef _POSIX_PTHREAD_SEMANTICS
348 if ( 0 != getpwuid_r(getuid(), &pwd
, buffer
, sizeof(buffer
), &ppwd
) )
351 ppwd
= getpwuid_r(getuid(), &pwd
, buffer
, sizeof(buffer
) );
357 pStr
= getenv("HOME");
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())) {
366 *pszDirectory
= OString(pStr
, len
);
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())) {
376 *pszDirectory
= OString(pSecImpl
->m_pPasswd
.pw_dir
, len
);
384 sal_Bool SAL_CALL
osl_getConfigDir(oslSecurity Security
, rtl_uString
**pustrDirectory
)
387 OString pszDirectory
;
389 bRet
= osl_psz_getConfigDir(Security
,&pszDirectory
);
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
);
403 static bool osl_psz_getConfigDir(oslSecurity Security
, OString
* pszDirectory
)
405 assert(pszDirectory
!= nullptr);
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
);
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.
433 if (!osl_psz_getHomeDir(Security
, &home
))
435 auto const config
= OString(home
+ "/.config");
437 // try to create dir if not present
439 if (mkdir(config
.getStr(), S_IRWXU
) != 0)
446 "mkdir(" << config
<< "): errno=" << e
);
452 // check file type and permissions
454 if (stat(config
.getStr(), &st
) != 0)
456 SAL_INFO("sal.osl","Could not stat $HOME/.config");
461 if (!S_ISDIR(st
.st_mode
))
463 SAL_INFO("sal.osl", "$HOME/.config is not a directory");
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");
474 // if !dirOK, resort to HOME
477 *pszDirectory
= home
;
481 auto const len
= std::strlen(pStr
);
482 if (len
> o3tl::make_unsigned(std::numeric_limits
<sal_Int32
>::max())) {
485 *pszDirectory
= OString(pStr
, len
);
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);
505 if( osl_psz_getHomeDir(Security
, &home
) )
507 *pszDirectory
= home
+ "/Library/Application Support"; /* Used on iOS, too */
516 sal_Bool SAL_CALL
osl_isAdministrator(oslSecurity Security
)
518 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
520 if (pSecImpl
== nullptr)
523 if (pSecImpl
->m_pPasswd
.pw_uid
!= 0)
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
)
539 void SAL_CALL
osl_unloadUserProfile(SAL_UNUSED_PARAMETER oslSecurity
) {}
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */