enlightenment/src/bin/e_ckpasswd_main.c

218 lines
4.7 KiB
C

#include "config.h"
#define __USE_MISC
#define _SVID_SOURCE
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#if defined(__OpenBSD__)
static int
_check_auth(uid_t uid, const char *guess)
{
struct passwd *pwent;
pwent = getpwuid_shadow(uid);
if (!pwent) return -1;
if (!pwent->pw_passwd) return -1;
return crypt_checkpass(guess, pwent->pw_passwd);
}
#elif defined(__FreeBSD__)
#include <security/pam_constants.h>
static int
_check_auth(uid_t uid, const char *pw)
{
struct passwd *pwent = getpwuid(uid);
if (!pwent) return -1;
if (!pwent->pw_passwd) return -1;
if (!strcmp(crypt(pw, pwent->pw_passwd), pwent->pw_passwd)) return 0;
return -1;
}
#elif defined(HAVE_PAM)
# include <security/pam_appl.h>
typedef struct
{
const char *user;
const char *pw;
} Authinfo;
static int
_conv_cb(int num, const struct pam_message **msg, struct pam_response **resp, void *data)
{
Authinfo *ai = data;
int replies;
struct pam_response *reply = NULL;
reply = malloc(sizeof(struct pam_response) * num);
if (!reply) return PAM_CONV_ERR;
for (replies = 0; replies < num; replies++)
{
switch (msg[replies]->msg_style)
{
case PAM_PROMPT_ECHO_ON:
reply[replies].resp_retcode = PAM_SUCCESS;
reply[replies].resp = strdup(ai->user);
break;
case PAM_PROMPT_ECHO_OFF:
reply[replies].resp_retcode = PAM_SUCCESS;
reply[replies].resp = strdup(ai->pw);
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
reply[replies].resp_retcode = PAM_SUCCESS;
reply[replies].resp = NULL;
break;
default:
free(reply);
return PAM_CONV_ERR;
}
}
*resp = reply;
return PAM_SUCCESS;
}
static int
_check_auth(uid_t uid, const char *pw)
{
Authinfo ai;
struct passwd *pwent;
const char *user;
const char *prof;
const char *host;
struct stat st;
pam_handle_t *handle;
int pamerr;
struct pam_conv conv;
pwent = getpwuid(uid);
if (!pwent) return -1;
user = pwent->pw_name;
if (!user) return -1;
host = "localhost";
prof = "login";
if (!stat("/etc/pam.d/enlightenment", &st)) prof = "enlightenment";
else if (!stat("/etc/pam.d/xscreensaver", &st)) prof = "xscreensaver";
else if (!stat("/etc/pam.d/kscreensaver", &st)) prof = "kscreensaver";
else if (!stat("/etc/pam.d/system-auth", &st)) prof = "system-auth";
else if (!stat("/etc/pam.d/system", &st)) prof = "system";
else if (!stat("/etc/pam.d/xdm", &st)) prof = "xdm";
else if (!stat("/etc/pam.d/gdm", &st)) prof = "gdm";
else if (!stat("/etc/pam.d/kdm", &st)) prof = "kdm";
ai.user = user;
ai.pw = pw;
conv.conv = _conv_cb;
conv.appdata_ptr = &ai;
if (pam_start(prof, user, &conv, &handle) != PAM_SUCCESS) return -1;
if (pam_set_item(handle, PAM_USER, user) != PAM_SUCCESS) return -1;
if (pam_set_item(handle, PAM_RHOST, host) != PAM_SUCCESS) return -1;
pamerr = pam_authenticate(handle, 0);
pam_end(handle, pamerr);
if (pamerr != PAM_SUCCESS) return -1;
return 0;
}
#else
static int
_check_auth(uid_t uid, const char *pw)
{
return -1;
}
#endif
int
main(int argc, char **argv)
{
ssize_t rd;
uid_t id;
char pw[4096], *p;
if (argc != 1)
{
int i;
for (i = 1; i < argc; i++)
fprintf(stderr, "Unknown option %s\n", argv[i]);
fprintf(stderr,
"This is an internal tool for Enlightenment\n");
goto err;
}
// get uid who ran this
id = getuid();
// read passwd from stdin
rd = read(0, pw, sizeof(pw) - 1);
if (rd < 0)
{
fprintf(stderr,
"Error. Can't read passwd on stdin\n");
goto err;
}
pw[rd] = 0;
for (p = pw; *p; p++)
{
if ((*p == '\r') || (*p == '\n'))
{
*p = 0;
break;
}
}
// If we are setuid root then try become root - we can work without though
// if pam etc. can work without being root
if (setuid(0) != 0)
fprintf(stderr,
"Warning. Can't become user root. If password auth requires root then this will fail\n");
if (setgid(0) != 0)
fprintf(stderr,
"Warning. Can't become group root. If password auth requires root then this will fail\n");
if (_check_auth(id, pw) == 0) return 0;
err:
fprintf(stderr,
"Password auth fail\n");
return -1;
}