]> granicus.if.org Git - fcron/commitdiff
Implemented fcrondyn client authentication through Linux getsockopt(SO_PEERCRED).
authorthib <thib@thib-eee.(none)>
Mon, 9 Feb 2009 00:33:39 +0000 (00:33 +0000)
committerthib <thib@thib-eee.(none)>
Mon, 9 Feb 2009 00:33:39 +0000 (00:33 +0000)
Updated copyright years to include 2009

.gitignore
config.h.in
configure
configure.in
doc/en/changes.sgml
fcrondyn.c
global.h
socket.c

index 6930b2e999e842f4f88ad3870185b5747c282156..f8bad6fad13d407929bf55cd0a7134c88b8b3fd4 100644 (file)
@@ -23,4 +23,4 @@ doc/en/txt/
 doc/fr/HTML/
 doc/fr/man/
 doc/fr/txt/
-
+configure
index 370d8d4126b443d8b57239236abf5181bc9fe93e..cb5c726ce0594e5c86ff4a5fa8f0d6497f51cd84 100644 (file)
@@ -29,6 +29,7 @@
 /* *********************************************************** */
 
 
+/* ****************************************************************** */
 /* ****************************************************************** */
 /* beginning of configurable stuff ********************************** */
 
 
 /* end of configurable stuff **************************************** */
 /* ****************************************************************** */
+/* ****************************************************************** */
 
 
+/* ****************************************************************** */
 /* ****************************************************************** */
 /* *** options which are set by configure script ******************** */
 
 
 #undef CFLAGS
 
+/* ****************************************************************** */
 /* *** paths *** */
+
 #undef PROC
 
+/* ****************************************************************** */
+/* *** Compilation options *** */
+
 /* 1 if we want to compile and install fcrondyn */
 #undef FCRONDYN
 #undef NOLOADAVG
 /* special user for the system fcrontab */
 #undef SYSFCRONTAB
 
+/* ****************************************************************** */
+/* *** Types *** */
+
 /* Define to empty if the keyword does not work.  */
 #undef const
 
 /* Define on System V Release 4.  */
 #undef SVR4
 
+/* ****************************************************************** */
+/* *** Functions *** */
+
 /* Define if you have the crypt function.  */
 #undef HAVE_CRYPT
 
 /* Define if you have the wait3 system call.  */
 #undef HAVE_WAIT3
 
+/* ****************************************************************** */
+/* *** Headers *** */
+
 /* Define if you have the ANSI C header files.  */
 #undef STDC_HEADERS
 
 /* Define if your <sys/time.h> declares struct tm.  */
 #undef TM_IN_SYS_TIME
 
+/* Define if you have the <cred.h> header file.  */
+#undef HAVE_CRED_H
+
 /* Define if you have the <crypt.h> header file.  */
 #undef HAVE_CRYPT_H
 
 /* Define if you have the <strings.h> header file.  */
 #undef HAVE_STRINGS_H
 
+/* Define if you have the <sys/cred.h> header file.  */
+#undef HAVE_SYS_CRED_H
+
 /* Define if you have the <sys/dir.h> header file.  */
 #undef HAVE_SYS_DIR_H
 
 /* Define if you have the <sys/types.h> header file.  */
 #undef HAVE_SYS_TYPES_H
 
+/* Define if you have the <sys/ucred.h> header file.  */
+#undef HAVE_SYS_UCRED_H
+
 /* Define if you have the <sys/un.h> header file.  */
 #undef HAVE_SYS_UN_H
 
 /* Define if you have the <termios.h> header file.  */
 #undef HAVE_TERMIOS_H
 
+/* Define if you have the <ucred.h> header file.  */
+#undef HAVE_UCRED_H
+
 /* Define if you have the <unistd.h> header file.  */
 #undef HAVE_UNISTD_H
 
 #define O_SYNC O_FSYNC
 #endif
 
+/* ****************************************************************** */
+/* *** Size of *** */
+
 /* These SIZEOF_* constants are defined by the AC_CHECK_SIZEOF macro */
 #undef SIZEOF_TIME_T
 #undef SIZEOF_PID_T
index e8747904229aa7be8d39db29e67b4fef9f0b29ab..94772610b32ef15183fc1b1546c029f4bfbb592c 100755 (executable)
--- a/configure
+++ b/configure
@@ -1761,7 +1761,7 @@ _ACEOF
 VERSION="$vers"
 
 
-copyright_quoted="\"2000-2008\""
+copyright_quoted="\"2000-2009\""
 cat >>confdefs.h <<_ACEOF
 #define COPYRIGHT_QUOTED $copyright_quoted
 _ACEOF
@@ -14296,6 +14296,245 @@ _ACEOF
 fi
 
 
+
+
+
+for ac_header in cred.h sys/cred.h ucred.h sys/ucred.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in getpeerucred
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
 fcron_enable_checks=yes
 # Check whether --enable-checks was given.
 if test "${enable_checks+set}" = set; then
