xref: /trunk/main/sal/osl/unx/security.c (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <stddef.h>
29 
30 /* Solaris 8 has no C99 stdint.h, and Solaris generally seems not to miss it for
31    SIZE_MAX: */
32 #if !defined __SUNPRO_C
33 #include <stdint.h>
34 #endif
35 
36 #include "system.h"
37 
38 #include <osl/security.h>
39 #include <osl/diagnose.h>
40 
41 #include "osl/thread.h"
42 #include "osl/file.h"
43 
44 #if defined LINUX || defined SOLARIS
45 #include <crypt.h>
46 #endif
47 
48 #include "secimpl.h"
49 
50 #ifndef NOPAM
51 #ifndef PAM_BINARY_MSG
52 #define PAM_BINARY_MSG 6
53 #endif
54 #endif
55 
56 static oslSecurityError SAL_CALL
57 osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd,
58                   oslSecurity* pSecurity);
59 sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax);
60 static sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32  nMax);
61 static sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax);
62 static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax);
63 
64 static sal_Bool sysconf_SC_GETPW_R_SIZE_MAX(size_t * value) {
65 #if defined _SC_GETPW_R_SIZE_MAX
66     long m;
67     errno = 0;
68     m = sysconf(_SC_GETPW_R_SIZE_MAX);
69     if (m == -1) {
70         /* _SC_GETPW_R_SIZE_MAX has no limit; some platforms like certain
71            FreeBSD versions support sysconf(_SC_GETPW_R_SIZE_MAX) in a broken
72            way and always set EINVAL, so be resilient here: */
73         return sal_False;
74     } else {
75         OSL_ASSERT(m >= 0 && (unsigned long) m < SIZE_MAX);
76         *value = (size_t) m;
77         return sal_True;
78     }
79 #else
80     /* some platforms like Mac OS X 1.3 do not define _SC_GETPW_R_SIZE_MAX: */
81     return sal_False;
82 #endif
83 }
84 
85 static oslSecurityImpl * growSecurityImpl(
86     oslSecurityImpl * impl, size_t * bufSize)
87 {
88     size_t n = 0;
89     oslSecurityImpl * p = NULL;
90     if (impl == NULL) {
91         if (!sysconf_SC_GETPW_R_SIZE_MAX(&n)) {
92             /* choose something sensible (the callers of growSecurityImpl will
93                detect it if the allocated buffer is too small: */
94             n = 1024;
95         }
96     } else if (*bufSize <= SIZE_MAX / 2) {
97         n = 2 * *bufSize;
98     }
99     if (n != 0) {
100         if (n <= SIZE_MAX - offsetof(oslSecurityImpl, m_buffer)) {
101             *bufSize = n;
102             n += offsetof(oslSecurityImpl, m_buffer);
103         } else {
104             *bufSize = SIZE_MAX - offsetof(oslSecurityImpl, m_buffer);
105             n = SIZE_MAX;
106         }
107         p = realloc(impl, n);
108     }
109     if (p == NULL) {
110         free(impl);
111     }
112     return p;
113 }
114 
115 static void deleteSecurityImpl(oslSecurityImpl * impl) {
116     free(impl);
117 }
118 
119 oslSecurity SAL_CALL osl_getCurrentSecurity()
120 {
121     size_t n = 0;
122     oslSecurityImpl * p = NULL;
123     for (;;) {
124         struct passwd * found;
125         p = growSecurityImpl(p, &n);
126         if (p == NULL) {
127             return NULL;
128         }
129         switch (getpwuid_r(getuid(), &p->m_pPasswd, p->m_buffer, n, &found)) {
130         case ERANGE:
131             break;
132         case 0:
133             if (found != NULL) {
134                 return p;
135             }
136             /* fall through */
137         default:
138             deleteSecurityImpl(p);
139             return NULL;
140         }
141     }
142 }
143 
144 
145 #if defined LINUX && !defined NOPAM
146 
147 /*
148  *
149  * osl Routines for Pluggable Authentication Modules (PAM)
150  * tested with Linux-PAM 0.66 on Redhat-6.0 and
151  * Linux-PAM 0.64 on RedHat-5.2,
152  * XXX Will probably not run on PAM 0.59 or prior, since
153  *     number of pam_response* responses has changed
154  *
155  */
156 
157 #include <security/pam_appl.h>
158 
159 typedef struct {
160     char* name;
161     char* password;
162 } sal_PamData;
163 
164 typedef struct {
165     int (*pam_start)(const char *service_name, const char *user,
166                      const struct pam_conv *pam_conversation,
167                      pam_handle_t **pamh);
168     int (*pam_end)          (pam_handle_t *pamh, int pam_status);
169     int (*pam_authenticate) (pam_handle_t *pamh, int flags);
170     int (*pam_acct_mgmt)    (pam_handle_t *pamh, int flags);
171 } sal_PamModule;
172 
173 /*
174  * Implement a pam-conversation callback-routine,
175  * it just supply name and password instead of prompting the user.
176  * I guess that echo-off means 'ask for password' and echo-on means
177  * 'ask for user-name'. In fact I've never been asked anything else
178  * than the password
179  * XXX Please notice that if a pam-module does ask anything else, we
180  *     are completely lost, and a pam-module is free to do so
181  * XXX
182  */
183 
184 static int
185 osl_PamConversation (int num_msg, const struct pam_message **msgm,
186                      struct pam_response **response, void *appdata_ptr)
187 {
188     int         i;
189     sal_Bool    error;
190     sal_PamData         *pam_data;
191     struct pam_response *p_reply;
192 
193     /* resource initialization */
194     pam_data = (sal_PamData*) appdata_ptr;
195     p_reply  = (struct pam_response *) calloc( num_msg,
196                                                sizeof(struct pam_response));
197     if ( p_reply == NULL || pam_data == NULL )
198     {
199         if ( p_reply != NULL )
200             free ( p_reply );
201         *response = NULL;
202         return PAM_CONV_ERR;
203     }
204 
205     /* pseudo dialog */
206     error = sal_False;
207     for ( i = 0; i < num_msg ; i++ )
208     {
209         switch ( msgm[ i ]->msg_style )
210         {
211             case PAM_PROMPT_ECHO_OFF:
212                 p_reply[ i ].resp_retcode = 0;
213                 p_reply[ i ].resp         = strdup( pam_data->password );
214                 break;
215             case PAM_PROMPT_ECHO_ON:
216                 p_reply[ i ].resp_retcode = 0;
217                 p_reply[ i ].resp       = strdup( pam_data->name );
218                 break;
219             case PAM_ERROR_MSG:
220             case PAM_TEXT_INFO:
221             case PAM_BINARY_PROMPT:
222             case PAM_BINARY_MSG:
223                 p_reply[ i ].resp_retcode   = 0;
224                 p_reply[ i ].resp           = NULL;
225                 break;
226             default:
227                 error = sal_True;
228                 break;
229         }
230     }
231 
232     /* free resources on error */
233     if ( error )
234     {
235         for ( i = 0; i < num_msg ; i++ )
236             if ( p_reply[ i ].resp )
237             {
238                 memset ( p_reply[ i ].resp, 0,
239                          strlen( p_reply[ i ].resp ) );
240                 free   ( p_reply[ i ].resp );
241             }
242         free ( p_reply );
243 
244         *response = NULL;
245         return PAM_CONV_ERR;
246     }
247 
248     /* well done */
249     *response = p_reply;
250     return PAM_SUCCESS;
251 }
252 
253 #ifndef PAM_LINK
254 /*
255  * avoid linking against libpam.so, since it is not available on all systems,
256  * instead load-on-call, returns structure which holds pointer to
257  * pam-functions,
258  * library is never closed in case of success
259  */
260 
261 static sal_PamModule* osl_getPAM()
262 {
263     static sal_PamModule *pam_module = NULL;
264     static sal_Bool load_once = sal_False;
265 
266     if ( !load_once )
267     {
268         /* get library-handle. cannot use osl-module, since
269            RTLD_GLOBAL is required for PAM-0.64 RH 5.2
270            (but not for PAM-0.66 RH 6.0) */
271         void *pam_hdl;
272 
273         pam_hdl = dlopen( "libpam.so.0", RTLD_GLOBAL | RTLD_LAZY );
274 
275         if ( pam_hdl != NULL )
276             pam_module = (sal_PamModule*)calloc( 1, sizeof(sal_PamModule) );
277 
278         /* load functions */
279         if ( pam_module  != NULL )
280         {
281             pam_module->pam_acct_mgmt = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_acct_mgmt" );
282             pam_module->pam_authenticate
283                                       = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_authenticate" );
284             pam_module->pam_end       = (int (*)(pam_handle_t *, int)) dlsym ( pam_hdl, "pam_end" );
285             pam_module->pam_start     = (int (*)(const char *, const char *, const struct pam_conv *, pam_handle_t **)) dlsym ( pam_hdl, "pam_start" );
286 
287             /* free resources, if not completely successful */
288             if (   (pam_module->pam_start        == NULL)
289                 || (pam_module->pam_end          == NULL)
290                 || (pam_module->pam_authenticate == NULL)
291                 || (pam_module->pam_acct_mgmt    == NULL) )
292             {
293                 free( pam_module );
294                 pam_module = NULL;
295                 dlclose( pam_hdl );
296             }
297         }
298 
299         /* never try again */
300         load_once = sal_True;
301     }
302 
303     return pam_module;
304 }
305 #endif
306 
307 /*
308  * User Identification using PAM
309  */
310 
311 static sal_Bool
312 osl_PamAuthentification( const sal_Char* name, const sal_Char* password )
313 {
314     sal_Bool success = sal_False;
315 
316 #ifndef PAM_LINK
317     sal_PamModule* pam_module;
318 
319     pam_module = osl_getPAM();
320     if ( pam_module != NULL )
321     {
322 #endif
323         pam_handle_t   *pam_handle = NULL;
324         struct pam_conv pam_conversation;
325         sal_PamData     pam_data;
326 
327         int             return_value;
328 
329         pam_data.name     = (char*) name;
330         pam_data.password = (char*) password;
331 
332         pam_conversation.conv        = osl_PamConversation;
333         pam_conversation.appdata_ptr = (void*)(&pam_data);
334 
335 #ifndef PAM_LINK
336         return_value = pam_module->pam_start( "su", name,
337             &pam_conversation, &pam_handle);
338 #else
339         return_value = pam_start( "su", name,
340             &pam_conversation, &pam_handle);
341 #endif
342         if (return_value == PAM_SUCCESS )
343 #ifndef PAM_LINK
344             return_value = pam_module->pam_authenticate(pam_handle, 0);
345 #else
346             return_value = pam_authenticate(pam_handle, 0);
347 #endif
348         if (return_value == PAM_SUCCESS )
349 #ifndef PAM_LINK
350             return_value = pam_module->pam_acct_mgmt(pam_handle, 0);
351         pam_module->pam_end( pam_handle, return_value );
352 #else
353             return_value = pam_acct_mgmt(pam_handle, 0);
354         pam_end( pam_handle, return_value );
355 #endif
356 
357         success = (sal_Bool)(return_value == PAM_SUCCESS);
358 #ifndef PAM_LINK
359     }
360 #endif
361 
362     return success;
363 }
364 
365 
366 #ifndef CRYPT_LINK
367 /* dummy crypt, matches the interface of
368    crypt() but does not encrypt at all */
369 static const sal_Char* SAL_CALL
370 osl_noCrypt ( const sal_Char *key, const sal_Char *salt )
371 {
372     (void) salt; /* unused */
373     return key;
374 }
375 
376 /* load-on-call crypt library and crypt symbol */
377 static void*  SAL_CALL
378 osl_getCrypt()
379 {
380     static char* (*crypt_sym)(const char*, const char*) = NULL;
381     static sal_Bool load_once  = sal_False;
382 
383     if ( !load_once )
384     {
385         void * crypt_library;
386 
387         crypt_library = dlopen( "libcrypt.so.1", RTLD_GLOBAL | RTLD_LAZY ); /* never closed */
388         if ( crypt_library != NULL )
389             crypt_sym = (char* (*)(const char *, const char *)) dlsym(crypt_library, "crypt" );
390         if ( crypt_sym == NULL ) /* no libcrypt or libcrypt without crypt */
391             crypt_sym = (char* (*)(const char *, const char *)) &osl_noCrypt;
392 
393         load_once = sal_True;
394     }
395 
396     return (void*)crypt_sym;
397 }
398 
399 /* replacement for crypt function for password encryption, uses either
400    strong encryption of dlopen'ed libcrypt.so.1 or dummy implementation
401    with no encryption. Objective target is to avoid linking against
402    libcrypt (not available on caldera open linux 2.2 #63822#) */
403 static sal_Char* SAL_CALL
404 osl_dynamicCrypt ( const sal_Char *key, const sal_Char *salt )
405 {
406     char* (*dynamic_crypt)(char *, char *);
407 
408     dynamic_crypt = (char * (*)(char *, char *)) osl_getCrypt();
409 
410     return dynamic_crypt( (sal_Char*)key, (sal_Char*)salt );
411 }
412 #endif
413 
414 /*
415  * compare an encrypted and an unencrypted password for equality
416  * returns true if passwords are equal, false otherwise
417  * Note: uses crypt() and a mutex instead of crypt_r() since crypt_r needs
418  * more than 128KByte of external buffer for struct crypt_data
419  */
420 
421 static sal_Bool SAL_CALL
422 osl_equalPasswords ( const sal_Char *pEncryptedPassword, const sal_Char *pPlainPassword )
423 {
424     static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER;
425 
426     sal_Bool  success;
427     sal_Char  salt[3];
428     sal_Char *encrypted_plain;
429 
430     salt[0] = pEncryptedPassword[0];
431     salt[1] = pEncryptedPassword[1];
432     salt[2] = '\0';
433 
434     pthread_mutex_lock(&crypt_mutex);
435 
436 #ifndef CRYPT_LINK
437     encrypted_plain = (sal_Char *)osl_dynamicCrypt( pPlainPassword, salt );
438 #else
439     encrypted_plain = (sal_Char *)crypt( pPlainPassword, salt );
440 #endif
441     success = (sal_Bool) (strcmp(pEncryptedPassword, encrypted_plain) == 0);
442 
443     pthread_mutex_unlock(&crypt_mutex);
444 
445     return success;
446 }
447 
448 #endif /* defined LINUX && !defined NOPAM */
449 oslSecurityError SAL_CALL osl_loginUser(
450     rtl_uString *ustrUserName,
451     rtl_uString *ustrPassword,
452     oslSecurity *pSecurity
453     )
454 {
455     oslSecurityError Error;
456     rtl_String* strUserName=0;
457     rtl_String* strPassword=0;
458     sal_Char* pszUserName=0;
459     sal_Char* pszPassword=0;
460 
461     if ( ustrUserName != 0 )
462     {
463 
464         rtl_uString2String( &strUserName,
465                             rtl_uString_getStr(ustrUserName),
466                             rtl_uString_getLength(ustrUserName),
467                             RTL_TEXTENCODING_UTF8,
468                             OUSTRING_TO_OSTRING_CVTFLAGS );
469         pszUserName = rtl_string_getStr(strUserName);
470     }
471 
472 
473     if ( ustrPassword != 0 )
474     {
475         rtl_uString2String( &strPassword,
476                             rtl_uString_getStr(ustrPassword),
477                             rtl_uString_getLength(ustrPassword),
478                             RTL_TEXTENCODING_UTF8,
479                             OUSTRING_TO_OSTRING_CVTFLAGS );
480         pszPassword = rtl_string_getStr(strPassword);
481     }
482 
483 
484     Error=osl_psz_loginUser(pszUserName,pszPassword,pSecurity);
485 
486     if ( strUserName != 0 )
487     {
488         rtl_string_release(strUserName);
489     }
490 
491     if ( strPassword)
492     {
493         rtl_string_release(strPassword);
494     }
495 
496 
497     return Error;
498 }
499 
500 
501 static oslSecurityError SAL_CALL
502 osl_psz_loginUser(const sal_Char* pszUserName, const sal_Char* pszPasswd,
503                oslSecurity* pSecurity)
504 {
505 #if defined NETBSD || defined SCO || defined AIX || defined FREEBSD || \
506     defined MACOSX
507 
508     return osl_Security_E_None;
509 
510 #else
511 
512     oslSecurityError nError = osl_Security_E_Unknown;
513     oslSecurityImpl * p = NULL;
514     if (pszUserName != NULL && pszPasswd != NULL && pSecurity != NULL) {
515         /* get nis or normal password, should succeed for any known user, but
516            perhaps the password is wrong (i.e. 'x') if shadow passwords are in
517            use or authentication must be done by PAM */
518         size_t n = 0;
519         int err = 0;
520         struct passwd * found = NULL;
521         for (;;) {
522             p = growSecurityImpl(p, &n);
523             if (p == NULL) {
524                 break;
525             }
526             err = getpwnam_r(
527                 pszUserName, &p->m_pPasswd, p->m_buffer, n, &found);
528             if (err != ERANGE) {
529                 break;
530             }
531         }
532         if (p != NULL && err == 0) {
533             if (found == NULL) {
534                 nError = osl_Security_E_UserUnknown;
535             } else {
536 #if defined LINUX && !defined NOPAM
537                 /* only root is able to read the /etc/shadow passwd, a normal
538                    user even can't read his own encrypted passwd */
539                 if (osl_equalPasswords(p->m_pPasswd.pw_passwd, pszPasswd) ||
540                     osl_PamAuthentification(pszUserName, pszPasswd))
541                 {
542                     nError = osl_Security_E_None;
543                 } else {
544                     char buffer[1024];
545                     struct spwd result_buf;
546                     struct spwd * pShadowPasswd;
547                     buffer[0] = '\0';
548                     if (getspnam_r(
549                             pszUserName, &result_buf, buffer, sizeof buffer,
550                             &pShadowPasswd) == 0 &&
551                         pShadowPasswd != NULL)
552                     {
553                         nError =
554                             osl_equalPasswords(
555                                 pShadowPasswd->sp_pwdp, pszPasswd)
556                             ? osl_Security_E_None
557                             : osl_Security_E_WrongPassword;
558                     } else if (getuid() == 0) {
559                         /* mfe: Try to verify the root-password via nis */
560                         if (getspnam_r(
561                                 "root", &result_buf, buffer, sizeof buffer,
562                                 &pShadowPasswd) == 0 &&
563                             pShadowPasswd != NULL &&
564                             osl_equalPasswords(
565                                 pShadowPasswd->sp_pwdp, pszPasswd))
566                         {
567                             nError = osl_Security_E_None;
568                         } else {
569                             /* mfe: we can't get via nis (glibc2.0.x has bug in
570                                getspnam_r) we try it with the normal getspnam */
571                             static pthread_mutex_t pwmutex =
572                                 PTHREAD_MUTEX_INITIALIZER;
573                             pthread_mutex_lock(&pwmutex);
574                             pShadowPasswd = getspnam("root");
575                             pthread_mutex_unlock(&pwmutex);
576                             nError =
577                                 ((pShadowPasswd != NULL &&
578                                   osl_equalPasswords(
579                                       pShadowPasswd->sp_pwdp, pszPasswd)) ||
580                                  osl_PamAuthentification("root", pszPasswd))
581                                 ? osl_Security_E_None
582                                 : osl_Security_E_WrongPassword;
583                         }
584                     }
585                 }
586 #else
587                 char buffer[1024];
588                 struct spwd spwdStruct;
589                 buffer[0] = '\0';
590 #ifndef NEW_SHADOW_API
591                 if (getspnam_r(pszUserName, &spwdStruct, buffer, sizeof buffer) != NULL)
592 #else
593                 if (getspnam_r(pszUserName, &spwdStruct, buffer, sizeof buffer, NULL) == 0)
594 #endif
595                 {
596                     char salt[3];
597                     char * cryptPasswd;
598                     strncpy(salt, spwdStruct.sp_pwdp, 2);
599                     salt[2] = '\0';
600                     cryptPasswd = (char *) crypt(pszPasswd, salt);
601                     if (strcmp(spwdStruct.sp_pwdp, cryptPasswd) == 0) {
602                         nError = osl_Security_E_None;
603                     } else if (getuid() == 0 &&
604 #ifndef NEW_SHADOW_API
605                                (getspnam_r("root", &spwdStruct, buffer, sizeof buffer) != NULL))
606 #else
607                                (getspnam_r("root", &spwdStruct, buffer, sizeof buffer, NULL) == 0))
608 #endif
609                     {
610                         /* if current process is running as root, allow to logon
611                            as any other user */
612                         strncpy(salt, spwdStruct.sp_pwdp, 2);
613                         salt[2] = '\0';
614                         cryptPasswd = (char *) crypt(pszPasswd, salt);
615                         if (strcmp(spwdStruct.sp_pwdp, cryptPasswd) == 0) {
616                             nError = osl_Security_E_None;
617                         }
618                     } else {
619                         nError = osl_Security_E_WrongPassword;
620                     }
621                 }
622 #endif
623             }
624         }
625     }
626     if (nError == osl_Security_E_None) {
627         *pSecurity = p;
628     } else {
629         deleteSecurityImpl(p);
630         *pSecurity = NULL;
631     }
632     return nError;
633 
634 #endif
635 }
636 
637 oslSecurityError SAL_CALL osl_loginUserOnFileServer(
638     rtl_uString *strUserName,
639     rtl_uString *strPasswd,
640     rtl_uString *strFileServer,
641     oslSecurity *pSecurity
642     )
643 {
644     (void) strUserName; /* unused */
645     (void) strPasswd; /* unused */
646     (void) strFileServer; /* unused */
647     (void) pSecurity; /* unused */
648     return osl_Security_E_UserUnknown;
649 }
650 
651 
652 sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **ustrIdent)
653 {
654     sal_Bool bRet=sal_False;
655     sal_Char pszIdent[1024];
656 
657     pszIdent[0] = '\0';
658 
659     bRet = osl_psz_getUserIdent(Security,pszIdent,sizeof(pszIdent));
660 
661     rtl_string2UString( ustrIdent, pszIdent, rtl_str_getLength( pszIdent ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
662     OSL_ASSERT(*ustrIdent != NULL);
663 
664     return bRet;
665 }
666 
667 
668 sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax)
669 {
670     sal_Char  buffer[32];
671     sal_Int32 nChr;
672 
673     oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security;
674 
675     if (pSecImpl == NULL)
676         return sal_False;
677 
678     nChr = snprintf(buffer, sizeof(buffer), "%u", pSecImpl->m_pPasswd.pw_uid);
679     if ( nChr < 0 || SAL_INT_CAST(sal_uInt32, nChr) >= sizeof(buffer)
680          || SAL_INT_CAST(sal_uInt32, nChr) >= nMax )
681         return sal_False; /* leave *pszIdent unmodified in case of failure */
682 
683     memcpy(pszIdent, buffer, nChr+1);
684     return sal_True;
685 }
686 
687 sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **ustrName)
688 {
689     sal_Bool bRet=sal_False;
690     sal_Char pszName[1024];
691 
692     pszName[0] = '\0';
693 
694     bRet = osl_psz_getUserName(Security,pszName,sizeof(pszName));
695 
696     rtl_string2UString( ustrName, pszName, rtl_str_getLength( pszName ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
697     OSL_ASSERT(*ustrName != NULL);
698 
699     return bRet;
700 }
701 
702 
703 
704 static sal_Bool SAL_CALL osl_psz_getUserName(oslSecurity Security, sal_Char* pszName, sal_uInt32  nMax)
705 {
706     oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security;
707 
708     if (pSecImpl == NULL)
709         return sal_False;
710 
711     strncpy(pszName, pSecImpl->m_pPasswd.pw_name, nMax);
712 
713     return sal_True;
714 }
715 
716 sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
717 {
718     sal_Bool bRet=sal_False;
719     sal_Char pszDirectory[PATH_MAX];
720 
721     pszDirectory[0] = '\0';
722 
723     bRet = osl_psz_getHomeDir(Security,pszDirectory,sizeof(pszDirectory));
724 
725     if ( bRet == sal_True )
726     {
727         rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
728         OSL_ASSERT(*pustrDirectory != NULL);
729         osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
730     }
731 
732     return bRet;
733 }
734 
735 
736 static sal_Bool SAL_CALL osl_psz_getHomeDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
737 {
738     oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security;
739 
740     if (pSecImpl == NULL)
741         return sal_False;
742 
743     /* if current user, check also environment for HOME */
744     if (getuid() == pSecImpl->m_pPasswd.pw_uid)
745     {
746         sal_Char *pStr = NULL;
747 #ifdef SOLARIS
748         char    buffer[8192];
749 
750         struct passwd pwd;
751         struct passwd *ppwd;
752 
753 #ifdef _POSIX_PTHREAD_SEMANTICS
754         if ( 0 != getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &ppwd ) )
755             ppwd = NULL;
756 #else
757         ppwd = getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer) );
758 #endif
759 
760         if ( ppwd )
761             pStr = ppwd->pw_dir;
762 #else
763         pStr = getenv("HOME");
764 #endif
765 
766         if ((pStr != NULL) && (strlen(pStr) > 0) &&
767             (access(pStr, 0) == 0))
768             strncpy(pszDirectory, pStr, nMax);
769         else
770             strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax);
771     }
772     else
773         strncpy(pszDirectory, pSecImpl->m_pPasswd.pw_dir, nMax);
774 
775     return sal_True;
776 }
777 
778 sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
779 {
780     sal_Bool bRet = sal_False;
781     sal_Char pszDirectory[PATH_MAX];
782 
783     pszDirectory[0] = '\0';
784 
785     bRet = osl_psz_getConfigDir(Security,pszDirectory,sizeof(pszDirectory));
786 
787     if ( bRet == sal_True )
788     {
789         rtl_string2UString( pustrDirectory, pszDirectory, rtl_str_getLength( pszDirectory ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS );
790         OSL_ASSERT(*pustrDirectory != NULL);
791         osl_getFileURLFromSystemPath( *pustrDirectory, pustrDirectory );
792     }
793 
794     return bRet;
795 }
796 
797 #ifndef MACOSX
798 
799 static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
800 {
801     sal_Char *pStr = getenv("XDG_CONFIG_HOME");
802 
803     if ((pStr == NULL) || (strlen(pStr) == 0) ||
804         (access(pStr, 0) != 0))
805         return (osl_psz_getHomeDir(Security, pszDirectory, nMax));
806 
807     strncpy(pszDirectory, pStr, nMax);
808     return sal_True;
809 }
810 
811 #else
812 
813 /*
814  * FIXME: rewrite to use more flexible
815  * NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)
816  * as soon as we can bumb the baseline to Tiger (for NSApplicationSupportDirectory) and have
817  * support for Objective-C in the build environment
818  */
819 
820 #define MACOSX_CONFIG_DIR "/Library/Application Support"
821 static sal_Bool SAL_CALL osl_psz_getConfigDir(oslSecurity Security, sal_Char* pszDirectory, sal_uInt32 nMax)
822 {
823     if( osl_psz_getHomeDir(Security, pszDirectory, nMax - sizeof(MACOSX_CONFIG_DIR) + 1) )
824     {
825         strcat( pszDirectory, MACOSX_CONFIG_DIR );
826         return sal_True;
827     }
828 
829     return sal_False;
830 }
831 
832 #endif
833 
834 sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
835 {
836     oslSecurityImpl *pSecImpl = (oslSecurityImpl *)Security;
837 
838     if (pSecImpl == NULL)
839         return sal_False;
840 
841     if (pSecImpl->m_pPasswd.pw_uid != 0)
842         return (sal_False);
843 
844     return (sal_True);
845 }
846 
847 void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
848 {
849     deleteSecurityImpl(Security);
850 }
851 
852 
853 sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security)
854 {
855     (void) Security; /* unused */
856     return sal_False;
857 }
858 
859 void SAL_CALL osl_unloadUserProfile(oslSecurity Security)
860 {
861     (void) Security; /* unused */
862 }
863