117 lines
3.3 KiB
C++
117 lines
3.3 KiB
C++
#pragma once
|
|
#ifdef __sun
|
|
#include <security/pam_appl.h>
|
|
#include <security/pam_modules.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
static int pam_vprompt_compat(pam_handle_t *pamh, int style, char **out,
|
|
const char *fmt, va_list ap) {
|
|
const struct pam_conv *conv = NULL;
|
|
if (pam_get_item(pamh, PAM_CONV, (void **)&conv) != PAM_SUCCESS || !conv || !conv->conv)
|
|
return PAM_SYSTEM_ERR;
|
|
|
|
char buf[1024];
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
|
|
struct pam_message msg = { .msg_style = style, .msg = buf };
|
|
struct pam_message *pmsg[1] = { &msg };
|
|
struct pam_response *resp = NULL;
|
|
|
|
int r = conv->conv(1, pmsg, &resp, conv->appdata_ptr);
|
|
if (r != PAM_SUCCESS) return r;
|
|
|
|
if (out) {
|
|
if (resp && resp[0].resp) *out = resp[0].resp; else *out = NULL;
|
|
}
|
|
if (resp) free(resp); // NIE zwalniaj *out; zwolni to wywołujący
|
|
return PAM_SUCCESS;
|
|
}
|
|
|
|
static int pam_prompt_compat(pam_handle_t *pamh, int style, char **out, const char *fmt, ...) {
|
|
va_list ap; va_start(ap, fmt);
|
|
int r = pam_vprompt_compat(pamh, style, out, fmt, ap);
|
|
va_end(ap);
|
|
return r;
|
|
}
|
|
|
|
#define pam_prompt pam_prompt_compat
|
|
|
|
#else
|
|
#include <security/pam_appl.h>
|
|
#include <security/pam_ext.h>
|
|
#endif
|
|
|
|
#include <rublon/non_owning_ptr.hpp>
|
|
#include <rublon/utils.hpp>
|
|
|
|
namespace rublon {
|
|
class LinuxPam {
|
|
pam_handle_t * pamh;
|
|
|
|
bool _noninteractive{false};
|
|
|
|
public:
|
|
LinuxPam(pam_handle_t * handler) : pamh{handler} {}
|
|
|
|
void enableNoninteractive(){
|
|
_noninteractive = true;
|
|
}
|
|
|
|
rublon::NonOwningPtr< const char > ip() const {
|
|
#ifdef __sun
|
|
void * ip = NULL;
|
|
#else
|
|
const void * ip = NULL;
|
|
#endif
|
|
pam_get_item(pamh, PAM_RHOST, &ip);
|
|
if(ip == NULL) {
|
|
rublon::log(rublon::LogLevel::Warning, "Cant read ip from linux PAM");
|
|
return "";
|
|
}
|
|
return ( const char * ) ip;
|
|
}
|
|
|
|
rublon::NonOwningPtr< const char > username() const {
|
|
#ifdef __sun
|
|
char * user = NULL;
|
|
#else
|
|
const char * user = NULL;
|
|
#endif
|
|
pam_get_user(pamh, &user, nullptr);
|
|
if(user == NULL) {
|
|
rublon::log(rublon::LogLevel::Warning, "Cant read user from linux PAM");
|
|
return "";
|
|
}
|
|
return user;
|
|
}
|
|
|
|
template < typename... Ti >
|
|
void print(const char * fmt, Ti... ti) const noexcept {
|
|
if(_noninteractive){
|
|
log(LogLevel::Info, "pam_print ommited due working in noninteractive mode");
|
|
return;
|
|
}
|
|
char buf[256] = {};
|
|
sprintf(buf, fmt, std::forward< Ti >(ti)...);
|
|
if(auto r = pam_prompt(pamh, PAM_TEXT_INFO, nullptr, fmt, std::forward< Ti >(ti)...); r != PAM_SUCCESS) {
|
|
log(LogLevel::Error, "pam_print returned with error code %d", r);
|
|
}
|
|
}
|
|
|
|
template < typename Fun, typename... Ti >
|
|
auto scan(Fun && f, const char * fmt, Ti... ti) const noexcept {
|
|
assert(_noninteractive == false);
|
|
char * response = nullptr;
|
|
pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &response, fmt, std::forward< Ti >(ti)...);
|
|
if(response) {
|
|
auto ret = f(response);
|
|
free(response);
|
|
return ret;
|
|
}
|
|
return std::result_of_t< Fun(char *) >();
|
|
}
|
|
};
|
|
} // namespace rublon
|