2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
12 #include "auth_ntlm.h"
13 #include "git2/sys/credential.h"
17 #include "ntlmclient.h"
20 git_http_auth_context parent
;
24 } http_auth_ntlm_context
;
26 static int ntlm_set_challenge(
27 git_http_auth_context
*c
,
28 const char *challenge
)
30 http_auth_ntlm_context
*ctx
= (http_auth_ntlm_context
*)c
;
33 GIT_ASSERT_ARG(challenge
);
35 git__free(ctx
->challenge
);
37 ctx
->challenge
= git__strdup(challenge
);
38 GIT_ERROR_CHECK_ALLOC(ctx
->challenge
);
43 static int ntlm_set_credentials(http_auth_ntlm_context
*ctx
, git_credential
*_cred
)
45 git_credential_userpass_plaintext
*cred
;
46 const char *sep
, *username
;
47 char *domain
= NULL
, *domainuser
= NULL
;
50 GIT_ASSERT(_cred
->credtype
== GIT_CREDENTIAL_USERPASS_PLAINTEXT
);
51 cred
= (git_credential_userpass_plaintext
*)_cred
;
53 if ((sep
= strchr(cred
->username
, '\\')) != NULL
) {
54 domain
= git__strndup(cred
->username
, (sep
- cred
->username
));
55 GIT_ERROR_CHECK_ALLOC(domain
);
57 domainuser
= git__strdup(sep
+ 1);
58 GIT_ERROR_CHECK_ALLOC(domainuser
);
60 username
= domainuser
;
62 username
= cred
->username
;
65 if (ntlm_client_set_credentials(ctx
->ntlm
,
66 username
, domain
, cred
->password
) < 0) {
67 git_error_set(GIT_ERROR_NET
, "could not set credentials: %s",
68 ntlm_client_errmsg(ctx
->ntlm
));
75 git__free(domainuser
);
79 static int ntlm_next_token(
81 git_http_auth_context
*c
,
84 http_auth_ntlm_context
*ctx
= (http_auth_ntlm_context
*)c
;
85 git_buf input_buf
= GIT_BUF_INIT
;
86 const unsigned char *msg
;
87 size_t challenge_len
, msg_len
;
88 int error
= GIT_EAUTH
;
93 GIT_ASSERT(ctx
->ntlm
);
95 challenge_len
= ctx
->challenge
? strlen(ctx
->challenge
) : 0;
98 ntlm_client_reset(ctx
->ntlm
);
101 * Set us complete now since it's the default case; the one
102 * incomplete case (successfully created a client request)
103 * will explicitly set that it requires a second step.
105 ctx
->complete
= true;
107 if (cred
&& ntlm_set_credentials(ctx
, cred
) != 0)
110 if (challenge_len
< 4) {
111 git_error_set(GIT_ERROR_NET
, "no ntlm challenge sent from server");
113 } else if (challenge_len
== 4) {
114 if (memcmp(ctx
->challenge
, "NTLM", 4) != 0) {
115 git_error_set(GIT_ERROR_NET
, "server did not request NTLM");
119 if (ntlm_client_negotiate(&msg
, &msg_len
, ctx
->ntlm
) != 0) {
120 git_error_set(GIT_ERROR_NET
, "ntlm authentication failed: %s",
121 ntlm_client_errmsg(ctx
->ntlm
));
125 ctx
->complete
= false;
127 if (memcmp(ctx
->challenge
, "NTLM ", 5) != 0) {
128 git_error_set(GIT_ERROR_NET
, "challenge from server was not NTLM");
132 if (git_buf_decode_base64(&input_buf
,
133 ctx
->challenge
+ 5, challenge_len
- 5) < 0) {
134 git_error_set(GIT_ERROR_NET
, "invalid NTLM challenge from server");
138 if (ntlm_client_set_challenge(ctx
->ntlm
,
139 (const unsigned char *)input_buf
.ptr
, input_buf
.size
) != 0) {
140 git_error_set(GIT_ERROR_NET
, "ntlm challenge failed: %s",
141 ntlm_client_errmsg(ctx
->ntlm
));
145 if (ntlm_client_response(&msg
, &msg_len
, ctx
->ntlm
) != 0) {
146 git_error_set(GIT_ERROR_NET
, "ntlm authentication failed: %s",
147 ntlm_client_errmsg(ctx
->ntlm
));
152 git_buf_puts(buf
, "NTLM ");
153 git_buf_encode_base64(buf
, (const char *)msg
, msg_len
);
155 if (git_buf_oom(buf
))
161 git_buf_dispose(&input_buf
);
165 static int ntlm_is_complete(git_http_auth_context
*c
)
167 http_auth_ntlm_context
*ctx
= (http_auth_ntlm_context
*)c
;
170 return (ctx
->complete
== true);
173 static void ntlm_context_free(git_http_auth_context
*c
)
175 http_auth_ntlm_context
*ctx
= (http_auth_ntlm_context
*)c
;
177 ntlm_client_free(ctx
->ntlm
);
178 git__free(ctx
->challenge
);
182 static int ntlm_init_context(
183 http_auth_ntlm_context
*ctx
,
184 const git_net_url
*url
)
188 if ((ctx
->ntlm
= ntlm_client_init(NTLM_CLIENT_DEFAULTS
)) == NULL
) {
196 int git_http_auth_ntlm(
197 git_http_auth_context
**out
,
198 const git_net_url
*url
)
200 http_auth_ntlm_context
*ctx
;
206 ctx
= git__calloc(1, sizeof(http_auth_ntlm_context
));
207 GIT_ERROR_CHECK_ALLOC(ctx
);
209 if (ntlm_init_context(ctx
, url
) < 0) {
214 ctx
->parent
.type
= GIT_HTTP_AUTH_NTLM
;
215 ctx
->parent
.credtypes
= GIT_CREDENTIAL_USERPASS_PLAINTEXT
;
216 ctx
->parent
.connection_affinity
= 1;
217 ctx
->parent
.set_challenge
= ntlm_set_challenge
;
218 ctx
->parent
.next_token
= ntlm_next_token
;
219 ctx
->parent
.is_complete
= ntlm_is_complete
;
220 ctx
->parent
.free
= ntlm_context_free
;
222 *out
= (git_http_auth_context
*)ctx
;
227 #endif /* GIT_NTLM */