Forgot to commit this:
[gnupg.git] / util / secmem.c
index 8796e6f..c808dfe 100644 (file)
@@ -1,5 +1,5 @@
 /* secmem.c  - memory allocation from a secure heap
- *     Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -32,6 +32,9 @@
   #ifdef USE_CAPABILITIES
     #include <sys/capability.h>
   #endif
+  #ifdef HAVE_PLOCK
+    #include <sys/lock.h>
+  #endif
 #endif
 
 #include "types.h"
 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
   #define MAP_ANONYMOUS MAP_ANON
 #endif
+/* It seems that Slackware 7.1 does not know about EPERM */
+#if !defined(EPERM) && defined(ENOMEM)
+  #define EPERM  ENOMEM
+#endif
+
 
 #define DEFAULT_POOLSIZE 16384
 
@@ -58,7 +66,7 @@ struct memblock_struct {
 
 static void  *pool;
 static volatile int pool_okay; /* may be checked in an atexit function */
-static int   pool_is_mmapped;
+static volatile int pool_is_mmapped;
 static size_t poolsize; /* allocated length */
 static size_t poollen; /* used length */
 static MEMBLOCK *unused_blocks;
@@ -75,8 +83,12 @@ static int suspend_warning;
 static void
 print_warn(void)
 {
-    if( !no_warning )
-       log_info(_("Warning: using insecure memory!\n"));
+  if (!no_warning)
+    {
+      log_info(_("Warning: using insecure memory!\n"));
+      log_info(_("please see http://www.gnupg.org/faq.html "
+                "for more information\n"));
+    }
 }
 
 
@@ -97,8 +109,14 @@ lock_pool( void *p, size_t n )
          #ifdef EAGAIN  /* OpenBSD returns this */
            && errno != EAGAIN
          #endif
+         #ifdef ENOSYS  /* Some SCOs return this (function not implemented) */
+           && errno != ENOSYS
+         #endif
+          #ifdef ENOMEM  /* Linux can return this */
+            && errno != ENOMEM
+          #endif
          )
-           log_error("can´t lock memory: %s\n", strerror(err));
+           log_error("can't lock memory: %s\n", strerror(err));
        show_warning = 1;
     }
 
@@ -109,6 +127,13 @@ lock_pool( void *p, size_t n )
     uid = getuid();
 
   #ifdef HAVE_BROKEN_MLOCK
+    /* ick. but at least we get secured memory. about to lock
+       entire data segment. */
+  #ifdef HAVE_PLOCK
+    err = plock( DATLOCK );
+    if( err && errno )
+        err = errno;
+#else /*!HAVE_PLOCK*/
     if( uid ) {
        errno = EPERM;
        err = errno;
@@ -118,6 +143,7 @@ lock_pool( void *p, size_t n )
        if( err && errno )
            err = errno;
     }
+  #endif /*!HAVE_PLOCK*/
   #else
     err = mlock( p, n );
     if( err && errno )
@@ -125,7 +151,9 @@ lock_pool( void *p, size_t n )
   #endif
 
     if( uid && !geteuid() ) {
-       if( setuid( uid ) || getuid() != geteuid()  )
+       /* check that we really dropped the privs.
+        * Note: setuid(0) should always fail */
+       if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
            log_fatal("failed to reset uid: %s\n", strerror(errno));
     }
 
@@ -134,11 +162,32 @@ lock_pool( void *p, size_t n )
          #ifdef EAGAIN  /* OpenBSD returns this */
            && errno != EAGAIN
          #endif
+         #ifdef ENOSYS  /* Some SCOs return this (function not implemented) */
+           && errno != ENOSYS
+         #endif
+          #ifdef ENOMEM  /* Linux can return this */
+            && errno != ENOMEM
+          #endif
          )
-           log_error("can´t lock memory: %s\n", strerror(err));
+           log_error("can't lock memory: %s\n", strerror(err));
        show_warning = 1;
     }
 
+  #elif defined ( __QNX__ )
+    /* QNX does not page at all, so the whole secure memory stuff does
+     * not make much sense.  However it is still of use because it
+     * wipes out the memory on a free().
+     * Therefore it is sufficient to suppress the warning
+     */
+  #elif defined (HAVE_DOSISH_SYSTEM)
+    /* It does not make sense to print such a warning, given the fact that 
+     * this whole Windows !@#$% and their user base are inherently insecure
+     */
+  #elif defined (__riscos__)
+    /* no virtual memory on RISC OS, so no pages are swapped to disc,
+     * besides we don't have mmap, so we don't use it! ;-)
+     * But don't complain, as explained above.
+     */
   #else
     log_info("Please note that you don't have secure memory on this system\n");
   #endif
@@ -238,6 +287,7 @@ void
 secmem_init( size_t n )
 {
     if( !n ) {
+#ifndef __riscos__
       #ifdef USE_CAPABILITIES
        /* drop all capabilities */
        cap_set_proc( cap_from_text("all-eip") );
@@ -248,10 +298,11 @@ secmem_init( size_t n )
        disable_secmem=1;
        uid = getuid();
        if( uid != geteuid() ) {
-           if( setuid( uid ) || getuid() != geteuid() )
+           if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
                log_fatal("failed to drop setuid\n" );
        }
       #endif
+#endif /* !__riscos__ */
     }
     else {
        if( n < DEFAULT_POOLSIZE )
@@ -333,9 +384,11 @@ secmem_realloc( void *p, size_t newsize )
     if( newsize < size )
        return p; /* it is easier not to shrink the memory */
     a = secmem_malloc( newsize );
-    memcpy(a, p, size);
-    memset((char*)a+size, 0, newsize-size);
-    secmem_free(p);
+    if ( a ) {
+        memcpy(a, p, size);
+        memset((char*)a+size, 0, newsize-size);
+        secmem_free(p);
+    }
     return a;
 }
 
@@ -370,6 +423,16 @@ m_is_secure( const void *p )
     return p >= pool && p < (void*)((char*)pool+poolsize);
 }
 
+
+
+/****************
+ * Warning:  This code might be called by an interrupt handler
+ *          and frankly, there should really be such a handler,
+ *          to make sure that the memory is wiped out.
+ *          We hope that the OS wipes out mlocked memory after
+ *          receiving a SIGKILL - it really should do so, otherwise
+ *          there is no chance to get the secure memory cleaned.
+ */
 void
 secmem_term()
 {