2 Unix SMB/CIFS implementation.
3 async implementation of WINBINDD_PAM_CHAUTHTOK
4 Copyright (C) Volker Lendecke 2010
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.
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.
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/>.
22 #include "lib/util/string_wrappers.h"
23 #include "lib/global_contexts.h"
24 #include "librpc/gen_ndr/ndr_winbind_c.h"
26 static void fill_in_password_policy(struct winbindd_response
*r
,
27 const struct samr_DomInfo1
*p
)
29 r
->data
.auth
.policy
.min_length_password
=
30 p
->min_password_length
;
31 r
->data
.auth
.policy
.password_history
=
32 p
->password_history_length
;
33 r
->data
.auth
.policy
.password_properties
=
34 p
->password_properties
;
35 r
->data
.auth
.policy
.expire
=
36 nt_time_to_unix_abs((const NTTIME
*)&(p
->max_password_age
));
37 r
->data
.auth
.policy
.min_passwordage
=
38 nt_time_to_unix_abs((const NTTIME
*)&(p
->min_password_age
));
41 struct winbindd_pam_chauthtok_state
{
42 struct wbint_PamAuthChangePassword r
;
45 static void winbindd_pam_chauthtok_done(struct tevent_req
*subreq
);
47 struct tevent_req
*winbindd_pam_chauthtok_send(
49 struct tevent_context
*ev
,
50 struct winbindd_cli_state
*cli
,
51 struct winbindd_request
*request
)
53 struct tevent_req
*req
, *subreq
;
54 struct winbindd_pam_chauthtok_state
*state
;
55 struct winbindd_domain
*contact_domain
;
56 fstring
namespace, domain
, user
;
61 req
= tevent_req_create(mem_ctx
, &state
,
62 struct winbindd_pam_chauthtok_state
);
67 /* Ensure null termination */
68 request
->data
.chauthtok
.user
[
69 sizeof(request
->data
.chauthtok
.user
)-1]='\0';
71 DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)cli
->pid
,
72 request
->data
.chauthtok
.user
));
74 status
= normalize_name_unmap(state
, request
->data
.chauthtok
.user
,
77 if (NT_STATUS_IS_OK(status
) ||
78 NT_STATUS_EQUAL(status
, NT_STATUS_FILE_RENAMED
)) {
79 fstrcpy(request
->data
.chauthtok
.user
, mapped_user
);
82 ok
= canonicalize_username(request
->data
.chauthtok
.user
,
87 DEBUG(10, ("winbindd_pam_chauthtok: canonicalize_username %s "
88 "failed with\n", request
->data
.chauthtok
.user
));
89 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
90 return tevent_req_post(req
, ev
);
93 contact_domain
= find_domain_from_name(namespace);
94 if (contact_domain
== NULL
) {
95 DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] "
96 "as %s is not a trusted domain\n",
97 request
->data
.chauthtok
.user
, domain
, user
, domain
));
98 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
99 return tevent_req_post(req
, ev
);
102 state
->r
.in
.client_pid
= request
->pid
;
103 state
->r
.in
.flags
= request
->flags
;
105 state
->r
.in
.client_name
= talloc_strdup(state
, request
->client_name
);
106 if (tevent_req_nomem(state
->r
.in
.client_name
, req
)) {
107 return tevent_req_post(req
, ev
);
110 state
->r
.in
.user
= talloc_strdup(state
, request
->data
.chauthtok
.user
);
111 if (tevent_req_nomem(state
->r
.in
.user
, req
)) {
112 return tevent_req_post(req
, ev
);
115 state
->r
.in
.old_password
= talloc_strdup(state
,
116 request
->data
.chauthtok
.oldpass
);
117 if (tevent_req_nomem(state
->r
.in
.old_password
, req
)) {
118 return tevent_req_post(req
, ev
);
121 state
->r
.in
.new_password
= talloc_strdup(state
,
122 request
->data
.chauthtok
.newpass
);
123 if (tevent_req_nomem(state
->r
.in
.new_password
, req
)) {
124 return tevent_req_post(req
, ev
);
127 subreq
= dcerpc_wbint_PamAuthChangePassword_r_send(state
,
128 global_event_context(),
129 dom_child_handle(contact_domain
),
131 if (tevent_req_nomem(subreq
, req
)) {
132 return tevent_req_post(req
, ev
);
134 tevent_req_set_callback(subreq
, winbindd_pam_chauthtok_done
, req
);
138 static void winbindd_pam_chauthtok_done(struct tevent_req
*subreq
)
140 struct tevent_req
*req
= tevent_req_callback_data(
141 subreq
, struct tevent_req
);
142 struct winbindd_pam_chauthtok_state
*state
= tevent_req_data(
143 req
, struct winbindd_pam_chauthtok_state
);
146 status
= dcerpc_wbint_PamAuthChangePassword_r_recv(subreq
, state
);
148 if (tevent_req_nterror(req
, status
)) {
152 tevent_req_done(req
);
155 NTSTATUS
winbindd_pam_chauthtok_recv(struct tevent_req
*req
,
156 struct winbindd_response
*response
)
158 struct winbindd_pam_chauthtok_state
*state
= tevent_req_data(
159 req
, struct winbindd_pam_chauthtok_state
);
160 NTSTATUS status
= NT_STATUS_OK
;
162 if (tevent_req_is_nterror(req
, &status
)) {
163 set_auth_errors(response
, status
);
167 response
->result
= WINBINDD_PENDING
;
169 set_auth_errors(response
, state
->r
.out
.result
);
170 if (*state
->r
.out
.dominfo
!= NULL
) {
171 fill_in_password_policy(response
, *state
->r
.out
.dominfo
);
173 response
->data
.auth
.reject_reason
= *state
->r
.out
.reject_reason
;
175 if (state
->r
.in
.flags
& WBFLAG_PAM_CACHED_LOGIN
) {
177 /* Update the single sign-on memory creds. */
178 status
= winbindd_replace_memory_creds(
179 state
->r
.in
.user
, state
->r
.in
.new_password
);
181 DEBUG(10, ("winbindd_replace_memory_creds returned %s\n",
185 * When we login from gdm or xdm and password expires,
186 * we change password, but there are no memory
187 * crendentials So, winbindd_replace_memory_creds()
188 * returns NT_STATUS_OBJECT_NAME_NOT_FOUND. This is
189 * not a failure. --- BoYang
191 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
192 status
= NT_STATUS_OK
;
196 return NT_STATUS(response
->data
.auth
.nt_status
);