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