winbindd: winbindd_ccache_ntlm_auth() -> bool_dispatch_table
[samba.git] / nsswitch / libwbclient / wbclient.c
index f5c72315f2e117ea87bb46c1d5de48a3dae03935..5444e823ddfdbfc3b97a3e79811e1fc704aaed10 100644 (file)
@@ -4,6 +4,7 @@
    Winbind client API
 
    Copyright (C) Gerald (Jerry) Carter 2007
+   Copyright (C) Matthew Newton 2015
 
 
    This library is free software; you can redistribute it and/or
 
 /* Required Headers */
 
+#include "replace.h"
 #include "libwbclient.h"
 
 /* From wb_common.c */
 
-NSS_STATUS winbindd_request_response(int req_type,
+struct winbindd_context;
+
+NSS_STATUS winbindd_request_response(struct winbindd_context *wbctx,
+                                    int req_type,
                                     struct winbindd_request *request,
                                     struct winbindd_response *response);
+NSS_STATUS winbindd_priv_request_response(struct winbindd_context *wbctx,
+                                         int req_type,
+                                         struct winbindd_request *request,
+                                         struct winbindd_response *response);
+struct winbindd_context *winbindd_ctx_create(void);
+void winbindd_ctx_free(struct winbindd_context *ctx);
 
-/** @brief Wrapper around Winbind's send/receive API call
- *
- * @param cmd       Winbind command operation to perform
- * @param request   Send structure
- * @param response  Receive structure
- *
- * @return #wbcErr
- **/
+/* Global context used for non-Ctx functions */
+
+static struct wbcContext wbcGlobalCtx = {
+       .winbindd_ctx = NULL,
+       .pw_cache_size = 0,
+       .pw_cache_idx = 0,
+       .gr_cache_size = 0,
+       .gr_cache_idx = 0
+};
 
-/**********************************************************************
+/*
  result == NSS_STATUS_UNAVAIL: winbind not around
  result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
 
@@ -50,18 +62,23 @@ NSS_STATUS winbindd_request_response(int req_type,
  (as far as I have seen) with the callers of is_trusted_domains.
 
  --Volker
-**********************************************************************/
+*/
 
-wbcErr wbcRequestResponse(int cmd,
-                         struct winbindd_request *request,
-                         struct winbindd_response *response)
+static wbcErr wbcRequestResponseInt(
+       struct winbindd_context *wbctx,
+       int cmd,
+       struct winbindd_request *request,
+       struct winbindd_response *response,
+       NSS_STATUS (*fn)(struct winbindd_context *wbctx, int req_type,
+                        struct winbindd_request *request,
+                        struct winbindd_response *response))
 {
        wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
        NSS_STATUS nss_status;
 
        /* for some calls the request and/or response can be NULL */
 
-       nss_status = winbindd_request_response(cmd, request, response);
+       nss_status = fn(wbctx, cmd, request, response);
 
        switch (nss_status) {
        case NSS_STATUS_SUCCESS:
@@ -81,6 +98,44 @@ wbcErr wbcRequestResponse(int cmd,
        return wbc_status;
 }
 
+/**
+ * @brief Wrapper around Winbind's send/receive API call
+ *
+ * @param ctx       Context
+ * @param cmd       Winbind command operation to perform
+ * @param request   Send structure
+ * @param response  Receive structure
+ *
+ * @return #wbcErr
+ */
+wbcErr wbcRequestResponse(struct wbcContext *ctx, int cmd,
+                         struct winbindd_request *request,
+                         struct winbindd_response *response)
+{
+       struct winbindd_context *wbctx = NULL;
+
+       if (ctx) {
+               wbctx = ctx->winbindd_ctx;
+       }
+
+       return wbcRequestResponseInt(wbctx, cmd, request, response,
+                                    winbindd_request_response);
+}
+
+wbcErr wbcRequestResponsePriv(struct wbcContext *ctx, int cmd,
+                             struct winbindd_request *request,
+                             struct winbindd_response *response)
+{
+       struct winbindd_context *wbctx = NULL;
+
+       if (ctx) {
+               wbctx = ctx->winbindd_ctx;
+       }
+
+       return wbcRequestResponseInt(wbctx, cmd, request, response,
+                                    winbindd_priv_request_response);
+}
+
 /** @brief Translate an error value into a string
  *
  * @param error
@@ -123,35 +178,156 @@ const char *wbcErrorString(wbcErr error)
        return "unknown wbcErr value";
 }
 
+#define WBC_MAGIC (0x7a2b0e1e)
+#define WBC_MAGIC_FREE (0x875634fe)
+
+struct wbcMemPrefix {
+       uint32_t magic;
+       void (*destructor)(void *ptr);
+};
+
+static size_t wbcPrefixLen(void)
+{
+       size_t result = sizeof(struct wbcMemPrefix);
+       return (result + 15) & ~15;
+}
+
+static struct wbcMemPrefix *wbcMemToPrefix(void *ptr)
+{
+       return (struct wbcMemPrefix *)(((char *)ptr) - wbcPrefixLen());
+}
+
+void *wbcAllocateMemory(size_t nelem, size_t elsize,
+                       void (*destructor)(void *ptr))
+{
+       struct wbcMemPrefix *result;
+
+       if (nelem >= (2<<24)/elsize) {
+               /* basic protection against integer wrap */
+               return NULL;
+       }
+
+       result = (struct wbcMemPrefix *)calloc(
+               1, nelem*elsize + wbcPrefixLen());
+       if (result == NULL) {
+               return NULL;
+       }
+       result->magic = WBC_MAGIC;
+       result->destructor = destructor;
+       return ((char *)result) + wbcPrefixLen();
+}
+
 /* Free library allocated memory */
 void wbcFreeMemory(void *p)
 {
-       if (p)
-               talloc_free(p);
+       struct wbcMemPrefix *wbcMem;
+
+       if (p == NULL) {
+               return;
+       }
+       wbcMem = wbcMemToPrefix(p);
+       if (wbcMem->magic != WBC_MAGIC) {
+               return;
+       }
 
+       /* paranoid check to ensure we don't double free */
+       wbcMem->magic = WBC_MAGIC_FREE;
+
+       if (wbcMem->destructor != NULL) {
+               wbcMem->destructor(p);
+       }
+       free(wbcMem);
        return;
 }
 
+char *wbcStrDup(const char *str)
+{
+       char *result;
+       size_t len;
+
+       len = strlen(str);
+       result = (char *)wbcAllocateMemory(len+1, sizeof(char), NULL);
+       if (result == NULL) {
+               return NULL;
+       }
+       memcpy(result, str, len+1);
+       return result;
+}
+
+static void wbcStringArrayDestructor(void *ptr)
+{
+       char **p = (char **)ptr;
+       while (*p != NULL) {
+               free(*p);
+               p += 1;
+       }
+}
+
+const char **wbcAllocateStringArray(int num_strings)
+{
+       return (const char **)wbcAllocateMemory(
+               num_strings + 1, sizeof(const char *),
+               wbcStringArrayDestructor);
+}
+
 wbcErr wbcLibraryDetails(struct wbcLibraryDetails **_details)
 {
-       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
        struct wbcLibraryDetails *info;
 
-       info = talloc(NULL, struct wbcLibraryDetails);
-       BAIL_ON_PTR_ERROR(info, wbc_status);
+       info = (struct wbcLibraryDetails *)wbcAllocateMemory(
+               1, sizeof(struct wbcLibraryDetails), NULL);
+
+       if (info == NULL) {
+               return WBC_ERR_NO_MEMORY;
+       }
 
        info->major_version = WBCLIENT_MAJOR_VERSION;
        info->minor_version = WBCLIENT_MINOR_VERSION;
-       info->vendor_version = talloc_strdup(info,
-                                            WBCLIENT_VENDOR_VERSION);
-       BAIL_ON_PTR_ERROR(info->vendor_version, wbc_status);
+       info->vendor_version = WBCLIENT_VENDOR_VERSION;
 
        *_details = info;
-       info = NULL;
+       return WBC_ERR_SUCCESS;
+}
 
-       wbc_status = WBC_ERR_SUCCESS;
+/* Context handling functions */
 
-done:
-       talloc_free(info);
-       return wbc_status;
+static void wbcContextDestructor(void *ptr)
+{
+       struct wbcContext *ctx = (struct wbcContext *)ptr;
+
+       winbindd_ctx_free(ctx->winbindd_ctx);
+}
+
+struct wbcContext *wbcCtxCreate(void)
+{
+       struct wbcContext *ctx;
+       struct winbindd_context *wbctx;
+
+       ctx = (struct wbcContext *)wbcAllocateMemory(
+               1, sizeof(struct wbcContext), wbcContextDestructor);
+
+       if (!ctx) {
+               return NULL;
+       }
+
+       wbctx = winbindd_ctx_create();
+
+       if (!wbctx) {
+               wbcFreeMemory(ctx);
+               return NULL;
+       }
+
+       ctx->winbindd_ctx = wbctx;
+
+       return ctx;
+}
+
+void wbcCtxFree(struct wbcContext *ctx)
+{
+       wbcFreeMemory(ctx);
+}
+
+struct wbcContext *wbcGetGlobalCtx(void)
+{
+       return &wbcGlobalCtx;
 }