Skip to content

Commit

Permalink
cache: add mutex to avoid race (avoid validating same proxy ticket in…
Browse files Browse the repository at this point in the history
… parallel)
  • Loading branch information
prigaux committed Jun 2, 2020
1 parent 3cf2f37 commit e28804e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 33 deletions.
71 changes: 51 additions & 20 deletions sources/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/md5.h>
#include <security/pam_appl.h>

#include "cas.h"

#define DIGEST_LENGTH 16

void create(const char *file) {
FILE *f = fopen(file, "w");
if (f != NULL) fclose(f);
}

char *cacheFile(const char *service, const char *user, const char *ticket, const pam_cas_config_t *config)
char *cacheFilename(const char *service, const char *user, const char *ticket, const pam_cas_config_t *config)
{
MD5_CTX context;
MD5_Init(&context);
Expand All @@ -40,33 +37,67 @@ char *cacheFile(const char *service, const char *user, const char *ticket, const
return f;
}

int update_atime(const char *f)
int update_atime(FILE *f)
{
struct timespec times[2];
times[0].tv_sec = 0;
times[0].tv_nsec = UTIME_NOW;
times[1].tv_sec = 0;
times[1].tv_nsec = UTIME_OMIT;
return utimensat(0, f, times, 0);
return futimens(fileno(f), times);
}

int readCacheFile(FILE *f)
{
rewind(f);
int ret;
char c;
if (fscanf(f, "%d%c", &ret, &c) == 2 && c == '\n') {
printf("readCacheFile found %d <%c>\n", ret, c);
if (ret == PAM_SUCCESS || ret == PAM_AUTH_ERR) return ret;
}
return -1;
}

int hasCache(const char *service, const char *user, const char *ticket, const pam_cas_config_t *config)
int readCache_or_lockCache(const char *service, const char *user, const char *ticket, const pam_cas_config_t *config, FILE **cacheFile)
{
char *f = cacheFile(service, user, ticket, config);
char *filename = cacheFilename(service, user, ticket, config);
FILE *f = fopen(filename, "a+");
free(filename);

if (f == NULL) {
fprintf(stderr, "could not open cache file: %s\n", strerror(errno));
return -1;
}

int has = access(f, F_OK) != -1;
if (has) {
// update last modified time so we know the ticket is still in use
update_atime(f);
int ret = readCacheFile(f);
if (ret != -1) {
// cool, the normal easy case
update_atime(f);
fclose(f);
return ret;
}

free(f);
return has;
// ensure only one pam_cas is validating the ticket
lockf(fileno(f), F_LOCK, 0);

// check if someone did the work while we were waiting for the lock
ret = readCacheFile(f);
if (ret != -1) {
fclose(f); // NB: releases the lock
return ret;
} else {
// this pam_cas is responsable for validating the proxy ticket.
// keeping file open and locked
*cacheFile = f;
return -1;
}
}

void setCache(const char *service, const char *user, const char *ticket, const pam_cas_config_t *config)
void setCache(FILE *cacheFile, int status)
{
char *f = cacheFile(service, user, ticket, config);
create(f);
free(f);
rewind(cacheFile); ftruncate(fileno(cacheFile), 0); // just in case?

fprintf(cacheFile, "%d\n", status);
fclose(cacheFile); // NB: releases the lock
}
4 changes: 2 additions & 2 deletions sources/cas.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ typedef struct pam_cas_config
int cas_validate(
char *ticket, char *service, char *outbuf, int outbuflen, pam_cas_config_t *config);

int hasCache(const char *service, const char *user, const char *ticket, const pam_cas_config_t *config);
void setCache(const char *service, const char *user, const char *ticket, const pam_cas_config_t *config);
int readCache_or_lockCache(const char *service, const char *user, const char *ticket, const pam_cas_config_t *config, FILE **cacheFile);
void setCache(FILE *cacheFile, int status);

int read_config (const char *configFile, pam_cas_config_t ** presult, int localDebug);
void free_config(pam_cas_config_t ** pstConfig);
Expand Down
9 changes: 6 additions & 3 deletions sources/castest.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,10 @@ int main(int argc, char **argv) {

pstConfig->debug = DEBUG_LOCAL;

if (pstConfig->cacheDirectory != NULL &&
hasCache(service, "foo", ticket, pstConfig)) {
printf("found ticket in cache\n");
FILE *cacheFile = NULL;
if (pstConfig->cacheDirectory != NULL) {
int ret = readCache_or_lockCache(service, "foo", ticket, pstConfig, &cacheFile);
if (ret != -1) printf("found ticket in cache: %d\n", ret);
}

retour = cas_validate(ticket, service, netid, sizeof(netid), pstConfig);
Expand All @@ -107,6 +108,8 @@ int main(int argc, char **argv) {
printf("valid ticket for '%s'\n", netid);
else
printf("invalid ticket : %s\n\n", getErrorMessage(retour));

if (cacheFile != NULL) setCache(cacheFile, retour);

free_config(&pstConfig);
return 0;
Expand Down
19 changes: 11 additions & 8 deletions sources/pam_cas.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#define PAM_SM_AUTH
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
Expand Down Expand Up @@ -70,6 +71,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
{
pam_cas_config_t *pstConfig = NULL;
char *configFile = NULL;
FILE *cacheFile = NULL;
char *user, *pw;
char *service = NULL;
char netid[CAS_LEN_NETID];
Expand Down Expand Up @@ -132,11 +134,13 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
END(PAM_AUTH_ERR);
}

if (pstConfig->cacheDirectory != NULL &&
hasCache(service, user, pw, pstConfig)) {
if (pstConfig->debug)
syslog(LOG_NOTICE, "USER '%s' AUTHENTICATED WITH CACHED CAS PT:%s", user, pw);
END(PAM_SUCCESS);
if (pstConfig->cacheDirectory != NULL) {
ret = readCache_or_lockCache(service, user, pw, pstConfig, &cacheFile);
if (ret != -1) {
if (pstConfig->debug)
syslog(LOG_NOTICE, "USER '%s' %s WITH CACHED CAS PT:%s", user, ret == PAM_SUCCESS ? "AUTHENTICATED" : "FAILED", pw);
goto end;
}
}

/* determine the CAS-authenticated username */
Expand All @@ -152,9 +156,6 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
if (pstConfig->debug)
syslog(LOG_NOTICE, "USER '%s' AUTHENTICATED WITH CAS PT:%s", user, pw);

if (pstConfig->cacheDirectory != NULL)
setCache(service, user, pw, pstConfig);

END(PAM_SUCCESS);
} else {
if (strcmp(user, netid) && (success == CAS_SUCCESS)) {
Expand All @@ -172,6 +173,8 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
}

end:
if (cacheFile != NULL)
setCache(cacheFile, ret);
closelog();
if (service)
free(service);
Expand Down

0 comments on commit e28804e

Please sign in to comment.