1 | /*
|
---|
2 | * Copyright 2005, 2006 Kai Blin
|
---|
3 | *
|
---|
4 | * This library is free software; you can redistribute it and/or
|
---|
5 | * modify it under the terms of the GNU Lesser General Public
|
---|
6 | * License as published by the Free Software Foundation; either
|
---|
7 | * version 2.1 of the License, or (at your option) any later version.
|
---|
8 | *
|
---|
9 | * This library is distributed in the hope that it will be useful,
|
---|
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
12 | * Lesser General Public License for more details.
|
---|
13 | *
|
---|
14 | * You should have received a copy of the GNU Lesser General Public
|
---|
15 | * License along with this library; if not, write to the Free Software
|
---|
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
---|
17 | *
|
---|
18 | * A dispatcher to run ntlm_auth for wine's sspi module.
|
---|
19 | */
|
---|
20 |
|
---|
21 | #include "config.h"
|
---|
22 | #include <stdarg.h>
|
---|
23 | #include <stdio.h>
|
---|
24 | #ifdef HAVE_UNISTD_H
|
---|
25 | #include <unistd.h>
|
---|
26 | #endif
|
---|
27 | #include <sys/types.h>
|
---|
28 | #ifdef HAVE_SYS_WAIT_H
|
---|
29 | #include <sys/wait.h>
|
---|
30 | #endif
|
---|
31 | #include <stdlib.h>
|
---|
32 | #include <fcntl.h>
|
---|
33 | #include "windef.h"
|
---|
34 | #include "winbase.h"
|
---|
35 | #include "winerror.h"
|
---|
36 | #include "sspi.h"
|
---|
37 | #include "secur32_priv.h"
|
---|
38 | #include "wine/debug.h"
|
---|
39 |
|
---|
40 | #define INITIAL_BUFFER_SIZE 200
|
---|
41 |
|
---|
42 | WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
|
---|
43 |
|
---|
44 | SECURITY_STATUS fork_helper(PNegoHelper *new_helper, const char *prog,
|
---|
45 | char* const argv[])
|
---|
46 | {
|
---|
47 | int pipe_in[2];
|
---|
48 | int pipe_out[2];
|
---|
49 | int i;
|
---|
50 | PNegoHelper helper;
|
---|
51 | #if 0
|
---|
52 | TRACE("%s ", debugstr_a(prog));
|
---|
53 | for(i = 0; argv[i] != NULL; ++i)
|
---|
54 | {
|
---|
55 | TRACE("%s ", debugstr_a(argv[i]));
|
---|
56 | }
|
---|
57 | TRACE("\n");
|
---|
58 |
|
---|
59 | if( pipe(pipe_in) < 0 )
|
---|
60 | {
|
---|
61 | return SEC_E_INTERNAL_ERROR;
|
---|
62 | }
|
---|
63 | if( pipe(pipe_out) < 0 )
|
---|
64 | {
|
---|
65 | close(pipe_in[0]);
|
---|
66 | close(pipe_in[1]);
|
---|
67 | return SEC_E_INTERNAL_ERROR;
|
---|
68 | }
|
---|
69 | if (!(helper = HeapAlloc(GetProcessHeap(),0, sizeof(NegoHelper))))
|
---|
70 | {
|
---|
71 | close(pipe_in[0]);
|
---|
72 | close(pipe_in[1]);
|
---|
73 | close(pipe_out[0]);
|
---|
74 | close(pipe_out[1]);
|
---|
75 | return SEC_E_INSUFFICIENT_MEMORY;
|
---|
76 | }
|
---|
77 |
|
---|
78 | helper->helper_pid = fork();
|
---|
79 |
|
---|
80 | if(helper->helper_pid == -1)
|
---|
81 | {
|
---|
82 | close(pipe_in[0]);
|
---|
83 | close(pipe_in[1]);
|
---|
84 | close(pipe_out[0]);
|
---|
85 | close(pipe_out[1]);
|
---|
86 | HeapFree( GetProcessHeap(), 0, helper );
|
---|
87 | return SEC_E_INTERNAL_ERROR;
|
---|
88 | }
|
---|
89 |
|
---|
90 | if(helper->helper_pid == 0)
|
---|
91 | {
|
---|
92 | /* We're in the child now */
|
---|
93 | close(0);
|
---|
94 | close(1);
|
---|
95 |
|
---|
96 | dup2(pipe_out[0], 0);
|
---|
97 | close(pipe_out[0]);
|
---|
98 | close(pipe_out[1]);
|
---|
99 |
|
---|
100 | dup2(pipe_in[1], 1);
|
---|
101 | close(pipe_in[0]);
|
---|
102 | close(pipe_in[1]);
|
---|
103 |
|
---|
104 | execvp(prog, argv);
|
---|
105 |
|
---|
106 | /* Whoops, we shouldn't get here. Big badaboom.*/
|
---|
107 | write(STDOUT_FILENO, "BH\n", 3);
|
---|
108 | _exit(1);
|
---|
109 | }
|
---|
110 | else
|
---|
111 | {
|
---|
112 | *new_helper = helper;
|
---|
113 | helper->major = helper->minor = helper->micro = -1;
|
---|
114 | helper->com_buf = NULL;
|
---|
115 | helper->com_buf_size = 0;
|
---|
116 | helper->com_buf_offset = 0;
|
---|
117 | helper->session_key = NULL;
|
---|
118 | helper->neg_flags = 0;
|
---|
119 | helper->crypt.ntlm.a4i = NULL;
|
---|
120 | helper->crypt.ntlm2.send_a4i = NULL;
|
---|
121 | helper->crypt.ntlm2.recv_a4i = NULL;
|
---|
122 | helper->crypt.ntlm2.send_sign_key = NULL;
|
---|
123 | helper->crypt.ntlm2.send_seal_key = NULL;
|
---|
124 | helper->crypt.ntlm2.recv_sign_key = NULL;
|
---|
125 | helper->crypt.ntlm2.recv_seal_key = NULL;
|
---|
126 | helper->pipe_in = pipe_in[0];
|
---|
127 | fcntl( pipe_in[0], F_SETFD, 1 );
|
---|
128 | close(pipe_in[1]);
|
---|
129 | helper->pipe_out = pipe_out[1];
|
---|
130 | fcntl( pipe_out[1], F_SETFD, 1 );
|
---|
131 | close(pipe_out[0]);
|
---|
132 | }
|
---|
133 | return SEC_E_OK;
|
---|
134 | #else
|
---|
135 | return SEC_E_INTERNAL_ERROR;
|
---|
136 | #endif
|
---|
137 | }
|
---|
138 |
|
---|
139 | static SECURITY_STATUS read_line(PNegoHelper helper, int *offset_len)
|
---|
140 | {
|
---|
141 | char *newline;
|
---|
142 | int read_size;
|
---|
143 | #if 0
|
---|
144 | if(helper->com_buf == NULL)
|
---|
145 | {
|
---|
146 | TRACE("Creating a new buffer for the helper\n");
|
---|
147 | if((helper->com_buf = HeapAlloc(GetProcessHeap(), 0, INITIAL_BUFFER_SIZE)) == NULL)
|
---|
148 | return SEC_E_INSUFFICIENT_MEMORY;
|
---|
149 |
|
---|
150 | /* Created a new buffer, size is INITIAL_BUFFER_SIZE, offset is 0 */
|
---|
151 | helper->com_buf_size = INITIAL_BUFFER_SIZE;
|
---|
152 | helper->com_buf_offset = 0;
|
---|
153 | }
|
---|
154 |
|
---|
155 | do
|
---|
156 | {
|
---|
157 | TRACE("offset = %d, size = %d\n", helper->com_buf_offset, helper->com_buf_size);
|
---|
158 | if(helper->com_buf_offset + INITIAL_BUFFER_SIZE > helper->com_buf_size)
|
---|
159 | {
|
---|
160 | /* increment buffer size in INITIAL_BUFFER_SIZE steps */
|
---|
161 | char *buf = HeapReAlloc(GetProcessHeap(), 0, helper->com_buf,
|
---|
162 | helper->com_buf_size + INITIAL_BUFFER_SIZE);
|
---|
163 | TRACE("Resizing buffer!\n");
|
---|
164 | if (!buf) return SEC_E_INSUFFICIENT_MEMORY;
|
---|
165 | helper->com_buf_size += INITIAL_BUFFER_SIZE;
|
---|
166 | helper->com_buf = buf;
|
---|
167 | }
|
---|
168 | if((read_size = read(helper->pipe_in, helper->com_buf + helper->com_buf_offset,
|
---|
169 | helper->com_buf_size - helper->com_buf_offset)) <= 0)
|
---|
170 | {
|
---|
171 | return SEC_E_INTERNAL_ERROR;
|
---|
172 | }
|
---|
173 |
|
---|
174 | TRACE("read_size = %d, read: %s\n", read_size,
|
---|
175 | debugstr_a(helper->com_buf + helper->com_buf_offset));
|
---|
176 | helper->com_buf_offset += read_size;
|
---|
177 | newline = memchr(helper->com_buf, '\n', helper->com_buf_offset);
|
---|
178 | }while(newline == NULL);
|
---|
179 |
|
---|
180 | /* Now, if there's a newline character, and we read more than that newline,
|
---|
181 | * we have to store the offset so we can preserve the additional data.*/
|
---|
182 | if( newline != helper->com_buf + helper->com_buf_offset)
|
---|
183 | {
|
---|
184 | TRACE("offset_len is calculated from %p - %p\n",
|
---|
185 | (helper->com_buf + helper->com_buf_offset), newline+1);
|
---|
186 | /* the length of the offset is the number of chars after the newline */
|
---|
187 | *offset_len = (helper->com_buf + helper->com_buf_offset) - (newline + 1);
|
---|
188 | }
|
---|
189 | else
|
---|
190 | {
|
---|
191 | *offset_len = 0;
|
---|
192 | }
|
---|
193 |
|
---|
194 | *newline = '\0';
|
---|
195 | #endif
|
---|
196 | return SEC_E_OK;
|
---|
197 | }
|
---|
198 |
|
---|
199 | static SECURITY_STATUS preserve_unused(PNegoHelper helper, int offset_len)
|
---|
200 | {
|
---|
201 | TRACE("offset_len = %d\n", offset_len);
|
---|
202 | #if 0
|
---|
203 | if(offset_len > 0)
|
---|
204 | {
|
---|
205 | memmove(helper->com_buf, helper->com_buf + helper->com_buf_offset,
|
---|
206 | offset_len);
|
---|
207 | helper->com_buf_offset = offset_len;
|
---|
208 | }
|
---|
209 | else
|
---|
210 | {
|
---|
211 | helper->com_buf_offset = 0;
|
---|
212 | }
|
---|
213 |
|
---|
214 | TRACE("helper->com_buf_offset was set to: %d\n", helper->com_buf_offset);
|
---|
215 | #endif
|
---|
216 | return SEC_E_OK;
|
---|
217 | }
|
---|
218 |
|
---|
219 | SECURITY_STATUS run_helper(PNegoHelper helper, char *buffer,
|
---|
220 | unsigned int max_buflen, int *buflen)
|
---|
221 | {
|
---|
222 | int offset_len;
|
---|
223 | SECURITY_STATUS sec_status = SEC_E_OK;
|
---|
224 |
|
---|
225 | TRACE("In helper: sending %s\n", debugstr_a(buffer));
|
---|
226 | #if 0
|
---|
227 | /* buffer + '\n' */
|
---|
228 | write(helper->pipe_out, buffer, lstrlenA(buffer));
|
---|
229 | write(helper->pipe_out, "\n", 1);
|
---|
230 |
|
---|
231 | if((sec_status = read_line(helper, &offset_len)) != SEC_E_OK)
|
---|
232 | {
|
---|
233 | return sec_status;
|
---|
234 | }
|
---|
235 |
|
---|
236 | TRACE("In helper: received %s\n", debugstr_a(helper->com_buf));
|
---|
237 | *buflen = lstrlenA(helper->com_buf);
|
---|
238 |
|
---|
239 | if( *buflen > max_buflen)
|
---|
240 | {
|
---|
241 | ERR("Buffer size too small(%d given, %d required) dropping data!\n",
|
---|
242 | max_buflen, *buflen);
|
---|
243 | return SEC_E_BUFFER_TOO_SMALL;
|
---|
244 | }
|
---|
245 |
|
---|
246 | if( *buflen < 2 )
|
---|
247 | {
|
---|
248 | return SEC_E_ILLEGAL_MESSAGE;
|
---|
249 | }
|
---|
250 |
|
---|
251 | /* We only get ERR if the input size is too big. On a GENSEC error,
|
---|
252 | * ntlm_auth will return BH */
|
---|
253 | if(strncmp(helper->com_buf, "ERR", 3) == 0)
|
---|
254 | {
|
---|
255 | return SEC_E_INVALID_TOKEN;
|
---|
256 | }
|
---|
257 |
|
---|
258 | memcpy(buffer, helper->com_buf, *buflen+1);
|
---|
259 |
|
---|
260 | sec_status = preserve_unused(helper, offset_len);
|
---|
261 | #endif
|
---|
262 | return sec_status;
|
---|
263 | }
|
---|
264 |
|
---|
265 | void cleanup_helper(PNegoHelper helper)
|
---|
266 | {
|
---|
267 |
|
---|
268 | TRACE("Killing helper %p\n", helper);
|
---|
269 | #if 0
|
---|
270 | if( (helper == NULL) || (helper->helper_pid == 0))
|
---|
271 | return;
|
---|
272 |
|
---|
273 | HeapFree(GetProcessHeap(), 0, helper->com_buf);
|
---|
274 |
|
---|
275 | /* closing stdin will terminate ntlm_auth */
|
---|
276 | close(helper->pipe_out);
|
---|
277 | close(helper->pipe_in);
|
---|
278 |
|
---|
279 | helper->helper_pid = 0;
|
---|
280 | HeapFree(GetProcessHeap(), 0, helper);
|
---|
281 | #endif
|
---|
282 | }
|
---|
283 |
|
---|
284 | void check_version(PNegoHelper helper)
|
---|
285 | {
|
---|
286 | char temp[80];
|
---|
287 | char *newline;
|
---|
288 | int major = 0, minor = 0, micro = 0, ret;
|
---|
289 |
|
---|
290 | TRACE("Checking version of helper\n");
|
---|
291 | #if 0
|
---|
292 | if(helper != NULL)
|
---|
293 | {
|
---|
294 | int len = read(helper->pipe_in, temp, sizeof(temp)-1);
|
---|
295 | if (len > 8)
|
---|
296 | {
|
---|
297 | if((newline = memchr(temp, '\n', len)) != NULL)
|
---|
298 | *newline = '\0';
|
---|
299 | else
|
---|
300 | temp[len] = 0;
|
---|
301 |
|
---|
302 | TRACE("Exact version is %s\n", debugstr_a(temp));
|
---|
303 | ret = sscanf(temp, "Version %d.%d.%d", &major, &minor, µ);
|
---|
304 | if(ret != 3)
|
---|
305 | {
|
---|
306 | ERR("Failed to get the helper version.\n");
|
---|
307 | helper->major = helper->minor = helper->micro = -1;
|
---|
308 | }
|
---|
309 | else
|
---|
310 | {
|
---|
311 | TRACE("Version recognized: %d.%d.%d\n", major, minor, micro);
|
---|
312 | helper->major = major;
|
---|
313 | helper->minor = minor;
|
---|
314 | helper->micro = micro;
|
---|
315 | }
|
---|
316 | }
|
---|
317 | }
|
---|
318 | #endif
|
---|
319 | }
|
---|