Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/krb5.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* GSSAPI/krb5 support for FTP - loosely based on old krb4.c | |
| 2 * | |
| 3 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan | |
| 4 * (Royal Institute of Technology, Stockholm, Sweden). | |
| 5 * Copyright (c) 2004 - 2017 Daniel Stenberg | |
| 6 * All rights reserved. | |
| 7 * | |
| 8 * Redistribution and use in source and binary forms, with or without | |
| 9 * modification, are permitted provided that the following conditions | |
| 10 * are met: | |
| 11 * | |
| 12 * 1. Redistributions of source code must retain the above copyright | |
| 13 * notice, this list of conditions and the following disclaimer. | |
| 14 * | |
| 15 * 2. Redistributions in binary form must reproduce the above copyright | |
| 16 * notice, this list of conditions and the following disclaimer in the | |
| 17 * documentation and/or other materials provided with the distribution. | |
| 18 * | |
| 19 * 3. Neither the name of the Institute nor the names of its contributors | |
| 20 * may be used to endorse or promote products derived from this software | |
| 21 * without specific prior written permission. | |
| 22 * | |
| 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND | |
| 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE | |
| 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 33 * SUCH DAMAGE. */ | |
| 34 | |
| 35 #include "curl_setup.h" | |
| 36 | |
| 37 #if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) | |
| 38 | |
| 39 #ifdef HAVE_NETDB_H | |
| 40 #include <netdb.h> | |
| 41 #endif | |
| 42 | |
| 43 #include "urldata.h" | |
| 44 #include "curl_base64.h" | |
| 45 #include "ftp.h" | |
| 46 #include "curl_gssapi.h" | |
| 47 #include "sendf.h" | |
| 48 #include "curl_sec.h" | |
| 49 #include "warnless.h" | |
| 50 | |
| 51 /* The last 3 #include files should be in this order */ | |
| 52 #include "curl_printf.h" | |
| 53 #include "curl_memory.h" | |
| 54 #include "memdebug.h" | |
| 55 | |
| 56 static int | |
| 57 krb5_init(void *app_data) | |
| 58 { | |
| 59 gss_ctx_id_t *context = app_data; | |
| 60 /* Make sure our context is initialized for krb5_end. */ | |
| 61 *context = GSS_C_NO_CONTEXT; | |
| 62 return 0; | |
| 63 } | |
| 64 | |
| 65 static int | |
| 66 krb5_check_prot(void *app_data, int level) | |
| 67 { | |
| 68 (void)app_data; /* unused */ | |
| 69 if(level == PROT_CONFIDENTIAL) | |
| 70 return -1; | |
| 71 return 0; | |
| 72 } | |
| 73 | |
| 74 static int | |
| 75 krb5_decode(void *app_data, void *buf, int len, | |
| 76 int level UNUSED_PARAM, | |
| 77 struct connectdata *conn UNUSED_PARAM) | |
| 78 { | |
| 79 gss_ctx_id_t *context = app_data; | |
| 80 OM_uint32 maj, min; | |
| 81 gss_buffer_desc enc, dec; | |
| 82 | |
| 83 (void)level; | |
| 84 (void)conn; | |
| 85 | |
| 86 enc.value = buf; | |
| 87 enc.length = len; | |
| 88 maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL); | |
| 89 if(maj != GSS_S_COMPLETE) { | |
| 90 if(len >= 4) | |
| 91 strcpy(buf, "599 "); | |
| 92 return -1; | |
| 93 } | |
| 94 | |
| 95 memcpy(buf, dec.value, dec.length); | |
| 96 len = curlx_uztosi(dec.length); | |
| 97 gss_release_buffer(&min, &dec); | |
| 98 | |
| 99 return len; | |
| 100 } | |
| 101 | |
| 102 static int | |
| 103 krb5_overhead(void *app_data, int level, int len) | |
| 104 { | |
| 105 /* no arguments are used */ | |
| 106 (void)app_data; | |
| 107 (void)level; | |
| 108 (void)len; | |
| 109 return 0; | |
| 110 } | |
| 111 | |
| 112 static int | |
| 113 krb5_encode(void *app_data, const void *from, int length, int level, void **to) | |
| 114 { | |
| 115 gss_ctx_id_t *context = app_data; | |
| 116 gss_buffer_desc dec, enc; | |
| 117 OM_uint32 maj, min; | |
| 118 int state; | |
| 119 int len; | |
| 120 | |
| 121 /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal | |
| 122 * libraries modify the input buffer in gss_wrap() | |
| 123 */ | |
| 124 dec.value = (void *)from; | |
| 125 dec.length = length; | |
| 126 maj = gss_wrap(&min, *context, | |
| 127 level == PROT_PRIVATE, | |
| 128 GSS_C_QOP_DEFAULT, | |
| 129 &dec, &state, &enc); | |
| 130 | |
| 131 if(maj != GSS_S_COMPLETE) | |
| 132 return -1; | |
| 133 | |
| 134 /* malloc a new buffer, in case gss_release_buffer doesn't work as | |
| 135 expected */ | |
| 136 *to = malloc(enc.length); | |
| 137 if(!*to) | |
| 138 return -1; | |
| 139 memcpy(*to, enc.value, enc.length); | |
| 140 len = curlx_uztosi(enc.length); | |
| 141 gss_release_buffer(&min, &enc); | |
| 142 return len; | |
| 143 } | |
| 144 | |
| 145 static int | |
| 146 krb5_auth(void *app_data, struct connectdata *conn) | |
| 147 { | |
| 148 int ret = AUTH_OK; | |
| 149 char *p; | |
| 150 const char *host = conn->host.name; | |
| 151 ssize_t nread; | |
| 152 curl_socklen_t l = sizeof(conn->local_addr); | |
| 153 struct Curl_easy *data = conn->data; | |
| 154 CURLcode result; | |
| 155 const char *service = data->set.str[STRING_SERVICE_NAME] ? | |
| 156 data->set.str[STRING_SERVICE_NAME] : | |
| 157 "ftp"; | |
| 158 const char *srv_host = "host"; | |
| 159 gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp; | |
| 160 OM_uint32 maj, min; | |
| 161 gss_name_t gssname; | |
| 162 gss_ctx_id_t *context = app_data; | |
| 163 struct gss_channel_bindings_struct chan; | |
| 164 size_t base64_sz = 0; | |
| 165 struct sockaddr_in **remote_addr = | |
| 166 (struct sockaddr_in **)&conn->ip_addr->ai_addr; | |
| 167 char *stringp; | |
| 168 | |
| 169 if(getsockname(conn->sock[FIRSTSOCKET], | |
| 170 (struct sockaddr *)&conn->local_addr, &l) < 0) | |
| 171 perror("getsockname()"); | |
| 172 | |
| 173 chan.initiator_addrtype = GSS_C_AF_INET; | |
| 174 chan.initiator_address.length = l - 4; | |
| 175 chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; | |
| 176 chan.acceptor_addrtype = GSS_C_AF_INET; | |
| 177 chan.acceptor_address.length = l - 4; | |
| 178 chan.acceptor_address.value = &(*remote_addr)->sin_addr.s_addr; | |
| 179 chan.application_data.length = 0; | |
| 180 chan.application_data.value = NULL; | |
| 181 | |
| 182 /* this loop will execute twice (once for service, once for host) */ | |
| 183 for(;;) { | |
| 184 /* this really shouldn't be repeated here, but can't help it */ | |
| 185 if(service == srv_host) { | |
| 186 result = Curl_ftpsend(conn, "AUTH GSSAPI"); | |
| 187 if(result) | |
| 188 return -2; | |
| 189 | |
| 190 if(Curl_GetFTPResponse(&nread, conn, NULL)) | |
| 191 return -1; | |
| 192 | |
| 193 if(data->state.buffer[0] != '3') | |
| 194 return -1; | |
| 195 } | |
| 196 | |
| 197 stringp = aprintf("%s@%s", service, host); | |
| 198 if(!stringp) | |
| 199 return -2; | |
| 200 | |
| 201 input_buffer.value = stringp; | |
| 202 input_buffer.length = strlen(stringp); | |
| 203 maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE, | |
| 204 &gssname); | |
| 205 free(stringp); | |
| 206 if(maj != GSS_S_COMPLETE) { | |
| 207 gss_release_name(&min, &gssname); | |
| 208 if(service == srv_host) { | |
| 209 failf(data, "Error importing service name %s@%s", service, host); | |
| 210 return AUTH_ERROR; | |
| 211 } | |
| 212 service = srv_host; | |
| 213 continue; | |
| 214 } | |
| 215 /* We pass NULL as |output_name_type| to avoid a leak. */ | |
| 216 gss_display_name(&min, gssname, &output_buffer, NULL); | |
| 217 Curl_infof(data, "Trying against %s\n", output_buffer.value); | |
| 218 gssresp = GSS_C_NO_BUFFER; | |
| 219 *context = GSS_C_NO_CONTEXT; | |
| 220 | |
| 221 do { | |
| 222 /* Release the buffer at each iteration to avoid leaking: the first time | |
| 223 we are releasing the memory from gss_display_name. The last item is | |
| 224 taken care by a final gss_release_buffer. */ | |
| 225 gss_release_buffer(&min, &output_buffer); | |
| 226 ret = AUTH_OK; | |
| 227 maj = Curl_gss_init_sec_context(data, | |
| 228 &min, | |
| 229 context, | |
| 230 gssname, | |
| 231 &Curl_krb5_mech_oid, | |
| 232 &chan, | |
| 233 gssresp, | |
| 234 &output_buffer, | |
| 235 TRUE, | |
| 236 NULL); | |
| 237 | |
| 238 if(gssresp) { | |
| 239 free(_gssresp.value); | |
| 240 gssresp = NULL; | |
| 241 } | |
| 242 | |
| 243 if(GSS_ERROR(maj)) { | |
| 244 Curl_infof(data, "Error creating security context\n"); | |
| 245 ret = AUTH_ERROR; | |
| 246 break; | |
| 247 } | |
| 248 | |
| 249 if(output_buffer.length != 0) { | |
| 250 char *cmd; | |
| 251 | |
| 252 result = Curl_base64_encode(data, (char *)output_buffer.value, | |
| 253 output_buffer.length, &p, &base64_sz); | |
| 254 if(result) { | |
| 255 Curl_infof(data, "base64-encoding: %s\n", | |
| 256 curl_easy_strerror(result)); | |
| 257 ret = AUTH_ERROR; | |
| 258 break; | |
| 259 } | |
| 260 | |
| 261 cmd = aprintf("ADAT %s", p); | |
| 262 if(cmd) | |
| 263 result = Curl_ftpsend(conn, cmd); | |
| 264 else | |
| 265 result = CURLE_OUT_OF_MEMORY; | |
| 266 | |
| 267 free(p); | |
| 268 free(cmd); | |
| 269 | |
| 270 if(result) { | |
| 271 ret = -2; | |
| 272 break; | |
| 273 } | |
| 274 | |
| 275 if(Curl_GetFTPResponse(&nread, conn, NULL)) { | |
| 276 ret = -1; | |
| 277 break; | |
| 278 } | |
| 279 | |
| 280 if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') { | |
| 281 Curl_infof(data, "Server didn't accept auth data\n"); | |
| 282 ret = AUTH_ERROR; | |
| 283 break; | |
| 284 } | |
| 285 | |
| 286 _gssresp.value = NULL; /* make sure it is initialized */ | |
| 287 p = data->state.buffer + 4; | |
| 288 p = strstr(p, "ADAT="); | |
| 289 if(p) { | |
| 290 result = Curl_base64_decode(p + 5, | |
| 291 (unsigned char **)&_gssresp.value, | |
| 292 &_gssresp.length); | |
| 293 if(result) { | |
| 294 failf(data, "base64-decoding: %s", curl_easy_strerror(result)); | |
| 295 ret = AUTH_CONTINUE; | |
| 296 break; | |
| 297 } | |
| 298 } | |
| 299 | |
| 300 gssresp = &_gssresp; | |
| 301 } | |
| 302 } while(maj == GSS_S_CONTINUE_NEEDED); | |
| 303 | |
| 304 gss_release_name(&min, &gssname); | |
| 305 gss_release_buffer(&min, &output_buffer); | |
| 306 | |
| 307 if(gssresp) | |
| 308 free(_gssresp.value); | |
| 309 | |
| 310 if(ret == AUTH_OK || service == srv_host) | |
| 311 return ret; | |
| 312 | |
| 313 service = srv_host; | |
| 314 } | |
| 315 return ret; | |
| 316 } | |
| 317 | |
| 318 static void krb5_end(void *app_data) | |
| 319 { | |
| 320 OM_uint32 min; | |
| 321 gss_ctx_id_t *context = app_data; | |
| 322 if(*context != GSS_C_NO_CONTEXT) { | |
| 323 OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER); | |
| 324 (void)maj; | |
| 325 DEBUGASSERT(maj == GSS_S_COMPLETE); | |
| 326 } | |
| 327 } | |
| 328 | |
| 329 struct Curl_sec_client_mech Curl_krb5_client_mech = { | |
| 330 "GSSAPI", | |
| 331 sizeof(gss_ctx_id_t), | |
| 332 krb5_init, | |
| 333 krb5_auth, | |
| 334 krb5_end, | |
| 335 krb5_check_prot, | |
| 336 krb5_overhead, | |
| 337 krb5_encode, | |
| 338 krb5_decode | |
| 339 }; | |
| 340 | |
| 341 #endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */ |
