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