1/* 2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 - 2010 Apple Inc. 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 36#include "ntlm.h" 37#include <heim-ipc.h> 38#include <digest_asn1.h> 39 40/* 41 * 42 */ 43 44struct ntlmdgst { 45 heim_ipc ipc; 46 char *domain; 47 OM_uint32 flags; 48 struct ntlm_buf key; 49 krb5_data sessionkey; 50}; 51 52static OM_uint32 dstg_destroy(OM_uint32 *, void *); 53 54/* 55 * 56 */ 57 58static OM_uint32 59dstg_alloc(OM_uint32 *minor, void **ctx) 60{ 61 krb5_error_code ret; 62 struct ntlmdgst *c; 63 64 c = calloc(1, sizeof(*c)); 65 if (c == NULL) { 66 *minor = ENOMEM; 67 return GSS_S_FAILURE; 68 } 69 70 ret = heim_ipc_init_context("ANY:org.h5l.ntlm-service", &c->ipc); 71 if (ret) { 72 free(c); 73 *minor = ENOMEM; 74 return GSS_S_FAILURE; 75 } 76 77 *ctx = c; 78 79 return GSS_S_COMPLETE; 80} 81 82static int 83dstg_probe(OM_uint32 *minor_status, void *ctx, const char *realm, unsigned int *flags) 84{ 85 struct ntlmdgst *c = ctx; 86 heim_idata dreq, drep; 87 NTLMInitReply ir; 88 size_t size = 0; 89 NTLMInit ni; 90 int ret; 91 92 memset(&ni, 0, sizeof(ni)); 93 94 ni.flags = 0; 95 96 ASN1_MALLOC_ENCODE(NTLMInit, dreq.data, dreq.length, &ni, &size, ret); 97 if (ret) { 98 *minor_status = ret; 99 return GSS_S_FAILURE; 100 } 101 if (size != dreq.length) 102 abort(); 103 104 ret = heim_ipc_call(c->ipc, &dreq, &drep, NULL); 105 free(dreq.data); 106 if (ret) { 107 *minor_status = ret; 108 return GSS_S_FAILURE; 109 } 110 111 ret = decode_NTLMInitReply(drep.data, drep.length, &ir, &size); 112 free(drep.data); 113 if (ret) { 114 *minor_status = ret; 115 return GSS_S_FAILURE; 116 } 117 118 if (ir.ntlmNegFlags & NTLM_NEG_SIGN) 119 *flags |= NSI_NO_SIGNING; 120 121 free_NTLMInitReply(&ir); 122 123 return 0; 124} 125 126/* 127 * 128 */ 129 130static OM_uint32 131dstg_destroy(OM_uint32 *minor, void *ctx) 132{ 133 struct ntlmdgst *c = ctx; 134 krb5_data_free(&c->sessionkey); 135 if (c->ipc) 136 heim_ipc_free_context(c->ipc); 137 memset(c, 0, sizeof(*c)); 138 free(c); 139 140 return GSS_S_COMPLETE; 141} 142 143/* 144 * 145 */ 146 147static OM_uint32 148dstg_ti(OM_uint32 *minor_status, 149 ntlm_ctx ntlmctx, 150 void *ctx, 151 const char *hostname, 152 const char *domain, 153 uint32_t *negNtlmFlags) 154{ 155 struct ntlmdgst *c = ctx; 156 OM_uint32 maj_stat = GSS_S_FAILURE; 157 heim_idata dreq, drep; 158 NTLMInitReply ir; 159 size_t size = 0; 160 NTLMInit ni; 161 int ret; 162 163 memset(&ni, 0, sizeof(ni)); 164 memset(&ir, 0, sizeof(ir)); 165 166 ni.flags = 0; 167 if (hostname) 168 ni.hostname = (char **)&hostname; 169 if (domain) 170 ni.domain = (char **)&domain; 171 172 ASN1_MALLOC_ENCODE(NTLMInit, dreq.data, dreq.length, &ni, &size, ret); 173 if (ret) { 174 *minor_status = ret; 175 return GSS_S_FAILURE; 176 } 177 if (size != dreq.length) 178 abort(); 179 180 ret = heim_ipc_call(c->ipc, &dreq, &drep, NULL); 181 free(dreq.data); 182 if (ret) { 183 *minor_status = ret; 184 return GSS_S_FAILURE; 185 } 186 187 ret = decode_NTLMInitReply(drep.data, drep.length, &ir, &size); 188 free(drep.data); 189 if (ret) { 190 *minor_status = ret; 191 return GSS_S_FAILURE; 192 } 193 194 { 195 struct ntlm_buf buf; 196 197 buf.data = ir.targetinfo.data; 198 buf.length = ir.targetinfo.length; 199 200 ret = heim_ntlm_decode_targetinfo(&buf, 1, &ntlmctx->ti); 201 if (ret) { 202 free_NTLMInitReply(&ir); 203 *minor_status = ret; 204 return GSS_S_FAILURE; 205 } 206 } 207 *negNtlmFlags = ir.ntlmNegFlags; 208 209 maj_stat = GSS_S_COMPLETE; 210 211 free_NTLMInitReply(&ir); 212 213 return maj_stat; 214} 215 216/* 217 * 218 */ 219 220static OM_uint32 221dstg_type3(OM_uint32 *minor_status, 222 ntlm_ctx ntlmctx, 223 void *ctx, 224 const struct ntlm_type3 *type3, 225 ntlm_cred acceptor_cred, 226 uint32_t *flags, 227 uint32_t *avflags, 228 struct ntlm_buf *sessionkey, 229 ntlm_name *name, struct ntlm_buf *uuid, 230 struct ntlm_buf *pac) 231{ 232 struct ntlmdgst *c = ctx; 233 krb5_error_code ret; 234 NTLMRequest2 req; 235 NTLMReply rep; 236 heim_idata dreq, drep; 237 size_t size = 0; 238 239 *avflags = *flags = 0; 240 241 sessionkey->data = NULL; 242 sessionkey->length = 0; 243 *name = NULL; 244 uuid->data = NULL; 245 uuid->length = 0; 246 pac->data = NULL; 247 pac->length = 0; 248 249 memset(&req, 0, sizeof(req)); 250 memset(&rep, 0, sizeof(rep)); 251 252 req.loginUserName = type3->username; 253 req.loginDomainName = type3->targetname; 254 req.workstation = type3->ws; 255 req.ntlmFlags = type3->flags; 256 req.lmchallenge.data = ntlmctx->challenge; 257 req.lmchallenge.length = sizeof(ntlmctx->challenge); 258 req.ntChallengeResponse.data = type3->ntlm.data; 259 req.ntChallengeResponse.length = type3->ntlm.length; 260 req.lmChallengeResponse.data = type3->lm.data; 261 req.lmChallengeResponse.length = type3->lm.length; 262 req.encryptedSessionKey.data = type3->sessionkey.data; 263 req.encryptedSessionKey.length = type3->sessionkey.length; 264 req.t2targetname = ntlmctx->ti.domainname; 265 if (acceptor_cred) { 266 req.acceptorUser = acceptor_cred->user; 267 req.acceptorDomain = acceptor_cred->domain; 268 } else { 269 req.acceptorUser = ""; 270 req.acceptorDomain = ""; 271 } 272 273 /* take care of type3->targetname ? */ 274 275 ASN1_MALLOC_ENCODE(NTLMRequest2, dreq.data, dreq.length, &req, &size, ret); 276 if (ret) { 277 *minor_status = ret; 278 return GSS_S_FAILURE; 279 } 280 if (size != dreq.length) 281 abort(); 282 283 ret = heim_ipc_call(c->ipc, &dreq, &drep, NULL); 284 free(dreq.data); 285 if (ret) { 286 *minor_status = ret; 287 return gss_mg_set_error_string(GSS_NTLM_MECHANISM, GSS_S_FAILURE, ret, 288 "ipc to digest-service failed"); 289 } 290 291 ret = decode_NTLMReply(drep.data, drep.length, &rep, &size); 292 free(drep.data); 293 if (ret) { 294 *minor_status = ret; 295 return gss_mg_set_error_string(GSS_NTLM_MECHANISM, GSS_S_FAILURE, ret, 296 "message from digest-service malformed"); 297 } 298 299 if (rep.success != TRUE) { 300 ret = HNTLM_ERR_AUTH; 301 gss_mg_set_error_string(GSS_NTLM_MECHANISM, 302 GSS_S_FAILURE, ret, 303 "ntlm: authentication failed"); 304 goto out; 305 } 306 307 *flags = rep.ntlmFlags; 308 *avflags = rep.avflags; 309 310 if (rep.avflags & NTLM_TI_AV_FLAG_GUEST) 311 *flags |= NTLM_NEG_ANONYMOUS; 312 313 /* handle session key */ 314 if (rep.sessionkey) { 315 sessionkey->data = malloc(rep.sessionkey->length); 316 memcpy(sessionkey->data, rep.sessionkey->data, 317 rep.sessionkey->length); 318 sessionkey->length = rep.sessionkey->length; 319 } 320 321 *name = calloc(1, sizeof(**name)); 322 if (*name == NULL) 323 goto out; 324 (*name)->user = strdup(rep.user); 325 (*name)->domain = strdup(rep.domain); 326 if ((*name)->user == NULL || (*name)->domain == NULL) 327 goto out; 328 329 if (rep.uuid) { 330 uuid->data = malloc(rep.uuid->length); 331 memcpy(uuid->data, rep.uuid->data, rep.uuid->length); 332 uuid->length = rep.uuid->length; 333 } 334 335 free_NTLMReply(&rep); 336 337 return 0; 338 339 out: 340 free_NTLMReply(&rep); 341 *minor_status = ret; 342 return GSS_S_FAILURE; 343} 344 345/* 346 * 347 */ 348 349static void 350dstg_free_buffer(struct ntlm_buf *sessionkey) 351{ 352 if (sessionkey->data) 353 free(sessionkey->data); 354 sessionkey->data = NULL; 355 sessionkey->length = 0; 356} 357 358/* 359 * 360 */ 361 362struct ntlm_server_interface ntlmsspi_dstg_digest = { 363 "digest", 364 dstg_alloc, 365 dstg_destroy, 366 dstg_probe, 367 dstg_type3, 368 dstg_free_buffer, 369 dstg_ti 370}; 371