comparison usr/src/lib/libkmsagent/common/SYSCommon.c @ 12720:3db6e0082404

PSARC 2010/195 PKCS11 KMS Provider 6944296 Solaris needs a PKCS#11 provider to allow access to KMS keystore functionality
author Wyllys Ingersoll <Wyllys.Ingersoll@Sun.COM>
date Mon, 28 Jun 2010 16:04:11 -0700
parents
children
comparison
equal deleted inserted replaced
12719:bd9fb35d09c2 12720:3db6e0082404
1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*---------------------------------------------------------------------------
27 * Module: SYSCommon.c
28 *-------------------------------------------------------------------------*/
29
30 #include <stdio.h>
31 #include "SYSCommon.h"
32 #include <time.h>
33 #include <errno.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <signal.h>
37
38 #ifndef WIN32
39 #include <unistd.h>
40 #endif
41
42 #ifdef WIN32
43 #include <io.h>
44 #include <stdlib.h> /* for malloc, calloc, and free */
45 #elif defined K_LINUX_PLATFORM
46 #include <unistd.h> /* it includes usleep(us) */
47 #include <sys/time.h>
48 #include <fts.h>
49 #else
50 /*
51 * Directory traversal code is not yet available for Solaris.
52 * If such code will need to be written, then it will probably use ftw.h.
53 */
54 #endif
55
56 #ifdef K_SOLARIS_PLATFORM
57 /* For K_AdjustLocalClock */
58 #include <unistd.h>
59 /* For K_SetRootPassword */
60 #define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
61 #include <errno.h>
62 #include <libgen.h>
63 #include <malloc.h>
64 #include <signal.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <strings.h>
68 #include <stropts.h>
69 #include <unistd.h>
70 #include <termio.h>
71 #include <security/pam_appl.h>
72 #include <widec.h>
73 #endif
74
75 #ifdef K_LINUX_PLATFORM
76 extern int pthread_mutexattr_settype __P ((pthread_mutexattr_t *__attr,
77 int __kind));
78 #endif
79
80 #ifdef K_HPUX_PLATFORM
81 int64 atoll(const char *str)
82 {
83 int64 tmp = 0;
84 sscanf(str, "%lld", &tmp);
85 return tmp;
86 }
87
88 #endif
89
90
91 /*---------------------------------------------------------------------------
92 * Function: K_CreateThread
93 *
94 * Description:
95 * Thread creation function "CreateThread" takes a thread function
96 * and its parameter to create a thread. It also has a Boolean
97 * parameter to indicate if the thread is detached or joinable.
98 * A new thread's handle is returned through the output parameter.
99 *
100 * Input
101 * -----
102 * i_pFunc Function pointer of the thread function
103 * i_pvData The point of the parameter passed to the thread function
104 * i_bIsDetached The thread is detached or not
105 * (Note: It is not supported on Win32)
106 *
107 * Output
108 * ------
109 * o_pNewThread The Thread handle
110 *
111 * Return value Error code
112 *
113 *--------------------------------------------------------------------------*/
114
115 int K_CreateThread(K_ThreadFunc i_pFunc,
116 void *i_pvData,
117 int i_bIsDetached,
118 K_THREAD_HANDLE *o_pNewThread)
119 {
120 int iOK = K_SYS_OK;
121 int iReturn = 0;
122
123 #ifdef WIN32
124
125 {
126 unsigned id;
127
128 *o_pNewThread = (HANDLE)_beginthreadex(NULL,
129 0,
130 (int (_stdcall *) (void *vpData))i_pFunc,
131 i_pvData,
132 0,
133 &id);
134
135
136 if(*o_pNewThread == 0)
137 {
138 #ifdef SYS_DEBUG
139 printf(" (%s, %d): error creating pthread, error = %d\n",
140 __FILE__, __LINE__, iReturn);
141 #endif
142 return K_SYS_ERR_CREATE_THREAD;
143 }
144
145 return K_SYS_OK;
146 }
147
148 #else
149 pthread_attr_t attr;
150
151 iReturn = pthread_attr_init(&attr);
152
153 if ( iReturn == 0 )
154 {
155 iReturn = pthread_attr_setdetachstate(&attr, (i_bIsDetached) ?
156 PTHREAD_CREATE_DETACHED :
157 PTHREAD_CREATE_JOINABLE);
158 }
159
160 #ifdef UNIX
161 if ( iReturn == 0 )
162 {
163 iReturn = pthread_attr_setstacksize(&attr, 1024*1024);
164 }
165 #endif
166
167 if ( iReturn == 0 )
168 {
169 iReturn = pthread_create(o_pNewThread, &attr, (void *(*)(void *)) i_pFunc, i_pvData);
170 }
171
172 if ( iReturn == 0 )
173 {
174 iReturn = pthread_attr_destroy(&attr);
175 }
176
177 // TODO: Log error?
178 if ( iReturn )
179 {
180 #ifdef SYS_DEBUG
181 printf(" (%s, %d): error creating pthread, error = %d\n",
182 __FILE__, __LINE__, iReturn);
183 #endif
184
185 iOK = K_SYS_ERR_CREATE_THREAD;
186 }
187
188 return iOK;
189 #endif
190 }
191
192
193 /*---------------------------------------------------------------------------
194 * Function: K_JoinThread
195 *
196 * Description:
197 * Thread joining function is called when the current thread
198 * waits another thread to terminate.
199 *
200 * Input
201 * -----
202 * i_hThread The thread handle of the to-be-joined thread
203 *
204 * Output
205 * ------
206 * (none)
207 *
208 * Return value Error code
209 *
210 *--------------------------------------------------------------------------*/
211
212 int K_JoinThread(K_THREAD_HANDLE i_hThread)
213 {
214 int iOK = K_SYS_OK;
215 #ifdef WIN32
216
217 WaitForSingleObject(i_hThread, INFINITE);
218
219 #else
220 {
221 int iReturn;
222 iReturn = pthread_join(i_hThread, NULL);
223
224 if ( iReturn )
225 {
226
227 #ifdef SYS_DEBUG
228 printf(" (%s, %d): error creating pthread, error = %d\n",
229 __FILE__, __LINE__, iReturn);
230 #endif
231 iOK = K_SYS_ERR_JOIN_THREAD;
232 }
233 }
234
235 #endif
236 return iOK;
237 }
238
239
240 /*---------------------------------------------------------------------------
241 * Function: K_GetCurrentThreadId
242 *
243 * Description:
244 * Returns the thread ID of the current thread.
245 *
246 * Input
247 * -----
248 * (none)
249 *
250 * Output
251 * ------
252 * (none)
253 *
254 * Return value The thread ID
255 *
256 *--------------------------------------------------------------------------*/
257
258 int K_GetCurrentThreadId()
259 {
260 #ifdef WIN32
261 return GetCurrentThreadId();
262 #else
263 return pthread_self();
264 #endif
265
266 }
267
268
269 /*---------------------------------------------------------------------------
270 * Function: K_CreateMutex
271 *
272 * Description:
273 * The mutex creation function creates a mutex according to the given
274 * mutex type, and returns the mutex handle to the output parameter.
275 *
276 * Input
277 * -----
278 * i_bIsRecursive Indication whether the mutex can be entered recursively
279 *
280 * Output
281 * ------
282 * o_phandle the handle pointer to the mutex
283 *
284 * Return value Error Code
285 *
286 *--------------------------------------------------------------------------*/
287
288 int K_CreateMutex( K_MUTEX_HANDLE *o_phandle )
289 {
290 int iOK = K_SYS_OK;
291 BOOL bIsRecursive = 1; // this used to be an input -- but why do we want this to be optional?
292
293 #ifdef WIN32
294 {
295 *o_phandle = (WIN32Mutex *)malloc(sizeof(WIN32Mutex));
296 if(*o_phandle == NULL)
297 {
298 return K_SYS_ERR_NO_MEMORY;
299 }
300 (*o_phandle)->m_bIsRecursive = bIsRecursive;
301 if(bIsRecursive)
302 {
303 InitializeCriticalSection(&((*o_phandle)->m_stCriticalSection));
304 }
305 else
306 {
307 (*o_phandle)->m_handle = CreateMutex(NULL, FALSE, NULL);
308 }
309
310 }
311 #else
312 {
313 int iType;
314 pthread_mutexattr_t attr;
315
316 if ( pthread_mutexattr_init(&attr) )
317 {
318 return K_SYS_ERR_COND;
319 }
320
321 if(bIsRecursive)
322 {
323 iType =
324 #ifdef K_LINUX_PLATFORM
325 PTHREAD_MUTEX_RECURSIVE_NP;
326 #else
327 PTHREAD_MUTEX_RECURSIVE;
328 #endif
329
330 if ( pthread_mutexattr_settype(&attr, iType) )
331 {
332 return K_SYS_ERR_COND;
333 }
334 }
335
336 *o_phandle = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
337 if(*o_phandle == NULL)
338 {
339 return K_SYS_ERR_NO_MEMORY;
340 }
341
342 if ( pthread_mutex_init(*o_phandle, &attr) )
343 {
344 return K_SYS_ERR_COND;
345 }
346
347 if ( pthread_mutexattr_destroy(&attr) )
348 {
349 return K_SYS_ERR_COND;
350 }
351 }
352 #endif
353
354 return iOK;
355 }
356
357
358 /*---------------------------------------------------------------------------
359 * Function: K_LockMutex
360 *
361 * Description:
362 * K_LockMutex is used to lock the mutex, and K_UnlockMutex is
363 * used to unlock it.
364 *
365 * Input
366 * -----
367 * i_handle the mutex handle
368 *
369 * Output
370 * ------
371 * (none)
372 *
373 * Return value Error Code
374 *
375 *--------------------------------------------------------------------------*/
376
377 int K_LockMutex(K_MUTEX_HANDLE i_handle)
378 {
379 int iOK = K_SYS_OK;
380 #ifdef WIN32
381
382 if(i_handle->m_bIsRecursive)
383 {
384 EnterCriticalSection(&(i_handle->m_stCriticalSection));
385 }
386 else
387 {
388 WaitForSingleObject(i_handle->m_handle, INFINITE);
389 }
390
391 #else
392
393 if ( pthread_mutex_lock(i_handle) )
394 {
395 return K_SYS_ERR_COND;
396 }
397
398 #endif
399 return iOK; // TODO: better error handling
400 }
401
402
403 /*---------------------------------------------------------------------------
404 * Function: K_UnlockMutex
405 *
406 * Description:
407 * K_UnlockMutex is used to unlock the lock.
408 *
409 * Input
410 * -----
411 * i_handle the mutex handle
412 *
413 * Output
414 * ------
415 * (none)
416 *
417 * Return value Error Code
418 *
419 *--------------------------------------------------------------------------*/
420
421 int K_UnlockMutex(K_MUTEX_HANDLE i_handle)
422 {
423 int iOK = K_SYS_OK;
424
425 #ifdef WIN32
426 if(i_handle->m_bIsRecursive)
427 {
428 LeaveCriticalSection(&(i_handle->m_stCriticalSection));
429 }
430 else
431 {
432 ReleaseMutex(i_handle->m_handle);
433 }
434
435 #else
436
437 if ( pthread_mutex_unlock(i_handle) )
438 {
439 return K_SYS_ERR_COND;
440 }
441 #endif
442
443 return iOK; // TODO: better error handling
444 }
445
446
447 /*---------------------------------------------------------------------------
448 * Function: K_DestroyMutex
449 *
450 * Description:
451 * When a mutex is no longer needed, K_DestroyMutex must be called
452 * to destroy it.
453 *
454 * Input
455 * -----
456 * i_handle the mutex handle
457 * Output
458 * ------
459 * (none)
460 *
461 * Return value Error Code
462 *
463 *--------------------------------------------------------------------------*/
464
465 int K_DestroyMutex(K_MUTEX_HANDLE i_handle)
466 {
467
468 int iOK = K_SYS_OK;
469
470 #ifdef WIN32
471
472 if(i_handle->m_bIsRecursive)
473 {
474 DeleteCriticalSection(&(i_handle->m_stCriticalSection));
475 }
476 else
477 {
478 CloseHandle(i_handle->m_handle);
479 }
480 free(i_handle);
481
482 #else
483 pthread_mutex_destroy(i_handle);
484 free(i_handle);
485 #endif
486 return iOK; // TODO: better error handling
487 }
488
489
490 /*---------------------------------------------------------------------------
491 * Function: K_InitConditionalVariable
492 *
493 * Description:
494 * This function initializes a conditional variable. Upon successful
495 * completion, the new condition variable is returned via the condition
496 * parameter, and 0 is returned. Otherwise, an error code is returned.
497 *
498 * Input
499 * -----
500 * i_pCond the pointer to the conditional variable which is to be
501 * initialized
502 *
503 * Output
504 * ------
505 * (none)
506 *
507 * Return value Error Code
508 *
509 *--------------------------------------------------------------------------*/
510
511 int K_InitConditionalVariable (K_ConditionalVariable * i_pCond)
512 {
513 int iOK = K_SYS_OK;
514 #ifdef WIN32
515
516 i_pCond->m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
517 i_pCond->m_hMutex = CreateMutex(NULL, FALSE, NULL);
518 i_pCond->m_iSignalAll = 0;
519 i_pCond->m_iNumWaiting = 0;
520
521 #else
522
523 if ( pthread_cond_init(i_pCond, NULL) )
524 {
525 return K_SYS_ERR_COND;
526 }
527
528 #endif
529
530 return iOK;
531 }
532
533
534 /*---------------------------------------------------------------------------
535 * Function: K_DestroyConditionalVariable
536 *
537 * Description:
538 * This function destroys a conditional variable. Upon successful
539 * completion, the condition variable is destroyed, and 0 is returned.
540 * Otherwise, an error code is returned.
541 * After deletion of the condition variable, the condition parameter
542 * is not valid until it is initialized again by a call to the
543 * K_InitConditionalVariable subroutine.
544 *
545 * Input
546 * -----
547 * i_pCond the pointer to the conditional variable which is to be
548 * destroyed
549 * Output
550 * ------
551 * (none)
552 *
553 * Return value Error Code
554 *
555 *--------------------------------------------------------------------------*/
556
557 int K_DestroyConditionalVariable(K_ConditionalVariable * i_pCond)
558 {
559 int iOK = K_SYS_OK;
560 #ifdef WIN32
561 CloseHandle(i_pCond->m_hMutex);
562 CloseHandle(i_pCond->m_hEvent);
563 #else
564
565 if ( pthread_cond_destroy(i_pCond) )
566 {
567 return K_SYS_ERR_COND;
568 }
569
570 #endif
571 return iOK;
572
573 }
574
575
576 /*---------------------------------------------------------------------------
577 * Function: K_WaitConditionalVariable
578 *
579 * Description:
580 * This function is used to block on a condition variable.
581 * They are called with mutex locked by the calling thread or undefined
582 * behaviour will result.
583 *
584 * Input
585 * -----
586 * i_pCond the pointer to the conditional variable
587 * i_handle the companion mutex handle
588 *
589 * Output
590 * ------
591 * (none)
592 *
593 * Return value Error Code
594 *
595 *--------------------------------------------------------------------------*/
596
597 int K_WaitConditionalVariable(K_ConditionalVariable * i_pCond,
598 K_MUTEX_HANDLE i_handle)
599 {
600
601 int iOK = K_SYS_OK;
602 #ifdef WIN32
603 DWORD res;
604
605 while (1)
606 {
607 iOK = WaitForSingleObject(i_pCond->m_hMutex, INFINITE);
608 if (iOK != WAIT_OBJECT_0)
609 {
610 return K_SYS_ERR_COND;
611 }
612 i_pCond->m_iNumWaiting++;
613 ReleaseMutex(i_pCond->m_hMutex);
614
615 K_UnlockMutex(i_handle);
616 res = WaitForSingleObject(i_pCond->m_hEvent, INFINITE);
617 i_pCond->m_iNumWaiting--;
618
619 if (res != WAIT_OBJECT_0)
620 {
621 ReleaseMutex(i_pCond->m_hMutex);
622 return K_SYS_ERR_COND;
623 }
624
625 if (i_pCond->m_iSignalAll)
626 {
627 if (i_pCond->m_iNumWaiting == 0)
628 {
629 ResetEvent(i_pCond->m_hEvent);
630 }
631 break;
632 }
633
634 if (i_pCond->m_iSignalled)
635 {
636 i_pCond->m_iSignalled = 0;
637 ResetEvent(i_pCond->m_hEvent);
638 break;
639 }
640 ReleaseMutex(i_pCond->m_hMutex);
641 }
642
643 K_LockMutex(i_handle);
644
645 return K_SYS_OK;
646 #else
647
648 if ( pthread_cond_wait(i_pCond, i_handle) )
649 {
650 return K_SYS_ERR_COND;
651 }
652
653 #endif
654 return iOK; // TODO: better error handling
655 }
656
657
658 /*---------------------------------------------------------------------------
659 * Function: K_SignalConditionalVariable
660 *
661 * Description:
662 * This function is used to restart one of the threads that are waiting on
663 * the condition variable. If no threads are waiting on it, nothing happens.
664 * If several threads are waiting on it, exactly one is restarted.
665 *
666 * Input
667 * -----
668 * i_pCond the pointer to the conditional variable
669 *
670 * Output
671 * ------
672 * (none)
673 *
674 * Return value Error Code
675 *
676 *--------------------------------------------------------------------------*/
677
678 int K_SignalConditionalVariable(K_ConditionalVariable * i_pCond)
679 {
680 int iOK = K_SYS_OK;
681 #ifdef WIN32
682
683 int iReturn;
684
685 iReturn = WaitForSingleObject(i_pCond->m_hMutex, INFINITE);
686 if (iReturn != WAIT_OBJECT_0)
687 {
688 return K_SYS_ERR_COND;
689 }
690
691 i_pCond->m_iSignalled = 1;
692
693 iReturn = SetEvent(i_pCond->m_hEvent);
694 if (iReturn == 0)
695 {
696 iOK = K_SYS_ERR_COND;
697 }
698 ReleaseMutex(i_pCond->m_hMutex);
699
700 return iOK;
701 #else
702
703 if ( pthread_cond_signal(i_pCond) )
704 {
705 return K_SYS_ERR_COND;
706 }
707
708 #endif
709 return iOK;
710 }
711
712
713 /*---------------------------------------------------------------------------
714 * Function: K_BroadcastConditionalVariable
715 *
716 * Description:
717 * This function is used to restart all threads that are waiting on
718 * the condition variable.
719 *
720 * Input
721 * -----
722 * i_pCond the pointer to the conditional variable
723 *
724 * Output
725 * ------
726 * (none)
727 *
728 * Return value Error Code
729 *
730 *--------------------------------------------------------------------------*/
731
732 int K_BroadcastConditionalVariable(K_ConditionalVariable * i_pCond)
733 {
734
735 int iOK = K_SYS_OK;
736
737 #ifdef WIN32
738
739 int iReturn;
740
741 iReturn = WaitForSingleObject(i_pCond->m_hMutex, INFINITE);
742 if (iReturn != WAIT_OBJECT_0)
743 {
744 return K_SYS_ERR_COND;
745 }
746 i_pCond->m_iSignalled = 1;
747 i_pCond->m_iSignalAll = 1;
748
749 iReturn = SetEvent(i_pCond->m_hEvent);
750
751 if (iReturn == 0)
752 {
753 iOK = K_SYS_ERR_COND;
754 }
755
756 ReleaseMutex(i_pCond->m_hMutex);
757
758 return iOK;
759
760 #else
761
762 if ( pthread_cond_broadcast(i_pCond) )
763 {
764 return K_SYS_ERR_COND;
765 }
766
767 #endif
768 return iOK;
769 }
770
771
772 /*---------------------------------------------------------------------------
773 * Function: K_Sleep
774 *
775 * Description:
776 * Sleep for a given period in given milliseconds.
777 *
778 * Input
779 * -----
780 * i_ms milliseconds
781 *
782 * Output
783 * ------
784 * (none)
785 *
786 * Return value (none)
787 *
788 *--------------------------------------------------------------------------*/
789
790 void K_Sleep(int i_ms)
791 {
792 #ifdef WIN32
793 Sleep(i_ms);
794 #else
795 usleep(i_ms * 1000);
796 #endif
797 }
798
799
800 /*---------------------------------------------------------------------------
801 * Function: K_GetTickCount
802 *
803 * Description:
804 * The K_GetTickCount function retrieves the number of
805 * milliseconds that have elapsed since the system was started.
806 *
807 * Input
808 * -----
809 * (none)
810 *
811 * Output
812 * ------
813 * (none)
814 *
815 * Return value the elasped milliseconds since the system was started
816 *
817 *--------------------------------------------------------------------------*/
818
819 unsigned int K_GetTickCount()
820 {
821 #ifdef WIN32
822 return (unsigned int)GetTickCount();
823 #else
824 {
825 struct timeval tv;
826 gettimeofday( &tv, NULL );
827 /* this will rollover ~ every 49.7 days
828 dont surprise when it returns negative values, since we are only interested
829 in using sth like "tickCount2 - tickCount1" to get the time interval
830 */
831 return ( tv.tv_sec * 1000 ) + ( tv.tv_usec / 1000 );
832 }
833 #endif
834 }
835
836
837 /*---------------------------------------------------------------------------
838 * Function: K_AdjustClock
839 *
840 * Description:
841 * The K_AdjustClock function immediately adjusts the system clock by
842 * the given number of seconds. A positive number adjusts the system
843 * clock forward; a negative number adjusts the system clock backward.
844 *
845 * Input
846 * -----
847 * i_iAdjustmentInSeconds Number of seconds by which to adjust the
848 * system clock
849 * Output
850 * ------
851 * (none)
852 *
853 * Return value 1 if successful, 0 on error
854 *
855 *--------------------------------------------------------------------------*/
856
857 int K_AdjustClock( long i_iAdjustmentInSeconds )
858 {
859 #ifndef WIN32
860 struct timeval stDateTime;
861 if ( 0 != gettimeofday(&stDateTime, NULL) )
862 {
863 return FALSE;
864 }
865
866 stDateTime.tv_sec += i_iAdjustmentInSeconds;
867
868 if ( 0 != settimeofday(&stDateTime, NULL) )
869 {
870 return FALSE;
871 }
872 #else
873 // TODO: implement for Windows
874 return FALSE;
875 #endif
876
877 return TRUE;
878 }
879
880
881 /*---------------------------------------------------------------------------
882 * Function: K_IsLittleEndian
883 *
884 * Description:
885 * Checks to see whether this platform uses little endian integer
886 * representation.
887 *
888 * Input
889 * -----
890 * (none)
891 *
892 * Output
893 * ------
894 * (none)
895 *
896 * Return value 1 for little endian
897 *
898 *--------------------------------------------------------------------------*/
899
900 int K_IsLittleEndian()
901 {
902 short iWord = 0x4321;
903 return ((*(unsigned char*)&iWord) == 0x21);
904 }
905
906
907 /*---------------------------------------------------------------------------
908 * Function: K_FileLength32
909 *
910 * Description:
911 * Gets the size in bytes of the file associated with the given FILE pointer.
912 *
913 * Input
914 * -----
915 * i_fpFile File handle
916 *
917 * Output
918 * ------
919 * (none)
920 *
921 * Return value File size in bytes, or -1L on error
922 *
923 *--------------------------------------------------------------------------*/
924
925 long K_FileLength32( FILE* i_fpFile )
926 {
927 #ifdef WIN32
928 int iFileDescriptor = _fileno( i_fpFile );
929 struct _stat stStat;
930
931 if ( _fstat(iFileDescriptor, &stStat) != 0)
932 {
933 // error
934 return -1L;
935 }
936
937 #else
938 int iFileDescriptor = fileno( i_fpFile );
939 struct stat stStat;
940
941 if ( fstat(iFileDescriptor, &stStat) != 0)
942 {
943 // error
944 return -1L;
945 }
946
947 #endif
948
949 return stStat.st_size;
950 }
951
952
953 /*---------------------------------------------------------------------------
954 * Function: K_StringCompareNoCase
955 *
956 * Description:
957 * Compares the two given strings insensitive to case.
958 *
959 * Input
960 * -----
961 * i_sString1 First string
962 * i_sString2 Second string
963 *
964 * Output
965 * ------
966 * (none)
967 *
968 * Return value 0 if identical, -1 if first string is less than second
969 * string, or 1 if first string is greater than second
970 *
971 *--------------------------------------------------------------------------*/
972
973 int K_StringCompareNoCase( const char* i_sString1, const char* i_sString2 )
974 {
975 #ifdef WIN32
976 return _stricmp( i_sString1, i_sString2 );
977 #else
978 return strcasecmp( i_sString1, i_sString2 );
979 #endif
980 }
981
982
983 /*---------------------------------------------------------------------------
984 * Function: K_StringCompareNoCaseWide
985 *
986 * Description:
987 * Compares the two given wide strings insensitive to case.
988 *
989 * Input
990 * -----
991 * i_wsString1 First wide string
992 * i_wsString2 Second wide string
993 *
994 * Output
995 * ------
996 * (none)
997 *
998 * Return value 0 if identical, -1 if first string is less than second
999 * string, or 1 if first string is greater than second
1000 *
1001 *--------------------------------------------------------------------------*/
1002
1003 int K_StringCompareNoCaseWide( const wchar_t* i_wsString1, const wchar_t* i_wsString2 )
1004 {
1005 #ifdef WIN32
1006 return _wcsicmp( i_wsString1, i_wsString2 );
1007 #elif defined K_SOLARIS_PLATFORM
1008 return wscasecmp( i_wsString1, i_wsString2 );
1009 #else
1010 return wcscasecmp( i_wsString1, i_wsString2 );
1011 #endif
1012 }
1013
1014
1015 /*---------------------------------------------------------------------------
1016 * Function: K_CreateDirectory
1017 *
1018 * Description:
1019 * Creates a directory with the given path name.
1020 *
1021 * Input
1022 * -----
1023 * i_sDirectoryName Directory name
1024 *
1025 * Output
1026 * ------
1027 * (none)
1028 *
1029 * Return value 0 on success, -1 on failure
1030 *
1031 *--------------------------------------------------------------------------*/
1032
1033 int K_CreateDirectory( const char* i_sDirectoryName )
1034 {
1035 // TODO: make this build all parent directories as well.
1036
1037 #ifdef WIN32
1038 if ( CreateDirectoryA( i_sDirectoryName, NULL ) )
1039 {
1040 return 0;
1041 }
1042 else
1043 {
1044 DWORD dwError = GetLastError();
1045 return ( dwError == ERROR_ALREADY_EXISTS ) ? 0 : (dwError ? dwError : -1);
1046 }
1047 #else
1048 if ( mkdir( i_sDirectoryName, S_IRWXU ) == 0 )
1049 {
1050 return 0;
1051 }
1052 else
1053 {
1054 return ( errno == EEXIST ) ? 0 : (errno ? errno : -1);
1055 }
1056 #endif
1057 }
1058
1059
1060 /*---------------------------------------------------------------------------
1061 * Function: K_DeleteFile
1062 *
1063 * Description:
1064 * Deletes the given file.
1065 *
1066 * Input
1067 * -----
1068 * i_sFilename Name of file to delete
1069 *
1070 * Output
1071 * ------
1072 * (none)
1073 *
1074 * Return value 0 on success, errno on failure
1075 *
1076 *--------------------------------------------------------------------------*/
1077
1078 int K_DeleteFile( const char* i_sFilename )
1079 {
1080 int bSuccess = 0;
1081
1082 bSuccess =
1083 #ifdef WIN32
1084 _unlink(
1085 #else
1086 unlink(
1087 #endif
1088 i_sFilename ) == 0;
1089
1090 return bSuccess ? 0 : errno;
1091 }
1092
1093
1094 /*---------------------------------------------------------------------------
1095 * Function: K_ReadFile
1096 *
1097 * Description:
1098 * Reads from the given file and passes the bytes read back to the output
1099 * parameter. The caller must deallocate o_ppFileData using free().
1100 *
1101 * Input
1102 * -----
1103 * i_sFilename Name of file from which to read
1104 *
1105 * Output
1106 * ------
1107 * o_ppFileData Pointer to bytes read
1108 *
1109 * Return value Number of bytes read on success, -1 on failure
1110 *
1111 *--------------------------------------------------------------------------*/
1112
1113 int K_ReadFile( const char* i_sFilename, unsigned char** o_ppFileData )
1114 {
1115 FILE* pFile = 0;
1116 long iFileSize = 0;
1117
1118 if ( !i_sFilename || (strlen(i_sFilename) <= 0) || !o_ppFileData )
1119 {
1120 return -1;
1121 }
1122
1123 *o_ppFileData = 0;
1124
1125 // Open the file
1126
1127 pFile = fopen( i_sFilename, "rb" );
1128 if ( !pFile )
1129 {
1130 return -1;
1131 }
1132
1133 // Determine the file size
1134
1135 if ( fseek( pFile, 0, SEEK_END ) )
1136 {
1137 (void) fclose( pFile );
1138 return -1;
1139 }
1140
1141 iFileSize = ftell( pFile );
1142 if ( iFileSize < 0 )
1143 {
1144 (void) fclose( pFile );
1145 return -1;
1146 }
1147 else if ( iFileSize == 0 )
1148 {
1149 (void) fclose( pFile );
1150 return 0;
1151 }
1152
1153 if ( fseek( pFile, 0, SEEK_SET ) )
1154 {
1155 (void) fclose( pFile );
1156 return -1;
1157 }
1158
1159 *o_ppFileData = (unsigned char*)malloc( iFileSize );
1160 if ( !*o_ppFileData )
1161 {
1162 // Out of memory.
1163 (void) fclose( pFile );
1164 return -1;
1165 }
1166
1167 if ( iFileSize != (long)fread( *o_ppFileData, 1, iFileSize, pFile ) )
1168 {
1169 free( *o_ppFileData );
1170 *o_ppFileData = 0;
1171 (void) fclose( pFile );
1172 return -1;
1173 }
1174
1175 (void) fclose( pFile );
1176
1177 return iFileSize;
1178 }
1179
1180
1181 /*---------------------------------------------------------------------------
1182 * Function: K_ReadFileString
1183 *
1184 * Description:
1185 * Reads from the given file and passes the bytes read back to the output
1186 * parameter, appending these bytes with a null terminator. There is no
1187 * guarantee that there are no non-text characters in the returned "string".
1188 * The caller must deallocate o_ppFileData using free().
1189 *
1190 * Input
1191 * -----
1192 * i_sFilename Name of file from which to read
1193 *
1194 * Output
1195 * ------
1196 * o_psFileDataString Pointer to bytes read
1197 *
1198 * Return value Number of bytes read (including null terminator) on
1199 * success (0 if file is empty), -1 on failure
1200 *
1201 *--------------------------------------------------------------------------*/
1202
1203 int K_ReadFileString( const char* i_sFilename, char** o_psFileDataString )
1204 {
1205 unsigned char* pFileData = 0;
1206 int iFileSize = 0;
1207
1208 *o_psFileDataString = 0;
1209
1210 iFileSize = K_ReadFile( i_sFilename, &pFileData );
1211
1212 if ( iFileSize <= 0 )
1213 {
1214 return iFileSize;
1215 }
1216
1217 *o_psFileDataString = (char*)malloc( iFileSize+1 );
1218
1219 if ( !*o_psFileDataString )
1220 {
1221 // Out of memory.
1222 if ( pFileData )
1223 {
1224 free( pFileData );
1225 }
1226 return -1;
1227 }
1228
1229 memcpy( *o_psFileDataString, pFileData, iFileSize );
1230
1231 (*o_psFileDataString)[iFileSize] = '\0';
1232
1233 if ( pFileData )
1234 {
1235 free( pFileData );
1236 }
1237
1238 return iFileSize+1;
1239 }
1240
1241
1242 /*---------------------------------------------------------------------------
1243 * Function: K_WriteFile
1244 *
1245 * Description:
1246 * Writes the given bytes to the given file.
1247 *
1248 * Input
1249 * -----
1250 * i_sFilename Name of file to which to write
1251 * i_pFileData Bytes to write
1252 * i_iFileDataSize Number of bytes to write
1253 *
1254 * Output
1255 * ------
1256 * (none)
1257 *
1258 * Return value 0 on success, errno or -1 (generic error) on failure
1259 *
1260 *--------------------------------------------------------------------------*/
1261
1262 int K_WriteFile( const char* i_sFilename, const unsigned char* i_pFileData, int i_iFileDataSize )
1263 {
1264 FILE* pFile = 0;
1265
1266 if ( !i_sFilename || (strlen(i_sFilename) <= 0) || (!i_pFileData && (i_iFileDataSize > 0)) || (i_iFileDataSize < 0) )
1267 {
1268 return -1;
1269 }
1270
1271 pFile = fopen( i_sFilename, "wb" );
1272 if ( !pFile )
1273 {
1274 int iError = errno;
1275 return (iError != 0) ? iError : -1;
1276 }
1277
1278 if ( i_iFileDataSize > 0 )
1279 {
1280 if ( i_iFileDataSize != (int)fwrite( i_pFileData, 1, i_iFileDataSize, pFile ) )
1281 {
1282 int iError = ferror( pFile );
1283 (void) fclose( pFile );
1284 return (iError != 0) ? iError : -1;
1285 }
1286 }
1287
1288 (void) fclose( pFile );
1289
1290 return 0;
1291 }
1292
1293
1294 /*---------------------------------------------------------------------------
1295 * Function: K_WriteFileString
1296 *
1297 * Description:
1298 * Writes the given null-terminated bytes to the given file. The null
1299 * terminator itself is not written to the file.
1300 *
1301 * Input
1302 * -----
1303 * i_sFilename Name of file to which to write
1304 * i_sFileData Bytes to write
1305 *
1306 * Output
1307 * ------
1308 * (none)
1309 *
1310 * Return value 0 on success, errno or -1 (generic error) on failure
1311 *
1312 *--------------------------------------------------------------------------*/
1313
1314 int K_WriteFileString( const char* i_sFilename, const char* i_sFileData )
1315 {
1316 if ( !i_sFilename || (strlen(i_sFilename) <= 0) || !i_sFileData || (strlen(i_sFileData) <= 0) )
1317 {
1318 return -1;
1319 }
1320
1321 return K_WriteFile( i_sFilename, (const unsigned char*)i_sFileData, strlen(i_sFileData) );
1322 }
1323
1324
1325 /*---------------------------------------------------------------------------
1326 * Function: K_FileExists
1327 *
1328 * Description:
1329 * Checks to see whehter the given file exists.
1330 *
1331 * Input
1332 * -----
1333 * i_sFilename Name of file to check
1334 *
1335 * Output
1336 * ------
1337 * (none)
1338 *
1339 * Return value 1 if file exists, 0 if not, -1 on failure
1340 *
1341 *--------------------------------------------------------------------------*/
1342
1343 int K_FileExists( const char* i_sFilename )
1344 {
1345 FILE* pFile = 0;
1346
1347 if ( !i_sFilename || (strlen(i_sFilename) <= 0) )
1348 {
1349 return -1;
1350 }
1351
1352 pFile = fopen( i_sFilename, "r+" );
1353
1354 if ( !pFile )
1355 {
1356 if ( errno == ENOENT )
1357 {
1358 return 0;
1359 }
1360
1361 return -1;
1362 }
1363
1364 (void) fclose( pFile );
1365
1366 return 1;
1367 }
1368
1369
1370 /*---------------------------------------------------------------------------
1371 * Function: K_CopyFile
1372 *
1373 * Description:
1374 * Reads from the given source file and writes these bytes to the given
1375 * destination file.
1376 *
1377 * Input
1378 * -----
1379 * i_sSrcFilename Name of file from which to read
1380 * i_sDestFilename Name of file to which to write
1381 *
1382 * Output
1383 * ------
1384 * o_pbFileExists Non-zero if the destination file already exists
1385 *
1386 * Return value 0 on success, errno or -1 (generic error) on failure
1387 *
1388 *--------------------------------------------------------------------------*/
1389
1390 int K_CopyFile( const char* i_sSrcFilename, const char* i_sDestFilename, int* o_pbFileExists )
1391 {
1392 unsigned char* pFileData = 0;
1393 int iFileSize = 0;
1394 int iError, iFileExists;
1395
1396 if ( !i_sSrcFilename || (strlen(i_sSrcFilename) <= 0)
1397 || !i_sDestFilename || (strlen(i_sDestFilename) <= 0)
1398 || !o_pbFileExists )
1399 {
1400 return -1;
1401 }
1402
1403 *o_pbFileExists = 0;
1404
1405 iFileExists = K_FileExists( i_sDestFilename );
1406
1407 if ( iFileExists < 0 )
1408 {
1409 iError = errno;
1410 return (iError == 0) ? -1 : iError;
1411 }
1412 else if ( iFileExists > 0 )
1413 {
1414 *o_pbFileExists = 1;
1415 return -1;
1416 }
1417
1418 iFileSize = K_ReadFile( i_sSrcFilename, &pFileData );
1419 if ( iFileSize < 0 )
1420 {
1421 iError = errno;
1422 return (iError == 0) ? -1 : iError;
1423 }
1424
1425 iError = K_WriteFile( i_sDestFilename, pFileData, iFileSize );
1426
1427 if ( pFileData )
1428 {
1429 free( pFileData );
1430 }
1431
1432 return iError;
1433 }
1434
1435
1436 #ifdef K_LINUX_PLATFORM
1437 static int fts_compare( const FTSENT** i_ppF1, const FTSENT** i_ppF2 )
1438 {
1439 return strcmp( (*i_ppF1)->fts_name, (*i_ppF2)->fts_name );
1440 }
1441 #else
1442 /*
1443 * Directory traversal code is not yet available for Solaris.
1444 * If such code will need to be written, then it will probably use ftw.h.
1445 */
1446 #endif
1447
1448
1449 /*
1450 * TODO: Set up functions for platform-specific find-file operations to
1451 * help clean up the code below.
1452 */
1453
1454 typedef struct K_FindInfo
1455 {
1456 #ifdef WIN32
1457 struct _finddata_t m_stFindData;
1458 long m_hFile;
1459 #elif defined K_LINUX_PLATFORM
1460 FTS* m_pFTS;
1461 FTSENT* m_pFTSENT;
1462 #else
1463 /*
1464 * Directory traversal code is not yet available for Solaris.
1465 * If such code will need to be written, then it will probably use ftw.h.
1466 */
1467 int unused;
1468 #endif
1469 } K_FindInfo;
1470
1471 // Memory for filename is held in i_pFindInfo.
1472 const char* K_GetFilenameFromInfo( const K_FindInfo* i_pFindInfo )
1473 {
1474 if( !i_pFindInfo )
1475 {
1476 return 0;
1477 }
1478
1479 #ifdef WIN32
1480 return i_pFindInfo->m_stFindData.name;
1481 #elif defined K_LINUX_PLATFORM
1482 return i_pFindInfo->m_pFTSENT->fts_name;
1483 #else
1484 /*
1485 * Directory traversal code is not yet available for Solaris.
1486 * If such code will need to be written, then it will probably use ftw.h.
1487 */
1488 FATAL_ASSERT( 0 );
1489 return 0;
1490 #endif
1491 }
1492
1493 // Forward declarations
1494 int K_FindFileNext( K_FindInfo* io_pFindInfo );
1495 void K_FindFileClose( K_FindInfo* io_pFindInfo );
1496
1497 // Returns 0 if successful, 1 if not found, -1 if error.
1498 // If not error, K_FindFileClose must be called.
1499 // o_pFindInfo must not be null.
1500 int K_FindFileFirst( const char* i_sDirectoryName, K_FindInfo* o_pFindInfo )
1501 {
1502 #ifdef WIN32
1503 char* sSearchString = 0;
1504 int iSearchStringIndex = 0;
1505 #endif
1506
1507 if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) || !o_pFindInfo )
1508 {
1509 return -1;
1510 }
1511
1512 #ifdef WIN32
1513 memset( o_pFindInfo, 0, sizeof(K_FindInfo) );
1514
1515 iSearchStringIndex = strlen(i_sDirectoryName);
1516 if ( i_sDirectoryName[iSearchStringIndex-1] == PATH_SEPARATOR )
1517 {
1518 iSearchStringIndex += 2;
1519 }
1520 else
1521 {
1522 iSearchStringIndex += 3;
1523 }
1524
1525 sSearchString = (char*)calloc( iSearchStringIndex, 1 );
1526 if ( !sSearchString )
1527 {
1528 return -1;
1529 }
1530
1531 strcpy( sSearchString, i_sDirectoryName );
1532 iSearchStringIndex--;
1533 sSearchString[iSearchStringIndex] = '\0';
1534 iSearchStringIndex--;
1535 sSearchString[iSearchStringIndex] = '*';
1536 iSearchStringIndex--;
1537 sSearchString[iSearchStringIndex] = PATH_SEPARATOR;
1538
1539 o_pFindInfo->m_hFile = _findfirst( sSearchString, &o_pFindInfo->m_stFindData );
1540 free( sSearchString );
1541 if ( o_pFindInfo->m_hFile == -1 )
1542 {
1543 if ( errno == ENOENT )
1544 {
1545 return 1;
1546 }
1547 else
1548 {
1549 return -1;
1550 }
1551 }
1552 #elif defined K_LINUX_PLATFORM
1553 memset( o_pFindInfo, 0, sizeof(K_FindInfo) );
1554
1555 o_pFindInfo->m_pFTS = fts_open( aPath, FTS_PHYSICAL | FTS_NOSTAT, fts_compare );
1556 if ( !o_pFindInfo->m_pFTS )
1557 {
1558 return -1;
1559 }
1560
1561 o_pFindInfo->m_pFTSENT = fts_read( o_pFindInfo->m_pFTS );
1562 if ( !o_pFindInfo->m_pFTSENT )
1563 {
1564 if ( errno == 0 )
1565 {
1566 return 1;
1567 }
1568 else
1569 {
1570 fts_close( o_pFindInfo->m_pFTS );
1571 return -1;
1572 }
1573 }
1574 #else
1575 /*
1576 * Directory traversal code is not yet available for Solaris.
1577 * If such code will need to be written, then it will probably use ftw.h.
1578 */
1579 #endif
1580
1581 // If what we found is not actually a file, get the next hit.
1582 #ifdef WIN32
1583 if ( (o_pFindInfo->m_stFindData.attrib & _A_SUBDIR) )
1584 #elif defined K_LINUX_PLATFORM
1585 if ( !(o_pFindInfo->m_pFTSENT->fts_info & FTS_F) )
1586 #else
1587 /*
1588 * Directory traversal code is not yet available for Solaris.
1589 * If such code will need to be written, then it will probably use ftw.h.
1590 */
1591 #endif
1592 {
1593 int iNextReturn = K_FindFileNext( o_pFindInfo );
1594 if ( iNextReturn < 0 )
1595 {
1596 K_FindFileClose( o_pFindInfo );
1597 return -1;
1598 }
1599 else
1600 {
1601 return iNextReturn;
1602 }
1603 }
1604
1605 #if defined(WIN32) || defined(K_LINUX_PLATFORM)
1606 return 0;
1607 #endif
1608 }
1609
1610 // Returns 0 if successful, 1 if not found, -1 if error.
1611 int K_FindFileNext( K_FindInfo* io_pFindInfo )
1612 {
1613 if ( !io_pFindInfo )
1614 {
1615 return -1;
1616 }
1617
1618 #ifdef WIN32
1619 if ( _findnext( io_pFindInfo->m_hFile, &io_pFindInfo->m_stFindData ) != 0 )
1620 {
1621 return (errno == ENOENT) ? 1 : -1;
1622 }
1623 #elif defined K_LINUX_PLATFORM
1624 io_pFindInfo->m_pFTSENT = fts_read( io_pFindInfo->m_pFTS );
1625 if ( !io_pFindInfo->m_pFTSENT )
1626 {
1627 return (errno == 0) ? 1 : -1;
1628 }
1629 #else
1630 /*
1631 * Directory traversal code is not yet available for Solaris.
1632 * If such code will need to be written, then it will probably use ftw.h.
1633 */
1634 #endif
1635
1636 // If what we found is not actually a file, get the next hit.
1637 #ifdef WIN32
1638 if ( (io_pFindInfo->m_stFindData.attrib & _A_SUBDIR) )
1639 #elif defined K_LINUX_PLATFORM
1640 if ( !(io_pFindInfo->m_pFTSENT->fts_info & FTS_F) )
1641 #else
1642 /*
1643 * Directory traversal code is not yet available for Solaris.
1644 * If such code will need to be written, then it will probably use ftw.h.
1645 */
1646 #endif
1647 {
1648 return K_FindFileNext( io_pFindInfo );
1649 }
1650
1651 #if defined(WIN32) || defined(K_LINUX_PLATFORM)
1652 return 0;
1653 #endif
1654 }
1655
1656 void K_FindFileClose( K_FindInfo* io_pFindInfo )
1657 {
1658 if ( !io_pFindInfo )
1659 {
1660 return;
1661 }
1662
1663 #ifdef WIN32
1664 _findclose( io_pFindInfo->m_hFile );
1665 #elif defined K_LINUX_PLATFORM
1666 fts_close( io_pFindInfo->m_pFTS );
1667 #else
1668 /*
1669 * Directory traversal code is not yet available for Solaris.
1670 * If such code will need to be written, then it will probably use ftw.h.
1671 */
1672 #endif
1673 }
1674
1675
1676 /*---------------------------------------------------------------------------
1677 * Function: K_GetFilenamesInDirectoryCount
1678 *
1679 * Description:
1680 * Reads the given directory and returns the number of files that it contains.
1681 *
1682 * Input
1683 * -----
1684 * i_sDirectoryName Name of directory
1685 *
1686 * Output
1687 * ------
1688 * (none)
1689 *
1690 * Return value Number of files on success, -1 on failure
1691 *
1692 *--------------------------------------------------------------------------*/
1693
1694 int K_GetFilenamesInDirectoryCount( const char* i_sDirectoryName )
1695 {
1696 K_FindInfo stFindInfo;
1697 int iCurrentFile = 0;
1698 int iError = 0;
1699
1700 if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) )
1701 {
1702 return -1;
1703 }
1704
1705 iError = K_FindFileFirst( i_sDirectoryName, &stFindInfo );
1706 if ( iError < 0 )
1707 {
1708 // error
1709 return -1;
1710 }
1711 else if ( iError > 0 )
1712 {
1713 // no files found
1714 K_FindFileClose( &stFindInfo );
1715 return 0;
1716 }
1717
1718 while ( 1 )
1719 {
1720 iCurrentFile++;
1721
1722 iError = K_FindFileNext( &stFindInfo );
1723 if ( iError < 0 )
1724 {
1725 // error
1726 K_FindFileClose( &stFindInfo );
1727 return -1;
1728 }
1729 else if ( iError > 0 )
1730 {
1731 // no more files found
1732 break;
1733 }
1734 }
1735
1736 K_FindFileClose( &stFindInfo );
1737
1738 return iCurrentFile;
1739 }
1740
1741
1742 /*---------------------------------------------------------------------------
1743 * Function: K_GetFilenamesInDirectory
1744 *
1745 * Description:
1746 * Reads the given directory and returns an array of names of files that it
1747 * contains. A null pointer appears at the last item in the array. The
1748 * caller must deallocate o_pasFilenames by using K_FreeFilenames or by
1749 * calling free() for each file name and then calling free() on the array
1750 * itself.
1751 *
1752 * Input
1753 * -----
1754 * i_sDirectoryName Name of directory
1755 *
1756 * Output
1757 * ------
1758 * o_pasFilenames Array of names of files found in this directory
1759 *
1760 * Return value Number of files on success, -1 on failure
1761 *
1762 *--------------------------------------------------------------------------*/
1763
1764 int K_GetFilenamesInDirectory(
1765 const char* i_sDirectoryName,
1766 char*** o_pasFilenames )
1767 {
1768 // Note that we iterate through the filenames twice -- once to get the count
1769 // (K_GetFilenamesInDirectoryCount) and then once to get all the names. But
1770 // it may happen that the count changes between these calls. So we'll retrieve
1771 // at most the number of files that's returned in the first pass.
1772
1773 K_FindInfo stFindInfo;
1774 int iFilenameCount = 0, iCurrentFile = 0;
1775 int iError = 0;
1776
1777 if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) || !o_pasFilenames )
1778 {
1779 return -1;
1780 }
1781
1782 *o_pasFilenames = 0;
1783
1784 iFilenameCount = K_GetFilenamesInDirectoryCount( i_sDirectoryName );
1785
1786 if ( iFilenameCount < 0 )
1787 {
1788 return -1;
1789 }
1790
1791 iError = K_FindFileFirst( i_sDirectoryName, &stFindInfo );
1792 if ( iError < 0 )
1793 {
1794 // error
1795 return -1;
1796 }
1797 else if ( iError > 0 )
1798 {
1799 // No files found
1800 K_FindFileClose( &stFindInfo );
1801 return 0;
1802 }
1803
1804 *o_pasFilenames = (char**)calloc( (iFilenameCount+1), sizeof(char*) ); // +1 for the null last one
1805 if ( !*o_pasFilenames )
1806 {
1807 // Out of memory
1808 K_FindFileClose( &stFindInfo );
1809 return -1;
1810 }
1811
1812 while ( 1 )
1813 {
1814 const char* sFilename = K_GetFilenameFromInfo( &stFindInfo );
1815
1816 size_t iFilenameLength = sFilename ? strlen( sFilename ) : 0;
1817
1818 if ( iFilenameLength <= 0 )
1819 {
1820 K_FreeFilenames( *o_pasFilenames );
1821 K_FindFileClose( &stFindInfo );
1822 return -1;
1823 }
1824
1825 (*o_pasFilenames)[iCurrentFile] = (char*)calloc( (iFilenameLength+1), sizeof(char) );
1826 if ( !(*o_pasFilenames)[iCurrentFile] )
1827 {
1828 K_FreeFilenames( *o_pasFilenames );
1829 K_FindFileClose( &stFindInfo );
1830 return -1;
1831 }
1832
1833 strncpy( (*o_pasFilenames)[iCurrentFile], sFilename, iFilenameLength );
1834 (*o_pasFilenames)[iCurrentFile][iFilenameLength] = '\0';
1835
1836 iCurrentFile++;
1837
1838 if ( iCurrentFile >= iFilenameCount )
1839 {
1840 break;
1841 }
1842
1843 iError = K_FindFileNext( &stFindInfo );
1844 if ( iError < 0 )
1845 {
1846 // error
1847 K_FindFileClose( &stFindInfo );
1848 return -1;
1849 }
1850 else if ( iError > 0 )
1851 {
1852 // no more files found
1853 break;
1854 }
1855 }
1856
1857 K_FindFileClose( &stFindInfo );
1858
1859 return iCurrentFile;
1860 }
1861
1862
1863 /*---------------------------------------------------------------------------
1864 * Function: K_FreeFilenames
1865 *
1866 * Description:
1867 * Deallocates the memory allocated in a successful call to
1868 * K_GetFilenamesInDirectory.
1869 *
1870 * Input
1871 * -----
1872 * i_asFilenames Array of names of files
1873 *
1874 * Output
1875 * ------
1876 * (none)
1877 *
1878 * Return value (none)
1879 *
1880 *--------------------------------------------------------------------------*/
1881
1882 void K_FreeFilenames( char** i_asFilenames )
1883 {
1884 int i;
1885
1886 if ( !i_asFilenames )
1887 {
1888 return;
1889 }
1890
1891 for ( i = 0; (i_asFilenames[i] != 0); i++ )
1892 {
1893 free( i_asFilenames[i] );
1894 i_asFilenames[i] = 0;
1895 }
1896
1897 free( i_asFilenames );
1898 }
1899
1900
1901 /*---------------------------------------------------------------------------
1902 * Function: K_AdjustLocalClock
1903 *
1904 * Description:
1905 * The K_AdjustLocalClock function gradually adjusts the system clock by
1906 * the given number of seconds. A positive number adjusts the system
1907 * clock forward; a negative number adjusts the system clock backward.
1908 *
1909 * Input
1910 * -----
1911 * i_iAdjustmentInSeconds Number of seconds by which to adjust the
1912 * system clock
1913 * Output
1914 * ------
1915 * (none)
1916 *
1917 * Return value 1 if successful, 0 on error
1918 *
1919 *--------------------------------------------------------------------------*/
1920
1921 int K_AdjustLocalClock( int i_iNumberOfSeconds )
1922 {
1923 struct timeval delta, lastchange;
1924
1925 #ifndef K_SOLARIS_PLATFORM
1926 /* Only supported/tested on Solaris at the moment */
1927
1928 return -1;
1929 #else
1930 /* WARNING: uses standard C time functions with Year 2038 limitations */
1931 time_t now;
1932
1933 if ( (now = time(NULL)) == ((time_t)-1) )
1934 {
1935 return -1;
1936 }
1937
1938 delta.tv_sec = i_iNumberOfSeconds;
1939 delta.tv_usec = 0;
1940
1941 return adjtime(&delta, &lastchange);
1942 #endif
1943 }
1944
1945
1946 #ifdef K_SOLARIS_PLATFORM
1947 static int pam_tty_conv(
1948 int num_msg,
1949 struct pam_message** mess,
1950 struct pam_response** resp,
1951 void* my_data)
1952 {
1953 // Following code implements a console-based PAM "conversation" function
1954 // (based sample code from Solaris 10 Software Developer Collection >>
1955 // Solaris Security for Developers Guide >>
1956 // 3. Writing PAM Applications and Services)
1957
1958 struct pam_message* m = *mess;
1959 struct pam_response* r;
1960 int i, j;
1961 const char* sPassword = (const char*)my_data;
1962 int error = PAM_CONV_ERR;
1963
1964 if (num_msg <= 0 || num_msg >= PAM_MAX_NUM_MSG)
1965 {
1966 (void) fprintf(stderr, "PAM error: bad number of messages");
1967 *resp = NULL;
1968 return (PAM_CONV_ERR);
1969 }
1970
1971 if ((*resp = r = calloc(num_msg, sizeof (struct pam_response))) == NULL)
1972 {
1973 return (PAM_BUF_ERR);
1974 }
1975
1976 // Loop through messages
1977 for (i = 0; i < num_msg; i++) {
1978
1979 // bad message from service module
1980 if (m->msg == NULL)
1981 {
1982 (void) fprintf(stderr, "PAM error: bad message");
1983 goto err;
1984 }
1985
1986 // fix up final newline: removed for prompts, added back for messages
1987 if (m->msg[strlen(m->msg)] == '\n')
1988 {
1989 m->msg[strlen(m->msg)] = '\0';
1990 }
1991
1992 // Since the KMA has its own password prompts and enforces its own rule checks, we already have the
1993 // new password in memory. So instead of displaying PAM prompts and collecting user responses, we
1994 // "automate" by assuming that the prompts correspond to the standard sequence of "New password:"
1995 // followed by "Confirm password:" and so in each case we immediately return the password we already
1996 // have in memory. This violates the PAM "conversation" function instructions (which say, basically,
1997 // not to assume any particular sequence of prompts since there could be any number of underlying
1998 // password managers), but since the KMA is running on an appliance with a fixed password manager,
1999 // our assumptions should hold.
2000
2001 r->resp = NULL;
2002 r->resp_retcode = 0;
2003 switch (m->msg_style)
2004 {
2005 case PAM_PROMPT_ECHO_OFF:
2006 case PAM_PROMPT_ECHO_ON:
2007 // Assume the prompt asked for New/Confirm password, so return password.
2008 if ( (r->resp = strdup(sPassword)) == NULL )
2009 {
2010 error = PAM_BUF_ERR;
2011 goto err;
2012 }
2013 break;
2014
2015 case PAM_ERROR_MSG:
2016 // Assuming the system is configured properly and the KMA password prompts enforce password strength rules,
2017 // there should not be errors because of weak passwords, etc. Still, print errors so users/support can
2018 // diagnose problems.
2019 (void) fputs(m->msg, stderr);
2020 (void) fputc('\n', stderr);
2021 break;
2022
2023 case PAM_TEXT_INFO:
2024 // Supress prompts (again, making assumptions).
2025 break;
2026
2027 default:
2028 (void) fprintf(stderr, "PAM error: unknown message");
2029 goto err;
2030 }
2031 if (errno == EINTR)
2032 {
2033 goto err;
2034 }
2035
2036 // next message/response
2037 m++;
2038 r++;
2039 }
2040 return (PAM_SUCCESS);
2041
2042 err:
2043 // Service modules do not clean up responses if an error is returned.
2044 // Free responses here.
2045 for (j = 0; j < i; j++, r++)
2046 {
2047 if (r->resp)
2048 {
2049 // clear before freeing -- may be a password
2050 bzero(r->resp, strlen(r->resp));
2051 free(r->resp);
2052 r->resp = NULL;
2053 }
2054 }
2055 free(r);
2056 *resp = NULL;
2057 return error;
2058 }
2059 #endif
2060
2061
2062 /*---------------------------------------------------------------------------
2063 * Function: K_SetRootPassword
2064 *
2065 * Description:
2066 * The K_SetRootPassword function sets the password for the root user via
2067 * Pluggable Authentication Module (PAM). This function is interactive.
2068 *
2069 * Input
2070 * -----
2071 * i_sPassword Password to set
2072 *
2073 * Output
2074 * ------
2075 * (none)
2076 *
2077 * Return value 0 if successful, -1 on error
2078 *
2079 *--------------------------------------------------------------------------*/
2080
2081 int K_SetRootPassword( const char* i_sPassword )
2082 {
2083 // Only supported/tested on Solaris at the moment
2084 #ifndef K_SOLARIS_PLATFORM
2085 return -1;
2086 #else
2087 // Based on sample code from Solaris 10 Software Developer Collection >>
2088 // Solaris Security for Developers Guide >>
2089 // 3. Writing PAM Applications and Services
2090
2091 // TODO: Return PAM error codes (to be logged) instead of emitting
2092 // messages to screen?
2093
2094 struct pam_conv conv;
2095 pam_handle_t *pamh;
2096 int err;
2097
2098 conv.conv = pam_tty_conv;
2099 conv.appdata_ptr = (void*)i_sPassword;
2100
2101 // Initialize PAM framework
2102 err = pam_start("KeyMgr", "root", &conv, &pamh);
2103 if (err != PAM_SUCCESS)
2104 {
2105 fprintf(stderr, "PAM error: %s\n", pam_strerror(pamh, err));
2106 return -1;
2107 }
2108
2109 // Change password
2110 err = pam_chauthtok(pamh, 0);
2111 if (err != PAM_SUCCESS)
2112 {
2113 fprintf(stderr, "PAM error: %s\n", pam_strerror(pamh, err));
2114 // fall through to cleanup
2115 }
2116
2117 // Cleanup session
2118 pam_end(pamh, 0);
2119
2120 return (err == PAM_SUCCESS) ? 0 : -1;
2121 #endif
2122 }
2123
2124
2125 /*---------------------------------------------------------------------------
2126 * Function: K_Alarm
2127 *
2128 * Description:
2129 * Calls alarm(2) on Unix in order to cause the operating system to generate
2130 * a SIGALRM signal for this process after the given number of real-time
2131 * seconds. Does nothing on Windows.
2132 *
2133 * Input
2134 * -----
2135 * i_iSeconds Number of seconds after which to generate a SIGALRM
2136 * signal
2137 *
2138 * Output
2139 * ------
2140 * (none)
2141 *
2142 * Return value If a previous alarm request is pending, then it returns
2143 * the number of seconds until this previous request would
2144 * have generated a SIGALRM signal. Otherwise, returns 0.
2145 *
2146 *--------------------------------------------------------------------------*/
2147
2148 unsigned int K_Alarm( unsigned int i_iSeconds )
2149 {
2150 #ifndef WIN32
2151 return alarm( i_iSeconds );
2152 #else
2153 return 0;
2154 #endif
2155 }
2156
2157
2158 /*---------------------------------------------------------------------------
2159 * Function: K_GetExtendedVersionFromBase
2160 *
2161 * Description:
2162 * This KMS-specific function prepends the timestamp value to the specified
2163 * base replication schema version and returns this value as an extended
2164 * replication schema version.
2165 *
2166 * Input
2167 * -----
2168 * i_iBaseSchemaVersion Base replication schema version
2169 *
2170 * Output
2171 * ------
2172 * (none)
2173 *
2174 * Return value Extended replication schema version
2175 *
2176 *--------------------------------------------------------------------------*/
2177
2178 unsigned int K_GetExtendedVersionFromBase( unsigned int i_iBaseSchemaVersion )
2179 {
2180 // seconds since 1970, force to 32-bit
2181 #ifdef WIN32
2182 INT32 iTimeStamp = (INT32) time(NULL);
2183 #else
2184 int32_t iTimeStamp = (int32_t) time(NULL);
2185 #endif
2186 // minutes since 1970
2187 iTimeStamp = iTimeStamp / 60;
2188 // minutes since 2000 (approximately)
2189 iTimeStamp -= (30*365*24*60);
2190 // shift 8 bits to clear out room for schema version #
2191 iTimeStamp = iTimeStamp << 8;
2192 // add schema version # to lower end
2193 iTimeStamp |= i_iBaseSchemaVersion;
2194
2195 return (unsigned int) iTimeStamp;
2196
2197 }
2198
2199
2200 /*---------------------------------------------------------------------------
2201 * Function: K_ParseTimestampFromExtendedVersion
2202 *
2203 * Description:
2204 * This KMS-specific function parses the timestamp value from the given
2205 * extended replication schema version and returns this timestamp value.
2206 *
2207 * Input
2208 * -----
2209 * i_iExtendedSchemaVersion Extended replication schema version
2210 *
2211 * Output
2212 * ------
2213 * (none)
2214 *
2215 * Return value Timestamp value
2216 *
2217 *--------------------------------------------------------------------------*/
2218
2219 unsigned int K_ParseTimestampFromExtendedVersion(
2220 unsigned int i_iExtendedSchemaVersion )
2221 {
2222 unsigned int iTimeStamp = i_iExtendedSchemaVersion >> 8;
2223
2224 return iTimeStamp;
2225 }
2226
2227
2228 /*---------------------------------------------------------------------------
2229 * Function: K_ParseBaseFromExtendedVersion
2230 *
2231 * Description:
2232 * This KMS-specific function parses the base replication schema value from
2233 * the given extended replication schema version and returns this base value.
2234 *
2235 * Input
2236 * -----
2237 * i_iExtendedSchemaVersion Extended replication schema version
2238 *
2239 * Output
2240 * ------
2241 * (none)
2242 *
2243 * Return value Base replication schema value
2244 *
2245 *--------------------------------------------------------------------------*/
2246
2247 unsigned int K_ParseBaseFromExtendedVersion(
2248 unsigned int i_iExtendedSchemaVersion )
2249 {
2250 unsigned int iBaseSchemaVersion = i_iExtendedSchemaVersion & 0x000000FF;
2251
2252 return iBaseSchemaVersion;
2253 }
2254
2255
2256 /*---------------------------------------------------------------------------
2257 * Function: K_System
2258 *
2259 * Description:
2260 * This function is a thread-safe replacement for the unsafe system(3C) call.
2261 * See the popen(3C) man page for more information.
2262 *
2263 * Input
2264 * -----
2265 * i_sCmd Command to execute
2266 *
2267 * Output
2268 * ------
2269 * (none)
2270 *
2271 * Return value Termination status of the command language interpreter
2272 * if successful, -1 on failure
2273 *
2274 *--------------------------------------------------------------------------*/
2275
2276 int K_System( const char *i_sCmd )
2277 {
2278 #ifndef WIN32
2279 FILE *p;
2280 int rc;
2281 struct sigaction sOldAction;
2282
2283 // Save signal handler
2284 sigaction( SIGCHLD, NULL, &sOldAction );
2285
2286 // Use default child signal handler
2287 sigset( SIGCHLD, SIG_DFL );
2288
2289 p = popen( i_sCmd, "w" );
2290 if ( p == NULL )
2291 {
2292 rc = -1;
2293 }
2294 else
2295 {
2296 rc = pclose( p );
2297 }
2298
2299 // Reset signal handler
2300 sigset( SIGCHLD, sOldAction.sa_handler );
2301
2302 return rc;
2303 #else
2304 return system( i_sCmd );
2305 #endif
2306 }
2307