| 1 | /*
 | 
|---|
| 2 |  * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
 | 
|---|
| 3 |  * (Royal Institute of Technology, Stockholm, Sweden).
 | 
|---|
| 4 |  * All rights reserved.
 | 
|---|
| 5 |  *
 | 
|---|
| 6 |  * Redistribution and use in source and binary forms, with or without
 | 
|---|
| 7 |  * modification, are permitted provided that the following conditions
 | 
|---|
| 8 |  * are met:
 | 
|---|
| 9 |  *
 | 
|---|
| 10 |  * 1. Redistributions of source code must retain the above copyright
 | 
|---|
| 11 |  *    notice, this list of conditions and the following disclaimer.
 | 
|---|
| 12 |  *
 | 
|---|
| 13 |  * 2. Redistributions in binary form must reproduce the above copyright
 | 
|---|
| 14 |  *    notice, this list of conditions and the following disclaimer in the
 | 
|---|
| 15 |  *    documentation and/or other materials provided with the distribution.
 | 
|---|
| 16 |  *
 | 
|---|
| 17 |  * 3. Neither the name of the Institute nor the names of its contributors
 | 
|---|
| 18 |  *    may be used to endorse or promote products derived from this software
 | 
|---|
| 19 |  *    without specific prior written permission.
 | 
|---|
| 20 |  *
 | 
|---|
| 21 |  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 | 
|---|
| 22 |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
|---|
| 23 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
|---|
| 24 |  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 | 
|---|
| 25 |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
|---|
| 26 |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
|---|
| 27 |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
|---|
| 28 |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
|---|
| 29 |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
|---|
| 30 |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
|---|
| 31 |  * SUCH DAMAGE.
 | 
|---|
| 32 |  */
 | 
|---|
| 33 | 
 | 
|---|
| 34 | #define HC_DEPRECATED_CRYPTO
 | 
|---|
| 35 | 
 | 
|---|
| 36 | #include "kuser_locl.h"
 | 
|---|
| 37 | 
 | 
|---|
| 38 | #include <kdigest-commands.h>
 | 
|---|
| 39 | #include <hex.h>
 | 
|---|
| 40 | #include <base64.h>
 | 
|---|
| 41 | #include <heimntlm.h>
 | 
|---|
| 42 | #include "crypto-headers.h"
 | 
|---|
| 43 | 
 | 
|---|
| 44 | static int version_flag = 0;
 | 
|---|
| 45 | static int help_flag    = 0;
 | 
|---|
| 46 | static char *ccache_string;
 | 
|---|
| 47 | static krb5_ccache id;
 | 
|---|
| 48 | 
 | 
|---|
| 49 | static struct getargs args[] = {
 | 
|---|
| 50 |     {"ccache",  0,      arg_string,     &ccache_string, "credential cache", NULL },
 | 
|---|
| 51 |     {"version", 0,      arg_flag,       &version_flag, "print version", NULL },
 | 
|---|
| 52 |     {"help",    0,      arg_flag,       &help_flag,  NULL, NULL }
 | 
|---|
| 53 | };
 | 
|---|
| 54 | 
 | 
|---|
| 55 | static void
 | 
|---|
| 56 | usage (int ret)
 | 
|---|
| 57 | {
 | 
|---|
| 58 |     arg_printusage (args, sizeof(args)/sizeof(*args),
 | 
|---|
| 59 |                     NULL, "");
 | 
|---|
| 60 |     exit (ret);
 | 
|---|
| 61 | }
 | 
|---|
| 62 | 
 | 
|---|
| 63 | static krb5_context context;
 | 
|---|
| 64 | 
 | 
|---|
| 65 | int
 | 
|---|
| 66 | digest_probe(struct digest_probe_options *opt,
 | 
|---|
| 67 |              int argc, char ** argv)
 | 
|---|
| 68 | {
 | 
|---|
| 69 |     krb5_error_code ret;
 | 
|---|
| 70 |     krb5_realm realm;
 | 
|---|
| 71 |     unsigned flags;
 | 
|---|
| 72 | 
 | 
|---|
| 73 |     realm = opt->realm_string;
 | 
|---|
| 74 | 
 | 
|---|
| 75 |     if (realm == NULL)
 | 
|---|
| 76 |         errx(1, "realm missing");
 | 
|---|
| 77 | 
 | 
|---|
| 78 |     ret = krb5_digest_probe(context, realm, id, &flags);
 | 
|---|
| 79 |     if (ret)
 | 
|---|
| 80 |         krb5_err(context, 1, ret, "digest_probe");
 | 
|---|
| 81 | 
 | 
|---|
| 82 |     printf("flags: %u\n", flags);
 | 
|---|
| 83 | 
 | 
|---|
| 84 |     return 0;
 | 
|---|
| 85 | }
 | 
