wb_dsgetdcname.c: move common message to higher log level
[samba.git] / source3 / winbindd / winbindd_pam_auth.c
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 static NTSTATUS fake_password_policy(struct winbindd_response *r,
28                                      uint16_t validation_level,
29                                      union netr_Validation  *validation)
30 {
31         const struct netr_SamBaseInfo *bi = NULL;
32         NTTIME min_password_age;
33         NTTIME max_password_age;
34
35         switch (validation_level) {
36         case 3:
37                 bi = &validation->sam3->base;
38                 break;
39         case 6:
40                 bi = &validation->sam6->base;
41                 break;
42         default:
43                 return NT_STATUS_INTERNAL_ERROR;
44         }
45
46         if (bi->allow_password_change > bi->last_password_change) {
47                 min_password_age = bi->allow_password_change -
48                                    bi->last_password_change;
49         } else {
50                 min_password_age = 0;
51         }
52
53         if (bi->force_password_change > bi->last_password_change) {
54                 max_password_age = bi->force_password_change -
55                                    bi->last_password_change;
56         } else {
57                 max_password_age = 0;
58         }
59
60         r->data.auth.policy.min_length_password = 0;
61         r->data.auth.policy.password_history = 0;
62         r->data.auth.policy.password_properties = 0;
63         r->data.auth.policy.expire =
64                 nt_time_to_unix_abs(&max_password_age);
65         r->data.auth.policy.min_passwordage =
66                 nt_time_to_unix_abs(&min_password_age);
67
68         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 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         char *mapped = NULL;
89         NTSTATUS status;
90         bool ok;
91
92         req = tevent_req_create(mem_ctx, &state,
93                                 struct winbindd_pam_auth_state);
94         if (req == NULL) {
95                 return NULL;
96         }
97
98         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         if (!check_request_flags(request->flags)) {
105                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
106                 return tevent_req_post(req, ev);
107         }
108
109         /* Parse domain and username */
110
111         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         if (NT_STATUS_IS_OK(status)
117             || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
118                 fstrcpy(request->data.auth.user, mapped);
119         }
120
121         ok = canonicalize_username(request->data.auth.user,
122                                    state->name_namespace,
123                                    state->name_domain,
124                                    state->name_user);
125         if (!ok) {
126                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
127                 return tevent_req_post(req, ev);
128         }
129
130         domain = find_auth_domain(request->flags, state->name_namespace);
131         if (domain == NULL) {
132                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
133                 return tevent_req_post(req, ev);
134         }
135
136         state->r = talloc_zero(state, struct wbint_PamAuth);
137         if (tevent_req_nomem(state->r, req)) {
138                 return tevent_req_post(req, ev);
139         }
140
141         state->r->in.client_name = talloc_strdup(
142                         state->r, request->client_name);
143         if (tevent_req_nomem(state->r, req)) {
144                 return tevent_req_post(req, ev);
145         }
146
147         state->r->in.client_pid = request->pid;
148         state->r->in.flags = request->flags;
149
150         state->r->in.info = talloc_zero(state->r, struct wbint_AuthUserInfo);
151         if (tevent_req_nomem(state->r, req)) {
152                 return tevent_req_post(req, ev);
153         }
154
155         state->r->in.info->krb5_cc_type = talloc_strdup(
156                         state->r, request->data.auth.krb5_cc_type);
157         if (tevent_req_nomem(state->r, req)) {
158                 return tevent_req_post(req, ev);
159         }
160
161         state->r->in.info->password = talloc_strdup(
162                         state->r, request->data.auth.pass);
163         if (tevent_req_nomem(state->r, req)) {
164                 return tevent_req_post(req, ev);
165         }
166
167         state->r->in.info->username = talloc_strdup(
168                         state->r, request->data.auth.user);
169         if (tevent_req_nomem(state->r, req)) {
170                 return tevent_req_post(req, ev);
171         }
172
173         state->r->in.info->uid = request->data.auth.uid;
174
175         status = extra_data_to_sid_array(
176                                 request->data.auth.require_membership_of_sid,
177                                 state->r,
178                                 &state->r->in.require_membership_of_sid);
179         if (tevent_req_nterror(req, status)) {
180                 return tevent_req_post(req, ev);
181         }
182
183         subreq = dcerpc_wbint_PamAuth_r_send(state,
184                                              global_event_context(),
185                                              dom_child_handle(domain),
186                                              state->r);
187         if (tevent_req_nomem(subreq, req)) {
188                 return tevent_req_post(req, ev);
189         }
190         tevent_req_set_callback(subreq, winbindd_pam_auth_done, req);
191         return req;
192 }
193
194 static void winbindd_pam_auth_done(struct tevent_req *subreq)
195 {
196         struct tevent_req *req = tevent_req_callback_data(
197                 subreq, struct tevent_req);
198         struct winbindd_pam_auth_state *state = tevent_req_data(
199                 req, struct winbindd_pam_auth_state);
200         NTSTATUS status;
201
202         status = dcerpc_wbint_PamAuth_r_recv(subreq, state);
203         TALLOC_FREE(subreq);
204         if (tevent_req_nterror(req, status)) {
205                 return;
206         }
207
208         if (tevent_req_nterror(req, state->r->out.result)) {
209                 return;
210         }
211
212         tevent_req_done(req);
213 }
214
215 NTSTATUS winbindd_pam_auth_recv(struct tevent_req *req,
216                                 struct winbindd_response *response)
217 {
218         struct winbindd_pam_auth_state *state = tevent_req_data(
219                 req, struct winbindd_pam_auth_state);
220         NTSTATUS status;
221
222         D_NOTICE("Winbind external command PAM_AUTH end.\n");
223         if (tevent_req_is_nterror(req, &status)) {
224                 set_auth_errors(response, status);
225                 return status;
226         }
227
228         response->result = WINBINDD_PENDING;
229
230         status = append_auth_data(response,
231                                   response,
232                                   state->r->in.flags,
233                                   state->r->out.validation->level,
234                                   state->r->out.validation->validation,
235                                   state->name_domain,
236                                   state->name_user);
237         fstrcpy(response->data.auth.krb5ccname,
238                 state->r->out.validation->krb5ccname);
239
240         if (state->r->in.flags & WBFLAG_PAM_INFO3_TEXT) {
241                 bool ok;
242
243                 ok = add_trusted_domain_from_auth(
244                         state->r->out.validation->level,
245                         &response->data.auth.info3,
246                         &response->data.auth.info6);
247                 if (!ok) {
248                         DBG_ERR("add_trusted_domain_from_auth failed\n");
249                         set_auth_errors(response, NT_STATUS_LOGON_FAILURE);
250                         return NT_STATUS_LOGON_FAILURE;
251                 }
252         }
253
254         if (state->r->in.flags & WBFLAG_PAM_CACHED_LOGIN) {
255
256                 /* Store in-memory creds for single-signon using ntlm_auth. */
257
258                 status = winbindd_add_memory_creds(
259                         state->r->in.info->username,
260                         state->r->in.info->uid,
261                         state->r->in.info->password);
262                 D_DEBUG("winbindd_add_memory_creds returned: %s\n",
263                            nt_errstr(status));
264         }
265
266         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                 status = fake_password_policy(response,
275                                 state->r->out.validation->level,
276                                 state->r->out.validation->validation);
277                 if (!NT_STATUS_IS_OK(status)) {
278                         DBG_ERR("Failed to fake password policy: %s\n",
279                                 nt_errstr(status));
280                         set_auth_errors(response, status);
281                         return status;
282                 }
283         }
284
285         return NT_STATUS_OK;
286 }