1 /*
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
13 **   drh@hwaci.com
14 **   http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This file contains code for miscellaneous utility routines.
19 */
20 #include "config.h"
21 #include "util.h"
22 #if defined(USE_MMAN_H)
23 # include <sys/mman.h>
24 # include <unistd.h>
25 #endif
26 #include <math.h>
27 
28 /*
29 ** For the fossil_timer_xxx() family of functions...
30 */
31 #ifdef _WIN32
32 # include <windows.h>
33 #else
34 # include <sys/time.h>
35 # include <sys/resource.h>
36 # include <sys/types.h>
37 # include <sys/stat.h>
38 # include <unistd.h>
39 # include <fcntl.h>
40 # include <errno.h>
41 #endif
42 
43 /*
44 ** Exit.  Take care to close the database first.
45 */
fossil_exit(int rc)46 NORETURN void fossil_exit(int rc){
47   db_close(1);
48 #ifndef _WIN32
49   if( g.fAnyTrace ){
50     fprintf(stderr, "/***** Subprocess %d exit(%d) *****/\n", getpid(), rc);
51     fflush(stderr);
52   }
53 #endif
54   exit(rc);
55 }
56 
57 /*
58 ** Malloc and free routines that cannot fail
59 */
fossil_malloc(size_t n)60 void *fossil_malloc(size_t n){
61   void *p = malloc(n==0 ? 1 : n);
62   if( p==0 ) fossil_fatal("out of memory");
63   return p;
64 }
fossil_malloc_zero(size_t n)65 void *fossil_malloc_zero(size_t n){
66   void *p = malloc(n==0 ? 1 : n);
67   if( p==0 ) fossil_fatal("out of memory");
68   memset(p, 0, n);
69   return p;
70 }
fossil_free(void * p)71 void fossil_free(void *p){
72   free(p);
73 }
fossil_realloc(void * p,size_t n)74 void *fossil_realloc(void *p, size_t n){
75   p = realloc(p, n);
76   if( p==0 ) fossil_fatal("out of memory");
77   return p;
78 }
fossil_secure_zero(void * p,size_t n)79 void fossil_secure_zero(void *p, size_t n){
80   volatile unsigned char *vp = (volatile unsigned char *)p;
81   size_t i;
82 
83   if( p==0 ) return;
84   assert( n>0 );
85   if( n==0 ) return;
86   for(i=0; i<n; i++){ vp[i] ^= 0xFF; }
87   for(i=0; i<n; i++){ vp[i] ^= vp[i]; }
88 }
fossil_get_page_size(size_t * piPageSize)89 void fossil_get_page_size(size_t *piPageSize){
90 #if defined(_WIN32)
91   SYSTEM_INFO sysInfo;
92   memset(&sysInfo, 0, sizeof(SYSTEM_INFO));
93   GetSystemInfo(&sysInfo);
94   *piPageSize = (size_t)sysInfo.dwPageSize;
95 #elif defined(USE_MMAN_H)
96   *piPageSize = (size_t)sysconf(_SC_PAGE_SIZE);
97 #else
98   *piPageSize = 4096; /* FIXME: What for POSIX? */
99 #endif
100 }
fossil_secure_alloc_page(size_t * pN)101 void *fossil_secure_alloc_page(size_t *pN){
102   void *p;
103   size_t pageSize = 0;
104 
105   fossil_get_page_size(&pageSize);
106   assert( pageSize>0 );
107   assert( pageSize%2==0 );
108 #if defined(_WIN32)
109   p = VirtualAlloc(NULL, pageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
110   if( p==NULL ){
111     fossil_fatal("VirtualAlloc failed: %lu\n", GetLastError());
112   }
113   if( !VirtualLock(p, pageSize) ){
114     fossil_fatal("VirtualLock failed: %lu\n", GetLastError());
115   }
116 #elif defined(USE_MMAN_H)
117   p = mmap(0, pageSize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
118   if( p==MAP_FAILED ){
119     fossil_fatal("mmap failed: %d\n", errno);
120   }
121   if( mlock(p, pageSize) ){
122     fossil_fatal("mlock failed: %d\n", errno);
123   }
124 #else
125   p = fossil_malloc(pageSize);
126 #endif
127   fossil_secure_zero(p, pageSize);
128   if( pN ) *pN = pageSize;
129   return p;
130 }
fossil_secure_free_page(void * p,size_t n)131 void fossil_secure_free_page(void *p, size_t n){
132   if( !p ) return;
133   assert( n>0 );
134   fossil_secure_zero(p, n);
135 #if defined(_WIN32)
136   if( !VirtualUnlock(p, n) ){
137     fossil_panic("VirtualUnlock failed: %lu\n", GetLastError());
138   }
139   if( !VirtualFree(p, 0, MEM_RELEASE) ){
140     fossil_panic("VirtualFree failed: %lu\n", GetLastError());
141   }
142 #elif defined(USE_MMAN_H)
143   if( munlock(p, n) ){
144     fossil_panic("munlock failed: %d\n", errno);
145   }
146   if( munmap(p, n) ){
147     fossil_panic("munmap failed: %d\n", errno);
148   }
149 #else
150   fossil_free(p);
151 #endif
152 }
153 
154 /*
155 ** Translate every upper-case character in the input string into
156 ** its equivalent lower-case.
157 */
fossil_strtolwr(char * zIn)158 char *fossil_strtolwr(char *zIn){
159   char *zStart = zIn;
160   if( zIn ){
161     while( *zIn ){
162       *zIn = fossil_tolower(*zIn);
163       zIn++;
164     }
165   }
166   return zStart;
167 }
168 
169 /*
170 ** This local variable determines the behavior of
171 ** fossil_assert_safe_command_string():
172 **
173 **    0 (default)       fossil_panic() on an unsafe command string
174 **
175 **    1                 Print an error but continue process.  Used for
176 **                      testing of fossil_assert_safe_command_string().
177 **
178 **    2                 No-op.  Used to allow any arbitrary command string
179 **                      through fossil_system(), such as when invoking
180 **                      COMMAND in "fossil bisect run COMMAND".
181 */
182 static int safeCmdStrTest = 0;
183 
184 /*
185 ** Check the input string to ensure that it is safe to pass into system().
186 ** A string is unsafe for system() on unix if it contains any of the following:
187 **
188 **   *  Any occurrance of '$' or '`' except single-quoted or after \
189 **   *  Any of the following characters, unquoted:  ;|& or \n except
190 **      these characters are allowed as the very last character in the
191 **      string.
192 **   *  Unbalanced single or double quotes
193 **
194 ** This routine is intended as a second line of defense against attack.
195 ** It should never fail.  Dangerous shell strings should be detected and
196 ** fixed before calling fossil_system().  This routine serves only as a
197 ** safety net in case of bugs elsewhere in the system.
198 **
199 ** If an unsafe string is seen, either abort (default) or print
200 ** a warning message (if safeCmdStrTest is true).
201 */
fossil_assert_safe_command_string(const char * z)202 static void fossil_assert_safe_command_string(const char *z){
203   int unsafe = 0;
204 #ifndef _WIN32
205   /* Unix */
206   int inQuote = 0;
207   int i, c;
208   for(i=0; !unsafe && (c = z[i])!=0; i++){
209     switch( c ){
210       case '$':
211       case '`': {
212         if( inQuote!='\'' ) unsafe = i+1;
213         break;
214       }
215       case ';':
216       case '|':
217       case '&':
218       case '\n': {
219         if( inQuote!='\'' && z[i+1]!=0 ) unsafe = i+1;
220         break;
221       }
222       case '"':
223       case '\'': {
224         if( inQuote==0 ){
225           inQuote = c;
226         }else if( inQuote==c ){
227           inQuote = 0;
228         }
229         break;
230       }
231       case '\\': {
232         if( z[i+1]==0 ){
233           unsafe = i+1;
234         }else if( inQuote!='\'' ){
235           i++;
236         }
237         break;
238       }
239     }
240   }
241   if( inQuote ) unsafe = i;
242 #else
243   /* Windows */
244   int i, c;
245   int inQuote = 0;
246   for(i=0; !unsafe && (c = z[i])!=0; i++){
247     switch( c ){
248       case '>':
249       case '<':
250       case '|':
251       case '&':
252       case '\n': {
253         if( inQuote==0 && z[i+1]!=0 ) unsafe = i+1;
254         break;
255       }
256       case '"': {
257         if( inQuote==c ){
258           inQuote = 0;
259         }else{
260           inQuote = c;
261         }
262         break;
263       }
264       case '^': {
265         if( !inQuote && z[i+1]!=0 ){
266           i++;
267         }
268         break;
269       }
270     }
271   }
272   if( inQuote ) unsafe = i;
273 #endif
274   if( unsafe && safeCmdStrTest<2 ){
275     char *zMsg = mprintf("Unsafe command string: %s\n%*shere ----^",
276                    z, unsafe+13, "");
277     if( safeCmdStrTest ){
278       fossil_print("%z\n", zMsg);
279       fossil_free(zMsg);
280     }else{
281       fossil_panic("%s", zMsg);
282     }
283   }
284 }
285 
286 /*
287 ** This function implements a cross-platform "system()" interface.
288 */
fossil_system(const char * zOrigCmd)289 int fossil_system(const char *zOrigCmd){
290   int rc;
291 #if defined(_WIN32)
292   /* On windows, we have to put double-quotes around the entire command.
293   ** Who knows why - this is just the way windows works.
294   */
295   char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
296   wchar_t *zUnicode = fossil_utf8_to_unicode(zNewCmd);
297   if( g.fSystemTrace ) {
298     fossil_trace("SYSTEM: %s\n", zNewCmd);
299   }
300   fossil_assert_safe_command_string(zOrigCmd);
301   rc = _wsystem(zUnicode);
302   fossil_unicode_free(zUnicode);
303   free(zNewCmd);
304 #else
305   /* On unix, evaluate the command directly.
306   */
307   if( g.fSystemTrace ) fprintf(stderr, "SYSTEM: %s\n", zOrigCmd);
308   fossil_assert_safe_command_string(zOrigCmd);
309 
310   /* Unix systems should never shell-out while processing an HTTP request,
311   ** either via CGI, SCGI, or direct HTTP.  The following assert verifies
312   ** this.  And the following assert proves that Fossil is not vulnerable
313   ** to the ShellShock or BashDoor bug.
314   */
315   assert( g.cgiOutput==0 );
316 
317   /* The regular system() call works to get a shell on unix */
318   fossil_limit_memory(0);
319   rc = system(zOrigCmd);
320   fossil_limit_memory(1);
321 #endif
322   return rc;
323 }
324 
325 /*
326 ** Like "fossil_system()" but does not check the command-string for
327 ** potential security problems.
328 */
fossil_unsafe_system(const char * zOrigCmd)329 int fossil_unsafe_system(const char *zOrigCmd){
330   int rc;
331   safeCmdStrTest = 2;
332   rc = fossil_system(zOrigCmd);
333   safeCmdStrTest = 0;
334   return rc;
335 }
336 
337 /*
338 ** COMMAND: test-fossil-system
339 **
340 ** Read lines of input and send them to fossil_system() for evaluation.
341 ** Use this command to verify that fossil_system() will not run "unsafe"
342 ** commands.
343 */
test_fossil_system_cmd(void)344 void test_fossil_system_cmd(void){
345   char zLine[10000];
346   safeCmdStrTest = 1;
347   while(1){
348     size_t n;
349     int rc;
350     printf("system-test> ");
351     fflush(stdout);
352     if( !fgets(zLine, sizeof(zLine), stdin) ) break;
353     n = strlen(zLine);
354     while( n>0 && fossil_isspace(zLine[n-1]) ) n--;
355     zLine[n] = 0;
356     printf("cmd: [%s]\n", zLine);
357     fflush(stdout);
358     rc = fossil_system(zLine);
359     printf("result: %d\n", rc);
360   }
361 }
362 
363 /*
364 ** Like strcmp() except that it accepts NULL pointers.  NULL sorts before
365 ** all non-NULL string pointers.  Also, this strcmp() is a binary comparison
366 ** that does not consider locale.
367 */
fossil_strcmp(const char * zA,const char * zB)368 int fossil_strcmp(const char *zA, const char *zB){
369   if( zA==0 ){
370     if( zB==0 ) return 0;
371     return -1;
372   }else if( zB==0 ){
373     return +1;
374   }else{
375     return strcmp(zA,zB);
376   }
377 }
fossil_strncmp(const char * zA,const char * zB,int nByte)378 int fossil_strncmp(const char *zA, const char *zB, int nByte){
379   if( zA==0 ){
380     if( zB==0 ) return 0;
381     return -1;
382   }else if( zB==0 ){
383     return +1;
384   }else if( nByte>0 ){
385     int a, b;
386     do{
387       a = *zA++;
388       b = *zB++;
389     }while( a==b && a!=0 && (--nByte)>0 );
390     return ((unsigned char)a) - (unsigned char)b;
391   }else{
392     return 0;
393   }
394 }
395 
396 /*
397 ** Case insensitive string comparison.
398 */
fossil_strnicmp(const char * zA,const char * zB,int nByte)399 int fossil_strnicmp(const char *zA, const char *zB, int nByte){
400   if( zA==0 ){
401     if( zB==0 ) return 0;
402     return -1;
403   }else if( zB==0 ){
404     return +1;
405   }
406   if( nByte<0 ) nByte = strlen(zB);
407   return sqlite3_strnicmp(zA, zB, nByte);
408 }
fossil_stricmp(const char * zA,const char * zB)409 int fossil_stricmp(const char *zA, const char *zB){
410   int nByte;
411   int rc;
412   if( zA==0 ){
413     if( zB==0 ) return 0;
414     return -1;
415   }else if( zB==0 ){
416     return +1;
417   }
418   nByte = strlen(zB);
419   rc = sqlite3_strnicmp(zA, zB, nByte);
420   if( rc==0 && zA[nByte] ) rc = 1;
421   return rc;
422 }
423 
424 /*
425 ** Get user and kernel times in microseconds.
426 */
fossil_cpu_times(sqlite3_uint64 * piUser,sqlite3_uint64 * piKernel)427 void fossil_cpu_times(sqlite3_uint64 *piUser, sqlite3_uint64 *piKernel){
428 #ifdef _WIN32
429   FILETIME not_used;
430   FILETIME kernel_time;
431   FILETIME user_time;
432   GetProcessTimes(GetCurrentProcess(), &not_used, &not_used,
433                   &kernel_time, &user_time);
434   if( piUser ){
435      *piUser = ((((sqlite3_uint64)user_time.dwHighDateTime)<<32) +
436                          (sqlite3_uint64)user_time.dwLowDateTime + 5)/10;
437   }
438   if( piKernel ){
439      *piKernel = ((((sqlite3_uint64)kernel_time.dwHighDateTime)<<32) +
440                          (sqlite3_uint64)kernel_time.dwLowDateTime + 5)/10;
441   }
442 #else
443   struct rusage s;
444   getrusage(RUSAGE_SELF, &s);
445   if( piUser ){
446     *piUser = ((sqlite3_uint64)s.ru_utime.tv_sec)*1000000 + s.ru_utime.tv_usec;
447   }
448   if( piKernel ){
449     *piKernel =
450               ((sqlite3_uint64)s.ru_stime.tv_sec)*1000000 + s.ru_stime.tv_usec;
451   }
452 #endif
453 }
454 
455 /*
456 ** Return the resident set size for this process
457 */
fossil_rss(void)458 sqlite3_uint64 fossil_rss(void){
459 #ifdef _WIN32
460   return 0;
461 #else
462   struct rusage s;
463   getrusage(RUSAGE_SELF, &s);
464   return s.ru_maxrss*1024;
465 #endif
466 }
467 
468 
469 /*
470 ** Internal helper type for fossil_timer_xxx().
471  */
472 enum FossilTimerEnum {
473   FOSSIL_TIMER_COUNT = 10 /* Number of timers we can track. */
474 };
475 static struct FossilTimer {
476   sqlite3_uint64 u; /* "User" CPU times */
477   sqlite3_uint64 s; /* "System" CPU times */
478   int id; /* positive if allocated, else 0. */
479 } fossilTimerList[FOSSIL_TIMER_COUNT] = {{0,0,0}};
480 
481 /*
482 ** Stores the current CPU times into the shared timer list
483 ** and returns that timer's internal ID. Pass that ID to
484 ** fossil_timer_fetch() to get the elapsed time for that
485 ** timer.
486 **
487 ** The system has a fixed number of timers, and they can be
488 ** "deallocated" by passing this function's return value to
489 ** fossil_timer_stop() Adjust FOSSIL_TIMER_COUNT to set the number of
490 ** available timers.
491 **
492 ** Returns 0 on error (no more timers available), with 1+ being valid
493 ** timer IDs.
494 */
fossil_timer_start()495 int fossil_timer_start(){
496   int i;
497   for( i = 0; i < FOSSIL_TIMER_COUNT; ++i ){
498     struct FossilTimer * ft = &fossilTimerList[i];
499     if(ft->id) continue;
500     ft->id = i+1;
501     fossil_cpu_times( &ft->u, &ft->s );
502     break;
503   }
504   return (i<FOSSIL_TIMER_COUNT) ? i+1 : 0;
505 }
506 
507 /*
508 ** Returns the difference in CPU times in microseconds since
509 ** fossil_timer_start() was called and returned the given timer ID (or
510 ** since it was last reset). Returns 0 if timerId is out of range.
511 */
fossil_timer_fetch(int timerId)512 sqlite3_uint64 fossil_timer_fetch(int timerId){
513   if( timerId>0 && timerId<=FOSSIL_TIMER_COUNT ){
514     struct FossilTimer * start = &fossilTimerList[timerId-1];
515     if( !start->id ){
516       fossil_panic("Invalid call to fetch a non-allocated "
517                    "timer (#%d)", timerId);
518       /*NOTREACHED*/
519     }else{
520       sqlite3_uint64 eu = 0, es = 0;
521       fossil_cpu_times( &eu, &es );
522       return (eu - start->u) + (es - start->s);
523     }
524   }
525   return 0;
526 }
527 
528 /*
529 ** Resets the timer associated with the given ID, as obtained via
530 ** fossil_timer_start(), to the current CPU time values.
531 */
fossil_timer_reset(int timerId)532 sqlite3_uint64 fossil_timer_reset(int timerId){
533   if( timerId>0 && timerId<=FOSSIL_TIMER_COUNT ){
534     struct FossilTimer * start = &fossilTimerList[timerId-1];
535     if( !start->id ){
536       fossil_panic("Invalid call to reset a non-allocated "
537                    "timer (#%d)", timerId);
538       /*NOTREACHED*/
539     }else{
540       sqlite3_uint64 const rc = fossil_timer_fetch(timerId);
541       fossil_cpu_times( &start->u, &start->s );
542       return rc;
543     }
544   }
545   return 0;
546 }
547 
548 /**
549    "Deallocates" the fossil timer identified by the given timer ID.
550    returns the difference (in uSec) between the last time that timer
551    was started or reset. Returns 0 if timerId is out of range (but
552    note that, due to system-level precision restrictions, this
553    function might return 0 on success, too!). It is not legal to
554    re-use the passed-in timerId after calling this until/unless it is
555    re-initialized using fossil_timer_start() (NOT
556    fossil_timer_reset()).
557 */
fossil_timer_stop(int timerId)558 sqlite3_uint64 fossil_timer_stop(int timerId){
559   if(timerId<1 || timerId>FOSSIL_TIMER_COUNT){
560     return 0;
561   }else{
562     sqlite3_uint64 const rc = fossil_timer_fetch(timerId);
563     struct FossilTimer * t = &fossilTimerList[timerId-1];
564     t->id = 0;
565     t->u = t->s = 0U;
566     return rc;
567   }
568 }
569 
570 /*
571 ** Returns true (non-0) if the given timer ID (as returned from
572 ** fossil_timer_start() is currently active.
573 */
fossil_timer_is_active(int timerId)574 int fossil_timer_is_active( int timerId ){
575   if(timerId<1 || timerId>FOSSIL_TIMER_COUNT){
576     return 0;
577   }else{
578     const int rc = fossilTimerList[timerId-1].id;
579     assert(!rc || (rc == timerId));
580     return fossilTimerList[timerId-1].id;
581   }
582 }
583 
584 /*
585 ** Return TRUE if fd is a valid open file descriptor.  This only
586 ** works on unix.  The function always returns true on Windows.
587 */
is_valid_fd(int fd)588 int is_valid_fd(int fd){
589 #ifdef _WIN32
590   return 1;
591 #else
592   return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
593 #endif
594 }
595 
596 /*
597 ** Returns TRUE if zSym is exactly HNAME_LEN_SHA1 or HNAME_LEN_K256
598 ** bytes long and contains only lower-case ASCII hexadecimal values.
599 */
fossil_is_artifact_hash(const char * zSym)600 int fossil_is_artifact_hash(const char *zSym){
601   int sz = zSym ? (int)strlen(zSym) : 0;
602   return (HNAME_LEN_SHA1==sz || HNAME_LEN_K256==sz) && validate16(zSym, sz);
603 }
604 
605 /*
606 ** Return true if the input string is NULL or all whitespace.
607 ** Return false if the input string contains text.
608 */
fossil_all_whitespace(const char * z)609 int fossil_all_whitespace(const char *z){
610   if( z==0 ) return 1;
611   while( fossil_isspace(z[0]) ){ z++; }
612   return z[0]==0;
613 }
614 
615 /*
616 ** Return the name of the users preferred text editor.  Return NULL if
617 ** not found.
618 **
619 ** Search algorithm:
620 ** (1) The local "editor" setting
621 ** (2) The global "editor" setting
622 ** (3) The VISUAL environment variable
623 ** (4) The EDITOR environment variable
624 ** (5) (Windows only:) "notepad.exe"
625 */
fossil_text_editor(void)626 const char *fossil_text_editor(void){
627   const char *zEditor = db_get("editor", 0);
628   if( zEditor==0 ){
629     zEditor = fossil_getenv("VISUAL");
630   }
631   if( zEditor==0 ){
632     zEditor = fossil_getenv("EDITOR");
633   }
634 #if defined(_WIN32) || defined(__CYGWIN__)
635   if( zEditor==0 ){
636     zEditor = mprintf("%s\\notepad.exe", fossil_getenv("SYSTEMROOT"));
637 #if defined(__CYGWIN__)
638     zEditor = fossil_utf8_to_path(zEditor, 0);
639 #endif
640   }
641 #endif
642   return zEditor;
643 }
644 
645 /*
646 ** Construct a temporary filename.
647 **
648 ** The returned string is obtained from sqlite3_malloc() and must be
649 ** freed by the caller.
650 */
fossil_temp_filename(void)651 char *fossil_temp_filename(void){
652   char *zTFile = 0;
653   const char *zDir;
654   char cDirSep;
655   char zSep[2];
656   size_t nDir;
657   u64 r[2];
658 #ifdef _WIN32
659   char *zTempDirA = NULL;
660   WCHAR zTempDirW[MAX_PATH+1];
661   const DWORD dwTempSizeW = sizeof(zTempDirW)/sizeof(zTempDirW[0]);
662   DWORD dwTempLenW;
663 #else
664   int i;
665   static const char *azTmp[] = {"/var/tmp","/usr/tmp","/tmp"};
666 #endif
667   if( g.db ){
668     sqlite3_file_control(g.db, 0, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTFile);
669     if( zTFile ) return zTFile;
670   }
671   sqlite3_randomness(sizeof(r), &r);
672 #if _WIN32
673   cDirSep = '\\';
674   dwTempLenW = GetTempPathW(dwTempSizeW, zTempDirW);
675   if( dwTempLenW>0 && dwTempLenW<dwTempSizeW
676       && ( zTempDirA = fossil_path_to_utf8(zTempDirW) )){
677     zDir = zTempDirA;
678   }else{
679     zDir = fossil_getenv("LOCALAPPDATA");
680     if( zDir==0 ) zDir = ".";
681   }
682 #else
683   for(i=0; i<sizeof(azTmp)/sizeof(azTmp[0]); i++){
684     struct stat buf;
685     zDir = azTmp[i];
686     if( stat(zDir,&buf)==0 && S_ISDIR(buf.st_mode) && access(zDir,03)==0 ){
687       break;
688     }
689   }
690   if( i>=sizeof(azTmp)/sizeof(azTmp[0]) ) zDir = ".";
691   cDirSep = '/';
692 #endif
693   nDir = strlen(zDir);
694   zSep[1] = 0;
695   zSep[0] = (nDir && zDir[nDir-1]==cDirSep) ? 0 : cDirSep;
696   zTFile = sqlite3_mprintf("%s%sfossil%016llx%016llx", zDir,zSep,r[0],r[1]);
697 #ifdef _WIN32
698   if( zTempDirA ) fossil_path_free(zTempDirA);
699 #endif
700   return zTFile;
701 }
702 
703 /*
704 ** Turn memory limits for stack and heap on and off.  The argument
705 ** is true to turn memory limits on and false to turn them off.
706 **
707 ** Memory limits should be enabled at startup, but then turned off
708 ** before starting subprocesses.
709 */
fossil_limit_memory(int onOff)710 void fossil_limit_memory(int onOff){
711 #if defined(__unix__)
712   static sqlite3_int64 origHeap = 10000000000LL;  /* 10GB */
713   static sqlite3_int64 origStack =    8000000  ;  /*  8MB */
714   struct rlimit x;
715 
716 #if defined(RLIMIT_DATA)
717   getrlimit(RLIMIT_DATA, &x);
718   if( onOff ){
719     origHeap = x.rlim_cur;
720     if( sizeof(void*)<8 || sizeof(x.rlim_cur)<8 ){
721       x.rlim_cur =  1000000000  ;  /* 1GB on 32-bit systems */
722     }else{
723       x.rlim_cur = 10000000000LL;  /* 10GB on 64-bit systems */
724     }
725   }else{
726     x.rlim_cur = origHeap;
727   }
728   setrlimit(RLIMIT_DATA, &x);
729 #endif /* defined(RLIMIT_DATA) */
730 #if defined(RLIMIT_STACK)
731   getrlimit(RLIMIT_STACK, &x);
732   if( onOff ){
733     origStack = x.rlim_cur;
734     x.rlim_cur =  8000000;  /* 8MB */
735   }else{
736     x.rlim_cur = origStack;
737   }
738   setrlimit(RLIMIT_STACK, &x);
739 #endif /* defined(RLIMIT_STACK) */
740 #endif /* defined(__unix__) */
741 }
742 
743 #if defined(HAVE_PLEDGE)
744 /*
745 ** Interface to pledge() on OpenBSD 5.9 and later.
746 **
747 ** On platforms that have pledge(), use this routine.
748 ** On all other platforms, this routine does not exist, but instead
749 ** a macro defined in config.h is used to provide a no-op.
750 */
fossil_pledge(const char * promises)751 void fossil_pledge(const char *promises){
752   if( pledge(promises, 0) ){
753     fossil_panic("pledge(\"%s\",NULL) fails with errno=%d",
754       promises, (int)errno);
755   }
756 }
757 #endif /* defined(HAVE_PLEDGE) */
758 
759 /*
760 ** Construct a random password and return it as a string.  N is the
761 ** recommended number of characters for the password.
762 **
763 ** Space to hold the returned string is obtained from fossil_malloc()
764 ** and should be freed by the caller.
765 */
fossil_random_password(int N)766 char *fossil_random_password(int N){
767   char zSrc[60];
768   int nSrc;
769   int i;
770   char z[60];
771 
772   /* Source characters for the password.  Omit characters like "0", "O",
773   ** "1" and "I"  that might be easily confused */
774   static const char zAlphabet[] =
775            /*  0         1         2         3         4         5       */
776            /*   123456789 123456789 123456789 123456789 123456789 123456 */
777               "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
778 
779   if( N<8 ) N = 8;
780   nSrc = sizeof(zAlphabet) - 1;
781   if( N>nSrc ) N = nSrc;
782   memcpy(zSrc, zAlphabet, nSrc);
783 
784   for(i=0; i<N; i++){
785     unsigned r;
786     sqlite3_randomness(sizeof(r), &r);
787     r %= nSrc;
788     z[i] = zSrc[r];
789     zSrc[r] = zSrc[--nSrc];
790   }
791   z[i] = 0;
792   return fossil_strdup(z);
793 }
794 
795 /*
796 ** COMMAND: test-random-password
797 **
798 ** Usage: %fossil test-random-password [N] [--entropy]
799 **
800 ** Generate a random password string of approximately N characters in length.
801 ** If N is omitted, use 12.  Values of N less than 8 are changed to 8
802 ** and greater than 57 and changed to 57.
803 **
804 ** If the --entropy flag is included, the number of bits of entropy in
805 ** the password is show as well.
806 */
test_random_password(void)807 void test_random_password(void){
808   int N = 12;
809   int showEntropy = 0;
810   int i;
811   char *zPassword;
812   for(i=2; i<g.argc; i++){
813     const char *z = g.argv[i];
814     if( z[0]=='-' && z[1]=='-' ) z++;
815     if( strcmp(z,"-entropy")==0 ){
816       showEntropy = 1;
817     }else if( fossil_isdigit(z[0]) ){
818       N = atoi(z);
819       if( N<8 ) N = 8;
820       if( N>57 ) N = 57;
821     }else{
822       usage("[N] [--entropy]");
823     }
824   }
825   zPassword = fossil_random_password(N);
826   if( showEntropy ){
827     double et = 57.0;
828     for(i=1; i<N; i++) et *= 57-i;
829     fossil_print("%s (%d bits of entropy)\n", zPassword,
830                  (int)(log(et)/log(2.0)));
831   }else{
832     fossil_print("%s\n", zPassword);
833   }
834   fossil_free(zPassword);
835 }
836 
837 /*
838 ** Return the number of decimal digits in a nonnegative integer.  This is useful
839 ** when formatting text.
840 */
fossil_num_digits(int n)841 int fossil_num_digits(int n){
842   return n<      10 ? 1 : n<      100 ? 2 : n<      1000 ? 3
843        : n<   10000 ? 4 : n<   100000 ? 5 : n<   1000000 ? 6
844        : n<10000000 ? 7 : n<100000000 ? 8 : n<1000000000 ? 9 : 10;
845 }
846 
847 #if !defined(_WIN32)
848 #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
849 /*
850 ** Search for an executable on the PATH environment variable.
851 ** Return true (1) if found and false (0) if not found.
852 */
binaryOnPath(const char * zBinary)853 static int binaryOnPath(const char *zBinary){
854   const char *zPath = fossil_getenv("PATH");
855   char *zFull;
856   int i;
857   int bExists;
858   while( zPath && zPath[0] ){
859     while( zPath[0]==':' ) zPath++;
860     for(i=0; zPath[i] && zPath[i]!=':'; i++){}
861     zFull = mprintf("%.*s/%s", i, zPath, zBinary);
862     bExists = file_access(zFull, X_OK);
863     fossil_free(zFull);
864     if( bExists==0 ) return 1;
865     zPath += i;
866   }
867   return 0;
868 }
869 #endif
870 #endif
871 
872 
873 /*
874 ** Return the name of a command that will launch a web-browser.
875 */
fossil_web_browser(void)876 const char *fossil_web_browser(void){
877   const char *zBrowser = 0;
878 #if defined(_WIN32)
879   zBrowser = db_get("web-browser", "start \"\"");
880 #elif defined(__DARWIN__) || defined(__APPLE__) || defined(__HAIKU__)
881   zBrowser = db_get("web-browser", "open");
882 #else
883   zBrowser = db_get("web-browser", 0);
884   if( zBrowser==0 ){
885     static const char *const azBrowserProg[] =
886         { "xdg-open", "gnome-open", "firefox", "google-chrome" };
887     int i;
888     zBrowser = "echo";
889     for(i=0; i<count(azBrowserProg); i++){
890       if( binaryOnPath(azBrowserProg[i]) ){
891         zBrowser = azBrowserProg[i];
892         break;
893       }
894     }
895   }
896 #endif
897   return zBrowser;
898 }
899