pppgetpass.vt.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <sys/stat.h>
  8. #include <sys/ioctl.h>
  9. #include <syslog.h>
  10. #include <termios.h>
  11. #include <sys/vt.h>
  12. static int console_owner(uid_t, int);
  13. int main(int argc, char **argv)
  14. {
  15. int console;
  16. uid_t uid;
  17. struct vt_stat origstate;
  18. int openvtnum;
  19. char openvtname[256];
  20. int openvt;
  21. gid_t gid;
  22. int chowned;
  23. FILE *fp;
  24. struct termios t;
  25. char pass[256], *nl;
  26. int outfd, passlen;
  27. ssize_t wrote;
  28. console=open("/dev/console", O_RDWR);
  29. uid=getuid();
  30. gid=getgid();
  31. seteuid(uid);
  32. openlog(argv[0], LOG_PID, LOG_DAEMON);
  33. if(argc!=4) {
  34. syslog(LOG_WARNING, "Usage error");
  35. return 1;
  36. }
  37. if(console<0) {
  38. syslog(LOG_ERR, "open(/dev/console): %m");
  39. return 1;
  40. }
  41. if(ioctl(console, VT_GETSTATE, &origstate)<0) {
  42. syslog(LOG_ERR, "VT_GETSTATE: %m");
  43. return 1;
  44. }
  45. if(uid) {
  46. if(!console_owner(uid, origstate.v_active)) {
  47. int i;
  48. for(i=0;i<64;++i) {
  49. if(i!=origstate.v_active && console_owner(uid, i))
  50. break;
  51. }
  52. if(i==64) {
  53. syslog(LOG_WARNING, "run by uid %lu not at console", (unsigned long)uid);
  54. return 1;
  55. }
  56. }
  57. }
  58. if(ioctl(console, VT_OPENQRY, &openvtnum)<0) {
  59. syslog(LOG_ERR, "VT_OPENQRY: %m");
  60. return 1;
  61. }
  62. if(openvtnum==-1) {
  63. syslog(LOG_ERR, "No free VTs");
  64. return 1;
  65. }
  66. snprintf(openvtname, sizeof openvtname, "/dev/tty%d", openvtnum);
  67. seteuid(0);
  68. openvt=open(openvtname, O_RDWR);
  69. if(openvt<0) {
  70. seteuid(uid);
  71. syslog(LOG_ERR, "open(%s): %m", openvtname);
  72. return 1;
  73. }
  74. chowned=fchown(openvt, uid, gid);
  75. if(chowned<0) {
  76. seteuid(uid);
  77. syslog(LOG_ERR, "fchown(%s): %m", openvtname);
  78. return 1;
  79. }
  80. close(console);
  81. if(ioctl(openvt, VT_ACTIVATE, openvtnum)<0) {
  82. seteuid(uid);
  83. syslog(LOG_ERR, "VT_ACTIVATE(%d): %m", openvtnum);
  84. return 1;
  85. }
  86. while(ioctl(openvt, VT_WAITACTIVE, openvtnum)<0) {
  87. if(errno!=EINTR) {
  88. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  89. seteuid(uid);
  90. syslog(LOG_ERR, "VT_WAITACTIVE(%d): %m", openvtnum);
  91. return 1;
  92. }
  93. }
  94. seteuid(uid);
  95. fp=fdopen(openvt, "r+");
  96. if(!fp) {
  97. seteuid(0);
  98. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  99. seteuid(uid);
  100. syslog(LOG_ERR, "fdopen(%s): %m", openvtname);
  101. return 1;
  102. }
  103. if(tcgetattr(openvt, &t)<0) {
  104. seteuid(0);
  105. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  106. seteuid(uid);
  107. syslog(LOG_ERR, "tcgetattr(%s): %m", openvtname);
  108. return 1;
  109. }
  110. t.c_lflag &= ~ECHO;
  111. if(tcsetattr(openvt, TCSANOW, &t)<0) {
  112. seteuid(0);
  113. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  114. seteuid(uid);
  115. syslog(LOG_ERR, "tcsetattr(%s): %m", openvtname);
  116. return 1;
  117. }
  118. if(fprintf(fp, "\033[2J\033[H")<0) {
  119. seteuid(0);
  120. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  121. seteuid(uid);
  122. syslog(LOG_ERR, "write error on %s: %m", openvtname);
  123. return 1;
  124. }
  125. if(argv[1][0] && argv[2][0]) {
  126. if(fprintf(fp, "Password for PPP client %s on server %s: ", argv[1], argv[2])<0) {
  127. seteuid(0);
  128. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  129. seteuid(uid);
  130. syslog(LOG_ERR, "write error on %s: %m", openvtname);
  131. return 1;
  132. }
  133. } else if(argv[1][0] && !argv[2][0]) {
  134. if(fprintf(fp, "Password for PPP client %s: ", argv[1])<0) {
  135. syslog(LOG_ERR, "write error on %s: %m", openvtname);
  136. seteuid(0);
  137. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  138. seteuid(uid);
  139. return 1;
  140. }
  141. } else if(!argv[1][0] && argv[2][0]) {
  142. if(fprintf(fp, "Password for PPP on server %s: ", argv[2])<0) {
  143. seteuid(0);
  144. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  145. seteuid(uid);
  146. syslog(LOG_ERR, "write error on %s: %m", openvtname);
  147. return 1;
  148. }
  149. } else {
  150. if(fprintf(fp, "Enter PPP password: ")<0) {
  151. seteuid(0);
  152. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  153. seteuid(uid);
  154. syslog(LOG_ERR, "write error on %s: %m", openvtname);
  155. return 1;
  156. }
  157. }
  158. if(!fgets(pass, sizeof pass, fp)) {
  159. seteuid(0);
  160. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  161. seteuid(uid);
  162. if(ferror(fp)) {
  163. syslog(LOG_ERR, "read error on %s: %m", openvtname);
  164. }
  165. return 1;
  166. }
  167. if((nl=strchr(pass, '\n')))
  168. *nl=0;
  169. passlen=strlen(pass);
  170. outfd=atoi(argv[3]);
  171. if((wrote=write(outfd, pass, passlen))!=passlen) {
  172. seteuid(0);
  173. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  174. seteuid(uid);
  175. if(wrote<0)
  176. syslog(LOG_ERR, "write error on outpipe: %m");
  177. else
  178. syslog(LOG_ERR, "short write on outpipe");
  179. return 1;
  180. }
  181. seteuid(0);
  182. ioctl(openvt, VT_ACTIVATE, origstate.v_active);
  183. seteuid(uid);
  184. return 0;
  185. }
  186. static int console_owner(uid_t uid, int cons)
  187. {
  188. char name[256];
  189. struct stat st;
  190. snprintf(name, sizeof name, "/dev/tty%d", cons);
  191. if(stat(name, &st)<0) {
  192. if(errno!=ENOENT)
  193. syslog(LOG_ERR, "stat(%s): %m", name);
  194. return 0;
  195. }
  196. return uid==st.st_uid;
  197. }