doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
security.c
Go to the documentation of this file.
1 /* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
2  * use in Curl. His latest changes were done 2000-09-18.
3  *
4  * It has since been patched and modified a lot by Daniel Stenberg
5  * <daniel@haxx.se> to make it better applied to curl conditions, and to make
6  * it not use globals, pollute name space and more. This source code awaits a
7  * rewrite to work around the paragraph 2 in the BSD licenses as explained
8  * below.
9  *
10  * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
11  * (Royal Institute of Technology, Stockholm, Sweden).
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  *
18  * 1. Redistributions of source code must retain the above copyright
19  * notice, this list of conditions and the following disclaimer.
20  *
21  * 2. Redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution.
24  *
25  * 3. Neither the name of the Institute nor the names of its contributors
26  * may be used to endorse or promote products derived from this software
27  * without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE. */
40 
41 #include "setup.h"
42 
43 #ifndef CURL_DISABLE_FTP
44 #ifdef HAVE_KRB4
45 
46 #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
47 #include <curl/mprintf.h>
48 
49 #include "security.h"
50 #include <stdlib.h>
51 #include <string.h>
52 #include <netdb.h>
53 
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 
58 #include "base64.h"
59 #include "sendf.h"
60 #include "ftp.h"
61 
62 /* The last #include file should be: */
63 #ifdef CURLDEBUG
64 #include "memdebug.h"
65 #endif
66 
67 #define min(a, b) ((a) < (b) ? (a) : (b))
68 
69 static struct {
70  enum protection_level level;
71  const char *name;
72 } level_names[] = {
73  { prot_clear, "clear" },
74  { prot_safe, "safe" },
75  { prot_confidential, "confidential" },
76  { prot_private, "private" }
77 };
78 
79 static enum protection_level
80 name_to_level(const char *name)
81 {
82  int i;
83  for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
84  if(!strncasecmp(level_names[i].name, name, strlen(name)))
85  return level_names[i].level;
86  return (enum protection_level)-1;
87 }
88 
89 static struct Curl_sec_client_mech *mechs[] = {
90 #ifdef KRB5
91  /* not supported */
92 #endif
93 #ifdef HAVE_KRB4
95 #endif
96  NULL
97 };
98 
99 int
100 Curl_sec_getc(struct connectdata *conn, FILE *F)
101 {
102  if(conn->sec_complete && conn->data_prot) {
103  char c;
104  if(Curl_sec_read(conn, fileno(F), &c, 1) <= 0)
105  return EOF;
106  return c;
107  }
108  else
109  return getc(F);
110 }
111 
112 static int
113 block_read(int fd, void *buf, size_t len)
114 {
115  unsigned char *p = buf;
116  int b;
117  while(len) {
118  b = read(fd, p, len);
119  if (b == 0)
120  return 0;
121  else if (b < 0)
122  return -1;
123  len -= b;
124  p += b;
125  }
126  return p - (unsigned char*)buf;
127 }
128 
129 static int
130 block_write(int fd, void *buf, size_t len)
131 {
132  unsigned char *p = buf;
133  int b;
134  while(len) {
135  b = write(fd, p, len);
136  if(b < 0)
137  return -1;
138  len -= b;
139  p += b;
140  }
141  return p - (unsigned char*)buf;
142 }
143 
144 static int
145 sec_get_data(struct connectdata *conn,
146  int fd, struct krb4buffer *buf)
147 {
148  int len;
149  int b;
150 
151  b = block_read(fd, &len, sizeof(len));
152  if (b == 0)
153  return 0;
154  else if (b < 0)
155  return -1;
156  len = ntohl(len);
157  buf->data = realloc(buf->data, len);
158  b = block_read(fd, buf->data, len);
159  if (b == 0)
160  return 0;
161  else if (b < 0)
162  return -1;
163  buf->size = (conn->mech->decode)(conn->app_data, buf->data, len,
164  conn->data_prot, conn);
165  buf->index = 0;
166  return 0;
167 }
168 
169 static size_t
170 buffer_read(struct krb4buffer *buf, void *data, size_t len)
171 {
172  len = min(len, buf->size - buf->index);
173  memcpy(data, (char*)buf->data + buf->index, len);
174  buf->index += len;
175  return len;
176 }
177 
178 static size_t
179 buffer_write(struct krb4buffer *buf, void *data, size_t len)
180 {
181  if(buf->index + len > buf->size) {
182  void *tmp;
183  if(buf->data == NULL)
184  tmp = malloc(1024);
185  else
186  tmp = realloc(buf->data, buf->index + len);
187  if(tmp == NULL)
188  return -1;
189  buf->data = tmp;
190  buf->size = buf->index + len;
191  }
192  memcpy((char*)buf->data + buf->index, data, len);
193  buf->index += len;
194  return len;
195 }
196 
197 int
198 Curl_sec_read(struct connectdata *conn, int fd, void *buffer, int length)
199 {
200  size_t len;
201  int rx = 0;
202 
203  if(conn->sec_complete == 0 || conn->data_prot == 0)
204  return read(fd, buffer, length);
205 
206  if(conn->in_buffer.eof_flag){
207  conn->in_buffer.eof_flag = 0;
208  return 0;
209  }
210 
211  len = buffer_read(&conn->in_buffer, buffer, length);
212  length -= len;
213  rx += len;
214  buffer = (char*)buffer + len;
215 
216  while(length) {
217  if(sec_get_data(conn, fd, &conn->in_buffer) < 0)
218  return -1;
219  if(conn->in_buffer.size == 0) {
220  if(rx)
221  conn->in_buffer.eof_flag = 1;
222  return rx;
223  }
224  len = buffer_read(&conn->in_buffer, buffer, length);
225  length -= len;
226  rx += len;
227  buffer = (char*)buffer + len;
228  }
229  return rx;
230 }
231 
232 static int
233 sec_send(struct connectdata *conn, int fd, char *from, int length)
234 {
235  int bytes;
236  void *buf;
237  bytes = (conn->mech->encode)(conn->app_data, from, length, conn->data_prot,
238  &buf, conn);
239  bytes = htonl(bytes);
240  block_write(fd, &bytes, sizeof(bytes));
241  block_write(fd, buf, ntohl(bytes));
242  free(buf);
243  return length;
244 }
245 
246 int
247 Curl_sec_fflush_fd(struct connectdata *conn, int fd)
248 {
249  if(conn->data_prot != prot_clear) {
250  if(conn->out_buffer.index > 0){
251  Curl_sec_write(conn, fd,
252  conn->out_buffer.data, conn->out_buffer.index);
253  conn->out_buffer.index = 0;
254  }
255  sec_send(conn, fd, NULL, 0);
256  }
257  return 0;
258 }
259 
260 int
261 Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length)
262 {
263  int len = conn->buffer_size;
264  int tx = 0;
265 
266  if(conn->data_prot == prot_clear)
267  return write(fd, buffer, length);
268 
269  len -= (conn->mech->overhead)(conn->app_data, conn->data_prot, len);
270  while(length){
271  if(length < len)
272  len = length;
273  sec_send(conn, fd, buffer, len);
274  length -= len;
275  buffer += len;
276  tx += len;
277  }
278  return tx;
279 }
280 
281 int
282 Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
283 {
284  char ch = c;
285  if(conn->data_prot == prot_clear)
286  return putc(c, F);
287 
288  buffer_write(&conn->out_buffer, &ch, 1);
289  if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) {
290  Curl_sec_write(conn, fileno(F), conn->out_buffer.data,
291  conn->out_buffer.index);
292  conn->out_buffer.index = 0;
293  }
294  return c;
295 }
296 
297 int
298 Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
299 {
300  int len;
301  char *buf;
302  int code;
303 
304  buf = malloc(strlen(s));
305  len = Curl_base64_decode(s + 4, buf); /* XXX */
306 
307  len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
308  if(len < 0)
309  return -1;
310 
311  buf[len] = '\0';
312 
313  if(buf[3] == '-')
314  code = 0;
315  else
316  sscanf(buf, "%d", &code);
317  if(buf[len-1] == '\n')
318  buf[len-1] = '\0';
319  strcpy(s, buf);
320  free(buf);
321  return code;
322 }
323 
324 enum protection_level
325 Curl_set_command_prot(struct connectdata *conn, enum protection_level level)
326 {
327  enum protection_level old = conn->command_prot;
328  conn->command_prot = level;
329  return old;
330 }
331 
332 static int
333 sec_prot_internal(struct connectdata *conn, int level)
334 {
335  char *p;
336  unsigned int s = 1048576;
337  ssize_t nread;
338 
339  if(!conn->sec_complete){
340  infof(conn->data, "No security data exchange has taken place.\n");
341  return -1;
342  }
343 
344  if(level){
345  int code;
346  if(Curl_ftpsendf(conn, "PBSZ %u", s))
347  return -1;
348 
349  if(Curl_GetFTPResponse(&nread, conn, &code))
350  return -1;
351 
352  if(code/100 != '2'){
353  failf(conn->data, "Failed to set protection buffer size.");
354  return -1;
355  }
356  conn->buffer_size = s;
357 
358  p = strstr(conn->data->state.buffer, "PBSZ=");
359  if(p)
360  sscanf(p, "PBSZ=%u", &s);
361  if(s < conn->buffer_size)
362  conn->buffer_size = s;
363  }
364 
365  if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"]))
366  return -1;
367 
368  if(Curl_GetFTPResponse(&nread, conn, NULL))
369  return -1;
370 
371  if(conn->data->state.buffer[0] != '2'){
372  failf(conn->data, "Failed to set protection level.");
373  return -1;
374  }
375 
376  conn->data_prot = (enum protection_level)level;
377  return 0;
378 }
379 
380 void
382 {
383  if(conn->sec_complete && conn->data_prot != conn->request_data_prot)
384  sec_prot_internal(conn, conn->request_data_prot);
385 }
386 
387 
388 int
389 Curl_sec_request_prot(struct connectdata *conn, const char *level)
390 {
391  int l = name_to_level(level);
392  if(l == -1)
393  return -1;
394  conn->request_data_prot = (enum protection_level)l;
395  return 0;
396 }
397 
398 int
399 Curl_sec_login(struct connectdata *conn)
400 {
401  int ret;
402  struct Curl_sec_client_mech **m;
403  ssize_t nread;
404  struct SessionHandle *data=conn->data;
405  int ftpcode;
406 
407  for(m = mechs; *m && (*m)->name; m++) {
408  void *tmp;
409 
410  tmp = realloc(conn->app_data, (*m)->size);
411  if (tmp == NULL) {
412  failf (data, "realloc %u failed", (*m)->size);
413  return -1;
414  }
415  conn->app_data = tmp;
416 
417  if((*m)->init && (*(*m)->init)(conn->app_data) != 0) {
418  infof(data, "Skipping %s...\n", (*m)->name);
419  continue;
420  }
421  infof(data, "Trying %s...\n", (*m)->name);
422 
423  if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name))
424  return -1;
425 
426  if(Curl_GetFTPResponse(&nread, conn, &ftpcode))
427  return -1;
428 
429  if(conn->data->state.buffer[0] != '3'){
430  switch(ftpcode) {
431  case 504:
432  infof(data,
433  "%s is not supported by the server.\n", (*m)->name);
434  break;
435  case 534:
436  infof(data, "%s rejected as security mechanism.\n", (*m)->name);
437  break;
438  default:
439  if(conn->data->state.buffer[0] == '5') {
440  infof(data, "The server doesn't support the FTP "
441  "security extensions.\n");
442  return -1;
443  }
444  break;
445  }
446  continue;
447  }
448 
449  ret = (*(*m)->auth)(conn->app_data, conn);
450 
451  if(ret == AUTH_CONTINUE)
452  continue;
453  else if(ret != AUTH_OK){
454  /* mechanism is supposed to output error string */
455  return -1;
456  }
457  conn->mech = *m;
458  conn->sec_complete = 1;
459  conn->command_prot = prot_safe;
460  break;
461  }
462 
463  return *m == NULL;
464 }
465 
466 void
467 Curl_sec_end(struct connectdata *conn)
468 {
469  if (conn->mech != NULL) {
470  if(conn->mech->end)
471  (conn->mech->end)(conn->app_data);
472  memset(conn->app_data, 0, conn->mech->size);
473  free(conn->app_data);
474  conn->app_data = NULL;
475  }
476  conn->sec_complete = 0;
477  conn->data_prot = (enum protection_level)0;
478  conn->mech=NULL;
479 }
480 
481 #endif /* HAVE_KRB4 */
482 #endif /* CURL_DISABLE_FTP */
int Curl_sec_read_msg(struct connectdata *conn, char *, int)
#define F(x, y, z)
Definition: md5.c:103
#define min(a, b)
char buffer[BUFSIZE+1]
Definition: urldata.h:679
int strncasecmp(const char *, const char *, size_t)
const char * name
Definition: security.h:32
void Curl_sec_end(struct connectdata *)
#define AUTH_CONTINUE
Definition: security.h:45
struct Curl_sec_client_mech Curl_krb4_client_mech
#define failf
Definition: sendf.h:32
case const int
Definition: Callbacks.cpp:52
int fileno(FILE *stream)
CURLcode Curl_GetFTPResponse(ssize_t *nreadp, struct connectdata *conn, int *ftpcode)
Definition: ftp.c:208
int Curl_sec_write(struct connectdata *conn, int, char *, int)
size_t Curl_base64_decode(const char *src, char *dest)
Definition: base64.c:81
GLdouble s
Definition: glext.h:2935
struct UrlState state
Definition: urldata.h:903
GLenum GLsizei len
Definition: glext.h:3472
int Curl_sec_read(struct connectdata *conn, int, void *, int)
CURLcode Curl_ftpsendf(struct connectdata *conn, const char *fmt,...)
Definition: ftp.c:2416
int i
Definition: process.py:33
#define ssize_t
Definition: config-win32.h:27
int Curl_sec_request_prot(struct connectdata *conn, const char *level)
list l
Definition: prepare.py:17
const GLubyte * c
Definition: glext.h:4677
curl_off_t size
Definition: urldata.h:494
#define NULL
Definition: Lib.h:88
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
GLuint buffer
Definition: glext.h:3108
int Curl_sec_fflush_fd(struct connectdata *conn, int fd)
void Curl_sec_set_protection_level(struct connectdata *conn)
struct SessionHandle * data
Definition: urldata.h:403
GLubyte GLubyte b
Definition: glext.h:4662
int Curl_sec_getc(struct connectdata *conn, FILE *)
char * name
Definition: urldata.h:430
enum protection_level Curl_set_command_prot(struct connectdata *, enum protection_level)
const GLcharARB * name
Definition: glext.h:3629
GLsizei const GLcharARB const GLint * length
Definition: glext.h:3599
#define infof
Definition: sendf.h:31
GLint level
Definition: glext.h:2878
GLfloat GLfloat p
Definition: glext.h:4674
int Curl_sec_putc(struct connectdata *conn, int, FILE *)
int Curl_sec_login(struct connectdata *)