1 /* $NetBSD: digest-service.c,v 1.1.1.2 2014/04/24 12:45:27 pettai Exp $ */ 2 3 /* 4 * Copyright (c) 2006 - 2007 Kungliga Tekniska H�gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #define HC_DEPRECATED_CRYPTO 39 40 #include "headers.h" 41 #include <krb5/digest_asn1.h> 42 #include <krb5/heimntlm.h> 43 #include <heim-ipc.h> 44 #include <krb5/getarg.h> 45 46 typedef struct pk_client_params pk_client_params; 47 struct DigestREQ; 48 struct Kx509Request; 49 #include <kdc-private.h> 50 51 krb5_kdc_configuration *config; 52 53 static void 54 ntlm_service(void *ctx, const heim_idata *req, 55 const heim_icred cred, 56 heim_ipc_complete complete, 57 heim_sipc_call cctx) 58 { 59 NTLMRequest2 ntq; 60 unsigned char sessionkey[16]; 61 heim_idata rep = { 0, NULL }; 62 krb5_context context = ctx; 63 hdb_entry_ex *user = NULL; 64 Key *key = NULL; 65 NTLMReply ntp; 66 size_t size; 67 int ret; 68 const char *domain; 69 70 kdc_log(context, config, 1, "digest-request: uid=%d", 71 (int)heim_ipc_cred_get_uid(cred)); 72 73 if (heim_ipc_cred_get_uid(cred) != 0) { 74 (*complete)(cctx, EPERM, NULL); 75 return; 76 } 77 78 ntp.success = 0; 79 ntp.flags = 0; 80 ntp.sessionkey = NULL; 81 82 ret = decode_NTLMRequest2(req->data, req->length, &ntq, NULL); 83 if (ret) 84 goto failed; 85 86 /* XXX forward to NetrLogonSamLogonEx() if not a local domain */ 87 if (strcmp(ntq.loginDomainName, "BUILTIN") == 0) { 88 domain = ntq.loginDomainName; 89 } else if (strcmp(ntq.loginDomainName, "") == 0) { 90 domain = "BUILTIN"; 91 } else { 92 ret = EINVAL; 93 goto failed; 94 } 95 96 kdc_log(context, config, 1, "digest-request: user=%s/%s", 97 ntq.loginUserName, domain); 98 99 if (ntq.lmchallenge.length != 8) 100 goto failed; 101 102 if (ntq.ntChallengeResponce.length == 0) 103 goto failed; 104 105 { 106 krb5_principal client; 107 108 ret = krb5_make_principal(context, &client, domain, 109 ntq.loginUserName, NULL); 110 if (ret) 111 goto failed; 112 113 krb5_principal_set_type(context, client, KRB5_NT_NTLM); 114 115 ret = _kdc_db_fetch(context, config, client, 116 HDB_F_GET_CLIENT, NULL, NULL, &user); 117 krb5_free_principal(context, client); 118 if (ret) 119 goto failed; 120 121 ret = hdb_enctype2key(context, &user->entry, 122 ETYPE_ARCFOUR_HMAC_MD5, &key); 123 if (ret) { 124 krb5_set_error_message(context, ret, "NTLM missing arcfour key"); 125 goto failed; 126 } 127 } 128 129 kdc_log(context, config, 2, 130 "digest-request: found user, processing ntlm request", ret); 131 132 if (ntq.ntChallengeResponce.length != 24) { 133 struct ntlm_buf infotarget, answer; 134 135 answer.length = ntq.ntChallengeResponce.length; 136 answer.data = ntq.ntChallengeResponce.data; 137 138 ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, 139 key->key.keyvalue.length, 140 ntq.loginUserName, 141 ntq.loginDomainName, 142 0, 143 ntq.lmchallenge.data, 144 &answer, 145 &infotarget, 146 sessionkey); 147 if (ret) { 148 goto failed; 149 } 150 151 free(infotarget.data); 152 /* XXX verify info target */ 153 154 } else { 155 struct ntlm_buf answer; 156 157 if (ntq.flags & NTLM_NEG_NTLM2_SESSION) { 158 unsigned char sessionhash[MD5_DIGEST_LENGTH]; 159 EVP_MD_CTX *md5ctx; 160 161 /* the first first 8 bytes is the challenge, what is the other 16 bytes ? */ 162 if (ntq.lmChallengeResponce.length != 24) 163 goto failed; 164 165 md5ctx = EVP_MD_CTX_create(); 166 EVP_DigestInit_ex(md5ctx, EVP_md5(), NULL); 167 EVP_DigestUpdate(md5ctx, ntq.lmchallenge.data, 8); 168 EVP_DigestUpdate(md5ctx, ntq.lmChallengeResponce.data, 8); 169 EVP_DigestFinal_ex(md5ctx, sessionhash, NULL); 170 EVP_MD_CTX_destroy(md5ctx); 171 memcpy(ntq.lmchallenge.data, sessionhash, ntq.lmchallenge.length); 172 } 173 174 ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, 175 key->key.keyvalue.length, 176 ntq.lmchallenge.data, &answer); 177 if (ret) 178 goto failed; 179 180 if (ntq.ntChallengeResponce.length != answer.length || 181 memcmp(ntq.ntChallengeResponce.data, answer.data, answer.length) != 0) { 182 free(answer.data); 183 ret = EINVAL; 184 goto failed; 185 } 186 free(answer.data); 187 188 { 189 EVP_MD_CTX *ctxp; 190 191 ctxp = EVP_MD_CTX_create(); 192 EVP_DigestInit_ex(ctxp, EVP_md4(), NULL); 193 EVP_DigestUpdate(ctxp, key->key.keyvalue.data, key->key.keyvalue.length); 194 EVP_DigestFinal_ex(ctxp, sessionkey, NULL); 195 EVP_MD_CTX_destroy(ctxp); 196 } 197 } 198 199 ntp.success = 1; 200 201 ASN1_MALLOC_ENCODE(NTLMReply, rep.data, rep.length, &ntp, &size, ret); 202 if (ret) 203 goto failed; 204 if (rep.length != size) 205 abort(); 206 207 failed: 208 kdc_log(context, config, 1, "digest-request: %d", ret); 209 210 (*complete)(cctx, ret, &rep); 211 212 free(rep.data); 213 214 free_NTLMRequest2(&ntq); 215 if (user) 216 _kdc_free_ent (context, user); 217 } 218 219 static int help_flag; 220 static int version_flag; 221 222 static struct getargs args[] = { 223 { "help", 'h', arg_flag, &help_flag, NULL, NULL }, 224 { "version", 'v', arg_flag, &version_flag, NULL, NULL } 225 }; 226 227 static int num_args = sizeof(args) / sizeof(args[0]); 228 229 static void 230 usage(int ret) 231 { 232 arg_printusage (args, num_args, NULL, ""); 233 exit (ret); 234 } 235 236 int 237 main(int argc, char **argv) 238 { 239 krb5_context context; 240 int ret, optidx = 0; 241 242 setprogname(argv[0]); 243 244 if (getarg(args, num_args, argc, argv, &optidx)) 245 usage(1); 246 247 if (help_flag) 248 usage(0); 249 250 if (version_flag) { 251 print_version(NULL); 252 exit(0); 253 } 254 255 ret = krb5_init_context(&context); 256 if (ret) 257 krb5_errx(context, 1, "krb5_init_context"); 258 259 ret = krb5_kdc_get_config(context, &config); 260 if (ret) 261 krb5_err(context, 1, ret, "krb5_kdc_default_config"); 262 263 kdc_openlog(context, "digest-service", config); 264 265 ret = krb5_kdc_set_dbinfo(context, config); 266 if (ret) 267 krb5_err(context, 1, ret, "krb5_kdc_set_dbinfo"); 268 269 #if __APPLE__ 270 { 271 heim_sipc mach; 272 heim_sipc_launchd_mach_init("org.h5l.ntlm-service", 273 ntlm_service, context, &mach); 274 heim_sipc_timeout(60); 275 } 276 #endif 277 { 278 heim_sipc un; 279 heim_sipc_service_unix("org.h5l.ntlm-service", ntlm_service, NULL, &un); 280 } 281 282 heim_ipc_main(); 283 return 0; 284 } 285