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