|---|
| 86 | 
 | 
|---|
| 87 | int
 | 
|---|
| 88 | digest_server_init(struct digest_server_init_options *opt,
 | 
|---|
| 89 |                    int argc, char ** argv)
 | 
|---|
| 90 | {
 | 
|---|
| 91 |     krb5_error_code ret;
 | 
|---|
| 92 |     krb5_digest digest;
 | 
|---|
| 93 | 
 | 
|---|
| 94 |     ret = krb5_digest_alloc(context, &digest);
 | 
|---|
| 95 |     if (ret)
 | 
|---|
| 96 |         krb5_err(context, 1, ret, "digest_alloc");
 | 
|---|
| 97 | 
 | 
|---|
| 98 |     ret = krb5_digest_set_type(context, digest, opt->type_string);
 | 
|---|
| 99 |     if (ret)
 | 
|---|
| 100 |         krb5_err(context, 1, ret, "krb5_digest_set_type");
 | 
|---|
| 101 | 
 | 
|---|
| 102 |     if (opt->cb_type_string && opt->cb_value_string) {
 | 
|---|
| 103 |         ret = krb5_digest_set_server_cb(context, digest,
 | 
|---|
| 104 |                                         opt->cb_type_string,
 | 
|---|
| 105 |                                         opt->cb_value_string);
 | 
|---|
| 106 |         if (ret)
 | 
|---|
| 107 |             krb5_err(context, 1, ret, "krb5_digest_set_server_cb");
 | 
|---|
| 108 |     }
 | 
|---|
| 109 |     ret = krb5_digest_init_request(context,
 | 
|---|
| 110 |                                    digest,
 | 
|---|
| 111 |                                    opt->kerberos_realm_string,
 | 
|---|
| 112 |                                    id);
 | 
|---|
| 113 |     if (ret)
 | 
|---|
| 114 |         krb5_err(context, 1, ret, "krb5_digest_init_request");
 | 
|---|
| 115 | 
 | 
|---|
| 116 |     printf("type=%s\n", opt->type_string);
 | 
|---|
| 117 |     printf("server-nonce=%s\n",
 | 
|---|
| 118 |            krb5_digest_get_server_nonce(context, digest));
 | 
|---|
| 119 |     {
 | 
|---|
| 120 |         const char *s = krb5_digest_get_identifier(context, digest);
 | 
|---|
| 121 |         if (s)
 | 
|---|
| 122 |             printf("identifier=%s\n", s);
 | 
|---|
| 123 |     }
 | 
|---|
| 124 |     printf("opaque=%s\n", krb5_digest_get_opaque(context, digest));
 | 
|---|
| 125 | 
 | 
|---|
| 126 |     krb5_digest_free(digest);
 | 
|---|
| 127 | 
 | 
|---|
| 128 |     return 0;
 | 
|---|
| 129 | }
 | 
|---|
| 130 | 
 | 
|---|
| 131 | int
 | 
|---|
| 132 | digest_server_request(struct digest_server_request_options *opt,
 | 
|---|
| 133 |                       int argc, char **argv)
 | 
