1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2010, Mandy Wu, <mandy.wu@intel.com>
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23/*
24 * This is a fake ntlm_auth, which is used for testing NTLM single-sign-on.
25 * When DEBUGBUILD is defined, libcurl invoke this tool instead of real winbind
26 * daemon helper /usr/bin/ntlm_auth. This tool will accept commands and
27 * responses with a pre-written string saved in test case test2005.
28 */
29
30#define CURL_NO_OLDIES
31
32#include "setup.h"
33
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#define ENABLE_CURLX_PRINTF
39#include "curlx.h" /* from the private lib dir */
40#include "getpart.h"
41#include "util.h"
42
43/* include memdebug.h last */
44#include "memdebug.h"
45
46#ifndef DEFAULT_LOGFILE
47#define DEFAULT_LOGFILE "log/fake_ntlm.log"
48#endif
49
50const char *serverlogfile = DEFAULT_LOGFILE;
51
52/*
53 * Returns an allocated buffer with printable representation of input
54 * buffer contents or returns NULL on out of memory condition.
55 */
56static char *printable(char *inbuf, size_t inlength)
57{
58  char *outbuf;
59  char *newbuf;
60  size_t newsize;
61  size_t outsize;
62  size_t outincr = 0;
63  size_t i, o = 0;
64
65#define HEX_FMT_STR  "[0x%02X]"
66#define HEX_STR_LEN  6
67#define NOTHING_STR  "[NOTHING]"
68#define NOTHING_LEN  9
69
70  if(!inlength)
71    inlength = strlen(inbuf);
72
73  if(inlength) {
74    outincr = ((inlength/2) < (HEX_STR_LEN+1)) ? HEX_STR_LEN+1 : inlength/2;
75    outsize = inlength + outincr;
76  }
77  else
78    outsize = NOTHING_LEN + 1;
79
80  outbuf = malloc(outsize);
81  if(!outbuf)
82    return NULL;
83
84  if(!inlength) {
85    sprintf(&outbuf[0], "%s", NOTHING_STR);
86    return outbuf;
87  }
88
89  for(i=0; i<inlength; i++) {
90
91    if(o > outsize - (HEX_STR_LEN + 1)) {
92      newsize = outsize + outincr;
93      newbuf = realloc(outbuf, newsize);
94      if(!newbuf) {
95        free(outbuf);
96        return NULL;
97      }
98      outbuf = newbuf;
99      outsize = newsize;
100    }
101
102    if((inbuf[i] > 0x20) && (inbuf[i] < 0x7F)) {
103      outbuf[o] = inbuf[i];
104      o++;
105    }
106    else {
107      sprintf(&outbuf[o], HEX_FMT_STR, inbuf[i]);
108      o += HEX_STR_LEN;
109    }
110
111  }
112  outbuf[o] = '\0';
113
114  return outbuf;
115}
116
117int main(int argc, char *argv[])
118{
119  char buf[1024];
120  FILE *stream;
121  char *filename;
122  int error;
123  char *type1_input = NULL, *type3_input = NULL;
124  char *type1_output = NULL, *type3_output = NULL;
125  size_t size = 0;
126  long testnum;
127  const char *env;
128  int arg = 1;
129  char *helper_user = (char *)"unknown";
130  char *helper_proto = (char *)"unknown";
131  char *helper_domain = (char *)"unknown";
132  bool use_cached_creds = FALSE;
133  char *msgbuf;
134
135  buf[0] = '\0';
136
137  while(argc > arg) {
138    if(!strcmp("--use-cached-creds", argv[arg])) {
139      use_cached_creds = TRUE;
140      arg++;
141    }
142    else if(!strcmp("--helper-protocol", argv[arg])) {
143      arg++;
144      if(argc > arg)
145        helper_proto = argv[arg++];
146    }
147    else if(!strcmp("--username", argv[arg])) {
148      arg++;
149      if(argc > arg)
150        helper_user = argv[arg++];
151    }
152    else if(!strcmp("--domain", argv[arg])) {
153      arg++;
154      if(argc > arg)
155        helper_domain = argv[arg++];
156    }
157    else {
158      puts("Usage: fake_ntlm [option]\n"
159           " --use-cached-creds\n"
160           " --helper-protocol [protocol]\n"
161           " --username [username]\n"
162           " --domain [domain]");
163      exit(1);
164    }
165  }
166
167  logmsg("fake_ntlm (user: %s) (proto: %s) (domain: %s) (cached creds: %s)",
168         helper_user, helper_proto, helper_domain,
169         (use_cached_creds) ? "yes" : "no");
170
171  env = getenv("CURL_NTLM_AUTH_TESTNUM");
172  if (env) {
173    char *endptr;
174    long lnum = strtol(env, &endptr, 10);
175    if((endptr != env + strlen(env)) || (lnum < 1L)) {
176      logmsg("Test number not valid in CURL_NTLM_AUTH_TESTNUM");
177      exit(1);
178    }
179    testnum = lnum;
180  } else {
181    logmsg("Test number not specified in CURL_NTLM_AUTH_TESTNUM");
182    exit(1);
183  }
184
185  env = getenv("CURL_NTLM_AUTH_SRCDIR");
186  if (env) {
187    path = env;
188  }
189
190  filename = test2file(testnum);
191  stream=fopen(filename, "rb");
192  if(!stream) {
193    error = ERRNO;
194    logmsg("fopen() failed with error: %d %s", error, strerror(error));
195    logmsg("Error opening file: %s", filename);
196    logmsg("Couldn't open test file %ld", testnum);
197    exit(1);
198  }
199  else {
200    /* get the ntlm_auth input/output */
201    error = getpart(&type1_input, &size, "ntlm_auth_type1", "input", stream);
202    fclose(stream);
203    if(error || size == 0) {
204      logmsg("getpart() type 1 input failed with error: %d", error);
205      exit(1);
206    }
207  }
208
209  stream=fopen(filename, "rb");
210  if(!stream) {
211    error = ERRNO;
212    logmsg("fopen() failed with error: %d %s", error, strerror(error));
213    logmsg("Error opening file: %s", filename);
214    logmsg("Couldn't open test file %ld", testnum);
215    exit(1);
216  }
217  else {
218    size = 0;
219    error = getpart(&type3_input, &size, "ntlm_auth_type3", "input", stream);
220    fclose(stream);
221    if(error || size == 0) {
222      logmsg("getpart() type 3 input failed with error: %d", error);
223      exit(1);
224    }
225  }
226
227  while(fgets(buf, sizeof(buf), stdin)) {
228    if(strcmp(buf, type1_input) == 0) {
229      stream=fopen(filename, "rb");
230      if(!stream) {
231        error = ERRNO;
232        logmsg("fopen() failed with error: %d %s", error, strerror(error));
233        logmsg("Error opening file: %s", filename);
234        logmsg("Couldn't open test file %ld", testnum);
235        exit(1);
236      }
237      else {
238        size = 0;
239        error = getpart(&type1_output, &size, "ntlm_auth_type1", "output", stream);
240        fclose(stream);
241        if(error || size == 0) {
242          logmsg("getpart() type 1 output failed with error: %d", error);
243          exit(1);
244        }
245      }
246      printf("%s", type1_output);
247      fflush(stdout);
248    }
249    else if(strncmp(buf, type3_input, strlen(type3_input)) == 0) {
250      stream=fopen(filename, "rb");
251      if(!stream) {
252        error = ERRNO;
253        logmsg("fopen() failed with error: %d %s", error, strerror(error));
254        logmsg("Error opening file: %s", filename);
255        logmsg("Couldn't open test file %ld", testnum);
256        exit(1);
257      }
258      else {
259        size = 0;
260        error = getpart(&type3_output, &size, "ntlm_auth_type3", "output", stream);
261        fclose(stream);
262        if(error || size == 0) {
263          logmsg("getpart() type 3 output failed with error: %d", error);
264          exit(1);
265        }
266      }
267      printf("%s", type3_output);
268      fflush(stdout);
269    }
270    else {
271      printf("Unknown request\n");
272      msgbuf = printable(buf, 0);
273      if(msgbuf) {
274        logmsg("invalid input: '%s'\n", msgbuf);
275        free(msgbuf);
276      }
277      else
278        logmsg("OOM formatting invalid input: '%s'\n", buf);
279      exit(1);
280    }
281  }
282  return 1;
283}
284