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 char *namespace = NULL
;
59 char *chauthtok_user
= NULL
;
64 req
= tevent_req_create(mem_ctx
, &state
,
65 struct winbindd_pam_chauthtok_state
);
70 /* Ensure null termination */
71 request
->data
.chauthtok
.user
[
72 sizeof(request
->data
.chauthtok
.user
)-1]='\0';
74 DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)cli
->pid
,
75 request
->data
.chauthtok
.user
));
77 status
= normalize_name_unmap(state
, request
->data
.chauthtok
.user
,
80 if (NT_STATUS_IS_OK(status
) ||
81 NT_STATUS_EQUAL(status
, NT_STATUS_FILE_RENAMED
)) {
82 fstrcpy(request
->data
.chauthtok
.user
, mapped_user
);
85 chauthtok_user
= request
->data
.chauthtok
.user
;
86 ok
= canonicalize_username(req
,
92 DEBUG(10, ("winbindd_pam_chauthtok: canonicalize_username %s "
93 "failed with\n", request
->data
.chauthtok
.user
));
94 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
95 return tevent_req_post(req
, ev
);
98 fstrcpy(request
->data
.chauthtok
.user
, chauthtok_user
);
100 contact_domain
= find_domain_from_name(namespace);
101 if (contact_domain
== NULL
) {
102 DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] "
103 "as %s is not a trusted domain\n",
104 request
->data
.chauthtok
.user
, domain
, user
, domain
));
105 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
106 return tevent_req_post(req
, ev
);
109 state
->r
.in
.client_pid
= request
->pid
;
110 state
->r
.in
.flags
= request
->flags
;
112 state
->r
.in
.client_name
= talloc_strdup(state
, request
->client_name
);
113 if (tevent_req_nomem(state
->r
.in
.client_name
, req
)) {
114 return tevent_req_post(req
, ev
);
117 state
->r
.in
.user
= talloc_strdup(state
, request
->data
.chauthtok
.user
);
118 if (tevent_req_nomem(state
->r
.in
.user
, req
)) {
119 return tevent_req_post(req
, ev
);
122 state
->r
.in
.old_password
= talloc_strdup(state
,
123 request
->data
.chauthtok
.oldpass
);
124 if (tevent_req_nomem(state
->r
.in
.old_password
, req
)) {
125 return tevent_req_post(req
, ev
);
128 state
->r
.in
.new_password
= talloc_strdup(state
,
129 request
->data
.chauthtok
.newpass
);
130 if (tevent_req_nomem(state
->r
.in
.new_password
, req
)) {
131 return tevent_req_post(req
, ev
);
134 subreq
= dcerpc_wbint_PamAuthChangePassword_r_send(state
,
135 global_event_context(),
136 dom_child_handle(contact_domain
),
138 if (tevent_req_nomem(subreq
, req
)) {
139 return tevent_req_post(req
, ev
);
141 tevent_req_set_callback(subreq
, winbindd_pam_chauthtok_done
, req
);
145 static void winbindd_pam_chauthtok_done(struct tevent_req
*subreq
)
147 struct tevent_req
*req
= tevent_req_callback_data(
148 subreq
, struct tevent_req
);
149 struct winbindd_pam_chauthtok_state
*state
= tevent_req_data(
150 req
, struct winbindd_pam_chauthtok_state
);
153 status
= dcerpc_wbint_PamAuthChangePassword_r_recv(subreq
, state
);
155 if (tevent_req_nterror(req
, status
)) {
159 tevent_req_done(req
);
162 NTSTATUS
winbindd_pam_chauthtok_recv(struct tevent_req
*req
,
163 struct winbindd_response
*response
)
165 struct winbindd_pam_chauthtok_state
*state
= tevent_req_data(
166 req
, struct winbindd_pam_chauthtok_state
);
167 NTSTATUS status
= NT_STATUS_OK
;
169 if (tevent_req_is_nterror(req
, &status
)) {
170 set_auth_errors(response
, status
);
174 response
->result
= WINBINDD_PENDING
;
176 set_auth_errors(response
, state
->r
.out
.result
);
177 if (*state
->r
.out
.dominfo
!= NULL
) {
178 fill_in_password_policy(response
, *state
->r
.out
.dominfo
);
180 response
->data
.auth
.reject_reason
= *state
->r
.out
.reject_reason
;
182 if (state
->r
.in
.flags
& WBFLAG_PAM_CACHED_LOGIN
) {
184 /* Update the single sign-on memory creds. */
185 status
= winbindd_replace_memory_creds(
186 state
->r
.in
.user
, state
->r
.in
.new_password
);
188 DEBUG(10, ("winbindd_replace_memory_creds returned %s\n",
192 * When we login from gdm or xdm and password expires,
193 * we change password, but there are no memory
194 * credentials. So, winbindd_replace_memory_creds()
195 * returns NT_STATUS_OBJECT_NAME_NOT_FOUND. This is
196 * not a failure. --- BoYang
198 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
199 status
= NT_STATUS_OK
;
203 return NT_STATUS(response
->data
.auth
.nt_status
);