|---|
| 134 | {
 | 
|---|
| 135 |     krb5_error_code ret;
 | 
|---|
| 136 |     krb5_digest digest;
 | 
|---|
| 137 |     const char *status, *rsp;
 | 
|---|
| 138 |     krb5_data session_key;
 | 
|---|
| 139 | 
 | 
|---|
| 140 |     if (opt->server_nonce_string == NULL)
 | 
|---|
| 141 |         errx(1, "server nonce missing");
 | 
|---|
| 142 |     if (opt->type_string == NULL)
 | 
|---|
| 143 |         errx(1, "type missing");
 | 
|---|
| 144 |     if (opt->opaque_string == NULL)
 | 
|---|
| 145 |         errx(1, "opaque missing");
 | 
|---|
| 146 |     if (opt->client_response_string == NULL)
 | 
|---|
| 147 |         errx(1, "client response missing");
 | 
|---|
| 148 | 
 | 
|---|
| 149 |     ret = krb5_digest_alloc(context, &digest);
 | 
|---|
| 150 |     if (ret)
 | 
|---|
| 151 |         krb5_err(context, 1, ret, "digest_alloc");
 | 
|---|
| 152 | 
 | 
|---|
| 153 |     if (strcasecmp(opt->type_string, "CHAP") == 0) {
 | 
|---|
| 154 |         if (opt->server_identifier_string == NULL)
 | 
|---|
| 155 |             errx(1, "server identifier missing");
 | 
|---|
| 156 | 
 | 
|---|
| 157 |         ret = krb5_digest_set_identifier(context, digest,
 | 
|---|
| 158 |                                          opt->server_identifier_string);
 | 
|---|
| 159 |         if (ret)
 | 
|---|
| 160 |             krb5_err(context, 1, ret, "krb5_digest_set_type");
 | 
|---|
| 161 |     }
 | 
|---|
| 162 | 
 | 
|---|
| 163 |     ret = krb5_digest_set_type(context, digest, opt->type_string);
 | 
|---|
| 164 |     if (ret)
 | 
|---|
| 165 |         krb5_err(context, 1, ret, "krb5_digest_set_type");
 | 
|---|
| 166 | 
 | 
|---|
| 167 |     ret = krb5_digest_set_username(context, digest, opt->username_string);
 | 
|---|
| 168 |     if (ret)
 | 
|---|
| 169 |         krb5_err(context, 1, ret, "krb5_digest_set_username");
 | 
|---|
| 170 | 
 | 
|---|
| 171 |     ret = krb5_digest_set_server_nonce(context, digest,
 | 
|---|
| 172 |                                        opt->server_nonce_string);
 | 
|---|
| 173 |     if (ret)
 | 
|---|
| 174 |         krb5_err(context, 1, ret, "krb5_digest_set_server_nonce");
 | 
|---|
| 175 | 
 | 
|---|
| 176 |     if(opt->client_nonce_string) {
 | 
|---|
| 177 |         ret = krb5_digest_set_client_nonce(context, digest,
 | 
|---|
| 178 |                                            opt->client_nonce_string);
 | 
|---|
| 179 |         if (ret)
 | 
|---|
| 180 |             krb5_err(context, 1, ret, "krb5_digest_set_client_nonce");
 | 
|---|
| 181 |     }
 | 
|---|
| 182 | 
 | 
|---|
| 183 | 
 | 
|---|
| 184 |     ret = krb5_digest_set_opaque(context, digest, opt->opaque_string);
 | 
|---|
| 185 |     if (ret)
 | 
|---|
| 186 |         krb5_err(context, 1, ret, "krb5_digest_set_opaque");
 | 
|---|
| 187 | 
 | 
|---|
| 188 |     ret = krb5_digest_set_responseData(context, digest,
 | 
|---|
| 189 |                                        opt->client_response_string);
 | 
|---|
| 190 |     if (ret)
 | 
|---|
| 191 |         krb5_err(context, 1, ret, "krb5_digest_set_responseData");
 | 
|---|
| 192 | 
 | 
|---|
| 193 |     ret = krb5_digest_request(context, digest,
 | 
|---|
| 194 |                               opt->kerberos_realm_string, id);
 | 
|---|
| 195 |     if (ret)
 | 
|---|
| 196 |         krb5_err(context, 1, ret, "krb5_digest_request");
 | 
|---|
| 197 | 
 | 
|---|
| 198 |     status = krb5_digest_rep_get_status(context, digest) ? "ok" : "failed";
 | 
|---|
| 199 |     rsp = krb5_digest_get_rsp(context, digest);
 | 
|---|
| 200 | 
 | 
|---|
| 201 |     printf("status=%s\n", status);
 | 
|---|
| 202 |     if (rsp)
 | 
|---|
| 203 |         printf("rsp=%s\n", rsp);
 | 
|---|
| 204 |     printf("tickets=no\n");
 | 
|---|
| 205 | 
 | 
|---|
| 206 |     ret = krb5_digest_get_session_key(context, digest, &session_key);
 | 
|---|
| 207 |     if (ret)
 | 
|---|
| 208 |         krb5_err(context, 1, ret, "krb5_digest_get_session_key");
 | 
|---|
| 209 | 
 | 
|---|
| 210 |     if (session_key.length) {
 | 
|---|
| 211 |         char *key;
 | 
|---|
| 212 |         hex_encode(session_key.data, session_key.length, &key);
 | 
|---|
| 213 |         if (key == NULL)
 | 
|---|
| 214 |             krb5_errx(context, 1, "hex_encode");
 | 
|---|
| 215 |         krb5_data_free(&session_key);
 | 
|---|
| 216 |         printf("session-key=%s\n", key);
 | 
|---|
| 217 |         free(key);
 | 
|---|
| 218 |     }
 | 
|---|
| 219 | 
 | 
|---|
| 220 |     krb5_digest_free(digest);
 | 
|---|
| 221 | 
 | 
|---|
| 222 |     return 0;
 | 
|---|
| 223 | }
 | 
