LCOV - code coverage report
Current view: top level - source3/winbindd - winbindd_pam_auth.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 83 134 61.9 %
Date: 2024-06-13 04:01:37 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    async implementation of WINBINDD_PAM_AUTH
       4             :    Copyright (C) Volker Lendecke 2010
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "winbindd.h"
      22             : #include "libcli/security/dom_sid.h"
      23             : #include "lib/util/string_wrappers.h"
      24             : #include "lib/global_contexts.h"
      25             : #include "librpc/gen_ndr/ndr_winbind_c.h"
      26             : 
      27           0 : static NTSTATUS fake_password_policy(struct winbindd_response *r,
      28             :                                      uint16_t validation_level,
      29             :                                      union netr_Validation  *validation)
      30             : {
      31           0 :         const struct netr_SamBaseInfo *bi = NULL;
      32             :         NTTIME min_password_age;
      33             :         NTTIME max_password_age;
      34             : 
      35           0 :         switch (validation_level) {
      36           0 :         case 3:
      37           0 :                 bi = &validation->sam3->base;
      38           0 :                 break;
      39           0 :         case 6:
      40           0 :                 bi = &validation->sam6->base;
      41           0 :                 break;
      42           0 :         default:
      43           0 :                 return NT_STATUS_INTERNAL_ERROR;
      44             :         }
      45             : 
      46           0 :         if (bi->allow_password_change > bi->last_password_change) {
      47           0 :                 min_password_age = bi->allow_password_change -
      48           0 :                                    bi->last_password_change;
      49             :         } else {
      50           0 :                 min_password_age = 0;
      51             :         }
      52             : 
      53           0 :         if (bi->force_password_change > bi->last_password_change) {
      54           0 :                 max_password_age = bi->force_password_change -
      55           0 :                                    bi->last_password_change;
      56             :         } else {
      57           0 :                 max_password_age = 0;
      58             :         }
      59             : 
      60           0 :         r->data.auth.policy.min_length_password = 0;
      61           0 :         r->data.auth.policy.password_history = 0;
      62           0 :         r->data.auth.policy.password_properties = 0;
      63           0 :         r->data.auth.policy.expire =
      64           0 :                 nt_time_to_unix_abs(&max_password_age);
      65           0 :         r->data.auth.policy.min_passwordage =
      66           0 :                 nt_time_to_unix_abs(&min_password_age);
      67             : 
      68           0 :         return NT_STATUS_OK;
      69             : }
      70             : 
      71             : struct winbindd_pam_auth_state {
      72             :         struct wbint_PamAuth *r;
      73             :         fstring name_namespace;
      74             :         fstring name_domain;
      75             :         fstring name_user;
      76             : };
      77             : 
      78             : static void winbindd_pam_auth_done(struct tevent_req *subreq);
      79             : 
      80         395 : struct tevent_req *winbindd_pam_auth_send(TALLOC_CTX *mem_ctx,
      81             :                                           struct tevent_context *ev,
      82             :                                           struct winbindd_cli_state *cli,
      83             :                                           struct winbindd_request *request)
      84             : {
      85             :         struct tevent_req *req, *subreq;
      86             :         struct winbindd_pam_auth_state *state;
      87             :         struct winbindd_domain *domain;
      88         395 :         char *mapped = NULL;
      89             :         NTSTATUS status;
      90             :         bool ok;
      91             : 
      92         395 :         req = tevent_req_create(mem_ctx, &state,
      93             :                                 struct winbindd_pam_auth_state);
      94         395 :         if (req == NULL) {
      95           0 :                 return NULL;
      96             :         }
      97             : 
      98         395 :         D_NOTICE("[%s (%u)] Winbind external command PAM_AUTH start.\n"
      99             :                  "Authenticating user '%s'.\n",
     100             :                  cli->client_name,
     101             :                  (unsigned int)cli->pid,
     102             :                  request->data.auth.user);
     103             : 
     104         395 :         if (!check_request_flags(request->flags)) {
     105           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
     106           0 :                 return tevent_req_post(req, ev);
     107             :         }
     108             : 
     109             :         /* Parse domain and username */
     110             : 
     111         395 :         status = normalize_name_unmap(state, request->data.auth.user, &mapped);
     112             : 
     113             :         /* If the name normalization changed something, copy it over the given
     114             :            name */
     115             : 
     116         395 :         if (NT_STATUS_IS_OK(status)
     117         395 :             || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
     118           0 :                 fstrcpy(request->data.auth.user, mapped);
     119             :         }
     120             : 
     121         395 :         ok = canonicalize_username(request->data.auth.user,
     122         395 :                                    state->name_namespace,
     123         395 :                                    state->name_domain,
     124         395 :                                    state->name_user);
     125         395 :         if (!ok) {
     126           0 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
     127           0 :                 return tevent_req_post(req, ev);
     128             :         }
     129             : 
     130         395 :         domain = find_auth_domain(request->flags, state->name_namespace);
     131         395 :         if (domain == NULL) {
     132           3 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
     133           3 :                 return tevent_req_post(req, ev);
     134             :         }
     135             : 
     136         392 :         state->r = talloc_zero(state, struct wbint_PamAuth);
     137         392 :         if (tevent_req_nomem(state->r, req)) {
     138           0 :                 return tevent_req_post(req, ev);
     139             :         }
     140             : 
     141         556 :         state->r->in.client_name = talloc_strdup(
     142         392 :                         state->r, request->client_name);
     143         392 :         if (tevent_req_nomem(state->r, req)) {
     144           0 :                 return tevent_req_post(req, ev);
     145             :         }
     146             : 
     147         392 :         state->r->in.client_pid = request->pid;
     148         392 :         state->r->in.flags = request->flags;
     149             : 
     150         392 :         state->r->in.info = talloc_zero(state->r, struct wbint_AuthUserInfo);
     151         392 :         if (tevent_req_nomem(state->r, req)) {
     152           0 :                 return tevent_req_post(req, ev);
     153             :         }
     154             : 
     155         556 :         state->r->in.info->krb5_cc_type = talloc_strdup(
     156         392 :                         state->r, request->data.auth.krb5_cc_type);
     157         392 :         if (tevent_req_nomem(state->r, req)) {
     158           0 :                 return tevent_req_post(req, ev);
     159             :         }
     160             : 
     161         556 :         state->r->in.info->password = talloc_strdup(
     162         392 :                         state->r, request->data.auth.pass);
     163         392 :         if (tevent_req_nomem(state->r, req)) {
     164           0 :                 return tevent_req_post(req, ev);
     165             :         }
     166             : 
     167         556 :         state->r->in.info->username = talloc_strdup(
     168         392 :                         state->r, request->data.auth.user);
     169         392 :         if (tevent_req_nomem(state->r, req)) {
     170           0 :                 return tevent_req_post(req, ev);
     171             :         }
     172             : 
     173         392 :         state->r->in.info->uid = request->data.auth.uid;
     174             : 
     175         620 :         status = extra_data_to_sid_array(
     176         392 :                                 request->data.auth.require_membership_of_sid,
     177         392 :                                 state->r,
     178         392 :                                 &state->r->in.require_membership_of_sid);
     179         392 :         if (tevent_req_nterror(req, status)) {
     180           0 :                 return tevent_req_post(req, ev);
     181             :         }
     182             : 
     183         392 :         subreq = dcerpc_wbint_PamAuth_r_send(state,
     184             :                                              global_event_context(),
     185             :                                              dom_child_handle(domain),
     186         392 :                                              state->r);
     187         392 :         if (tevent_req_nomem(subreq, req)) {
     188           0 :                 return tevent_req_post(req, ev);
     189             :         }
     190         392 :         tevent_req_set_callback(subreq, winbindd_pam_auth_done, req);
     191         392 :         return req;
     192             : }
     193             : 
     194         392 : static void winbindd_pam_auth_done(struct tevent_req *subreq)
     195             : {
     196         392 :         struct tevent_req *req = tevent_req_callback_data(
     197             :                 subreq, struct tevent_req);
     198         392 :         struct winbindd_pam_auth_state *state = tevent_req_data(
     199             :                 req, struct winbindd_pam_auth_state);
     200             :         NTSTATUS status;
     201             : 
     202         392 :         status = dcerpc_wbint_PamAuth_r_recv(subreq, state);
     203         392 :         TALLOC_FREE(subreq);
     204         392 :         if (tevent_req_nterror(req, status)) {
     205         114 :                 return;
     206             :         }
     207             : 
     208         392 :         if (tevent_req_nterror(req, state->r->out.result)) {
     209         114 :                 return;
     210             :         }
     211             : 
     212         278 :         tevent_req_done(req);
     213             : }
     214             : 
     215         395 : NTSTATUS winbindd_pam_auth_recv(struct tevent_req *req,
     216             :                                 struct winbindd_response *response)
     217             : {
     218         395 :         struct winbindd_pam_auth_state *state = tevent_req_data(
     219             :                 req, struct winbindd_pam_auth_state);
     220             :         NTSTATUS status;
     221             : 
     222         395 :         D_NOTICE("Winbind external command PAM_AUTH end.\n");
     223         395 :         if (tevent_req_is_nterror(req, &status)) {
     224         117 :                 set_auth_errors(response, status);
     225         117 :                 return status;
     226             :         }
     227             : 
     228         278 :         response->result = WINBINDD_PENDING;
     229             : 
     230         602 :         status = append_auth_data(response,
     231             :                                   response,
     232         278 :                                   state->r->in.flags,
     233         278 :                                   state->r->out.validation->level,
     234         278 :                                   state->r->out.validation->validation,
     235         278 :                                   state->name_domain,
     236         278 :                                   state->name_user);
     237         278 :         fstrcpy(response->data.auth.krb5ccname,
     238             :                 state->r->out.validation->krb5ccname);
     239             : 
     240         278 :         if (state->r->in.flags & WBFLAG_PAM_INFO3_TEXT) {
     241             :                 bool ok;
     242             : 
     243         424 :                 ok = add_trusted_domain_from_auth(
     244         269 :                         state->r->out.validation->level,
     245             :                         &response->data.auth.info3,
     246             :                         &response->data.auth.info6);
     247         269 :                 if (!ok) {
     248           0 :                         DBG_ERR("add_trusted_domain_from_auth failed\n");
     249           0 :                         set_auth_errors(response, NT_STATUS_LOGON_FAILURE);
     250           0 :                         return NT_STATUS_LOGON_FAILURE;
     251             :                 }
     252             :         }
     253             : 
     254         278 :         if (state->r->in.flags & WBFLAG_PAM_CACHED_LOGIN) {
     255             : 
     256             :                 /* Store in-memory creds for single-signon using ntlm_auth. */
     257             : 
     258          96 :                 status = winbindd_add_memory_creds(
     259          44 :                         state->r->in.info->username,
     260          44 :                         state->r->in.info->uid,
     261          44 :                         state->r->in.info->password);
     262          44 :                 D_DEBUG("winbindd_add_memory_creds returned: %s\n",
     263             :                            nt_errstr(status));
     264             :         }
     265             : 
     266         278 :         if (state->r->in.flags & WBFLAG_PAM_GET_PWD_POLICY) {
     267             :                 /*
     268             :                  * WBFLAG_PAM_GET_PWD_POLICY is not used within
     269             :                  * any Samba caller anymore.
     270             :                  *
     271             :                  * We just fake this based on the effective values
     272             :                  * for the user, for legacy callers.
     273             :                  */
     274           0 :                 status = fake_password_policy(response,
     275           0 :                                 state->r->out.validation->level,
     276           0 :                                 state->r->out.validation->validation);
     277           0 :                 if (!NT_STATUS_IS_OK(status)) {
     278           0 :                         DBG_ERR("Failed to fake password policy: %s\n",
     279             :                                 nt_errstr(status));
     280           0 :                         set_auth_errors(response, status);
     281           0 :                         return status;
     282             :                 }
     283             :         }
     284             : 
     285         278 :         return NT_STATUS_OK;
     286             : }

Generated by: LCOV version 1.13