index 0a8b97328a6cdfeb4b85ba7245b65986f274b8ed..01181624aec61ab2556d7edb0270a55325d4313f 100644 (file)
@@ -16,7 +16,7 @@ AC_DEFINE_UNQUOTED(VERSION_QUOTED, $vers_quoted)
 VERSION="$vers"
 AC_SUBST(VERSION)
 
-copyright_quoted="\"2000-2008\""
+copyright_quoted="\"2000-2009\""
 AC_DEFINE_UNQUOTED(COPYRIGHT_QUOTED, $copyright_quoted)
 
 
@@ -137,6 +137,7 @@ if test "$crypt" -eq "1"; then
 fi
 
 
+dnl --- sockets
 dnl Check for post-Reno style struct sockaddr
 AC_CACHE_CHECK([for sa_len],
   ac_cv_sa_len,
@@ -148,6 +149,10 @@ if test $ac_cv_sa_len = yes; then
   AC_DEFINE(HAVE_SA_LEN)
 fi
 
+dnl --- Socket authentication
+AC_CHECK_HEADERS(cred.h sys/cred.h ucred.h sys/ucred.h)
+AC_CHECK_FUNCS(getpeerucred)
+
 dnl ---------------------------------------------------------------------
 dnl Check for fcron more specific stuffs (paths, progs, ...)
 dnl ---------------------------------------------------------------------
index e69bd6b9a0fe67557ac2fa220816d245f016b3a9..f1aa07364c297cfeca90a68813b0b0f3332e191a 100644 (file)
@@ -13,6 +13,16 @@ A copy of the license is included in gfdl.sgml.
    <sect1 id="changes">
       <title>Changes</title>
 
+      <itemizedlist>
+        <title>From version 3.0.5 to 3.1.0</title>
+        <listitem>
+           <para>Pass fcrondyn client credentials through the socket when possible so as the user doesn't need to type his password when using fcrondyn.</para>
+         </listitem>
+        <listitem>
+           <para>Code clean-up: Implemented generic unordred list for lavgq / exeq.</para>
+         </listitem>
+      </itemizedlist>
+
       <itemizedlist>
         <title>From version 3.0.4 to 3.0.5</title>
         <listitem>
@@ -1151,4 +1161,4 @@ mode: sgml
 sgml-parent-document:("fcron-doc.sgml" "book" "chapter" "sect1" "")
 End:
 -->
-   
\ No newline at end of file
+   
index 8dd211ee8f6a6e14a9a9f0ec812f75ae8ce38f7e..43c42bda24ec21cd15a5ef4e34357c88fc540613 100644 (file)
@@ -50,7 +50,7 @@ int interactive_mode(int fd);
 int talk_fcron(char *cmd_str, int fd);
 int parse_cmd(char *cmd_str, long int **cmd, int *cmd_len);
 int connect_fcron(void);
-int authenticate_user(int fd);
+int authenticate_user_password(int fd);
 
 /* command line options */
 #ifdef DEBUG
@@ -359,7 +359,7 @@ parse_cmd(char *cmd_str, long int **cmd, int *cmd_len)
 }
 
 int
