Ticket #62468: ticket62468-hook-library-diff.txt

File ticket62468-hook-library-diff.txt, 28.5 KB (added by steven-michaud (Steven Michaud), 3 years ago)

HookCase hook library I tested with

Line 
1diff --git a/Users/smichaud/Documents/ReverseEngineering/HookCase-master/HookLibraryTemplate/hook.mm b/hook.mm
2index e7102fb..d7e0fce 100644
3--- a/Users/smichaud/Documents/ReverseEngineering/HookCase-master/HookLibraryTemplate/hook.mm
4+++ b/hook.mm
5@@ -1019,6 +1019,8 @@ loadHandler::loadHandler()
6   LogWithFormat(true, "Hook.mm: loadHandler()");
7   PrintStackTrace();
8 #endif
9+
10+  LogWithFormat(true, "Hook.mm: loadHandler()");
11 }
12 
13 loadHandler::~loadHandler()
14@@ -1200,6 +1202,748 @@ static int Hooked_interpose_example(char *arg1, int (*arg2)(char *))
15 
16 // Put other hooked methods and swizzled classes here
17 
18+typedef signed char INT1;  /*  8 bits */
19+typedef short INT2;   /* 16 bits */
20+typedef int INT4;   /* 32 bits */
21+/* There is no 64 bit type */
22+typedef unsigned char UINT1;  /*  8 bits */
23+typedef unsigned short UINT2;  /* 16 bits */
24+typedef unsigned int UINT4;  /* 32 bits */
25+/* There is no 64 bit type */
26+
27+#define NI_MAXHOST 1025
28+#define NI_MAXSERV 32
29+
30+#define CANON_BUF_SIZE 1024
31+
32+enum Sasl_conn_type { SASL_CONN_UNKNOWN = 0,
33+                      SASL_CONN_SERVER = 1,
34+                      SASL_CONN_CLIENT = 2 };
35+
36+/* security layer strength factor -- an unsigned integer usable by the caller
37+ *  to specify approximate security layer strength desired.  Roughly
38+ *  correlated to effective key length for encryption.
39+ * 0   = no protection
40+ * 1   = integrity protection only
41+ * 40  = 40-bit DES or 40-bit RC2/RC4
42+ * 56  = DES
43+ * 112 = triple-DES
44+ * 128 = 128-bit RC2/RC4/BLOWFISH
45+ * 256 = baseline AES
46+ */
47+typedef unsigned sasl_ssf_t;
48+
49+#define SASL_CB_LIST_END     0  /* end of list */
50+#define SASL_CB_GETOPT       1
51+#define SASL_CB_LOG          2
52+#define SASL_CB_GETPATH      3
53+#define SASL_CB_VERIFYFILE   4
54+#define SASL_CB_GETCONFPATH  5
55+#define SASL_CB_USER         0x4001  /* client user identity to login as */
56+#define SASL_CB_AUTHNAME     0x4002  /* client authentication name */
57+#define SASL_CB_LANGUAGE     0x4003  /* comma separated list of RFC 1766
58+                                      * language codes in order of preference
59+                                      * to be used to localize client prompts
60+                                      * or server error codes */
61+#define SASL_CB_CNONCE       0x4007  /* caller supplies client-nonce
62+                                      * primarily for testing purposes */
63+#define SASL_CB_PASS         0x4004  /* client passphrase-based secret */
64+#define SASL_CB_ECHOPROMPT   0x4005  /* challenge and client enterred result */
65+#define SASL_CB_NOECHOPROMPT 0x4006  /* challenge and client enterred result */
66+#define SASL_CB_GETREALM    (0x4008) /* realm to attempt authentication in */
67+#define SASL_CB_PROXY_POLICY 0x8001
68+#define SASL_CB_SERVER_USERDB_CHECKPASS (0x8005)
69+#define SASL_CB_SERVER_USERDB_SETPASS (0x8006)
70+#define SASL_CB_CANON_USER  (0x8007)
71+
72+typedef struct buffer_info {
73+  char *data;
74+  size_t curlen;
75+  size_t reallen;
76+} buffer_info_t;
77+
78+typedef struct sasl_callback {
79+  /* Identifies the type of the callback function.
80+   * Mechanisms must ignore callbacks with id's they don't recognize.
81+   */
82+  unsigned long id;
83+  int (*proc)(void);   /* Callback function.  Types of arguments vary by 'id' */
84+  void *context;
85+} sasl_callback_t;
86+
87+typedef struct {
88+  const sasl_callback_t *callbacks;
89+  const char *appname;
90+} sasl_global_callbacks_t;
91+
92+typedef struct sasl_out_params {
93+  unsigned doneflag;  /* exchange complete */
94+
95+  const char *user;  /* canonicalized user name */
96+  const char *authid;  /* canonicalized authentication id */
97+
98+  unsigned ulen;  /* length of canonicalized user name */
99+  unsigned alen;  /* length of canonicalized authid */
100+
101+  /* security layer information */
102+  unsigned maxoutbuf;         /* Maximum buffer size, which will
103+                                 produce buffer no bigger than the
104+                                 negotiated SASL maximum buffer size */
105+  sasl_ssf_t mech_ssf;   /* Should be set non-zero if negotiation of a
106+                          * security layer was *attempted*, even if
107+                          * the negotiation failed */
108+  void *encode_context;
109+  int (*encode)(void *context, const struct iovec *invec, unsigned numiov,
110+                const char **output, unsigned *outputlen);
111+  void *decode_context;
112+  int (*decode)(void *context, const char *input, unsigned inputlen,
113+                const char **output, unsigned *outputlen);
114+
115+  /* Pointer to delegated (client's) credentials, if supported by
116+     the SASL mechanism */
117+  void *client_creds;
118+
119+  /* for additions which don't require a version upgrade; set to 0 */
120+  const void *gss_peer_name;
121+  const void *gss_local_name;
122+  const char *cbindingname;   /* channel binding name from packet */
123+  int (*spare_fptr1)(void);
124+  int (*spare_fptr2)(void);
125+  unsigned int cbindingdisp;  /* channel binding disposition from client */
126+  int spare_int2;
127+  int spare_int3;
128+  int spare_int4;
129+
130+  /* set to 0 initially, this allows a plugin with extended parameters
131+   * to work with an older framework by updating version as parameters
132+   * are added.
133+   */
134+  int param_version;
135+} sasl_out_params_t;
136+
137+typedef struct _sasl_external_properties {
138+  sasl_ssf_t ssf;
139+  char *auth_id;
140+} _sasl_external_properties_t;
141+
142+typedef struct sasl_security_properties {
143+  /* security strength factor
144+   *  min_ssf      = minimum acceptable final level
145+   *  max_ssf      = maximum acceptable final level
146+   */
147+  sasl_ssf_t min_ssf;
148+  sasl_ssf_t max_ssf;
149+
150+  /* Maximum security layer receive buffer size.
151+   *  0=security layer not supported
152+   */
153+  unsigned maxbufsize;
154+
155+  /* bitfield for attacks to protect against */
156+  unsigned security_flags;
157+
158+  /* NULL terminated array of additional property names, values */
159+  const char **property_names;
160+  const char **property_values;
161+} sasl_security_properties_t;
162+
163+typedef struct sasl_secret {
164+  unsigned long len;
165+  unsigned char data[1];  /* variable sized */
166+} sasl_secret_t;
167+
168+typedef struct sasl_conn sasl_conn_t;
169+
170+struct sasl_conn {
171+  enum Sasl_conn_type type;
172+
173+  void (*destroy_conn)(sasl_conn_t *); /* destroy function */
174+
175+  char *service;
176+
177+  unsigned int flags;  /* flags passed to sasl_*_new */
178+
179+  /* IP information.  A buffer of size 52 is adequate for this in its
180+     longest format (see sasl.h) */
181+  int got_ip_local, got_ip_remote;
182+  char iplocalport[NI_MAXHOST + NI_MAXSERV];
183+  char ipremoteport[NI_MAXHOST + NI_MAXSERV];
184+
185+  void *context;
186+  sasl_out_params_t oparams;
187+
188+  sasl_security_properties_t props;
189+  _sasl_external_properties_t external;
190+
191+  sasl_secret_t *secret;
192+
193+  int (*idle_hook)(sasl_conn_t *conn);
194+  const sasl_callback_t *callbacks;
195+  const sasl_global_callbacks_t *global_callbacks; /* global callbacks
196+          * connection */
197+  char *serverFQDN;
198+
199+  /* Pointers to memory that we are responsible for */
200+  buffer_info_t *encode_buf;
201+
202+  int error_code;
203+  char *error_buf, *errdetail_buf;
204+  size_t error_buf_len, errdetail_buf_len;
205+  char *mechlist_buf;
206+  size_t mechlist_buf_len;
207+
208+  char *decode_buf;
209+
210+  char user_buf[CANON_BUF_SIZE+1], authid_buf[CANON_BUF_SIZE+1];
211+
212+  /* Allocated by sasl_encodev if the output contains multiple SASL packet. */
213+  buffer_info_t multipacket_encoded_data;
214+};
215+
216+typedef struct sasl_rand_s sasl_rand_t;
217+
218+typedef int sasl_getopt_t(void *context, const char *plugin_name,
219+                          const char *option,
220+                          const char **result, unsigned *len);
221+
222+typedef void *sasl_malloc_t(size_t);
223+typedef void *sasl_calloc_t(size_t, size_t);
224+typedef void *sasl_realloc_t(void *, size_t);
225+typedef void sasl_free_t(void *);
226+
227+typedef void *sasl_mutex_alloc_t(void);
228+typedef int sasl_mutex_lock_t(void *mutex);
229+typedef int sasl_mutex_unlock_t(void *mutex);
230+typedef void sasl_mutex_free_t(void *mutex);
231+
232+/* MD5 context. */
233+typedef struct {
234+  UINT4 state[4];                                   /* state (ABCD) */
235+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
236+  unsigned char buffer[64];                         /* input buffer */
237+} MD5_CTX;
238+
239+typedef struct HMAC_MD5_CTX_s {
240+  MD5_CTX ictx, octx;
241+} HMAC_MD5_CTX;
242+
243+typedef struct HMAC_MD5_STATE_s {
244+  UINT4 istate[4];
245+  UINT4 ostate[4];
246+} HMAC_MD5_STATE;
247+
248+typedef int (*sasl_callback_ft)(void);
249+typedef int sasl_getcallback_t(sasl_conn_t *conn,
250+                               unsigned long callbackid,
251+                               sasl_callback_ft * pproc,
252+                               void **pcontext);
253+
254+struct propctx;
255+
256+struct propval {
257+  const char *name;  /* name of property; NULL = end of list */
258+                     /* same pointer used in request will be used here */
259+  const char **values; /* list of strings, values == NULL if property not
260+                        * found, *values == NULL if property found with
261+                        * no values */
262+  unsigned nvalues;    /* total number of value strings */
263+  unsigned valsize;  /* total size in characters of all value strings */
264+};
265+
266+typedef struct sasl_utils {
267+  int version;
268+
269+  /* contexts */
270+  sasl_conn_t *conn;
271+  sasl_rand_t *rpool;
272+  void *getopt_context;
273+
274+  /* option function */
275+  sasl_getopt_t *getopt;
276+
277+  /* allocation functions: */
278+  sasl_malloc_t *malloc;
279+  sasl_calloc_t *calloc;
280+  sasl_realloc_t *realloc;
281+  sasl_free_t *free;
282+
283+  /* mutex functions: */
284+  sasl_mutex_alloc_t *mutex_alloc;
285+  sasl_mutex_lock_t *mutex_lock;
286+  sasl_mutex_unlock_t *mutex_unlock;
287+  sasl_mutex_free_t *mutex_free;
288+
289+  /* MD5 hash and HMAC functions */
290+  void (*MD5Init)(MD5_CTX *);
291+  void (*MD5Update)(MD5_CTX *, const unsigned char *text, unsigned int len);
292+  void (*MD5Final)(unsigned char [16], MD5_CTX *);
293+  void (*hmac_md5)(const unsigned char *text, int text_len,
294+                   const unsigned char *key, int key_len,
295+                   unsigned char [16]);
296+  void (*hmac_md5_init)(HMAC_MD5_CTX *, const unsigned char *key, int len);
297+  /* hmac_md5_update() is just a call to MD5Update on inner context */
298+  void (*hmac_md5_final)(unsigned char [16], HMAC_MD5_CTX *);
299+  void (*hmac_md5_precalc)(HMAC_MD5_STATE *,
300+                           const unsigned char *key, int len);
301+  void (*hmac_md5_import)(HMAC_MD5_CTX *, HMAC_MD5_STATE *);
302+
303+  /* mechanism utility functions (same as above): */
304+  int (*mkchal)(sasl_conn_t *conn, char *buf, unsigned maxlen,
305+                unsigned hostflag);
306+  int (*utf8verify)(const char *str, unsigned len);
307+  void (*rand)(sasl_rand_t *rpool, char *buf, unsigned len);
308+  void (*churn)(sasl_rand_t *rpool, const char *data, unsigned len);
309+
310+  /* This allows recursive calls to the sasl_checkpass() routine from
311+   * within a SASL plug-in.  This MUST NOT be used in the PLAIN mechanism
312+   * as sasl_checkpass MAY be a front-end for the PLAIN mechanism.
313+   * This is intended for use by the non-standard LOGIN mechanism and
314+   * potentially by a future mechanism which uses public-key technology to
315+   * set up a lightweight encryption layer just for sending a password.
316+   */
317+  int (*checkpass)(sasl_conn_t *conn,
318+                   const char *user, unsigned userlen,
319+                   const char *pass, unsigned passlen);
320+
321+  /* Access to base64 encode/decode routines */
322+  int (*decode64)(const char *in, unsigned inlen,
323+                  char *out, unsigned outmax, unsigned *outlen);
324+  int (*encode64)(const char *in, unsigned inlen,
325+                  char *out, unsigned outmax, unsigned *outlen);
326+
327+  /* erase a buffer */
328+  void (*erasebuffer)(char *buf, unsigned len);
329+
330+  /* callback to sasl_getprop() and sasl_setprop() */
331+  int (*getprop)(sasl_conn_t *conn, int propnum, const void **pvalue);
332+  int (*setprop)(sasl_conn_t *conn, int propnum, const void *value);
333+
334+  /* callback function */
335+  sasl_getcallback_t *getcallback;
336+
337+  /* format a message and then pass it to the SASL_CB_LOG callback
338+   *
339+   * use syslog()-style formatting (printf with %m as a human readable text
340+   * (strerror()) for the error specified as the parameter).
341+   * The implementation may use a fixed size buffer not smaller
342+   * than 512 octets if it securely truncates the message.
343+   *
344+   * level is a SASL_LOG_* level (see sasl.h)
345+   */
346+  void (*log)(sasl_conn_t *conn, int level, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
347+
348+  /* callback to sasl_seterror() */
349+  void (*seterror)(sasl_conn_t *conn, unsigned flags, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
350+
351+  /* spare function pointer */
352+  int *(*spare_fptr)(void);
353+
354+  /* auxiliary property utilities */
355+  struct propctx *(*prop_new)(unsigned estimate);
356+  int (*prop_dup)(struct propctx *src_ctx, struct propctx **dst_ctx);
357+  int (*prop_request)(struct propctx *ctx, const char **names);
358+  const struct propval *(*prop_get)(struct propctx *ctx);
359+  int (*prop_getnames)(struct propctx *ctx, const char **names,
360+                       struct propval *vals);
361+  void (*prop_clear)(struct propctx *ctx, int requests);
362+  void (*prop_dispose)(struct propctx **ctx);
363+  int (*prop_format)(struct propctx *ctx, const char *sep, int seplen,
364+                     char *outbuf, unsigned outmax, unsigned *outlen);
365+  int (*prop_set)(struct propctx *ctx, const char *name,
366+                  const char *value, int vallen);
367+  int (*prop_setvals)(struct propctx *ctx, const char *name,
368+                      const char **values);
369+  void (*prop_erase)(struct propctx *ctx, const char *name);
370+  int (*auxprop_store)(sasl_conn_t *conn,
371+  struct propctx *ctx, const char *user);
372+
373+  /* for additions which don't require a version upgrade; set to 0 */
374+  int (*spare_fptr1)(void);
375+  int (*spare_fptr2)(void);
376+} sasl_utils_t;
377+
378+typedef struct sasl_channel_binding {
379+  const char *name;
380+  int critical;
381+  unsigned long len;
382+  const unsigned char *data;
383+} sasl_channel_binding_t;
384+
385+typedef struct sasl_http_request {
386+  const char *method;   /* HTTP Method */
387+  const char *uri;   /* request-URI */
388+  const unsigned char *entity; /* entity-body */
389+  unsigned long elen;   /* entity-body length */
390+  unsigned non_persist;  /* Is it a non-persistent connection? */
391+} sasl_http_request_t;
392+
393+typedef struct sasl_client_params {
394+  const char *service; /* service name */
395+  const char *serverFQDN; /* server fully qualified domain name */
396+  const char *clientFQDN; /* client's fully qualified domain name */
397+  const sasl_utils_t *utils; /* SASL API utility routines --
398+                              * for a particular sasl_conn_t,
399+                              * MUST remain valid until mech_free is
400+                              * called */
401+  const sasl_callback_t *prompt_supp; /* client callback list */
402+  const char *iplocalport; /* server IP domain literal & port */
403+  const char *ipremoteport; /* client IP domain literal & port */
404+
405+  unsigned servicelen; /* length of service */
406+  unsigned slen;  /* length of serverFQDN */
407+  unsigned clen;  /* length of clientFQDN */
408+  unsigned iploclen;  /* length of iplocalport */
409+  unsigned ipremlen;  /* length of ipremoteport */
410+
411+  /* application's security requirements & info */
412+  sasl_security_properties_t props;
413+  sasl_ssf_t external_ssf; /* external SSF active */
414+
415+  /* for additions which don't require a version upgrade; set to 0 */
416+  const void *gss_creds;                  /* GSS credential handle */
417+  const sasl_channel_binding_t *cbinding; /* client channel binding */
418+  const sasl_http_request_t *http_request;/* HTTP Digest request method */
419+  void *spare_ptr4;
420+
421+  /* Canonicalize a user name from on-wire to internal format
422+   *  added rjs3 2001-05-23
423+   *  Must be called once user name aquired if canon_user is non-NULL.
424+   *  conn        connection context
425+   *  in          user name from wire protocol (need not be NUL terminated)
426+   *  len         length of user name from wire protocol (0 = strlen(user))
427+   *  flags       for SASL_CU_* flags
428+   *  oparams     the user, authid, ulen, alen, fields are
429+   *              set appropriately after canonicalization/copying and
430+   *              authorization of arguments
431+   *
432+   *  responsible for setting user, ulen, authid, and alen in the oparams
433+   *  structure
434+   *
435+   *  default behavior is to strip leading and trailing whitespace, as
436+   *  well as allocating space for and copying the parameters.
437+   *
438+   * results:
439+   *  SASL_OK       -- success
440+   *  SASL_NOMEM    -- out of memory
441+   *  SASL_BADPARAM -- invalid conn
442+   *  SASL_BADPROT  -- invalid user/authid
443+   */
444+  int (*canon_user)(sasl_conn_t *conn,
445+                    const char *in, unsigned len,
446+                    unsigned flags,
447+                    sasl_out_params_t *oparams);
448+
449+  int (*spare_fptr1)(void);
450+
451+  unsigned int cbindingdisp;
452+  int spare_int2;
453+  int spare_int3;
454+
455+  /* flags field as passed to sasl_client_new */
456+  unsigned flags;
457+
458+  /* set to 0 initially, this allows a plugin with extended parameters
459+   * to work with an older framework by updating version as parameters
460+   * are added.
461+   */
462+  int param_version;
463+} sasl_client_params_t;
464+
465+typedef struct sasl_interact {
466+  unsigned long id;  /* same as client/user callback ID */
467+  const char *challenge; /* presented to user (e.g. OTP challenge) */
468+  const char *prompt;  /* presented to user (e.g. "Username: ") */
469+  const char *defresult; /* default result string */
470+  const void *result;  /* set to point to result */
471+  unsigned len;  /* set to length of result */
472+} sasl_interact_t;
473+
474+typedef struct sasl_client_plug {
475+  /* mechanism name */
476+  const char *mech_name;
477+
478+  /* best mech additional security layer strength factor */
479+  sasl_ssf_t max_ssf;
480+
481+  /* best security flags, as defined in sasl_security_properties_t */
482+  unsigned security_flags;
483+
484+  /* features of plugin */
485+  unsigned features;
486+
487+  /* required prompt ids, NULL = user/pass only */
488+  const unsigned long *required_prompts;
489+
490+  /* global state for mechanism */
491+  void *glob_context;
492+
493+  /* create context for mechanism, using params supplied
494+   *  glob_context   -- from above
495+   *  params         -- params from sasl_client_new
496+   *  conn_context   -- context for one connection
497+   * returns:
498+   *  SASL_OK        -- success
499+   *  SASL_NOMEM     -- not enough memory
500+   *  SASL_WRONGMECH -- mech doesn't support security params
501+   */
502+  int (*mech_new)(void *glob_context,
503+                  sasl_client_params_t *cparams,
504+                  void **conn_context);
505+
506+  /* perform one step of exchange.  NULL is passed for serverin on
507+   * first step.
508+   * returns:
509+   *  SASL_OK        -- success
510+   *  SASL_INTERACT  -- user interaction needed to fill in prompts
511+   *  SASL_BADPROT   -- server protocol incorrect/cancelled
512+   *  SASL_BADSERV   -- server failed mutual auth
513+   */
514+  int (*mech_step)(void *conn_context,
515+                   sasl_client_params_t *cparams,
516+                   const char *serverin,
517+                   unsigned serverinlen,
518+                   sasl_interact_t **prompt_need,
519+                   const char **clientout,
520+                   unsigned *clientoutlen,
521+                   sasl_out_params_t *oparams);
522+
523+  /* dispose of connection context from mech_new
524+   */
525+    void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
526+
527+  /* free all global space used by mechanism
528+   *  mech_dispose must be called on all mechanisms first
529+   */
530+  void (*mech_free)(void *glob_context, const sasl_utils_t *utils);
531+
532+  /* perform precalculations during a network round-trip
533+   *  or idle period.  conn_context may be NULL
534+   *  returns 1 if action taken, 0 if no action taken
535+   */
536+  int (*idle)(void *glob_context,
537+  void *conn_context,
538+  sasl_client_params_t *cparams);
539+
540+  /* for additions which don't require a version upgrade; set to 0 */
541+  int (*spare_fptr1)(void);
542+  int (*spare_fptr2)(void);
543+} sasl_client_plug_t;
544+
545+typedef int sasl_client_plug_init_t(const sasl_utils_t *utils,
546+                                    int max_version,
547+                                    int *out_version,
548+                                    sasl_client_plug_t **pluglist,
549+                                    int *plugcount);
550+
551+typedef struct client_sasl_mechanism {
552+    int version;
553+    char *plugname;
554+    const sasl_client_plug_t *plug;
555+} client_sasl_mechanism_t;
556+
557+typedef struct cmechanism {
558+  client_sasl_mechanism_t m;
559+  struct cmechanism *next;
560+} cmechanism_t;
561+
562+typedef struct sasl_client_conn {
563+  sasl_conn_t base; /* parts common to server + client */
564+
565+  cmechanism_t *mech;
566+  sasl_client_params_t *cparams;
567+
568+  char *clientFQDN;
569+
570+  cmechanism_t *mech_list; /* list of available mechanisms */
571+  int mech_length;    /* number of available mechanisms */
572+} sasl_client_conn_t;
573+
574+GET_SET_IN_FUNCS(_sasl_locate_entry)
575+GET_SET_IN_FUNCS(dlsym)
576+
577+#define FIX_MACPORTS_CYRUS_SASL_BUG 1
578+
579+void *Hooked_dlsym(void* handle, const char* symbol)
580+{
581+  set_in_dlsym(true);
582+
583+#ifdef FIX_MACPORTS_CYRUS_SASL_BUG
584+  if ((get_in_dlsym_count() == 1) && get_in__sasl_locate_entry()) {
585+    if (symbol && (symbol[0]== '_')) {
586+      ++symbol;
587+    }
588+  }
589+#endif
590+
591+  void *retval = dlsym(handle, symbol);
592+
593+  if ((get_in_dlsym_count() == 1) && get_in__sasl_locate_entry()) {
594+    LogWithFormat(true, "Hook.mm: dlsym(): handle %p, symbol %s, returning %p",
595+                  handle, symbol, retval);
596+  }
597+
598+  set_in_dlsym(false);
599+  return retval;
600+}
601+
602+int (*_sasl_locate_entry_caller)(void *library, const char *entryname,
603+                                 void **entry_point) = NULL;
604+
605+int Hooked__sasl_locate_entry(void *library, const char *entryname,
606+                              void **entry_point)
607+{
608+  set_in__sasl_locate_entry(true);
609+
610+  int retval = _sasl_locate_entry_caller(library, entryname, entry_point);
611+
612+  LogWithFormat(true, "Hook.mm: _sasl_locate_entry(): library %p, entryname %s, entry_point %p, returning %i",
613+                library, entryname ? entryname : "[null]", entry_point ? *entry_point : NULL, retval);
614+
615+  set_in__sasl_locate_entry(false);
616+  return retval;
617+}
618+
619+int (*_sasl_get_plugin_caller)(const char *file,
620+                               const sasl_callback_t *verifyfile_cb,
621+                               void **libraryptr) = NULL;
622+
623+int Hooked__sasl_get_plugin(const char *file,
624+                            const sasl_callback_t *verifyfile_cb,
625+                            void **libraryptr)
626+{
627+  int retval = _sasl_get_plugin_caller(file, verifyfile_cb, libraryptr);
628+
629+  LogWithFormat(true, "Hook.mm: _sasl_get_plugin(): file %s, library %p, returning %i",
630+                file ? file : "[null]", libraryptr ? *libraryptr : NULL, retval);
631+  //PrintStackTrace();
632+
633+  return retval;
634+}
635+
636+int (*sasl_client_add_plugin_caller)(const char *plugname,
637+                                     sasl_client_plug_init_t *entry_point) = NULL;
638+
639+int Hooked_sasl_client_add_plugin(const char *plugname,
640+                                  sasl_client_plug_init_t *entry_point)
641+{
642+  int retval = sasl_client_add_plugin_caller(plugname, entry_point);
643+
644+  LogWithFormat(true, "Hook.mm: sasl_client_add_plugin(): plugname %s, entry_point %p, returning %i",
645+                plugname ? plugname : "[null]", entry_point, retval);
646+  //PrintStackTrace();
647+
648+  return retval;
649+}
650+
651+int (*sasl_client_new_caller)(const char *service,
652+                              const char *serverFQDN,
653+                              const char *iplocalport,
654+                              const char *ipremoteport,
655+                              const sasl_callback_t *prompt_supp,
656+                              unsigned flags,
657+                              sasl_conn_t **pconn) = NULL;
658+
659+int Hooked_sasl_client_new(const char *service,
660+                           const char *serverFQDN,
661+                           const char *iplocalport,
662+                           const char *ipremoteport,
663+                           const sasl_callback_t *prompt_supp,
664+                           unsigned flags,
665+                           sasl_conn_t **pconn)
666+{
667+  int retval = sasl_client_new_caller(service, serverFQDN,
668+                                      iplocalport, ipremoteport,
669+                                      prompt_supp, flags, pconn);
670+
671+  LogWithFormat(true, "Hook.mm: sasl_client_new(1): service %s, serverFQDN %s, iplocalport %s, ipremoteport %s, flags 0x%x, returning %i",
672+                service ? service : "[null]", serverFQDN ? serverFQDN : "[null]",
673+                iplocalport ? iplocalport : "[null]", ipremoteport ? ipremoteport : "[null]",
674+                flags, retval);
675+
676+  sasl_getopt_t *getopt = NULL;
677+  void *context = NULL;
678+  for (const sasl_callback_t *callback = prompt_supp; callback->id != SASL_CB_LIST_END; ++callback) {
679+    LogWithFormat(false, "  prompt_supp id 0x%lx, proc %p, context %p",
680+                  callback->id, callback->proc, callback->context);
681+    if (callback->id == SASL_CB_GETOPT) {
682+      getopt = (sasl_getopt_t *) callback->proc;
683+      context = callback->context;
684+    }
685+  }
686+
687+  const char *client_mech_list = NULL;
688+  if (getopt) {
689+    getopt(context, NULL, "client_mech_list", &client_mech_list, NULL);
690+  }
691+  LogWithFormat(true, "Hook.mm: sasl_client_new(2): client_mech_list %s",
692+                client_mech_list ? client_mech_list : "[null]");
693+
694+  return retval;
695+}
696+
697+int (*sasl_client_start_caller)(sasl_conn_t *conn,
698+                                const char *mechlist,
699+                                sasl_interact_t **prompt_need,
700+                                const char **clientout,
701+                                unsigned *clientoutlen,
702+                                const char **mech) = NULL;
703+
704+int Hooked_sasl_client_start(sasl_conn_t *conn,
705+                             const char *mechlist,
706+                             sasl_interact_t **prompt_need,
707+                             const char **clientout,
708+                             unsigned *clientoutlen,
709+                             const char **mech)
710+{
711+  sasl_client_conn_t *c_conn = (sasl_client_conn_t *) conn;
712+
713+  int retval = sasl_client_start_caller(conn, mechlist, prompt_need,
714+                                        clientout, clientoutlen, mech);
715+
716+  LogWithFormat(true, "Hook.mm: sasl_client_start(1): type %u, flags %x, props (min_ssf %u, max_ssf %u, security_flags 0x%x), external (ssf %u, auth_id %s), mechlist %s, returning 0x%x",
717+                conn ? conn->type : -1, conn ? conn->flags : -1,
718+                conn ? conn->props.min_ssf : -1,
719+                conn ? conn->props.max_ssf : -1,
720+                conn ? conn->props.security_flags : -1,
721+                conn ? conn->external.ssf : -1,
722+                conn ? (conn->external.auth_id ? conn->external.auth_id : "[null]") : "[null]",
723+                mechlist ? mechlist : "[null]",
724+                retval);
725+
726+  cmechanism_t *conn_mechs = NULL;
727+  int conn_mechs_length = 0;
728+  if (c_conn) {
729+    conn_mechs = c_conn->mech_list;
730+    conn_mechs_length = c_conn->mech_length;
731+  }
732+  LogWithFormat(true, "Hook.mm: sasl_client_start(2): conn_mechs %p, conn_mechs_length %i",
733+                conn_mechs, conn_mechs_length);
734+  for (cmechanism_t *m = conn_mechs; m != NULL; m = m->next) {
735+    LogWithFormat(false, "  plugin mech_name %s", m->m.plug->mech_name);
736+  }
737+
738+  return retval;
739+}
740+
741+int (*_sasl_is_equal_mech_caller)(const char *req_mech,
742+                                  const char *plug_mech,
743+                                  size_t req_mech_len,
744+                                  int *plus) = NULL;
745+
746+int Hooked__sasl_is_equal_mech(const char *req_mech,
747+                               const char *plug_mech,
748+                               size_t req_mech_len,
749+                               int *plus)
750+{
751+  int retval = _sasl_is_equal_mech_caller(req_mech, plug_mech, req_mech_len, plus);
752+
753+  LogWithFormat(true, "Hook.mm: _sasl_is_equal_mech(): req_mech %s, plug_mech %s, req_mech_len %lu, plus %i, returning %i",
754+                req_mech ? req_mech : "[null]", plug_mech ? plug_mech : "[null]",
755+                req_mech_len, plus ? *plus : -1, retval);
756+
757+  return retval;
758+}
759+
760 #pragma mark -
761 
762 typedef struct _hook_desc {
763@@ -1232,6 +1976,14 @@ __attribute__((used)) static const hook_desc user_hooks[]
764   INTERPOSE_FUNCTION(NSPushAutoreleasePool),
765   PATCH_FUNCTION(__CFInitialize, /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation),
766   PATCH_FUNCTION(__CFGetConverter, /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation),
767+
768+  INTERPOSE_FUNCTION(dlsym),
769+  PATCH_FUNCTION(_sasl_locate_entry, /opt/local/lib/libsasl2.3.dylib),
770+  PATCH_FUNCTION(_sasl_get_plugin, /opt/local/lib/libsasl2.3.dylib),
771+  PATCH_FUNCTION(sasl_client_add_plugin, /opt/local/lib/libsasl2.3.dylib),
772+  PATCH_FUNCTION(sasl_client_new, /opt/local/lib/libsasl2.3.dylib),
773+  PATCH_FUNCTION(sasl_client_start, /opt/local/lib/libsasl2.3.dylib),
774+  PATCH_FUNCTION(_sasl_is_equal_mech, /opt/local/lib/libsasl2.3.dylib),
775 };
776 
777 // What follows are declarations of the CoreSymbolication APIs that we use to