|---|
| 224 | 
 | 
|---|
| 225 | static void
 | 
|---|
| 226 | client_chap(const void *server_nonce, size_t snoncelen,
 | 
|---|
| 227 |             unsigned char server_identifier,
 | 
|---|
| 228 |             const char *password)
 | 
|---|
| 229 | {
 | 
|---|
| 230 |     EVP_MD_CTX *ctx;
 | 
|---|
| 231 |     unsigned char md[MD5_DIGEST_LENGTH];
 | 
|---|
| 232 |     char *h;
 | 
|---|
| 233 | 
 | 
|---|
| 234 |     ctx = EVP_MD_CTX_create();
 | 
|---|
| 235 |     EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
 | 
|---|
| 236 | 
 | 
|---|
| 237 |     EVP_DigestUpdate(ctx, &server_identifier, 1);
 | 
|---|
| 238 |     EVP_DigestUpdate(ctx, password, strlen(password));
 | 
|---|
| 239 |     EVP_DigestUpdate(ctx, server_nonce, snoncelen);
 | 
|---|
| 240 |     EVP_DigestFinal_ex(ctx, md, NULL);
 | 
|---|
| 241 | 
 | 
|---|
| 242 |     EVP_MD_CTX_destroy(ctx);
 | 
|---|
| 243 | 
 | 
|---|
| 244 |     hex_encode(md, 16, &h);
 | 
|---|
| 245 | 
 | 
|---|
| 246 |     printf("responseData=%s\n", h);
 | 
|---|
| 247 |     free(h);
 | 
|---|
| 248 | }
 | 
|---|
| 249 | 
 | 
|---|
| 250 | static const unsigned char ms_chap_v2_magic1[39] = {
 | 
|---|
| 251 |     0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
 | 
|---|
| 252 |     0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
 | 
|---|
| 253 |     0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
 | 
|---|
| 254 |     0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
 | 
|---|
| 255 | };
 | 
|---|
| 256 | static const unsigned char ms_chap_v2_magic2[41] = {
 | 
|---|
| 257 |     0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
 | 
|---|
| 258 |     0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
 | 
|---|
| 259 |     0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
 | 
|---|
| 260 |     0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
 | 
|---|
| 261 |     0x6E
 | 
|---|
| 262 | };
 | 
|---|
| 263 | static const unsigned char ms_rfc3079_magic1[27] = {
 | 
|---|
| 264 |     0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
 | 
|---|
| 265 |     0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
 | 
|---|
| 266 |     0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
 | 
|---|
| 267 | };
 | 
|---|
| 268 | 
 | 
|---|
| 269 | static void
 | 
|---|
| 270 | client_mschapv2(const void *server_nonce, size_t snoncelen,
 | 
|---|
| 271 |                 const void *client_nonce, size_t cnoncelen,
 | 
|---|
| 272 |                 const char *username,
 | 
|---|
| 273 |                 const char *password)
 | 
