this should fix T6211 ensuring no drivers can cause a segfault at exit time. this also happens to remove the enlightenment_sys -z option for openbsd and unifies all the passwd checking into the single enlightenment_ckpasswd binary util (that has ifdefs for openbsd, freebsd and linux pam in it). this simplifies code removing a mess of auth being done in multiple places, removes special fork vs run 1 exe or a different exe in different cases making it more maintainable. yes - this requires enlightenment_ckpasswd to be setuid root, but it already was when it was built. @fixdevs/discomfitor/junk
parent
46764d5975
commit
51cb454993
6 changed files with 202 additions and 364 deletions
@ -1,81 +1,217 @@ |
||||
#include <sys/types.h> |
||||
#include "config.h" |
||||
|
||||
#define __USE_MISC |
||||
#define _SVID_SOURCE |
||||
#define _DEFAULT_SOURCE |
||||
|
||||
#include <err.h> |
||||
#include <pwd.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.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, pw_ent->pw_passwd); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#elif defined(__FreeBSD__) |
||||
#include <security/pam_constants.h> |
||||
|
||||
// Exit codes, per src/modules/lokker/lokker.c:
|
||||
// 0: success (unlock)
|
||||
// 1-128: PAM error but also unlock (!!!)
|
||||
// else: failed.
|
||||
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; |
||||
|
||||
static char pw[4096]; |
||||
struct passwd *pwent; |
||||
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 void |
||||
zeropw(void) |
||||
static int |
||||
_check_auth(uid_t uid, const char *pw) |
||||
{ |
||||
/* security - null out passwd string once we are done with it */ |
||||
memset(pw, 0, sizeof(pw)); |
||||
if (pw[0] || pw[3]) printf("ACK!\n"); |
||||
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; |
||||
} |
||||
|
||||
|
||||
|
||||
if (pwent == NULL) return; |
||||
if (pwent->pw_passwd == NULL) return; |
||||
|
||||
/* security - null out passwd string once we are done with it */ |
||||
memset(pwent->pw_passwd, 0, strlen(pwent->pw_passwd)); |
||||
if (pwent->pw_passwd[0]) printf("ACK!\n"); |
||||
|
||||
#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; |
||||
int i; |
||||
char pw[4096], *p; |
||||
|
||||
for (i = 1; i < argc; i++) |
||||
if (argc != 1) |
||||
{ |
||||
if ((!strcmp(argv[i], "-h")) || |
||||
(!strcmp(argv[i], "-help")) || |
||||
(!strcmp(argv[i], "--help"))) |
||||
{ |
||||
printf("This is an internal tool for Enlightenment.\n" |
||||
"do not use it.\n"); |
||||
exit(129); |
||||
} |
||||
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; |
||||
} |
||||
if (argc != 1) |
||||
exit(130); |
||||
|
||||
// get uid who ran this
|
||||
id = getuid(); |
||||
|
||||
if (atexit(zeropw)) err(131, "atexit"); |
||||
|
||||
// read passwd from stdin
|
||||
rd = read(0, pw, sizeof(pw) - 1); |
||||
if (rd < 0) err(132, "read"); |
||||
|
||||
if (setuid(0) != 0) |
||||
if (rd < 0) |
||||
{ |
||||
printf("ERROR: UNABLE TO ASSUME ROOT PRIVILEGES\n"); |
||||
exit(133); |
||||
fprintf(stderr, |
||||
"Error. Can't read passwd on stdin\n"); |
||||
goto err; |
||||
} |
||||
if (setgid(0) != 0) |
||||
pw[rd] = 0; |
||||
for (p = pw; *p; p++) |
||||
{ |
||||
printf("ERROR: UNABLE TO ASSUME ROOT GROUP PRIVILEGES\n"); |
||||
exit(134); |
||||
if ((*p == '\r') || (*p == '\n')) |
||||
{ |
||||
*p = 0; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
pwent = getpwuid(id); |
||||
if (pwent == NULL) return -2; |
||||
|
||||
if (strcmp(crypt(pw, pwent->pw_passwd), pwent->pw_passwd) == 0) |
||||
return 0; |
||||
|
||||
// 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; |
||||
} |
||||
|
Loading…
Reference in new issue