Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

POSIX.6



-----BEGIN PGP SIGNED MESSAGE-----

This patch adds some new features, that make the shell aware of POSIX.1e
(POSIX.6) capability (privilege) sets.  (An implementation of POSIX.1e
is currently being developed for Linux; it is currently a bit more than
sufficient to support this code.)

The patch changes the prompt code such that a `#' prompt will be triggered
by POSIX.1e capabilities, as well as EUID zero.  This test is also made
available in the conditional syntax, as `%(!'.

The patch adds a new module, which provides a builtin `cap' with which
the shell's current capabilities can be examined and set.  This is a
crucial feature for a shell in the POSIX.1e environment.  The module also
implements the related POSIX utilities, getcap and setcap; due to the
braindead POSIX design, this actually provides significantly different
semantics from the usual situation of these being distinct programs.

 -zefram

 *** configure.in	1997/03/31 00:07:33	1.36
 --- configure.in	1997/04/26 04:13:29
 ***************
 *** 315,321 ****
   AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
   		 termios.h sys/param.h sys/filio.h string.h memory.h \
   		 limits.h fcntl.h libc.h sys/utsname.h sys/resource.h \
 ! 		 locale.h errno.h stdlib.h unistd.h)
   if test $dynamic = yes; then
     AC_CHECK_HEADERS(dlfcn.h)
   fi
 --- 315,321 ----
   AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
   		 termios.h sys/param.h sys/filio.h string.h memory.h \
   		 limits.h fcntl.h libc.h sys/utsname.h sys/resource.h \
 ! 		 locale.h errno.h stdlib.h unistd.h sys/capability.h)
   if test $dynamic = yes; then
     AC_CHECK_HEADERS(dlfcn.h)
   fi
 ***************
 *** 420,425 ****
 --- 420,427 ----
     AC_CHECK_LIB(dl, dlopen)
   fi
   
 + AC_CHECK_LIB(cap, cap_init)
 + 
   dnl ---------------------
   dnl CHECK TERMCAP LIBRARY
   dnl ---------------------
 ***************
 *** 508,514 ****
                 getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \
                 sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \
                 sigprocmask setuid seteuid setreuid setresuid setsid strerror \
 !               nis_list initgroups fchdir)
   if test $dynamic = yes; then
     AC_CHECK_FUNCS(dlopen dlerror dlsym dlclose)
   fi
 --- 510,516 ----
                 getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \
                 sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \
                 sigprocmask setuid seteuid setreuid setresuid setsid strerror \
 !               nis_list initgroups fchdir cap_init)
   if test $dynamic = yes; then
     AC_CHECK_FUNCS(dlopen dlerror dlsym dlclose)
   fi
 *** Doc/Makefile.in	1997/03/31 00:37:36	1.11
 --- Doc/Makefile.in	1997/04/26 05:43:36
 ***************
 *** 92,97 ****
 --- 92,98 ----
   Zsh/compat.yo Zsh/compctl.yo Zsh/cond.yo Zsh/exec.yo Zsh/expn.yo \
   Zsh/filelist.yo Zsh/files.yo Zsh/func.yo Zsh/grammar.yo Zsh/guide.yo \
   Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/modules.yo \
 + Zsh/mod_cap.yo \
   Zsh/mod_clone.yo Zsh/mod_comp1.yo Zsh/mod_compctl.yo Zsh/mod_deltochar.yo \
   Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_stat.yo \
   Zsh/mod_zle.yo Zsh/options.yo \
 *** Doc/Zsh/guide.yo	1997/03/30 00:49:03	1.10
 --- Doc/Zsh/guide.yo	1997/04/26 05:44:20
 ***************
 *** 104,109 ****
 --- 104,110 ----
   
   Zsh Modules
   
 + menu(The cap Module)
   menu(The clone Module)
   menu(The comp1 Module)
   menu(The compctl Module)
 *** ......................	Thu Sep  7 20:04:30 1995
 --- Doc/Zsh/mod_cap.yo	Sat Apr 26 06:52:41 1997
 ***************
 *** 0 ****
 --- 1,28 ----
 + texinode(The cap Module)(The clone Module)()(Zsh Modules)
 + sect(The cap Module)
 + The tt(cap) module is used for manipulating POSIX.1e (POSIX.6) capability
 + sets.  If the operating system does not support this interface, the
 + builtins defined by this module will do nothing.
 + The builtins in this module are:
 + 
 + startitem()
 + findex(cap)
 + cindex(capabilities, setting)
 + item(tt(cap) [ var(capabilities) ])(
 + Change the shell's process capability sets to the specified var(capabilities),
 + otherwise display the shell's current capabilities.
 + )
 + findex(getcap)
 + cindex(capabilities, getting from files)
 + item(tt(getcap) var(filename) ...)(
 + This is a built-in implementation of the POSIX standard utility.  It displays
 + the capability sets on each specified var(filename).
 + )
 + findex(setcap)
 + cindex(capabilities, setting on files)
 + item(tt(setcap) var(capabilities) var(filename) ...)(
 + This is a built-in implementation of the POSIX standard utility.  It sets
 + the capability sets on each specified var(filename) to the specified
 + var(capabilities).
 + )
 + enditem()
 *** Doc/Zsh/mod_clone.yo	1997/03/17 04:22:14	1.1
 --- Doc/Zsh/mod_clone.yo	1997/04/26 05:44:44
 ***************
 *** 1,4 ****
 ! texinode(The clone Module)(The comp1 Module)()(Zsh Modules)
   sect(The clone Module)
   The tt(clone) module makes available one builtin command:
   
 --- 1,4 ----
 ! texinode(The clone Module)(The comp1 Module)(The cap Module)(Zsh Modules)
   sect(The clone Module)
   The tt(clone) module makes available one builtin command:
   
 *** Doc/Zsh/modules.yo	1997/03/27 01:57:34	1.2
 --- Doc/Zsh/modules.yo	1997/04/26 05:45:58
 ***************
 *** 11,16 ****
 --- 11,19 ----
   .  The modules available are:
   
   startitem()
 + item(tt(cap))(
 + Builtins for manipulating POSIX.1e (POSIX.6) capability (privilege) sets.
 + )
   item(tt(clone))(
   A builtin that can clone a running shell onto another terminal.
   )
 ***************
 *** 40,45 ****
 --- 43,49 ----
   )
   enditem()
   startmenu()
 + menu(The cap Module)
   menu(The clone Module)
   menu(The comp1 Module)
   menu(The compctl Module)
 ***************
 *** 50,55 ****
 --- 54,60 ----
   menu(The stat Module)
   menu(The zle Module)
   endmenu()
 + includefile(Zsh/mod_cap.yo)
   includefile(Zsh/mod_clone.yo)
   includefile(Zsh/mod_comp1.yo)
   includefile(Zsh/mod_compctl.yo)
 *** Doc/Zsh/prompt.yo	1997/03/30 17:09:18	1.4
 --- Doc/Zsh/prompt.yo	1997/04/26 05:56:22
 ***************
 *** 124,131 ****
   Clears to end of line.
   )
   item(tt(%#))(
 ! A `tt(#)' if the shell is running as root, a `tt(%)' if not.
 ! Equivalent to `tt(%(#.#.%%))'.
   )
   item(tt(%v))(
   vindex(psvar, use of)
 --- 124,135 ----
   Clears to end of line.
   )
   item(tt(%#))(
 ! A `tt(#)' if the shell is running with privileges, a `tt(%)' if not.
 ! Equivalent to `tt(%(!.#.%%))'.
 ! The definition of `privileged', for these purposes, is that either the
 ! effective user ID is zero, or, if POSIX.1e capabilities are supported, that
 ! at least one capability is raised in either the Effective or Inheritable
 ! capability vectors.
   )
   item(tt(%v))(
   vindex(psvar, use of)
 ***************
 *** 171,176 ****
 --- 175,181 ----
   sitem(tt(S))(True if the tt(SECONDS) parameter is at least var(n).)
   sitem(tt(v))(True if the array tt(psvar) has at least var(n) elements.)
   sitem(tt(_))(True if at least var(n) shell constructs were started.)
 + sitem(tt(!))(True if the shell is running with privileges.)
   endsitem()
   )
   xitem(tt(%<)var(string)tt(<))
 *** Src/init.c	1997/03/30 18:54:12	1.49
 --- Src/init.c	1997/04/26 04:19:17
 ***************
 *** 449,455 ****
   	prompt = ztrdup("");
   	prompt2 = ztrdup("");
       } else if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
 ! 	prompt  = ztrdup(geteuid() ? "$ " : "# ");
   	prompt2 = ztrdup("> ");
       } else {
   	prompt  = ztrdup("%m%# ");
 --- 449,455 ----
   	prompt = ztrdup("");
   	prompt2 = ztrdup("");
       } else if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
 ! 	prompt  = ztrdup(privasserted() ? "# " : "$ ");
   	prompt2 = ztrdup("> ");
       } else {
   	prompt  = ztrdup("%m%# ");
 *** Src/mods.conf	1997/03/27 01:57:50	1.11
 --- Src/mods.conf	1997/04/26 04:47:48
 ***************
 *** 19,24 ****
 --- 19,25 ----
   # (This would be rather neater if we could rely on shell functions in sh.)
   #
   
 + cap:		Modules/cap.o
   example:	Modules/example.o
   files:		Modules/files.o
   clone:		Modules/clone.o
 *** Src/prompt.c	1997/03/30 17:09:23	1.11
 --- Src/prompt.c	1997/04/26 06:01:24
 ***************
 *** 210,215 ****
 --- 210,218 ----
   		case '_':
   		    test = (cmdsp >= arg);
   		    break;
 + 		case '!':
 + 		    test = privasserted();
 + 		    break;
   		default:
   		    test = -1;
   		    break;
 ***************
 *** 493,499 ****
   		break;
   	    case '#':
   		addbufspc(1);
 ! 		*bp++ = (geteuid())? '%' : '#';
   		break;
   	    case 'v':
   		if (!arg)
 --- 496,502 ----
   		break;
   	    case '#':
   		addbufspc(1);
 ! 		*bp++ = privasserted() ? '#' : '%';
   		break;
   	    case 'v':
   		if (!arg)
 *** Src/system.h	1997/03/31 00:07:41	1.15
 --- Src/system.h	1997/04/26 04:21:52
 ***************
 *** 415,420 ****
 --- 415,424 ----
   # endif
   #endif
   
 + #ifdef HAVE_SYS_CAPABILITY_H
 + # include <sys/capability.h>
 + #endif
 + 
   /* DIGBUFSIZ is the length of a buffer which can hold the -LONG_MAX-1 *
    * converted to printable decimal form including the sign and the     *
    * terminating null character. Below 0.30103 > lg 2.                  */
 *** Src/utils.c	1997/03/31 07:51:11	1.73
 --- Src/utils.c	1997/04/26 04:39:19
 ***************
 *** 3525,3530 ****
 --- 3525,3562 ----
       return -1;
   }
   
 + /* Check whether the shell is running with privileges in effect.  *
 +  * This is the case if EITHER the euid is zero, OR (if the system *
 +  * supports POSIX.1e (POSIX.6) capability sets) the process'      *
 +  * Effective or Inheritable capability sets are non-empty.        */
 + 
 + /**/
 + int
 + privasserted(void)
 + {
 +     if(!geteuid())
 + 	return 1;
 + #ifdef HAVE_CAP_INIT
 +     {
 + 	cap_t caps = cap_get_proc();
 + 	if(caps) {
 + 	    /* POSIX doesn't define a way to test whether a capability set *
 + 	     * is empty or not.  Typical.  I hope this is conforming...    */
 + 	    cap_flag_value_t val;
 + 	    cap_value_t n;
 + 	    for(n = 0; !cap_get_flag(caps, n, CAP_EFFECTIVE, &val); n++)
 + 		if(val ||
 + 		   (!cap_get_flag(caps, n, CAP_INHERITABLE, &val) && val)) {
 + 		    cap_free(&caps);
 + 		    return 1;
 + 		}
 + 	    cap_free(&caps);
 + 	}
 +     }
 + #endif /* HAVE_CAP_INIT */
 +     return 0;
 + }
 + 
   #ifdef DEBUG
   
   /**/
 *** Src/Modules/Makefile.in	1997/03/29 14:22:10	1.21
 --- Src/Modules/Makefile.in	1997/04/26 04:48:32
 ***************
 *** 105,118 ****
   ../signames.h ../system.h ../zsh.h ../ztype.h ../../config.h
   
   # generated prototypes
 ! PROTO = example.pro files.pro clone.pro sched.pro stat.pro
   
   # target modules
 ! MODULES = example.so files.so clone.so sched.so stat.so
   
   # object files
 ! OBJS = example.o files.o clone.o sched.o stat.o
 ! DOBJS = example..o files..o clone..o sched..o stat..o
   
   ALLOBJS = $(OBJS) $(DOBJS)
   
 --- 105,118 ----
   ../signames.h ../system.h ../zsh.h ../ztype.h ../../config.h
   
   # generated prototypes
 ! PROTO = cap.pro example.pro files.pro clone.pro sched.pro stat.pro
   
   # target modules
 ! MODULES = cap.so example.so files.so clone.so sched.so stat.so
   
   # object files
 ! OBJS = cap.o example.o files.o clone.o sched.o stat.o
 ! DOBJS = cap..o example..o files..o clone..o sched..o stat..o
   
   ALLOBJS = $(OBJS) $(DOBJS)
   
 ***************
 *** 133,138 ****
 --- 133,139 ----
   
   $(PROTO): ../makepro.sed
   
 + cap.so: cap..o
   example.so: example..o
   files.so: files..o
   clone.so: clone..o
 *** .....................	Thu Sep  7 20:04:30 1995
 --- Src/Modules/cap.c	Sat Apr 26 06:17:17 1997
 ***************
 *** 0 ****
 --- 1,151 ----
 + /*
 +  * $Id$
 +  *
 +  * cap.c - POSIX.1e (POSIX.6) capability set manipulation
 +  *
 +  * This file is part of zsh, the Z shell.
 +  *
 +  * Copyright (c) 1997 Andrew Main
 +  * All rights reserved.
 +  *
 +  * Permission is hereby granted, without written agreement and without
 +  * license or royalty fees, to use, copy, modify, and distribute this
 +  * software and to distribute modified versions of this software for any
 +  * purpose, provided that the above copyright notice and the following
 +  * two paragraphs appear in all copies of this software.
 +  *
 +  * In no event shall Andrew Main or the Zsh Development Group be liable
 +  * to any party for direct, indirect, special, incidental, or consequential
 +  * damages arising out of the use of this software and its documentation,
 +  * even if Andrew Main and the Zsh Development Group have been advised of
 +  * the possibility of such damage.
 +  *
 +  * Andrew Main and the Zsh Development Group specifically disclaim any
 +  * warranties, including, but not limited to, the implied warranties of
 +  * merchantability and fitness for a particular purpose.  The software
 +  * provided hereunder is on an "as is" basis, and Andrew Main and the
 +  * Zsh Development Group have no obligation to provide maintenance,
 +  * support, updates, enhancements, or modifications.
 +  *
 +  */
 + 
 + #include "zsh.h"
 + 
 + #include "cap.pro"
 + 
 + #ifdef HAVE_CAP_INIT
 + 
 + static int
 + bin_cap(char *nam, char **argv, char *ops, int func)
 + {
 +     int ret = 0;
 +     cap_t caps;
 +     if(*argv) {
 + 	caps = cap_from_text(*argv);
 + 	if(!caps) {
 + 	    zwarnnam(nam, "invalid capability string", NULL, 0);
 + 	    return 1;
 + 	}
 + 	if(cap_set_proc(caps)) {
 + 	    zwarnnam(nam, "can't change capabilites: %e", NULL, errno);
 + 	    ret = 1;
 + 	}
 +     } else {
 + 	char *result;
 + 	ssize_t length;
 + 	caps = cap_get_proc();
 + 	if(caps)
 + 	    result = cap_to_text(caps, &length);
 + 	if(!caps || !result) {
 + 	    zwarnnam(nam, "can't get capabilites: %e", NULL, errno);
 + 	    ret = 1;
 + 	} else
 + 	    puts(result);
 +     }
 +     cap_free(&caps);
 +     return ret;
 + }
 + 
 + static int
 + bin_getcap(char *nam, char **argv, char *ops, int func)
 + {
 +     int ret = 0;
 + 
 +     do {
 + 	char *result;
 + 	ssize_t length;
 + 	cap_t caps = cap_get_file(*argv);
 + 	if(caps)
 + 	    result = cap_to_text(caps, &length);
 + 	if (!caps || !result) {
 + 	    zwarnnam(nam, "%s: %e", *argv, errno);
 + 	    ret = 1;
 + 	} else
 + 	    printf("%s %s\n", *argv, result);
 + 	cap_free(&caps);
 +     } while(*++argv);
 +     return ret;
 + }
 + 
 + static int
 + bin_setcap(char *nam, char **argv, char *ops, int func)
 + {
 +     cap_t caps;
 +     int ret = 0;
 + 
 +     caps = cap_from_text(*argv++);
 +     if(!caps) {
 + 	zwarnnam(nam, "invalid capability string", NULL, 0);
 + 	return 1;
 +     }
 + 
 +     do {
 + 	if(cap_set_file(*argv, caps)) {
 + 	    zwarnnam(nam, "%s: %e", *argv, errno);
 + 	    ret = 1;
 + 	}
 +     } while(*++argv);
 +     cap_free(&caps);
 +     return ret;
 + }
 + 
 + #else /* !HAVE_CAP_INIT */
 + 
 + static int
 + bin_notavail(char *nam, char **argv, char *ops, int func)
 + {
 +     zwarnnam(nam, "not available on this system", NULL, 0);
 +     return 1;
 + }
 + 
 + # define bin_cap    bin_notavail
 + # define bin_getcap bin_notavail
 + # define bin_setcap bin_notavail
 + 
 + #endif /* !HAVE_CAP_INIT */
 + 
 + /* module paraphernalia */
 + 
 + static struct binlist bintab[] = {
 +     { "cap",    0, bin_cap,    0,  1, 0, NULL, NULL, 0 },
 +     { "getcap", 0, bin_getcap, 1, -1, 0, NULL, NULL, 0 },
 +     { "setcap", 0, bin_setcap, 2, -1, 0, NULL, NULL, 0 },
 + };
 + 
 + /**/
 + int BOOT(
 + boot_cap)(Module m)
 + {
 +     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
 + }
 + 
 + #ifdef MODULE
 + 
 + /**/
 + int CLEANUP(
 + cleanup_cap)(Module m)
 + {
 +     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
 +     return 0;
 + }
 + #endif

-----BEGIN PGP SIGNATURE-----
Version: 2.6.3ia
Charset: ascii

iQCVAwUBM2IpYnD/+HJTpU/hAQFT5QP/ZRgcrTZX95f2d4jP0H23zfS3QXuy9wmY
oveB4nn2eopCRjTAU5Uhrq9X0LCojfJZrnfBKgOkCwxC1fmRgNXdS8q24Nz2Ej4p
qFM/3B1zPkH9DgIl9hHn81NPTjiWF9IUGSiRErpexYOFCEoiAfc6LaFSCCwS9Wdv
zrEPfjPW794=
=Jdca
-----END PGP SIGNATURE-----



Messages sorted by: Reverse Date, Date, Thread, Author