|---|
| 274 | {
 | 
|---|
| 275 |     EVP_MD_CTX *hctx, *ctx;
 | 
|---|
| 276 |     unsigned char md[SHA_DIGEST_LENGTH], challenge[SHA_DIGEST_LENGTH];
 | 
|---|
| 277 |     unsigned char hmd[MD4_DIGEST_LENGTH];
 | 
|---|
| 278 |     struct ntlm_buf answer;
 | 
|---|
| 279 |     int i, len, ret;
 | 
|---|
| 280 |     char *h;
 | 
|---|
| 281 | 
 | 
|---|
| 282 |     ctx = EVP_MD_CTX_create();
 | 
|---|
| 283 |     EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
 | 
|---|
| 284 | 
 | 
|---|
| 285 |     EVP_DigestUpdate(ctx, client_nonce, cnoncelen);
 | 
|---|
| 286 |     EVP_DigestUpdate(ctx, server_nonce, snoncelen);
 | 
|---|
| 287 |     EVP_DigestUpdate(ctx, username, strlen(username));
 | 
|---|
| 288 |     EVP_DigestFinal_ex(ctx, md, NULL);
 | 
|---|
| 289 | 
 | 
|---|
| 290 | 
 | 
|---|
| 291 |     hctx = EVP_MD_CTX_create();
 | 
|---|
| 292 |     EVP_DigestInit_ex(hctx, EVP_md4(), NULL);
 | 
|---|
| 293 |     len = strlen(password);
 | 
|---|
| 294 |     for (i = 0; i < len; i++) {
 | 
|---|
| 295 |         EVP_DigestUpdate(hctx, &password[i], 1);
 | 
|---|
| 296 |         EVP_DigestUpdate(hctx, &password[len], 1);
 | 
|---|
| 297 |     }
 | 
|---|
| 298 |     EVP_DigestFinal_ex(hctx, hmd, NULL);
 | 
|---|
| 299 | 
 | 
|---|
| 300 | 
 | 
|---|
| 301 |     /* ChallengeResponse */
 | 
|---|
| 302 |     ret = heim_ntlm_calculate_ntlm1(hmd, sizeof(hmd), md, &answer);
 | 
|---|
| 303 |     if (ret)
 | 
|---|
| 304 |         errx(1, "heim_ntlm_calculate_ntlm1");
 | 
|---|
| 305 | 
 | 
|---|
| 306 |     hex_encode(answer.data, answer.length, &h);
 | 
|---|
| 307 |     printf("responseData=%s\n", h);
 | 
|---|
| 308 |     free(h);
 | 
|---|
| 309 | 
 | 
|---|
| 310 |     /* PasswordHash */
 | 
|---|
| 311 |     EVP_DigestInit_ex(hctx, EVP_md4(), NULL);
 | 
|---|
| 312 |     EVP_DigestUpdate(hctx, hmd, sizeof(hmd));
 | 
|---|
| 313 |     EVP_DigestFinal_ex(hctx, hmd, NULL);
 | 
|---|
| 314 | 
 | 
|---|
| 315 | 
 | 
|---|
| 316 |     /* GenerateAuthenticatorResponse */
 | 
|---|
| 317 |     EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
 | 
|---|
| 318 |     EVP_DigestUpdate(ctx, hmd, sizeof(hmd));
 | 
|---|
| 319 |     EVP_DigestUpdate(ctx, answer.data, answer.length);
 | 
|---|
| 320 |     EVP_DigestUpdate(ctx, ms_chap_v2_magic1, sizeof(ms_chap_v2_magic1));
 | 
|---|
| 321 |     EVP_DigestFinal_ex(ctx, md, NULL);
 | 
|---|
| 322 | 
 | 
|---|
| 323 |     /* ChallengeHash */
 | 
|---|
| 324 |     EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
 | 
|---|
| 325 |     EVP_DigestUpdate(ctx, client_nonce, cnoncelen);
 | 
|---|
| 326 |     EVP_DigestUpdate(ctx, server_nonce, snoncelen);
 | 
|---|
| 327 |     EVP_DigestUpdate(ctx, username, strlen(username));
 | 
|---|
| 328 |     EVP_DigestFinal_ex(ctx, challenge, NULL);
 | 
|---|
| 329 | 
 | 
|---|
| 330 |     EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
 | 
|---|
| 331 |     EVP_DigestUpdate(ctx, md, sizeof(md));
 | 
|---|
| 332 |     EVP_DigestUpdate(ctx, challenge, 8);
 | 
|---|
| 333 |     EVP_DigestUpdate(ctx, ms_chap_v2_magic2, sizeof(ms_chap_v2_magic2));
 | 
|---|
| 334 |     EVP_DigestFinal_ex(ctx, md, NULL);
 | 
|---|
| 335 | 
 | 
|---|
| 336 |     hex_encode(md, sizeof(md), &h);
 | 
|---|
| 337 |     printf("AuthenticatorResponse=%s\n", h);
 | 
|---|
| 338 |     free(h);
 | 
|---|
| 339 | 
 | 
|---|
| 340 |     /* get_master, rfc 3079 3.4 */
 | 
|---|
| 341 |     EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
 | 
|---|
| 342 |     EVP_DigestUpdate(ctx, hmd, sizeof(hmd));
 | 
|---|
| 343 |     EVP_DigestUpdate(ctx, answer.data, answer.length);
 | 
|---|
| 344 |     EVP_DigestUpdate(ctx, ms_rfc3079_magic1, sizeof(ms_rfc3079_magic1));
 | 
|---|
| 345 |     EVP_DigestFinal_ex(ctx, md, NULL);
 | 
|---|
| 346 | 
 | 
|---|
| 347 |     free(answer.data);
 | 
|---|
| 348 | 
 | 
|---|
| 349 |     hex_encode(md, 16, &h);
 | 
|---|
| 350 |     printf("session-key=%s\n", h);
 | 
|---|
| 351 |     free(h);
 | 
|---|
| 352 | 
 | 
|---|
| 353 |     EVP_MD_CTX_destroy(hctx);
 | 
|---|
| 354 |     EVP_MD_CTX_destroy(ctx);
 | 
|---|
| 355 | }
 | 
