|
|
@ -39,6 +39,8 @@ |
|
|
|
#include <stdarg.h> |
|
|
|
#include <stdarg.h> |
|
|
|
#include <ctype.h> |
|
|
|
#include <ctype.h> |
|
|
|
#include <signal.h> |
|
|
|
#include <signal.h> |
|
|
|
|
|
|
|
#include <time.h> |
|
|
|
|
|
|
|
#include <fcntl.h> |
|
|
|
|
|
|
|
|
|
|
|
#if !defined(_XOPEN_CRYPT) || _XOPEN_CRYPT == -1 |
|
|
|
#if !defined(_XOPEN_CRYPT) || _XOPEN_CRYPT == -1 |
|
|
|
#include <crypt.h> |
|
|
|
#include <crypt.h> |
|
|
@ -55,6 +57,8 @@ |
|
|
|
#define FLAG_PERSIST 0x1 |
|
|
|
#define FLAG_PERSIST 0x1 |
|
|
|
#define FLAG_NOPASS 0x2 |
|
|
|
#define FLAG_NOPASS 0x2 |
|
|
|
#define FLAG_NOLOG 0x4 |
|
|
|
#define FLAG_NOLOG 0x4 |
|
|
|
|
|
|
|
#define SESSION_FILE_DIR "/var/run" |
|
|
|
|
|
|
|
#define SESSION_TIMEOUT (60*5) |
|
|
|
|
|
|
|
|
|
|
|
struct env_elem { |
|
|
|
struct env_elem { |
|
|
|
char *name; |
|
|
|
char *name; |
|
|
@ -84,7 +88,7 @@ void *erealloc(void *, size_t); |
|
|
|
static void usage(void); |
|
|
|
static void usage(void); |
|
|
|
static void die(const char *, ...); |
|
|
|
static void die(const char *, ...); |
|
|
|
static int perm_set(struct passwd *, struct group *); |
|
|
|
static int perm_set(struct passwd *, struct group *); |
|
|
|
static int authenticate(uid_t, char); |
|
|
|
static int authenticate(uid_t, int, int); |
|
|
|
static struct passwd* user_to_passwd(const char *, struct user_info *); |
|
|
|
static struct passwd* user_to_passwd(const char *, struct user_info *); |
|
|
|
static struct group* group_to_grp(const char *, struct user_info *); |
|
|
|
static struct group* group_to_grp(const char *, struct user_info *); |
|
|
|
static int get_config(struct config **, int *); |
|
|
|
static int get_config(struct config **, int *); |
|
|
@ -159,6 +163,8 @@ int main(int argc, char *argv[]) |
|
|
|
/* From now on most actions require root */ |
|
|
|
/* From now on most actions require root */ |
|
|
|
if (setuid(0) == -1) |
|
|
|
if (setuid(0) == -1) |
|
|
|
die("setuid:"); |
|
|
|
die("setuid:"); |
|
|
|
|
|
|
|
if (setgid(0) == -1) |
|
|
|
|
|
|
|
die("setgid:"); |
|
|
|
|
|
|
|
|
|
|
|
/* get info from the config file and check if the action we want to
|
|
|
|
/* get info from the config file and check if the action we want to
|
|
|
|
* do is permitted */ |
|
|
|
* do is permitted */ |
|
|
@ -236,7 +242,7 @@ int main(int argc, char *argv[]) |
|
|
|
|
|
|
|
|
|
|
|
/* Authenticate, we will be root from now on */ |
|
|
|
/* Authenticate, we will be root from now on */ |
|
|
|
if (!(conf_flags & FLAG_NOPASS)) |
|
|
|
if (!(conf_flags & FLAG_NOPASS)) |
|
|
|
if (authenticate(my_pw->pw_uid, askpass)) |
|
|
|
if (authenticate(my_pw->pw_uid, askpass, conf_flags & FLAG_PERSIST)) |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
|
|
|
|
|
|
|
|
/* Get target user's shell */ |
|
|
|
/* Get target user's shell */ |
|
|
@ -394,9 +400,57 @@ static int perm_set(struct passwd *pw, struct group *gr) |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int authenticate(uid_t uid, char ask) |
|
|
|
static int authenticate(uid_t uid, int ask, int persist) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// TODO: implement u2f compat
|
|
|
|
// TODO: implement u2f compat
|
|
|
|
|
|
|
|
// TODO: check root access, maybe
|
|
|
|
|
|
|
|
/* try to check if a valid saved session exists */ |
|
|
|
|
|
|
|
char tmp_file[512] = {0}; |
|
|
|
|
|
|
|
if (persist) { |
|
|
|
|
|
|
|
pid_t sid = getsid(0); |
|
|
|
|
|
|
|
if (sid == (pid_t)-1) |
|
|
|
|
|
|
|
die("getsid:"); |
|
|
|
|
|
|
|
if (snprintf(tmp_file, 512, SESSION_FILE_DIR "/us.%d", sid) >= 512) |
|
|
|
|
|
|
|
die("snprintf: output truncated"); |
|
|
|
|
|
|
|
int session_file = open(tmp_file, O_RDONLY | O_CLOEXEC); |
|
|
|
|
|
|
|
int valid_session = 1; |
|
|
|
|
|
|
|
struct timespec now_t[2] = {0}, old_t[2] = {0}; |
|
|
|
|
|
|
|
if (session_file != -1) { |
|
|
|
|
|
|
|
struct stat st; |
|
|
|
|
|
|
|
if (fstat(session_file, &st) == -1) { |
|
|
|
|
|
|
|
valid_session = 0; |
|
|
|
|
|
|
|
} else if (st.st_uid != 0 || st.st_gid != 0) { |
|
|
|
|
|
|
|
valid_session = 0; |
|
|
|
|
|
|
|
} else if (!S_ISREG(st.st_mode)) { |
|
|
|
|
|
|
|
valid_session = 0; |
|
|
|
|
|
|
|
} else if (st.st_mode & S_IRWXO || |
|
|
|
|
|
|
|
st.st_mode & S_IROTH || |
|
|
|
|
|
|
|
st.st_mode & S_IWOTH || st.st_mode & S_IXOTH) { |
|
|
|
|
|
|
|
valid_session = 0; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
int r = read(session_file, old_t, sizeof(struct timespec)*2); |
|
|
|
|
|
|
|
if (r != sizeof(struct timespec)*2) |
|
|
|
|
|
|
|
valid_session = 0; |
|
|
|
|
|
|
|
close(session_file); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
valid_session = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (valid_session && session_file != -1) { |
|
|
|
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC, &(now_t[0])) == -1) |
|
|
|
|
|
|
|
die("clock_gettime:"); |
|
|
|
|
|
|
|
if (clock_gettime(CLOCK_REALTIME, &(now_t[1])) == -1) |
|
|
|
|
|
|
|
die("clock_gettime:"); |
|
|
|
|
|
|
|
if (now_t[0].tv_sec <= old_t[0].tv_sec || |
|
|
|
|
|
|
|
old_t[0].tv_sec < now_t[0].tv_sec - SESSION_TIMEOUT || |
|
|
|
|
|
|
|
now_t[1].tv_sec <= old_t[1].tv_sec || |
|
|
|
|
|
|
|
old_t[1].tv_sec < now_t[1].tv_sec - SESSION_TIMEOUT) |
|
|
|
|
|
|
|
valid_session = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (valid_session) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
/* get the encrypted password */ |
|
|
|
/* get the encrypted password */ |
|
|
|
struct passwd *pw = getpwuid(uid); |
|
|
|
struct passwd *pw = getpwuid(uid); |
|
|
|
char *hash_p, hash[MAX_HASH]; |
|
|
|
char *hash_p, hash[MAX_HASH]; |
|
|
@ -511,6 +565,22 @@ static int authenticate(uid_t uid, char ask) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
printf("\n"); |
|
|
|
printf("\n"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (persist) { |
|
|
|
|
|
|
|
if (!tmp_file[0]) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
int session_file = creat(tmp_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); |
|
|
|
|
|
|
|
if (session_file == -1) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
chown(tmp_file, 0, 0); |
|
|
|
|
|
|
|
struct timespec t[2] = {0}; |
|
|
|
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC, &(t[0])) == -1) |
|
|
|
|
|
|
|
die("clock_gettime:"); |
|
|
|
|
|
|
|
if (clock_gettime(CLOCK_REALTIME, &(t[1])) == -1) |
|
|
|
|
|
|
|
die("clock_gettime:"); |
|
|
|
|
|
|
|
write(session_file, t, sizeof(struct timespec)*2); |
|
|
|
|
|
|
|
close(session_file); |
|
|
|
|
|
|
|
} |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|