blob: a1520883cbbb2928c38b8398bca0431ceaf2c5eb [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001#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}