-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathcopyauth.c
264 lines (255 loc) · 7.12 KB
/
copyauth.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/* This file is part of "xtrace"
* Copyright (C) 2005 Bernhard R. Link
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <errno.h>
#include <assert.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>
#include "xtrace.h"
/* This file is responsible for getting the autorisation tokens of the
* device we are connecting to and saving them for the fake device we
* are creating. This is done by calling xauth. (This allows to
* to set PATH to an alternative utility to do even more funny things,
* and is simpler than reimplementing xauth by using libXau) */
static inline ssize_t readtoend(int fd, char *buffer, size_t len) {
size_t bytesgottotal = 0;
ssize_t bytesgotlast;
do {
bytesgotlast = read(fd,buffer+bytesgottotal,len-bytesgottotal);
if( bytesgotlast < 0 ) {
int e = errno;
fprintf(stderr,"Error reading from xauth pipe: %d=%s\n",e,strerror(e));
return bytesgotlast;
} else if( bytesgotlast > 0 ) {
bytesgottotal += bytesgotlast;
if( bytesgottotal >= len ) {
fprintf(stderr,"Too much data from xauth command: more than %u\n",(unsigned int)len);
return -1;
}
}
} while( bytesgotlast != 0 );
return bytesgottotal;
}
static inline bool parseauthdata(char *buffer,const char **name,const char **data) {
char *p;
bool foundsomething = false;
char *thisname;
char *thisdata;
p = buffer;
do {
while( *p != '\0' && *p != '\n' && *p != ' ' && *p != '\t')
p++;
while( *p != '\0' && *p != '\n' && (*p == ' ' || *p == '\t') )
p++;
thisname = p;
while( *p != '\0' && *p != '\n' && *p != ' ' && *p != '\t' )
p++;
if( *p != '\0' && *p != '\n' ) {
*p = '\0';
p++;
}
while( *p != '\0' && *p != '\n' && (*p == ' ' || *p == '\t') )
p++;
thisdata = p;
while( *p != '\0' && *p != '\n' && *p != ' ' && *p != '\t' )
p++;
if( *p != '\0' && *p != '\n' ) {
*p = '\0';
p++;
}
while( *p != '\0' && *p != '\n' && (*p == ' ' || *p == '\t') )
p++;
if( *p == '\n' ) {
*p = '\0';
} else if( *p != '\0' ) {
fprintf(stderr,"Error parsing xauth list data: more than three things in a line!\n");
return false;
}
if( thisname[0] == '\0' || thisdata[0] == '\0' ) {
fprintf(stderr,"Error parsing xauth list data: less than three things in a line!\n");
return false;
}
if( strcmp(thisname,"MIT-MAGIC-COOKIE-1") == 0) {
*name = thisname;
*data = thisdata;
foundsomething = true;
}
} while( *p != '\0' );
return foundsomething;
}
bool copy_authentication(const char *fakedisplay,const char *display, const char *infile, const char *outfile) {
int pipe_fds[2];
int r,e;
pid_t pid,waitresult;
/* if this is not enough, copy manually */
char buffer[4096];
ssize_t bytesgot;
#ifdef STUPIDCC
const char *name = NULL, *data = NULL;
#else
const char *name,*data;
#endif
int status;
if( strncmp(display,"localhost:",10) == 0 ) {
/* copy with remote X DISPLAYs */
display += 9;
}
pid = fork();
if( pid < 0 ) {
e = errno;
fprintf(stderr,"Error forking: %d=%s\n",e,strerror(e));
return false;
}
if( pid == 0 ) {
int fd = open("/dev/null",O_RDONLY);
if( fd >= 0 ) {
(void)dup2(fd,0);
(void)dup2(fd,1);
if( fd > 2 )
(void)close(fd);
}
if( outfile != NULL )
r = execlp("xauth","xauth","-f",outfile,"remove",fakedisplay,(char*)NULL);
else
r = execlp("xauth","xauth","remove",fakedisplay,(char*)NULL);
exit(EXIT_FAILURE);
}
do {
waitresult = waitpid(pid,&status,0);
} while( waitresult < 0 && errno == EINTR );
if( waitresult < 0 ) {
e = errno;
fprintf(stderr,"Error waiting for xauth remove: %d=%s\n",e,strerror(e));
return false;
}
if( !WIFEXITED(status) ) {
fprintf(stderr,"Abnormal termination of xauth remove!\n");
return false;
}
if( WEXITSTATUS(status) != 0 ) {
fprintf(stderr,"xauth remove terminated with exit code %d!\n",(int)(WEXITSTATUS(status)));
return false;
}
r = pipe(pipe_fds);
if( r != 0 ) {
e = errno;
fprintf(stderr,"Error creating pipe: %d=%s\n",e,strerror(e));
return false;
}
pid = fork();
if( pid < 0 ) {
e = errno;
fprintf(stderr,"Error forking: %d=%s\n",e,strerror(e));
return false;
}
if( pid == 0 ) {
int fd = open("/dev/null",O_RDONLY);
if( fd >= 0 ) {
(void)dup2(fd,0);
if( fd > 2 )
(void)close(fd);
}
(void)close(pipe_fds[0]);
r = dup2(pipe_fds[1],1);
if( r < 0 ) {
e = errno;
fprintf(stderr,"Error connecting pipe to stdin in child process: %d=%s\n",e,strerror(e));
exit(EXIT_FAILURE);
}
(void)close(pipe_fds[1]);
if( infile != NULL )
r = execlp("xauth","xauth","-f",infile,"list",display,(char*)NULL);
else
r = execlp("xauth","xauth","list",display,(char*)NULL);
exit(EXIT_FAILURE);
}
(void)close(pipe_fds[1]);
bytesgot = readtoend(pipe_fds[0],buffer,sizeof(buffer)-1);
if( bytesgot < 0 ) {
return false;
}
r = close(pipe_fds[0]);
if( r != 0 ) {
e = errno;
fprintf(stderr,"Error reading from pipe from xauth: %d=%s\n",e,strerror(e));
return false;
}
buffer[bytesgot-1] = '\0';
do {
waitresult = waitpid(pid,&status,0);
} while( waitresult < 0 && errno == EINTR );
if( waitresult < 0 ) {
e = errno;
fprintf(stderr,"Error waiting for xauth list: %d=%s\n",e,strerror(e));
return false;
}
if( !WIFEXITED(status) ) {
fprintf(stderr,"Abnormal termination of xauth list!\n");
return false;
}
if( WEXITSTATUS(status) != 0 ) {
fprintf(stderr,"xauth list terminated with exit code %d!\n",(int)(WEXITSTATUS(status)));
return false;
}
if( !parseauthdata(buffer,&name,&data) ) {
return false;
}
pid = fork();
if( pid < 0 ) {
e = errno;
fprintf(stderr,"Error forking: %d=%s\n",e,strerror(e));
return false;
}
if( pid == 0 ) {
int fd = open("/dev/null",O_RDONLY);
if( fd >= 0 ) {
(void)dup2(fd,0);
(void)dup2(fd,1);
if( fd > 2 )
(void)close(fd);
}
if( outfile != NULL )
r = execlp("xauth","xauth","-f",outfile,"add",fakedisplay,name,data,(char*)NULL);
else
r = execlp("xauth","xauth","add",fakedisplay,name,data,(char*)NULL);
exit(EXIT_FAILURE);
}
do {
waitresult = waitpid(pid,&status,0);
} while( waitresult < 0 && errno == EINTR );
if( waitresult < 0 ) {
e = errno;
fprintf(stderr,"Error waiting for xauth add: %d=%s\n",e,strerror(e));
return false;
}
if( !WIFEXITED(status) ) {
fprintf(stderr,"Abnormal termination of xauth add!\n");
return false;
}
if( WEXITSTATUS(status) != 0 ) {
fprintf(stderr,"xauth add terminated with exit code %d!\n",(int)(WEXITSTATUS(status)));
return false;
}
return true;
}