diff --git a/rdo.c b/rdo.c index 8c74445..089b20b 100644 --- a/rdo.c +++ b/rdo.c @@ -14,132 +14,132 @@ #define VERSION "1.4.2" void getconf(FILE* fp, const char* entry, char* result, size_t len_result) { - char* line = NULL; - size_t len = 0; + char* line = NULL; + size_t len = 0; - fseek(fp, 0, SEEK_SET); + fseek(fp, 0, SEEK_SET); - while (getline(&line, &len, fp) != -1) { - if (strncmp(entry, line, strlen(entry)) == 0) { - strtok(line, "="); - char* token = strtok(NULL, "="); - if (token) { - strncpy(result, token, len_result); - result[strcspn(result, "\n")] = 0; - free(line); - return; - } - } - } + while (getline(&line, &len, fp) != -1) { + if (strncmp(entry, line, strlen(entry)) == 0) { + strtok(line, "="); + char* token = strtok(NULL, "="); + if (token) { + strncpy(result, token, len_result); + result[strcspn(result, "\n")] = 0; + free(line); + return; + } + } + } - errx(1, "Could not get '%s' entry in config", entry); + errx(1, "Could not get '%s' entry in config", entry); } void runprog(char** program_argv) { - if (setuid(0) < 0) - err(1, "Could not setuid"); - if (setgid(0) < 0) - err(1, "Could not setgid"); + if (setuid(0) < 0) + err(1, "Could not setuid"); + if (setgid(0) < 0) + err(1, "Could not setgid"); - putenv("HOME=/root"); + putenv("HOME=/root"); - // NOTE: this does not return when no error occurred. - execvp(program_argv[0], program_argv); + // NOTE: this does not return when no error occurred. + execvp(program_argv[0], program_argv); - err(1, "%s", program_argv[0]); + err(1, "%s", program_argv[0]); } int main(int argc, char** argv) { - char groupname[64], wrong_pw_sleep[64], session_ttl[64], password[128]; - unsigned int sleep_us, tries, ts_ttl; + char groupname[64], wrong_pw_sleep[64], session_ttl[64], password[128]; + unsigned int sleep_us, tries, ts_ttl; - int read_pw_from_stdin = 0; - if (argc > 1) - read_pw_from_stdin = strcmp(argv[1], "-") == 0; + int read_pw_from_stdin = 0; + if (argc > 1) + read_pw_from_stdin = strcmp(argv[1], "-") == 0; - if (argc == 1 || (read_pw_from_stdin && argc == 2)) { - printf("RootDO version: %s\n\n", VERSION); - printf("Usage: %s [command]\n", argv[0]); - return 0; - } + if (argc == 1 || (read_pw_from_stdin && argc == 2)) { + printf("RootDO version: %s\n\n", VERSION); + printf("Usage: %s [command]\n", argv[0]); + return 0; + } - if (geteuid() != 0) - errx(1, "The rdo binary needs to be installed as SUID."); + if (geteuid() != 0) + errx(1, "The rdo binary needs to be installed as SUID."); - int ruid = getuid(); - if (ruid == 0) - runprog(&argv[read_pw_from_stdin+1]); + int ruid = getuid(); + if (ruid == 0) + runprog(&argv[read_pw_from_stdin+1]); - FILE* fp = fopen("/etc/rdo.conf", "r"); + FILE* fp = fopen("/etc/rdo.conf", "r"); - if (!fp) - err(1, "Could not open /etc/rdo.conf"); + if (!fp) + err(1, "Could not open /etc/rdo.conf"); - getconf(fp, "group", groupname, sizeof(groupname)); - getconf(fp, "wrong_pw_sleep", wrong_pw_sleep, sizeof(wrong_pw_sleep)); - getconf(fp, "session_ttl", session_ttl, sizeof(session_ttl)); - sleep_us = atoi(wrong_pw_sleep) * 1000; - ts_ttl = atoi(session_ttl) * 60; + getconf(fp, "group", groupname, sizeof(groupname)); + getconf(fp, "wrong_pw_sleep", wrong_pw_sleep, sizeof(wrong_pw_sleep)); + getconf(fp, "session_ttl", session_ttl, sizeof(session_ttl)); + sleep_us = atoi(wrong_pw_sleep) * 1000; + ts_ttl = atoi(session_ttl) * 60; - fclose(fp); + fclose(fp); - if (getsession(getppid(), ts_ttl, ruid) == 0 && !read_pw_from_stdin) - runprog(&argv[1]); + if (getsession(getppid(), ts_ttl, ruid) == 0 && !read_pw_from_stdin) + runprog(&argv[1]); - struct passwd* pw = getpwuid(ruid); - if (!pw) { - if (errno == 0) - errx(1, "No user with UID %d", ruid); - else - err(1, "Could not get user info"); - } + struct passwd* pw = getpwuid(ruid); + if (!pw) { + if (errno == 0) + errx(1, "No user with UID %d", ruid); + else + err(1, "Could not get user info"); + } - struct group* current_group_entry = getgrent(); - while (current_group_entry) { - if (strcmp(current_group_entry->gr_name, groupname) == 0) - break; - current_group_entry = getgrent(); - } + struct group* current_group_entry = getgrent(); + while (current_group_entry) { + if (strcmp(current_group_entry->gr_name, groupname) == 0) + break; + current_group_entry = getgrent(); + } - if (!current_group_entry) - errx(1, "The group '%s' does not exist.", groupname); - - char* current_member = current_group_entry->gr_mem[0]; - for (int i = 1; current_member; i++) { - if (strcmp(current_member, pw->pw_name) == 0) - break; - current_member = current_group_entry->gr_mem[i]; - } + if (!current_group_entry) + errx(1, "The group '%s' does not exist.", groupname); - if (!current_member) - errx(1, "You are not allowed to execute rdo."); + char* current_member = current_group_entry->gr_mem[0]; + for (int i = 1; current_member; i++) { + if (strcmp(current_member, pw->pw_name) == 0) + break; + current_member = current_group_entry->gr_mem[i]; + } - struct spwd* shadowEntry = getspnam(pw->pw_name); + if (!current_member) + errx(1, "You are not allowed to execute rdo."); - if (!shadowEntry || !shadowEntry->sp_pwdp) - err(1, "Could not get shadow entry"); + struct spwd* shadowEntry = getspnam(pw->pw_name); - tries = 0; - while (tries < 3) { - if (!readpassphrase("(rdo) Password: ", password, sizeof(password), read_pw_from_stdin)) - err(1, "Could not get passphrase"); + if (!shadowEntry || !shadowEntry->sp_pwdp) + err(1, "Could not get shadow entry"); - char* hashed_pw = crypt(password, shadowEntry->sp_pwdp); - memset(password, 0, sizeof(password)); - - if (!hashed_pw) - errx(1, "Could not hash password, does your user have a password?"); + tries = 0; + while (tries < 3) { + if (!readpassphrase("(rdo) Password: ", password, sizeof(password), read_pw_from_stdin)) + err(1, "Could not get passphrase"); - if (strcmp(shadowEntry->sp_pwdp, hashed_pw) == 0) { - if (!read_pw_from_stdin) - setsession(getppid(), ts_ttl, ruid); - runprog(&argv[read_pw_from_stdin+1]); - } + char* hashed_pw = crypt(password, shadowEntry->sp_pwdp); + memset(password, 0, sizeof(password)); - usleep(sleep_us); - fprintf(stderr, "Wrong password.\n"); - tries++; - } - errx(1, "Too many wrong password attempts."); - return 1; + if (!hashed_pw) + errx(1, "Could not hash password, does your user have a password?"); + + if (strcmp(shadowEntry->sp_pwdp, hashed_pw) == 0) { + if (!read_pw_from_stdin) + setsession(getppid(), ts_ttl, ruid); + runprog(&argv[read_pw_from_stdin+1]); + } + + usleep(sleep_us); + fprintf(stderr, "Wrong password.\n"); + tries++; + } + errx(1, "Too many wrong password attempts."); + return 1; } diff --git a/sessions.h b/sessions.h index 9c82b58..a322fc8 100644 --- a/sessions.h +++ b/sessions.h @@ -8,140 +8,140 @@ #include int getpstartts(int pid, unsigned long long* startts) { - char path[255], fc[1024]; - char* ptr = fc; + char path[255], fc[1024]; + char* ptr = fc; - snprintf(path, sizeof(path), "/proc/%d/stat", pid); - int fd = open(path, O_RDONLY); + snprintf(path, sizeof(path), "/proc/%d/stat", pid); + int fd = open(path, O_RDONLY); - if (fd < 0) - err(1, "Could not open %s", path); + if (fd < 0) + err(1, "Could not open %s", path); - int bytes_read = read(fd, fc, sizeof(fc)); + int bytes_read = read(fd, fc, sizeof(fc)); - close(fd); + close(fd); - if (bytes_read < 0) - err(1, "Could not read %s", path); + if (bytes_read < 0) + err(1, "Could not read %s", path); - fc[bytes_read] = '\0'; + fc[bytes_read] = '\0'; - if (memchr(ptr, '\0', bytes_read) != NULL) - return -1; + if (memchr(ptr, '\0', bytes_read) != NULL) + return -1; - ptr = strrchr(fc, ')'); + ptr = strrchr(fc, ')'); - char* token = strtok(ptr, " "); + char* token = strtok(ptr, " "); - for (int i = 0; i<20 && token; i++) - token = strtok(NULL, " "); + for (int i = 0; i<20 && token; i++) + token = strtok(NULL, " "); - if (!token) - return -1; + if (!token) + return -1; - unsigned long long temp_ts = strtoull(token, NULL, 10); - if (temp_ts == 0 || temp_ts == ULLONG_MAX) - return -1; + unsigned long long temp_ts = strtoull(token, NULL, 10); + if (temp_ts == 0 || temp_ts == ULLONG_MAX) + return -1; - *startts = temp_ts; - return 0; + *startts = temp_ts; + return 0; } int ensuredir() { - struct stat st; - int fd = open("/run/rdo", O_RDONLY, O_DIRECTORY | O_NOFOLLOW); + struct stat st; + int fd = open("/run/rdo", O_RDONLY, O_DIRECTORY | O_NOFOLLOW); - if (fd < 0) { - if (errno == ENOENT) { - if (mkdir("/run/rdo", 0700) < 0) - err(1, "Could not create /run/rdo"); + if (fd < 0) { + if (errno == ENOENT) { + if (mkdir("/run/rdo", 0700) < 0) + err(1, "Could not create /run/rdo"); - fd = open("/run/rdo", O_RDONLY, O_DIRECTORY | O_NOFOLLOW); - if (fd < 0) - err(1, "Could not open /run/rdo"); - } - else - err(1, "Could not open /run/rdo"); - } + fd = open("/run/rdo", O_RDONLY, O_DIRECTORY | O_NOFOLLOW); + if (fd < 0) + err(1, "Could not open /run/rdo"); + } + else + err(1, "Could not open /run/rdo"); + } - if (fstat(fd, &st) < 0) { - close(fd); - err(1, "Could not fstat /run/rdo"); - } + if (fstat(fd, &st) < 0) { + close(fd); + err(1, "Could not fstat /run/rdo"); + } - close(fd); + close(fd); - if (st.st_uid != 0 || st.st_mode != (0700 | S_IFDIR)) - return -1; + if (st.st_uid != 0 || st.st_mode != (0700 | S_IFDIR)) + return -1; - return 0; + return 0; } void setsession(int pid, unsigned int ts_ttl, int ruid) { - unsigned long long startts; - char path[1024], ts_str[32]; + unsigned long long startts; + char path[1024], ts_str[32]; - if (ts_ttl == 0) - return; + if (ts_ttl == 0) + return; - if (ensuredir() < 0 || getpstartts(pid, &startts) < 0) - return; + if (ensuredir() < 0 || getpstartts(pid, &startts) < 0) + return; - snprintf(path, sizeof(path), "/run/rdo/%d-%d-%llu", ruid, pid, startts); + snprintf(path, sizeof(path), "/run/rdo/%d-%d-%llu", ruid, pid, startts); - int fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0700); - if (fd < 0) { - if (errno == EEXIST) - return; - err(1, "Could not open %s", path); - } + int fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0700); + if (fd < 0) { + if (errno == EEXIST) + return; + err(1, "Could not open %s", path); + } - snprintf(ts_str, sizeof(ts_str), "%llu", (unsigned long long)time(NULL)); + snprintf(ts_str, sizeof(ts_str), "%llu", (unsigned long long)time(NULL)); - if (write(fd, ts_str, strlen(ts_str)) < 0) { - close(fd); - err(1, "Could not write to %s", path); - } + if (write(fd, ts_str, strlen(ts_str)) < 0) { + close(fd); + err(1, "Could not write to %s", path); + } - close(fd); + close(fd); - return; + return; } int getsession(int pid, unsigned int ts_ttl, int ruid) { - unsigned long long startts, current; - char path[1024], ts_str[32]; + unsigned long long startts, current; + char path[1024], ts_str[32]; - if (ts_ttl == 0) - return -1; + if (ts_ttl == 0) + return -1; - if (ensuredir() < 0 || getpstartts(pid, &startts) < 0) - return -1; + if (ensuredir() < 0 || getpstartts(pid, &startts) < 0) + return -1; - snprintf(path, sizeof(path), "/run/rdo/%d-%d-%llu", ruid, pid, startts); + snprintf(path, sizeof(path), "/run/rdo/%d-%d-%llu", ruid, pid, startts); - int fd = open(path, O_RDONLY); - if (fd < 0) { - if (errno == ENOENT) - return -1; - err(1, "Could not open %s", path); - } + int fd = open(path, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) + return -1; + err(1, "Could not open %s", path); + } - int bytes_read = read(fd, ts_str, sizeof(ts_str)); + int bytes_read = read(fd, ts_str, sizeof(ts_str)); - close(fd); + close(fd); - if (bytes_read < 0) - err(1, "Could not read %s", path); - ts_str[bytes_read] = '\0'; + if (bytes_read < 0) + err(1, "Could not read %s", path); + ts_str[bytes_read] = '\0'; - startts = strtoull(ts_str, NULL, 10); - current = time(NULL); + startts = strtoull(ts_str, NULL, 10); + current = time(NULL); - if (current - startts > ts_ttl) { - unlink(path); - return -1; - } + if (current - startts > ts_ttl) { + unlink(path); + return -1; + } - return 0; + return 0; }