|---|
| 356 | 
 | 
|---|
| 357 | 
 | 
|---|
| 358 | int
 | 
|---|
| 359 | digest_client_request(struct digest_client_request_options *opt,
 | 
|---|
| 360 |                       int argc, char **argv)
 | 
|---|
| 361 | {
 | 
|---|
| 362 |     char *server_nonce, *client_nonce = NULL, server_identifier;
 | 
|---|
| 363 |     ssize_t snoncelen, cnoncelen = 0;
 | 
|---|
| 364 | 
 | 
|---|
| 365 |     if (opt->server_nonce_string == NULL)
 | 
|---|
| 366 |         errx(1, "server nonce missing");
 | 
|---|
| 367 |     if (opt->password_string == NULL)
 | 
|---|
| 368 |         errx(1, "password missing");
 | 
|---|
| 369 | 
 | 
|---|
| 370 |     if (opt->opaque_string == NULL)
 | 
|---|
| 371 |         errx(1, "opaque missing");
 | 
|---|
| 372 | 
 | 
|---|
| 373 |     snoncelen = strlen(opt->server_nonce_string);
 | 
|---|
| 374 |     server_nonce = malloc(snoncelen);
 | 
|---|
| 375 |     if (server_nonce == NULL)
 | 
|---|
| 376 |         errx(1, "server_nonce");
 | 
|---|
| 377 | 
 | 
|---|
| 378 |     snoncelen = hex_decode(opt->server_nonce_string, server_nonce, snoncelen);
 | 
|---|
| 379 |     if (snoncelen <= 0)
 | 
|---|
| 380 |         errx(1, "server nonce wrong");
 | 
|---|
| 381 | 
 | 
|---|
| 382 |     if (opt->client_nonce_string) {
 | 
|---|
| 383 |         cnoncelen = strlen(opt->client_nonce_string);
 | 
|---|
| 384 |         client_nonce = malloc(cnoncelen);
 | 
|---|
| 385 |         if (client_nonce == NULL)
 | 
|---|
| 386 |             errx(1, "client_nonce");
 | 
|---|
| 387 | 
 | 
|---|
| 388 |         cnoncelen = hex_decode(opt->client_nonce_string,
 | 
|---|
| 389 |                                client_nonce, cnoncelen);
 | 
|---|
| 390 |         if (cnoncelen <= 0)
 | 
|---|
| 391 |             errx(1, "client nonce wrong");
 | 
|---|
| 392 |     }
 | 
|---|
| 393 | 
 | 
|---|
| 394 |     if (opt->server_identifier_string) {
 | 
|---|
| 395 |         int ret;
 | 
|---|
| 396 | 
 | 
|---|
| 397 |         ret = hex_decode(opt->server_identifier_string, &server_identifier, 1);
 | 
|---|
| 398 |         if (ret != 1)
 | 
|---|
| 399 |             errx(1, "server identifier wrong length");
 | 
|---|
| 400 |     }
 | 
|---|
| 401 | 
 | 
|---|
| 402 |     if (strcasecmp(opt->type_string, "CHAP") == 0) {
 | 
|---|
| 403 |         if (opt->server_identifier_string == NULL)
 | 
|---|
| 404 |             errx(1, "server identifier missing");
 | 
|---|
| 405 | 
 | 
|---|
| 406 |         client_chap(server_nonce, snoncelen, server_identifier,
 | 
|---|
| 407 |                     opt->password_string);
 | 
|---|
| 408 | 
 | 
|---|
| 409 |     } else if (strcasecmp(opt->type_string, "MS-CHAP-V2") == 0) {
 | 
|---|
| 410 |         if (opt->client_nonce_string == NULL)
 | 
|---|
| 411 |             errx(1, "client nonce missing");
 | 
|---|
| 412 |         if (opt->username_string == NULL)
 | 
|---|
| 413 |             errx(1, "client nonce missing");
 | 
|---|
| 414 | 
 | 
|---|
| 415 |         client_mschapv2(server_nonce, snoncelen,
 | 
|---|
| 416 |                         client_nonce, cnoncelen,
 | 
|---|
| 417 |                         opt->username_string,
 | 
|---|
| 418 |                         opt->password_string);
 | 
|---|
| 419 |     }
 | 
|---|
| 420 |     if (client_nonce)
 | 
|---|
| 421 |         free(client_nonce);
 | 
|---|
| 422 |     free(server_nonce);
 | 
|---|
| 423 | 
 | 
|---|
| 424 |     return 0;
 | 
|---|
| 425 | }
 | 
