sessmgr/sessmgr.c

303 righe
7.0 KiB
C

/**
* @PROJECT Session Manager
* @COPYRIGHT See COPYING in the top level directory
* @FILE sessmgr.h
* @PURPOSE WebUI session manager
* @DEVELOPERS Eric Bishop <eric@gargoyle-router.com>
* Rafal Kupiec <belliash@asiotec.eu.org>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>
#include <pwd.h>
#ifdef USE_SHADOW
#include <shadow.h>
#endif
#include "sessmgr.h"
#include "sha256.h"
char* get_admin_hash(const char* username) {
char* admin_hash = NULL;
if(username) {
#ifdef USE_SHADOW
struct spwd* pw;
if((pw = getspnam(username)) != NULL) {
admin_hash = strdup(pw->sp_pwdp);
}
#else
struct passwd* pw;
if((pw = getpwnam(username)) != NULL) {
admin_hash = strdup(pw->pw_passwd);
}
#endif
}
return admin_hash;
}
char* get_cookie_time(time_t t) {
struct tm* utc = gmtime(&t);
char wday[4];
char month[4];
switch(utc->tm_wday) {
case 0:
sprintf(wday, "Sun");
break;
case 1:
sprintf(wday, "Mon");
break;
case 2:
sprintf(wday, "Tue");
break;
case 3:
sprintf(wday, "Wed");
break;
case 4:
sprintf(wday, "Thu");
break;
case 5:
sprintf(wday, "Fri");
break;
case 6:
sprintf(wday, "Sat");
break;
}
switch(utc->tm_mon) {
case 0:
sprintf(month, "Jan");
break;
case 1:
sprintf(month, "Feb");
break;
case 2:
sprintf(month, "Mar");
break;
case 3:
sprintf(month, "Apr");
break;
case 4:
sprintf(month, "May");
break;
case 5:
sprintf(month, "Jun");
break;
case 6:
sprintf(month, "Jul");
break;
case 7:
sprintf(month, "Aug");
break;
case 8:
sprintf(month, "Sep");
break;
case 9:
sprintf(month, "Oct");
break;
case 10:
sprintf(month, "Nov");
break;
case 11:
sprintf(month, "Dec");
break;
}
char utc_str[200];
sprintf(utc_str, "%s, %d %s %d %02d:%02d:%02d UTC", wday, utc->tm_mday, month, (utc->tm_year + 1900), utc->tm_hour, utc->tm_min, utc->tm_sec);
return safe_strdup(utc_str);
}
int main(int argc, char **argv) {
char *password = NULL;
char *username = NULL;
char *cookie_hash = NULL;
char *cookie_exp = NULL;
char *user_agent = NULL;
char *src_ip = NULL;
char *redirect = NULL;
int timeout_minutes = DEFAULT_SESSION_TIMEOUT;
unsigned long browser_time = 0;
int loggedout = 0;
int next_opt;
int read;
while((next_opt = getopt(argc, argv, "p:P:u:U:c:C:e:E:a:A:i:I:r:R:t:T:b:B:lL")) != -1) {
switch(next_opt) {
case 'p':
case 'P':
password = safe_strdup(optarg);
break;
case 'u':
case 'U':
username = safe_strdup(optarg);
break;
case 'c':
case 'C':
cookie_hash = safe_strdup(optarg);
break;
case 'e':
case 'E':
cookie_exp = safe_strdup(optarg);
break;
case 'a':
case 'A':
user_agent = safe_strdup(optarg);
break;
case 'i':
case 'I':
src_ip = safe_strdup(optarg);
break;
case 'r':
case 'R':
redirect = safe_strdup(optarg);
break;
case 't':
case 'T':
read = sscanf(optarg, "%d", &timeout_minutes);
if(read > 0) {
timeout_minutes = timeout_minutes > 0 ? timeout_minutes : DEFAULT_SESSION_TIMEOUT;
} else {
timeout_minutes = DEFAULT_SESSION_TIMEOUT;
}
timeout_minutes *= 60;
break;
case 'b':
case 'B':
read = sscanf(optarg, "%ld", &browser_time);
browser_time = read > 0 ? browser_time : 0;
break;
case 'l':
case 'L':
loggedout = 1;
break;
}
}
int expired = 0;
int valid = 0;
char* admin_hash = get_admin_hash(username);
if(loggedout == 1) {
printf("echo \"Set-Cookie:kagera_sid=loggedout;\"; echo \"Set-Cookie:kagera_usr=loggedout;\"; ");
} else if(admin_hash != NULL) {
time_t now;
time(&now);
if(password != NULL) {
valid = strcmp(crypt(password, admin_hash), admin_hash) == 0 ? 1 : 0;
if(valid) {
printf("logger -t webui \"Kagera Administration Interface authorization succeeded from ${REMOTE_ADDR}\"; ");
}
} else if(cookie_hash != NULL && cookie_exp != NULL && user_agent != NULL && src_ip != NULL) {
time_t exp_time;
int read = sscanf(cookie_exp, "%ld", &exp_time);
if(read > 0) {
expired = 1;
if(exp_time > now && (exp_time - (timeout_minutes) - 2) <= now) {
expired = 0;
}
}
char *combined = safe_strcat(4, admin_hash, cookie_exp, user_agent, src_ip);
char* hashed = get_sha256_hash_hex_str(combined);
if(strcmp(hashed, cookie_hash) == 0) {
if(expired == 0 && read > 0) {
valid = 1;
}
} else {
expired = 0;
}
free(hashed);
free(combined);
}
if(valid == 1 && src_ip != NULL && user_agent != NULL) {
char* new_hash;
char* combined;
char new_exp[100] = "";
time_t new_exp_t = now + (timeout_minutes);
sprintf(new_exp, "%ld", new_exp_t);
char* cookie_exp;
if(browser_time > 0 && ((browser_time - now) < (-5*60) || (browser_time - now) > (5*60))) {
time_t cookie_exp_t = browser_time+(timeout_minutes);
cookie_exp = get_cookie_time(cookie_exp_t);
} else {
cookie_exp = get_cookie_time(new_exp_t);
}
combined = safe_strcat(4, admin_hash, new_exp, user_agent, src_ip);
new_hash = get_sha256_hash_hex_str(combined);
if(browser_time == 0) {
printf("echo \"Set-Cookie:kagera_sid=%s; Path=/;\"; echo \"Set-Cookie:kagera_usr=%s; Path=/;\"; echo \"Set-Cookie:kagera_exp=%s; Path=/;\"; ", new_hash, username, new_exp);
} else {
printf("echo \"Set-Cookie:kagera_sid=%s; Expires=%s; Path=/;\"; echo \"Set-Cookie:kagera_usr=%s; Expires=%s; Path=/;\"; echo \"Set-Cookie:kagera_exp=%s; Expires=%s; Path=/;\"; ", new_hash, cookie_exp, username, cookie_exp, new_exp, cookie_exp);
}
free(new_hash);
free(combined);
free(cookie_exp);
printf("VALIDSESS=1\n");
}
free(admin_hash);
}
if(redirect != NULL) {
char str[20] = "";
if(expired == 1) {
sprintf(str, "&expired=1");
} else if(loggedout == 1) {
sprintf(str, "&loggedout=1");
}
printf("echo \"HTTP/1.1 301 Moved Permanently;\"; echo \"Location: %s%s\"; exit", redirect, str);
}
return 0;
}
void* safe_malloc(size_t size) {
void* val = malloc(size);
if(val == NULL) {
fprintf(stderr, "ERROR: MALLOC FAILURE!\n");
exit(1);
}
return val;
}
char* safe_strcat(int num_strs, ...) {
va_list strs;
int new_length = 0;
int i;
int next_start;
char* new_str;
va_start(strs, num_strs);
for(i=0; i < num_strs; i++) {
char* next_arg = va_arg(strs, char*);
if(next_arg != NULL) {
new_length = new_length + strlen(next_arg);
}
}
va_end(strs);
new_str = safe_malloc((1 + new_length) * sizeof(char));
va_start(strs, num_strs);
next_start = 0;
for(i=0; i < num_strs; i++) {
char* next_arg = va_arg(strs, char*);
if(next_arg != NULL) {
int next_length = strlen(next_arg);
memcpy(new_str+next_start,next_arg, next_length);
next_start = next_start+next_length;
}
}
new_str[next_start] = '\0';
return new_str;
}
char* safe_strdup(const char* str) {
char* new_str = NULL;
if(str != NULL) {
new_str = strdup(str);
if(new_str == NULL) {
fprintf(stderr, "ERROR: MALLOC FAILURE!\n");
exit(1);
}
}
return new_str;
}