1226031Sstas/* 2226031Sstas * Copyright (c) 2006 - 2007 Kungliga Tekniska H�gskolan 3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4226031Sstas * All rights reserved. 5226031Sstas * 6226031Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7226031Sstas * 8226031Sstas * Redistribution and use in source and binary forms, with or without 9226031Sstas * modification, are permitted provided that the following conditions 10226031Sstas * are met: 11226031Sstas * 12226031Sstas * 1. Redistributions of source code must retain the above copyright 13226031Sstas * notice, this list of conditions and the following disclaimer. 14226031Sstas * 15226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 16226031Sstas * notice, this list of conditions and the following disclaimer in the 17226031Sstas * documentation and/or other materials provided with the distribution. 18226031Sstas * 19226031Sstas * 3. Neither the name of the Institute nor the names of its contributors 20226031Sstas * may be used to endorse or promote products derived from this software 21226031Sstas * without specific prior written permission. 22226031Sstas * 23226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33226031Sstas * SUCH DAMAGE. 34226031Sstas */ 35226031Sstas 36226031Sstas#define HC_DEPRECATED_CRYPTO 37226031Sstas 38226031Sstas#include "headers.h" 39226031Sstas#include <digest_asn1.h> 40226031Sstas#include <heimntlm.h> 41226031Sstas#include <heim-ipc.h> 42226031Sstas#include <getarg.h> 43226031Sstas 44226031Sstastypedef struct pk_client_params pk_client_params; 45226031Sstasstruct DigestREQ; 46226031Sstasstruct Kx509Request; 47226031Sstas#include <kdc-private.h> 48226031Sstas 49226031Sstaskrb5_kdc_configuration *config; 50226031Sstas 51226031Sstasstatic void 52226031Sstasntlm_service(void *ctx, const heim_idata *req, 53226031Sstas const heim_icred cred, 54226031Sstas heim_ipc_complete complete, 55226031Sstas heim_sipc_call cctx) 56226031Sstas{ 57226031Sstas NTLMRequest2 ntq; 58226031Sstas unsigned char sessionkey[16]; 59226031Sstas heim_idata rep = { 0, NULL }; 60226031Sstas krb5_context context = ctx; 61226031Sstas hdb_entry_ex *user = NULL; 62226031Sstas Key *key = NULL; 63226031Sstas NTLMReply ntp; 64226031Sstas size_t size; 65226031Sstas int ret; 66226031Sstas const char *domain; 67226031Sstas 68226031Sstas kdc_log(context, config, 1, "digest-request: uid=%d", 69226031Sstas (int)heim_ipc_cred_get_uid(cred)); 70226031Sstas 71226031Sstas if (heim_ipc_cred_get_uid(cred) != 0) { 72226031Sstas (*complete)(cctx, EPERM, NULL); 73226031Sstas return; 74226031Sstas } 75226031Sstas 76226031Sstas ntp.success = 0; 77226031Sstas ntp.flags = 0; 78226031Sstas ntp.sessionkey = NULL; 79226031Sstas 80226031Sstas ret = decode_NTLMRequest2(req->data, req->length, &ntq, NULL); 81226031Sstas if (ret) 82226031Sstas goto failed; 83226031Sstas 84226031Sstas /* XXX forward to NetrLogonSamLogonEx() if not a local domain */ 85226031Sstas if (strcmp(ntq.loginDomainName, "BUILTIN") == 0) { 86226031Sstas domain = ntq.loginDomainName; 87226031Sstas } else if (strcmp(ntq.loginDomainName, "") == 0) { 88226031Sstas domain = "BUILTIN"; 89226031Sstas } else { 90226031Sstas ret = EINVAL; 91226031Sstas goto failed; 92226031Sstas } 93226031Sstas 94226031Sstas kdc_log(context, config, 1, "digest-request: user=%s/%s", 95226031Sstas ntq.loginUserName, domain); 96226031Sstas 97226031Sstas if (ntq.lmchallenge.length != 8) 98226031Sstas goto failed; 99226031Sstas 100226031Sstas if (ntq.ntChallengeResponce.length == 0) 101226031Sstas goto failed; 102226031Sstas 103226031Sstas { 104226031Sstas krb5_principal client; 105226031Sstas 106226031Sstas ret = krb5_make_principal(context, &client, domain, 107226031Sstas ntq.loginUserName, NULL); 108226031Sstas if (ret) 109226031Sstas goto failed; 110226031Sstas 111226031Sstas krb5_principal_set_type(context, client, KRB5_NT_NTLM); 112226031Sstas 113226031Sstas ret = _kdc_db_fetch(context, config, client, 114226031Sstas HDB_F_GET_CLIENT, NULL, NULL, &user); 115226031Sstas krb5_free_principal(context, client); 116226031Sstas if (ret) 117226031Sstas goto failed; 118226031Sstas 119226031Sstas ret = hdb_enctype2key(context, &user->entry, 120226031Sstas ETYPE_ARCFOUR_HMAC_MD5, &key); 121226031Sstas if (ret) { 122226031Sstas krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 123226031Sstas goto failed; 124226031Sstas } 125226031Sstas } 126226031Sstas 127226031Sstas kdc_log(context, config, 2, 128226031Sstas "digest-request: found user, processing ntlm request", ret); 129226031Sstas 130226031Sstas if (ntq.ntChallengeResponce.length != 24) { 131226031Sstas struct ntlm_buf infotarget, answer; 132226031Sstas 133226031Sstas answer.length = ntq.ntChallengeResponce.length; 134226031Sstas answer.data = ntq.ntChallengeResponce.data; 135226031Sstas 136226031Sstas ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, 137226031Sstas key->key.keyvalue.length, 138226031Sstas ntq.loginUserName, 139226031Sstas ntq.loginDomainName, 140226031Sstas 0, 141226031Sstas ntq.lmchallenge.data, 142226031Sstas &answer, 143226031Sstas &infotarget, 144226031Sstas sessionkey); 145226031Sstas if (ret) { 146226031Sstas goto failed; 147226031Sstas } 148226031Sstas 149226031Sstas free(infotarget.data); 150226031Sstas /* XXX verify info target */ 151226031Sstas 152226031Sstas } else { 153226031Sstas struct ntlm_buf answer; 154226031Sstas 155226031Sstas if (ntq.flags & NTLM_NEG_NTLM2_SESSION) { 156226031Sstas unsigned char sessionhash[MD5_DIGEST_LENGTH]; 157226031Sstas EVP_MD_CTX *md5ctx; 158226031Sstas 159226031Sstas /* the first first 8 bytes is the challenge, what is the other 16 bytes ? */ 160226031Sstas if (ntq.lmChallengeResponce.length != 24) 161226031Sstas goto failed; 162226031Sstas 163226031Sstas md5ctx = EVP_MD_CTX_create(); 164226031Sstas EVP_DigestInit_ex(md5ctx, EVP_md5(), NULL); 165226031Sstas EVP_DigestUpdate(md5ctx, ntq.lmchallenge.data, 8); 166226031Sstas EVP_DigestUpdate(md5ctx, ntq.lmChallengeResponce.data, 8); 167226031Sstas EVP_DigestFinal_ex(md5ctx, sessionhash, NULL); 168226031Sstas EVP_MD_CTX_destroy(md5ctx); 169226031Sstas memcpy(ntq.lmchallenge.data, sessionhash, ntq.lmchallenge.length); 170226031Sstas } 171226031Sstas 172226031Sstas ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, 173226031Sstas key->key.keyvalue.length, 174226031Sstas ntq.lmchallenge.data, &answer); 175226031Sstas if (ret) 176226031Sstas goto failed; 177226031Sstas 178226031Sstas if (ntq.ntChallengeResponce.length != answer.length || 179226031Sstas memcmp(ntq.ntChallengeResponce.data, answer.data, answer.length) != 0) { 180226031Sstas free(answer.data); 181226031Sstas ret = EINVAL; 182226031Sstas goto failed; 183226031Sstas } 184226031Sstas free(answer.data); 185226031Sstas 186226031Sstas { 187226031Sstas EVP_MD_CTX *ctxp; 188226031Sstas 189226031Sstas ctxp = EVP_MD_CTX_create(); 190226031Sstas EVP_DigestInit_ex(ctxp, EVP_md4(), NULL); 191226031Sstas EVP_DigestUpdate(ctxp, key->key.keyvalue.data, key->key.keyvalue.length); 192226031Sstas EVP_DigestFinal_ex(ctxp, sessionkey, NULL); 193226031Sstas EVP_MD_CTX_destroy(ctxp); 194226031Sstas } 195226031Sstas } 196226031Sstas 197226031Sstas ntp.success = 1; 198226031Sstas 199226031Sstas ASN1_MALLOC_ENCODE(NTLMReply, rep.data, rep.length, &ntp, &size, ret); 200226031Sstas if (ret) 201226031Sstas goto failed; 202226031Sstas if (rep.length != size) 203226031Sstas abort(); 204226031Sstas 205226031Sstas failed: 206226031Sstas kdc_log(context, config, 1, "digest-request: %d", ret); 207226031Sstas 208226031Sstas (*complete)(cctx, ret, &rep); 209226031Sstas 210226031Sstas free(rep.data); 211226031Sstas 212226031Sstas free_NTLMRequest2(&ntq); 213226031Sstas if (user) 214226031Sstas _kdc_free_ent (context, user); 215226031Sstas} 216226031Sstas 217226031Sstasstatic int help_flag; 218226031Sstasstatic int version_flag; 219226031Sstas 220226031Sstasstatic struct getargs args[] = { 221226031Sstas { "help", 'h', arg_flag, &help_flag, NULL, NULL }, 222226031Sstas { "version", 'v', arg_flag, &version_flag, NULL, NULL } 223226031Sstas}; 224226031Sstas 225226031Sstasstatic int num_args = sizeof(args) / sizeof(args[0]); 226226031Sstas 227226031Sstasstatic void 228226031Sstasusage(int ret) 229226031Sstas{ 230226031Sstas arg_printusage (args, num_args, NULL, ""); 231226031Sstas exit (ret); 232226031Sstas} 233226031Sstas 234226031Sstasint 235226031Sstasmain(int argc, char **argv) 236226031Sstas{ 237226031Sstas krb5_context context; 238226031Sstas int ret, optidx = 0; 239226031Sstas 240226031Sstas setprogname(argv[0]); 241226031Sstas 242226031Sstas if (getarg(args, num_args, argc, argv, &optidx)) 243226031Sstas usage(1); 244226031Sstas 245226031Sstas if (help_flag) 246226031Sstas usage(0); 247226031Sstas 248226031Sstas if (version_flag) { 249226031Sstas print_version(NULL); 250226031Sstas exit(0); 251226031Sstas } 252226031Sstas 253226031Sstas ret = krb5_init_context(&context); 254226031Sstas if (ret) 255226031Sstas krb5_errx(context, 1, "krb5_init_context"); 256226031Sstas 257226031Sstas ret = krb5_kdc_get_config(context, &config); 258226031Sstas if (ret) 259226031Sstas krb5_err(context, 1, ret, "krb5_kdc_default_config"); 260226031Sstas 261226031Sstas kdc_openlog(context, "digest-service", config); 262226031Sstas 263226031Sstas ret = krb5_kdc_set_dbinfo(context, config); 264226031Sstas if (ret) 265226031Sstas krb5_err(context, 1, ret, "krb5_kdc_set_dbinfo"); 266226031Sstas 267226031Sstas#if __APPLE__ 268226031Sstas { 269226031Sstas heim_sipc mach; 270226031Sstas heim_sipc_launchd_mach_init("org.h5l.ntlm-service", 271226031Sstas ntlm_service, context, &mach); 272226031Sstas heim_sipc_timeout(60); 273226031Sstas } 274226031Sstas#endif 275226031Sstas { 276226031Sstas heim_sipc un; 277226031Sstas heim_sipc_service_unix("org.h5l.ntlm-service", ntlm_service, NULL, &un); 278226031Sstas } 279226031Sstas 280226031Sstas heim_ipc_main(); 281226031Sstas return 0; 282226031Sstas} 283