|---|
| 426 | 
 | 
|---|
| 427 | #include <heimntlm.h>
 | 
|---|
| 428 | 
 | 
|---|
| 429 | int
 | 
|---|
| 430 | ntlm_server_init(struct ntlm_server_init_options *opt,
 | 
|---|
| 431 |                  int argc, char ** argv)
 | 
|---|
| 432 | {
 | 
|---|
| 433 |     krb5_error_code ret;
 | 
|---|
| 434 |     krb5_ntlm ntlm;
 | 
|---|
| 435 |     struct ntlm_type2 type2;
 | 
|---|
| 436 |     krb5_data challenge, opaque;
 | 
|---|
| 437 |     struct ntlm_buf data;
 | 
|---|
| 438 |     char *s;
 | 
|---|
| 439 |     static char zero2[] = "\x00\x00";
 | 
|---|
| 440 | 
 | 
|---|
| 441 |     memset(&type2, 0, sizeof(type2));
 | 
|---|
| 442 | 
 | 
|---|
| 443 |     ret = krb5_ntlm_alloc(context, &ntlm);
 | 
|---|
| 444 |     if (ret)
 | 
|---|
| 445 |         krb5_err(context, 1, ret, "krb5_ntlm_alloc");
 | 
|---|
| 446 | 
 | 
|---|
| 447 |     ret = krb5_ntlm_init_request(context,
 | 
|---|
| 448 |                                  ntlm,
 | 
|---|
| 449 |                                  opt->kerberos_realm_string,
 | 
|---|
| 450 |                                  id,
 | 
|---|
| 451 |                                  NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
 | 
|---|
| 452 |                                  "NUTCRACKER",
 | 
|---|
| 453 |                                  "L");
 | 
|---|
| 454 |     if (ret)
 | 
|---|
| 455 |         krb5_err(context, 1, ret, "krb5_ntlm_init_request");
 | 
|---|
| 456 | 
 | 
|---|
| 457 |     /*
 | 
|---|
| 458 |      *
 | 
|---|
| 459 |      */
 | 
|---|
| 460 | 
 | 
|---|
| 461 |     ret = krb5_ntlm_init_get_challange(context, ntlm, &challenge);
 | 
|---|
| 462 |     if (ret)
 | 
|---|
| 463 |         krb5_err(context, 1, ret, "krb5_ntlm_init_get_challange");
 | 
|---|
| 464 | 
 | 
|---|
| 465 |     if (challenge.length != sizeof(type2.challenge))
 | 
|---|
| 466 |         krb5_errx(context, 1, "ntlm challenge have wrong length");
 | 
|---|
| 467 |     memcpy(type2.challenge, challenge.data, sizeof(type2.challenge));
 | 
|---|
| 468 |     krb5_data_free(&challenge);
 | 
|---|
| 469 | 
 | 
|---|
| 470 |     ret = krb5_ntlm_init_get_flags(context, ntlm, &type2.flags);
 | 
|---|
| 471 |     if (ret)
 | 
|---|
| 472 |         krb5_err(context, 1, ret, "krb5_ntlm_init_get_flags");
 | 
|---|
| 473 | 
 | 
|---|
| 474 |     krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
 | 
|---|
| 475 |     type2.targetinfo.data = zero2;
 | 
|---|
| 476 |     type2.targetinfo.length = 2;
 | 
|---|
| 477 | 
 | 
|---|
| 478 |     ret = heim_ntlm_encode_type2(&type2, &data);
 | 
|---|
| 479 |     if (ret)
 | 
|---|
| 480 |         krb5_errx(context, 1, "heim_ntlm_encode_type2");
 | 
|---|
| 481 | 
 | 
|---|
| 482 |     free(type2.targetname);
 | 
|---|
| 483 | 
 | 
|---|
| 484 |     /*
 | 
|---|
| 485 |      *
 | 
|---|
| 486 |      */
 | 
|---|
| 487 | 
 | 
|---|
| 488 |     base64_encode(data.data, data.length, &s);
 | 
|---|
| 489 |     free(data.data);
 | 
|---|
| 490 |     printf("type2=%s\n", s);
 | 
|---|
| 491 |     free(s);
 | 
|---|
| 492 | 
 | 
|---|
| 493 |     /*
 | 
|---|
| 494 |      *
 | 
|---|
| 495 |      */
 | 
|---|
| 496 | 
 | 
|---|
| 497 |     ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
 | 
|---|
| 498 |     if (ret)
 | 
|---|
| 499 |         krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
 | 
|---|
| 500 | 
 | 
|---|
| 501 |     base64_encode(opaque.data, opaque.length, &s);
 | 
|---|
| 502 |     krb5_data_free(&opaque);
 | 
|---|
| 503 |     printf("opaque=%s\n", s);
 | 
|---|
| 504 |     free(s);
 | 
|---|
| 505 | 
 | 
|---|
| 506 |     /*
 | 
|---|
| 507 |      *
 | 
|---|
| 508 |      */
 | 
|---|
| 509 | 
 | 
|---|
| 510 |     krb5_ntlm_free(context, ntlm);
 | 
|---|
| 511 | 
 | 
|---|
| 512 |     return 0;
 | 
|---|
| 513 | }
 | 
