def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True):
        """username and password authentication for the given service.

           Returns True for success, or False for failure.

           self.code (integer) and self.reason (string) are always stored and may
           be referenced for the reason why authentication failed. 0/'Success' will
           be stored for success.

           Python3 expects bytes() for ctypes inputs.  This function will make
           necessary conversions using the supplied encoding.

        Inputs:
          username: username to authenticate
          password: password in plain text
          service:  PAM service to authenticate against, defaults to 'login'

        Returns:
          success:  True
          failure:  False
        """

        @conv_func
        def my_conv(n_messages, messages, p_response, app_data):
            """Simple conversation function that responds to any
               prompt where the echo is off with the supplied password"""
            # Create an array of n_messages response objects
            addr = calloc(n_messages, sizeof(PamResponse))
            response = cast(addr, POINTER(PamResponse))
            p_response[0] = response
            for i in range(n_messages):
                if messages[i].contents.msg_style == PAM_PROMPT_ECHO_OFF:
                    dst = calloc(len(password)+1, sizeof(c_char))
                    memmove(dst, cpassword, len(password))
                    response[i].resp = dst
                    response[i].resp_retcode = 0
            return 0

        # python3 ctypes prefers bytes
        if sys.version_info >= (3,):
            if isinstance(username, str): username = username.encode(encoding)
            if isinstance(password, str): password = password.encode(encoding)
            if isinstance(service, str):  service  = service.encode(encoding)
        else:
            if isinstance(username, unicode):
                username = username.encode(encoding)
            if isinstance(password, unicode):
                password = password.encode(encoding)
            if isinstance(service, unicode):
                service  = service.encode(encoding)

        if b'\x00' in username or b'\x00' in password or b'\x00' in service:
            self.code = 4  # PAM_SYSTEM_ERR in Linux-PAM
            self.reason = 'strings may not contain NUL'
            return False

        # do this up front so we can safely throw an exception if there's
        # anything wrong with it
        cpassword = c_char_p(password)

        handle = PamHandle()
        conv   = PamConv(my_conv, 0)
        retval = pam_start(service, username, byref(conv), byref(handle))

        if retval != 0:
            # This is not an authentication error, something has gone wrong starting up PAM
            self.code   = retval
            self.reason = "pam_start() failed"
            return False

        retval = pam_authenticate(handle, 0)
        auth_success = retval == 0

        if auth_success and resetcreds:
            retval = pam_setcred(handle, PAM_REINITIALIZE_CRED);

        # store information to inform the caller why we failed
        self.code   = retval
        self.reason = pam_strerror(handle, retval)
        if sys.version_info >= (3,):
            self.reason = self.reason.decode(encoding)

        if hasattr(libpam, 'pam_end'):
            pam_end(handle, retval)

        return auth_success
def authenticate ( self , username , password , service = 'login' , encoding = 'utf-8' , resetcreds = True ) : @ conv_func def my_conv ( n_messages , messages , p_response , app_data ) : addr = calloc ( n_messages , sizeof ( PamResponse ) ) response = cast ( addr , POINTER ( PamResponse ) ) p_response [ 0 ] = response for i in range ( n_messages ) : if messages [ i ] . contents . msg_style == PAM_PROMPT_ECHO_OFF : dst = calloc ( len ( password ) + 1 , sizeof ( c_char ) ) memmove ( dst , cpassword , len ( password ) ) response [ i ] . resp = dst response [ i ] . resp_retcode = 0 return 0 if sys . version_info >= ( 3 , ) : if isinstance ( username , str ) : username = username . encode ( encoding ) if isinstance ( password , str ) : password = password . encode ( encoding ) if isinstance ( service , str ) : service = service . encode ( encoding ) else : if isinstance ( username , unicode ) : username = username . encode ( encoding ) if isinstance ( password , unicode ) : password = password . encode ( encoding ) if isinstance ( service , unicode ) : service = service . encode ( encoding ) if b'\x00' in username or b'\x00' in password or b'\x00' in service : self . code = 4 self . reason = 'strings may not contain NUL' return False cpassword = c_char_p ( password ) handle = PamHandle ( ) conv = PamConv ( my_conv , 0 ) retval = pam_start ( service , username , byref ( conv ) , byref ( handle ) ) if retval != 0 : self . code = retval self . reason = "pam_start() failed" return False retval = pam_authenticate ( handle , 0 ) auth_success = retval == 0 if auth_success and resetcreds : retval = pam_setcred ( handle , PAM_REINITIALIZE_CRED ) ; self . code = retval self . reason = pam_strerror ( handle , retval ) if sys . version_info >= ( 3 , ) : self . reason = self . reason . decode ( encoding ) if hasattr ( libpam , 'pam_end' ) : pam_end ( handle , retval ) return auth_success
username and password authentication for the given service.

           Returns True for success, or False for failure.

           self.code (integer) and self.reason (string) are always stored and may
           be referenced for the reason why authentication failed. 0/'Success' will
           be stored for success.

           Python3 expects bytes() for ctypes inputs.  This function will make
           necessary conversions using the supplied encoding.

        Inputs:
          username: username to authenticate
          password: password in plain text
          service:  PAM service to authenticate against, defaults to 'login'

        Returns:
          success:  True
          failure:  False