libwbclient: wbc_create_error_info is always called with mem_ctx==NULL
[ira/wip.git] / nsswitch / libwbclient / wbc_pam.c
index 4cd212a34aefd09e4696bce7c587f3e3c73bafb8..e6a7c095bdf474b44592e4cc2ff4998a30605534 100644 (file)
@@ -5,6 +5,7 @@
 
    Copyright (C) Gerald (Jerry) Carter 2007
    Copyright (C) Guenther Deschner 2008
+   Copyright (C) Volker Lendecke 2009
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -24,6 +25,7 @@
 
 #include "replace.h"
 #include "libwbclient.h"
+#include "../winbind_client.h"
 
 /* Authenticate a username/password pair */
 wbcErr wbcAuthenticateUser(const char *username,
@@ -205,14 +207,13 @@ done:
        return wbc_status;
 }
 
-static wbcErr wbc_create_error_info(TALLOC_CTX *mem_ctx,
-                                 const struct winbindd_response *resp,
-                                 struct wbcAuthErrorInfo **_e)
+static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
+                                   struct wbcAuthErrorInfo **_e)
 {
        wbcErr wbc_status = WBC_ERR_SUCCESS;
        struct wbcAuthErrorInfo *e;
 
-       e = talloc(mem_ctx, struct wbcAuthErrorInfo);
+       e = talloc(NULL, struct wbcAuthErrorInfo);
        BAIL_ON_PTR_ERROR(e, wbc_status);
 
        e->nt_status = resp->data.auth.nt_status;
@@ -467,8 +468,7 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
                                        &response);
        if (response.data.auth.nt_status != 0) {
                if (error) {
-                       wbc_status = wbc_create_error_info(NULL,
-                                                          &response,
+                       wbc_status = wbc_create_error_info(&response,
                                                           error);
                        BAIL_ON_WBC_ERROR(wbc_status);
                }
@@ -486,8 +486,7 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
        }
 
 done:
-       if (response.extra_data.data)
-               free(response.extra_data.data);
+       winbindd_free_response(&response);
 
        talloc_free(request.extra_data.data);
 
@@ -517,8 +516,87 @@ wbcErr wbcCheckTrustCredentials(const char *domain,
                                        &response);
        if (response.data.auth.nt_status != 0) {
                if (error) {
-                       wbc_status = wbc_create_error_info(NULL,
-                                                          &response,
+                       wbc_status = wbc_create_error_info(&response,
+                                                          error);
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               wbc_status = WBC_ERR_AUTH_ERROR;
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+       BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+       return wbc_status;
+}
+
+/* Trigger a change of the trust credentials for a specific domain */
+wbcErr wbcChangeTrustCredentials(const char *domain,
+                                struct wbcAuthErrorInfo **error)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       if (domain) {
+               strncpy(request.domain_name, domain,
+                       sizeof(request.domain_name)-1);
+       }
+
+       /* Send request */
+
+       wbc_status = wbcRequestResponse(WINBINDD_CHANGE_MACHACC,
+                                       &request,
+                                       &response);
+       if (response.data.auth.nt_status != 0) {
+               if (error) {
+                       wbc_status = wbc_create_error_info(&response,
+                                                          error);
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               wbc_status = WBC_ERR_AUTH_ERROR;
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+       BAIL_ON_WBC_ERROR(wbc_status);
+
+ done:
+       return wbc_status;
+}
+
+/*
+ * Trigger a no-op NETLOGON call. Lightweight version of
+ * wbcCheckTrustCredentials
+ */
+wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+
+       if (domain) {
+               /*
+                * the current protocol doesn't support
+                * specifying a domain
+                */
+               wbc_status = WBC_ERR_NOT_IMPLEMENTED;
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       /* Send request */
+
+       wbc_status = wbcRequestResponse(WINBINDD_PING_DC,
+                                       &request,
+                                       &response);
+       if (response.data.auth.nt_status != 0) {
+               if (error) {
+                       wbc_status = wbc_create_error_info(&response,
                                                           error);
                        BAIL_ON_WBC_ERROR(wbc_status);
                }
@@ -604,8 +682,7 @@ wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
        /* Take the response above and return it to the caller */
        if (response.data.auth.nt_status != 0) {
                if (error) {
-                       wbc_status = wbc_create_error_info(NULL,
-                                                          &response,
+                       wbc_status = wbc_create_error_info(&response,
                                                           error);
                        BAIL_ON_WBC_ERROR(wbc_status);
                }
@@ -833,8 +910,7 @@ wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
 
        if (response.data.auth.nt_status != 0) {
                if (error) {
-                       wbc_status = wbc_create_error_info(NULL,
-                                                          &response,
+                       wbc_status = wbc_create_error_info(&response,
                                                           error);
                        BAIL_ON_WBC_ERROR(wbc_status);
                }
@@ -998,8 +1074,7 @@ wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
 
        if (response.data.auth.nt_status != 0) {
                if (error) {
-                       wbc_status = wbc_create_error_info(NULL,
-                                                          &response,
+                       wbc_status = wbc_create_error_info(&response,
                                                           error);
                        BAIL_ON_WBC_ERROR(wbc_status);
                }
@@ -1024,8 +1099,7 @@ wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
        }
 
 done:
-       if (response.extra_data.data)
-               free(response.extra_data.data);
+       winbindd_free_response(&response);
 
        return wbc_status;
 }
@@ -1035,5 +1109,149 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
                           struct wbcCredentialCacheInfo **info,
                           struct wbcAuthErrorInfo **error)
 {
-       return WBC_ERR_NOT_IMPLEMENTED;
+       wbcErr status = WBC_ERR_UNKNOWN_FAILURE;
+       struct wbcCredentialCacheInfo *result = NULL;
+       struct winbindd_request request;
+       struct winbindd_response response;
+       struct wbcNamedBlob *initial_blob = NULL;
+       struct wbcNamedBlob *challenge_blob = NULL;
+       int i;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       if (info != NULL) {
+               *info = NULL;
+       }
+       if (error != NULL) {
+               *error = NULL;
+       }
+       if ((params == NULL)
+           || (params->account_name == NULL)
+           || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) {
+               status = WBC_ERR_INVALID_PARAM;
+               goto fail;
+       }
+
+       if (params->domain_name != NULL) {
+               status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
+               if (!WBC_ERROR_IS_OK(status)) {
+                       goto fail;
+               }
+               snprintf(request.data.ccache_ntlm_auth.user,
+                        sizeof(request.data.ccache_ntlm_auth.user)-1,
+                        "%s%c%s", params->domain_name,
+                        response.data.info.winbind_separator,
+                        params->account_name);
+       } else {
+               strncpy(request.data.ccache_ntlm_auth.user,
+                       params->account_name,
+                       sizeof(request.data.ccache_ntlm_auth.user)-1);
+       }
+       request.data.ccache_ntlm_auth.uid = getuid();
+
+       for (i=0; i<params->num_blobs; i++) {
+               if (strcasecmp(params->blobs[i].name, "initial_blob") == 0) {
+                       initial_blob = &params->blobs[i];
+                       break;
+               }
+               if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) {
+                       challenge_blob = &params->blobs[i];
+                       break;
+               }
+       }
+
+       request.data.ccache_ntlm_auth.initial_blob_len = 0;
+       request.data.ccache_ntlm_auth.challenge_blob_len = 0;
+       request.extra_len = 0;
+
+       if (initial_blob != NULL) {
+               request.data.ccache_ntlm_auth.initial_blob_len =
+                       initial_blob->blob.length;
+               request.extra_len += initial_blob->blob.length;
+       }
+       if (challenge_blob != NULL) {
+               request.data.ccache_ntlm_auth.challenge_blob_len =
+                       challenge_blob->blob.length;
+               request.extra_len += challenge_blob->blob.length;
+       }
+
+       if (request.extra_len != 0) {
+               request.extra_data.data = talloc_array(
+                       NULL, char, request.extra_len);
+               if (request.extra_data.data == NULL) {
+                       status = WBC_ERR_NO_MEMORY;
+                       goto fail;
+               }
+       }
+       if (initial_blob != NULL) {
+               memcpy(request.extra_data.data,
+                      initial_blob->blob.data, initial_blob->blob.length);
+       }
+       if (challenge_blob != NULL) {
+               memcpy(request.extra_data.data
+                      + request.data.ccache_ntlm_auth.initial_blob_len,
+                      challenge_blob->blob.data,
+                      challenge_blob->blob.length);
+       }
+
+       status = wbcRequestResponse(WINBINDD_CCACHE_NTLMAUTH, &request,
+                                   &response);
+       if (!WBC_ERROR_IS_OK(status)) {
+               goto fail;
+       }
+
+       result = talloc(NULL, struct wbcCredentialCacheInfo);
+       if (result == NULL) {
+               status = WBC_ERR_NO_MEMORY;
+               goto fail;
+       }
+       result->num_blobs = 0;
+       result->blobs = talloc(result, struct wbcNamedBlob);
+       if (result->blobs == NULL) {
+               status = WBC_ERR_NO_MEMORY;
+               goto fail;
+       }
+       status = wbcAddNamedBlob(&result->num_blobs, &result->blobs,
+                                "auth_blob", 0,
+                                (uint8_t *)response.extra_data.data,
+                                response.data.ccache_ntlm_auth.auth_blob_len);
+       if (!WBC_ERROR_IS_OK(status)) {
+               goto fail;
+       }
+       status = wbcAddNamedBlob(
+               &result->num_blobs, &result->blobs, "session_key", 0,
+               response.data.ccache_ntlm_auth.session_key,
+               sizeof(response.data.ccache_ntlm_auth.session_key));
+       if (!WBC_ERROR_IS_OK(status)) {
+               goto fail;
+       }
+
+       winbindd_free_response(&response);
+       *info = result;
+       return WBC_ERR_SUCCESS;
+
+fail:
+       TALLOC_FREE(request.extra_data.data);
+       winbindd_free_response(&response);
+       talloc_free(result);
+       return status;
+}
+
+/* Authenticate a user with cached credentials */
+wbcErr wbcCredentialSave(const char *user, const char *password)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       strncpy(request.data.ccache_save.user, user,
+               sizeof(request.data.ccache_save.user)-1);
+       strncpy(request.data.ccache_save.pass, password,
+               sizeof(request.data.ccache_save.pass)-1);
+       request.data.ccache_save.uid = getuid();
+
+       return wbcRequestResponse(WINBINDD_CCACHE_SAVE, &request, &response);
 }