|---|
| 514 | 
 | 
|---|
| 515 | 
 | 
|---|
| 516 | /*
 | 
|---|
| 517 |  *
 | 
|---|
| 518 |  */
 | 
|---|
| 519 | 
 | 
|---|
| 520 | int
 | 
|---|
| 521 | help(void *opt, int argc, char **argv)
 | 
|---|
| 522 | {
 | 
|---|
| 523 |     sl_slc_help(commands, argc, argv);
 | 
|---|
| 524 |     return 0;
 | 
|---|
| 525 | }
 | 
|---|
| 526 | 
 | 
|---|
| 527 | int
 | 
|---|
| 528 | main(int argc, char **argv)
 | 
|---|
| 529 | {
 | 
|---|
| 530 |     krb5_error_code ret;
 | 
|---|
| 531 |     int optidx = 0;
 | 
|---|
| 532 | 
 | 
|---|
| 533 |     setprogname(argv[0]);
 | 
|---|
| 534 | 
 | 
|---|
| 535 |     ret = krb5_init_context (&context);
 | 
|---|
| 536 |     if (ret == KRB5_CONFIG_BADFORMAT)
 | 
|---|
| 537 |         errx (1, "krb5_init_context failed to parse configuration file");
 | 
|---|
| 538 |     else if (ret)
 | 
|---|
| 539 |         errx(1, "krb5_init_context failed: %d", ret);
 | 
|---|
| 540 | 
 | 
|---|
| 541 |     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
 | 
|---|
| 542 |         usage(1);
 | 
|---|
| 543 | 
 | 
|---|
| 544 |     if (help_flag)
 | 
|---|
| 545 |         usage (0);
 | 
|---|
| 546 | 
 | 
|---|
| 547 |     if(version_flag){
 | 
|---|
| 548 |         print_version(NULL);
 | 
|---|
| 549 |         exit(0);
 | 
|---|
| 550 |     }
 | 
|---|
| 551 | 
 | 
|---|
| 552 |     argc -= optidx;
 | 
|---|
| 553 |     argv += optidx;
 | 
|---|
| 554 | 
 | 
|---|
| 555 |     if (argc == 0) {
 | 
|---|
| 556 |         help(NULL, argc, argv);
 | 
|---|
| 557 |         return 1;
 | 
|---|
| 558 |     }
 | 
|---|
| 559 | 
 | 
|---|
| 560 |     if (ccache_string) {
 | 
|---|
| 561 |         ret = krb5_cc_resolve(context, ccache_string, &id);
 | 
|---|
| 562 |         if (ret)
 | 
|---|
| 563 |             krb5_err(context, 1, ret, "krb5_cc_resolve");
 | 
|---|
| 564 |     }
 | 
|---|
| 565 | 
 | 
|---|
| 566 |     ret = sl_command (commands, argc, argv);
 | 
|---|
| 567 |     if (ret == -1) {
 | 
|---|
| 568 |         help(NULL, argc, argv);
 | 
|---|
| 569 |         return 1;
 | 
|---|
| 570 |     }
 | 
|---|
| 571 |     return ret;
 | 
|---|
| 572 | }
 | 
|---|