kcheckpass: actually allow method selection during runtime

requires:
e1fe980be1

log some errors to auth log and use the actual service as PAM service while
at it

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-03-30 16:53:26 +03:00
parent 0acc0d3d5a
commit 459e73c8d3
6 changed files with 109 additions and 53 deletions

View file

@ -23,11 +23,10 @@ target_link_libraries(kcheckpass
${SOCKET_LIBRARIES}
)
if (PAM_FOUND)
set(kcheckpass_suid "")
else()
if (HAVE_GETSPNAM)
set(kcheckpass_suid "SETUID")
message(WARNING "PAM not found, will install kcheckpass SUID")
message(WARNING "Will install kcheckpass SUID")
endif()
install(

View file

@ -21,28 +21,32 @@
#include "kcheckpass.h"
#ifdef HAVE_ETCPASSWD
/*******************************************************************
* This is the authentication code for /etc/passwd passwords
*******************************************************************/
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <syslog.h>
AuthReturn Authenticate(const char *method,
AuthReturn Authenticate_etcpasswd(const char *method,
const char *login, char *(*conv) (ConvRequest, const char *))
{
if (strcmp(method, "etcpasswd") != 0)
return AuthError;
struct passwd *pw;
char *passwd;
char *crpt_passwd;
if (strcmp(method, "classic"))
return AuthError;
openlog("kcheckpass", LOG_PID, LOG_AUTH);
/* Get the password entry for the user we want */
if (!(pw = getpwnam(login)))
if (!(pw = getpwnam(login))) {
syslog(LOG_ERR, "getpwnam: %s", strerror(errno));
return AuthBad;
}
if (!*pw->pw_passwd)
return AuthOk;
@ -57,5 +61,3 @@ AuthReturn Authenticate(const char *method,
dispose(passwd);
return AuthBad; /* Password wrong or account locked */
}
#endif

View file

@ -30,7 +30,6 @@
struct pam_data {
char *(*conv) (ConvRequest, const char *);
int abort:1;
int classic:1;
};
#ifdef PAM_MESSAGE_CONST
@ -68,7 +67,7 @@ PAM_conv (int num_msg, pam_message_type **msg,
break;
case PAM_PROMPT_ECHO_OFF:
repl[count].resp =
pd->conv(ConvGetHidden, pd->classic ? 0 : msg[count]->msg);
pd->conv(ConvGetHidden, msg[count]->msg);
break;
#ifdef PAM_BINARY_PROMPT
case PAM_BINARY_PROMPT:
@ -122,9 +121,12 @@ fail_delay(int retval ATTR_UNUSED, unsigned usec_delay ATTR_UNUSED,
#endif
AuthReturn Authenticate(const char *caller, const char *method,
AuthReturn Authenticate_pam(const char *caller, const char *method,
const char *user, char *(*conv) (ConvRequest, const char *))
{
if (strcmp(method, "pam") != 0)
return AuthError;
const char *tty;
pam_handle_t *pamh;
pam_gi_type pam_item;
@ -135,14 +137,7 @@ AuthReturn Authenticate(const char *caller, const char *method,
openlog("kcheckpass", LOG_PID, LOG_AUTH);
PAM_data.conv = conv;
if (strcmp(method, "classic")) {
sprintf(pservb, "%.31s-%.31s", caller, method);
pam_service = pservb;
} else {
/* PAM_data.classic = 1; */
pam_service = caller;
}
pam_error = pam_start(pam_service, user, &PAM_conversation, &pamh);
pam_error = pam_start(caller, user, &PAM_conversation, &pamh);
if (pam_error != PAM_SUCCESS)
return AuthError;
@ -196,4 +191,4 @@ AuthReturn Authenticate(const char *caller, const char *method,
return AuthOk;
}
#endif
#endif // HAVE_PAM

View file

@ -31,31 +31,40 @@
*******************************************************************/
#ifdef HAVE_SHADOW
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <syslog.h>
#include <pwd.h>
#include <shadow.h>
#include <unistd.h>
#include <sys/types.h>
AuthReturn Authenticate(const char *method,
AuthReturn Authenticate_shadow(const char *method,
const char *login, char *(*conv) (ConvRequest, const char *))
{
if (strcmp(method, "shadow") != 0)
return AuthError;
char *typed_in_password;
char *crpt_passwd;
char *password;
struct passwd *pw;
struct spwd *spw;
if (strcmp(method, "classic"))
return AuthError;
openlog("kcheckpass", LOG_PID, LOG_AUTH);
if (!(pw = getpwnam(login)))
if (!(pw = getpwnam(login))) {
syslog(LOG_ERR, "getpwnam: %s", strerror(errno));
return AuthAbort;
}
uid_t eid = geteuid();
if (eid != 0 && seteuid(0) != 0)
if (eid != 0 && seteuid(0) != 0) {
syslog(LOG_ERR, "seteuid: %s", strerror(errno));
return AuthAbort;
}
spw = getspnam(login);
password = spw ? spw->sp_pwdp : pw->pw_passwd;
@ -92,4 +101,4 @@ AuthReturn Authenticate(const char *method,
everything else you need to support shadow passwords is in
the standard (ELF) libc.
*/
#endif
#endif // HAVE_SHADOW

View file

@ -27,7 +27,6 @@
* It's hopefully simple enough to allow it to be setuid
* root.
*
* Compile with -DHAVE_VSYSLOG if you have vsyslog().
* Compile with -DHAVE_PAM if you have a PAM system,
* and link with -lpam -ldl.
* Compile with -DHAVE_SHADOW if you have a shadow
@ -65,6 +64,15 @@
static int havetty, nullpass = 0;
static int sfd = -1;
static const char* methods[3] = { "", "", "" };
#if defined(HAVE_PAM)
const char *method = "pam";
#elif defined(HAVE_SHADOW)
const char *method = "shadow";
#else
const char *method = "etcpasswd";
#endif
static char *
conv_legacy (ConvRequest what, const char *prompt)
{
@ -292,23 +300,22 @@ usage(int exitval)
" -U username authenticate the specified user instead of current user\n"
" -S handle operate in binary server mode on file descriptor handle\n"
" -c caller the calling application, effectively the PAM service basename\n"
" -m method use the specified authentication method (default: \"classic\")\n"
" -m method use the specified authentication method (default: \"%s\")\n"
" exit codes:\n"
" 0 success\n"
" 1 invalid password\n"
" 2 cannot read password database\n"
" Anything else tells you something's badly hosed.\n"
);
" Anything else tells you something's badly hosed.\n",
method);
exit(exitval);
}
int
main(int argc, char **argv)
{
#ifdef HAVE_PAM
#if defined(HAVE_PAM)
const char *caller = KSCREENSAVER_PAM_SERVICE;
#endif
const char *method = "classic";
const char *username = 0;
#ifdef ACCEPT_ENV
char *p;
@ -362,6 +369,28 @@ main(int argc, char **argv)
}
}
int validmethod = 0;
#ifdef HAVE_PAM
methods[0] = "pam";
if (strcmp(method, "pam") == 0) {
validmethod = 1;
}
#endif
#ifdef HAVE_SHADOW
methods[1] = ", shadow";
if (strcmp(method, "shadow") == 0) {
validmethod = 1;
}
#endif
methods[2] = ", etcpasswd";
if (strcmp(method, "etcpasswd") == 0) {
validmethod = 1;
}
if (!validmethod) {
message("Method must be one of: %s%s%s\n", methods[0], methods[1], methods[2]);
usage(11);
}
uid = getuid();
#ifdef ACCEPT_ENV
@ -417,13 +446,32 @@ main(int argc, char **argv)
}
/* Now do the fandango */
ret = Authenticate(
#ifdef HAVE_PAM
if (strcmp(method, "pam") == 0) {
ret = Authenticate_pam(
caller,
#endif
method,
username,
sfd < 0 ? conv_legacy : conv_server);
sfd < 0 ? conv_legacy : conv_server
);
}
#endif
#ifdef HAVE_SHADOW
if (strcmp(method, "shadow") == 0) {
ret = Authenticate_shadow(
method,
username,
sfd < 0 ? conv_legacy : conv_server
);
}
#endif
if (strcmp(method, "etcpasswd") == 0) {
ret = Authenticate_etcpasswd(
method,
username,
sfd < 0 ? conv_legacy : conv_server
);
}
if (ret == AuthBad) {
message("Authentication failure\n");

View file

@ -51,19 +51,10 @@
#include <pwd.h>
#include <sys/types.h>
#ifndef _PATH_TMP
#define _PATH_TMP "/tmp/"
#endif
#include <unistd.h>
/* Make sure there is only one! */
#if defined(HAVE_PAM)
#elif defined(HAVE_GETSPNAM)
#ifdef HAVE_GETSPNAM
# define HAVE_SHADOW
#else
# define HAVE_ETCPASSWD
#endif
#if !defined(__INSURE__)
@ -85,10 +76,22 @@ extern "C" {
/*****************************************************************
* Authenticates user
*****************************************************************/
AuthReturn Authenticate(
#ifdef HAVE_PAM
AuthReturn Authenticate_pam(
const char *caller,
const char *method,
const char *user,
char *(*conv) (ConvRequest, const char *));
#endif
#ifdef HAVE_SHADOW
AuthReturn Authenticate_shadow(
const char *method,
const char *user,
char *(*conv) (ConvRequest, const char *));
#endif
AuthReturn Authenticate_etcpasswd(
const char *method,
const char *user,
char *(*conv) (ConvRequest, const char *));