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