Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
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.
6 - */
7 -
8 - #include "git2.h"
9 - #include "common.h"
10 - #include "buffer.h"
11 - #include "auth.h"
12 - #include "auth_ntlm.h"
13 - #include "git2/sys/credential.h"
14 -
15 - #ifdef GIT_NTLM
16 -
17 - #include "ntlm.h"
18 -
19 - typedef struct {
20 - git_http_auth_context parent;
21 - ntlm_client *ntlm;
22 - char *challenge;
23 - bool complete;
24 - } http_auth_ntlm_context;
25 -
26 ##### 2 static int ntlm_set_challenge(
27 - git_http_auth_context *c,
28 - const char *challenge)
29 - {
30 ##### 2 http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
31 -
32 ##### 2-4 assert(ctx && challenge);
33 -
34 ##### 5 git__free(ctx->challenge);
35 -
36 ##### 6 ctx->challenge = git__strdup(challenge);
37 ##### 7,8 GIT_ERROR_CHECK_ALLOC(ctx->challenge);
38 -
39 ##### 9 return 0;
40 - }
41 -
42 ##### 2 static int ntlm_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cred)
43 - {
44 - git_credential_userpass_plaintext *cred;
45 - const char *sep, *username;
46 ##### 2 char *domain = NULL, *domainuser = NULL;
47 ##### 2 int error = 0;
48 -
49 ##### 2,3 assert(_cred->credtype == GIT_CREDENTIAL_USERPASS_PLAINTEXT);
50 ##### 4 cred = (git_credential_userpass_plaintext *)_cred;
51 -
52 ##### 4 if ((sep = strchr(cred->username, '\\')) != NULL) {
53 ##### 5 domain = git__strndup(cred->username, (sep - cred->username));
54 ##### 6,7 GIT_ERROR_CHECK_ALLOC(domain);
55 -
56 ##### 8 domainuser = git__strdup(sep + 1);
57 ##### 9,10 GIT_ERROR_CHECK_ALLOC(domainuser);
58 -
59 ##### 11 username = domainuser;
60 - } else {
61 ##### 12 username = cred->username;
62 - }
63 -
64 ##### 13,14 if (ntlm_client_set_credentials(ctx->ntlm,
65 ##### 13 username, domain, cred->password) < 0) {
66 ##### 15,16 git_error_set(GIT_ERROR_NET, "could not set credentials: %s",
67 - ntlm_client_errmsg(ctx->ntlm));
68 ##### 17 error = -1;
69 ##### 17 goto done;
70 - }
71 -
72 - done:
73 ##### 18 git__free(domain);
74 ##### 19 git__free(domainuser);
75 ##### 20 return error;
76 - }
77 -
78 ##### 2 static int ntlm_next_token(
79 - git_buf *buf,
80 - git_http_auth_context *c,
81 - git_credential *cred)
82 - {
83 ##### 2 http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
84 ##### 2 git_buf input_buf = GIT_BUF_INIT;
85 - const unsigned char *msg;
86 - size_t challenge_len, msg_len;
87 ##### 2 int error = -1;
88 -
89 ##### 2-5 assert(buf && ctx && ctx->ntlm);
90 -
91 ##### 6-8 challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0;
92 -
93 ##### 9 if (ctx->complete)
94 ##### 10 ntlm_client_reset(ctx->ntlm);
95 -
96 - /*
97 - * Set us complete now since it's the default case; the one
98 - * incomplete case (successfully created a client request)
99 - * will explicitly set that it requires a second step.
100 - */
101 ##### 11 ctx->complete = true;
102 -
103 ##### 11-13 if (cred && ntlm_set_credentials(ctx, cred) != 0)
104 ##### 14 goto done;
105 -
106 ##### 15 if (challenge_len < 4) {
107 ##### 16 git_error_set(GIT_ERROR_NET, "no ntlm challenge sent from server");
108 ##### 17 goto done;
109 ##### 18 } else if (challenge_len == 4) {
110 ##### 19 if (memcmp(ctx->challenge, "NTLM", 4) != 0) {
111 ##### 20 git_error_set(GIT_ERROR_NET, "server did not request NTLM");
112 ##### 21 goto done;
113 - }
114 -
115 ##### 22,23 if (ntlm_client_negotiate(&msg, &msg_len, ctx->ntlm) != 0) {
116 ##### 24,25 git_error_set(GIT_ERROR_NET, "ntlm authentication failed: %s",
117 - ntlm_client_errmsg(ctx->ntlm));
118 ##### 26 goto done;
119 - }
120 -
121 ##### 27 ctx->complete = false;
122 - } else {
123 ##### 28 if (memcmp(ctx->challenge, "NTLM ", 5) != 0) {
124 ##### 29 git_error_set(GIT_ERROR_NET, "challenge from server was not NTLM");
125 ##### 30 goto done;
126 - }
127 -
128 ##### 31,31,32 if (git_buf_decode_base64(&input_buf,
129 ##### 31 ctx->challenge + 5, challenge_len - 5) < 0) {
130 ##### 33 git_error_set(GIT_ERROR_NET, "invalid NTLM challenge from server");
131 ##### 34 goto done;
132 - }
133 -
134 ##### 35,35,36 if (ntlm_client_set_challenge(ctx->ntlm,
135 ##### 35 (const unsigned char *)input_buf.ptr, input_buf.size) != 0) {
136 ##### 37,38 git_error_set(GIT_ERROR_NET, "ntlm challenge failed: %s",
137 - ntlm_client_errmsg(ctx->ntlm));
138 ##### 39 goto done;
139 - }
140 -
141 ##### 40,41 if (ntlm_client_response(&msg, &msg_len, ctx->ntlm) != 0) {
142 ##### 42,43 git_error_set(GIT_ERROR_NET, "ntlm authentication failed: %s",
143 - ntlm_client_errmsg(ctx->ntlm));
144 ##### 44 goto done;
145 - }
146 - }
147 -
148 ##### 45 git_buf_puts(buf, "NTLM ");
149 ##### 46 git_buf_encode_base64(buf, (const char *)msg, msg_len);
150 -
151 ##### 47,48 if (git_buf_oom(buf))
152 ##### 49 goto done;
153 -
154 ##### 50 error = 0;
155 -
156 - done:
157 ##### 51 git_buf_dispose(&input_buf);
158 ##### 52 return error;
159 - }
160 -
161 ##### 2 static int ntlm_is_complete(git_http_auth_context *c)
162 - {
163 ##### 2 http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
164 -
165 ##### 2,3 assert(ctx);
166 ##### 4 return (ctx->complete == true);
167 - }
168 -
169 ##### 2 static void ntlm_context_free(git_http_auth_context *c)
170 - {
171 ##### 2 http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
172 -
173 ##### 2 ntlm_client_free(ctx->ntlm);
174 ##### 3 git__free(ctx->challenge);
175 ##### 4 git__free(ctx);
176 ##### 5 }
177 -
178 ##### 2 static int ntlm_init_context(
179 - http_auth_ntlm_context *ctx,
180 - const git_net_url *url)
181 - {
182 - GIT_UNUSED(url);
183 -
184 ##### 2,3 if ((ctx->ntlm = ntlm_client_init(NTLM_CLIENT_DEFAULTS)) == NULL) {
185 ##### 4 git_error_set_oom();
186 ##### 5 return -1;
187 - }
188 -
189 ##### 6 return 0;
190 - }
191 -
192 ##### 2 int git_http_auth_ntlm(
193 - git_http_auth_context **out,
194 - const git_net_url *url)
195 - {
196 - http_auth_ntlm_context *ctx;
197 -
198 - GIT_UNUSED(url);
199 -
200 ##### 2 *out = NULL;
201 -
202 ##### 2 ctx = git__calloc(1, sizeof(http_auth_ntlm_context));
203 ##### 3,4 GIT_ERROR_CHECK_ALLOC(ctx);
204 -
205 ##### 5,6 if (ntlm_init_context(ctx, url) < 0) {
206 ##### 7 git__free(ctx);
207 ##### 8 return -1;
208 - }
209 -
210 ##### 9 ctx->parent.type = GIT_HTTP_AUTH_NTLM;
211 ##### 9 ctx->parent.credtypes = GIT_CREDENTIAL_USERPASS_PLAINTEXT;
212 ##### 9 ctx->parent.connection_affinity = 1;
213 ##### 9 ctx->parent.set_challenge = ntlm_set_challenge;
214 ##### 9 ctx->parent.next_token = ntlm_next_token;
215 ##### 9 ctx->parent.is_complete = ntlm_is_complete;
216 ##### 9 ctx->parent.free = ntlm_context_free;
217 -
218 ##### 9 *out = (git_http_auth_context *)ctx;
219 -
220 ##### 9 return 0;
221 - }
222 -
223 - #endif /* GIT_NTLM */