snmpksm.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:57k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * snmpksm.c
  3.  *
  4.  * This code implements the Kerberos Security Model (KSM) for SNMP.
  5.  *
  6.  * Security number - 2066432
  7.  */
  8. #include <net-snmp/net-snmp-config.h>
  9. #include <sys/types.h>
  10. #if HAVE_WINSOCK_H
  11. #include <winsock.h>
  12. #endif
  13. #include <stdio.h>
  14. #ifdef HAVE_STDLIB_H
  15. #include <stdlib.h>
  16. #endif
  17. #if TIME_WITH_SYS_TIME
  18. # ifdef WIN32
  19. #  include <sys/timeb.h>
  20. # else
  21. #  include <sys/time.h>
  22. # endif
  23. # include <time.h>
  24. #else
  25. # if HAVE_SYS_TIME_H
  26. #  include <sys/time.h>
  27. # else
  28. #  include <time.h>
  29. # endif
  30. #endif
  31. #if HAVE_STRING_H
  32. #include <string.h>
  33. #else
  34. #include <strings.h>
  35. #endif
  36. #ifdef HAVE_NETINET_IN_H
  37. #include <netinet/in.h>
  38. #endif
  39. #include <errno.h>
  40. #if HAVE_DMALLOC_H
  41. #include <dmalloc.h>
  42. #endif
  43. #ifdef HEIMDAL
  44. #ifndef MIT_NEW_CRYPTO
  45. #define OLD_HEIMDAL
  46. #endif  /* ! MIT_NEW_CRYPTO */
  47. #endif  /* HEIMDAL */
  48. #ifdef HEIMDAL
  49. #define oid heimdal_oid_renamed
  50. #endif /* HEIMDAL */
  51. #include <krb5.h>
  52. #include <com_err.h>
  53. #ifdef HEIMDAL
  54. #undef oid
  55. #endif /* HEIMDAL */
  56. #ifdef HEIMDAL
  57. #define CHECKSUM_TYPE(x) (x)->cksumtype
  58. #define CHECKSUM_CONTENTS(x) ((char *)((x)->checksum.data))
  59. #define CHECKSUM_LENGTH(x) (x)->checksum.length
  60. #define TICKET_CLIENT(x) (x)->client
  61. #else /* HEIMDAL */
  62. #define CHECKSUM_TYPE(x) (x)->checksum_type
  63. #define CHECKSUM_CONTENTS(x) (x)->contents
  64. #define CHECKSUM_LENGTH(x) (x)->length
  65. #define TICKET_CLIENT(x) (x)->enc_part2->client
  66. #endif /* HEIMDAL */
  67. #include <net-snmp/output_api.h>
  68. #include <net-snmp/config_api.h>
  69. #include <net-snmp/utilities.h>
  70. #include <net-snmp/library/asn1.h>
  71. #include <net-snmp/library/snmp_api.h>
  72. #include <net-snmp/library/callback.h>
  73. #include <net-snmp/library/keytools.h>
  74. #include <net-snmp/library/snmpv3.h>
  75. #include <net-snmp/library/lcd_time.h>
  76. #include <net-snmp/library/scapi.h>
  77. #include <net-snmp/library/callback.h>
  78. #include <net-snmp/library/snmp_secmod.h>
  79. #include <net-snmp/library/snmpksm.h>
  80. static krb5_context kcontext = NULL;
  81. static krb5_rcache rcache = NULL;
  82. static krb5_keytab keytab = NULL;
  83. static int keytab_setup = 0;
  84. static const char *service_name = NULL;
  85. static int      ksm_session_init(netsnmp_session *);
  86. static void     ksm_free_state_ref(void *);
  87. static int      ksm_free_pdu(netsnmp_pdu *);
  88. static int      ksm_clone_pdu(netsnmp_pdu *, netsnmp_pdu *);
  89. static int      ksm_insert_cache(long, krb5_auth_context, u_char *,
  90.                                  size_t);
  91. static void     ksm_decrement_ref_count(long);
  92. static void     ksm_increment_ref_count(long);
  93. static struct ksm_cache_entry *ksm_get_cache(long);
  94. #define HASHSIZE 64
  95. /*
  96.  * Our information stored for the response PDU.
  97.  */
  98. struct ksm_secStateRef {
  99.     krb5_auth_context auth_context;
  100.     krb5_cksumtype  cksumtype;
  101. };
  102. /*
  103.  * A KSM outgoing pdu cache entry
  104.  */
  105. struct ksm_cache_entry {
  106.     long            msgid;
  107.     int             refcount;
  108.     krb5_auth_context auth_context;
  109.     u_char         *secName;
  110.     size_t          secNameLen;
  111.     struct ksm_cache_entry *next;
  112. };
  113. /*
  114.  * Poor man's hash table
  115.  */
  116. static struct ksm_cache_entry *ksm_hash_table[HASHSIZE];
  117. /*
  118.  * Stuff to deal with config values
  119.  * Note the conditionals that wrap these--i don't know if these are
  120.  * needed, since i don't know how library initialization and callbacks
  121.  * and stuff work
  122.  */
  123. static int
  124. init_snmpksm_post_config(int majorid, int minorid, void *serverarg,
  125.  void *clientarg)
  126. {
  127.     if (kcontext == NULL) {
  128. /* not reached, i'd imagine */
  129.         return SNMPERR_KRB5;
  130.     }
  131.     if (service_name == NULL) {
  132. /* always reached, i'd imagine */
  133. char *c = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
  134. NETSNMP_DS_LIB_KSM_SERVICE_NAME);
  135. if (c != NULL) {
  136. service_name = c;
  137. }
  138. else {
  139. service_name = "host";
  140. }
  141.     }
  142.     if (keytab_setup == 0) {
  143. /* always reached, i'd imagine */
  144. char *c = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
  145. NETSNMP_DS_LIB_KSM_KEYTAB);
  146. if (c) {
  147.     krb5_error_code retval;
  148.     DEBUGMSGTL(("ksm", "Using keytab %sn", c));
  149.     retval = krb5_kt_resolve(kcontext, c, &keytab);
  150.     if (retval) {
  151. DEBUGMSGTL(("ksm", "krb5_kt_resolve("%s") failed. KSM "
  152.     "config callback failingn", error_message(retval)));
  153. return SNMPERR_KRB5;
  154.     }
  155. }
  156. else {
  157.     DEBUGMSGTL(("ksm", "Using default keytabn", c));
  158. }
  159. keytab_setup = 1;
  160.     }
  161.     return SNMPERR_SUCCESS;
  162. }
  163. /*
  164.  * Initialize all of the state required for Kerberos (right now, just call
  165.  * krb5_init_context).
  166.  */
  167. void
  168. init_ksm(void)
  169. {
  170.     krb5_error_code retval;
  171.     struct snmp_secmod_def *def;
  172.     int             i;
  173.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defKSMKeytab",
  174.                                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_KSM_KEYTAB);
  175.     netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defKSMServiceName",
  176.                                NETSNMP_DS_LIBRARY_ID,
  177.        NETSNMP_DS_LIB_KSM_SERVICE_NAME);
  178.     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
  179.    SNMP_CALLBACK_POST_READ_CONFIG,
  180.    init_snmpksm_post_config, NULL);
  181.     if (kcontext == NULL) {
  182.         retval = krb5_init_context(&kcontext);
  183.         if (retval) {
  184.             DEBUGMSGTL(("ksm", "krb5_init_context failed (%s), not "
  185.                         "registering KSMn", error_message(retval)));
  186.             return;
  187.         }
  188.     }
  189.     for (i = 0; i < HASHSIZE; i++)
  190.         ksm_hash_table[i] = NULL;
  191.     def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
  192.     if (!def) {
  193.         DEBUGMSGTL(("ksm", "Unable to malloc snmp_secmod struct, not "
  194.                     "registering KSMn"));
  195.         return;
  196.     }
  197.     def->encode_reverse = ksm_rgenerate_out_msg;
  198.     def->decode = ksm_process_in_msg;
  199.     def->session_open = ksm_session_init;
  200.     def->pdu_free_state_ref = ksm_free_state_ref;
  201.     def->pdu_free = ksm_free_pdu;
  202.     def->pdu_clone = ksm_clone_pdu;
  203.     register_sec_mod(2066432, "ksm", def);
  204. }
  205. /*
  206.  * These routines implement a simple cache for information we need to
  207.  * process responses.  When we send out a request, it contains an AP_REQ;
  208.  * we get back an AP_REP, and we need the authorization context from the
  209.  * AP_REQ to decrypt the AP_REP.  But because right now there's nothing
  210.  * that gets preserved across calls to rgenerate_out_msg to process_in_msg,
  211.  * we cache these internally based on the message ID (we also cache the
  212.  * passed-in security name, for reasons that are mostly stupid).
  213.  */
  214. static int
  215. ksm_insert_cache(long msgid, krb5_auth_context auth_context,
  216.                  u_char * secName, size_t secNameLen)
  217. {
  218.     struct ksm_cache_entry *entry;
  219.     int             bucket;
  220.     int             retval;
  221.     entry = SNMP_MALLOC_STRUCT(ksm_cache_entry);
  222.     if (!entry)
  223.         return SNMPERR_MALLOC;
  224.     entry->msgid = msgid;
  225.     entry->auth_context = auth_context;
  226.     entry->refcount = 1;
  227.     retval = memdup(&entry->secName, secName, secNameLen);
  228.     if (retval != SNMPERR_SUCCESS) {
  229.         free(entry);
  230.         return retval;
  231.     }
  232.     entry->secNameLen = secNameLen;
  233.     bucket = msgid % HASHSIZE;
  234.     entry->next = ksm_hash_table[bucket];
  235.     ksm_hash_table[bucket] = entry;
  236.     return SNMPERR_SUCCESS;
  237. }
  238. static struct ksm_cache_entry *
  239. ksm_get_cache(long msgid)
  240. {
  241.     struct ksm_cache_entry *entry;
  242.     int             bucket;
  243.     bucket = msgid % HASHSIZE;
  244.     for (entry = ksm_hash_table[bucket]; entry != NULL;
  245.          entry = entry->next)
  246.         if (entry->msgid == msgid)
  247.             return entry;
  248.     return NULL;
  249. }
  250. static void
  251. ksm_decrement_ref_count(long msgid)
  252. {
  253.     struct ksm_cache_entry *entry, *entry1;
  254.     int             bucket;
  255.     bucket = msgid % HASHSIZE;
  256.     if (ksm_hash_table[bucket] && ksm_hash_table[bucket]->msgid == msgid) {
  257.         entry = ksm_hash_table[bucket];
  258.         /*
  259.          * If the reference count is zero, then free it
  260.          */
  261.         if (--entry->refcount <= 0) {
  262.             DEBUGMSGTL(("ksm", "Freeing entry for msgid %ldn", msgid));
  263.             krb5_auth_con_free(kcontext, entry->auth_context);
  264.             free(entry->secName);
  265.             ksm_hash_table[bucket] = entry->next;
  266.             free(entry);
  267.         }
  268.         return;
  269.     } else if (ksm_hash_table[bucket])
  270.         for (entry1 = ksm_hash_table[bucket], entry = entry1->next;
  271.              entry != NULL; entry1 = entry, entry = entry->next)
  272.             if (entry->msgid == msgid) {
  273.                 if (--entry->refcount <= 0) {
  274.                     DEBUGMSGTL(("ksm", "Freeing entry for msgid %ldn",
  275.                                 msgid));
  276.                     krb5_auth_con_free(kcontext, entry->auth_context);
  277.                     free(entry->secName);
  278.                     entry1->next = entry->next;
  279.                     free(entry);
  280.                 }
  281.                 return;
  282.             }
  283.     DEBUGMSGTL(("ksm",
  284.                 "KSM: Unable to decrement cache entry for msgid %ld.n",
  285.                 msgid));
  286. }
  287. static void
  288. ksm_increment_ref_count(long msgid)
  289. {
  290.     struct ksm_cache_entry *entry = ksm_get_cache(msgid);
  291.     if (!entry) {
  292.         DEBUGMSGTL(("ksm", "Unable to find cache entry for msgid %ld "
  293.                     "for incrementn", msgid));
  294.         return;
  295.     }
  296.     entry->refcount++;
  297. }
  298. /*
  299.  * Initialize specific session information (right now, just set up things to
  300.  * not do an engineID probe)
  301.  */
  302. static int
  303. ksm_session_init(netsnmp_session * sess)
  304. {
  305.     DEBUGMSGTL(("ksm",
  306.                 "KSM: Reached our session initialization callbackn"));
  307.     sess->flags |= SNMP_FLAGS_DONT_PROBE;
  308.     return SNMPERR_SUCCESS;
  309. }
  310. /*
  311.  * Free our state information (this is only done on the agent side)
  312.  */
  313. static void
  314. ksm_free_state_ref(void *ptr)
  315. {
  316.     struct ksm_secStateRef *ref = (struct ksm_secStateRef *) ptr;
  317.     DEBUGMSGTL(("ksm", "KSM: Freeing state referencen"));
  318.     krb5_auth_con_free(kcontext, ref->auth_context);
  319.     free(ref);
  320. }
  321. /*
  322.  * This is called when the PDU is freed; this will decrement reference counts
  323.  * for entries in our state cache.
  324.  */
  325. static int
  326. ksm_free_pdu(netsnmp_pdu *pdu)
  327. {
  328.     ksm_decrement_ref_count(pdu->msgid);
  329.     DEBUGMSGTL(("ksm", "Decrementing cache entry for PDU msgid %ldn",
  330.                 pdu->msgid));
  331.     return SNMPERR_SUCCESS;
  332. }
  333. /*
  334.  * This is called when a PDU is cloned (to increase reference counts)
  335.  */
  336. static int
  337. ksm_clone_pdu(netsnmp_pdu *pdu, netsnmp_pdu *pdu2)
  338. {
  339.     ksm_increment_ref_count(pdu->msgid);
  340.     DEBUGMSGTL(("ksm", "Incrementing cache entry for PDU msgid %ldn",
  341.                 pdu->msgid));
  342.     return SNMPERR_SUCCESS;
  343. }
  344. /****************************************************************************
  345.  *
  346.  * ksm_generate_out_msg
  347.  *
  348.  * Parameters:
  349.  * (See list below...)
  350.  *
  351.  * Returns:
  352.  * SNMPERR_GENERIC                        On success.
  353.  * SNMPERR_KRB5
  354.  * ... and others
  355.  *
  356.  *
  357.  * Generate an outgoing message.
  358.  *
  359.  ****************************************************************************/
  360. int
  361. ksm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
  362. {
  363.     krb5_auth_context auth_context = NULL;
  364.     krb5_error_code retcode;
  365.     krb5_ccache     cc = NULL;
  366.     int             retval = SNMPERR_SUCCESS;
  367.     krb5_data       outdata, ivector;
  368.     krb5_keyblock  *subkey = NULL;
  369. #ifdef MIT_NEW_CRYPTO
  370.     krb5_data       input;
  371.     krb5_enc_data   output;
  372.     unsigned int    numcksumtypes;
  373.     krb5_cksumtype  *cksumtype_array;
  374. #elif defined OLD_HEIMDAL /* MIT_NEW_CRYPTO */
  375.     krb5_crypto heim_crypto = NULL;
  376. #else                           /* MIT_NEW_CRYPTO */
  377.     krb5_encrypt_block eblock;
  378. #endif                          /* MIT_NEW_CRYPTO */
  379.     size_t          blocksize, encrypted_length;
  380.     unsigned char  *encrypted_data = NULL;
  381.     int             zero = 0, i;
  382.     u_char         *cksum_pointer, *endp = *parms->wholeMsg;
  383.     krb5_cksumtype  cksumtype;
  384.     krb5_checksum   pdu_checksum;
  385.     u_char         **wholeMsg = parms->wholeMsg;
  386.     size_t    *offset = parms->wholeMsgOffset, seq_offset;
  387.     struct ksm_secStateRef *ksm_state = (struct ksm_secStateRef *)
  388.         parms->secStateRef;
  389. #ifdef OLD_HEIMDAL
  390.     krb5_data encrypted_scoped_pdu;
  391. #endif /* OLD_HEIMDAL */
  392.     int rc;
  393.     char *colon = NULL;
  394.     DEBUGMSGTL(("ksm", "Starting KSM processingn"));
  395.     outdata.length = 0;
  396.     outdata.data = NULL;
  397.     ivector.length = 0;
  398.     ivector.data = NULL;
  399.     CHECKSUM_CONTENTS(&pdu_checksum) = NULL;
  400.     if (!ksm_state) {
  401.         /*
  402.          * If we've got a port number as part of the "peername", then
  403.          * suppress this (temporarily) while we build the credential info.
  404.          *   XXX - what about "udp:host" style addresses?
  405.          */
  406.         colon = strrchr(params->session->peername, ':');
  407.         if (colon != NULL) {
  408.             *colon='';
  409.         }
  410.         /*
  411.          * If we don't have a ksm_state, then we're a request.  Get a
  412.          * credential cache and build a ap_req.
  413.          */
  414.         retcode = krb5_cc_default(kcontext, &cc);
  415.         if (retcode) {
  416.             DEBUGMSGTL(("ksm", "KSM: krb5_cc_default failed: %sn",
  417.                         error_message(retcode)));
  418.             snmp_set_detail(error_message(retcode));
  419.             retval = SNMPERR_KRB5;
  420.             goto error;
  421.         }
  422.         DEBUGMSGTL(("ksm", "KSM: Set credential cache successfullyn"));
  423.         /*
  424.          * This seems odd, since we don't need this until later (or earlier,
  425.          * depending on how you look at it), but because the most likely
  426.          * errors are Kerberos at this point, I'll get this now to save
  427.          * time not encoding the rest of the packet.
  428.          *
  429.          * Also, we need the subkey to encrypt the PDU (if required).
  430.          */
  431.         retcode =
  432.             krb5_mk_req(kcontext, &auth_context,
  433.                         AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
  434.                         (char *) service_name, parms->session->peername, NULL,
  435.                         cc, &outdata);
  436.         if (colon != NULL)
  437.             *colon=':';
  438.         if (retcode) {
  439.             DEBUGMSGTL(("ksm", "KSM: krb5_mk_req failed: %sn",
  440.                         error_message(retcode)));
  441.             snmp_set_detail(error_message(retcode));
  442.             retval = SNMPERR_KRB5;
  443.             goto error;
  444.         }
  445. DEBUGMSGTL(("ksm", "KSM: ticket retrieved successfully for "%s/%s" "
  446.     "(may not be actual ticket sname)n", service_name,
  447.     parms->session->peername));
  448.     } else {
  449.         /*
  450.          * Grab the auth_context from our security state reference
  451.          */
  452.         auth_context = ksm_state->auth_context;
  453.         /*
  454.          * Bundle up an AP_REP.  Note that we do this only when we
  455.          * have a security state reference (which means we're in an agent
  456.          * and we're sending a response).
  457.          */
  458.         DEBUGMSGTL(("ksm", "KSM: Starting reply processing.n"));
  459.         retcode = krb5_mk_rep(kcontext, auth_context, &outdata);
  460.         if (retcode) {
  461.             DEBUGMSGTL(("ksm", "KSM: krb5_mk_rep failed: %sn",
  462.                         error_message(retcode)));
  463.             snmp_set_detail(error_message(retcode));
  464.             retval = SNMPERR_KRB5;
  465.             goto error;
  466.         }
  467.         DEBUGMSGTL(("ksm", "KSM: Finished with krb5_mk_rep()n"));
  468.     }
  469.     /*
  470.      * If we have to encrypt the PDU, do that now
  471.      */
  472.     if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
  473.         DEBUGMSGTL(("ksm", "KSM: Starting PDU encryption.n"));
  474.         /*
  475.          * It's weird -
  476.          *
  477.          * If we're on the manager, it's a local subkey (because that's in
  478.          * our AP_REQ)
  479.          *
  480.          * If we're on the agent, it's a remote subkey (because that comes
  481.          * FROM the received AP_REQ).
  482.          */
  483.         if (ksm_state)
  484.             retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context,
  485.                                                     &subkey);
  486.         else
  487.             retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context,
  488.                                                    &subkey);
  489.         if (retcode) {
  490.             DEBUGMSGTL(("ksm",
  491.                         "KSM: krb5_auth_con_getlocalsubkey failed: %sn",
  492.                         error_message(retcode)));
  493.             snmp_set_detail(error_message(retcode));
  494.             retval = SNMPERR_KRB5;
  495.             goto error;
  496.         }
  497.         /*
  498.          * Note that here we need to handle different things between the
  499.          * old and new crypto APIs.  First, we need to get the final encrypted
  500.          * length of the PDU.
  501.          */
  502. #ifdef MIT_NEW_CRYPTO
  503.         retcode = krb5_c_encrypt_length(kcontext, subkey->enctype,
  504.                                         parms->scopedPduLen,
  505.                                         &encrypted_length);
  506.         if (retcode) {
  507.             DEBUGMSGTL(("ksm",
  508.                         "Encryption length calculation failed: %sn",
  509.                         error_message(retcode)));
  510.             snmp_set_detail(error_message(retcode));
  511.             retval = SNMPERR_KRB5;
  512.             goto error;
  513.         }
  514. #elif defined OLD_HEIMDAL
  515. retcode = krb5_crypto_init(kcontext, subkey, 0, &heim_crypto);
  516.         if (retcode) {
  517.             DEBUGMSGTL(("ksm", "krb5_crypto_init failed: %sn",
  518.                         error_message(retcode)));
  519.             snmp_set_detail(error_message(retcode));
  520.             retval = SNMPERR_KRB5;
  521.             goto error;
  522.         }
  523. encrypted_length = krb5_get_wrapped_length(kcontext, heim_crypto,
  524.    parms->scopedPduLen);
  525. #else                           /* MIT_NEW_CRYPTO */
  526.         krb5_use_enctype(kcontext, &eblock, subkey->enctype);
  527.         retcode = krb5_process_key(kcontext, &eblock, subkey);
  528.         if (retcode) {
  529.             DEBUGMSGTL(("ksm", "krb5_process_key failed: %sn",
  530.                         error_message(retcode)));
  531.             snmp_set_detail(error_message(retcode));
  532.             retval = SNMPERR_KRB5;
  533.             goto error;
  534.         }
  535.         encrypted_length = krb5_encrypt_size(parms->scopedPduLen,
  536.                                              eblock.crypto_entry);
  537. #endif                          /* MIT_NEW_CRYPTO */
  538. #ifndef OLD_HEIMDAL /* since heimdal allocs the space for us */
  539.         encrypted_data = malloc(encrypted_length);
  540.         if (!encrypted_data) {
  541.             DEBUGMSGTL(("ksm",
  542.                         "KSM: Unable to malloc %d bytes for encrypt "
  543.                         "buffer: %sn", parms->scopedPduLen,
  544.                         strerror(errno)));
  545.             retval = SNMPERR_MALLOC;
  546. #ifndef MIT_NEW_CRYPTO
  547.             krb5_finish_key(kcontext, &eblock);
  548. #endif                          /* ! MIT_NEW_CRYPTO */
  549.             goto error;
  550.         }
  551. #endif /* ! OLD_HEIMDAL */
  552.         /*
  553.          * We need to set up a blank initialization vector for the encryption.
  554.          * Use a block of all zero's (which is dependent on the block size
  555.          * of the encryption method).
  556.          */
  557. #ifdef MIT_NEW_CRYPTO
  558.         retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);
  559.         if (retcode) {
  560.             DEBUGMSGTL(("ksm",
  561.                         "Unable to determine crypto block size: %sn",
  562.                         error_message(retcode)));
  563.             snmp_set_detail(error_message(retcode));
  564.             retval = SNMPERR_KRB5;
  565.             goto error;
  566.         }
  567. #elif defined (OLD_HEIMDAL) /* MIT_NEW_CRYPTO */
  568. #else                           /* MIT_NEW_CRYPTO */
  569.         blocksize =
  570.             krb5_enctype_array[subkey->enctype]->system->block_length;
  571. #endif                          /* MIT_NEW_CRYPTO */
  572. #ifndef OLD_HEIMDAL /* since allocs the space for us */
  573.         ivector.data = malloc(blocksize);
  574.         if (!ivector.data) {
  575.             DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivectorn",
  576.                         blocksize));
  577.             retval = SNMPERR_MALLOC;
  578.             goto error;
  579.         }
  580.         ivector.length = blocksize;
  581.         memset(ivector.data, 0, blocksize);
  582. #endif /* OLD_HEIMDAL */
  583.         /*
  584.          * Finally!  Do the encryption!
  585.          */
  586. #ifdef MIT_NEW_CRYPTO
  587.         input.data = (char *) parms->scopedPdu;
  588.         input.length = parms->scopedPduLen;
  589.         output.ciphertext.data = (char *) encrypted_data;
  590.         output.ciphertext.length = encrypted_length;
  591.         retcode =
  592.             krb5_c_encrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
  593.                            &ivector, &input, &output);
  594. #elif defined OLD_HEIMDAL /* MIT_NEW_CRYPTO */
  595. krb5_data_zero(&encrypted_scoped_pdu);
  596. retcode = krb5_encrypt(kcontext, heim_crypto, KSM_KEY_USAGE_ENCRYPTION,
  597.        parms->scopedPdu, parms->scopedPduLen,
  598.        &encrypted_scoped_pdu);
  599. if (retcode == 0) {
  600. encrypted_length = encrypted_scoped_pdu.length;
  601. encrypted_data = encrypted_scoped_pdu.data;
  602. krb5_data_zero(&encrypted_scoped_pdu);
  603. }
  604. #else                           /* MIT_NEW_CRYPTO */
  605.         retcode = krb5_encrypt(kcontext, (krb5_pointer) parms->scopedPdu,
  606.                                (krb5_pointer) encrypted_data,
  607.                                parms->scopedPduLen, &eblock, ivector.data);
  608.         krb5_finish_key(kcontext, &eblock);
  609. #endif                          /* MIT_NEW_CRYPTO */
  610.         if (retcode) {
  611.             DEBUGMSGTL(("ksm", "KSM: krb5_encrypt failed: %sn",
  612.                         error_message(retcode)));
  613.             retval = SNMPERR_KRB5;
  614.             snmp_set_detail(error_message(retcode));
  615.             goto error;
  616.         }
  617. *offset = 0;
  618.         rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen,
  619.                                              offset, 1,
  620.                                              (u_char) (ASN_UNIVERSAL |
  621.                                                        ASN_PRIMITIVE |
  622.                                                        ASN_OCTET_STR),
  623.                                              encrypted_data,
  624.                                              encrypted_length);
  625.         if (rc == 0) {
  626.             DEBUGMSGTL(("ksm", "Building encrypted payload failed.n"));
  627.             retval = SNMPERR_TOO_LONG;
  628.             goto error;
  629.         }
  630.         DEBUGMSGTL(("ksm", "KSM: Encryption complete.n"));
  631.     } else {
  632.         /*
  633.          * Plaintext PDU (not encrypted)
  634.          */
  635.         if (*parms->wholeMsgLen < parms->scopedPduLen) {
  636.             DEBUGMSGTL(("ksm", "Not enough room for plaintext PDU.n"));
  637.             retval = SNMPERR_TOO_LONG;
  638.             goto error;
  639.         }
  640.     }
  641.     /*
  642.      * Start encoding the msgSecurityParameters
  643.      *
  644.      * For now, use 0 for the response hint
  645.      */
  646.     DEBUGMSGTL(("ksm", "KSM: scopedPdu added to payloadn"));
  647.     seq_offset = *offset;
  648.     rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen,
  649.                                       offset, 1,
  650.                                       (u_char) (ASN_UNIVERSAL |
  651.                                                 ASN_PRIMITIVE |
  652.                                                 ASN_INTEGER),
  653.                                       (long *) &zero, sizeof(zero));
  654.     if (rc == 0) {
  655.         DEBUGMSGTL(("ksm", "Building ksm security parameters failed.n"));
  656.         retval = SNMPERR_TOO_LONG;
  657.         goto error;
  658.     }
  659.     rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen,
  660.                                          offset, 1,
  661.                                          (u_char) (ASN_UNIVERSAL |
  662.                                                    ASN_PRIMITIVE |
  663.                                                    ASN_OCTET_STR),
  664.                                          (u_char *) outdata.data,
  665.                                          outdata.length);
  666.     if (rc == 0) {
  667.         DEBUGMSGTL(("ksm", "Building ksm AP_REQ failed.n"));
  668.         retval = SNMPERR_TOO_LONG;
  669.         goto error;
  670.     }
  671.     /*
  672.      * If we didn't encrypt the packet, we haven't yet got the subkey.
  673.      * Get that now.
  674.      */
  675.     if (!subkey) {
  676.         if (ksm_state)
  677.             retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context,
  678.                                                     &subkey);
  679.         else
  680.             retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context,
  681.                                                    &subkey);
  682.         if (retcode) {
  683.             DEBUGMSGTL(("ksm", "krb5_auth_con_getlocalsubkey failed: %sn",
  684.                         error_message(retcode)));
  685.             snmp_set_detail(error_message(retcode));
  686.             retval = SNMPERR_KRB5;
  687.             goto error;
  688.         }
  689. #ifdef OLD_HEIMDAL
  690.  retcode = krb5_crypto_init(kcontext, subkey, 0, &heim_crypto);
  691.         if (retcode) {
  692.             DEBUGMSGTL(("ksm", "krb5_crypto_init failed: %sn",
  693.                         error_message(retcode)));
  694.             snmp_set_detail(error_message(retcode));
  695.             retval = SNMPERR_KRB5;
  696.             goto error;
  697.         }
  698. #endif /* OLD_HEIMDAL */
  699.     }
  700.     /*
  701.      * Now, we need to pick the "right" checksum algorithm.  For old
  702.      * crypto, just pick CKSUMTYPE_RSA_MD5_DES; for new crypto, pick
  703.      * one of the "approved" ones.
  704.      */
  705. #ifdef MIT_NEW_CRYPTO
  706.     retcode = krb5_c_keyed_checksum_types(kcontext, subkey->enctype,
  707.                                           &numcksumtypes, &cksumtype_array);
  708.     if (retcode) {
  709. DEBUGMSGTL(("ksm", "Unable to find appropriate keyed checksum: %sn",
  710.     error_message(retcode)));
  711. snmp_set_detail(error_message(retcode));
  712.         retval = SNMPERR_KRB5;
  713.         goto error;
  714.     }
  715.     if (numcksumtypes <= 0) {
  716. DEBUGMSGTL(("ksm", "We received a list of zero cksumtypes for this "
  717.     "enctype (%d)n", subkey->enctype));
  718. snmp_set_detail("No valid checksum type for this encryption type");
  719. retval = SNMPERR_KRB5;
  720. goto error;
  721.     }
  722.     /*
  723.      * It's not clear to me from the API which checksum you're supposed
  724.      * to support, so I'm taking a guess at the first one
  725.      */
  726.     cksumtype = cksumtype_array[0];
  727.     krb5_free_cksumtypes(kcontext, cksumtype_array);
  728.     DEBUGMSGTL(("ksm", "KSM: Choosing checksum type of %d (subkey type "
  729. "of %d)n", cksumtype, subkey->enctype));
  730.     retcode = krb5_c_checksum_length(kcontext, cksumtype, &blocksize);
  731.     if (retcode) {
  732.         DEBUGMSGTL(("ksm", "Unable to determine checksum length: %sn",
  733.                     error_message(retcode)));
  734.         snmp_set_detail(error_message(retcode));
  735.         retval = SNMPERR_KRB5;
  736.         goto error;
  737.     }
  738.     CHECKSUM_LENGTH(&pdu_checksum) = blocksize;
  739. #else /* MIT_NEW_CRYPTO */
  740.     if (ksm_state)
  741.         cksumtype = ksm_state->cksumtype;
  742.     else
  743. #ifdef OLD_HEIMDAL
  744.     {
  745.     /* no way to tell what kind of checksum to use without trying */
  746.     retval = krb5_create_checksum(kcontext, heim_crypto, 
  747.   KSM_KEY_USAGE_CHECKSUM, 0,
  748.   parms->scopedPdu, parms->scopedPduLen,
  749.   &pdu_checksum);
  750.     if (retval) {
  751.     DEBUGMSGTL(("ksm", "Unable to create a checksum: %sn",
  752. error_message(retval)));
  753.     snmp_set_detail(error_message(retcode));
  754.     retval = SNMPERR_KRB5;
  755.     goto error;
  756.     }
  757.     cksumtype = CHECKSUM_TYPE(&pdu_checksum);
  758.     }
  759. #else /* OLD_HEIMDAL */
  760. cksumtype = CKSUMTYPE_RSA_MD5_DES;
  761. #endif /* OLD_HEIMDAL */
  762. #ifdef OLD_HEIMDAL
  763. if (!krb5_checksum_is_keyed(kcontext, cksumtype)) {
  764. #else  /* OLD_HEIMDAL */
  765.     if (!is_keyed_cksum(cksumtype)) {
  766. #endif  /* OLD_HEIMDAL */
  767.         DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksumn",
  768.                     cksumtype));
  769.         snmp_set_detail("Checksum is not a keyed checksum");
  770.         retval = SNMPERR_KRB5;
  771.         goto error;
  772.     }
  773. #ifdef OLD_HEIMDAL
  774.     if (!krb5_checksum_is_collision_proof(kcontext, cksumtype)) {
  775. #else  /* OLD_HEIMDAL */
  776.     if (!is_coll_proof_cksum(cksumtype)) {
  777. #endif  /* OLD_HEIMDAL */
  778.         DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
  779.                     "checksumn", cksumtype));
  780.         snmp_set_detail("Checksum is not a collision-proof checksum");
  781.         retval = SNMPERR_KRB5;
  782.         goto error;
  783.     }
  784. #ifdef OLD_HEIMDAL
  785.     if (CHECKSUM_CONTENTS(&pdu_checksum) != NULL ) {
  786. /* we did the bogus checksum--don't need to ask for the size again
  787.  * or initialize cksumtype; just free the bits */
  788. free(CHECKSUM_CONTENTS(&pdu_checksum));
  789. CHECKSUM_CONTENTS(&pdu_checksum) = NULL;
  790.     }
  791.     else {
  792. retval = krb5_checksumsize(kcontext, cksumtype,
  793.    &CHECKSUM_LENGTH(&pdu_checksum));
  794. if (retval) {
  795.     DEBUGMSGTL(("ksm", "Unable to determine checksum length: %sn",
  796. error_message(retval)));
  797.     snmp_set_detail(error_message(retcode));
  798.     retval = SNMPERR_KRB5;
  799.     goto error;
  800. }
  801. #else /* OLD_HEIMDAL */
  802.     CHECKSUM_LENGTH(&pdu_checksum) = krb5_checksum_size(kcontext, cksumtype);
  803. #endif /* OLD_HEIMDAL */
  804.     CHECKSUM_TYPE(&pdu_checksum) = cksumtype;
  805. #ifdef OLD_HEIMDAL
  806.     }
  807. #endif /* OLD_HEIMDAL */
  808. #endif /* MIT_NEW_CRYPTO */
  809.     /*
  810.      * Note that here, we're just leaving blank space for the checksum;
  811.      * we remember where that is, and we'll fill it in later.
  812.      */
  813.     *offset += CHECKSUM_LENGTH(&pdu_checksum);
  814.     memset(*wholeMsg + *parms->wholeMsgLen - *offset, 0, CHECKSUM_LENGTH(&pdu_checksum));
  815.     cksum_pointer = *wholeMsg + *parms->wholeMsgLen - *offset;
  816.     rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen,
  817.                                          parms->wholeMsgOffset, 1,
  818.                                          (u_char) (ASN_UNIVERSAL |
  819.                                                    ASN_PRIMITIVE |
  820.                                                    ASN_OCTET_STR),
  821.                                          CHECKSUM_LENGTH(&pdu_checksum));
  822.     if (rc == 0) {
  823.         DEBUGMSGTL(("ksm", "Building ksm security parameters failed.n"));
  824.         retval = SNMPERR_TOO_LONG;
  825.         goto error;
  826.     }
  827.     rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen,
  828.                                       parms->wholeMsgOffset, 1,
  829.                                       (u_char) (ASN_UNIVERSAL |
  830.                                                 ASN_PRIMITIVE |
  831.                                                 ASN_OCTET_STR),
  832.                                       (long *) &cksumtype,
  833.                                       sizeof(cksumtype));
  834.     if (rc == 0) {
  835.         DEBUGMSGTL(("ksm", "Building ksm security parameters failed.n"));
  836.         retval = SNMPERR_TOO_LONG;
  837.         goto error;
  838.     }
  839.     rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen,
  840.                                            parms->wholeMsgOffset, 1,
  841.                                            (u_char) (ASN_SEQUENCE |
  842.                                                      ASN_CONSTRUCTOR),
  843.                                            *offset - seq_offset);
  844.     if (rc == 0) {
  845.         DEBUGMSGTL(("ksm", "Building ksm security parameters failed.n"));
  846.         retval = SNMPERR_TOO_LONG;
  847.         goto error;
  848.     }
  849.     rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen,
  850.                                          parms->wholeMsgOffset, 1,
  851.                                          (u_char) (ASN_UNIVERSAL |
  852.                                                    ASN_PRIMITIVE |
  853.                                                    ASN_OCTET_STR),
  854.                                          *offset - seq_offset);
  855.     if (rc == 0) {
  856.         DEBUGMSGTL(("ksm", "Building ksm security parameters failed.n"));
  857.         retval = SNMPERR_TOO_LONG;
  858.         goto error;
  859.     }
  860.     DEBUGMSGTL(("ksm", "KSM: Security parameter encoding completedn"));
  861.     /*
  862.      * We're done with the KSM security parameters - now we do the global
  863.      * header and wrap up the whole PDU.
  864.      */
  865.     if (*parms->wholeMsgLen < parms->globalDataLen) {
  866.         DEBUGMSGTL(("ksm", "Building global data failed.n"));
  867.         retval = SNMPERR_TOO_LONG;
  868.         goto error;
  869.     }
  870.     *offset += parms->globalDataLen;
  871.     memcpy(*wholeMsg + *parms->wholeMsgLen - *offset,
  872.    parms->globalData, parms->globalDataLen);
  873.     rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen,
  874.                                            offset, 1,
  875.                                            (u_char) (ASN_SEQUENCE |
  876.                                                      ASN_CONSTRUCTOR),
  877.                                            *offset);
  878.     if (rc == 0) {
  879.         DEBUGMSGTL(("ksm", "Building master packet sequence.n"));
  880.         retval = SNMPERR_TOO_LONG;
  881.         goto error;
  882.     }
  883.     DEBUGMSGTL(("ksm", "KSM: PDU master packet encoding complete.n"));
  884.     /*
  885.      * Now we need to checksum the entire PDU (since it's built).
  886.      */
  887. #ifndef OLD_HEIMDAL /* since heimdal allocs the mem for us */
  888.     CHECKSUM_CONTENTS(&pdu_checksum) = malloc(CHECKSUM_LENGTH(&pdu_checksum));
  889.     if (!CHECKSUM_CONTENTS(&pdu_checksum)) {
  890.         DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksumn",
  891.                     CHECKSUM_LENGTH(&pdu_checksum)));
  892.         retval = SNMPERR_MALLOC;
  893.         goto error;
  894.     }
  895. #endif /* ! OLD_HEIMDAL */
  896. #ifdef MIT_NEW_CRYPTO
  897.     input.data = (char *) (*wholeMsg + *parms->wholeMsgLen - *offset);
  898.     input.length = *offset;
  899.         retcode = krb5_c_make_checksum(kcontext, cksumtype, subkey,
  900.                                        KSM_KEY_USAGE_CHECKSUM, &input,
  901.                                        &pdu_checksum);
  902. #elif defined(OLD_HEIMDAL) /* MIT_NEW_CRYPTO */
  903. retcode = krb5_create_checksum(kcontext, heim_crypto,
  904.        KSM_KEY_USAGE_CHECKSUM, cksumtype,
  905.        *wholeMsg + *parms->wholeMsgLen
  906.        - *offset, *offset, &pdu_checksum);
  907. #else                           /* MIT_NEW_CRYPTO */
  908.     retcode = krb5_calculate_checksum(kcontext, cksumtype, *wholeMsg +
  909.       *parms->wholeMsgLen - *offset,
  910.                                       *offset,
  911.                                       (krb5_pointer) subkey->contents,
  912.                                       subkey->length, &pdu_checksum);
  913. #endif                          /* MIT_NEW_CRYPTO */
  914.     if (retcode) {
  915.         DEBUGMSGTL(("ksm", "Calculate checksum failed: %sn",
  916.                     error_message(retcode)));
  917.         retval = SNMPERR_KRB5;
  918.         snmp_set_detail(error_message(retcode));
  919.         goto error;
  920.     }
  921.     DEBUGMSGTL(("ksm", "KSM: Checksum calculation complete.n"));
  922.     memcpy(cksum_pointer, CHECKSUM_CONTENTS(&pdu_checksum), CHECKSUM_LENGTH(&pdu_checksum));
  923.     DEBUGMSGTL(("ksm", "KSM: Writing checksum of %d bytes at offset %dn",
  924.                 CHECKSUM_LENGTH(&pdu_checksum), cksum_pointer - (*wholeMsg + 1)));
  925.     DEBUGMSGTL(("ksm", "KSM: Checksum:"));
  926.     for (i = 0; i < CHECKSUM_LENGTH(&pdu_checksum); i++)
  927.         DEBUGMSG(("ksm", " %02x",
  928.                   (unsigned int) CHECKSUM_CONTENTS(&pdu_checksum)[i]));
  929.     DEBUGMSG(("ksm", "n"));
  930.     /*
  931.      * If we're _not_ called as part of a response (null ksm_state),
  932.      * then save the auth_context for later using our cache routines.
  933.      */
  934.     if (!ksm_state) {
  935.         if ((retval = ksm_insert_cache(parms->pdu->msgid, auth_context,
  936.                                        (u_char *) parms->secName,
  937.                                        parms->secNameLen)) !=
  938.             SNMPERR_SUCCESS)
  939.             goto error;
  940.         auth_context = NULL;
  941.     }
  942.     DEBUGMSGTL(("ksm", "KSM processing complete!n"));
  943.   error:
  944.     if (CHECKSUM_CONTENTS(&pdu_checksum))
  945. #ifdef MIT_NEW_CRYPTO
  946.         krb5_free_checksum_contents(kcontext, &pdu_checksum);
  947. #else                           /* MIT_NEW_CRYPTO */
  948.         free(CHECKSUM_CONTENTS(&pdu_checksum));
  949. #endif                          /* MIT_NEW_CRYPTO */
  950.     if (ivector.data)
  951.         free(ivector.data);
  952.     if (subkey)
  953.         krb5_free_keyblock(kcontext, subkey);
  954. #ifdef OLD_HEIMDAL /* OLD_HEIMDAL */
  955.     if (heim_crypto)
  956.     krb5_crypto_destroy(kcontext, heim_crypto);
  957. #endif /* OLD_HEIMDAL */
  958.     if (encrypted_data)
  959.         free(encrypted_data);
  960.     if (cc)
  961.         krb5_cc_close(kcontext, cc);
  962.     if (auth_context && !ksm_state)
  963.         krb5_auth_con_free(kcontext, auth_context);
  964.     return retval;
  965. }
  966. /****************************************************************************
  967.  *
  968.  * ksm_process_in_msg
  969.  *
  970.  * Parameters:
  971.  * (See list below...)
  972.  *
  973.  * Returns:
  974.  * KSM_ERR_NO_ERROR                        On success.
  975.  * SNMPERR_KRB5
  976.  * KSM_ERR_GENERIC_ERROR
  977.  * KSM_ERR_UNSUPPORTED_SECURITY_LEVEL
  978.  *
  979.  *
  980.  * Processes an incoming message.
  981.  *
  982.  ****************************************************************************/
  983. int
  984. ksm_process_in_msg(struct snmp_secmod_incoming_params *parms)
  985. {
  986.     long            temp;
  987.     krb5_cksumtype  cksumtype;
  988.     krb5_auth_context auth_context = NULL;
  989.     krb5_error_code retcode;
  990.     krb5_checksum   checksum;
  991.     krb5_data       ap_req, ivector;
  992.     krb5_flags      flags;
  993.     krb5_keyblock  *subkey = NULL;
  994. #ifdef MIT_NEW_CRYPTO
  995.     krb5_data       input, output;
  996.     krb5_boolean    valid;
  997.     krb5_enc_data   in_crypt;
  998. #elif defined OLD_HEIMDAL /* MIT_NEW_CRYPTO */
  999.     krb5_data output;
  1000.     krb5_crypto heim_crypto = NULL;
  1001. #else                           /* MIT_NEW_CRYPTO */
  1002.     krb5_encrypt_block eblock;
  1003. #endif                          /* MIT_NEW_CRYPTO */
  1004.     krb5_ticket    *ticket = NULL;
  1005.     int             retval = SNMPERR_SUCCESS, response = 0;
  1006.     size_t          length =
  1007.         parms->wholeMsgLen - (u_int) (parms->secParams - parms->wholeMsg);
  1008.     u_char         *current = parms->secParams, type;
  1009.     size_t          cksumlength, blocksize;
  1010.     long            hint;
  1011.     char           *cname;
  1012.     struct ksm_secStateRef *ksm_state;
  1013.     struct ksm_cache_entry *entry;
  1014.     DEBUGMSGTL(("ksm", "Processing has begunn"));
  1015.     CHECKSUM_CONTENTS(&checksum) = NULL;
  1016.     ap_req.data = NULL;
  1017.     ivector.length = 0;
  1018.     ivector.data = NULL;
  1019.     /*
  1020.      * First, parse the security parameters (because we need the subkey inside
  1021.      * of the ticket to do anything
  1022.      */
  1023.     if ((current = asn_parse_sequence(current, &length, &type,
  1024.                                       (ASN_UNIVERSAL | ASN_PRIMITIVE |
  1025.                                        ASN_OCTET_STR),
  1026.                                       "ksm first octet")) == NULL) {
  1027.         DEBUGMSGTL(("ksm", "Initial security paramter parsing failedn"));
  1028.         retval = SNMPERR_ASN_PARSE_ERR;
  1029.         goto error;
  1030.     }
  1031.     if ((current = asn_parse_sequence(current, &length, &type,
  1032.                                       (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  1033.                                       "ksm sequence")) == NULL) {
  1034.         DEBUGMSGTL(("ksm",
  1035.                     "Security parameter sequence parsing failedn"));
  1036.         retval = SNMPERR_ASN_PARSE_ERR;
  1037.         goto error;
  1038.     }
  1039.     if ((current = asn_parse_int(current, &length, &type, &temp,
  1040.                                  sizeof(temp))) == NULL) {
  1041.         DEBUGMSGTL(("ksm", "Security parameter checksum type parsing"
  1042.                     "failedn"));
  1043.         retval = SNMPERR_ASN_PARSE_ERR;
  1044.         goto error;
  1045.     }
  1046.     cksumtype = temp;
  1047. #ifdef MIT_NEW_CRYPTO
  1048.     if (!krb5_c_valid_cksumtype(cksumtype)) {
  1049.         DEBUGMSGTL(("ksm", "Invalid checksum type (%d)n", cksumtype));
  1050.         retval = SNMPERR_KRB5;
  1051.         snmp_set_detail("Invalid checksum type");
  1052.         goto error;
  1053.     }
  1054.     if (!krb5_c_is_keyed_cksum(cksumtype)) {
  1055.         DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksumn",
  1056.                     cksumtype));
  1057.         snmp_set_detail("Checksum is not a keyed checksum");
  1058.         retval = SNMPERR_KRB5;
  1059.         goto error;
  1060.     }
  1061.     if (!krb5_c_is_coll_proof_cksum(cksumtype)) {
  1062.         DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
  1063.                     "checksumn", cksumtype));
  1064.         snmp_set_detail("Checksum is not a collision-proof checksum");
  1065.         retval = SNMPERR_KRB5;
  1066.         goto error;
  1067.     }
  1068. #else /* ! MIT_NEW_CRYPTO */
  1069. #ifdef OLD_HEIMDAL
  1070.     /* kludge */
  1071.     if (krb5_checksumsize(kcontext, cksumtype, &cksumlength)) {
  1072. #else /* OLD_HEIMDAL */
  1073.     if (!valid_cksumtype(cksumtype)) {
  1074. #endif /* OLD_HEIMDAL */
  1075.         DEBUGMSGTL(("ksm", "Invalid checksum type (%d)n", cksumtype));
  1076.         retval = SNMPERR_KRB5;
  1077.         snmp_set_detail("Invalid checksum type");
  1078.         goto error;
  1079.     }
  1080. #ifdef OLD_HEIMDAL
  1081.     if (!krb5_checksum_is_keyed(kcontext, cksumtype)) {
  1082. #else /* OLD_HEIMDAL */
  1083.     if (!is_keyed_cksum(cksumtype)) {
  1084. #endif /* OLD_HEIMDAL */
  1085.         DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksumn",
  1086.                     cksumtype));
  1087.         snmp_set_detail("Checksum is not a keyed checksum");
  1088.         retval = SNMPERR_KRB5;
  1089.         goto error;
  1090.     }
  1091. #ifdef OLD_HEIMDAL
  1092.     if (!krb5_checksum_is_collision_proof(kcontext, cksumtype)) {
  1093. #else /* OLD_HEIMDAL */
  1094.     if (!is_coll_proof_cksum(cksumtype)) {
  1095. #endif /* OLD_HEIMDAL */
  1096.         DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
  1097.                     "checksumn", cksumtype));
  1098.         snmp_set_detail("Checksum is not a collision-proof checksum");
  1099.         retval = SNMPERR_KRB5;
  1100.         goto error;
  1101.     }
  1102. #endif /* MIT_NEW_CRYPTO */
  1103.     CHECKSUM_TYPE(&checksum) = cksumtype;
  1104.     cksumlength = length;
  1105.     if ((current = asn_parse_sequence(current, &cksumlength, &type,
  1106.                                       (ASN_UNIVERSAL | ASN_PRIMITIVE |
  1107.                                        ASN_OCTET_STR), "ksm checksum")) ==
  1108.         NULL) {
  1109.         DEBUGMSGTL(("ksm",
  1110.                     "Security parameter checksum parsing failedn"));
  1111.         retval = SNMPERR_ASN_PARSE_ERR;
  1112.         goto error;
  1113.     }
  1114.     CHECKSUM_CONTENTS(&checksum) = malloc(cksumlength);
  1115.     if (!CHECKSUM_CONTENTS(&checksum)) {
  1116.         DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum.n",
  1117.                     cksumlength));
  1118.         retval = SNMPERR_MALLOC;
  1119.         goto error;
  1120.     }
  1121.     memcpy(CHECKSUM_CONTENTS(&checksum), current, cksumlength);
  1122.     CHECKSUM_LENGTH(&checksum) = cksumlength;
  1123.     CHECKSUM_TYPE(&checksum) = cksumtype;
  1124.     /*
  1125.      * Zero out the checksum so the validation works correctly
  1126.      */
  1127.     memset(current, 0, cksumlength);
  1128.     current += cksumlength;
  1129.     length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);
  1130.     if ((current = asn_parse_sequence(current, &length, &type,
  1131.                                       (ASN_UNIVERSAL | ASN_PRIMITIVE |
  1132.                                        ASN_OCTET_STR), "ksm ap_req")) ==
  1133.         NULL) {
  1134.         DEBUGMSGTL(("ksm", "KSM security parameter AP_REQ/REP parsing "
  1135.                     "failedn"));
  1136.         retval = SNMPERR_ASN_PARSE_ERR;
  1137.         goto error;
  1138.     }
  1139.     ap_req.length = length;
  1140.     ap_req.data = malloc(length);
  1141.     if (!ap_req.data) {
  1142.         DEBUGMSGTL(("ksm",
  1143.                     "KSM unable to malloc %d bytes for AP_REQ/REP.n",
  1144.                     length));
  1145.         retval = SNMPERR_MALLOC;
  1146.         goto error;
  1147.     }
  1148.     memcpy(ap_req.data, current, length);
  1149.     current += length;
  1150.     length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);
  1151.     if ((current = asn_parse_int(current, &length, &type, &hint,
  1152.                                  sizeof(hint))) == NULL) {
  1153.         DEBUGMSGTL(("ksm",
  1154.                     "KSM security parameter hint parsing failedn"));
  1155.         retval = SNMPERR_ASN_PARSE_ERR;
  1156.         goto error;
  1157.     }
  1158.     /*
  1159.      * Okay!  We've got it all!  Now try decoding the damn ticket.
  1160.      *
  1161.      * But of course there's a WRINKLE!  We need to figure out if we're
  1162.      * processing a AP_REQ or an AP_REP.  How do we do that?  We're going
  1163.      * to cheat, and look at the first couple of bytes (which is what
  1164.      * the Kerberos library routines do anyway).
  1165.      *
  1166.      * If there are ever new Kerberos message formats, we'll need to fix
  1167.      * this here.
  1168.      *
  1169.      * If it's a _response_, then we need to get the auth_context
  1170.      * from our cache.
  1171.      */
  1172.     if (ap_req.length
  1173. #ifndef HEIMDAL
  1174.         && (ap_req.data[0] == 0x6e || ap_req.data[0] == 0x4e)) {
  1175. #else /* HEIMDAL */
  1176.         && (((char *)ap_req.data)[0] == 0x6e || ((char *)ap_req.data)[0] == 0x4e)) {
  1177. #endif
  1178.         /*
  1179.          * We need to initalize the authorization context, and set the
  1180.          * replay cache in it (and initialize the replay cache if we
  1181.          * haven't already
  1182.          */
  1183.         retcode = krb5_auth_con_init(kcontext, &auth_context);
  1184.         if (retcode) {
  1185.             DEBUGMSGTL(("ksm", "krb5_auth_con_init failed: %sn",
  1186.                         error_message(retcode)));
  1187.             retval = SNMPERR_KRB5;
  1188.             snmp_set_detail(error_message(retcode));
  1189.             goto error;
  1190.         }
  1191.         if (!rcache) {
  1192.             krb5_data       server;
  1193.             server.data = "host";
  1194.             server.length = strlen(server.data);
  1195.             retcode = krb5_get_server_rcache(kcontext, &server, &rcache);
  1196.             if (retcode) {
  1197.                 DEBUGMSGTL(("ksm", "krb5_get_server_rcache failed: %sn",
  1198.                             error_message(retcode)));
  1199.                 retval = SNMPERR_KRB5;
  1200.                 snmp_set_detail(error_message(retcode));
  1201.                 goto error;
  1202.             }
  1203.         }
  1204.         retcode = krb5_auth_con_setrcache(kcontext, auth_context, rcache);
  1205.         if (retcode) {
  1206.             DEBUGMSGTL(("ksm", "krb5_auth_con_setrcache failed: %sn",
  1207.                         error_message(retcode)));
  1208.             retval = SNMPERR_KRB5;
  1209.             snmp_set_detail(error_message(retcode));
  1210.             goto error;
  1211.         }
  1212.         retcode = krb5_rd_req(kcontext, &auth_context, &ap_req, NULL,
  1213.                               keytab, &flags, &ticket);
  1214.         krb5_auth_con_setrcache(kcontext, auth_context, NULL);
  1215.         if (retcode) {
  1216.             DEBUGMSGTL(("ksm", "krb5_rd_req() failed: %sn",
  1217.                         error_message(retcode)));
  1218.             retval = SNMPERR_KRB5;
  1219.             snmp_set_detail(error_message(retcode));
  1220.             goto error;
  1221.         }
  1222.         retcode =
  1223.             krb5_unparse_name(kcontext, TICKET_CLIENT(ticket), &cname);
  1224.         if (retcode == 0) {
  1225.             DEBUGMSGTL(("ksm", "KSM authenticated principal name: %sn",
  1226.                         cname));
  1227.             free(cname);
  1228.         }
  1229.         /*
  1230.          * Check to make sure AP_OPTS_MUTUAL_REQUIRED was set
  1231.          */
  1232.         if (!(flags & AP_OPTS_MUTUAL_REQUIRED)) {
  1233.             DEBUGMSGTL(("ksm",
  1234.                         "KSM MUTUAL_REQUIRED not set in request!n"));
  1235.             retval = SNMPERR_KRB5;
  1236.             snmp_set_detail("MUTUAL_REQUIRED not set in message");
  1237.             goto error;
  1238.         }
  1239.         retcode =
  1240.             krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey);
  1241.         if (retcode) {
  1242.             DEBUGMSGTL(("ksm", "KSM remote subkey retrieval failed: %sn",
  1243.                         error_message(retcode)));
  1244.             retval = SNMPERR_KRB5;
  1245.             snmp_set_detail(error_message(retcode));
  1246.             goto error;
  1247.         }
  1248. #ifndef HEIMDAL
  1249.     } else if (ap_req.length && (ap_req.data[0] == 0x6f ||
  1250.                                  ap_req.data[0] == 0x4f)) {
  1251. #else /* HEIMDAL */
  1252.     } else if (ap_req.length && (((char *)ap_req.data)[0] == 0x6f ||
  1253.                                  ((char *)ap_req.data)[0] == 0x4f)) {
  1254. #endif /* HEIMDAL */
  1255.         /*
  1256.          * Looks like a response; let's see if we've got that auth_context
  1257.          * in our cache.
  1258.          */
  1259.         krb5_ap_rep_enc_part *repl = NULL;
  1260.         response = 1;
  1261.         entry = ksm_get_cache(parms->pdu->msgid);
  1262.         if (!entry) {
  1263.             DEBUGMSGTL(("ksm",
  1264.                         "KSM: Unable to find auth_context for PDU with "
  1265.                         "message ID of %ldn", parms->pdu->msgid));
  1266.             retval = SNMPERR_KRB5;
  1267.             goto error;
  1268.         }
  1269.         auth_context = entry->auth_context;
  1270.         /*
  1271.          * In that case, let's call the rd_rep function
  1272.          */
  1273.         retcode = krb5_rd_rep(kcontext, auth_context, &ap_req, &repl);
  1274.         if (repl)
  1275.             krb5_free_ap_rep_enc_part(kcontext, repl);
  1276.         if (retcode) {
  1277.             DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() failed: %sn",
  1278.                         error_message(retcode)));
  1279.             retval = SNMPERR_KRB5;
  1280.             goto error;
  1281.         }
  1282.         DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() decoded successfully.n"));
  1283.         retcode =
  1284.             krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey);
  1285.         if (retcode) {
  1286.             DEBUGMSGTL(("ksm", "Unable to retrieve local subkey: %sn",
  1287.                         error_message(retcode)));
  1288.             retval = SNMPERR_KRB5;
  1289.             snmp_set_detail("Unable to retrieve local subkey");
  1290.             goto error;
  1291.         }
  1292.     } else {
  1293. #ifndef HEIMDAL
  1294.         DEBUGMSGTL(("ksm", "Unknown Kerberos message type (%02x)n",
  1295.                     ap_req.data[0]));
  1296. #else  /* HEIMDAL */
  1297.  DEBUGMSGTL(("ksm", "Unknown Kerberos message type (%02x)n",
  1298.                     ((char *)ap_req.data)[0]));
  1299. #endif
  1300.         retval = SNMPERR_KRB5;
  1301.         snmp_set_detail("Unknown Kerberos message type");
  1302.         goto error;
  1303.     }
  1304. #ifdef MIT_NEW_CRYPTO
  1305.     input.data = (char *) parms->wholeMsg;
  1306.     input.length = parms->wholeMsgLen;
  1307.     retcode =
  1308.         krb5_c_verify_checksum(kcontext, subkey, KSM_KEY_USAGE_CHECKSUM,
  1309.                                &input, &checksum, &valid);
  1310. #elif defined(OLD_HEIMDAL) /* MIT_NEW_CRYPTO */
  1311.     retcode = krb5_crypto_init(kcontext, subkey, 0, &heim_crypto);
  1312.     if (retcode) {
  1313.             DEBUGMSGTL(("ksm", "krb5_crypto_init failed: %sn",
  1314.                         error_message(retcode)));
  1315.             snmp_set_detail(error_message(retcode));
  1316.             retval = SNMPERR_KRB5;
  1317.             goto error;
  1318.     }
  1319.     retcode = krb5_verify_checksum(kcontext, heim_crypto,
  1320.    KSM_KEY_USAGE_CHECKSUM, parms->wholeMsg,
  1321.    parms->wholeMsgLen, &checksum);
  1322. #else                           /* MIT_NEW_CRYPTO */
  1323.     retcode = krb5_verify_checksum(kcontext, cksumtype, &checksum,
  1324.                                    parms->wholeMsg, parms->wholeMsgLen,
  1325.                                    (krb5_pointer) subkey->contents,
  1326.                                    subkey->length);
  1327. #endif                          /* MIT_NEW_CRYPTO */
  1328.     if (retcode) {
  1329.         DEBUGMSGTL(("ksm", "KSM checksum verification failed: %sn",
  1330.                     error_message(retcode)));
  1331.         retval = SNMPERR_KRB5;
  1332.         snmp_set_detail(error_message(retcode));
  1333.         goto error;
  1334.     }
  1335.     /*
  1336.      * Don't ask me why they didn't simply return an error, but we have
  1337.      * to check to see if "valid" is false.
  1338.      */
  1339. #ifdef MIT_NEW_CRYPTO
  1340.     if (!valid) {
  1341.         DEBUGMSGTL(("ksm", "Computed checksum did not match supplied "
  1342.                     "checksum!n"));
  1343.         retval = SNMPERR_KRB5;
  1344.         snmp_set_detail
  1345.             ("Computed checksum did not match supplied checksum");
  1346.         goto error;
  1347.     }
  1348. #endif                          /* MIT_NEW_CRYPTO */
  1349.     /*
  1350.      * Handle an encrypted PDU.  Note that it's an OCTET_STRING of the
  1351.      * output of whatever Kerberos cryptosystem you're using (defined by
  1352.      * the encryption type).  Note that this is NOT the EncryptedData
  1353.      * sequence - it's what goes in the "cipher" field of EncryptedData.
  1354.      */
  1355.     if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
  1356.         if ((current = asn_parse_sequence(current, &length, &type,
  1357.                                           (ASN_UNIVERSAL | ASN_PRIMITIVE |
  1358.                                            ASN_OCTET_STR), "ksm pdu")) ==
  1359.             NULL) {
  1360.             DEBUGMSGTL(("ksm", "KSM sPDU octet decoding failedn"));
  1361.             retval = SNMPERR_ASN_PARSE_ERR;
  1362.             goto error;
  1363.         }
  1364.         /*
  1365.          * The PDU is now pointed at by "current", and the length is in
  1366.          * "length".
  1367.          */
  1368.         DEBUGMSGTL(("ksm", "KSM starting sPDU decoden"));
  1369.         /*
  1370.          * We need to set up a blank initialization vector for the decryption.
  1371.          * Use a block of all zero's (which is dependent on the block size
  1372.          * of the encryption method).
  1373.          */
  1374. #ifdef MIT_NEW_CRYPTO
  1375.         retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);
  1376.         if (retcode) {
  1377.             DEBUGMSGTL(("ksm",
  1378.                         "Unable to determine crypto block size: %sn",
  1379.                         error_message(retcode)));
  1380.             snmp_set_detail(error_message(retcode));
  1381.             retval = SNMPERR_KRB5;
  1382.             goto error;
  1383.         }
  1384. #elif defined(OLD_HEIMDAL) /* MIT_NEW_CRYPTO */
  1385. #else                           /* MIT_NEW_CRYPTO */
  1386.         blocksize =
  1387.             krb5_enctype_array[subkey->enctype]->system->block_length;
  1388. #endif                          /* MIT_NEW_CRYPTO */
  1389. #ifndef OLD_HEIMDAL
  1390.         ivector.data = malloc(blocksize);
  1391.         if (!ivector.data) {
  1392.             DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivectorn",
  1393.                         blocksize));
  1394.             retval = SNMPERR_MALLOC;
  1395.             goto error;
  1396.         }
  1397.         ivector.length = blocksize;
  1398.         memset(ivector.data, 0, blocksize);
  1399. #ifndef MIT_NEW_CRYPTO
  1400.         krb5_use_enctype(kcontext, &eblock, subkey->enctype);
  1401.         retcode = krb5_process_key(kcontext, &eblock, subkey);
  1402.         if (retcode) {
  1403.             DEBUGMSGTL(("ksm", "KSM key post-processing failed: %sn",
  1404.                         error_message(retcode)));
  1405.             snmp_set_detail(error_message(retcode));
  1406.             retval = SNMPERR_KRB5;
  1407.             goto error;
  1408.         }
  1409. #endif                          /* !MIT_NEW_CRYPTO */
  1410. #endif /* ! OLD_HEIMDAL */
  1411.         if (length > *parms->scopedPduLen) {
  1412.             DEBUGMSGTL(("ksm", "KSM not enough room - have %d bytes to "
  1413.                         "decrypt but only %d bytes availablen", length,
  1414.                         *parms->scopedPduLen));
  1415.             retval = SNMPERR_TOO_LONG;
  1416. #ifndef MIT_NEW_CRYPTO
  1417. #ifndef OLD_HEIMDAL
  1418.             krb5_finish_key(kcontext, &eblock);
  1419. #endif                          /* ! OLD_HEIMDAL */
  1420. #endif                          /* ! MIT_NEW_CRYPTO */
  1421.             goto error;
  1422.         }
  1423. #ifdef MIT_NEW_CRYPTO
  1424.         in_crypt.ciphertext.data = (char *) current;
  1425.         in_crypt.ciphertext.length = length;
  1426.         in_crypt.enctype = subkey->enctype;
  1427.         output.data = (char *) *parms->scopedPdu;
  1428.         output.length = *parms->scopedPduLen;
  1429.         retcode =
  1430.             krb5_c_decrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
  1431.                            &ivector, &in_crypt, &output);
  1432. #elif defined (OLD_HEIMDAL) /* MIT_NEW_CRYPTO */
  1433. retcode = krb5_decrypt(kcontext, heim_crypto, KSM_KEY_USAGE_ENCRYPTION,
  1434.        current, length, &output);
  1435. if (retcode == 0) {
  1436. *parms->scopedPdu = (char *) output.data;
  1437. *parms->scopedPduLen = output.length;
  1438. krb5_data_zero(&output);
  1439. }
  1440. #else                           /* MIT_NEW_CRYPTO */
  1441.         retcode = krb5_decrypt(kcontext, (krb5_pointer) current,
  1442.                                *parms->scopedPdu, length, &eblock,
  1443.                                ivector.data);
  1444.         krb5_finish_key(kcontext, &eblock);
  1445. #endif                          /* MIT_NEW_CRYPTO */
  1446.         if (retcode) {
  1447.             DEBUGMSGTL(("ksm", "Decryption failed: %sn",
  1448.                         error_message(retcode)));
  1449.             snmp_set_detail(error_message(retcode));
  1450.             retval = SNMPERR_KRB5;
  1451.             goto error;
  1452.         }
  1453.         *parms->scopedPduLen = length;
  1454.     } else {
  1455.         /*
  1456.          * Clear PDU
  1457.          */
  1458.         *parms->scopedPdu = current;
  1459.         *parms->scopedPduLen =
  1460.             parms->wholeMsgLen - (current - parms->wholeMsg);
  1461.     }
  1462.     /*
  1463.      * A HUGE GROSS HACK
  1464.      */
  1465.     *parms->maxSizeResponse = parms->maxMsgSize - 200;
  1466.     DEBUGMSGTL(("ksm", "KSM processing completen"));
  1467.     /*
  1468.      * Set the secName to the right value (a hack for now).  But that's
  1469.      * only used for when we're processing a request, not a response.
  1470.      */
  1471.     if (!response) {
  1472.         retcode = krb5_unparse_name(kcontext, TICKET_CLIENT(ticket),
  1473.                                     &cname);
  1474.         if (retcode) {
  1475.             DEBUGMSGTL(("ksm", "KSM krb5_unparse_name failed: %sn",
  1476.                         error_message(retcode)));
  1477.             snmp_set_detail(error_message(retcode));
  1478.             retval = SNMPERR_KRB5;
  1479.             goto error;
  1480.         }
  1481.         if (strlen(cname) > *parms->secNameLen + 1) {
  1482.             DEBUGMSGTL(("ksm",
  1483.                         "KSM: Principal length (%d) is too long (%d)n",
  1484.                         strlen(cname), parms->secNameLen));
  1485.             retval = SNMPERR_TOO_LONG;
  1486.             free(cname);
  1487.             goto error;
  1488.         }
  1489.         strcpy(parms->secName, cname);
  1490.         *parms->secNameLen = strlen(cname);
  1491.         free(cname);
  1492.         /*
  1493.          * Also, if we're not a response, keep around our auth_context so we
  1494.          * can encode the reply message correctly
  1495.          */
  1496.         ksm_state = SNMP_MALLOC_STRUCT(ksm_secStateRef);
  1497.         if (!ksm_state) {
  1498.             DEBUGMSGTL(("ksm", "KSM unable to malloc memory for "
  1499.                         "ksm_secStateRefn"));
  1500.             retval = SNMPERR_MALLOC;
  1501.             goto error;
  1502.         }
  1503.         ksm_state->auth_context = auth_context;
  1504.         auth_context = NULL;
  1505.         ksm_state->cksumtype = cksumtype;
  1506.         *parms->secStateRef = ksm_state;
  1507.     } else {
  1508.         /*
  1509.          * We _still_ have to set the secName in process_in_msg().  Do
  1510.          * that now with what we were passed in before (we cached it,
  1511.          * remember?)
  1512.          */
  1513.         memcpy(parms->secName, entry->secName, entry->secNameLen);
  1514.         *parms->secNameLen = entry->secNameLen;
  1515.     }
  1516.     /*
  1517.      * Just in case
  1518.      */
  1519.     parms->secEngineID = (u_char *) "";
  1520.     *parms->secEngineIDLen = 0;
  1521.     auth_context = NULL;        /* So we don't try to free it on success */
  1522.   error:
  1523.     if (retval == SNMPERR_ASN_PARSE_ERR &&
  1524.         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0)
  1525.         DEBUGMSGTL(("ksm", "Failed to increment statistics.n"));
  1526.     if (subkey)
  1527.         krb5_free_keyblock(kcontext, subkey);
  1528. #ifdef OLD_HEIMDAL /* OLD_HEIMDAL */
  1529.     if (heim_crypto)
  1530.     krb5_crypto_destroy(kcontext, heim_crypto);
  1531. #endif /* OLD_HEIMDAL */
  1532.     if (CHECKSUM_CONTENTS(&checksum))
  1533.         free(CHECKSUM_CONTENTS(&checksum));
  1534.     if (ivector.data)
  1535.         free(ivector.data);
  1536.     if (ticket)
  1537.         krb5_free_ticket(kcontext, ticket);
  1538.     if (!response && auth_context)
  1539.         krb5_auth_con_free(kcontext, auth_context);
  1540.     if (ap_req.data)
  1541.         free(ap_req.data);
  1542.     return retval;
  1543. }