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 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 #define HC_DEPRECATED_CRYPTO 37 38 #include "headers.h" 39 #include <digest_asn1.h> 40 #include <heimntlm.h> 41 #include <heim-ipc.h> 42 #include <getarg.h> 43 44 typedef struct pk_client_params pk_client_params; 45 struct DigestREQ; 46 struct Kx509Request; 47 #include <kdc-private.h> 48 49 krb5_kdc_configuration *config; 50 51 static void 52 ntlm_service(void *ctx, const heim_idata *req, 53 const heim_icred cred, 54 heim_ipc_complete complete, 55 heim_sipc_call cctx) 56 { 57 NTLMRequest2 ntq; 58 unsigned char sessionkey[16]; 59 heim_idata rep = { 0, NULL }; 60 krb5_context context = ctx; 61 hdb_entry_ex *user = NULL; 62 Key *key = NULL; 63 NTLMReply ntp; 64 size_t size; 65 int ret; 66 const char *domain; 67 68 kdc_log(context, config, 1, "digest-request: uid=%d", 69 (int)heim_ipc_cred_get_uid(cred)); 70 71 if (heim_ipc_cred_get_uid(cred) != 0) { 72 (*complete)(cctx, EPERM, NULL); 73 return; 74 } 75 76 ntp.success = 0; 77 ntp.flags = 0; 78 ntp.sessionkey = NULL; 79 80 ret = decode_NTLMRequest2(req->data, req->length, &ntq, NULL); 81 if (ret) 82 goto failed; 83 84 /* XXX forward to NetrLogonSamLogonEx() if not a local domain */ 85 if (strcmp(ntq.loginDomainName, "BUILTIN") == 0) { 86 domain = ntq.loginDomainName; 87 } else if (strcmp(ntq.loginDomainName, "") == 0) { 88 domain = "BUILTIN"; 89 } else { 90 ret = EINVAL; 91 goto failed; 92 } 93 94 kdc_log(context, config, 1, "digest-request: user=%s/%s", 95 ntq.loginUserName, domain); 96 97 if (ntq.lmchallenge.length != 8) 98 goto failed; 99 100 if (ntq.ntChallengeResponce.length == 0) 101 goto failed; 102 103 { 104 krb5_principal client; 105 106 ret = krb5_make_principal(context, &client, domain, 107 ntq.loginUserName, NULL); 108 if (ret) 109 goto failed; 110 111 krb5_principal_set_type(context, client, KRB5_NT_NTLM); 112 113 ret = _kdc_db_fetch(context, config, client, 114 HDB_F_GET_CLIENT, NULL, NULL, &user); 115 krb5_free_principal(context, client); 116 if (ret) 117 goto failed; 118 119 ret = hdb_enctype2key(context, &user->entry, 120 ETYPE_ARCFOUR_HMAC_MD5, &key); 121 if (ret) { 122 krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 123 goto failed; 124 } 125 } 126 127 kdc_log(context, config, 2, 128 "digest-request: found user, processing ntlm request", ret); 129 130 if (ntq.ntChallengeResponce.length != 24) { 131 struct ntlm_buf infotarget, answer; 132 133 answer.length = ntq.ntChallengeResponce.length; 134 answer.data = ntq.ntChallengeResponce.data; 135 136 ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, 137 key->key.keyvalue.length, 138 ntq.loginUserName, 139 ntq.loginDomainName, 140 0, 141 ntq.lmchallenge.data, 142 &answer, 143 &infotarget, 144 sessionkey); 145 if (ret) { 146 goto failed; 147 } 148 149 free(infotarget.data); 150 /* XXX verify info target */ 151 152 } else { 153 struct ntlm_buf answer; 154 155 if (ntq.flags & NTLM_NEG_NTLM2_SESSION) { 156 unsigned char sessionhash[MD5_DIGEST_LENGTH]; 157 EVP_MD_CTX *md5ctx; 158 159 /* the first first 8 bytes is the challenge, what is the other 16 bytes ? */ 160 if (ntq.lmChallengeResponce.length != 24) 161 goto failed; 162 163 md5ctx = EVP_MD_CTX_create(); 164 EVP_DigestInit_ex(md5ctx, EVP_md5(), NULL); 165 EVP_DigestUpdate(md5ctx, ntq.lmchallenge.data, 8); 166 EVP_DigestUpdate(md5ctx, ntq.lmChallengeResponce.data, 8); 167 EVP_DigestFinal_ex(md5ctx, sessionhash, NULL); 168 EVP_MD_CTX_destroy(md5ctx); 169 memcpy(ntq.lmchallenge.data, sessionhash, ntq.lmchallenge.length); 170 } 171 172 ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, 173 key->key.keyvalue.length, 174 ntq.lmchallenge.data, &answer); 175 if (ret) 176 goto failed; 177 178 if (ntq.ntChallengeResponce.length != answer.length || 179 memcmp(ntq.ntChallengeResponce.data, answer.data, answer.length) != 0) { 180 free(answer.data); 181 ret = EINVAL; 182 goto failed; 183 } 184 free(answer.data); 185 186 { 187 EVP_MD_CTX *ctxp; 188 189 ctxp = EVP_MD_CTX_create(); 190 EVP_DigestInit_ex(ctxp, EVP_md4(), NULL); 191 EVP_DigestUpdate(ctxp, key->key.keyvalue.data, key->key.keyvalue.length); 192 EVP_DigestFinal_ex(ctxp, sessionkey, NULL); 193 EVP_MD_CTX_destroy(ctxp); 194 } 195 } 196 197 ntp.success = 1; 198 199 ASN1_MALLOC_ENCODE(NTLMReply, rep.data, rep.length, &ntp, &size, ret); 200 if (ret) 201 goto failed; 202 if (rep.length != size) 203 abort(); 204 205 failed: 206 kdc_log(context, config, 1, "digest-request: %d", ret); 207 208 (*complete)(cctx, ret, &rep); 209 210 free(rep.data); 211 212 free_NTLMRequest2(&ntq); 213 if (user) 214 _kdc_free_ent (context, user); 215 } 216 217 static int help_flag; 218 static int version_flag; 219 220 static struct getargs args[] = { 221 { "help", 'h', arg_flag, &help_flag, NULL, NULL }, 222 { "version", 'v', arg_flag, &version_flag, NULL, NULL } 223 }; 224 225 static int num_args = sizeof(args) / sizeof(args[0]); 226 227 static void 228 usage(int ret) 229 { 230 arg_printusage (args, num_args, NULL, ""); 231 exit (ret); 232 } 233 234 int 235 main(int argc, char **argv) 236 { 237 krb5_context context; 238 int ret, optidx = 0; 239 240 setprogname(argv[0]); 241 242 if (getarg(args, num_args, argc, argv, &optidx)) 243 usage(1); 244 245 if (help_flag) 246 usage(0); 247 248 if (version_flag) { 249 print_version(NULL); 250 exit(0); 251 } 252 253 ret = krb5_init_context(&context); 254 if (ret) 255 krb5_errx(context, 1, "krb5_init_context"); 256 257 ret = krb5_kdc_get_config(context, &config); 258 if (ret) 259 krb5_err(context, 1, ret, "krb5_kdc_default_config"); 260 261 kdc_openlog(context, "digest-service", config); 262 263 ret = krb5_kdc_set_dbinfo(context, config); 264 if (ret) 265 krb5_err(context, 1, ret, "krb5_kdc_set_dbinfo"); 266 267 #if __APPLE__ 268 { 269 heim_sipc mach; 270 heim_sipc_launchd_mach_init("org.h5l.ntlm-service", 271 ntlm_service, context, &mach); 272 heim_sipc_timeout(60); 273 } 274 #endif 275 { 276 heim_sipc un; 277 heim_sipc_service_unix("org.h5l.ntlm-service", ntlm_service, NULL, &un); 278 } 279 280 heim_ipc_main(); 281 return 0; 282 } 283