s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.git] / source4 / auth / ntlm / auth_winbind.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind authentication mechanism
5
6    Copyright (C) Tim Potter 2000
7    Copyright (C) Andrew Bartlett 2001 - 2002
8    Copyright (C) Stefan Metzmacher 2005
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include <tevent.h>
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "auth/auth.h"
28 #include "auth/ntlm/auth_proto.h"
29 #include "librpc/gen_ndr/ndr_winbind_c.h"
30 #include "lib/messaging/irpc.h"
31 #include "param/param.h"
32 #include "nsswitch/libwbclient/wbclient.h"
33 #include "auth/auth_sam_reply.h"
34 #include "libcli/security/security.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "auth/auth_sam.h"
37
38 #undef DBGC_CLASS
39 #define DBGC_CLASS DBGC_AUTH
40
41 _PUBLIC_ NTSTATUS auth4_winbind_init(TALLOC_CTX *);
42
43 static NTSTATUS winbind_want_check(struct auth_method_context *ctx,
44                                    TALLOC_CTX *mem_ctx,
45                                    const struct auth_usersupplied_info *user_info)
46 {
47         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
48                 return NT_STATUS_NOT_IMPLEMENTED;
49         }
50
51         /* TODO: maybe limit the user scope to remote users only */
52         return NT_STATUS_OK;
53 }
54
55 struct winbind_check_password_state {
56         struct auth_method_context *ctx;
57         const struct auth_usersupplied_info *user_info;
58         struct winbind_SamLogon req;
59         struct auth_user_info_dc *user_info_dc;
60         bool authoritative;
61 };
62
63 static void winbind_check_password_done(struct tevent_req *subreq);
64
65 /*
66  Authenticate a user with a challenge/response
67  using IRPC to the winbind task
68 */
69 static struct tevent_req *winbind_check_password_send(TALLOC_CTX *mem_ctx,
70                                 struct tevent_context *ev,
71                                 struct auth_method_context *ctx,
72                                 const struct auth_usersupplied_info *user_info)
73 {
74         struct tevent_req *req = NULL;
75         struct winbind_check_password_state *state = NULL;
76         NTSTATUS status;
77         struct dcerpc_binding_handle *irpc_handle;
78         const struct auth_usersupplied_info *user_info_new;
79         struct netr_IdentityInfo *identity_info;
80         struct imessaging_context *msg_ctx;
81         struct tevent_req *subreq = NULL;
82
83         req = tevent_req_create(mem_ctx, &state,
84                                 struct winbind_check_password_state);
85         if (req == NULL) {
86                 return NULL;
87         }
88         state->ctx = ctx;
89         state->user_info = user_info;
90         state->authoritative = true;
91
92         msg_ctx = imessaging_client_init(state, ctx->auth_ctx->lp_ctx, ev);
93         if (msg_ctx == NULL) {
94                 DEBUG(1, ("imessaging_init failed\n"));
95                 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
96                 return tevent_req_post(req, ev);
97         }
98
99         irpc_handle = irpc_binding_handle_by_name(state, msg_ctx,
100                                                   "winbind_server",
101                                                   &ndr_table_winbind);
102         if (irpc_handle == NULL) {
103                 DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, " 
104                           "no winbind_server running!\n",
105                           user_info->client.domain_name, user_info->client.account_name));
106                 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
107                 return tevent_req_post(req, ev);
108         }
109
110         /*
111          * 120 seconds should be enough even for trusted domains.
112          *
113          * Currently winbindd has a much lower limit.
114          * And tests with Windows RODCs show that it
115          * returns NO_LOGON_SERVERS after 90-100 seconds
116          * if it can't reach any RWDC.
117          */
118         dcerpc_binding_handle_set_timeout(irpc_handle, 120);
119
120         if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
121                 struct netr_PasswordInfo *password_info;
122
123                 status = encrypt_user_info(state, ctx->auth_ctx, AUTH_PASSWORD_HASH,
124                                            user_info, &user_info_new);
125                 if (tevent_req_nterror(req, status)) {
126                         return tevent_req_post(req, ev);
127                 }
128                 user_info = user_info_new;
129
130                 password_info = talloc_zero(state, struct netr_PasswordInfo);
131                 if (tevent_req_nomem(password_info, req)) {
132                         return tevent_req_post(req, ev);
133                 }
134
135                 password_info->lmpassword = *user_info->password.hash.lanman;
136                 password_info->ntpassword = *user_info->password.hash.nt;
137
138                 identity_info = &password_info->identity_info;
139                 state->req.in.logon_level       = 1;
140                 state->req.in.logon.password= password_info;
141         } else {
142                 struct netr_NetworkInfo *network_info;
143                 uint8_t chal[8];
144
145                 status = encrypt_user_info(state, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE,
146                                            user_info, &user_info_new);
147                 if (tevent_req_nterror(req, status)) {
148                         return tevent_req_post(req, ev);
149                 }
150                 user_info = user_info_new;
151
152                 network_info = talloc_zero(state, struct netr_NetworkInfo);
153                 if (tevent_req_nomem(network_info, req)) {
154                         return tevent_req_post(req, ev);
155                 }
156
157                 status = auth_get_challenge(ctx->auth_ctx, chal);
158                 if (tevent_req_nterror(req, status)) {
159                         return tevent_req_post(req, ev);
160                 }
161
162                 memcpy(network_info->challenge, chal, sizeof(network_info->challenge));
163
164                 network_info->nt.length = user_info->password.response.nt.length;
165                 network_info->nt.data   = user_info->password.response.nt.data;
166
167                 network_info->lm.length = user_info->password.response.lanman.length;
168                 network_info->lm.data   = user_info->password.response.lanman.data;
169
170                 identity_info = &network_info->identity_info;
171                 state->req.in.logon_level       = 2;
172                 state->req.in.logon.network = network_info;
173         }
174
175         identity_info->domain_name.string       = user_info->client.domain_name;
176         identity_info->parameter_control        = user_info->logon_parameters; /* see MSV1_0_* */
177         identity_info->logon_id                 = user_info->logon_id;
178         identity_info->account_name.string      = user_info->client.account_name;
179         identity_info->workstation.string       = user_info->workstation_name;
180
181         state->req.in.validation_level = 6;
182
183         subreq = dcerpc_winbind_SamLogon_r_send(state, ev, irpc_handle,
184                                                 &state->req);
185         if (tevent_req_nomem(subreq, req)) {
186                 return tevent_req_post(req, ev);
187         }
188         tevent_req_set_callback(subreq,
189                                 winbind_check_password_done,
190                                 req);
191
192         return req;
193 }
194
195 static void winbind_check_password_done(struct tevent_req *subreq)
196 {
197         struct tevent_req *req =
198                 tevent_req_callback_data(subreq,
199                 struct tevent_req);
200         struct winbind_check_password_state *state =
201                 tevent_req_data(req,
202                 struct winbind_check_password_state);
203         struct auth_method_context *ctx = state->ctx;
204         const struct auth_usersupplied_info *user_info = state->user_info;
205         struct ldb_dn *domain_dn = NULL;
206         const char *nt4_domain = NULL;
207         const char *nt4_account = NULL;
208         struct ldb_message *msg = NULL;
209         NTSTATUS status;
210
211         status = dcerpc_winbind_SamLogon_r_recv(subreq, state);
212         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
213                 status = NT_STATUS_NO_LOGON_SERVERS;
214         }
215         TALLOC_FREE(subreq);
216         if (tevent_req_nterror(req, status)) {
217                 return;
218         }
219
220         status = state->req.out.result;
221         if (!NT_STATUS_IS_OK(status)) {
222                 if (!state->req.out.authoritative) {
223                         state->authoritative = false;
224                 }
225                 tevent_req_nterror(req, status);
226                 return;
227         }
228
229         status = make_user_info_dc_netlogon_validation(state,
230                                                       user_info->client.account_name,
231                                                       state->req.in.validation_level,
232                                                       &state->req.out.validation,
233                                                       true, /* This user was authenticated */
234                                                       &state->user_info_dc);
235         if (tevent_req_nterror(req, status)) {
236                 return;
237         }
238
239         nt4_domain = state->user_info_dc->info->domain_name;
240         nt4_account = state->user_info_dc->info->account_name;
241
242         if (lpcfg_is_mydomain(ctx->auth_ctx->lp_ctx, nt4_domain)) {
243                 domain_dn = ldb_get_default_basedn(ctx->auth_ctx->sam_ctx);
244         }
245
246         if (domain_dn != NULL) {
247                 /*
248                  * At best, reset the badPwdCount to 0 if the account exists.
249                  * This means that lockouts happen at a badPwdCount earlier than
250                  * normal, but makes it more fault tolerant.
251                  */
252                 status = authsam_search_account(state, ctx->auth_ctx->sam_ctx,
253                                                 nt4_account, domain_dn, &msg);
254                 if (NT_STATUS_IS_OK(status)) {
255                         status = authsam_logon_success_accounting(
256                                 ctx->auth_ctx->sam_ctx, msg,
257                                 domain_dn,
258                                 user_info->flags & USER_INFO_INTERACTIVE_LOGON,
259                                 NULL, NULL);
260                         if (tevent_req_nterror(req, status)) {
261                                 return;
262                         }
263                 }
264         }
265
266         /*
267          * We need to expand group memberships within our local domain,
268          * as the token might be generated by a trusted domain, unless we're
269          * an RODC.
270          */
271         status = authsam_update_user_info_dc(state->user_info_dc,
272                                              ctx->auth_ctx->sam_ctx,
273                                              state->user_info_dc);
274         if (tevent_req_nterror(req, status)) {
275                 return;
276         }
277
278         tevent_req_done(req);
279 }
280
281 static NTSTATUS winbind_check_password_recv(struct tevent_req *req,
282                                             TALLOC_CTX *mem_ctx,
283                                             struct auth_user_info_dc **user_info_dc,
284                                             const struct authn_audit_info **client_audit_info,
285                                             const struct authn_audit_info **server_audit_info,
286                                             bool *pauthoritative)
287 {
288         struct winbind_check_password_state *state =
289                 tevent_req_data(req,
290                 struct winbind_check_password_state);
291         NTSTATUS status = NT_STATUS_OK;
292
293         *pauthoritative = state->authoritative;
294         *client_audit_info = NULL;
295         *server_audit_info = NULL;
296
297         if (tevent_req_is_nterror(req, &status)) {
298                 tevent_req_received(req);
299                 return status;
300         }
301
302         *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
303
304         tevent_req_received(req);
305         return NT_STATUS_OK;
306 }
307
308 static const struct auth_operations winbind_ops = {
309         .name                   = "winbind",
310         .want_check             = winbind_want_check,
311         .check_password_send    = winbind_check_password_send,
312         .check_password_recv    = winbind_check_password_recv
313 };
314
315 _PUBLIC_ NTSTATUS auth4_winbind_init(TALLOC_CTX *ctx)
316 {
317         NTSTATUS ret;
318
319         ret = auth_register(ctx, &winbind_ops);
320         if (!NT_STATUS_IS_OK(ret)) {
321                 DEBUG(0,("Failed to register 'winbind' auth backend!\n"));
322                 return ret;
323         }
324
325         return NT_STATUS_OK;
326 }