diff -U0 emacs-bzr/src/ChangeLog.selinux-context-fun emacs-bzr/src/ChangeLog --- emacs-bzr/src/ChangeLog.selinux-context-fun 2010-03-22 14:30:57.235887665 +0100 +++ emacs-bzr/src/ChangeLog 2010-03-22 15:05:20.936885923 +0100 @@ -2,0 +3,8 @@ + * eval.c, lisp.h (call7): New function. + + * fileio.c (Ffile_selinux_context): New function. + (Fset_file_selinux_context): New function. + (Fcopy_file): New parameter preserve-selinux-context. + (Frename_file): Preserve selinux context when renaming + by copy-file. + diff -up emacs-bzr/src/eval.c.selinux-context-fun emacs-bzr/src/eval.c --- emacs-bzr/src/eval.c.selinux-context-fun 2010-03-22 14:41:29.485760685 +0100 +++ emacs-bzr/src/eval.c 2010-03-22 14:57:18.547767559 +0100 @@ -2930,6 +2930,33 @@ call6 (fn, arg1, arg2, arg3, arg4, arg5, #endif /* not NO_ARG_ARRAY */ } +/* Call function fn with 7 arguments arg1, arg2, arg3, arg4, arg5, arg6, arg7 */ +/* ARGSUSED */ +Lisp_Object +call7 (fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7) + Lisp_Object fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7; +{ + struct gcpro gcpro1; +#ifdef NO_ARG_ARRAY + Lisp_Object args[8]; + args[0] = fn; + args[1] = arg1; + args[2] = arg2; + args[3] = arg3; + args[4] = arg4; + args[5] = arg5; + args[6] = arg6; + args[7] = arg7; + GCPRO1 (args[0]); + gcpro1.nvars = 8; + RETURN_UNGCPRO (Ffuncall (8, args)); +#else /* not NO_ARG_ARRAY */ + GCPRO1 (fn); + gcpro1.nvars = 8; + RETURN_UNGCPRO (Ffuncall (8, &fn)); +#endif /* not NO_ARG_ARRAY */ +} + /* The caller should GCPRO all the elements of ARGS. */ DEFUN ("funcall", Ffuncall, Sfuncall, 1, MANY, 0, diff -up emacs-bzr/src/fileio.c.selinux-context-fun emacs-bzr/src/fileio.c --- emacs-bzr/src/fileio.c.selinux-context-fun 2010-03-22 14:23:18.370761463 +0100 +++ emacs-bzr/src/fileio.c 2010-03-22 15:51:00.238886093 +0100 @@ -59,6 +59,11 @@ extern int errno; #endif #endif +#ifdef HAVE_LIBSELINUX +#include +#include +#endif + #include "lisp.h" #include "intervals.h" #include "buffer.h" @@ -339,6 +344,8 @@ Lisp_Object Qfile_accessible_directory_p Lisp_Object Qfile_modes; Lisp_Object Qset_file_modes; Lisp_Object Qset_file_times; +Lisp_Object Qfile_selinux_context; +Lisp_Object Qset_file_selinux_context; Lisp_Object Qfile_newer_than_file_p; Lisp_Object Qinsert_file_contents; Lisp_Object Qwrite_region; @@ -1902,7 +1909,7 @@ barf_or_query_if_file_exists (absname, q return; } -DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 5, +DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6, "fCopy file: \nGCopy %s to file: \np\nP", doc: /* Copy FILE to NEWNAME. Both args must be strings. If NEWNAME names a directory, copy FILE there. @@ -1924,10 +1931,13 @@ last-modified time as the old one. (Thi A prefix arg makes KEEP-TIME non-nil. If PRESERVE-UID-GID is non-nil, we try to transfer the -uid and gid of FILE to NEWNAME. */) - (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid) +uid and gid of FILE to NEWNAME. + +If PRESERVE-SELINUX-CONTEXT is non-nil and SELinux is enabled +on the system, we copy the SELinux context of FILE to NEWNAME. */) + (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid, preserve_selinux_context) Lisp_Object file, newname, ok_if_already_exists, keep_time; - Lisp_Object preserve_uid_gid; + Lisp_Object preserve_uid_gid, preserve_selinux_context; { int ifd, ofd, n; char buf[16 * 1024]; @@ -1937,6 +1947,10 @@ uid and gid of FILE to NEWNAME. */) int count = SPECPDL_INDEX (); int input_file_statable_p; Lisp_Object encoded_file, encoded_newname; +#if HAVE_LIBSELINUX + security_context_t con; + int fail, conlength = 0; +#endif encoded_file = encoded_newname = Qnil; GCPRO4 (file, newname, encoded_file, encoded_newname); @@ -1957,8 +1971,9 @@ uid and gid of FILE to NEWNAME. */) if (NILP (handler)) handler = Ffind_file_name_handler (newname, Qcopy_file); if (!NILP (handler)) - RETURN_UNGCPRO (call6 (handler, Qcopy_file, file, newname, - ok_if_already_exists, keep_time, preserve_uid_gid)); + RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname, + ok_if_already_exists, keep_time, preserve_uid_gid, + preserve_selinux_context)); encoded_file = ENCODE_FILE (file); encoded_newname = ENCODE_FILE (newname); @@ -2012,6 +2027,15 @@ uid and gid of FILE to NEWNAME. */) copyable by us. */ input_file_statable_p = (fstat (ifd, &st) >= 0); +#if HAVE_LIBSELINUX + if (!NILP (preserve_selinux_context) && is_selinux_enabled ()) + { + conlength = fgetfilecon (ifd, &con); + if (conlength == -1) + report_file_error ("Doing fgetfilecon", Fcons (file, Qnil)); + } +#endif + #if !defined (MSDOS) || __DJGPP__ > 1 if (out_st.st_mode != 0 && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) @@ -2071,6 +2095,18 @@ uid and gid of FILE to NEWNAME. */) } #endif /* not MSDOS */ +#if HAVE_LIBSELINUX + if (conlength > 0) + { + /* Set the modified context back to the file. */ + fail = fsetfilecon (ofd, con); + if (fail) + report_file_error ("Doing fsetfilecon", Fcons (newname, Qnil)); + + freecon (con); + } +#endif + /* Closing the output clobbers the file times on some systems. */ if (emacs_close (ofd) < 0) report_file_error ("I/O error", Fcons (newname, Qnil)); @@ -2297,7 +2333,7 @@ This is what happens in interactive use have copy-file prompt again. */ Fcopy_file (file, newname, NILP (ok_if_already_exists) ? Qnil : Qt, - Qt, Qt); + Qt, Qt, Qt); count = SPECPDL_INDEX (); specbind (Qdelete_by_moving_to_trash, Qnil); @@ -2863,6 +2899,136 @@ See `file-symlink-p' to distinguish syml #endif } +DEFUN ("file-selinux-context", Ffile_selinux_context, + Sfile_selinux_context, 1, 1, 0, + doc: /* Return SELinux context of file named FILENAME, +as a list ("user", "role", "type", "range"). Return (nil, nil, nil, nil) +if file does not exist, is not accessible, or SELinux is disabled */) + (filename) + Lisp_Object filename; +{ + Lisp_Object absname; + Lisp_Object values[4]; + Lisp_Object handler; +#if HAVE_LIBSELINUX + security_context_t con; + int conlength; + context_t context; +#endif + + absname = expand_and_dir_to_file (filename, current_buffer->directory); + + /* If the file name has special constructs in it, + call the corresponding file handler. */ + handler = Ffind_file_name_handler (absname, Qfile_selinux_context); + if (!NILP (handler)) + return call2 (handler, Qfile_selinux_context, absname); + + absname = ENCODE_FILE (absname); + + values[0] = Qnil; + values[1] = Qnil; + values[2] = Qnil; + values[3] = Qnil; +#if HAVE_LIBSELINUX + if (is_selinux_enabled ()) + { + conlength = lgetfilecon (SDATA (absname), &con); + if (conlength > 0) + { + context = context_new (con); + values[0] = build_string (context_user_get (context)); + values[1] = build_string (context_role_get (context)); + values[2] = build_string (context_type_get (context)); + values[3] = build_string (context_range_get (context)); + context_free (context); + } + if (con) + freecon (con); + } +#endif + + return Flist (sizeof(values) / sizeof(values[0]), values); +} + +DEFUN ("set-file-selinux-context", Fset_file_selinux_context, + Sset_file_selinux_context, 2, 2, 0, + doc: /* Set SELinux context of file named FILENAME to CONTEXT +as a list ("user", "role", "type", "range"). Has no effect if SELinux +is disabled. */) + (filename, context) + Lisp_Object filename, context; +{ + Lisp_Object absname, encoded_absname; + Lisp_Object handler; + Lisp_Object user = CAR_SAFE (context); + Lisp_Object role = CAR_SAFE (CDR_SAFE (context)); + Lisp_Object type = CAR_SAFE (CDR_SAFE (CDR_SAFE (context))); + Lisp_Object range = CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (context)))); +#if HAVE_LIBSELINUX + security_context_t con; + int fail, conlength; + context_t parsed_con; +#endif + + absname = Fexpand_file_name (filename, current_buffer->directory); + + /* If the file name has special constructs in it, + call the corresponding file handler. */ + handler = Ffind_file_name_handler (absname, Qset_file_selinux_context); + if (!NILP (handler)) + return call3 (handler, Qset_file_selinux_context, absname, context); + + encoded_absname = ENCODE_FILE (absname); + +#if HAVE_LIBSELINUX + if (is_selinux_enabled ()) + { + /* Get current file context. */ + conlength = lgetfilecon (SDATA (encoded_absname), &con); + if (conlength > 0) + { + parsed_con = context_new (con); + /* Change the parts defined in the parameter.*/ + if (STRINGP (user)) + { + if (context_user_set (parsed_con, SDATA (user))) + error ("Doing context_user_set"); + } + if (STRINGP (role)) + { + if (context_role_set (parsed_con, SDATA (role))) + error ("Doing context_role_set"); + } + if (STRINGP (type)) + { + if (context_type_set (parsed_con, SDATA (type))) + error ("Doing context_type_set"); + } + if (STRINGP (range)) + { + if (context_range_set (parsed_con, SDATA (range))) + error ("Doing context_range_set"); + } + + /* Set the modified context back to the file. */ + fail = lsetfilecon (SDATA (encoded_absname), context_str (parsed_con)); + if (fail) + report_file_error ("Doing lsetfilecon", Fcons (absname, Qnil)); + + context_free (parsed_con); + } + else + report_file_error("Doing lgetfilecon", Fcons (absname, Qnil)); + + if (con) + freecon (con); + } +#endif + + return Qnil; +} + DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, doc: /* Return mode bits of file named FILENAME, as an integer. Return nil, if file does not exist or is not accessible. */) @@ -5515,6 +5681,8 @@ syms_of_fileio () Qfile_modes = intern_c_string ("file-modes"); Qset_file_modes = intern_c_string ("set-file-modes"); Qset_file_times = intern_c_string ("set-file-times"); + Qfile_selinux_context = intern_c_string("file-selinux-context"); + Qset_file_selinux_context = intern_c_string("set-file-selinux-context"); Qfile_newer_than_file_p = intern_c_string ("file-newer-than-file-p"); Qinsert_file_contents = intern_c_string ("insert-file-contents"); Qwrite_region = intern_c_string ("write-region"); @@ -5550,6 +5718,8 @@ syms_of_fileio () staticpro (&Qfile_modes); staticpro (&Qset_file_modes); staticpro (&Qset_file_times); + staticpro (&Qfile_selinux_context); + staticpro (&Qset_file_selinux_context); staticpro (&Qfile_newer_than_file_p); staticpro (&Qinsert_file_contents); staticpro (&Qwrite_region); @@ -5783,6 +5953,8 @@ When non-nil, the function `move-file-to defsubr (&Sfile_modes); defsubr (&Sset_file_modes); defsubr (&Sset_file_times); + defsubr (&Sfile_selinux_context); + defsubr (&Sset_file_selinux_context); defsubr (&Sset_default_file_modes); defsubr (&Sdefault_file_modes); defsubr (&Sfile_newer_than_file_p); diff -up emacs-bzr/src/lisp.h.selinux-context-fun emacs-bzr/src/lisp.h --- emacs-bzr/src/lisp.h.selinux-context-fun 2010-03-22 14:43:16.637768779 +0100 +++ emacs-bzr/src/lisp.h 2010-03-22 14:39:25.416761387 +0100 @@ -2855,6 +2855,7 @@ extern Lisp_Object call3 P_ ((Lisp_Objec extern Lisp_Object call4 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); extern Lisp_Object call5 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); extern Lisp_Object call6 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); +extern Lisp_Object call7 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); EXFUN (Fdo_auto_save, 2); extern Lisp_Object apply_lambda P_ ((Lisp_Object, Lisp_Object, int)); extern Lisp_Object internal_catch P_ ((Lisp_Object, Lisp_Object (*) (Lisp_Object), Lisp_Object));