00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <net-snmp/net-snmp-config.h>
00010
00011 #include <sys/types.h>
00012 #if HAVE_WINSOCK_H
00013 #include <winsock.h>
00014 #endif
00015 #include <stdio.h>
00016 #ifdef HAVE_STDLIB_H
00017 #include <stdlib.h>
00018 #endif
00019 #if TIME_WITH_SYS_TIME
00020 # ifdef WIN32
00021 # include <sys/timeb.h>
00022 # else
00023 # include <sys/time.h>
00024 # endif
00025 # include <time.h>
00026 #else
00027 # if HAVE_SYS_TIME_H
00028 # include <sys/time.h>
00029 # else
00030 # include <time.h>
00031 # endif
00032 #endif
00033 #if HAVE_STRING_H
00034 #include <string.h>
00035 #else
00036 #include <strings.h>
00037 #endif
00038 #ifdef HAVE_NETINET_IN_H
00039 #include <netinet/in.h>
00040 #endif
00041 #include <errno.h>
00042
00043
00044 #if HAVE_DMALLOC_H
00045 #include <dmalloc.h>
00046 #endif
00047
00048 #ifdef HEIMDAL
00049 #ifndef MIT_NEW_CRYPTO
00050 #define OLD_HEIMDAL
00051 #endif
00052 #endif
00053
00054 #ifdef HEIMDAL
00055 #define oid heimdal_oid_renamed
00056 #endif
00057 #include <krb5.h>
00058 #include <com_err.h>
00059 #ifdef HEIMDAL
00060 #undef oid
00061 #endif
00062
00063 #ifdef HEIMDAL
00064 #define CHECKSUM_TYPE(x) (x)->cksumtype
00065 #define CHECKSUM_CONTENTS(x) ((char *)((x)->checksum.data))
00066 #define CHECKSUM_LENGTH(x) (x)->checksum.length
00067 #define TICKET_CLIENT(x) (x)->client
00068 #else
00069 #define CHECKSUM_TYPE(x) (x)->checksum_type
00070 #define CHECKSUM_CONTENTS(x) (x)->contents
00071 #define CHECKSUM_LENGTH(x) (x)->length
00072 #define TICKET_CLIENT(x) (x)->enc_part2->client
00073 #endif
00074
00075 #include <net-snmp/output_api.h>
00076 #include <net-snmp/config_api.h>
00077 #include <net-snmp/utilities.h>
00078
00079 #include <net-snmp/library/asn1.h>
00080 #include <net-snmp/library/snmp_api.h>
00081 #include <net-snmp/library/callback.h>
00082 #include <net-snmp/library/keytools.h>
00083 #include <net-snmp/library/snmpv3.h>
00084 #include <net-snmp/library/lcd_time.h>
00085 #include <net-snmp/library/scapi.h>
00086 #include <net-snmp/library/callback.h>
00087 #include <net-snmp/library/snmp_secmod.h>
00088 #include <net-snmp/library/snmpksm.h>
00089
00090 static krb5_context kcontext = NULL;
00091 static krb5_rcache rcache = NULL;
00092 static krb5_keytab keytab = NULL;
00093 static int keytab_setup = 0;
00094 static const char *service_name = NULL;
00095
00096 static int ksm_session_init(netsnmp_session *);
00097 static void ksm_free_state_ref(void *);
00098 static int ksm_free_pdu(netsnmp_pdu *);
00099 static int ksm_clone_pdu(netsnmp_pdu *, netsnmp_pdu *);
00100
00101 static int ksm_insert_cache(long, krb5_auth_context, u_char *,
00102 size_t);
00103 static void ksm_decrement_ref_count(long);
00104 static void ksm_increment_ref_count(long);
00105 static struct ksm_cache_entry *ksm_get_cache(long);
00106
00107 #define HASHSIZE 64
00108
00109
00110
00111
00112
00113 struct ksm_secStateRef {
00114 krb5_auth_context auth_context;
00115 krb5_cksumtype cksumtype;
00116 };
00117
00118
00119
00120
00121
00122 struct ksm_cache_entry {
00123 long msgid;
00124 int refcount;
00125 krb5_auth_context auth_context;
00126 u_char *secName;
00127 size_t secNameLen;
00128 struct ksm_cache_entry *next;
00129 };
00130
00131
00132
00133
00134
00135 static struct ksm_cache_entry *ksm_hash_table[HASHSIZE];
00136
00137
00138
00139
00140
00141
00142
00143
00144 static int
00145 init_snmpksm_post_config(int majorid, int minorid, void *serverarg,
00146 void *clientarg)
00147 {
00148
00149 if (kcontext == NULL) {
00150
00151 return SNMPERR_KRB5;
00152 }
00153
00154 if (service_name == NULL) {
00155
00156 char *c = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
00157 NETSNMP_DS_LIB_KSM_SERVICE_NAME);
00158 if (c != NULL) {
00159 service_name = c;
00160 }
00161 else {
00162 service_name = "host";
00163 }
00164 }
00165
00166 if (keytab_setup == 0) {
00167
00168 char *c = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
00169 NETSNMP_DS_LIB_KSM_KEYTAB);
00170 if (c) {
00171 krb5_error_code retval;
00172 DEBUGMSGTL(("ksm", "Using keytab %s\n", c));
00173 retval = krb5_kt_resolve(kcontext, c, &keytab);
00174 if (retval) {
00175 DEBUGMSGTL(("ksm", "krb5_kt_resolve(\"%s\") failed. KSM "
00176 "config callback failing\n", error_message(retval)));
00177 return SNMPERR_KRB5;
00178 }
00179 }
00180 else {
00181 DEBUGMSGTL(("ksm", "Using default keytab\n", c));
00182 }
00183 keytab_setup = 1;
00184 }
00185
00186 return SNMPERR_SUCCESS;
00187 }
00188
00189
00190
00191
00192
00193
00194 void
00195 init_ksm(void)
00196 {
00197 krb5_error_code retval;
00198 struct snmp_secmod_def *def;
00199 int i;
00200
00201 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defKSMKeytab",
00202 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_KSM_KEYTAB);
00203 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defKSMServiceName",
00204 NETSNMP_DS_LIBRARY_ID,
00205 NETSNMP_DS_LIB_KSM_SERVICE_NAME);
00206 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
00207 SNMP_CALLBACK_POST_READ_CONFIG,
00208 init_snmpksm_post_config, NULL);
00209
00210
00211 if (kcontext == NULL) {
00212 retval = krb5_init_context(&kcontext);
00213
00214 if (retval) {
00215 DEBUGMSGTL(("ksm", "krb5_init_context failed (%s), not "
00216 "registering KSM\n", error_message(retval)));
00217 return;
00218 }
00219 }
00220
00221 for (i = 0; i < HASHSIZE; i++)
00222 ksm_hash_table[i] = NULL;
00223
00224 def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
00225
00226 if (!def) {
00227 DEBUGMSGTL(("ksm", "Unable to malloc snmp_secmod struct, not "
00228 "registering KSM\n"));
00229 return;
00230 }
00231
00232 def->encode_reverse = ksm_rgenerate_out_msg;
00233 def->decode = ksm_process_in_msg;
00234 def->session_open = ksm_session_init;
00235 def->pdu_free_state_ref = ksm_free_state_ref;
00236 def->pdu_free = ksm_free_pdu;
00237 def->pdu_clone = ksm_clone_pdu;
00238
00239 register_sec_mod(NETSNMP_KSM_SECURITY_MODEL, "ksm", def);
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 static int
00253 ksm_insert_cache(long msgid, krb5_auth_context auth_context,
00254 u_char * secName, size_t secNameLen)
00255 {
00256 struct ksm_cache_entry *entry;
00257 int bucket;
00258 int retval;
00259
00260 entry = SNMP_MALLOC_STRUCT(ksm_cache_entry);
00261
00262 if (!entry)
00263 return SNMPERR_MALLOC;
00264
00265 entry->msgid = msgid;
00266 entry->auth_context = auth_context;
00267 entry->refcount = 1;
00268
00269 retval = memdup(&entry->secName, secName, secNameLen);
00270
00271 if (retval != SNMPERR_SUCCESS) {
00272 free(entry);
00273 return retval;
00274 }
00275
00276 entry->secNameLen = secNameLen;
00277
00278 bucket = msgid % HASHSIZE;
00279
00280 entry->next = ksm_hash_table[bucket];
00281 ksm_hash_table[bucket] = entry;
00282
00283 return SNMPERR_SUCCESS;
00284 }
00285
00286 static struct ksm_cache_entry *
00287 ksm_get_cache(long msgid)
00288 {
00289 struct ksm_cache_entry *entry;
00290 int bucket;
00291
00292 bucket = msgid % HASHSIZE;
00293
00294 for (entry = ksm_hash_table[bucket]; entry != NULL;
00295 entry = entry->next)
00296 if (entry->msgid == msgid)
00297 return entry;
00298
00299 return NULL;
00300 }
00301
00302 static void
00303 ksm_decrement_ref_count(long msgid)
00304 {
00305 struct ksm_cache_entry *entry, *entry1;
00306 int bucket;
00307
00308 bucket = msgid % HASHSIZE;
00309
00310 if (ksm_hash_table[bucket] && ksm_hash_table[bucket]->msgid == msgid) {
00311 entry = ksm_hash_table[bucket];
00312
00313
00314
00315
00316
00317 if (--entry->refcount <= 0) {
00318 DEBUGMSGTL(("ksm", "Freeing entry for msgid %ld\n", msgid));
00319 krb5_auth_con_free(kcontext, entry->auth_context);
00320 free(entry->secName);
00321 ksm_hash_table[bucket] = entry->next;
00322 free(entry);
00323 }
00324
00325 return;
00326
00327 } else if (ksm_hash_table[bucket])
00328 for (entry1 = ksm_hash_table[bucket], entry = entry1->next;
00329 entry != NULL; entry1 = entry, entry = entry->next)
00330 if (entry->msgid == msgid) {
00331
00332 if (--entry->refcount <= 0) {
00333 DEBUGMSGTL(("ksm", "Freeing entry for msgid %ld\n",
00334 msgid));
00335 krb5_auth_con_free(kcontext, entry->auth_context);
00336 free(entry->secName);
00337 entry1->next = entry->next;
00338 free(entry);
00339 }
00340
00341 return;
00342 }
00343
00344 DEBUGMSGTL(("ksm",
00345 "KSM: Unable to decrement cache entry for msgid %ld.\n",
00346 msgid));
00347 }
00348
00349 static void
00350 ksm_increment_ref_count(long msgid)
00351 {
00352 struct ksm_cache_entry *entry = ksm_get_cache(msgid);
00353
00354 if (!entry) {
00355 DEBUGMSGTL(("ksm", "Unable to find cache entry for msgid %ld "
00356 "for increment\n", msgid));
00357 return;
00358 }
00359
00360 entry->refcount++;
00361 }
00362
00363
00364
00365
00366
00367
00368 static int
00369 ksm_session_init(netsnmp_session * sess)
00370 {
00371 DEBUGMSGTL(("ksm",
00372 "KSM: Reached our session initialization callback\n"));
00373
00374 sess->flags |= SNMP_FLAGS_DONT_PROBE;
00375
00376 return SNMPERR_SUCCESS;
00377 }
00378
00379
00380
00381
00382
00383 static void
00384 ksm_free_state_ref(void *ptr)
00385 {
00386 struct ksm_secStateRef *ref = (struct ksm_secStateRef *) ptr;
00387
00388 DEBUGMSGTL(("ksm", "KSM: Freeing state reference\n"));
00389
00390 krb5_auth_con_free(kcontext, ref->auth_context);
00391
00392 free(ref);
00393 }
00394
00395
00396
00397
00398
00399
00400 static int
00401 ksm_free_pdu(netsnmp_pdu *pdu)
00402 {
00403 ksm_decrement_ref_count(pdu->msgid);
00404
00405 DEBUGMSGTL(("ksm", "Decrementing cache entry for PDU msgid %ld\n",
00406 pdu->msgid));
00407
00408 return SNMPERR_SUCCESS;
00409 }
00410
00411
00412
00413
00414
00415 static int
00416 ksm_clone_pdu(netsnmp_pdu *pdu, netsnmp_pdu *pdu2)
00417 {
00418 ksm_increment_ref_count(pdu->msgid);
00419
00420 DEBUGMSGTL(("ksm", "Incrementing cache entry for PDU msgid %ld\n",
00421 pdu->msgid));
00422
00423 return SNMPERR_SUCCESS;
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 int
00444 ksm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
00445 {
00446 krb5_auth_context auth_context = NULL;
00447 krb5_error_code retcode;
00448 krb5_ccache cc = NULL;
00449 int retval = SNMPERR_SUCCESS;
00450 krb5_data outdata, ivector;
00451 krb5_keyblock *subkey = NULL;
00452 #ifdef MIT_NEW_CRYPTO
00453 krb5_data input;
00454 krb5_enc_data output;
00455 unsigned int numcksumtypes;
00456 krb5_cksumtype *cksumtype_array;
00457 #elif defined OLD_HEIMDAL
00458 krb5_crypto heim_crypto = NULL;
00459 #else
00460 krb5_encrypt_block eblock;
00461 #endif
00462 size_t blocksize, encrypted_length;
00463 unsigned char *encrypted_data = NULL;
00464 int zero = 0, i;
00465 u_char *cksum_pointer, *endp = *parms->wholeMsg;
00466 krb5_cksumtype cksumtype;
00467 krb5_checksum pdu_checksum;
00468 u_char **wholeMsg = parms->wholeMsg;
00469 size_t *offset = parms->wholeMsgOffset, seq_offset;
00470 struct ksm_secStateRef *ksm_state = (struct ksm_secStateRef *)
00471 parms->secStateRef;
00472 #ifdef OLD_HEIMDAL
00473 krb5_data encrypted_scoped_pdu;
00474 #endif
00475 int rc;
00476 char *colon = NULL;
00477
00478 DEBUGMSGTL(("ksm", "Starting KSM processing\n"));
00479
00480 outdata.length = 0;
00481 outdata.data = NULL;
00482 ivector.length = 0;
00483 ivector.data = NULL;
00484 CHECKSUM_CONTENTS(&pdu_checksum) = NULL;
00485
00486 if (!ksm_state) {
00487
00488
00489
00490
00491
00492 colon = strrchr(params->session->peername, ':');
00493 if (colon != NULL) {
00494 *colon='\0';
00495 }
00496
00497
00498
00499
00500
00501 retcode = krb5_cc_default(kcontext, &cc);
00502
00503 if (retcode) {
00504 DEBUGMSGTL(("ksm", "KSM: krb5_cc_default failed: %s\n",
00505 error_message(retcode)));
00506 snmp_set_detail(error_message(retcode));
00507 retval = SNMPERR_KRB5;
00508 goto error;
00509 }
00510
00511 DEBUGMSGTL(("ksm", "KSM: Set credential cache successfully\n"));
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522 retcode =
00523 krb5_mk_req(kcontext, &auth_context,
00524 AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
00525 (char *) service_name, parms->session->peername, NULL,
00526 cc, &outdata);
00527
00528 if (colon != NULL)
00529 *colon=':';
00530
00531 if (retcode) {
00532 DEBUGMSGTL(("ksm", "KSM: krb5_mk_req failed: %s\n",
00533 error_message(retcode)));
00534 snmp_set_detail(error_message(retcode));
00535 retval = SNMPERR_KRB5;
00536 goto error;
00537 }
00538
00539 DEBUGMSGTL(("ksm", "KSM: ticket retrieved successfully for \"%s/%s\" "
00540 "(may not be actual ticket sname)\n", service_name,
00541 parms->session->peername));
00542
00543 } else {
00544
00545
00546
00547
00548
00549 auth_context = ksm_state->auth_context;
00550
00551
00552
00553
00554
00555
00556
00557 DEBUGMSGTL(("ksm", "KSM: Starting reply processing.\n"));
00558
00559 retcode = krb5_mk_rep(kcontext, auth_context, &outdata);
00560
00561 if (retcode) {
00562 DEBUGMSGTL(("ksm", "KSM: krb5_mk_rep failed: %s\n",
00563 error_message(retcode)));
00564 snmp_set_detail(error_message(retcode));
00565 retval = SNMPERR_KRB5;
00566 goto error;
00567 }
00568
00569 DEBUGMSGTL(("ksm", "KSM: Finished with krb5_mk_rep()\n"));
00570 }
00571
00572
00573
00574
00575
00576 if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
00577
00578 DEBUGMSGTL(("ksm", "KSM: Starting PDU encryption.\n"));
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 if (ksm_state)
00591 retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context,
00592 &subkey);
00593 else
00594 retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context,
00595 &subkey);
00596
00597 if (retcode) {
00598 DEBUGMSGTL(("ksm",
00599 "KSM: krb5_auth_con_getlocalsubkey failed: %s\n",
00600 error_message(retcode)));
00601 snmp_set_detail(error_message(retcode));
00602 retval = SNMPERR_KRB5;
00603 goto error;
00604 }
00605
00606
00607
00608
00609
00610
00611
00612 #ifdef MIT_NEW_CRYPTO
00613 retcode = krb5_c_encrypt_length(kcontext, subkey->enctype,
00614 parms->scopedPduLen,
00615 &encrypted_length);
00616
00617 if (retcode) {
00618 DEBUGMSGTL(("ksm",
00619 "Encryption length calculation failed: %s\n",
00620 error_message(retcode)));
00621 snmp_set_detail(error_message(retcode));
00622 retval = SNMPERR_KRB5;
00623 goto error;
00624 }
00625 #elif defined OLD_HEIMDAL
00626 retcode = krb5_crypto_init(kcontext, subkey, 0, &heim_crypto);
00627 if (retcode) {
00628 DEBUGMSGTL(("ksm", "krb5_crypto_init failed: %s\n",
00629 error_message(retcode)));
00630 snmp_set_detail(error_message(retcode));
00631 retval = SNMPERR_KRB5;
00632 goto error;
00633 }
00634 encrypted_length = krb5_get_wrapped_length(kcontext, heim_crypto,
00635 parms->scopedPduLen);
00636 #else
00637
00638 krb5_use_enctype(kcontext, &eblock, subkey->enctype);
00639 retcode = krb5_process_key(kcontext, &eblock, subkey);
00640
00641 if (retcode) {
00642 DEBUGMSGTL(("ksm", "krb5_process_key failed: %s\n",
00643 error_message(retcode)));
00644 snmp_set_detail(error_message(retcode));
00645 retval = SNMPERR_KRB5;
00646 goto error;
00647 }
00648
00649 encrypted_length = krb5_encrypt_size(parms->scopedPduLen,
00650 eblock.crypto_entry);
00651 #endif
00652
00653 #ifndef OLD_HEIMDAL
00654 encrypted_data = malloc(encrypted_length);
00655
00656 if (!encrypted_data) {
00657 DEBUGMSGTL(("ksm",
00658 "KSM: Unable to malloc %d bytes for encrypt "
00659 "buffer: %s\n", parms->scopedPduLen,
00660 strerror(errno)));
00661 retval = SNMPERR_MALLOC;
00662 #ifndef MIT_NEW_CRYPTO
00663 krb5_finish_key(kcontext, &eblock);
00664 #endif
00665
00666 goto error;
00667 }
00668 #endif
00669
00670
00671
00672
00673
00674
00675
00676 #ifdef MIT_NEW_CRYPTO
00677
00678 retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);
00679
00680 if (retcode) {
00681 DEBUGMSGTL(("ksm",
00682 "Unable to determine crypto block size: %s\n",
00683 error_message(retcode)));
00684 snmp_set_detail(error_message(retcode));
00685 retval = SNMPERR_KRB5;
00686 goto error;
00687 }
00688 #elif defined (OLD_HEIMDAL)
00689 #else
00690
00691 blocksize =
00692 krb5_enctype_array[subkey->enctype]->system->block_length;
00693
00694 #endif
00695
00696 #ifndef OLD_HEIMDAL
00697 ivector.data = malloc(blocksize);
00698
00699 if (!ivector.data) {
00700 DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n",
00701 blocksize));
00702 retval = SNMPERR_MALLOC;
00703 goto error;
00704 }
00705
00706 ivector.length = blocksize;
00707 memset(ivector.data, 0, blocksize);
00708 #endif
00709
00710
00711
00712
00713
00714 #ifdef MIT_NEW_CRYPTO
00715
00716 input.data = (char *) parms->scopedPdu;
00717 input.length = parms->scopedPduLen;
00718 output.ciphertext.data = (char *) encrypted_data;
00719 output.ciphertext.length = encrypted_length;
00720
00721 retcode =
00722 krb5_c_encrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
00723 &ivector, &input, &output);
00724
00725 #elif defined OLD_HEIMDAL
00726
00727 krb5_data_zero(&encrypted_scoped_pdu);
00728 retcode = krb5_encrypt(kcontext, heim_crypto, KSM_KEY_USAGE_ENCRYPTION,
00729 parms->scopedPdu, parms->scopedPduLen,
00730 &encrypted_scoped_pdu);
00731 if (retcode == 0) {
00732 encrypted_length = encrypted_scoped_pdu.length;
00733 encrypted_data = encrypted_scoped_pdu.data;
00734 krb5_data_zero(&encrypted_scoped_pdu);
00735 }
00736 #else
00737
00738 retcode = krb5_encrypt(kcontext, (krb5_pointer) parms->scopedPdu,
00739 (krb5_pointer) encrypted_data,
00740 parms->scopedPduLen, &eblock, ivector.data);
00741
00742 krb5_finish_key(kcontext, &eblock);
00743
00744 #endif
00745
00746 if (retcode) {
00747 DEBUGMSGTL(("ksm", "KSM: krb5_encrypt failed: %s\n",
00748 error_message(retcode)));
00749 retval = SNMPERR_KRB5;
00750 snmp_set_detail(error_message(retcode));
00751 goto error;
00752 }
00753
00754 *offset = 0;
00755
00756 rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen,
00757 offset, 1,
00758 (u_char) (ASN_UNIVERSAL |
00759 ASN_PRIMITIVE |
00760 ASN_OCTET_STR),
00761 encrypted_data,
00762 encrypted_length);
00763
00764 if (rc == 0) {
00765 DEBUGMSGTL(("ksm", "Building encrypted payload failed.\n"));
00766 retval = SNMPERR_TOO_LONG;
00767 goto error;
00768 }
00769
00770 DEBUGMSGTL(("ksm", "KSM: Encryption complete.\n"));
00771
00772 } else {
00773
00774
00775
00776
00777 if (*parms->wholeMsgLen < parms->scopedPduLen) {
00778 DEBUGMSGTL(("ksm", "Not enough room for plaintext PDU.\n"));
00779 retval = SNMPERR_TOO_LONG;
00780 goto error;
00781 }
00782 }
00783
00784
00785
00786
00787
00788
00789
00790 DEBUGMSGTL(("ksm", "KSM: scopedPdu added to payload\n"));
00791
00792 seq_offset = *offset;
00793
00794 rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen,
00795 offset, 1,
00796 (u_char) (ASN_UNIVERSAL |
00797 ASN_PRIMITIVE |
00798 ASN_INTEGER),
00799 (long *) &zero, sizeof(zero));
00800
00801 if (rc == 0) {
00802 DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
00803 retval = SNMPERR_TOO_LONG;
00804 goto error;
00805 }
00806
00807 rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen,
00808 offset, 1,
00809 (u_char) (ASN_UNIVERSAL |
00810 ASN_PRIMITIVE |
00811 ASN_OCTET_STR),
00812 (u_char *) outdata.data,
00813 outdata.length);
00814
00815 if (rc == 0) {
00816 DEBUGMSGTL(("ksm", "Building ksm AP_REQ failed.\n"));
00817 retval = SNMPERR_TOO_LONG;
00818 goto error;
00819 }
00820
00821
00822
00823
00824
00825
00826 if (!subkey) {
00827 if (ksm_state)
00828 retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context,
00829 &subkey);
00830 else
00831 retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context,
00832 &subkey);
00833 if (retcode) {
00834 DEBUGMSGTL(("ksm", "krb5_auth_con_getlocalsubkey failed: %s\n",
00835 error_message(retcode)));
00836 snmp_set_detail(error_message(retcode));
00837 retval = SNMPERR_KRB5;
00838 goto error;
00839 }
00840 #ifdef OLD_HEIMDAL
00841 retcode = krb5_crypto_init(kcontext, subkey, 0, &heim_crypto);
00842 if (retcode) {
00843 DEBUGMSGTL(("ksm", "krb5_crypto_init failed: %s\n",
00844 error_message(retcode)));
00845 snmp_set_detail(error_message(retcode));
00846 retval = SNMPERR_KRB5;
00847 goto error;
00848 }
00849 #endif
00850 }
00851
00852
00853
00854
00855
00856
00857
00858 #ifdef MIT_NEW_CRYPTO
00859 retcode = krb5_c_keyed_checksum_types(kcontext, subkey->enctype,
00860 &numcksumtypes, &cksumtype_array);
00861
00862 if (retcode) {
00863 DEBUGMSGTL(("ksm", "Unable to find appropriate keyed checksum: %s\n",
00864 error_message(retcode)));
00865 snmp_set_detail(error_message(retcode));
00866 retval = SNMPERR_KRB5;
00867 goto error;
00868 }
00869
00870 if (numcksumtypes <= 0) {
00871 DEBUGMSGTL(("ksm", "We received a list of zero cksumtypes for this "
00872 "enctype (%d)\n", subkey->enctype));
00873 snmp_set_detail("No valid checksum type for this encryption type");
00874 retval = SNMPERR_KRB5;
00875 goto error;
00876 }
00877
00878
00879
00880
00881
00882
00883 cksumtype = cksumtype_array[0];
00884
00885 krb5_free_cksumtypes(kcontext, cksumtype_array);
00886
00887 DEBUGMSGTL(("ksm", "KSM: Choosing checksum type of %d (subkey type "
00888 "of %d)\n", cksumtype, subkey->enctype));
00889
00890 retcode = krb5_c_checksum_length(kcontext, cksumtype, &blocksize);
00891
00892 if (retcode) {
00893 DEBUGMSGTL(("ksm", "Unable to determine checksum length: %s\n",
00894 error_message(retcode)));
00895 snmp_set_detail(error_message(retcode));
00896 retval = SNMPERR_KRB5;
00897 goto error;
00898 }
00899
00900 CHECKSUM_LENGTH(&pdu_checksum) = blocksize;
00901
00902 #else
00903 if (ksm_state)
00904 cksumtype = ksm_state->cksumtype;
00905 else
00906 #ifdef OLD_HEIMDAL
00907 {
00908
00909 retval = krb5_create_checksum(kcontext, heim_crypto,
00910 KSM_KEY_USAGE_CHECKSUM, 0,
00911 parms->scopedPdu, parms->scopedPduLen,
00912 &pdu_checksum);
00913 if (retval) {
00914 DEBUGMSGTL(("ksm", "Unable to create a checksum: %s\n",
00915 error_message(retval)));
00916 snmp_set_detail(error_message(retcode));
00917 retval = SNMPERR_KRB5;
00918 goto error;
00919 }
00920 cksumtype = CHECKSUM_TYPE(&pdu_checksum);
00921 }
00922 #else
00923 cksumtype = CKSUMTYPE_RSA_MD5_DES;
00924 #endif
00925
00926 #ifdef OLD_HEIMDAL
00927 if (!krb5_checksum_is_keyed(kcontext, cksumtype)) {
00928 #else
00929 if (!is_keyed_cksum(cksumtype)) {
00930 #endif
00931 DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
00932 cksumtype));
00933 snmp_set_detail("Checksum is not a keyed checksum");
00934 retval = SNMPERR_KRB5;
00935 goto error;
00936 }
00937
00938 #ifdef OLD_HEIMDAL
00939 if (!krb5_checksum_is_collision_proof(kcontext, cksumtype)) {
00940 #else
00941 if (!is_coll_proof_cksum(cksumtype)) {
00942 #endif
00943 DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
00944 "checksum\n", cksumtype));
00945 snmp_set_detail("Checksum is not a collision-proof checksum");
00946 retval = SNMPERR_KRB5;
00947 goto error;
00948 }
00949
00950 #ifdef OLD_HEIMDAL
00951 if (CHECKSUM_CONTENTS(&pdu_checksum) != NULL ) {
00952
00953
00954 free(CHECKSUM_CONTENTS(&pdu_checksum));
00955 CHECKSUM_CONTENTS(&pdu_checksum) = NULL;
00956 }
00957 else {
00958 retval = krb5_checksumsize(kcontext, cksumtype,
00959 &CHECKSUM_LENGTH(&pdu_checksum));
00960 if (retval) {
00961 DEBUGMSGTL(("ksm", "Unable to determine checksum length: %s\n",
00962 error_message(retval)));
00963 snmp_set_detail(error_message(retcode));
00964 retval = SNMPERR_KRB5;
00965 goto error;
00966 }
00967 #else
00968 CHECKSUM_LENGTH(&pdu_checksum) = krb5_checksum_size(kcontext, cksumtype);
00969 #endif
00970 CHECKSUM_TYPE(&pdu_checksum) = cksumtype;
00971 #ifdef OLD_HEIMDAL
00972 }
00973 #endif
00974
00975 #endif
00976
00977
00978
00979
00980
00981
00982 *offset += CHECKSUM_LENGTH(&pdu_checksum);
00983 memset(*wholeMsg + *parms->wholeMsgLen - *offset, 0, CHECKSUM_LENGTH(&pdu_checksum));
00984
00985 cksum_pointer = *wholeMsg + *parms->wholeMsgLen - *offset;
00986
00987 rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen,
00988 parms->wholeMsgOffset, 1,
00989 (u_char) (ASN_UNIVERSAL |
00990 ASN_PRIMITIVE |
00991 ASN_OCTET_STR),
00992 CHECKSUM_LENGTH(&pdu_checksum));
00993
00994 if (rc == 0) {
00995 DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
00996 retval = SNMPERR_TOO_LONG;
00997 goto error;
00998 }
00999
01000 rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen,
01001 parms->wholeMsgOffset, 1,
01002 (u_char) (ASN_UNIVERSAL |
01003 ASN_PRIMITIVE |
01004 ASN_OCTET_STR),
01005 (long *) &cksumtype,
01006 sizeof(cksumtype));
01007
01008 if (rc == 0) {
01009 DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
01010 retval = SNMPERR_TOO_LONG;
01011 goto error;
01012 }
01013
01014 rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen,
01015 parms->wholeMsgOffset, 1,
01016 (u_char) (ASN_SEQUENCE |
01017 ASN_CONSTRUCTOR),
01018 *offset - seq_offset);
01019
01020 if (rc == 0) {
01021 DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
01022 retval = SNMPERR_TOO_LONG;
01023 goto error;
01024 }
01025
01026 rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen,
01027 parms->wholeMsgOffset, 1,
01028 (u_char) (ASN_UNIVERSAL |
01029 ASN_PRIMITIVE |
01030 ASN_OCTET_STR),
01031 *offset - seq_offset);
01032
01033 if (rc == 0) {
01034 DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n"));
01035 retval = SNMPERR_TOO_LONG;
01036 goto error;
01037 }
01038
01039 DEBUGMSGTL(("ksm", "KSM: Security parameter encoding completed\n"));
01040
01041
01042
01043
01044
01045
01046 if (*parms->wholeMsgLen < parms->globalDataLen) {
01047 DEBUGMSGTL(("ksm", "Building global data failed.\n"));
01048 retval = SNMPERR_TOO_LONG;
01049 goto error;
01050 }
01051
01052 *offset += parms->globalDataLen;
01053 memcpy(*wholeMsg + *parms->wholeMsgLen - *offset,
01054 parms->globalData, parms->globalDataLen);
01055
01056 rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen,
01057 offset, 1,
01058 (u_char) (ASN_SEQUENCE |
01059 ASN_CONSTRUCTOR),
01060 *offset);
01061
01062 if (rc == 0) {
01063 DEBUGMSGTL(("ksm", "Building master packet sequence.\n"));
01064 retval = SNMPERR_TOO_LONG;
01065 goto error;
01066 }
01067
01068 DEBUGMSGTL(("ksm", "KSM: PDU master packet encoding complete.\n"));
01069
01070
01071
01072
01073
01074 #ifndef OLD_HEIMDAL
01075 CHECKSUM_CONTENTS(&pdu_checksum) = malloc(CHECKSUM_LENGTH(&pdu_checksum));
01076
01077 if (!CHECKSUM_CONTENTS(&pdu_checksum)) {
01078 DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum\n",
01079 CHECKSUM_LENGTH(&pdu_checksum)));
01080 retval = SNMPERR_MALLOC;
01081 goto error;
01082 }
01083 #endif
01084 #ifdef MIT_NEW_CRYPTO
01085
01086 input.data = (char *) (*wholeMsg + *parms->wholeMsgLen - *offset);
01087 input.length = *offset;
01088 retcode = krb5_c_make_checksum(kcontext, cksumtype, subkey,
01089 KSM_KEY_USAGE_CHECKSUM, &input,
01090 &pdu_checksum);
01091
01092 #elif defined(OLD_HEIMDAL)
01093
01094 retcode = krb5_create_checksum(kcontext, heim_crypto,
01095 KSM_KEY_USAGE_CHECKSUM, cksumtype,
01096 *wholeMsg + *parms->wholeMsgLen
01097 - *offset, *offset, &pdu_checksum);
01098 #else
01099
01100 retcode = krb5_calculate_checksum(kcontext, cksumtype, *wholeMsg +
01101 *parms->wholeMsgLen - *offset,
01102 *offset,
01103 (krb5_pointer) subkey->contents,
01104 subkey->length, &pdu_checksum);
01105
01106 #endif
01107
01108 if (retcode) {
01109 DEBUGMSGTL(("ksm", "Calculate checksum failed: %s\n",
01110 error_message(retcode)));
01111 retval = SNMPERR_KRB5;
01112 snmp_set_detail(error_message(retcode));
01113 goto error;
01114 }
01115
01116 DEBUGMSGTL(("ksm", "KSM: Checksum calculation complete.\n"));
01117
01118 memcpy(cksum_pointer, CHECKSUM_CONTENTS(&pdu_checksum), CHECKSUM_LENGTH(&pdu_checksum));
01119
01120 DEBUGMSGTL(("ksm", "KSM: Writing checksum of %d bytes at offset %d\n",
01121 CHECKSUM_LENGTH(&pdu_checksum), cksum_pointer - (*wholeMsg + 1)));
01122
01123 DEBUGMSGTL(("ksm", "KSM: Checksum:"));
01124
01125 for (i = 0; i < CHECKSUM_LENGTH(&pdu_checksum); i++)
01126 DEBUGMSG(("ksm", " %02x",
01127 (unsigned int) CHECKSUM_CONTENTS(&pdu_checksum)[i]));
01128
01129 DEBUGMSG(("ksm", "\n"));
01130
01131
01132
01133
01134
01135
01136 if (!ksm_state) {
01137 if ((retval = ksm_insert_cache(parms->pdu->msgid, auth_context,
01138 (u_char *) parms->secName,
01139 parms->secNameLen)) !=
01140 SNMPERR_SUCCESS)
01141 goto error;
01142 auth_context = NULL;
01143 }
01144
01145 DEBUGMSGTL(("ksm", "KSM processing complete!\n"));
01146
01147 error:
01148
01149 if (CHECKSUM_CONTENTS(&pdu_checksum))
01150 #ifdef MIT_NEW_CRYPTO
01151 krb5_free_checksum_contents(kcontext, &pdu_checksum);
01152 #else
01153 free(CHECKSUM_CONTENTS(&pdu_checksum));
01154 #endif
01155
01156 if (ivector.data)
01157 free(ivector.data);
01158
01159 if (subkey)
01160 krb5_free_keyblock(kcontext, subkey);
01161
01162 #ifdef OLD_HEIMDAL
01163 if (heim_crypto)
01164 krb5_crypto_destroy(kcontext, heim_crypto);
01165 #endif
01166
01167 if (encrypted_data)
01168 free(encrypted_data);
01169
01170 if (cc)
01171 krb5_cc_close(kcontext, cc);
01172
01173 if (auth_context && !ksm_state)
01174 krb5_auth_con_free(kcontext, auth_context);
01175
01176 return retval;
01177 }
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197 int
01198 ksm_process_in_msg(struct snmp_secmod_incoming_params *parms)
01199 {
01200 long temp;
01201 krb5_cksumtype cksumtype;
01202 krb5_auth_context auth_context = NULL;
01203 krb5_error_code retcode;
01204 krb5_checksum checksum;
01205 krb5_data ap_req, ivector;
01206 krb5_flags flags;
01207 krb5_keyblock *subkey = NULL;
01208 #ifdef MIT_NEW_CRYPTO
01209 krb5_data input, output;
01210 krb5_boolean valid;
01211 krb5_enc_data in_crypt;
01212 #elif defined OLD_HEIMDAL
01213 krb5_data output;
01214 krb5_crypto heim_crypto = NULL;
01215 #else
01216 krb5_encrypt_block eblock;
01217 #endif
01218 krb5_ticket *ticket = NULL;
01219 int retval = SNMPERR_SUCCESS, response = 0;
01220 size_t length =
01221 parms->wholeMsgLen - (u_int) (parms->secParams - parms->wholeMsg);
01222 u_char *current = parms->secParams, type;
01223 size_t cksumlength, blocksize;
01224 long hint;
01225 char *cname;
01226 struct ksm_secStateRef *ksm_state;
01227 struct ksm_cache_entry *entry;
01228
01229 DEBUGMSGTL(("ksm", "Processing has begun\n"));
01230
01231 CHECKSUM_CONTENTS(&checksum) = NULL;
01232 ap_req.data = NULL;
01233 ivector.length = 0;
01234 ivector.data = NULL;
01235
01236
01237
01238
01239
01240
01241 if ((current = asn_parse_sequence(current, &length, &type,
01242 (ASN_UNIVERSAL | ASN_PRIMITIVE |
01243 ASN_OCTET_STR),
01244 "ksm first octet")) == NULL) {
01245 DEBUGMSGTL(("ksm", "Initial security paramter parsing failed\n"));
01246
01247 retval = SNMPERR_ASN_PARSE_ERR;
01248 goto error;
01249 }
01250
01251 if ((current = asn_parse_sequence(current, &length, &type,
01252 (ASN_SEQUENCE | ASN_CONSTRUCTOR),
01253 "ksm sequence")) == NULL) {
01254 DEBUGMSGTL(("ksm",
01255 "Security parameter sequence parsing failed\n"));
01256
01257 retval = SNMPERR_ASN_PARSE_ERR;
01258 goto error;
01259 }
01260
01261 if ((current = asn_parse_int(current, &length, &type, &temp,
01262 sizeof(temp))) == NULL) {
01263 DEBUGMSGTL(("ksm", "Security parameter checksum type parsing"
01264 "failed\n"));
01265
01266 retval = SNMPERR_ASN_PARSE_ERR;
01267 goto error;
01268 }
01269
01270 cksumtype = temp;
01271
01272 #ifdef MIT_NEW_CRYPTO
01273 if (!krb5_c_valid_cksumtype(cksumtype)) {
01274 DEBUGMSGTL(("ksm", "Invalid checksum type (%d)\n", cksumtype));
01275
01276 retval = SNMPERR_KRB5;
01277 snmp_set_detail("Invalid checksum type");
01278 goto error;
01279 }
01280
01281 if (!krb5_c_is_keyed_cksum(cksumtype)) {
01282 DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
01283 cksumtype));
01284 snmp_set_detail("Checksum is not a keyed checksum");
01285 retval = SNMPERR_KRB5;
01286 goto error;
01287 }
01288
01289 if (!krb5_c_is_coll_proof_cksum(cksumtype)) {
01290 DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
01291 "checksum\n", cksumtype));
01292 snmp_set_detail("Checksum is not a collision-proof checksum");
01293 retval = SNMPERR_KRB5;
01294 goto error;
01295 }
01296 #else
01297 #ifdef OLD_HEIMDAL
01298
01299 if (krb5_checksumsize(kcontext, cksumtype, &cksumlength)) {
01300 #else
01301 if (!valid_cksumtype(cksumtype)) {
01302 #endif
01303 DEBUGMSGTL(("ksm", "Invalid checksum type (%d)\n", cksumtype));
01304
01305 retval = SNMPERR_KRB5;
01306 snmp_set_detail("Invalid checksum type");
01307 goto error;
01308 }
01309
01310 #ifdef OLD_HEIMDAL
01311 if (!krb5_checksum_is_keyed(kcontext, cksumtype)) {
01312 #else
01313 if (!is_keyed_cksum(cksumtype)) {
01314 #endif
01315 DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
01316 cksumtype));
01317 snmp_set_detail("Checksum is not a keyed checksum");
01318 retval = SNMPERR_KRB5;
01319 goto error;
01320 }
01321
01322 #ifdef OLD_HEIMDAL
01323 if (!krb5_checksum_is_collision_proof(kcontext, cksumtype)) {
01324 #else
01325 if (!is_coll_proof_cksum(cksumtype)) {
01326 #endif
01327 DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
01328 "checksum\n", cksumtype));
01329 snmp_set_detail("Checksum is not a collision-proof checksum");
01330 retval = SNMPERR_KRB5;
01331 goto error;
01332 }
01333 #endif
01334
01335 CHECKSUM_TYPE(&checksum) = cksumtype;
01336
01337 cksumlength = length;
01338
01339 if ((current = asn_parse_sequence(current, &cksumlength, &type,
01340 (ASN_UNIVERSAL | ASN_PRIMITIVE |
01341 ASN_OCTET_STR), "ksm checksum")) ==
01342 NULL) {
01343 DEBUGMSGTL(("ksm",
01344 "Security parameter checksum parsing failed\n"));
01345
01346 retval = SNMPERR_ASN_PARSE_ERR;
01347 goto error;
01348 }
01349
01350 CHECKSUM_CONTENTS(&checksum) = malloc(cksumlength);
01351 if (!CHECKSUM_CONTENTS(&checksum)) {
01352 DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum.\n",
01353 cksumlength));
01354 retval = SNMPERR_MALLOC;
01355 goto error;
01356 }
01357
01358 memcpy(CHECKSUM_CONTENTS(&checksum), current, cksumlength);
01359
01360 CHECKSUM_LENGTH(&checksum) = cksumlength;
01361 CHECKSUM_TYPE(&checksum) = cksumtype;
01362
01363
01364
01365
01366
01367 memset(current, 0, cksumlength);
01368
01369 current += cksumlength;
01370 length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);
01371
01372 if ((current = asn_parse_sequence(current, &length, &type,
01373 (ASN_UNIVERSAL | ASN_PRIMITIVE |
01374 ASN_OCTET_STR), "ksm ap_req")) ==
01375 NULL) {
01376 DEBUGMSGTL(("ksm", "KSM security parameter AP_REQ/REP parsing "
01377 "failed\n"));
01378
01379 retval = SNMPERR_ASN_PARSE_ERR;
01380 goto error;
01381 }
01382
01383 ap_req.length = length;
01384 ap_req.data = malloc(length);
01385 if (!ap_req.data) {
01386 DEBUGMSGTL(("ksm",
01387 "KSM unable to malloc %d bytes for AP_REQ/REP.\n",
01388 length));
01389 retval = SNMPERR_MALLOC;
01390 goto error;
01391 }
01392
01393 memcpy(ap_req.data, current, length);
01394
01395 current += length;
01396 length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);
01397
01398 if ((current = asn_parse_int(current, &length, &type, &hint,
01399 sizeof(hint))) == NULL) {
01400 DEBUGMSGTL(("ksm",
01401 "KSM security parameter hint parsing failed\n"));
01402
01403 retval = SNMPERR_ASN_PARSE_ERR;
01404 goto error;
01405 }
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422 if (ap_req.length
01423 #ifndef HEIMDAL
01424 && (ap_req.data[0] == 0x6e || ap_req.data[0] == 0x4e)) {
01425 #else
01426 && (((char *)ap_req.data)[0] == 0x6e || ((char *)ap_req.data)[0] == 0x4e)) {
01427 #endif
01428
01429
01430
01431
01432
01433
01434
01435 retcode = krb5_auth_con_init(kcontext, &auth_context);
01436
01437 if (retcode) {
01438 DEBUGMSGTL(("ksm", "krb5_auth_con_init failed: %s\n",
01439 error_message(retcode)));
01440 retval = SNMPERR_KRB5;
01441 snmp_set_detail(error_message(retcode));
01442 goto error;
01443 }
01444
01445 if (!rcache) {
01446 krb5_data server;
01447 server.data = "host";
01448 server.length = strlen(server.data);
01449
01450 retcode = krb5_get_server_rcache(kcontext, &server, &rcache);
01451
01452 if (retcode) {
01453 DEBUGMSGTL(("ksm", "krb5_get_server_rcache failed: %s\n",
01454 error_message(retcode)));
01455 retval = SNMPERR_KRB5;
01456 snmp_set_detail(error_message(retcode));
01457 goto error;
01458 }
01459 }
01460
01461 retcode = krb5_auth_con_setrcache(kcontext, auth_context, rcache);
01462
01463 if (retcode) {
01464 DEBUGMSGTL(("ksm", "krb5_auth_con_setrcache failed: %s\n",
01465 error_message(retcode)));
01466 retval = SNMPERR_KRB5;
01467 snmp_set_detail(error_message(retcode));
01468 goto error;
01469 }
01470
01471 retcode = krb5_rd_req(kcontext, &auth_context, &ap_req, NULL,
01472 keytab, &flags, &ticket);
01473
01474 krb5_auth_con_setrcache(kcontext, auth_context, NULL);
01475
01476 if (retcode) {
01477 DEBUGMSGTL(("ksm", "krb5_rd_req() failed: %s\n",
01478 error_message(retcode)));
01479 retval = SNMPERR_KRB5;
01480 snmp_set_detail(error_message(retcode));
01481 goto error;
01482 }
01483
01484 retcode =
01485 krb5_unparse_name(kcontext, TICKET_CLIENT(ticket), &cname);
01486
01487 if (retcode == 0) {
01488 DEBUGMSGTL(("ksm", "KSM authenticated principal name: %s\n",
01489 cname));
01490 free(cname);
01491 }
01492
01493
01494
01495
01496
01497 if (!(flags & AP_OPTS_MUTUAL_REQUIRED)) {
01498 DEBUGMSGTL(("ksm",
01499 "KSM MUTUAL_REQUIRED not set in request!\n"));
01500 retval = SNMPERR_KRB5;
01501 snmp_set_detail("MUTUAL_REQUIRED not set in message");
01502 goto error;
01503 }
01504
01505 retcode =
01506 krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey);
01507
01508 if (retcode) {
01509 DEBUGMSGTL(("ksm", "KSM remote subkey retrieval failed: %s\n",
01510 error_message(retcode)));
01511 retval = SNMPERR_KRB5;
01512 snmp_set_detail(error_message(retcode));
01513 goto error;
01514 }
01515
01516 #ifndef HEIMDAL
01517 } else if (ap_req.length && (ap_req.data[0] == 0x6f ||
01518 ap_req.data[0] == 0x4f)) {
01519 #else
01520 } else if (ap_req.length && (((char *)ap_req.data)[0] == 0x6f ||
01521 ((char *)ap_req.data)[0] == 0x4f)) {
01522 #endif
01523
01524
01525
01526
01527
01528 krb5_ap_rep_enc_part *repl = NULL;
01529
01530 response = 1;
01531
01532 entry = ksm_get_cache(parms->pdu->msgid);
01533
01534 if (!entry) {
01535 DEBUGMSGTL(("ksm",
01536 "KSM: Unable to find auth_context for PDU with "
01537 "message ID of %ld\n", parms->pdu->msgid));
01538 retval = SNMPERR_KRB5;
01539 goto error;
01540 }
01541
01542 auth_context = entry->auth_context;
01543
01544
01545
01546
01547
01548 retcode = krb5_rd_rep(kcontext, auth_context, &ap_req, &repl);
01549
01550 if (repl)
01551 krb5_free_ap_rep_enc_part(kcontext, repl);
01552
01553 if (retcode) {
01554 DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() failed: %s\n",
01555 error_message(retcode)));
01556 retval = SNMPERR_KRB5;
01557 goto error;
01558 }
01559
01560 DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() decoded successfully.\n"));
01561
01562 retcode =
01563 krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey);
01564
01565 if (retcode) {
01566 DEBUGMSGTL(("ksm", "Unable to retrieve local subkey: %s\n",
01567 error_message(retcode)));
01568 retval = SNMPERR_KRB5;
01569 snmp_set_detail("Unable to retrieve local subkey");
01570 goto error;
01571 }
01572
01573 } else {
01574 #ifndef HEIMDAL
01575 DEBUGMSGTL(("ksm", "Unknown Kerberos message type (%02x)\n",
01576 ap_req.data[0]));
01577 #else
01578 DEBUGMSGTL(("ksm", "Unknown Kerberos message type (%02x)\n",
01579 ((char *)ap_req.data)[0]));
01580 #endif
01581 retval = SNMPERR_KRB5;
01582 snmp_set_detail("Unknown Kerberos message type");
01583 goto error;
01584 }
01585
01586 #ifdef MIT_NEW_CRYPTO
01587 input.data = (char *) parms->wholeMsg;
01588 input.length = parms->wholeMsgLen;
01589
01590 retcode =
01591 krb5_c_verify_checksum(kcontext, subkey, KSM_KEY_USAGE_CHECKSUM,
01592 &input, &checksum, &valid);
01593 #elif defined(OLD_HEIMDAL)
01594 retcode = krb5_crypto_init(kcontext, subkey, 0, &heim_crypto);
01595 if (retcode) {
01596 DEBUGMSGTL(("ksm", "krb5_crypto_init failed: %s\n",
01597 error_message(retcode)));
01598 snmp_set_detail(error_message(retcode));
01599 retval = SNMPERR_KRB5;
01600 goto error;
01601 }
01602 retcode = krb5_verify_checksum(kcontext, heim_crypto,
01603 KSM_KEY_USAGE_CHECKSUM, parms->wholeMsg,
01604 parms->wholeMsgLen, &checksum);
01605 #else
01606 retcode = krb5_verify_checksum(kcontext, cksumtype, &checksum,
01607 parms->wholeMsg, parms->wholeMsgLen,
01608 (krb5_pointer) subkey->contents,
01609 subkey->length);
01610 #endif
01611
01612 if (retcode) {
01613 DEBUGMSGTL(("ksm", "KSM checksum verification failed: %s\n",
01614 error_message(retcode)));
01615 retval = SNMPERR_KRB5;
01616 snmp_set_detail(error_message(retcode));
01617 goto error;
01618 }
01619
01620
01621
01622
01623
01624
01625 #ifdef MIT_NEW_CRYPTO
01626 if (!valid) {
01627 DEBUGMSGTL(("ksm", "Computed checksum did not match supplied "
01628 "checksum!\n"));
01629 retval = SNMPERR_KRB5;
01630 snmp_set_detail
01631 ("Computed checksum did not match supplied checksum");
01632 goto error;
01633 }
01634 #endif
01635
01636
01637
01638
01639
01640
01641
01642
01643 if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
01644
01645 if ((current = asn_parse_sequence(current, &length, &type,
01646 (ASN_UNIVERSAL | ASN_PRIMITIVE |
01647 ASN_OCTET_STR), "ksm pdu")) ==
01648 NULL) {
01649 DEBUGMSGTL(("ksm", "KSM sPDU octet decoding failed\n"));
01650 retval = SNMPERR_ASN_PARSE_ERR;
01651 goto error;
01652 }
01653
01654
01655
01656
01657
01658
01659 DEBUGMSGTL(("ksm", "KSM starting sPDU decode\n"));
01660
01661
01662
01663
01664
01665
01666
01667 #ifdef MIT_NEW_CRYPTO
01668
01669 retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);
01670
01671 if (retcode) {
01672 DEBUGMSGTL(("ksm",
01673 "Unable to determine crypto block size: %s\n",
01674 error_message(retcode)));
01675 snmp_set_detail(error_message(retcode));
01676 retval = SNMPERR_KRB5;
01677 goto error;
01678 }
01679 #elif defined(OLD_HEIMDAL)
01680 #else
01681
01682 blocksize =
01683 krb5_enctype_array[subkey->enctype]->system->block_length;
01684
01685 #endif
01686
01687 #ifndef OLD_HEIMDAL
01688 ivector.data = malloc(blocksize);
01689
01690 if (!ivector.data) {
01691 DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n",
01692 blocksize));
01693 retval = SNMPERR_MALLOC;
01694 goto error;
01695 }
01696
01697 ivector.length = blocksize;
01698 memset(ivector.data, 0, blocksize);
01699
01700 #ifndef MIT_NEW_CRYPTO
01701
01702 krb5_use_enctype(kcontext, &eblock, subkey->enctype);
01703
01704 retcode = krb5_process_key(kcontext, &eblock, subkey);
01705
01706 if (retcode) {
01707 DEBUGMSGTL(("ksm", "KSM key post-processing failed: %s\n",
01708 error_message(retcode)));
01709 snmp_set_detail(error_message(retcode));
01710 retval = SNMPERR_KRB5;
01711 goto error;
01712 }
01713 #endif
01714
01715 #endif
01716
01717 if (length > *parms->scopedPduLen) {
01718 DEBUGMSGTL(("ksm", "KSM not enough room - have %d bytes to "
01719 "decrypt but only %d bytes available\n", length,
01720 *parms->scopedPduLen));
01721 retval = SNMPERR_TOO_LONG;
01722 #ifndef MIT_NEW_CRYPTO
01723 #ifndef OLD_HEIMDAL
01724 krb5_finish_key(kcontext, &eblock);
01725 #endif
01726 #endif
01727 goto error;
01728 }
01729 #ifdef MIT_NEW_CRYPTO
01730 in_crypt.ciphertext.data = (char *) current;
01731 in_crypt.ciphertext.length = length;
01732 in_crypt.enctype = subkey->enctype;
01733 output.data = (char *) *parms->scopedPdu;
01734 output.length = *parms->scopedPduLen;
01735
01736 retcode =
01737 krb5_c_decrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
01738 &ivector, &in_crypt, &output);
01739 #elif defined (OLD_HEIMDAL)
01740 retcode = krb5_decrypt(kcontext, heim_crypto, KSM_KEY_USAGE_ENCRYPTION,
01741 current, length, &output);
01742 if (retcode == 0) {
01743 *parms->scopedPdu = (char *) output.data;
01744 *parms->scopedPduLen = output.length;
01745 krb5_data_zero(&output);
01746 }
01747 #else
01748
01749 retcode = krb5_decrypt(kcontext, (krb5_pointer) current,
01750 *parms->scopedPdu, length, &eblock,
01751 ivector.data);
01752
01753 krb5_finish_key(kcontext, &eblock);
01754
01755 #endif
01756
01757 if (retcode) {
01758 DEBUGMSGTL(("ksm", "Decryption failed: %s\n",
01759 error_message(retcode)));
01760 snmp_set_detail(error_message(retcode));
01761 retval = SNMPERR_KRB5;
01762 goto error;
01763 }
01764
01765 *parms->scopedPduLen = length;
01766
01767 } else {
01768
01769
01770
01771
01772 *parms->scopedPdu = current;
01773 *parms->scopedPduLen =
01774 parms->wholeMsgLen - (current - parms->wholeMsg);
01775 }
01776
01777
01778
01779
01780
01781 *parms->maxSizeResponse = parms->maxMsgSize - 200;
01782
01783 DEBUGMSGTL(("ksm", "KSM processing complete\n"));
01784
01785
01786
01787
01788
01789
01790 if (!response) {
01791
01792 retcode = krb5_unparse_name(kcontext, TICKET_CLIENT(ticket),
01793 &cname);
01794
01795 if (retcode) {
01796 DEBUGMSGTL(("ksm", "KSM krb5_unparse_name failed: %s\n",
01797 error_message(retcode)));
01798 snmp_set_detail(error_message(retcode));
01799 retval = SNMPERR_KRB5;
01800 goto error;
01801 }
01802
01803 if (strlen(cname) > *parms->secNameLen + 1) {
01804 DEBUGMSGTL(("ksm",
01805 "KSM: Principal length (%d) is too long (%d)\n",
01806 strlen(cname), parms->secNameLen));
01807 retval = SNMPERR_TOO_LONG;
01808 free(cname);
01809 goto error;
01810 }
01811
01812 strcpy(parms->secName, cname);
01813 *parms->secNameLen = strlen(cname);
01814
01815 free(cname);
01816
01817
01818
01819
01820
01821
01822 ksm_state = SNMP_MALLOC_STRUCT(ksm_secStateRef);
01823
01824 if (!ksm_state) {
01825 DEBUGMSGTL(("ksm", "KSM unable to malloc memory for "
01826 "ksm_secStateRef\n"));
01827 retval = SNMPERR_MALLOC;
01828 goto error;
01829 }
01830
01831 ksm_state->auth_context = auth_context;
01832 auth_context = NULL;
01833 ksm_state->cksumtype = cksumtype;
01834
01835 *parms->secStateRef = ksm_state;
01836 } else {
01837
01838
01839
01840
01841
01842
01843
01844 memcpy(parms->secName, entry->secName, entry->secNameLen);
01845 *parms->secNameLen = entry->secNameLen;
01846 }
01847
01848
01849
01850
01851
01852 parms->secEngineID = (u_char *) "";
01853 *parms->secEngineIDLen = 0;
01854
01855 auth_context = NULL;
01856
01857 error:
01858 if (retval == SNMPERR_ASN_PARSE_ERR &&
01859 snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0)
01860 DEBUGMSGTL(("ksm", "Failed to increment statistics.\n"));
01861
01862 if (subkey)
01863 krb5_free_keyblock(kcontext, subkey);
01864
01865 #ifdef OLD_HEIMDAL
01866 if (heim_crypto)
01867 krb5_crypto_destroy(kcontext, heim_crypto);
01868 #endif
01869
01870 if (CHECKSUM_CONTENTS(&checksum))
01871 free(CHECKSUM_CONTENTS(&checksum));
01872
01873 if (ivector.data)
01874 free(ivector.data);
01875
01876 if (ticket)
01877 krb5_free_ticket(kcontext, ticket);
01878
01879 if (!response && auth_context)
01880 krb5_auth_con_free(kcontext, auth_context);
01881
01882 if (ap_req.data)
01883 free(ap_req.data);
01884
01885 return retval;
01886 }