-authenticate_user(int fd)
+authenticate_user_password(int fd)
     /* authenticate user */
 {
     char *password = NULL;
@@ -426,12 +426,15 @@ connect_fcron(void)
     if ( connect(fd, (struct sockaddr *) &addr, sun_len) < 0 )
        die_e("Cannot connect() to fcron (check if fcron is running)");
 
-    if ( authenticate_user(fd) == ERR ) {
-    fprintf(stderr, "Invalid password or too many authentication failures"
+/* Nothing to do on the client side if we use SO_PASSCRED */
+#ifndef SO_PASSCRED
+    if ( authenticate_user_password(fd) == ERR ) {
+        fprintf(stderr, "Invalid password or too many authentication failures"
            " (try to connect later).\n(In the later case, fcron rejects all"
            " new authentication during %d secs)\n", AUTH_WAIT);        
        die("Unable to authenticate user");
     }
+#endif /* SO_PASSCRED */
 
     return fd;
 
index 14fcdfd4d6004b25e5e284fde2e344c88e5f75f1..96f3edc867d3ef8e39e2906cb97cdb6ba0d49c2d 100644 (file)
--- a/global.h
+++ b/global.h
 #include <sys/fcntl.h>
 #endif
 
+#ifdef HAVE_CRED_H
+#include <cred.h>
+#endif
+#ifdef HAVE_UCRED_H
+#include <ucred.h>
+#endif
+#ifdef HAVE_SYS_CRED_H
+#include <sys/cred.h>
+#endif
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
+
 #ifdef HAVE_LIBPAM
 #include "pam.h"
 #endif
index 4c1e1925ef52802bec2ebb64a620a2f6dd464eb4..bfe973a041f28bd160b517cc5c9f6399921a305b 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -34,7 +34,8 @@
 
 void remove_connection(struct fcrondyn_cl **client, struct fcrondyn_cl *prev_client);
 void exe_cmd(struct fcrondyn_cl *client);
-void auth_client(struct fcrondyn_cl *client);
+void auth_client_password(struct fcrondyn_cl *client);
+void auth_client_so_passcred(struct fcrondyn_cl *client);
 void cmd_ls(struct fcrondyn_cl *client, long int *cmd, int fd, int is_root);
 void print_fields(int fd, unsigned char *details);
 void print_line(int fd, struct cl_t *line,  unsigned char *details, pid_t pid, int index,
@@ -196,9 +197,52 @@ init_socket(void)
 
 }
 
+#ifdef SO_PASSCRED
 void
-auth_client(struct fcrondyn_cl *client)
-    /* check client identity */
+auth_client_so_passcred(struct fcrondyn_cl *client)
+    /* check client identity by reading its credentials from the socket
+     * using getsockopt(SO_PASSCRED).
+     * Sets client->fcl_user on success, don't do anything on failure */
+{
+    const int true = 1;
+    /* There is no ucred.h (or equivalent) on linux to define struct ucred (!!)
+     * so we do it here */
+#if ! ( defined(HAVE_CRED_H) && defined(HAVE_UCRED_H) \
+               && defined(HAVE_SYS_CRED_H) && defined(HAVE_SYS_UCRED_H) )
+    struct ucred {
+        pid_t pid;
+        uid_t uid;
+        gid_t gid;
+    };
+#endif
+    struct ucred cred;
+    socklen_t cred_size = sizeof(cred);
+    struct passwd *p_entry = NULL;
+    
+    setsockopt(client->fcl_sock_fd, SOL_SOCKET, SO_PASSCRED, &true, sizeof(true));
+    if ( getsockopt(client->fcl_sock_fd, SOL_SOCKET, SO_PEERCRED,
+                           &cred, &cred_size) != 0) {
+        error_e("Could not get client credentials using getsockopt(SO_PEERCRED)");
+       return;
+    }
+
+    p_entry = getpwuid(cred.uid);
+    if ( p_entry == NULL ) {
+        error_e("Could not find password entry for uid %d", cred.uid);
+       return;
+    }
+
+    /* Successfully identified user: */
+    client->fcl_user = strdup2(p_entry->pw_name);
+
+    explain("Client's pid=%d, uid=%d, gid=%d username=%s\n", cred.pid, cred.uid, cred.gid, client->fcl_user);
+
+}
+#endif /* SO_PASSCRED */
+
+void
+auth_client_password(struct fcrondyn_cl *client)
+    /* check client identity by asking him to input his password */
 {
     char *pass_cry = NULL;
     char *pass_sys = NULL;
@@ -224,7 +268,7 @@ auth_client(struct fcrondyn_cl *client)
 #endif
 
     /* */
-    debug("auth_client() : socket : %d", client->fcl_sock_fd);
+    debug("auth_client_password() : socket : %d", client->fcl_sock_fd);
     /* */
 
     /* we need to limit auth failures : otherwise fcron may be used to "read"
@@ -239,7 +283,7 @@ auth_client(struct fcrondyn_cl *client)
        return;    
     }
 
-    /* password is stored after user name */
+    /* the password is stored after the user name */
     pass_str = &( (char *)client->fcl_cmd ) [ strlen( (char*)client->fcl_cmd ) + 1 ];
     if ( (pass_cry = crypt(pass_str, pass_sys)) == NULL ) {
        error_e("could not crypt()");
@@ -781,7 +825,8 @@ check_socket(int num)
 
     if ( FD_ISSET(listen_fd, &read_set) ) {
        debug("got new connection ...");
-       if ((fd = accept(listen_fd, (struct sockaddr *)&client_addr, &addr_len)) == -1) {
+       fd = accept(listen_fd, (struct sockaddr *)&client_addr, &addr_len);
+       if ( fd  == -1 ) {
            error_e("could not accept new connection : isset(listen_fd = %d) = %d",
                    listen_fd, FD_ISSET(listen_fd, &read_set));
        }
@@ -811,6 +856,10 @@ check_socket(int num)
                fcrondyn_cl_num += 1;
                
                debug("Added connection fd : %d - %d connections", fd, fcrondyn_cl_num);
+
+#ifdef SO_PASSCRED
+               auth_client_so_passcred(client);
+#endif /* SO_PASSCRED */
            }
        }
     }
@@ -853,7 +902,7 @@ check_socket(int num)
            client->fcl_cmd = buf_int;
            if ( client->fcl_user == NULL )
                /* not authenticated yet */
-               auth_client(client);
+               auth_client_password(client);
            else {
                /* we've just read a command ... */
                client->fcl_idle_since = now;