sudo.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2014 K. Lange
  5. *
  6. * sudo
  7. *
  8. */
  9. #include <stdio.h>
  10. #include <stdint.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <unistd.h>
  14. #include <time.h>
  15. #include <termios.h>
  16. #include <errno.h>
  17. #include <pwd.h>
  18. #include <dirent.h>
  19. #include <sys/utsname.h>
  20. #include <sys/stat.h>
  21. #include <sys/time.h>
  22. #include <toaru/auth.h>
  23. #define MINUTES * 60
  24. #define SUDO_TIME 5 MINUTES
  25. static int sudo_loop(int (*prompt_callback)(char * username, char * password, int failures, char * argv[]), char * argv[]) {
  26. int fails = 0;
  27. struct stat buf;
  28. if (stat("/var/sudoers", &buf)) {
  29. mkdir("/var/sudoers", 0700);
  30. }
  31. while (1) {
  32. int need_password = 1;
  33. int need_sudoers = 1;
  34. uid_t me = getuid();
  35. if (me == 0) {
  36. need_password = 0;
  37. need_sudoers = 0;
  38. }
  39. struct passwd * p = getpwuid(me);
  40. if (!p) {
  41. fprintf(stderr, "%s: unable to obtain username for real uid=%d\n", argv[0], getuid());
  42. return 1;
  43. }
  44. char * username = p->pw_name;
  45. char token_file[64];
  46. sprintf(token_file, "/var/sudoers/%d", me); /* TODO: Restrict to this session? */
  47. if (need_password) {
  48. struct stat buf;
  49. if (!stat(token_file, &buf)) {
  50. /* check the time */
  51. if (buf.st_mtime > (SUDO_TIME) && time(NULL) - buf.st_mtime < (SUDO_TIME)) {
  52. need_password = 0;
  53. }
  54. }
  55. }
  56. if (need_password) {
  57. char * password = calloc(sizeof(char) * 1024, 1);
  58. if (prompt_callback(username, password, fails, argv)) {
  59. return 1;
  60. }
  61. int uid = toaru_auth_check_pass(username, password);
  62. free(password);
  63. if (uid < 0) {
  64. fails++;
  65. if (fails == 3) {
  66. fprintf(stderr, "%s: %d incorrect password attempts\n", argv[0], fails);
  67. return 1;
  68. }
  69. fprintf(stderr, "Sorry, try again.\n");
  70. continue;
  71. }
  72. }
  73. /* Determine if this user is in the sudoers file */
  74. if (need_sudoers) {
  75. FILE * sudoers = fopen("/etc/sudoers","r");
  76. if (!sudoers) {
  77. fprintf(stderr, "%s: /etc/sudoers is not available\n", argv[0]);
  78. return 1;
  79. }
  80. /* Read each line */
  81. int in_sudoers = 0;
  82. while (!feof(sudoers)) {
  83. char line[1024];
  84. fgets(line, 1024, sudoers);
  85. char * nl = strchr(line, '\n');
  86. if (nl) {
  87. *nl = '\0';
  88. }
  89. if (!strncmp(line,username,1024)) {
  90. in_sudoers = 1;
  91. break;
  92. }
  93. }
  94. fclose(sudoers);
  95. if (!in_sudoers) {
  96. fprintf(stderr, "%s is not in sudoers file.\n", username);
  97. return 1;
  98. }
  99. }
  100. /* Write a timestamp file */
  101. FILE * f = fopen(token_file, "w");
  102. if (!f) {
  103. fprintf(stderr, "%s: (warning) failed to create token file\n", argv[0]);
  104. }
  105. fclose(f);
  106. /* Set username to root */
  107. putenv("USER=root");
  108. /* Actually become root, so real user id = 0 */
  109. setuid(0);
  110. if (!strcmp(argv[1], "-s")) {
  111. argv[1] = getenv("SHELL");
  112. }
  113. char ** args = &argv[1];
  114. execvp(args[0], args);
  115. /* XXX: There are other things that can cause an exec to fail. */
  116. fprintf(stderr, "%s: %s: command not found\n", argv[0], args[0]);
  117. return 1;
  118. }
  119. return 0;
  120. }
  121. static int basic_callback(char * username, char * password, int fails, char * argv[]) {
  122. fprintf(stderr, "[%s] password for %s: ", argv[0], username);
  123. fflush(stderr);
  124. /* Disable echo */
  125. struct termios old, new;
  126. tcgetattr(fileno(stdin), &old);
  127. new = old;
  128. new.c_lflag &= (~ECHO);
  129. tcsetattr(fileno(stdin), TCSAFLUSH, &new);
  130. fgets(password, 1024, stdin);
  131. if (feof(stdin)) return 1;
  132. password[strlen(password)-1] = '\0';
  133. tcsetattr(fileno(stdin), TCSAFLUSH, &old);
  134. fprintf(stderr, "\n");
  135. return 0;
  136. }
  137. void usage(int argc, char * argv[]) {
  138. fprintf(stderr, "usage: %s [command]\n", argv[0]);
  139. }
  140. int main(int argc, char ** argv) {
  141. if (argc < 2) {
  142. usage(argc, argv);
  143. return 1;
  144. }
  145. return sudo_loop(basic_callback, argv);
  146. }