Get the repository a bit closer to what will be released
[ppp.git] / contrib / pppgetpass / pppgetpass.vt.c
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
13 static int console_owner(uid_t, int);
14
15 int 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
207 static 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 }