The crux of the problem is that sudo in Precise (v1.8.3p1) is a massively re-factored code-base compared to v1.7.4p6 in Oneiric.
From what I've been able to deduce sudo has been massively re-written to use a 'plugin' architecture to easily support many different authorisation mechanisms. This seems to have divorced the sudo timestamp checking from the PAM authentication logic such that if a valid sudo timestamp exists for the user then a PAM session (via pam_open_session() ) is never created.
The sudo session closing logic however doesn't know this and blindly goes on to try and close the PAM session (via pam_close_session() ) which discovers that the PAM Config hasn't been initialised during authentication and hits this assert.
Next I'm going to look at the current upstream sudo in detail to see if this issue has been resolved and whether it is possible to backport any change.
I've tracked the call paths in Precise's v1.8.3p1 and provide it here.
plugins/sudoers/sudoers.c::sudoers_policy_main()
/* Require a password if sudoers says so. */
rval = check_user(validated, sudo_mode);
if (rval != TRUE)
goto done;
plugins/sudoers/check.c::check_user()
status = timestamp_status(timestampdir, timestampfile, user_name,
TS_MAKE_DIRS);
////**** TJ: if the timestamp is valid status == TS_CURRENT
////**** this code never calls verify_user() so the PAM session is not created.
plugins/sudoers/auth/sudo_auth.h
typedef struct sudo_auth {
int flags; /* various flags, see below */
int status; /* status from verify routine */
char *name; /* name of the method as a string */
void *data; /* method-specific data pointer */
int (*init)(struct passwd *pw, struct sudo_auth *auth);
int (*setup)(struct passwd *pw, char **prompt, struct sudo_auth *auth);
int (*verify)(struct passwd *pw, char *p, struct sudo_auth *auth);
int (*cleanup)(struct passwd *pw, struct sudo_auth *auth);
int (*begin_session)(struct passwd *pw, struct sudo_auth *auth);
int (*end_session)(struct passwd *pw, struct sudo_auth *auth);
} sudo_auth;
The crux of the problem is that sudo in Precise (v1.8.3p1) is a massively re-factored code-base compared to v1.7.4p6 in Oneiric.
From what I've been able to deduce sudo has been massively re-written to use a 'plugin' architecture to easily support many different authorisation mechanisms. This seems to have divorced the sudo timestamp checking from the PAM authentication logic such that if a valid sudo timestamp exists for the user then a PAM session (via pam_open_session() ) is never created.
The sudo session closing logic however doesn't know this and blindly goes on to try and close the PAM session (via pam_close_session() ) which discovers that the PAM Config hasn't been initialised during authentication and hits this assert.
Next I'm going to look at the current upstream sudo in detail to see if this issue has been resolved and whether it is possible to backport any change.
I've tracked the call paths in Precise's v1.8.3p1 and provide it here.
plugins/ sudoers/ sudoers. c::sudoers_ policy_ main() validated, sudo_mode);
/* Require a password if sudoers says so. */
rval = check_user(
if (rval != TRUE)
goto done;
plugins/ sudoers/ check.c: :check_ user() status( timestampdir, timestampfile, user_name,
status = timestamp_
TS_MAKE_DIRS);
////**** TJ: if the timestamp is valid status == TS_CURRENT
////**** this code never calls verify_user() so the PAM session is not created.
if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) { user(auth_ pw, prompt);
...
rval = verify_
plugins/ sudoers/ auth/sudo_ auth.c: :verify_ user()
while (--counter) {
...
/* Call authentication functions. */
for (auth = auth_switch; auth->name; auth++) {
if (IS_DISABLED(auth))
continue;
if (NEEDS_USER(auth)) PERM_USER) ;
set_perms(
success = auth->status = (auth->verify)(pw, p, auth);
plugins/ sudoers/ auth/sudo_ auth.h session) (struct passwd *pw, struct sudo_auth *auth); (struct passwd *pw, struct sudo_auth *auth);
typedef struct sudo_auth {
int flags; /* various flags, see below */
int status; /* status from verify routine */
char *name; /* name of the method as a string */
void *data; /* method-specific data pointer */
int (*init)(struct passwd *pw, struct sudo_auth *auth);
int (*setup)(struct passwd *pw, char **prompt, struct sudo_auth *auth);
int (*verify)(struct passwd *pw, char *p, struct sudo_auth *auth);
int (*cleanup)(struct passwd *pw, struct sudo_auth *auth);
int (*begin_
int (*end_session)
} sudo_auth;
plugins/ sudoers/ auth/sudo_ auth.c ENTRY(" pam", FLAG_STANDALONE, pam_init, NULL, pam_verify, pam_cleanup, pam_begin_session, pam_end_session)
static sudo_auth auth_switch[] = {
/* Standalone entries first */
#ifdef HAVE_PAM
AUTH_
#endif
plugins/ sudoers/ auth/pam. c::pam_ verify( ) e(pamh, PAM_SILENT);
*pam_status = pam_authenticat
...
src/sudo. c::exec_ setup() init_session( &policy_ plugin, pw) != TRUE)
if (policy_
goto done;
src/sudo. c::policy_ init_session( ) >u.policy- >init_session) >u.policy- >init_session( pwd);
{
if (plugin-
return plugin-
plugin/ sudoers/ sudoers. c::sudoers_ policy_ init_session( ) begin_session( pwd);
return sudo_auth_
plugins/ sudoers/ auth/sudo_ auth.c: :sudo_auth_ begin_session( ) begin_session && !IS_DISABLED(auth)) { begin_session) (pw, auth);
for (auth = auth_switch; auth->name; auth++) {
if (auth->
status = (auth->