aboutsummaryrefslogtreecommitdiffstats
path: root/g10/g10.c
diff options
context:
space:
mode:
authorDavid Shaw <[email protected]>2002-08-07 15:53:15 +0000
committerDavid Shaw <[email protected]>2002-08-07 15:53:15 +0000
commitfee7e35baefb742d504c979b3cf0aeaeb5a87b60 (patch)
tree23112bb915861942dacce217c2474486d76be48d /g10/g10.c
parent* configure.ac: If the static IDEA cipher is present, disable dynamic (diff)
downloadgnupg-fee7e35baefb742d504c979b3cf0aeaeb5a87b60.tar.gz
gnupg-fee7e35baefb742d504c979b3cf0aeaeb5a87b60.zip
* keyedit.c (menu_revsig): Properly show a uid is revoked without
restarting gpg. This is Debian bug 124219, though their supplied patch will not do the right thing. * main.h, tdbio.c (tdbio_set_dbname), misc.c (removed check_permissions), keydb.c (keydb_add_resource), g10.c (main, check_permissions): Significant reworking of the permission check mechanism. The new behavior is to check everything in the homedir by checking the homedir itself. If the user wants to put (possibly shared) keyrings outside the homedir, they are not checked. The options file and any extension files are checked wherever they are, as well as their enclosing directories. This is Debian bug 147760.
Diffstat (limited to 'g10/g10.c')
-rw-r--r--g10/g10.c224
1 files changed, 192 insertions, 32 deletions
diff --git a/g10/g10.c b/g10/g10.c
index 8dcf6b40f..545c5b8a2 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -28,6 +28,9 @@
#ifdef HAVE_DOSISH_SYSTEM
#include <fcntl.h> /* for setmode() */
#endif
+#ifdef HAVE_STAT
+#include <sys/stat.h> /* for stat() */
+#endif
#define INCLUDED_BY_MAIN_MODULE 1
#include "packet.h"
@@ -832,6 +835,180 @@ static void add_group(char *string)
opt.grouplist=item;
}
+/* We need to check three things.
+
+ 0) The homedir. It must be x00, a directory, and owned by the
+ user.
+
+ 1) The options file. Okay unless it or its containing directory is
+ group or other writable or not owned by us. disable exec in this
+ case.
+
+ 2) Extensions. Same as #2.
+
+ Returns true if the item is unsafe. */
+static int
+check_permissions(const char *path,int item)
+{
+#if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
+ static int homedir_cache=-1;
+ char *tmppath,*isa,*dir;
+ struct stat statbuf,dirbuf;
+ int homedir=0,ret=0,checkonly=0;
+ int perm=0,own=0,enc_dir_perm=0,enc_dir_own=0;
+
+ if(opt.no_perm_warn)
+ return 0;
+
+ /* extensions may attach a path */
+ if(item==2 && path[0]!=DIRSEP_C)
+ {
+ if(strchr(path,DIRSEP_C))
+ tmppath=make_filename(path,NULL);
+ else
+ tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
+ }
+ else
+ tmppath=m_strdup(path);
+
+ /* If the item is located in the homedir, but isn't the homedir,
+ don't continue if we already checked the homedir itself. This is
+ to avoid user confusion with an extra options file warning which
+ could be rectified if the homedir itself had proper
+ permissions. */
+ if(item!=0 && homedir_cache>-1 &&
+ ascii_memcasecmp(opt.homedir,tmppath,strlen(opt.homedir))==0)
+ {
+ ret=homedir_cache;
+ goto end;
+ }
+
+ /* It's okay if the file or directory doesn't exist */
+ if(stat(tmppath,&statbuf)!=0)
+ {
+ ret=0;
+ goto end;
+ }
+
+ /* Now check the enclosing directory. Theoretically, we could walk
+ this test up to the root directory /, but for the sake of sanity,
+ I'm stopping at one level down. */
+ dir=make_dirname(tmppath);
+
+ if(stat(dir,&dirbuf)!=0 || !S_ISDIR(dirbuf.st_mode))
+ {
+ /* Weird error */
+ ret=1;
+ goto end;
+ }
+
+ m_free(dir);
+
+ /* Assume failure */
+ ret=1;
+
+ if(item==0)
+ {
+ isa="homedir";
+
+ /* The homedir must be x00, a directory, and owned by the user. */
+
+ if(S_ISDIR(statbuf.st_mode))
+ {
+ if(statbuf.st_uid==getuid())
+ {
+ if((statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
+ ret=0;
+ else
+ perm=1;
+ }
+ else
+ own=1;
+
+ homedir_cache=ret;
+ }
+ }
+ else if(item==1 || item==2)
+ {
+ if(item==1)
+ isa="configuration file";
+ else
+ isa="extension";
+
+ /* The options or extension file. Okay unless it or its
+ containing directory is group or other writable or not owned
+ by us or root. */
+
+ if(S_ISREG(statbuf.st_mode))
+ {
+ if(statbuf.st_uid==getuid() || statbuf.st_uid==0)
+ {
+ if((statbuf.st_mode & (S_IWGRP|S_IWOTH))==0)
+ {
+ /* it's not writable, so make sure the enclosing
+ directory is also not writable */
+ if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0)
+ {
+ if((dirbuf.st_mode & (S_IWGRP|S_IWOTH))==0)
+ ret=0;
+ else
+ enc_dir_perm=1;
+ }
+ else
+ enc_dir_own=1;
+ }
+ else
+ {
+ /* it's writable, so the enclosing directory had
+ better not let people get to it. */
+ if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0)
+ {
+ if((dirbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
+ ret=0;
+ else
+ perm=enc_dir_perm=1; /* unclear which one to fix! */
+ }
+ else
+ enc_dir_own=1;
+ }
+ }
+ else
+ own=1;
+ }
+ }
+ else
+ BUG();
+
+ if(!checkonly)
+ {
+ if(own)
+ log_info(_("WARNING: unsafe ownership on %s \"%s\"\n"),
+ isa,tmppath);
+ if(perm)
+ log_info(_("WARNING: unsafe permissions on %s \"%s\"\n"),
+ isa,tmppath);
+ if(enc_dir_own)
+ log_info(_("WARNING: unsafe enclosing directory "
+ "ownership on %s \"%s\"\n"),
+ isa,tmppath);
+ if(enc_dir_perm)
+ log_info(_("WARNING: unsafe enclosing directory "
+ "permissions on %s \"%s\"\n"),
+ isa,tmppath);
+ }
+
+ end:
+ m_free(tmppath);
+
+ if(homedir)
+ homedir_cache=ret;
+
+ return ret;
+
+#endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
+
+ return 0;
+}
int
main( int argc, char **argv )
@@ -843,8 +1020,6 @@ main( int argc, char **argv )
char **orig_argv;
const char *fname;
char *username;
- STRLIST unsafe_files=NULL;
- STRLIST extensions=NULL;
int may_coredump;
STRLIST sl, remusr= NULL, locusr=NULL;
STRLIST nrings=NULL, sec_nrings=NULL;
@@ -945,6 +1120,8 @@ main( int argc, char **argv )
default_config = 0; /* --no-options */
else if( pargs.r_opt == oHomedir )
opt.homedir = pargs.r.ret_str;
+ else if( pargs.r_opt == oNoPermissionWarn )
+ opt.no_perm_warn=1;
#ifdef USE_SHM_COPROCESSING
else if( pargs.r_opt == oRunAsShmCP ) {
/* does not make sense in a options file, we do it here,
@@ -1001,13 +1178,14 @@ main( int argc, char **argv )
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
+
+ /* By this point we have a homedir, and cannot change it. */
+ check_permissions(opt.homedir,0);
+
next_pass:
if( configname ) {
-
- if(check_permissions(configname,0,1))
+ if(check_permissions(configname,1))
{
- add_to_strlist(&unsafe_files,configname);
-
/* If any options file is unsafe, then disable any external
programs for keyserver calls or photo IDs. Since the
external program to call is set in the options file, a
@@ -1206,9 +1384,14 @@ main( int argc, char **argv )
case oAlwaysTrust: opt.always_trust = 1; break;
case oLoadExtension:
#ifndef __riscos__
- add_to_strlist(&extensions,pargs.r.ret_str);
- register_cipher_extension(orig_argc? *orig_argv:NULL,
- pargs.r.ret_str);
+#ifdef USE_DYNAMIC_LINKING
+ if(check_permissions(pargs.r.ret_str,2))
+ log_info(_("cipher extension \"%s\" not loaded due to "
+ "unsafe permissions\n"),pargs.r.ret_str);
+ else
+ register_cipher_extension(orig_argc? *orig_argv:NULL,
+ pargs.r.ret_str);
+#endif
#else /* __riscos__ */
not_implemented("load-extension");
#endif /* __riscos__ */
@@ -1496,28 +1679,6 @@ main( int argc, char **argv )
}
#endif
- check_permissions(opt.homedir,0,0);
-
- if(unsafe_files)
- {
- STRLIST tmp;
-
- for(tmp=unsafe_files;tmp;tmp=tmp->next)
- check_permissions(tmp->d,0,0);
-
- free_strlist(unsafe_files);
- }
-
- if(extensions)
- {
- STRLIST tmp;
-
- for(tmp=extensions;tmp;tmp=tmp->next)
- check_permissions(tmp->d,1,0);
-
- free_strlist(extensions);
- }
-
if( may_coredump && !opt.quiet )
log_info(_("WARNING: program may create a core file!\n"));
@@ -1723,7 +1884,6 @@ main( int argc, char **argv )
/* set the random seed file */
if( use_random_seed ) {
char *p = make_filename(opt.homedir, "random_seed", NULL );
- check_permissions(p,0,0);
set_random_seed_file(p);
m_free(p);
}