00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
00026 defined(NTLM_WB_ENABLED)
00027
00028
00029
00030
00031
00032
00033
00034
00035 #define DEBUG_ME 0
00036
00037 #ifdef HAVE_SYS_WAIT_H
00038 #include <sys/wait.h>
00039 #endif
00040 #ifdef HAVE_SIGNAL_H
00041 #include <signal.h>
00042 #endif
00043 #ifdef HAVE_PWD_H
00044 #include <pwd.h>
00045 #endif
00046
00047 #include "urldata.h"
00048 #include "sendf.h"
00049 #include "select.h"
00050 #include "vauth/ntlm.h"
00051 #include "curl_ntlm_wb.h"
00052 #include "url.h"
00053 #include "strerror.h"
00054 #include "strdup.h"
00055
00056 #include "curl_printf.h"
00057 #include "curl_memory.h"
00058 #include "memdebug.h"
00059
00060 #if DEBUG_ME
00061 # define DEBUG_OUT(x) x
00062 #else
00063 # define DEBUG_OUT(x) Curl_nop_stmt
00064 #endif
00065
00066
00067
00068 #if defined(HAVE_CLOSESOCKET)
00069 # define sclose_nolog(x) closesocket((x))
00070 #elif defined(HAVE_CLOSESOCKET_CAMEL)
00071 # define sclose_nolog(x) CloseSocket((x))
00072 #else
00073 # define sclose_nolog(x) close((x))
00074 #endif
00075
00076 void Curl_ntlm_wb_cleanup(struct connectdata *conn)
00077 {
00078 if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
00079 sclose(conn->ntlm_auth_hlpr_socket);
00080 conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
00081 }
00082
00083 if(conn->ntlm_auth_hlpr_pid) {
00084 int i;
00085 for(i = 0; i < 4; i++) {
00086 pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG);
00087 if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD)
00088 break;
00089 switch(i) {
00090 case 0:
00091 kill(conn->ntlm_auth_hlpr_pid, SIGTERM);
00092 break;
00093 case 1:
00094
00095
00096 Curl_wait_ms(1);
00097 break;
00098 case 2:
00099 kill(conn->ntlm_auth_hlpr_pid, SIGKILL);
00100 break;
00101 case 3:
00102 break;
00103 }
00104 }
00105 conn->ntlm_auth_hlpr_pid = 0;
00106 }
00107
00108 free(conn->challenge_header);
00109 conn->challenge_header = NULL;
00110 free(conn->response_header);
00111 conn->response_header = NULL;
00112 }
00113
00114 static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
00115 {
00116 curl_socket_t sockfds[2];
00117 pid_t child_pid;
00118 const char *username;
00119 char *slash, *domain = NULL;
00120 const char *ntlm_auth = NULL;
00121 char *ntlm_auth_alloc = NULL;
00122 #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
00123 struct passwd pw, *pw_res;
00124 char pwbuf[1024];
00125 #endif
00126 int error;
00127
00128
00129 if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
00130 conn->ntlm_auth_hlpr_pid)
00131 return CURLE_OK;
00132
00133 username = userp;
00134
00135
00136
00137
00138
00139
00140
00141
00142 if(!username || !username[0]) {
00143 username = getenv("NTLMUSER");
00144 if(!username || !username[0])
00145 username = getenv("LOGNAME");
00146 if(!username || !username[0])
00147 username = getenv("USER");
00148 #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
00149 if((!username || !username[0]) &&
00150 !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) &&
00151 pw_res) {
00152 username = pw.pw_name;
00153 }
00154 #endif
00155 if(!username || !username[0])
00156 username = userp;
00157 }
00158 slash = strpbrk(username, "\\/");
00159 if(slash) {
00160 domain = strdup(username);
00161 if(!domain)
00162 return CURLE_OUT_OF_MEMORY;
00163 slash = domain + (slash - username);
00164 *slash = '\0';
00165 username = username + (slash - domain) + 1;
00166 }
00167
00168
00169
00170
00171
00172 #ifdef DEBUGBUILD
00173 ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE");
00174 if(ntlm_auth_alloc)
00175 ntlm_auth = ntlm_auth_alloc;
00176 else
00177 #endif
00178 ntlm_auth = NTLM_WB_FILE;
00179
00180 if(access(ntlm_auth, X_OK) != 0) {
00181 error = ERRNO;
00182 failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s",
00183 ntlm_auth, error, Curl_strerror(conn, error));
00184 goto done;
00185 }
00186
00187 if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
00188 error = ERRNO;
00189 failf(conn->data, "Could not open socket pair. errno %d: %s",
00190 error, Curl_strerror(conn, error));
00191 goto done;
00192 }
00193
00194 child_pid = fork();
00195 if(child_pid == -1) {
00196 error = ERRNO;
00197 sclose(sockfds[0]);
00198 sclose(sockfds[1]);
00199 failf(conn->data, "Could not fork. errno %d: %s",
00200 error, Curl_strerror(conn, error));
00201 goto done;
00202 }
00203 else if(!child_pid) {
00204
00205
00206
00207
00208
00209 sclose_nolog(sockfds[0]);
00210 if(dup2(sockfds[1], STDIN_FILENO) == -1) {
00211 error = ERRNO;
00212 failf(conn->data, "Could not redirect child stdin. errno %d: %s",
00213 error, Curl_strerror(conn, error));
00214 exit(1);
00215 }
00216
00217 if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
00218 error = ERRNO;
00219 failf(conn->data, "Could not redirect child stdout. errno %d: %s",
00220 error, Curl_strerror(conn, error));
00221 exit(1);
00222 }
00223
00224 if(domain)
00225 execl(ntlm_auth, ntlm_auth,
00226 "--helper-protocol", "ntlmssp-client-1",
00227 "--use-cached-creds",
00228 "--username", username,
00229 "--domain", domain,
00230 NULL);
00231 else
00232 execl(ntlm_auth, ntlm_auth,
00233 "--helper-protocol", "ntlmssp-client-1",
00234 "--use-cached-creds",
00235 "--username", username,
00236 NULL);
00237
00238 error = ERRNO;
00239 sclose_nolog(sockfds[1]);
00240 failf(conn->data, "Could not execl(). errno %d: %s",
00241 error, Curl_strerror(conn, error));
00242 exit(1);
00243 }
00244
00245 sclose(sockfds[1]);
00246 conn->ntlm_auth_hlpr_socket = sockfds[0];
00247 conn->ntlm_auth_hlpr_pid = child_pid;
00248 free(domain);
00249 free(ntlm_auth_alloc);
00250 return CURLE_OK;
00251
00252 done:
00253 free(domain);
00254 free(ntlm_auth_alloc);
00255 return CURLE_REMOTE_ACCESS_DENIED;
00256 }
00257
00258 static CURLcode ntlm_wb_response(struct connectdata *conn,
00259 const char *input, curlntlm state)
00260 {
00261 char *buf = malloc(NTLM_BUFSIZE);
00262 size_t len_in = strlen(input), len_out = 0;
00263
00264 if(!buf)
00265 return CURLE_OUT_OF_MEMORY;
00266
00267 while(len_in > 0) {
00268 ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in);
00269 if(written == -1) {
00270
00271 if(errno == EINTR)
00272 continue;
00273
00274 goto done;
00275 }
00276 input += written;
00277 len_in -= written;
00278 }
00279
00280 while(1) {
00281 ssize_t size;
00282 char *newbuf;
00283
00284 size = sread(conn->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE);
00285 if(size == -1) {
00286 if(errno == EINTR)
00287 continue;
00288 goto done;
00289 }
00290 else if(size == 0)
00291 goto done;
00292
00293 len_out += size;
00294 if(buf[len_out - 1] == '\n') {
00295 buf[len_out - 1] = '\0';
00296 break;
00297 }
00298 newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE);
00299 if(!newbuf)
00300 return CURLE_OUT_OF_MEMORY;
00301
00302 buf = newbuf;
00303 }
00304
00305
00306 if(state == NTLMSTATE_TYPE1 &&
00307 len_out == 3 &&
00308 buf[0] == 'P' && buf[1] == 'W')
00309 goto done;
00310
00311 if(len_out < 4)
00312 goto done;
00313 if(state == NTLMSTATE_TYPE1 &&
00314 (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' '))
00315 goto done;
00316 if(state == NTLMSTATE_TYPE2 &&
00317 (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') &&
00318 (buf[0]!='A' || buf[1]!='F' || buf[2]!=' '))
00319 goto done;
00320
00321 conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3);
00322 free(buf);
00323 return CURLE_OK;
00324 done:
00325 free(buf);
00326 return CURLE_REMOTE_ACCESS_DENIED;
00327 }
00328
00329
00330
00331
00332
00333 CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
00334 bool proxy)
00335 {
00336
00337
00338 char **allocuserpwd;
00339
00340 const char *userp;
00341
00342 struct ntlmdata *ntlm;
00343 struct auth *authp;
00344
00345 CURLcode res = CURLE_OK;
00346 char *input;
00347
00348 DEBUGASSERT(conn);
00349 DEBUGASSERT(conn->data);
00350
00351 if(proxy) {
00352 allocuserpwd = &conn->allocptr.proxyuserpwd;
00353 userp = conn->http_proxy.user;
00354 ntlm = &conn->proxyntlm;
00355 authp = &conn->data->state.authproxy;
00356 }
00357 else {
00358 allocuserpwd = &conn->allocptr.userpwd;
00359 userp = conn->user;
00360 ntlm = &conn->ntlm;
00361 authp = &conn->data->state.authhost;
00362 }
00363 authp->done = FALSE;
00364
00365
00366 if(!userp)
00367 userp="";
00368
00369 switch(ntlm->state) {
00370 case NTLMSTATE_TYPE1:
00371 default:
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 res = ntlm_wb_init(conn, userp);
00386 if(res)
00387 return res;
00388 res = ntlm_wb_response(conn, "YR\n", ntlm->state);
00389 if(res)
00390 return res;
00391
00392 free(*allocuserpwd);
00393 *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
00394 proxy ? "Proxy-" : "",
00395 conn->response_header);
00396 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
00397 free(conn->response_header);
00398 conn->response_header = NULL;
00399 break;
00400 case NTLMSTATE_TYPE2:
00401 input = aprintf("TT %s\n", conn->challenge_header);
00402 if(!input)
00403 return CURLE_OUT_OF_MEMORY;
00404 res = ntlm_wb_response(conn, input, ntlm->state);
00405 free(input);
00406 input = NULL;
00407 if(res)
00408 return res;
00409
00410 free(*allocuserpwd);
00411 *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
00412 proxy ? "Proxy-" : "",
00413 conn->response_header);
00414 DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
00415 ntlm->state = NTLMSTATE_TYPE3;
00416 authp->done = TRUE;
00417 Curl_ntlm_wb_cleanup(conn);
00418 break;
00419 case NTLMSTATE_TYPE3:
00420
00421
00422 free(*allocuserpwd);
00423 *allocuserpwd=NULL;
00424 authp->done = TRUE;
00425 break;
00426 }
00427
00428 return CURLE_OK;
00429 }
00430
00431 #endif