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>
31 #import <Foundation/Foundation.h>
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>
45 #include <FindDirectory.h>
48 #include "secimpl.hxx"
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>
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
62 m
= sysconf(_SC_GETPW_R_SIZE_MAX
);
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: */
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
);
74 /* some platforms like macOS 1.3 do not define _SC_GETPW_R_SIZE_MAX: */
79 static oslSecurityImpl
* growSecurityImpl(
80 oslSecurityImpl
* impl
, std::size_t * bufSize
)
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: */
90 } else if (*bufSize
<= std::numeric_limits
<std::size_t>::max() / 2) {
94 if (n
<= std::numeric_limits
<std::size_t>::max()
95 - offsetof(oslSecurityImpl
, m_buffer
))
98 n
+= offsetof(oslSecurityImpl
, m_buffer
);
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
));
106 // coverity[overrun-buffer-arg] - theoretically massive n is not due to
107 // a negative parameter being interpreted as unsigned
117 static void deleteSecurityImpl(oslSecurityImpl
* impl
) {
121 oslSecurity SAL_CALL
osl_getCurrentSecurity()
124 oslSecurityImpl
* p
= nullptr;
126 struct passwd
* found
;
127 p
= growSecurityImpl(p
, &n
);
131 #if (defined(IOS) && defined(X86_64)) || defined(EMSCRIPTEN)
132 // getpwuid_r() does not work in the iOS simulator
134 char * buffer
= p
->m_buffer
;
136 strcpy(buffer
, "mobile");
137 p
->m_pPasswd
.pw_name
= buffer
;
138 buffer
+= strlen(buffer
) + 1;
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;
147 p
->m_pPasswd
.pw_class
= buffer
;
148 buffer
+= strlen(buffer
) + 1;
149 p
->m_pPasswd
.pw_expire
= 0;
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;
158 p
->m_pPasswd
.pw_shell
= buffer
;
159 buffer
+= strlen(buffer
) + 1;
162 switch (getpwuid_r(getuid(), &p
->m_pPasswd
, p
->m_buffer
, n
, &found
)) {
166 if (found
!= nullptr) {
171 deleteSecurityImpl(p
);
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
)
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");
212 bool osl_psz_getUserIdent(oslSecurity Security
, char *pszIdent
, sal_uInt32 nMax
)
217 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
219 if (pSecImpl
== nullptr)
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);
231 sal_Bool SAL_CALL
osl_getUserName(oslSecurity Security
, rtl_uString
**ustrName
)
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())) {
253 rtl_string2UString( ustrName
, pszName
, len
, osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS
);
254 SAL_WARN_IF(*ustrName
== nullptr, "sal.osl", "ustrName == NULL");
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
)
267 OString pszDirectory
;
269 bRet
= osl_psz_getHomeDir(Security
,&pszDirectory
);
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
);
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)
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
,
295 if (result
== B_OK
) {
297 B_PATH_NAME_LENGTH
+ B_FILE_NAME_LENGTH
<= std::numeric_limits
<sal_Int32
>::max());
298 *pszDirectory
= OString(homeDir
, std::strlen(homeDir
));
308 if (rtl::Bootstrap::get("HOME", pValue
))
310 auto const pStrValue
= OUStringToOString(pValue
, RTL_TEXTENCODING_UTF8
);
311 if (!pStrValue
.isEmpty())
313 *pszDirectory
= pStrValue
;
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
);
334 /* if current user, check also environment for HOME */
335 if (getuid() == pSecImpl
->m_pPasswd
.pw_uid
)
337 char *pStr
= nullptr;
344 #ifdef _POSIX_PTHREAD_SEMANTICS
345 if ( 0 != getpwuid_r(getuid(), &pwd
, buffer
, sizeof(buffer
), &ppwd
) )
348 ppwd
= getpwuid_r(getuid(), &pwd
, buffer
, sizeof(buffer
) );
354 pStr
= getenv("HOME");
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())) {
363 *pszDirectory
= OString(pStr
, len
);
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())) {
373 *pszDirectory
= OString(pSecImpl
->m_pPasswd
.pw_dir
, len
);
381 sal_Bool SAL_CALL
osl_getConfigDir(oslSecurity Security
, rtl_uString
**pustrDirectory
)
384 OString pszDirectory
;
386 bRet
= osl_psz_getConfigDir(Security
,&pszDirectory
);
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
);
400 static bool osl_psz_getConfigDir(oslSecurity Security
, OString
* pszDirectory
)
402 assert(pszDirectory
!= nullptr);
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
);
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.
430 if (!osl_psz_getHomeDir(Security
, &home
))
432 auto const config
= OString(home
+ "/.config");
434 // try to create dir if not present
436 if (mkdir(config
.getStr(), S_IRWXU
) != 0)
443 "mkdir(" << config
<< "): errno=" << e
);
449 // check file type and permissions
451 if (stat(config
.getStr(), &st
) != 0)
453 SAL_INFO("sal.osl","Could not stat $HOME/.config");
458 if (!S_ISDIR(st
.st_mode
))
460 SAL_INFO("sal.osl", "$HOME/.config is not a directory");
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");
471 // if !dirOK, resort to HOME
474 *pszDirectory
= home
;
478 auto const len
= std::strlen(pStr
);
479 if (len
> o3tl::make_unsigned(std::numeric_limits
<sal_Int32
>::max())) {
482 *pszDirectory
= OString(pStr
, len
);
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);
502 if( osl_psz_getHomeDir(Security
, &home
) )
504 *pszDirectory
= home
+ "/Library/Application Support"; /* Used on iOS, too */
513 sal_Bool SAL_CALL
osl_isAdministrator(oslSecurity Security
)
515 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
517 if (pSecImpl
== nullptr)
520 if (pSecImpl
->m_pPasswd
.pw_uid
!= 0)
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
)
536 void SAL_CALL
osl_unloadUserProfile(SAL_UNUSED_PARAMETER oslSecurity
) {}
538 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */