[sudo-workers] PAM and return of init_session ignored ?

aurel aurel at aurel-r.fr
Mon Aug 10 10:26:47 MDT 2015


Hi,

I'm developing a PAM module for/auth/  and/session/. When my module return PAM_AUTH_ERR
to sudoers, the command is not executed. But when the/session/  return PAM_SESSION_ERR,
the command is executed anyway. Why ?

However, in source code (sudo-1.8.10p3), a session error causes EXIT_FAILURE in parent before forking.
But the macro AUTH_FAILURE and AUTH_FATALdo not have the same value  (see the comments) :


(sudo/plugins/sudoers/auth/pam.c)

|sudo_pam_begin_session(struct passwd *pw, char **user_envp[], sudo_auth *auth)||
||{||
||	...||
	
||	if (def_pam_session) {
         *pam_status = pam_open_session(pamh, 0);
         if (*pam_status != PAM_SUCCESS) {   /* PAM_SUCCESS = 0 */
             (void) pam_end(pamh, *pam_status | PAM_DATA_SILENT);
             pamh = NULL;
             status = AUTH_FAILURE;  /* AUTH_FAILURE = 1 */
             goto done;
         }
     }

	...
	done:		
||  	    debug_return_int(status);||   /* return 1 */
||}|



called by
(sudo/plugins/sudoers/auth/sudo_auth.c)

|static sudo_auth auth_switch[] = {||
||/* Standalone entries first */||
||#ifdef HAVE_PAM||
||     AUTH_ENTRY("pam", FLAG_STANDALONE, sudo_pam_init, NULL, sudo_pam_verify, sudo_pam_cleanup, sudo_pam_begin_session, sudo_pam_end_session)||
||#endif||
||	...||
||}||
|...
  |int sudo_auth_begin_session(struct passwd *pw, char **user_env[])||
||{||
||     sudo_auth *auth;||
||     int status = AUTH_SUCCESS;||
||     debug_decl(sudo_auth_begin_session, SUDO_DEBUG_AUTH)||
||
||     for (auth = auth_switch; auth->name; auth++) {||
||         if (auth->begin_session && !IS_DISABLED(auth)) {||
||             status = (auth->begin_session)(pw, user_env, auth);  /* call|||||sudo_pam_begin_session|  */
||             if (status == AUTH_FATAL) /* AUTH_FATAL = 3  ???!!! if|||sudo_pam_begin_session return error (1) status = 1|*/||
||                 break;          /* assume error msg already printed */||
||         }||
||     }||
||     debug_return_int(status == AUTH_FATAL ? -1 : 1);  /* So always return 1 ?! */||
||}||
|


called by
(sudo/plugins/sudoers/policy.c)

|static int||
||sudoers_policy_init_session(struct passwd *pwd, char **user_env[])||
||{||
||     debug_decl(sudoers_policy_init_session, SUDO_DEBUG_PLUGIN)||
||
||     /* user_env is only specified for API version 1.2 and higher. */||
||     if (sudo_version < SUDO_API_MKVERSION(1, 2))||
||         user_env = NULL;||
||
||     if (fatal_setjmp() != 0) {||
||         /* called via fatal(), fatalx() or log_fatal() */||
||         fatal_disable_setjmp();||
||         debug_return_bool(-1);||
||     }||
||
||     debug_return_bool(sudo_auth_begin_session(pwd, user_env));||
||}|

|...||
||
||__dso_public struct policy_plugin sudoers_policy = {||
||     SUDO_POLICY_PLUGIN,||
||     SUDO_API_VERSION,||
||     sudoers_policy_open,||
||     sudoers_policy_close,||
||     sudoers_policy_version,||
||     sudoers_policy_check,||
||     sudoers_policy_list,||
||     sudoers_policy_validate,||
||     sudoers_policy_invalidate,||
||     sudoers_policy_init_session,  /*  (*init_session)||   */
||     sudoers_policy_register_hooks||
||};|



called by
(sudo/src/sudo.c)

|int||
||policy_init_session(struct command_details *details)||
||{||
||     int rval = true;||
||     debug_decl(policy_init_session, SUDO_DEBUG_PCOMM)||
||
||     if (policy_plugin.u.policy->init_session) {||
||         /*||
||          * Backwards compatibility for older API versions||
||          */||
||         switch (policy_plugin.u.generic->version) {||
||         case SUDO_API_MKVERSION(1, 0):||
||         case SUDO_API_MKVERSION(1, 1):||
||             rval = policy_plugin.u.policy_1_0->init_session(details->pw);||
||             break;||
||         default:||
||             rval = policy_plugin.u.policy->init_session(details->pw,||
||                 &details->envp);||
||         }||
||     }||
||     debug_return_bool(rval);||
||}||
||
||
|and finally
(sudo/src/exec.c)

|static int fork_cmnd(struct command_details *details, int sv[2])||
||{||
||	...||
||     ||if (policy_init_session(details) != true)||
||         fatalx(U_("policy plugin failed session initialization"));|||||/* exit(EXIT_FAILURE); OR siglongjmp(fatal_jmp, 1); ... but return is always true */|
||     ||
||     cmnd_pid = sudo_debug_fork();||
||     switch (cmnd_pid) {||
||     case -1:||
||         fatal(U_("unable to fork"));||
||         break;||
||     case 0:||
||         /* child */||
||         close(sv[0]);||
||         close(signal_pipe[0]);||
||         close(signal_pipe[1]);||
||         fcntl(sv[1], F_SETFD, FD_CLOEXEC);||
||         exec_cmnd(details, &cstat, sv[1]);||
||         send(sv[1], &cstat, sizeof(cstat), 0);||
||         sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1);||
||         _exit(1);||
||     }||
||     sudo_debug_printf(SUDO_DEBUG_INFO, "executed %s, pid %d", details->command,||
||         (int)cmnd_pid);||
||     debug_return_int(cmnd_pid);||
||}||
|


I have not tried it with gdb yet...

To reproduce : (/etc/pam.d/sudo)
@include common-auth
@include common-account
session	required	pam_deny.so
@include common-session-noninteractive


If it's normal, why ? And how can I stop sudo to not run the command when/session/  return PAM_SESSION_ERR ?

Thanks and sorry for my bad english.




More information about the sudo-workers mailing list