xref: /trunk/main/sal/osl/unx/security.c (revision cdf0e10c)
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