LCOV - code coverage report
Current view: top level - source3/winbindd - winbindd_pam_auth.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 84 147 57.1 %
Date: 2024-02-28 12:06:22 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           0 :         NTTIME min_password_age;
      33           0 :         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             :         char *name_namespace;
      74             :         char *name_domain;
      75             :         char *name_user;
      76             : };
      77             : 
      78             : static void winbindd_pam_auth_done(struct tevent_req *subreq);
      79             : 
      80         391 : 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           0 :         struct tevent_req *req, *subreq;
      86           0 :         struct winbindd_pam_auth_state *state;
      87           0 :         struct winbindd_domain *domain;
      88         391 :         char *mapped = NULL;
      89         391 :         char *auth_user = NULL;
      90           0 :         NTSTATUS status;
      91           0 :         bool ok;
      92             : 
      93         391 :         req = tevent_req_create(mem_ctx, &state,
      94             :                                 struct winbindd_pam_auth_state);
      95         391 :         if (req == NULL) {
      96           0 :                 return NULL;
      97             :         }
      98             : 
      99         391 :         D_NOTICE("[%s (%u)] Winbind external command PAM_AUTH start.\n"
     100             :                  "Authenticating user '%s'.\n",
     101             :                  cli->client_name,
     102             :                  (unsigned int)cli->pid,
     103             :                  request->data.auth.user);
     104             : 
     105         391 :         if (!check_request_flags(request->flags)) {
     106           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
     107           0 :                 return tevent_req_post(req, ev);
     108             :         }
     109             : 
     110             :         /* Parse domain and username */
     111             : 
     112         391 :         status = normalize_name_unmap(state, request->data.auth.user, &mapped);
     113             : 
     114             :         /* If the name normalization changed something, copy it over the given
     115             :            name */
     116             : 
     117         391 :         if (NT_STATUS_IS_OK(status)
     118         391 :             || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
     119           0 :                 fstrcpy(request->data.auth.user, mapped);
     120             :         }
     121             : 
     122         391 :         auth_user = request->data.auth.user;
     123         391 :         ok = canonicalize_username(state,
     124             :                                    &auth_user,
     125         391 :                                    &state->name_namespace,
     126         391 :                                    &state->name_domain,
     127         391 :                                    &state->name_user);
     128         391 :         if (!ok) {
     129           0 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
     130           0 :                 return tevent_req_post(req, ev);
     131             :         }
     132             : 
     133         391 :         fstrcpy(request->data.auth.user, auth_user);
     134             : 
     135         391 :         domain = find_auth_domain(request->flags, state->name_namespace);
     136         391 :         if (domain == NULL) {
     137           0 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
     138           0 :                 return tevent_req_post(req, ev);
     139             :         }
     140             : 
     141         391 :         state->r = talloc_zero(state, struct wbint_PamAuth);
     142         391 :         if (tevent_req_nomem(state->r, req)) {
     143           0 :                 return tevent_req_post(req, ev);
     144             :         }
     145             : 
     146         782 :         state->r->in.client_name = talloc_strdup(
     147         391 :                         state->r, request->client_name);
     148         391 :         if (tevent_req_nomem(state->r, req)) {
     149           0 :                 return tevent_req_post(req, ev);
     150             :         }
     151             : 
     152         391 :         state->r->in.client_pid = request->pid;
     153         391 :         state->r->in.flags = request->flags;
     154             : 
     155         391 :         state->r->in.info = talloc_zero(state->r, struct wbint_AuthUserInfo);
     156         391 :         if (tevent_req_nomem(state->r, req)) {
     157           0 :                 return tevent_req_post(req, ev);
     158             :         }
     159             : 
     160         782 :         state->r->in.info->krb5_cc_type = talloc_strdup(
     161         391 :                         state->r, request->data.auth.krb5_cc_type);
     162         391 :         if (tevent_req_nomem(state->r, req)) {
     163           0 :                 return tevent_req_post(req, ev);
     164             :         }
     165             : 
     166         782 :         state->r->in.info->password = talloc_strdup(
     167         391 :                         state->r, request->data.auth.pass);
     168         391 :         if (tevent_req_nomem(state->r, req)) {
     169           0 :                 return tevent_req_post(req, ev);
     170             :         }
     171             : 
     172         782 :         state->r->in.info->username = talloc_strdup(
     173         391 :                         state->r, request->data.auth.user);
     174         391 :         if (tevent_req_nomem(state->r, req)) {
     175           0 :                 return tevent_req_post(req, ev);
     176             :         }
     177             : 
     178         391 :         state->r->in.info->uid = request->data.auth.uid;
     179             : 
     180         391 :         status = extra_data_to_sid_array(
     181         391 :                                 request->data.auth.require_membership_of_sid,
     182         391 :                                 state->r,
     183         391 :                                 &state->r->in.require_membership_of_sid);
     184         391 :         if (tevent_req_nterror(req, status)) {
     185           0 :                 return tevent_req_post(req, ev);
     186             :         }
     187             : 
     188         391 :         subreq = dcerpc_wbint_PamAuth_r_send(state,
     189             :                                              global_event_context(),
     190             :                                              dom_child_handle(domain),
     191         391 :                                              state->r);
     192         391 :         if (tevent_req_nomem(subreq, req)) {
     193           0 :                 return tevent_req_post(req, ev);
     194             :         }
     195         391 :         tevent_req_set_callback(subreq, winbindd_pam_auth_done, req);
     196         391 :         return req;
     197             : }
     198             : 
     199         391 : static void winbindd_pam_auth_done(struct tevent_req *subreq)
     200             : {
     201         391 :         struct tevent_req *req = tevent_req_callback_data(
     202             :                 subreq, struct tevent_req);
     203         391 :         struct winbindd_pam_auth_state *state = tevent_req_data(
     204             :                 req, struct winbindd_pam_auth_state);
     205           0 :         NTSTATUS status;
     206             : 
     207         391 :         status = dcerpc_wbint_PamAuth_r_recv(subreq, state);
     208         391 :         TALLOC_FREE(subreq);
     209         391 :         if (tevent_req_nterror(req, status)) {
     210         120 :                 return;
     211             :         }
     212             : 
     213         391 :         if (tevent_req_nterror(req, state->r->out.result)) {
     214         120 :                 return;
     215             :         }
     216             : 
     217         271 :         tevent_req_done(req);
     218             : }
     219             : 
     220         391 : NTSTATUS winbindd_pam_auth_recv(struct tevent_req *req,
     221             :                                 struct winbindd_response *response)
     222             : {
     223         391 :         struct winbindd_pam_auth_state *state = tevent_req_data(
     224             :                 req, struct winbindd_pam_auth_state);
     225           0 :         NTSTATUS status;
     226             : 
     227         391 :         D_NOTICE("Winbind external command PAM_AUTH end.\n");
     228         391 :         if (tevent_req_is_nterror(req, &status)) {
     229         120 :                 set_auth_errors(response, status);
     230         120 :                 return status;
     231             :         }
     232             : 
     233         271 :         response->result = WINBINDD_PENDING;
     234             : 
     235         271 :         status = append_auth_data(response,
     236             :                                   response,
     237         271 :                                   state->r->in.flags,
     238         271 :                                   state->r->out.validation->level,
     239         271 :                                   state->r->out.validation->validation,
     240         271 :                                   state->name_domain,
     241         271 :                                   state->name_user);
     242         271 :         fstrcpy(response->data.auth.krb5ccname,
     243             :                 state->r->out.validation->krb5ccname);
     244             : 
     245         271 :         if (state->r->in.flags & WBFLAG_PAM_INFO3_TEXT) {
     246           0 :                 bool ok;
     247             : 
     248         258 :                 ok = add_trusted_domain_from_auth(
     249         258 :                         state->r->out.validation->level,
     250             :                         &response->data.auth.info3,
     251             :                         &response->data.auth.info6);
     252         258 :                 if (!ok) {
     253           0 :                         DBG_ERR("add_trusted_domain_from_auth failed\n");
     254           0 :                         set_auth_errors(response, NT_STATUS_LOGON_FAILURE);
     255           0 :                         return NT_STATUS_LOGON_FAILURE;
     256             :                 }
     257             :         }
     258             : 
     259         271 :         if (state->r->in.flags & WBFLAG_PAM_CACHED_LOGIN) {
     260             : 
     261             :                 /* Store in-memory creds for single-signon using ntlm_auth. */
     262             : 
     263          36 :                 status = winbindd_add_memory_creds(
     264          36 :                         state->r->in.info->username,
     265          36 :                         state->r->in.info->uid,
     266          36 :                         state->r->in.info->password);
     267          36 :                 D_DEBUG("winbindd_add_memory_creds returned: %s\n",
     268             :                            nt_errstr(status));
     269             :         }
     270             : 
     271         271 :         if (state->r->in.flags & WBFLAG_PAM_GET_PWD_POLICY) {
     272             :                 /*
     273             :                  * WBFLAG_PAM_GET_PWD_POLICY is not used within
     274             :                  * any Samba caller anymore.
     275             :                  *
     276             :                  * We just fake this based on the effective values
     277             :                  * for the user, for legacy callers.
     278             :                  */
     279           0 :                 status = fake_password_policy(response,
     280           0 :                                 state->r->out.validation->level,
     281           0 :                                 state->r->out.validation->validation);
     282           0 :                 if (!NT_STATUS_IS_OK(status)) {
     283           0 :                         DBG_ERR("Failed to fake password policy: %s\n",
     284             :                                 nt_errstr(status));
     285           0 :                         set_auth_errors(response, status);
     286           0 :                         return status;
     287             :                 }
     288             :         }
     289             : 
     290         271 :         return NT_STATUS_OK;
     291             : }

Generated by: LCOV version 1.14