Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <cstddef>
23 : #include <limits>
24 :
25 : #include "system.h"
26 :
27 : #include <osl/security.h>
28 : #include <osl/diagnose.h>
29 : #include <rtl/bootstrap.h>
30 : #include <sal/log.hxx>
31 :
32 : #include "osl/thread.h"
33 : #include "osl/file.h"
34 :
35 : #if defined LINUX || defined SOLARIS
36 : #include <crypt.h>
37 : #endif
38 :
39 : #include "secimpl.h"
40 :
41 : #ifdef ANDROID
42 : #define getpwuid_r(uid, pwd, buf, buflen, result) (*(result) = getpwuid(uid), (*(result) ? (memcpy (buf, *(result), sizeof (struct passwd)), 0) : errno))
43 : #endif
44 :
45 : static oslSecurityError SAL_CALL
46 : osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd,
47 : oslSecurity* pSecurity);
48 : extern "C" sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax);
49 : static sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax);
50 : static sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax);
51 : static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax);
52 :
53 255003 : static sal_Bool sysconf_SC_GETPW_R_SIZE_MAX(std::size_t * value) {
54 : #if defined _SC_GETPW_R_SIZE_MAX
55 : long m;
56 255003 : errno = 0;
57 255003 : m = sysconf(_SC_GETPW_R_SIZE_MAX);
58 255003 : if (m == -1) {
59 : /* _SC_GETPW_R_SIZE_MAX has no limit; some platforms like certain
60 : FreeBSD versions support sysconf(_SC_GETPW_R_SIZE_MAX) in a broken
61 : way and always set EINVAL, so be resilient here: */
62 0 : return sal_False;
63 : } else {
64 : OSL_ASSERT(
65 : m >= 0
66 : && (unsigned long) m < std::numeric_limits<std::size_t>::max());
67 255003 : *value = (std::size_t) m;
68 255003 : return sal_True;
69 : }
70 : #else
71 : /* some platforms like Mac OS X 1.3 do not define _SC_GETPW_R_SIZE_MAX: */
72 : return sal_False;
73 : #endif
74 : }
75 :
76 255003 : static oslSecurityImpl * growSecurityImpl(
77 : oslSecurityImpl * impl, std::size_t * bufSize)
78 : {
79 255003 : std::size_t n = 0;
80 255003 : oslSecurityImpl * p = NULL;
81 255003 : if (impl == NULL) {
82 255003 : if (!sysconf_SC_GETPW_R_SIZE_MAX(&n)) {
83 : /* choose something sensible (the callers of growSecurityImpl will
84 : detect it if the allocated buffer is too small: */
85 0 : n = 1024;
86 : }
87 0 : } else if (*bufSize <= std::numeric_limits<std::size_t>::max() / 2) {
88 0 : n = 2 * *bufSize;
89 : }
90 255003 : if (n != 0) {
91 510006 : if (n <= std::numeric_limits<std::size_t>::max()
92 255003 : - offsetof(oslSecurityImpl, m_buffer))
93 : {
94 255003 : *bufSize = n;
95 255003 : n += offsetof(oslSecurityImpl, m_buffer);
96 : } else {
97 0 : *bufSize = std::numeric_limits<std::size_t>::max()
98 0 : - offsetof(oslSecurityImpl, m_buffer);
99 0 : n = std::numeric_limits<std::size_t>::max();
100 : }
101 255003 : p = static_cast<oslSecurityImpl *>(realloc(impl, n));
102 255003 : memset (p, 0, n);
103 : }
104 255003 : if (p == NULL) {
105 0 : free(impl);
106 : }
107 255003 : return p;
108 : }
109 :
110 255003 : static void deleteSecurityImpl(oslSecurityImpl * impl) {
111 255003 : free(impl);
112 255003 : }
113 :
114 255003 : oslSecurity SAL_CALL osl_getCurrentSecurity()
115 : {
116 255003 : std::size_t n = 0;
117 255003 : oslSecurityImpl * p = NULL;
118 : for (;;) {
119 : struct passwd * found;
120 255003 : p = growSecurityImpl(p, &n);
121 255003 : if (p == NULL) {
122 255003 : return NULL;
123 : }
124 255003 : switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) {
125 : case ERANGE:
126 0 : break;
127 : case 0:
128 255003 : if (found != NULL) {
129 255003 : return p;
130 : }
131 : /* fall through */
132 : default:
133 0 : deleteSecurityImpl(p);
134 0 : return NULL;
135 : }
136 0 : }
137 : }
138 :
139 0 : oslSecurityError SAL_CALL osl_loginUser(
140 : rtl_uString *ustrUserName,
141 : rtl_uString *ustrPassword,
142 : oslSecurity *pSecurity
143 : )
144 : {
145 : oslSecurityError Error;
146 0 : rtl_String* strUserName=0;
147 0 : rtl_String* strPassword=0;
148 0 : sal_Char* pszUserName=0;
149 0 : sal_Char* pszPassword=0;
150 :
151 0 : if ( ustrUserName != 0 )
152 : {
153 : rtl_uString2String( &strUserName,
154 0 : rtl_uString_getStr(ustrUserName),
155 : rtl_uString_getLength(ustrUserName),
156 : RTL_TEXTENCODING_UTF8,
157 0 : OUSTRING_TO_OSTRING_CVTFLAGS );
158 0 : pszUserName = rtl_string_getStr(strUserName);
159 : }
160 :
161 0 : if ( ustrPassword != 0 )
162 : {
163 : rtl_uString2String( &strPassword,
164 0 : rtl_uString_getStr(ustrPassword),
165 : rtl_uString_getLength(ustrPassword),
166 : RTL_TEXTENCODING_UTF8,
167 0 : OUSTRING_TO_OSTRING_CVTFLAGS );
168 0 : pszPassword = rtl_string_getStr(strPassword);
169 : }
170 :
171 0 : Error=osl_psz_loginUser(pszUserName,pszPassword,pSecurity);
172 :
173 0 : if ( strUserName != 0 )
174 : {
175 0 : rtl_string_release(strUserName);
176 : }
177 :
178 0 : if ( strPassword)
179 : {
180 0 : rtl_string_release(strPassword);
181 : }
182 :
183 0 : return Error;
184 : }
185 :
186 : static oslSecurityError SAL_CALL
187 0 : osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd,
188 : oslSecurity* pSecurity)
189 : {
190 : (void)pszUserName;
191 : (void)pszPasswd;
192 : (void)pSecurity;
193 :
194 0 : return osl_Security_E_None;
195 : }
196 :
197 0 : oslSecurityError SAL_CALL osl_loginUserOnFileServer(
198 : rtl_uString *strUserName,
199 : rtl_uString *strPasswd,
200 : rtl_uString *strFileServer,
201 : oslSecurity *pSecurity
202 : )
203 : {
204 : (void) strUserName; /* unused */
205 : (void) strPasswd; /* unused */
206 : (void) strFileServer; /* unused */
207 : (void) pSecurity; /* unused */
208 0 : return osl_Security_E_UserUnknown;
209 : }
210 :
211 0 : sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent)
212 : {
213 0 : sal_Bool bRet=sal_False;
214 : sal_Char pszIdent[1024];
215 :
216 0 : pszIdent[0] = '\0';
217 :
218 0 : bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent));
219 :
220 0 : rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
221 : OSL_ASSERT(*ustrIdent != NULL);
222 :
223 0 : return bRet;
224 : }
225 :
226 2 : sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax)
227 : {
228 : sal_Char buffer[32];
229 : sal_Int32 nChr;
230 :
231 2 : oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security;
232 :
233 2 : if (pSecImpl == NULL)
234 0 : return sal_False;
235 :
236 2 : nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid);
237 4 : if ( nChr < 0 || sal::static_int_cast<sal_uInt32>(nChr) >= sizeof(buffer)
238 4 : || sal::static_int_cast<sal_uInt32>(nChr) >= nMax )
239 0 : return sal_False; /* leave *pszIdent unmodified in case of failure */
240 :
241 2 : memcpy(pszIdent, buffer, nChr+1);
242 2 : return sal_True;
243 : }
244 :
245 0 : sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName)
246 : {
247 0 : sal_Bool bRet=sal_False;
248 : sal_Char pszName[1024];
249 :
250 0 : pszName[0] = '\0';
251 :
252 0 : bRet = osl_psz_getUserName(Security,pszName,sizeof(pszName));
253 :
254 0 : rtl_string2UString( ustrName, pszName, rtl_str_getLength( pszName ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
255 : OSL_ASSERT(*ustrName != NULL);
256 :
257 0 : return bRet;
258 : }
259 :
260 0 : static sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax)
261 : {
262 0 : oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security;
263 :
264 0 : if (pSecImpl == NULL || pSecImpl->m_pPasswd.pw_name == NULL)
265 0 : return sal_False;
266 :
267 0 : strncpy(pszName, pSecImpl->m_pPasswd.pw_name, nMax);
268 :
269 0 : return sal_True;
270 : }
271 :
272 0 : sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
273 : {
274 0 : sal_Bool bRet=sal_False;
275 : sal_Char pszDirectory[PATH_MAX];
276 :
277 0 : pszDirectory[0] = '\0';
278 :
279 0 : bRet = osl_psz_getHomeDir(Security,pszDirectory,sizeof(pszDirectory));
280 :
281 0 : if ( bRet == sal_True )
282 : {
283 0 : rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
284 : OSL_ASSERT(*pustrDirectory != NULL);
285 0 : osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
286 : }
287 :
288 0 : return bRet;
289 : }
290 :
291 255002 : static sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
292 : {
293 255002 : oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security;
294 :
295 255002 : if (pSecImpl == NULL)
296 0 : return sal_False;
297 :
298 : #ifdef ANDROID
299 : {
300 : sal_Bool bRet = sal_False;
301 : rtl_uString *pName = 0, *pValue = 0;
302 :
303 : rtl_uString_newFromAscii(&pName, "HOME");
304 :
305 : if (rtl_bootstrap_get(pName, &pValue, NULL))
306 : {
307 : rtl_String *pStrValue = 0;
308 : if (pValue && pValue->length > 0)
309 : {
310 : rtl_uString2String(&pStrValue, pValue->buffer,
311 : pValue->length, RTL_TEXTENCODING_UTF8,
312 : OUSTRING_TO_OSTRING_CVTFLAGS);
313 : if (pStrValue && pStrValue->length > 0)
314 : {
315 : sal_Int32 nCopy = (sal_Int32)(nMax-1) < pStrValue->length ? (sal_Int32)(nMax-1) : pStrValue->length ;
316 : strncpy (pszDirectory, pStrValue->buffer, nCopy);
317 : pszDirectory[nCopy] = '\0';
318 : bRet = (std::size_t)pStrValue->length < nMax;
319 : }
320 : rtl_string_release(pStrValue);
321 : }
322 : rtl_uString_release(pName);
323 : }
324 : if (bRet)
325 : return bRet;
326 : }
327 : #endif
328 :
329 : /* if current user, check also environment for HOME */
330 255002 : if (getuid() == pSecImpl->m_pPasswd.pw_uid)
331 : {
332 255002 : sal_Char *pStr = NULL;
333 : #ifdef SOLARIS
334 : char buffer[8192];
335 :
336 : struct passwd pwd;
337 : struct passwd *ppwd;
338 :
339 : #ifdef _POSIX_PTHREAD_SEMANTICS
340 : if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) )
341 : ppwd = NULL;
342 : #else
343 : ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) );
344 : #endif
345 :
346 : if ( ppwd )
347 : pStr = ppwd->pw_dir;
348 : #else
349 255002 : pStr = getenv("HOME");
350 : #endif
351 :
352 255002 : if (pStr != NULL && strlen(pStr) > 0 && access(pStr, 0) == 0)
353 255002 : strncpy(pszDirectory, pStr, nMax);
354 0 : else if (pSecImpl->m_pPasswd.pw_dir != NULL)
355 0 : strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax);
356 : else
357 0 : return sal_False;
358 : }
359 0 : else if (pSecImpl->m_pPasswd.pw_dir != NULL)
360 0 : strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax);
361 : else
362 0 : return sal_False;
363 :
364 255002 : return sal_True;
365 : }
366 :
367 255002 : sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
368 : {
369 255002 : sal_Bool bRet = sal_False;
370 : sal_Char pszDirectory[PATH_MAX];
371 :
372 255002 : pszDirectory[0] = '\0';
373 :
374 255002 : bRet = osl_psz_getConfigDir(Security,pszDirectory,sizeof(pszDirectory));
375 :
376 255002 : if ( bRet == sal_True )
377 : {
378 255002 : rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
379 : OSL_ASSERT(*pustrDirectory != NULL);
380 255002 : osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
381 : }
382 :
383 255002 : return bRet;
384 : }
385 :
386 : #if !defined(MACOSX) && !defined(IOS)
387 :
388 : #define DOT_CONFIG "/.config"
389 :
390 255002 : static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
391 : {
392 255002 : sal_Char *pStr = getenv("XDG_CONFIG_HOME");
393 :
394 255002 : if (pStr == NULL || strlen(pStr) == 0 || access(pStr, 0) != 0)
395 : {
396 255002 : std::size_t n = 0;
397 :
398 : // a default equal to $HOME/.config should be used.
399 255002 : if (!osl_psz_getHomeDir(Security, pszDirectory, nMax))
400 0 : return sal_False;
401 255002 : n = strlen(pszDirectory);
402 255002 : if (n + sizeof(DOT_CONFIG) < nMax)
403 : {
404 255002 : strncpy(pszDirectory+n, DOT_CONFIG, sizeof(DOT_CONFIG));
405 :
406 : // try to create dir if not present
407 255002 : bool dirOK = true;
408 255002 : if (mkdir(pszDirectory, S_IRWXU) != 0)
409 : {
410 255002 : int e = errno;
411 255002 : if (e != EEXIST)
412 : {
413 : SAL_WARN(
414 : "sal.osl",
415 : "mkdir(" << pszDirectory << "): errno=" << e);
416 0 : dirOK = false;
417 : }
418 : }
419 255002 : if (dirOK)
420 : {
421 : // check file type and permissions
422 : struct stat st;
423 255002 : if (stat(pszDirectory, &st) != 0)
424 : {
425 : OSL_TRACE("Could not stat $HOME/.config");
426 0 : dirOK = false;
427 : }
428 : else
429 : {
430 255002 : if (!S_ISDIR(st.st_mode))
431 : {
432 : OSL_TRACE("$HOME/.config is not a directory");
433 0 : dirOK = false;
434 : }
435 255002 : if (!(st.st_mode & S_IRUSR && st.st_mode & S_IWUSR && st.st_mode & S_IXUSR))
436 : {
437 : OSL_TRACE("$HOME/.config has bad permissions");
438 0 : dirOK = false;
439 : }
440 : }
441 : }
442 :
443 : // resort to HOME
444 255002 : if (!dirOK)
445 0 : pszDirectory[n] = '\0';
446 : }
447 : }
448 : else
449 0 : strncpy(pszDirectory, pStr, nMax);
450 :
451 255002 : return sal_True;
452 : }
453 :
454 : #undef DOT_CONFIG
455 :
456 : #else
457 :
458 : /*
459 : * FIXME: rewrite to use more flexible
460 : * NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)
461 : * as soon as we can bumb the baseline to Tiger (for NSApplicationSupportDirectory) and have
462 : * support for Objective-C in the build environment
463 : */
464 :
465 : #define MACOSX_CONFIG_DIR "/Library/Application Support" /* Used on iOS, too */
466 : static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
467 : {
468 : if( osl_psz_getHomeDir(Security, pszDirectory, nMax - sizeof(MACOSX_CONFIG_DIR) + 1) )
469 : {
470 : strcat( pszDirectory, MACOSX_CONFIG_DIR );
471 : return sal_True;
472 : }
473 :
474 : return sal_False;
475 : }
476 :
477 : #endif
478 :
479 0 : sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
480 : {
481 0 : oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security;
482 :
483 0 : if (pSecImpl == NULL)
484 0 : return sal_False;
485 :
486 0 : if (pSecImpl->m_pPasswd.pw_uid != 0)
487 0 : return sal_False;
488 :
489 0 : return sal_True;
490 : }
491 :
492 255003 : void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
493 : {
494 255003 : deleteSecurityImpl(static_cast<oslSecurityImpl *>(Security));
495 255003 : }
496 :
497 0 : sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security)
498 : {
499 : (void) Security; /* unused */
500 0 : return sal_False;
501 : }
502 :
503 0 : void SAL_CALL osl_unloadUserProfile(oslSecurity Security)
504 : {
505 : (void) Security; /* unused */
506 0 : }
507 :
508 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|