r8110: More PAC work. I still can't get WinXP to accept the PAC, but we are
[ira/wip.git] / source4 / auth / auth_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Authentication utility functions
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Andrew Bartlett 2001
6    Copyright (C) Jeremy Allison 2000-2001
7    Copyright (C) Rafal Szczesniak 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 2 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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "librpc/gen_ndr/ndr_netlogon.h"
28 #include "libcli/security/security.h"
29 #include "auth/auth.h"
30
31 /* this default function can be used by mostly all backends
32  * which don't want to set a challlenge
33  */
34 NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge)
35 {
36         /* we don't want to set a challenge */
37         return NT_STATUS_NOT_IMPLEMENTED;
38 }
39
40 /****************************************************************************
41  Create an auth_usersupplied_data structure
42 ****************************************************************************/
43 NTSTATUS make_user_info(TALLOC_CTX *mem_ctx,
44                                const char *c_account_name,
45                                const char *account_name,
46                                const char *c_domain_name, 
47                                const char *domain_name,
48                                const char *workstation_name, 
49                                const char *remote_host, 
50                                DATA_BLOB *lm_password, DATA_BLOB *nt_password,
51                                DATA_BLOB *lm_interactive_password, DATA_BLOB *nt_interactive_password,
52                                DATA_BLOB *plaintext_password, BOOL encrypted, uint32_t flags,
53                                struct auth_usersupplied_info **_user_info)
54 {
55         struct auth_usersupplied_info *user_info;
56         DATA_BLOB blob;
57
58         DEBUG(5,("attempting to make a user_info for %s (%s)\n", account_name, c_account_name));
59
60         user_info = talloc(mem_ctx, struct auth_usersupplied_info);
61         NT_STATUS_HAVE_NO_MEMORY(user_info);
62
63         DEBUG(5,("making strings for %s's user_info struct\n", account_name));
64
65         user_info->client.account_name = talloc_strdup(user_info, c_account_name);
66         NT_STATUS_HAVE_NO_MEMORY(user_info->client.account_name);
67
68         user_info->account_name = talloc_strdup(user_info, account_name);
69         NT_STATUS_HAVE_NO_MEMORY(user_info->account_name);
70
71         user_info->client.domain_name = talloc_strdup(user_info, c_domain_name);
72         if (c_domain_name && !user_info->client.domain_name) {
73                 return NT_STATUS_NO_MEMORY;
74         }
75
76         user_info->domain_name = talloc_strdup(user_info, domain_name);
77         NT_STATUS_HAVE_NO_MEMORY(user_info->domain_name);
78
79         user_info->workstation_name = talloc_strdup(user_info, workstation_name);
80         NT_STATUS_HAVE_NO_MEMORY(user_info->workstation_name);
81
82         user_info->remote_host = talloc_strdup(user_info, remote_host);
83         NT_STATUS_HAVE_NO_MEMORY(user_info->remote_host);
84
85         DEBUG(5,("making blobs for %s's user_info struct\n", account_name));
86
87         if (lm_password) {
88                 blob = data_blob_dup_talloc(user_info, lm_password);
89                 NT_STATUS_HAVE_NO_MEMORY(blob.data);
90         } else {
91                 blob = data_blob(NULL, 0);
92         }
93         user_info->lm_resp = blob;
94
95         if (nt_password) {
96                 blob = data_blob_dup_talloc(user_info, nt_password);
97                 NT_STATUS_HAVE_NO_MEMORY(blob.data);
98         } else {
99                 blob = data_blob(NULL, 0);
100         }
101         user_info->nt_resp = blob;
102
103         if (lm_interactive_password) {
104                 blob = data_blob_dup_talloc(user_info, lm_interactive_password);
105                 NT_STATUS_HAVE_NO_MEMORY(blob.data);
106         } else {
107                 blob = data_blob(NULL, 0);
108         }
109         user_info->lm_interactive_password = blob;
110
111         if (nt_interactive_password) {
112                 blob = data_blob_dup_talloc(user_info, nt_interactive_password);
113                 NT_STATUS_HAVE_NO_MEMORY(blob.data);
114         } else {
115                 blob = data_blob(NULL, 0);
116         }
117         user_info->nt_interactive_password = blob;
118
119         if (plaintext_password) {
120                 blob = data_blob_dup_talloc(user_info, plaintext_password);
121                 NT_STATUS_HAVE_NO_MEMORY(blob.data);
122         } else {
123                 blob = data_blob(NULL, 0);
124         }
125         user_info->plaintext_password = blob;
126
127         user_info->encrypted = encrypted;
128
129         DEBUG(10,("made an %sencrypted user_info for %s (%s)\n", encrypted ? "":"un" , account_name, c_account_name));
130
131         *_user_info = user_info;
132
133         return NT_STATUS_OK;
134 }
135
136 /****************************************************************************
137  Create an auth_usersupplied_data structure after appropriate mapping.
138 ****************************************************************************/
139
140 NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
141                             const char *c_account_name,
142                             const char *c_domain_name,
143                             const char *workstation_name,
144                             DATA_BLOB *lm_password, DATA_BLOB *nt_password,
145                             DATA_BLOB *lm_interactive_password, DATA_BLOB *nt_interactive_password,
146                             DATA_BLOB *plaintext, BOOL encrypted,
147                             struct auth_usersupplied_info **user_info)
148 {
149         const char *domain;
150         const char *account_name;
151         char *d;
152         DEBUG(5,("make_user_info_map: Mapping user [%s]\\[%s] from workstation [%s]\n",
153                 c_domain_name, c_account_name, workstation_name));
154
155         account_name = c_account_name;
156
157         /* don't allow "" as a domain, fixes a Win9X bug 
158            where it doens't supply a domain for logon script
159            'net use' commands.                                 */
160
161         /* Split user@realm names into user and realm components.  This is TODO to fix with proper userprincipalname support */
162         if (c_domain_name && *c_domain_name) {
163                 domain = c_domain_name;
164         } else if (strchr_m(c_account_name, '@')) {
165                 account_name = talloc_strdup(mem_ctx, c_account_name);
166                 if (!account_name) {
167                         return NT_STATUS_NO_MEMORY;
168                 }
169                 d = strchr_m(account_name, '@');
170                 if (!d) {
171                         return NT_STATUS_INTERNAL_ERROR;
172                 }
173                 d[0] = '\0';
174                 d++;
175                 domain = d;
176         } else {
177                 domain = lp_workgroup();
178         }
179
180         return make_user_info(mem_ctx,
181                               c_account_name, account_name, 
182                               c_domain_name, domain,
183                               workstation_name,
184                               workstation_name,
185                               lm_password, nt_password,
186                               lm_interactive_password, nt_interactive_password,
187                               plaintext, encrypted, 0x00,
188                               user_info);
189 }
190
191 /****************************************************************************
192  Create an auth_usersupplied_data, making the DATA_BLOBs here. 
193  Decrypt and encrypt the passwords.
194 ****************************************************************************/
195 NTSTATUS make_user_info_netlogon_network(TALLOC_CTX *mem_ctx,
196                                          const char *c_account_name,
197                                          const char *c_domain_name,
198                                          const char *workstation_name,
199                                          const uint8_t *lm_network_password, int lm_password_len,
200                                          const uint8_t *nt_network_password, int nt_password_len,
201                                          struct auth_usersupplied_info **user_info)
202 {
203         DATA_BLOB lm_blob = data_blob_const(lm_network_password, lm_password_len);
204         DATA_BLOB nt_blob = data_blob_const(nt_network_password, nt_password_len);
205
206         return make_user_info_map(mem_ctx,
207                                   c_account_name,
208                                   c_domain_name, 
209                                   workstation_name, 
210                                   lm_password_len ? &lm_blob : NULL, 
211                                   nt_password_len ? &nt_blob : NULL,
212                                   NULL, NULL, NULL, True,
213                                   user_info);
214 }
215
216 /****************************************************************************
217  Create an auth_usersupplied_data, making the DATA_BLOBs here. 
218  Decrypt and encrypt the passwords.
219 ****************************************************************************/
220 NTSTATUS make_user_info_netlogon_interactive(TALLOC_CTX *mem_ctx,
221                                              const char *c_account_name,
222                                              const char *c_domain_name,
223                                              const char *workstation_name,
224                                              const uint8_t chal[8],
225                                              const struct samr_Password *lm_interactive_password,
226                                              const struct samr_Password *nt_interactive_password,
227                                              struct auth_usersupplied_info **user_info)
228 {
229         NTSTATUS nt_status;
230         DATA_BLOB local_lm_blob;
231         DATA_BLOB local_nt_blob;
232         
233         DATA_BLOB lm_interactive_blob;
234         DATA_BLOB nt_interactive_blob;
235         uint8_t local_lm_response[24];
236         uint8_t local_nt_response[24];
237
238         SMBOWFencrypt(lm_interactive_password->hash, chal, local_lm_response);
239         SMBOWFencrypt(nt_interactive_password->hash, chal, local_nt_response);
240
241         local_lm_blob = data_blob_const(local_lm_response, sizeof(local_lm_response));
242         lm_interactive_blob = data_blob_const(lm_interactive_password->hash, 
243                                               sizeof(lm_interactive_password->hash));
244
245         local_nt_blob = data_blob_const(local_nt_response, sizeof(local_nt_response));
246         nt_interactive_blob = data_blob_const(nt_interactive_password->hash, 
247                                               sizeof(nt_interactive_password->hash));
248         
249         nt_status = make_user_info_map(mem_ctx,
250                                        c_account_name,
251                                        c_domain_name, 
252                                        workstation_name,
253                                        &local_lm_blob,
254                                        &local_nt_blob,
255                                        &lm_interactive_blob,
256                                        &nt_interactive_blob,
257                                        NULL, True,
258                                        user_info);
259         return nt_status;
260 }
261
262 /****************************************************************************
263  Create an auth_usersupplied_data structure
264 ****************************************************************************/
265 NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
266                                       const char *c_account_name,
267                                       const char *c_domain_name,
268                                       const char *workstation_name,
269                                       DATA_BLOB lm_resp, DATA_BLOB nt_resp,
270                                       struct auth_usersupplied_info **user_info)
271 {
272         return make_user_info_map(mem_ctx,
273                                   c_account_name,
274                                   c_domain_name,
275                                   workstation_name,
276                                   lm_resp.data ? &lm_resp : NULL,
277                                   nt_resp.data ? &nt_resp : NULL,
278                                   NULL, NULL, NULL, True,
279                                   user_info);
280 }
281
282 /****************************************************************************
283  Create a anonymous user_info blob, for anonymous authenticaion.
284 ****************************************************************************/
285 NTSTATUS make_user_info_anonymous(TALLOC_CTX *mem_ctx, struct auth_usersupplied_info **user_info) 
286 {
287         return make_user_info(mem_ctx,
288                               "", "", "", "", "", "",
289                               NULL, NULL, NULL, NULL, 
290                               NULL, True, 0x00,
291                               user_info);
292 }
293
294
295 /***************************************************************************
296  Make a server_info struct from the info3 returned by a domain logon 
297 ***************************************************************************/
298 NTSTATUS make_server_info_netlogon_validation(TALLOC_CTX *mem_ctx,
299                                               const char *account_name,
300                                               uint16_t validation_level,
301                                               union netr_Validation *validation,
302                                               struct auth_serversupplied_info **_server_info)
303 {
304         struct auth_serversupplied_info *server_info;
305         struct netr_SamBaseInfo *base = NULL;
306         int i;
307
308         switch (validation_level) {
309         case 2:
310                 if (!validation || !validation->sam2) {
311                         return NT_STATUS_INVALID_PARAMETER;
312                 }
313                 base = &validation->sam2->base;
314                 break;
315         case 3:
316                 if (!validation || !validation->sam3) {
317                         return NT_STATUS_INVALID_PARAMETER;
318                 }
319                 base = &validation->sam3->base;
320                 break;
321         case 6:
322                 if (!validation || !validation->sam6) {
323                         return NT_STATUS_INVALID_PARAMETER;
324                 }
325                 base = &validation->sam6->base;
326                 break;
327         default:
328                 return NT_STATUS_INVALID_LEVEL;
329         }
330
331         server_info = talloc(mem_ctx, struct auth_serversupplied_info);
332         NT_STATUS_HAVE_NO_MEMORY(server_info);
333
334         /*
335            Here is where we should check the list of
336            trusted domains, and verify that the SID 
337            matches.
338         */
339         server_info->account_sid = dom_sid_add_rid(server_info, base->domain_sid, base->rid);
340         NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid);
341
342
343         server_info->primary_group_sid = dom_sid_add_rid(server_info, base->domain_sid, base->primary_gid);
344         NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid);
345
346         server_info->n_domain_groups = base->groups.count;
347         if (base->groups.count) {
348                 server_info->domain_groups = talloc_array(server_info, struct dom_sid*, base->groups.count);
349                 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_groups);
350         } else {
351                 server_info->domain_groups = NULL;
352         }
353
354         for (i = 0; i < base->groups.count; i++) {
355                 server_info->domain_groups[i] = dom_sid_add_rid(server_info, base->domain_sid, base->groups.rids[i].rid);
356                 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_groups[i]);
357         }
358
359         /* Copy 'other' sids.  We need to do sid filtering here to
360            prevent possible elevation of privileges.  See:
361
362            http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
363          */
364
365         if (validation_level == 3) {
366                 struct dom_sid **dgrps = server_info->domain_groups;
367                 size_t sidcount = server_info->n_domain_groups + validation->sam3->sidcount;
368                 size_t n_dgrps = server_info->n_domain_groups;
369
370                 dgrps = talloc_realloc(server_info, dgrps, struct dom_sid*, sidcount);
371                 NT_STATUS_HAVE_NO_MEMORY(dgrps);
372
373                 for (i = 0; i < validation->sam3->sidcount; i++) {
374                         dgrps[n_dgrps + i] = talloc_reference(dgrps, validation->sam3->sids[i].sid);
375                 }
376
377                 server_info->n_domain_groups = sidcount;
378                 server_info->domain_groups = dgrps;
379
380                 /* Where are the 'global' sids?... */
381         }
382
383         if (base->account_name.string) {
384                 server_info->account_name = talloc_reference(server_info, base->account_name.string);
385         } else {
386                 server_info->account_name = talloc_strdup(server_info, account_name);
387                 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
388         }
389
390         server_info->domain_name = talloc_reference(server_info, base->domain.string);
391         server_info->full_name = talloc_reference(server_info, base->full_name.string);
392         server_info->logon_script = talloc_reference(server_info, base->logon_script.string);
393         server_info->profile_path = talloc_reference(server_info, base->profile_path.string);
394         server_info->home_directory = talloc_reference(server_info, base->home_directory.string);
395         server_info->home_drive = talloc_reference(server_info, base->home_drive.string);
396         server_info->last_logon = base->last_logon;
397         server_info->last_logoff = base->last_logoff;
398         server_info->acct_expiry = base->acct_expiry;
399         server_info->last_password_change = base->last_password_change;
400         server_info->allow_password_change = base->allow_password_change;
401         server_info->force_password_change = base->force_password_change;
402         server_info->logon_count = base->logon_count;
403         server_info->bad_password_count = base->bad_password_count;
404         server_info->acct_flags = base->acct_flags;
405
406         server_info->authenticated = True;
407
408         /* ensure we are never given NULL session keys */
409
410         if (all_zero(base->key.key, sizeof(base->key.key))) {
411                 server_info->user_session_key = data_blob(NULL, 0);
412         } else {
413                 server_info->user_session_key = data_blob_talloc(server_info, base->key.key, sizeof(base->key.key));
414                 NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data);
415         }
416
417         if (all_zero(base->LMSessKey.key, sizeof(base->LMSessKey.key))) {
418                 server_info->lm_session_key = data_blob(NULL, 0);
419         } else {
420                 server_info->lm_session_key = data_blob_talloc(server_info, base->LMSessKey.key, sizeof(base->LMSessKey.key));
421                 NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data);
422         }
423
424         *_server_info = server_info;
425         return NT_STATUS_OK;
426 }
427
428
429 NTSTATUS auth_anonymous_server_info(TALLOC_CTX *mem_ctx, struct auth_serversupplied_info **_server_info) 
430 {
431         struct auth_serversupplied_info *server_info;
432         server_info = talloc(mem_ctx, struct auth_serversupplied_info);
433         NT_STATUS_HAVE_NO_MEMORY(server_info);
434
435         server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS);
436         NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid);
437
438         /* is this correct? */
439         server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS);
440         NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid);
441
442         server_info->n_domain_groups = 0;
443         server_info->domain_groups = NULL;
444
445         /* annoying, but the Anonymous really does have a session key, 
446            and it is all zeros! */
447         server_info->user_session_key = data_blob_talloc(server_info, NULL, 16);
448         NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data);
449
450         server_info->lm_session_key = data_blob_talloc(server_info, NULL, 16);
451         NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data);
452
453         data_blob_clear(&server_info->user_session_key);
454         data_blob_clear(&server_info->lm_session_key);
455
456         server_info->account_name = talloc_strdup(server_info, "ANONYMOUS LOGON");
457         NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
458
459         server_info->domain_name = talloc_strdup(server_info, "NT AUTHORITY");
460         NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
461
462         server_info->full_name = talloc_strdup(server_info, "Anonymous Logon");
463         NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
464
465         server_info->logon_script = talloc_strdup(server_info, "");
466         NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
467
468         server_info->profile_path = talloc_strdup(server_info, "");
469         NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
470
471         server_info->home_directory = talloc_strdup(server_info, "");
472         NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
473
474         server_info->home_drive = talloc_strdup(server_info, "");
475         NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
476
477         server_info->last_logon = 0;
478         server_info->last_logoff = 0;
479         server_info->acct_expiry = 0;
480         server_info->last_password_change = 0;
481         server_info->allow_password_change = 0;
482         server_info->force_password_change = 0;
483
484         server_info->logon_count = 0;
485         server_info->bad_password_count = 0;
486
487         server_info->acct_flags = ACB_NORMAL;
488
489         server_info->authenticated = False;
490
491         *_server_info = server_info;
492
493         return NT_STATUS_OK;
494 }
495
496 NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx, 
497                                     struct auth_serversupplied_info *server_info, 
498                                     struct auth_session_info **_session_info) 
499 {
500         struct auth_session_info *session_info;
501         NTSTATUS nt_status;
502
503         session_info = talloc(mem_ctx, struct auth_session_info);
504         NT_STATUS_HAVE_NO_MEMORY(session_info);
505
506         session_info->server_info = talloc_reference(session_info, server_info);
507
508         /* unless set otherwise, the session key is the user session
509          * key from the auth subsystem */ 
510         session_info->session_key = server_info->user_session_key;
511
512         nt_status = security_token_create(session_info,
513                                           server_info->account_sid,
514                                           server_info->primary_group_sid,
515                                           server_info->n_domain_groups,
516                                           server_info->domain_groups,
517                                           server_info->authenticated,
518                                           &session_info->security_token);
519         NT_STATUS_NOT_OK_RETURN(nt_status);
520
521         *_session_info = session_info;
522         return NT_STATUS_OK;
523 }
524
525 /****************************************************************************
526  prints a struct auth_session_info security token to debug output.
527 ****************************************************************************/
528 void auth_session_info_debug(int dbg_lev, 
529                              const struct auth_session_info *session_info)
530 {
531         if (!session_info) {
532                 DEBUGC(dbg_class, dbg_lev, ("Session Info: (NULL)\n"));
533                 return; 
534         }
535
536         security_token_debug(dbg_lev, session_info->security_token);
537 }
538
539 /**
540  * Squash an NT_STATUS in line with security requirements.
541  * In an attempt to avoid giving the whole game away when users
542  * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and 
543  * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations 
544  * (session setups in particular).
545  *
546  * @param nt_status NTSTATUS input for squashing.
547  * @return the 'squashed' nt_status
548  **/
549 NTSTATUS auth_nt_status_squash(NTSTATUS nt_status)
550 {
551         if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
552                 /* Match WinXP and don't give the game away */
553                 return NT_STATUS_LOGON_FAILURE;
554         } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
555                 /* Match WinXP and don't give the game away */
556                 return NT_STATUS_LOGON_FAILURE;
557         }
558
559         return nt_status;
560 }