35 #include <sys/types.h>
45 char * strdup_(
const char * p )
48 char * copy =
static_cast<char*
>( std::malloc(std::strlen(p)+1U) ) ;
50 std::strcpy( copy , p ) ;
66 typedef struct pam_conv Conversation ;
69 enum { MAGIC = 3456 } ;
80 PamImp(
G::Pam & pam ,
const std::string & app ,
const std::string & user ,
bool silent ) ;
85 void check(
const std::string & ,
int )
const ;
91 std::string
name()
const ;
94 static int converse(
int n ,
const struct pam_message ** in ,
struct pam_response ** out ,
void * vp ) ;
95 static void delay(
int ,
unsigned ,
void * ) ;
96 static std::string decodeStyle(
int pam_style ) ;
97 static void release(
struct pam_response * ,
size_t ) ;
108 G_DEBUG(
"G::PamImp::ctor: [" << application <<
"] [" << user <<
"]" ) ;
111 m_conv.appdata_ptr = this ;
112 m_rc = ::pam_start( application.c_str() , user.c_str() , &
m_conv , &
m_hpam ) ;
113 if(
m_rc != PAM_SUCCESS )
119 #ifdef PAM_FAIL_DELAY
120 m_rc = ::pam_set_item(
m_hpam , PAM_FAIL_DELAY , reinterpret_cast<const void*>(delay) ) ;
121 if(
m_rc != PAM_SUCCESS )
134 ::pam_end( m_hpam , m_rc ) ;
152 std::string G::PamImp::decodeStyle(
int pam_style )
154 std::string defolt = std::string(
"#" ) +
G::Str::fromInt( pam_style ) ;
155 if( pam_style == PAM_PROMPT_ECHO_OFF )
return "password" ;
156 if( pam_style == PAM_PROMPT_ECHO_ON )
return "prompt" ;
157 if( pam_style == PAM_ERROR_MSG )
return "error" ;
158 if( pam_style == PAM_TEXT_INFO )
return "info" ;
165 if( silent() ) flags |= PAM_SILENT ;
166 if( require_token ) flags |= PAM_DISALLOW_NULL_AUTHTOK ;
167 m_rc = ::pam_authenticate( hpam() , flags ) ;
168 #ifdef PAM_INCOMPLETE
169 if( m_rc == PAM_INCOMPLETE )
173 check(
"pam_authenticate" , m_rc ) ;
179 const void * vp = NULL ;
180 m_rc = ::pam_get_item( hpam() , PAM_USER , &vp ) ;
181 check(
"pam_get_item" , m_rc ) ;
182 const char * cp =
reinterpret_cast<const char*
>(vp) ;
183 return std::string( cp ? cp :
"" ) ;
190 if( silent() ) flags |= PAM_SILENT ;
191 m_rc = ::pam_setcred( hpam() , flags ) ;
192 check(
"pam_setcred" , m_rc ) ;
198 if( silent() ) flags |= PAM_SILENT ;
199 if( require_token ) flags |= PAM_DISALLOW_NULL_AUTHTOK ;
200 m_rc = ::pam_acct_mgmt( hpam() , flags ) ;
201 check(
"pam_acct_mgmt" , m_rc ) ;
204 void G::PamImp::release(
struct pam_response * rsp ,
size_t n )
208 for(
size_t i = 0U ; i < n ; i++ )
210 if( rsp[i].resp != NULL )
211 std::free( rsp[i].resp ) ;
217 int G::PamImp::converse(
int n_in ,
const struct pam_message ** in ,
struct pam_response ** out ,
void * vp )
221 size_t n = n_in < 0 ? size_t(0U) : static_cast<size_t>(n_in) ;
229 static bool warned = false ;
232 G_WARNING(
"PamImp::converse: received a complex pam converse() structure: proceed with caution" ) ;
238 struct pam_response * rsp = NULL ;
241 G_DEBUG(
"G::Pam::converse: " << n <<
" item(s)" ) ;
242 PamImp * This =
reinterpret_cast<PamImp*
>(vp) ;
243 G_ASSERT( This->m_magic == MAGIC ) ;
249 ItemArray array( n ) ;
250 for(
size_t i = 0U ; i < n ; i++ )
252 std::string & s1 =
const_cast<std::string&
>(array[i].in_type) ;
253 s1 = decodeStyle( in[i]->msg_style ) ;
255 std::string & s2 =
const_cast<std::string&
>(array[i].in) ;
256 s2 = std::string(in[i]->msg ? in[i]->msg :
"") ;
258 array[i].out_defined = false ;
263 This->m_pam.converse( array ) ;
269 rsp =
reinterpret_cast<struct pam_response*
>( std::malloc(n*
sizeof(
struct pam_response)) ) ;
271 throw std::bad_alloc() ;
272 for(
size_t j = 0U ; j < n ; j++ )
277 for(
size_t i = 0U ; i < n ; i++ )
279 rsp[i].resp_retcode = 0 ;
280 if( array[i].out_defined )
282 char * response = strdup_( array[i].out.c_str() ) ;
283 if( response == NULL )
284 throw std::bad_alloc() ;
285 rsp[i].resp = response ;
290 G_DEBUG(
"G::Pam::converse: complete" ) ;
295 G_ERROR(
"G::Pam::converse: exception" ) ;
297 return PAM_CONV_ERR ;
301 void G::PamImp::delay(
int status ,
unsigned delay_usec ,
void * pam_vp )
305 G_DEBUG(
"G::Pam::delay: status=" << status <<
", delay=" << delay_usec ) ;
306 if( status != PAM_SUCCESS )
308 PamImp * This =
reinterpret_cast<PamImp*
>(pam_vp) ;
311 G_ASSERT( This->m_magic == MAGIC ) ;
312 This->m_pam.delay( delay_usec ) ;
318 G_ERROR(
"G::Pam::delay: exception" ) ;
325 if( silent() ) flags |= PAM_SILENT ;
326 m_rc = ::pam_open_session( hpam() , flags ) ;
327 check(
"pam_open_session" , m_rc ) ;
333 if( silent() ) flags |= PAM_SILENT ;
334 m_rc = ::pam_close_session( hpam() , flags ) ;
335 check(
"pam_close_session" , m_rc ) ;
340 return rc == PAM_SUCCESS ;
346 throw Error( op , rc , ::pam_strerror(hpam(),rc) ) ;
351 G::Pam::Pam(
const std::string & application ,
const std::string & user ,
bool silent ) :
352 m_imp( new
PamImp(*this,application,user,silent) )
363 G_DEBUG(
"G::Pam::authenticate" ) ;
364 return m_imp->authenticate( require_token ) ;
369 G_DEBUG(
"G::Pam::checkAccount" ) ;
370 return m_imp->checkAccount( require_token ) ;
375 G_DEBUG(
"G::Pam::establishCredentials" ) ;
376 m_imp->setCredentials( PAM_ESTABLISH_CRED ) ;
381 G_DEBUG(
"G::Pam::openSession" ) ;
382 m_imp->openSession() ;
387 G_DEBUG(
"G::Pam::closeSession" ) ;
388 m_imp->closeSession() ;
393 m_imp->setCredentials( PAM_DELETE_CRED ) ;
398 m_imp->setCredentials( PAM_REINITIALIZE_CRED ) ;
403 m_imp->setCredentials( PAM_REFRESH_CRED ) ;
410 typedef struct timeval Timeval ;
413 timeout.tv_usec = usec ;
414 ::select( 0 , NULL , NULL , NULL , &timeout ) ;
420 return m_imp->name() ;
PamImp(G::Pam &pam, const std::string &app, const std::string &user, bool silent)
void closeSession()
Closes a session.
std::string name() const
Returns the authenticated user name.
void check(const std::string &, int) const
void refreshCredentials()
Refreshes credentials.
static std::string fromInt(int i)
Converts int 'i' to a string.
void checkAccount(bool require_token)
Does "account management", checking that the authenticated user is currently allowed to use the syste...
void reinitialiseCredentials()
Reinitialises credentials.
std::vector< Item > ItemArray
void openSession()
Starts a session.
An exception class used by G::Pam.
void establishCredentials()
Embues the authenticated user with their credentials, such as "tickets" in the form of environment va...
bool authenticate(bool require_token)
Authenticates the user.
Pam(const std::string &app, const std::string &user, bool silent)
Constructor.
virtual void delay(unsigned int usec)=0
Called when the pam library wants the application to introduce a delay to prevent brute-force attacks...
A pimple-pattern implementation class for Pam.
virtual ~Pam()
Destructor.
void deleteCredentials()
Deletes credentials.
A thin abstract interface to the system PAM library.