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.hxx"
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.hxx"
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 1706 : static bool sysconf_SC_GETPW_R_SIZE_MAX(std::size_t * value) {
59 : #if defined _SC_GETPW_R_SIZE_MAX
60 : long m;
61 1706 : errno = 0;
62 1706 : m = sysconf(_SC_GETPW_R_SIZE_MAX);
63 1706 : 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 1706 : *value = (std::size_t) m;
72 1706 : 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 1706 : static oslSecurityImpl * growSecurityImpl(
81 : oslSecurityImpl * impl, std::size_t * bufSize)
82 : {
83 1706 : std::size_t n = 0;
84 1706 : oslSecurityImpl * p = NULL;
85 1706 : if (impl == NULL) {
86 1706 : 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 1706 : if (n != 0) {
95 3412 : if (n <= std::numeric_limits<std::size_t>::max()
96 1706 : - offsetof(oslSecurityImpl, m_buffer))
97 : {
98 1706 : *bufSize = n;
99 1706 : 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 1706 : p = static_cast<oslSecurityImpl *>(realloc(impl, n));
106 1706 : memset (p, 0, n);
107 : }
108 1706 : if (p == NULL) {
109 0 : free(impl);
110 : }
111 1706 : return p;
112 : }
113 :
114 1706 : static void deleteSecurityImpl(oslSecurityImpl * impl) {
115 1706 : free(impl);
116 1706 : }
117 :
118 1706 : oslSecurity SAL_CALL osl_getCurrentSecurity()
119 : {
120 1706 : std::size_t n = 0;
121 1706 : oslSecurityImpl * p = NULL;
122 : for (;;) {
123 : struct passwd * found;
124 1706 : p = growSecurityImpl(p, &n);
125 1706 : if (p == NULL) {
126 1706 : return NULL;
127 : }
128 1706 : switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) {
129 : case ERANGE:
130 0 : break;
131 : case 0:
132 1706 : if (found != NULL) {
133 1706 : 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 1 : 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 1 : return osl_Security_E_UserUnknown;
213 : }
214 :
215 1 : sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent)
216 : {
217 1 : bool bRet = false;
218 : sal_Char pszIdent[1024];
219 :
220 1 : pszIdent[0] = '\0';
221 :
222 1 : bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent));
223 :
224 1 : 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 1 : return bRet;
228 : }
229 :
230 516 : 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 516 : oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
236 :
237 516 : if (pSecImpl == NULL)
238 0 : return false;
239 :
240 516 : nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid);
241 1032 : if ( nChr < 0 || sal::static_int_cast<sal_uInt32>(nChr) >= sizeof(buffer)
242 1032 : || sal::static_int_cast<sal_uInt32>(nChr) >= nMax )
243 0 : return false; /* leave *pszIdent unmodified in case of failure */
244 :
245 516 : memcpy(pszIdent, buffer, nChr+1);
246 516 : return true;
247 : }
248 :
249 181 : sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName)
250 : {
251 181 : bool bRet = false;
252 : sal_Char pszName[1024];
253 :
254 181 : pszName[0] = '\0';
255 :
256 181 : bRet = osl_psz_getUserName(Security,pszName,sizeof(pszName));
257 :
258 181 : 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 181 : return bRet;
262 : }
263 :
264 181 : static bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32 nMax)
265 : {
266 181 : oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
267 :
268 181 : if (pSecImpl == NULL || pSecImpl->m_pPasswd.pw_name == NULL)
269 0 : return false;
270 :
271 181 : strncpy(pszName, pSecImpl->m_pPasswd.pw_name, nMax);
272 :
273 181 : return true;
274 : }
275 :
276 938 : sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
277 : {
278 938 : bool bRet = false;
279 : sal_Char pszDirectory[PATH_MAX];
280 :
281 938 : pszDirectory[0] = '\0';
282 :
283 938 : bRet = osl_psz_getHomeDir(Security,pszDirectory,sizeof(pszDirectory));
284 :
285 938 : if ( bRet )
286 : {
287 938 : 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 938 : osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
290 : }
291 :
292 938 : return bRet;
293 : }
294 :
295 992 : static bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
296 : {
297 992 : oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
298 :
299 992 : 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 992 : if (getuid() == pSecImpl->m_pPasswd.pw_uid)
348 : {
349 992 : 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 992 : pStr = getenv("HOME");
367 : #endif
368 :
369 992 : if (pStr != NULL && strlen(pStr) > 0 && access(pStr, 0) == 0)
370 992 : 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 992 : return true;
382 : }
383 :
384 54 : sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
385 : {
386 54 : bool bRet = false;
387 : sal_Char pszDirectory[PATH_MAX];
388 :
389 54 : pszDirectory[0] = '\0';
390 :
391 54 : bRet = osl_psz_getConfigDir(Security,pszDirectory,sizeof(pszDirectory));
392 :
393 54 : if ( bRet )
394 : {
395 54 : 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 54 : osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
398 : }
399 :
400 54 : return bRet;
401 : }
402 :
403 : #if !defined(MACOSX) && !defined(IOS)
404 :
405 : #define DOT_CONFIG "/.config"
406 :
407 54 : static bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
408 : {
409 54 : sal_Char *pStr = getenv("XDG_CONFIG_HOME");
410 :
411 54 : if (pStr == NULL || strlen(pStr) == 0 || access(pStr, 0) != 0)
412 : {
413 54 : std::size_t n = 0;
414 :
415 : // a default equal to $HOME/.config should be used.
416 54 : if (!osl_psz_getHomeDir(Security, pszDirectory, nMax))
417 0 : return false;
418 54 : n = strlen(pszDirectory);
419 54 : if (n + sizeof(DOT_CONFIG) < nMax)
420 : {
421 54 : strncpy(pszDirectory+n, DOT_CONFIG, sizeof(DOT_CONFIG));
422 :
423 : // try to create dir if not present
424 54 : bool dirOK = true;
425 54 : if (mkdir(pszDirectory, S_IRWXU) != 0)
426 : {
427 54 : int e = errno;
428 54 : if (e != EEXIST)
429 : {
430 : SAL_WARN(
431 : "sal.osl",
432 : "mkdir(" << pszDirectory << "): errno=" << e);
433 0 : dirOK = false;
434 : }
435 : }
436 54 : if (dirOK)
437 : {
438 : // check file type and permissions
439 : struct stat st;
440 54 : 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 54 : if (!S_ISDIR(st.st_mode))
448 : {
449 : SAL_INFO("sal.osl", "$HOME/.config is not a directory");
450 0 : dirOK = false;
451 : }
452 54 : 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 54 : if (!dirOK)
462 0 : pszDirectory[n] = '\0';
463 : }
464 : }
465 : else
466 0 : strncpy(pszDirectory, pStr, nMax);
467 :
468 54 : 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 3 : sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
497 : {
498 3 : oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl *>(Security);
499 :
500 3 : if (pSecImpl == NULL)
501 0 : return sal_False;
502 :
503 3 : if (pSecImpl->m_pPasswd.pw_uid != 0)
504 3 : return sal_False;
505 :
506 0 : return sal_True;
507 : }
508 :
509 1706 : void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
510 : {
511 1706 : deleteSecurityImpl(static_cast<oslSecurityImpl *>(Security));
512 1706 : }
513 :
514 1 : sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security)
515 : {
516 : (void) Security; /* unused */
517 1 : return sal_False;
518 : }
519 :
520 1 : void SAL_CALL osl_unloadUserProfile(oslSecurity Security)
521 : {
522 : (void) Security; /* unused */
523 1 : }
524 :
525 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|