Hello community, here is the log from the commit of package snapper for openSUSE:Factory checked in at 2013-06-05 13:38:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/snapper (Old) and /work/SRC/openSUSE:Factory/.snapper.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "snapper" Changes: -------- --- /work/SRC/openSUSE:Factory/snapper/snapper.changes 2013-05-13 15:34:02.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.snapper.new/snapper.changes 2013-06-05 14:24:49.000000000 +0200 @@ -1,0 +2,5 @@ +Fri May 31 17:35:33 CEST 2013 - [email protected] + +- fixed xattrs reading for certain block/character devices + +------------------------------------------------------------------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ snapper-0.1.4.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/snapper-0.1.4/doc/pam_snapper.8 new/snapper-0.1.4/doc/pam_snapper.8 --- old/snapper-0.1.4/doc/pam_snapper.8 2013-05-03 09:57:13.000000000 +0200 +++ new/snapper-0.1.4/doc/pam_snapper.8 2013-05-31 17:42:14.000000000 +0200 @@ -124,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "PAM_SNAPPER 8" -.TH PAM_SNAPPER 8 "2013-05-02" "0.1.4" " " +.TH "PAM_SNAPPER" "8" "2013-05-23" "0.1.4" "Filesystem Snapshot Management" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -133,7 +133,7 @@ pam_snapper \- PAM module which creates filesystem snapshots via "Snapper" .SH "SYNOPSIS" .IX Header "SYNOPSIS" -pam_snapper.so debug [homeprefix=<>] [ignoreservices=<>] [ignoreusers=<>] [rootasroot] [ignoreroot] [openonly] [closeonly] +pam_snapper.so [debug] [homeprefix=<>] [ignoreservices=<>] [ignoreusers=<>] [rootasroot] [ignoreroot] [openonly] [closeonly] [cleanup=<>] .SH "DESCRIPTION" .IX Header "DESCRIPTION" Create a snapshot at every login of a User, thus he or she always have a save starting point. @@ -199,7 +199,7 @@ \&\*(L"session optional pam_snapper.so\*(R" .SH "SEE ALSO" .IX Header "SEE ALSO" -\&\fIpam.conf\fR\|(5), \fIpam.d\fR\|(5) \fIpam\fR\|(8), pam_snapper_homeconvert, pam_snapper_pamconfig, pam_snapper_useradd, pam_snapper_userdel +snapper(8), pam.conf(5), pam(8), pam_snapper_homeconvert, pam_snapper_pamconfig, pam_snapper_useradd, pam_snapper_userdel .SH "AUTHORS and CONTRIBUTORS" .IX Header "AUTHORS and CONTRIBUTORS" pam-snapper was written by Matthias G. Eckermann <[email protected]> @@ -227,7 +227,7 @@ General Public License for more details. .PP You should have received a copy of the \s-1GNU\s0 General Public License -along with this program; if not, contact \s-1SUSE\s0 +along with this program; if not, contact \s-1SUSE\s0. .PP To contact \s-1SUSE\s0 about this file by physical or electronic mail, you -may find current contact information at www.suse.com +may find current contact information at www.suse.com. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/snapper-0.1.4/doc/pam_snapper.8.in new/snapper-0.1.4/doc/pam_snapper.8.in --- old/snapper-0.1.4/doc/pam_snapper.8.in 2013-05-02 16:46:40.000000000 +0200 +++ new/snapper-0.1.4/doc/pam_snapper.8.in 2013-05-23 16:51:34.000000000 +0200 @@ -124,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "PAM_SNAPPER 8" -.TH PAM_SNAPPER 8 "2013-05-02" "@VERSION@" " " +.TH "PAM_SNAPPER" "8" "2013-05-23" "@VERSION@" "Filesystem Snapshot Management" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -133,7 +133,7 @@ pam_snapper \- PAM module which creates filesystem snapshots via "Snapper" .SH "SYNOPSIS" .IX Header "SYNOPSIS" -pam_snapper.so debug [homeprefix=<>] [ignoreservices=<>] [ignoreusers=<>] [rootasroot] [ignoreroot] [openonly] [closeonly] +pam_snapper.so [debug] [homeprefix=<>] [ignoreservices=<>] [ignoreusers=<>] [rootasroot] [ignoreroot] [openonly] [closeonly] [cleanup=<>] .SH "DESCRIPTION" .IX Header "DESCRIPTION" Create a snapshot at every login of a User, thus he or she always have a save starting point. @@ -199,7 +199,7 @@ \&\*(L"session optional pam_snapper.so\*(R" .SH "SEE ALSO" .IX Header "SEE ALSO" -\&\fIpam.conf\fR\|(5), \fIpam.d\fR\|(5) \fIpam\fR\|(8), pam_snapper_homeconvert, pam_snapper_pamconfig, pam_snapper_useradd, pam_snapper_userdel +snapper(8), pam.conf(5), pam(8), pam_snapper_homeconvert, pam_snapper_pamconfig, pam_snapper_useradd, pam_snapper_userdel .SH "AUTHORS and CONTRIBUTORS" .IX Header "AUTHORS and CONTRIBUTORS" pam-snapper was written by Matthias G. Eckermann <[email protected]> @@ -227,7 +227,7 @@ General Public License for more details. .PP You should have received a copy of the \s-1GNU\s0 General Public License -along with this program; if not, contact \s-1SUSE\s0 +along with this program; if not, contact \s-1SUSE\s0. .PP To contact \s-1SUSE\s0 about this file by physical or electronic mail, you -may find current contact information at www.suse.com +may find current contact information at www.suse.com. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/snapper-0.1.4/pam/pam_snapper.c new/snapper-0.1.4/pam/pam_snapper.c --- old/snapper-0.1.4/pam/pam_snapper.c 2013-05-03 09:56:33.000000000 +0200 +++ new/snapper-0.1.4/pam/pam_snapper.c 2013-05-23 11:46:33.000000000 +0200 @@ -1,5 +1,4 @@ /** - * @file * @author Matthias G. Eckermann <[email protected]> * * @section License @@ -25,14 +24,10 @@ * * @section Usage * - * 1. Create a btrfs subvolume for the new user, - * and a snapper configuration, e.g. using - * "pam_snapper_useradd.sh". + * Add the following line to /etc/pam.d/common-session: + * "session optional pam_snapper.so" * - * 2. Add the following line to /etc/pam.d/common-session: - * "session optional pam_snapper.so homeprefix=home_" - * - * See "man snapper" for more information. + * See "man pam_snapper" and "map snapper" for more information. * * @section Related Projects * @@ -48,12 +43,10 @@ * * @section Coding Style * - * indent -linux -i8 -ts8 -l140 -cbi8 -cli8 -prs -nbap -nbbb -nbad -sob *.c + * indent -linux -i8 -ts8 -l100 -cbi8 -cli8 -prs -nbap -nbbb -nbad -sob *.c * */ -/* #define PAM_SNAPPER_DEBUG */ - #include "../config.h" /* @@ -68,6 +61,7 @@ #include <errno.h> #include <syslog.h> #include <sys/types.h> +#include <sys/wait.h> #include <pwd.h> /* @@ -147,51 +141,14 @@ * Functions for DBUS handling */ -/** - * init the connection to the DBUS - * - * @param pamh the PAM handle - * - * @return DBusConnection * - * -*/ -static DBusConnection *cdbus_conn( pam_handle_t * pamh ) -{ - DBusError err; - DBusConnection *conn; - dbus_error_init( &err ); - /* bus connection */ - conn = dbus_bus_get( DBUS_BUS_SYSTEM, &err ); - if ( dbus_error_is_set( &err ) ) { - pam_syslog( pamh, LOG_ERR, "connection error: %s", strerror( errno ) ); - dbus_error_free( &err ); - } - if ( NULL == conn ) { - return NULL; - } - return conn; -} - -/** - * send a message to the DBUS - * - * @param pamh PAM handle - * @param conn current DBus connection - * @param msg message to send - * @param pend_out handle for a reply - * - * @return error condition - * -*/ -static int cdbus_msg_send( pam_handle_t * pamh, DBusConnection * conn, DBusMessage * msg, DBusPendingCall ** pend_out ) +static int cdbus_msg_send( DBusConnection * conn, DBusMessage * msg, DBusPendingCall ** pend_out ) { DBusPendingCall *pending; /* send message and get a handle for a reply */ - if ( !dbus_connection_send_with_reply( conn, msg, &pending, -1 ) ) { + if ( !dbus_connection_send_with_reply( conn, msg, &pending, 0x7fffffff ) ) { return -ENOMEM; } if ( NULL == pending ) { - pam_syslog( pamh, LOG_ERR, "Pending Call Null" ); return -EINVAL; } dbus_connection_flush( conn ); @@ -199,18 +156,8 @@ return 0; } -/** - * receive a message from the DBUS - * - * @param pamh PAM handle - * @param conn current DBus connection - * @param pending pointer for the pending call - * @param msg_out handle for the result data set - * - * @return error condition - * -*/ -static int cdbus_msg_recv( pam_handle_t * pamh, DBusConnection * conn, DBusPendingCall * pending, DBusMessage ** msg_out ) +static int cdbus_msg_recv( DBusConnection * conn, DBusPendingCall * pending, + DBusMessage ** msg_out ) { DBusMessage *msg; /* block until we receive a reply */ @@ -218,7 +165,6 @@ /* get the reply message */ msg = dbus_pending_call_steal_reply( pending ); if ( msg == NULL ) { - pam_syslog( pamh, LOG_ERR, "Reply Null" ); return -ENOMEM; } /* free the pending message handle */ @@ -227,40 +173,19 @@ return 0; } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * - * @return error condition or OK - * -*/ -static int cdbus_type_check( pam_handle_t * pamh, DBusMessageIter * iter, int expected_type ) +static int cdbus_type_check( DBusMessageIter * iter, int expected_type ) { int type = dbus_message_iter_get_arg_type( iter ); if ( type != expected_type ) { - pam_syslog( pamh, LOG_ERR, "got type %d, expecting %d", type, expected_type ); return -EINVAL; } return 0; } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * - * @return error condition or OK - * -*/ -static int cdbus_type_check_get( pam_handle_t * pamh, DBusMessageIter * iter, int expected_type, void *val ) +static int cdbus_type_check_get( DBusMessageIter * iter, int expected_type, void *val ) { int ret; - ret = cdbus_type_check( pamh, iter, expected_type ); + ret = cdbus_type_check( iter, expected_type ); if ( ret < 0 ) { return ret; } @@ -268,82 +193,68 @@ return 0; } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * @param - * @param - * @param - * - * @return -ENOMEM or OK - * -*/ -static int cdbus_create_snap_pack( pam_handle_t * pamh, const char *snapper_conf, createmode_t create_mode, const char *cleanup, - uint32_t num_user_data, struct dict *user_data, DBusMessage ** req_msg_out ) +static int cdbus_create_snap_pack( const char *snapper_conf, createmode_t createmode, + const char *cleanup, uint32_t num_user_data, + const struct dict *user_data, const uint32_t * snapshot_num_in, + DBusMessage ** req_msg_out ) { DBusMessage *msg; DBusMessageIter args; DBusMessageIter array_iter; DBusMessageIter struct_iter; - const char *desc = MODULE_NAME; - uint32_t *snap_id = NULL; - bool ret; - const char *modestrings[3] = { "CreateSingleSnapshot", "CreatePreSnapshot", "CreatePostSnapshot" }; + const char *modestrings[3] = + { "CreateSingleSnapshot", "CreatePreSnapshot", "CreatePostSnapshot" }; msg = dbus_message_new_method_call( "org.opensuse.Snapper", /* target for the method call */ "/org/opensuse/Snapper", /* object to call on */ "org.opensuse.Snapper", /* interface to call on */ - modestrings[create_mode] ); /* method name */ + modestrings[createmode] ); /* method name */ if ( msg == NULL ) { - pam_syslog( pamh, LOG_ERR, "failed to create req msg" ); return -ENOMEM; } - /* append arguments */ + dbus_message_iter_init_append( msg, &args ); if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &snapper_conf ) ) { - pam_syslog( pamh, LOG_ERR, "Out Of Memory!" ); return -ENOMEM; } - if ( create_mode == createmode_post ) { - pam_get_data( pamh, "pam_snapper_snapshot_num", ( const void ** )&snap_id ); - if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_UINT32, snap_id ) ) { - pam_syslog( pamh, LOG_ERR, "Out Of Memory!" ); + if ( createmode == createmode_post ) { + if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_UINT32, snapshot_num_in ) ) { return -ENOMEM; } } + + const char *desc = MODULE_NAME; if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &desc ) ) { - pam_syslog( pamh, LOG_ERR, "Out Of Memory!" ); return -ENOMEM; } - /* cleanup */ + if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &cleanup ) ) { - pam_syslog( pamh, LOG_ERR, "Out Of Memory!" ); return -ENOMEM; } - ret = dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, CDBUS_SIG_STRING_DICT, &array_iter ); + + dbus_bool_t ret = + dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, CDBUS_SIG_STRING_DICT, + &array_iter ); if ( !ret ) { - pam_syslog( pamh, LOG_ERR, "failed to open array container" ); return -ENOMEM; } + for ( uint32_t i = 0; i < num_user_data; ++i ) { - ret = dbus_message_iter_open_container( &array_iter, DBUS_TYPE_DICT_ENTRY, NULL, &struct_iter ); + ret = + dbus_message_iter_open_container( &array_iter, DBUS_TYPE_DICT_ENTRY, NULL, + &struct_iter ); if ( !ret ) { - pam_syslog( pamh, LOG_ERR, "failed to open struct container" ); return -ENOMEM; } - if ( !dbus_message_iter_append_basic( &struct_iter, DBUS_TYPE_STRING, &user_data[i].key ) ) { - pam_syslog( pamh, LOG_ERR, "Out Of Memory!" ); + if ( !dbus_message_iter_append_basic + ( &struct_iter, DBUS_TYPE_STRING, &user_data[i].key ) ) { return -ENOMEM; } - if ( !dbus_message_iter_append_basic( &struct_iter, DBUS_TYPE_STRING, &user_data[i].val ) ) { - pam_syslog( pamh, LOG_ERR, "Out Of Memory!" ); + if ( !dbus_message_iter_append_basic + ( &struct_iter, DBUS_TYPE_STRING, &user_data[i].val ) ) { return -ENOMEM; } ret = dbus_message_iter_close_container( &array_iter, &struct_iter ); if ( !ret ) { - pam_syslog( pamh, LOG_ERR, "failed to close struct container" ); return -ENOMEM; } } @@ -352,157 +263,263 @@ return 0; } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * - * @return -EINVAL or OK - * -*/ -static int cdbus_create_snap_unpack( pam_handle_t * pamh, DBusConnection * conn, DBusMessage * rsp_msg, uint32_t * snap_id_out ) +static int cdbus_create_snap_unpack( DBusConnection * conn, DBusMessage * rsp_msg, + uint32_t * snapshot_num ) { DBusMessageIter iter; int msg_type; const char *sig; msg_type = dbus_message_get_type( rsp_msg ); if ( msg_type == DBUS_MESSAGE_TYPE_ERROR ) { - pam_syslog( pamh, LOG_ERR, "create snap error response: %s", dbus_message_get_error_name( rsp_msg ) ); return -EINVAL; } if ( msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN ) { - pam_syslog( pamh, LOG_ERR, "unexpected create snap ret type: %d", msg_type ); return -EINVAL; } sig = dbus_message_get_signature( rsp_msg ); - if ( ( sig == NULL ) - || ( strcmp( sig, CDBUS_SIG_CREATE_SNAP_RSP ) != 0 ) ) { - pam_syslog( pamh, LOG_ERR, "bad create snap response sig: %s, " - "expected: %s", ( sig ? sig : "NULL" ), CDBUS_SIG_CREATE_SNAP_RSP ); + if ( ( sig == NULL ) || ( strcmp( sig, CDBUS_SIG_CREATE_SNAP_RSP ) != 0 ) ) { return -EINVAL; } /* read the parameters */ if ( !dbus_message_iter_init( rsp_msg, &iter ) ) { - pam_syslog( pamh, LOG_ERR, "Message has no arguments!" ); return -EINVAL; } - if ( cdbus_type_check_get( pamh, &iter, DBUS_TYPE_UINT32, snap_id_out ) ) { + if ( cdbus_type_check_get( &iter, DBUS_TYPE_UINT32, snapshot_num ) ) { return -EINVAL; } return 0; } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * @param - * - * @return -EINVAL or OK - * -*/ -static void cdbus_fill_user_data( pam_handle_t * pamh, struct dict ( *user_data )[], int *user_data_num, int user_data_max ) +static int cdbus_create_snapshot( const char *snapper_conf, createmode_t createmode, + const char *cleanup, uint32_t num_user_data, + const struct dict *user_data, const uint32_t * snapshot_num_in, + uint32_t * snapshot_num_out ) { - int fields[4] = { PAM_RUSER, PAM_RHOST, PAM_TTY, PAM_SERVICE }; - const char *names[4] = { "ruser", "rhost", "tty", "service" }; - for ( int i = 0; i < 4; ++i ) { - const char *readval = NULL; - int ret = pam_get_item( pamh, fields[i], ( const void ** )&readval ); - if ( ret == PAM_SUCCESS && readval ) { - ( *user_data )[*user_data_num].key = names[i]; - ( *user_data )[*user_data_num].val = readval; - if ( ( *user_data_num ) < user_data_max ) { - ( *user_data_num )++; - } - } - } -} + DBusError err; + dbus_error_init( &err ); -static void cleanup_snapshot_num( pam_handle_t * pamh, void *data, int error_status ) -{ - free( data ); -} + /* without a private connection setting uid/gui can be in vain, e.g. with gdm */ + + DBusConnection *conn = dbus_bus_get_private( DBUS_BUS_SYSTEM, &err ); + if ( dbus_error_is_set( &err ) ) { + dbus_error_free( &err ); + } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * @param - * - * @return -EINVAL or OK - * -*/ -static int cdbus_create_snap_call( pam_handle_t * pamh, const char *snapper_conf, createmode_t create_mode, const char *cleanup, - DBusConnection * conn ) -{ - int ret; DBusMessage *req_msg; - DBusMessage *rsp_msg; - DBusPendingCall *pending; - uint32_t *snap_id = malloc( sizeof( uint32_t ) ); -#ifdef PAM_SNAPPER_DEBUG - uint32_t *snap_id_check = NULL; -#endif - int user_data_num = 0; - enum { user_data_max = 6 }; - struct dict user_data[user_data_max]; - cdbus_fill_user_data( pamh, &user_data, &user_data_num, user_data_max ); - ret = cdbus_create_snap_pack( pamh, snapper_conf, create_mode, cleanup, user_data_num, user_data, &req_msg ); + int ret = cdbus_create_snap_pack( snapper_conf, createmode, cleanup, num_user_data, + user_data, snapshot_num_in, &req_msg ); if ( ret < 0 ) { - pam_syslog( pamh, LOG_ERR, "failed to pack create snap request" ); + dbus_connection_close( conn ); + dbus_connection_unref( conn ); return ret; } - ret = cdbus_msg_send( pamh, conn, req_msg, &pending ); + + DBusPendingCall *pending; + ret = cdbus_msg_send( conn, req_msg, &pending ); if ( ret < 0 ) { dbus_message_unref( req_msg ); + dbus_connection_close( conn ); + dbus_connection_unref( conn ); return ret; } - ret = cdbus_msg_recv( pamh, conn, pending, &rsp_msg ); + + DBusMessage *rsp_msg; + ret = cdbus_msg_recv( conn, pending, &rsp_msg ); if ( ret < 0 ) { dbus_message_unref( req_msg ); dbus_pending_call_unref( pending ); + dbus_connection_close( conn ); + dbus_connection_unref( conn ); return ret; } - ret = cdbus_create_snap_unpack( pamh, conn, rsp_msg, snap_id ); + + ret = cdbus_create_snap_unpack( conn, rsp_msg, snapshot_num_out ); if ( ret < 0 ) { - pam_syslog( pamh, LOG_ERR, "failed to unpack create snap response: %s", strerror( -ret ) ); dbus_message_unref( req_msg ); dbus_message_unref( rsp_msg ); + dbus_connection_close( conn ); + dbus_connection_unref( conn ); return ret; } - ret = pam_set_data( pamh, "pam_snapper_snapshot_num", snap_id, cleanup_snapshot_num ); - if ( ret != PAM_SUCCESS ) { - pam_syslog( pamh, LOG_ERR, "pam_set_data failed." ); - } -#ifdef PAM_SNAPPER_DEBUG - pam_syslog( pamh, LOG_DEBUG, "created new snapshot %u", *snap_id ); - pam_get_data( pamh, "pam_snapper_snapshot_num", ( const void ** )&snap_id_check ); - pam_syslog( pamh, LOG_DEBUG, "Check new snapshot: '%u'", *snap_id_check ); -#endif + dbus_message_unref( req_msg ); dbus_message_unref( rsp_msg ); + dbus_connection_close( conn ); + dbus_connection_unref( conn ); return 0; } /** - * ?? - * - * @param - * - * @return PAM_SUCCESS - * -*/ -static void cdbus_pam_options_setdefault( pam_options_t * options ) + * Special functions for pam_snapper + */ + +static int forker( pam_handle_t * pamh, uid_t uid, gid_t gid, const char *snapper_conf, + createmode_t createmode, const char *cleanup, uint32_t num_user_data, + const struct dict *user_data, const uint32_t * snapshot_num_in, + uint32_t * snapshot_num_out ) +{ + int fds[2]; + if ( pipe( fds ) != 0 ) { + pam_syslog( pamh, LOG_ERR, "pipe failed" ); + return -1; + } + + int child = fork( ); + if ( child == 0 ) { + + /* setting uid/gui affects other threads so it has to be done in a separate process */ + + if ( setegid( gid ) != 0 || seteuid( uid ) != 0 ) { + exit( EXIT_FAILURE ); + } + + close( fds[0] ); + + if ( cdbus_create_snapshot( snapper_conf, createmode, cleanup, num_user_data, + user_data, snapshot_num_in, snapshot_num_out ) != 0 ) + exit( EXIT_FAILURE ); + + if ( pam_modutil_write + ( fds[1], ( char * )snapshot_num_out, + sizeof( *snapshot_num_out ) ) != sizeof( *snapshot_num_out ) ) + exit( EXIT_FAILURE ); + + close( fds[1] ); + + exit( EXIT_SUCCESS ); + + } else if ( child > 0 ) { + + close( fds[1] ); + + int status; + int ret = waitpid( child, &status, 0 ); + + if ( ret == -1 ) { + pam_syslog( pamh, LOG_ERR, "waitpid failed" ); + close( fds[0] ); + return -1; + } + + if ( !WIFEXITED( status ) ) { + pam_syslog( pamh, LOG_ERR, "child exited abnormal" ); + close( fds[0] ); + return -1; + } + + if ( WEXITSTATUS( status ) != EXIT_SUCCESS ) { + pam_syslog( pamh, LOG_ERR, "child exited normal but with failure" ); + close( fds[0] ); + return -1; + } + + if ( pam_modutil_read + ( fds[0], ( char * )snapshot_num_out, + sizeof( *snapshot_num_out ) ) != sizeof( *snapshot_num_out ) ) { + pam_syslog( pamh, LOG_ERR, "reading snapshot_num_out failed" ); + close( fds[0] ); + return -1; + } + + close( fds[0] ); + + return 0; + + } else { + + pam_syslog( pamh, LOG_ERR, "fork failed" ); + return -1; + + } +} + +static void fill_user_data( pam_handle_t * pamh, struct dict ( *user_data )[], int *num_user_data, + int max_user_data ) +{ + int fields[4] = { PAM_RUSER, PAM_RHOST, PAM_TTY, PAM_SERVICE }; + const char *names[4] = { "ruser", "rhost", "tty", "service" }; + for ( int i = 0; i < 4; ++i ) { + const char *readval = NULL; + int ret = pam_get_item( pamh, fields[i], ( const void ** )&readval ); + if ( ret == PAM_SUCCESS && readval ) { + ( *user_data )[*num_user_data].key = names[i]; + ( *user_data )[*num_user_data].val = readval; + if ( ( *num_user_data ) < max_user_data ) { + ( *num_user_data )++; + } + } + } +} + +static void cleanup_snapshot_num( pam_handle_t * pamh, void *data, int error_status ) +{ + free( data ); +} + +static int get_ugid( pam_handle_t * pamh, const char *pam_user, uid_t * uid, gid_t * gid ) +{ + struct passwd pwd; + struct passwd *result; + + long bufsize = sysconf( _SC_GETPW_R_SIZE_MAX ); + char buf[bufsize]; + + if ( getpwnam_r( pam_user, &pwd, buf, bufsize, &result ) != 0 || result != &pwd ) { + pam_syslog( pamh, LOG_ERR, "getpwnam failed" ); + return -1; + } + + memset( pwd.pw_passwd, 0, strlen( pwd.pw_passwd ) ); + + *uid = pwd.pw_uid; + *gid = pwd.pw_gid; + + return 0; +} + +static int worker( pam_handle_t * pamh, const char *pam_user, const char *snapper_conf, + createmode_t createmode, const char *cleanup ) +{ + const int max_user_data = 5; + struct dict user_data[max_user_data]; + int num_user_data = 0; + fill_user_data( pamh, &user_data, &num_user_data, max_user_data ); + + uid_t uid; + gid_t gid; + if ( get_ugid( pamh, pam_user, &uid, &gid ) != 0 ) + return -1; + + uint32_t *snapshot_num_in = NULL; + uint32_t *snapshot_num_out = malloc( sizeof( *snapshot_num_out ) ); + + if ( createmode == createmode_post ) { + if ( pam_get_data + ( pamh, "pam_snapper_snapshot_num", + ( const void ** )&snapshot_num_in ) != PAM_SUCCESS ) { + pam_syslog( pamh, LOG_ERR, "getting previous snapshot_num failed" ); + return -1; + } + } + + if ( forker( pamh, uid, gid, snapper_conf, createmode, cleanup, num_user_data, user_data, + snapshot_num_in, snapshot_num_out ) != 0 ) + return -1; + + if ( pam_set_data + ( pamh, "pam_snapper_snapshot_num", snapshot_num_out, + cleanup_snapshot_num ) != PAM_SUCCESS ) { + pam_syslog( pamh, LOG_ERR, "pam_set_data failed" ); + } + + return 0; +} + +static void set_default_options( pam_options_t * options ) { options->homeprefix = "home_"; options->ignoreservices = "crond"; - options->ignoreusers = NULL; + options->ignoreusers = ""; options->rootasroot = false; options->ignoreroot = false; options->do_open = true; @@ -511,18 +528,11 @@ options->debug = false; } -/** - * ?? - * - * @param - * - * @return PAM status - * -*/ static int csv_contains( pam_handle_t * pamh, const char *haystack, const char *needle, bool debug ) { if ( debug ) { - pam_syslog( pamh, LOG_DEBUG, "csv_contains haystack: '%s' needle: '%s'", haystack, needle ); + pam_syslog( pamh, LOG_DEBUG, "csv_contains haystack: '%s' needle: '%s'", haystack, + needle ); } const size_t l = strlen( needle ); @@ -540,16 +550,8 @@ return strcmp( s, needle ) == 0; } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * @param - * -*/ -static void cdbus_pam_options_parser( pam_handle_t * pamh, pam_options_t * options, int argc, const char **argv ) +static void options_parser( pam_handle_t * pamh, pam_options_t * options, int argc, + const char **argv ) { for ( ; argc-- > 0; ++argv ) { if ( !strncmp( *argv, "homeprefix=", 11 ) ) { @@ -574,40 +576,33 @@ options->do_close = true; } else { pam_syslog( pamh, LOG_ERR, "unknown option: %s", *argv ); - pam_syslog( pamh, LOG_ERR, "valid options: debug homeprefix=<> ignoreservices=<> ignoreusers=<> " - "rootasroot ignoreroot openonly closeonly cleanup=" ); + pam_syslog( pamh, LOG_ERR, "valid options: debug homeprefix=<> " + "ignoreservices=<> ignoreusers=<> rootasroot ignoreroot " + "openonly closeonly cleanup=<>" ); } } + if ( options->rootasroot && options->ignoreroot ) { options->rootasroot = false; - pam_syslog( pamh, LOG_WARNING, "'ignoreroot' options shadows 'rootasroot'. 'rootasroot' will be ignored." ); + pam_syslog( pamh, LOG_WARNING, "'ignoreroot' options shadows 'rootasroot'. " + "'rootasroot' will be ignored." ); } + if ( options->debug ) { - pam_syslog( pamh, LOG_ERR, - "current settings: homeprefix=%s ignoreservices=%s ignoreusers=%s", - options->homeprefix, options->ignoreservices, options->ignoreusers ); + pam_syslog( pamh, LOG_ERR, "current settings: homeprefix='%s' ignoreservices='%s' " + "ignoreusers='%s' cleanup='%s'", options->homeprefix, + options->ignoreservices, options->ignoreusers, options->cleanup ); } } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * @param - * - * @return PAM_SUCCESS or PAM_IGNORE - * -*/ -static int cdbus_pam_check_ignore( pam_handle_t * pamh, const pam_options_t * options ) +static int check_ignore( pam_handle_t * pamh, const pam_options_t * options ) { if ( options->ignoreservices ) { const char *pam_service = NULL; int ret = pam_get_item( pamh, PAM_SERVICE, ( const void ** )&pam_service ); if ( ret != PAM_SUCCESS ) { - pam_syslog( pamh, LOG_ERR, "cannot get PAM_SERVICE: %s", strerror( -ret ) ); + pam_syslog( pamh, LOG_ERR, "cannot get PAM_SERVICE" ); return PAM_IGNORE; } if ( !pam_service ) { @@ -615,8 +610,13 @@ return PAM_IGNORE; } + if ( options->debug ) { + pam_syslog( pamh, LOG_DEBUG, "PAM_SERVICE is '%s'", pam_service ); + } + if ( options->ignoreservices ) { - if ( csv_contains( pamh, options->ignoreservices, pam_service, options->debug ) ) { + if ( csv_contains + ( pamh, options->ignoreservices, pam_service, options->debug ) ) { return PAM_IGNORE; } } @@ -627,7 +627,7 @@ const char *pam_user = NULL; int ret = pam_get_item( pamh, PAM_USER, ( const void ** )&pam_user ); if ( ret != PAM_SUCCESS ) { - pam_syslog( pamh, LOG_ERR, "cannot get PAM_USER: %s", strerror( -ret ) ); + pam_syslog( pamh, LOG_ERR, "cannot get PAM_USER" ); return PAM_IGNORE; } if ( !pam_user ) { @@ -635,6 +635,10 @@ return PAM_IGNORE; } + if ( options->debug ) { + pam_syslog( pamh, LOG_DEBUG, "PAM_USER is '%s'", pam_user ); + } + if ( options->ignoreusers ) { if ( csv_contains( pamh, options->ignoreusers, pam_user, options->debug ) ) { return PAM_IGNORE; @@ -650,217 +654,77 @@ return PAM_SUCCESS; } -/** - * - * - * -*/ -static int cdbus_pam_switch_to_user( pam_handle_t * pamh, struct passwd **user_entry, const char *real_user ) +static char *get_snapper_conf( const char *pam_user, const pam_options_t * options ) { - /* save current user */ - if ( ( ( *user_entry ) = getpwnam( real_user ) ) == NULL ) { - int ret = errno; - pam_syslog( pamh, LOG_ERR, "getpwnam( %s ) failed: %s", real_user, strerror( ret ) ); - return PAM_IGNORE; - } - memset( ( *user_entry )->pw_passwd, 0, strlen( ( *user_entry )->pw_passwd ) ); - - if ( setegid( ( *user_entry )->pw_gid ) == -1 ) { - int ret = errno; - pam_syslog( pamh, LOG_ERR, "setgid(%lu) failed: %s", ( unsigned long )( *user_entry )->pw_gid, strerror( ret ) ); - return PAM_IGNORE; - } - if ( seteuid( ( *user_entry )->pw_uid ) == -1 ) { - int ret = errno; - pam_syslog( pamh, LOG_ERR, "setuid(%lu) failed: %s", ( unsigned long )( *user_entry )->pw_uid, strerror( ret ) ); - return PAM_IGNORE; + char *snapper_conf = NULL; + if ( options->rootasroot && strcmp( pam_user, "root" ) == 0 ) { + snapper_conf = strdup( "root" ); + } else { + snapper_conf = malloc( strlen( options->homeprefix ) + strlen( pam_user ) + 1 ); + strcpy( snapper_conf, options->homeprefix ); + strcat( snapper_conf, pam_user ); } - return PAM_SUCCESS; + return snapper_conf; } -/** - * - * - * -*/ -static int cdbus_pam_drop_privileges( pam_handle_t * pamh, struct passwd **user_entry ) +static void pam_session( pam_handle_t * pamh, openclose_t openclose, int argc, const char **argv ) { - PAM_MODUTIL_DEF_PRIVS( privs ); - if ( pam_modutil_drop_priv( pamh, &privs, ( *user_entry ) ) ) { - int ret = errno; - pam_syslog( pamh, LOG_ERR, "pam_modutil_drop_priv (%lu) failed: %s", ( unsigned long )( *user_entry )->pw_uid, - strerror( ret ) ); - return PAM_IGNORE; - } - return PAM_SUCCESS; -} + pam_options_t options; + set_default_options( &options ); + options_parser( pamh, &options, argc, argv ); -/** - * - * - * -*/ -static int cdbus_pam_switch_from_user( pam_handle_t * pamh ) -{ - uid_t ruid, euid, suid; - gid_t rgid, egid, sgid; - getresuid( &ruid, &euid, &suid ); - getresgid( &rgid, &egid, &sgid ); - if ( setegid( sgid ) == -1 ) { - int ret = errno; - pam_syslog( pamh, LOG_ERR, "setgid(%lu) failed: %s", ( unsigned long )sgid, strerror( ret ) ); - } - if ( seteuid( suid ) == -1 ) { - int ret = errno; - pam_syslog( pamh, LOG_ERR, "setuid(%lu) failed: %s", ( unsigned long )suid, strerror( ret ) ); + if ( check_ignore( pamh, &options ) == PAM_IGNORE ) { + return; } - return PAM_SUCCESS; -} -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * @param - * @param - * - * @return -EINVAL or OK - * -*/ -static int cdbus_pam_session( pam_handle_t * pamh, openclose_t openclose, const char *real_user, int argc, const char **argv ) -{ - DBusConnection *conn; - int ret = -EINVAL; - char *real_user_config = NULL; - pam_options_t options; - cdbus_pam_options_setdefault( &options ); - cdbus_pam_options_parser( pamh, &options, argc, argv ); - ret = cdbus_pam_check_ignore( pamh, &options ); - if ( ret == PAM_IGNORE ) { - goto pam_snapper_ignore; - } - /* open the connection to the D-Bus */ - conn = cdbus_conn( pamh ); - if ( conn == NULL ) { - pam_syslog( pamh, LOG_ERR, "connect to D-Bus failed" ); - goto pam_snapper_ignore; + const char *pam_user = NULL; + int ret = pam_get_item( pamh, PAM_USER, ( const void ** )&pam_user ); + if ( ret != PAM_SUCCESS ) { + pam_syslog( pamh, LOG_ERR, "cannot get PAM_USER" ); + return; } - if ( !strcmp( real_user, "root" ) && options.rootasroot ) { - real_user_config = strdup( "root" ); - } else { - real_user_config = malloc( strlen( options.homeprefix ) + strlen( real_user ) + 1 ); - if ( !real_user_config ) { - goto pam_sm_open_session_err; - } - strcpy( real_user_config, options.homeprefix ); - strcat( real_user_config, real_user ); + if ( !pam_user ) { + pam_syslog( pamh, LOG_ERR, "PAM_USER is null" ); + return; + } + + char *snapper_conf = get_snapper_conf( pam_user, &options ); + if ( !snapper_conf ) { + return; } + if ( options.debug ) { pam_syslog( pamh, LOG_DEBUG, MODULE_NAME " version " VERSION ); - pam_syslog( pamh, LOG_DEBUG, "real_user_config='%s'", real_user_config ); + pam_syslog( pamh, LOG_DEBUG, "pam_user='%s', snapper_conf='%s'", pam_user, + snapper_conf ); } + if ( ( openclose == open_session ) && options.do_open ) { - ret = - cdbus_create_snap_call( pamh, real_user_config, options.do_close ? createmode_pre : createmode_single, options.cleanup, - conn ); + ret = worker( pamh, pam_user, snapper_conf, options.do_close ? createmode_pre : + createmode_single, options.cleanup ); } else if ( ( openclose == close_session ) && options.do_close ) { - ret = - cdbus_create_snap_call( pamh, real_user_config, options.do_open ? createmode_post : createmode_single, options.cleanup, - conn ); - } - if ( ret < 0 ) { - pam_syslog( pamh, LOG_ERR, "snapshot create call failed: %s", strerror( -ret ) ); - } - pam_sm_open_session_err: - if ( real_user_config ) { - free( real_user_config ); + ret = worker( pamh, pam_user, snapper_conf, options.do_open ? createmode_post : + createmode_single, options.cleanup ); } - dbus_connection_unref( conn ); - pam_snapper_ignore: - return PAM_SUCCESS; + + free( snapper_conf ); } /* - * HERE the PAM stuff starts + * PAM stuff starts here */ -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * @param - * - * @return PAM_SUCCESS (always) - * -*/ PAM_EXTERN int pam_sm_open_session( pam_handle_t * pamh, int flags, int argc, const char **argv ) { - int ret = -EINVAL; - const char *real_user = NULL; - struct passwd *user_entry; - ret = pam_get_item( pamh, PAM_USER, ( const void ** )&real_user ); - if ( ret != PAM_SUCCESS ) { - pam_syslog( pamh, LOG_ERR, "cannot get PAM_USER: %s", strerror( -ret ) ); - goto pam_snapper_skip; - } - if ( !real_user ) { - goto pam_snapper_skip; - } - /* no need to proceed as root */ - if ( cdbus_pam_switch_to_user( pamh, &user_entry, real_user ) == PAM_IGNORE ) { - goto pam_snapper_skip; - } - if ( cdbus_pam_drop_privileges( pamh, &user_entry ) == PAM_IGNORE ) { - goto pam_snapper_skip; - } - /* do the real stuff */ - cdbus_pam_session( pamh, open_session, real_user, argc, argv ); - /* go back to original user */ - cdbus_pam_switch_from_user( pamh ); - pam_snapper_skip: + pam_session( pamh, open_session, argc, argv ); + return PAM_SUCCESS; } -/** - * ?? - * - * @param pamh PAM handle - * @param - * @param - * @param - * - * @return PAM_SUCCESS (always) - * -*/ PAM_EXTERN int pam_sm_close_session( pam_handle_t * pamh, int flags, int argc, const char **argv ) { - int ret = -EINVAL; - const char *real_user = NULL; - struct passwd *user_entry; - ret = pam_get_item( pamh, PAM_USER, ( const void ** )&real_user ); - if ( ret != PAM_SUCCESS ) { - pam_syslog( pamh, LOG_ERR, "cannot get PAM_USER: %s", strerror( -ret ) ); - goto pam_snapper_skip; - } - if ( !real_user ) { - goto pam_snapper_skip; - } - /* no need to proceed as root */ - if ( cdbus_pam_switch_to_user( pamh, &user_entry, real_user ) == PAM_IGNORE ) { - goto pam_snapper_skip; - } - if ( cdbus_pam_drop_privileges( pamh, &user_entry ) == PAM_IGNORE ) { - goto pam_snapper_skip; - } - /* do the real stuff */ - cdbus_pam_session( pamh, close_session, real_user, argc, argv ); - /* go back to original user */ - cdbus_pam_switch_from_user( pamh ); - pam_snapper_skip: + pam_session( pamh, close_session, argc, argv ); + return PAM_SUCCESS; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/snapper-0.1.4/snapper/FileUtils.cc new/snapper-0.1.4/snapper/FileUtils.cc --- old/snapper-0.1.4/snapper/FileUtils.cc 2013-04-22 16:26:33.000000000 +0200 +++ new/snapper-0.1.4/snapper/FileUtils.cc 2013-05-31 17:41:33.000000000 +0200 @@ -68,6 +68,7 @@ y2err("not a directory path:" << base_path); throw IOErrorException(); } + #ifdef ENABLE_XATTRS setXaStatus(); #endif @@ -95,6 +96,7 @@ close(dirfd); throw IOErrorException(); } + #ifdef ENABLE_XATTRS xastatus = dir.xastatus; #endif @@ -104,12 +106,13 @@ SDir::SDir(const SDir& dir) : base_path(dir.base_path), path(dir.path) { - dirfd = dup(dir.dirfd); + dirfd = fcntl(dir.dirfd, F_DUPFD_CLOEXEC, 0); if (dirfd == -1) { - y2err("dup failed" << " error:" << stringerror(errno)); + y2err("fcntl(F_DUPFD_CLOEXEC) failed error:" << stringerror(errno)); throw IOErrorException(); } + #ifdef ENABLE_XATTRS xastatus = dir.xastatus; #endif @@ -121,16 +124,17 @@ { if (this != &dir) { -#ifdef ENABLE_XATTRS - xastatus = dir.xastatus; -#endif ::close(dirfd); - dirfd = dup(dir.dirfd); + dirfd = fcntl(dir.dirfd, F_DUPFD_CLOEXEC, 0); if (dirfd == -1) { - y2err("dup failed" << " error:" << stringerror(errno)); + y2err("fcntl(F_DUPFD_CLOEXEC) failed error:" << stringerror(errno)); throw IOErrorException(); } + +#ifdef ENABLE_XATTRS + xastatus = dir.xastatus; +#endif } return *this; @@ -146,11 +150,11 @@ SDir SDir::deepopen(const SDir& dir, const string& name) { - string::size_type pos = name.find('/'); - if (pos == string::npos) - return SDir(dir, name); + string::size_type pos = name.find('/'); + if (pos == string::npos) + return SDir(dir, name); - return deepopen(SDir(dir, string(name, 0, pos)), string(name, pos + 1)); + return deepopen(SDir(dir, string(name, 0, pos)), string(name, pos + 1)); } @@ -185,10 +189,10 @@ vector<string> SDir::entries(entries_pred_t pred) const { - int fd = dup(dirfd); + int fd = fcntl(dirfd, F_DUPFD_CLOEXEC, 0); if (fd == -1) { - y2err("dup failed" << " error:" << stringerror(errno)); + y2err("fcntl(F_DUPFD_CLOEXEC) failed error:" << stringerror(errno)); throw IOErrorException(); } @@ -410,18 +414,15 @@ assert(path.find('/') == string::npos); assert(path != ".."); - int fd = ::openat(dirfd, path.c_str(), O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC); + int fd = ::openat(dirfd, path.c_str(), O_RDONLY | O_NOFOLLOW | O_NONBLOCK | O_NOATIME | + O_CLOEXEC); if (fd >= 0) { ssize_t r1 = ::flistxattr(fd, list, size); - close(fd); + ::close(fd); return r1; } - else if (errno != ELOOP) - { - return -1; - } - else + else if (errno == ELOOP || errno == ENXIO || errno == EWOULDBLOCK) { boost::lock_guard<boost::mutex> lock(cwd_mutex); @@ -436,6 +437,10 @@ chdir("/"); return r2; } + else + { + return -1; + } } @@ -445,18 +450,15 @@ assert(path.find('/') == string::npos); assert(path != ".."); - int fd = ::openat(dirfd, path.c_str(), O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC); + int fd = ::openat(dirfd, path.c_str(), O_RDONLY | O_NOFOLLOW | O_NONBLOCK | O_NOATIME | + O_CLOEXEC); if (fd >= 0) { ssize_t r1 = ::fgetxattr(fd, name, value, size); - close(fd); + ::close(fd); return r1; } - else if (errno != ELOOP) - { - return -1; - } - else + else if (errno == ELOOP || errno == ENXIO || errno == EWOULDBLOCK) { boost::lock_guard<boost::mutex> lock(cwd_mutex); @@ -471,6 +473,10 @@ chdir("/"); return r2; } + else + { + return -1; + } } @@ -488,7 +494,8 @@ } else { - y2err("Couldn't get extended attributes status for " << base_path << "/" << path << stringerror(errno)); + y2err("Couldn't get extended attributes status for " << base_path << "/" << + path << stringerror(errno)); throw IOErrorException(); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/snapper-0.1.4/snapper/Makefile.am new/snapper-0.1.4/snapper/Makefile.am --- old/snapper-0.1.4/snapper/Makefile.am 2013-05-03 09:56:33.000000000 +0200 +++ new/snapper-0.1.4/snapper/Makefile.am 2013-05-29 14:31:34.000000000 +0200 @@ -53,7 +53,7 @@ libsnapper_la_LDFLAGS = -version-info @LIBVERSION_INFO@ -libsnapper_la_LIBADD = -lboost_thread-mt -lxml2 -lz -lm +libsnapper_la_LIBADD = -lboost_thread-mt -lboost_system-mt -lxml2 -lz -lm pkgincludedir = $(includedir)/snapper diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/snapper-0.1.4/snapper/Makefile.in new/snapper-0.1.4/snapper/Makefile.in --- old/snapper-0.1.4/snapper/Makefile.in 2013-05-03 09:56:56.000000000 +0200 +++ new/snapper-0.1.4/snapper/Makefile.in 2013-05-31 17:41:56.000000000 +0200 @@ -334,7 +334,7 @@ SnapperDefines.h $(TMP_XA) $(am__append_1) $(am__append_2) \ $(am__append_3) libsnapper_la_LDFLAGS = -version-info @LIBVERSION_INFO@ -libsnapper_la_LIBADD = -lboost_thread-mt -lxml2 -lz -lm +libsnapper_la_LIBADD = -lboost_thread-mt -lboost_system-mt -lxml2 -lz -lm pkginclude_HEADERS = \ Factory.h \ Snapper.h \ -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
