auth4: Fix map_user_info_cracknames for domain==NULL
[sfrench/samba-autobuild/.git] / source4 / auth / ntlm / 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 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 "auth/auth.h"
26 #include "libcli/auth/libcli_auth.h"
27 #include "param/param.h"
28 #include "auth/ntlm/auth_proto.h"
29 #include "librpc/gen_ndr/drsuapi.h"
30 #include "dsdb/samdb/samdb.h"
31
32 /* this default function can be used by mostly all backends
33  * which don't want to set a challenge
34  */
35 NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, uint8_t chal[8])
36 {
37         /* we don't want to set a challenge */
38         return NT_STATUS_NOT_IMPLEMENTED;
39 }
40
41 /****************************************************************************
42  Create an auth_usersupplied_data structure after appropriate mapping.
43 ****************************************************************************/
44 static NTSTATUS map_user_info_cracknames(struct ldb_context *sam_ctx,
45                                          TALLOC_CTX *mem_ctx,
46                                          const char *default_domain,
47                                          const struct auth_usersupplied_info *user_info,
48                                          struct auth_usersupplied_info **user_info_mapped)
49 {
50         char *domain;
51         char *account_name;
52         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
53         WERROR werr;
54         struct drsuapi_DsNameInfo1 info1;
55
56         DEBUG(5,("map_user_info_cracknames: Mapping user [%s]\\[%s] from workstation [%s]\n",
57                  user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
58
59         account_name = talloc_strdup(tmp_ctx, user_info->client.account_name);
60         if (!account_name) {
61                 talloc_free(tmp_ctx);
62                 return NT_STATUS_NO_MEMORY;
63         }
64
65         /* use cracknames to work out what domain is being
66            asked for */
67         if (strchr_m(user_info->client.account_name, '@') != NULL) {
68                 werr = DsCrackNameOneName(sam_ctx, tmp_ctx, 0,
69                                           DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
70                                           DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
71                                           user_info->client.account_name,
72                                           &info1);
73                 if (!W_ERROR_IS_OK(werr)) {
74                         DEBUG(2,("map_user_info: Failed cracknames of account '%s'\n",
75                                  user_info->client.account_name));
76                         talloc_free(tmp_ctx);
77                         return werror_to_ntstatus(werr);
78                 }
79                 switch (info1.status) {
80                 case DRSUAPI_DS_NAME_STATUS_OK:
81                         break;
82                 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
83                         DEBUG(2,("map_user_info: Cracknames of account '%s' -> NOT_FOUND\n",
84                                  user_info->client.account_name));
85                         talloc_free(tmp_ctx);
86                         return NT_STATUS_NO_SUCH_USER;
87                 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
88                         DEBUG(2,("map_user_info: Cracknames of account '%s' -> DOMAIN_ONLY\n",
89                                  user_info->client.account_name));
90                         talloc_free(tmp_ctx);
91                         return NT_STATUS_NO_SUCH_USER;
92                 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
93                         DEBUG(2,("map_user_info: Cracknames of account '%s' -> NOT_UNIQUE\n",
94                                  user_info->client.account_name));
95                         talloc_free(tmp_ctx);
96                         return NT_STATUS_NO_SUCH_USER;
97                 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
98                         DEBUG(2,("map_user_info: Cracknames of account '%s' -> RESOLVE_ERROR\n",
99                                  user_info->client.account_name));
100                         talloc_free(tmp_ctx);
101                         return NT_STATUS_NO_SUCH_USER;
102                 default:
103                         DEBUG(2,("map_user_info: Cracknames of account '%s' -> unknown error %u\n",
104                                  user_info->client.account_name, info1.status));
105                         talloc_free(tmp_ctx);
106                         return NT_STATUS_NO_SUCH_USER;
107                 }
108                 /* info1.result_name is in DOMAIN\username
109                  * form, which we need to split up into the
110                  * user_info_mapped structure
111                  */
112                 domain = talloc_strdup(tmp_ctx, info1.result_name);
113                 if (domain == NULL) {
114                         talloc_free(tmp_ctx);
115                         return NT_STATUS_NO_MEMORY;
116                 }
117                 account_name = strchr_m(domain, '\\');
118                 if (account_name == NULL) {
119                         DEBUG(2,("map_user_info: Cracknames of account '%s' gave invalid result '%s'\n",
120                                  user_info->client.account_name, info1.result_name));
121                         talloc_free(tmp_ctx);
122                         return NT_STATUS_NO_SUCH_USER;
123                 }
124                 *account_name = 0;
125                 account_name = talloc_strdup(tmp_ctx, account_name+1);
126                 if (account_name == NULL) {
127                         talloc_free(tmp_ctx);
128                         return NT_STATUS_NO_MEMORY;
129                 }
130         } else {
131                 const char *domain_name = default_domain;
132                 if (user_info->client.domain_name && *user_info->client.domain_name) {
133                         domain_name = user_info->client.domain_name;
134                 }
135                 domain_name = talloc_asprintf(tmp_ctx, "%s\\", domain_name);
136                 if (domain_name == NULL) {
137                         talloc_free(tmp_ctx);
138                         return NT_STATUS_NO_MEMORY;
139                 }
140                 werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0,
141                                           DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
142                                           DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
143                                           domain_name,
144                                           &info1);
145                 if (!W_ERROR_IS_OK(werr)) {
146                         DEBUG(2,("map_user_info: Failed cracknames of domain '%s'\n",
147                                  domain_name));
148                         talloc_free(tmp_ctx);
149                         return werror_to_ntstatus(werr);
150                 }
151
152                 /* we use the account_name as-is, but get the
153                  * domain name from cracknames if possible */
154                 account_name = talloc_strdup(mem_ctx, user_info->client.account_name);
155                 if (account_name == NULL) {
156                         talloc_free(tmp_ctx);
157                         return NT_STATUS_NO_MEMORY;
158                 }
159
160                 switch (info1.status) {
161                 case DRSUAPI_DS_NAME_STATUS_OK:
162                 case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY:
163                         domain = talloc_strdup(tmp_ctx, info1.result_name);
164                         if (domain == NULL) {
165                                 talloc_free(tmp_ctx);
166                                 return NT_STATUS_NO_MEMORY;
167                         }
168                         if (domain[strlen_m(domain)-1] == '\\') {
169                                 domain[strlen_m(domain)-1] = 0;
170                         }
171                         break;
172                 case DRSUAPI_DS_NAME_STATUS_NOT_FOUND:
173                         /* the domain is unknown - use the
174                            default domain */
175                         domain = talloc_strdup(tmp_ctx, default_domain);
176                         break;
177                 case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE:
178                         DEBUG(2,("map_user_info: Cracknames of domain '%s' -> NOT_UNIQUE\n",
179                                  domain_name));
180                         talloc_free(tmp_ctx);
181                         return NT_STATUS_NO_SUCH_USER;
182                 case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR:
183                         DEBUG(2,("map_user_info: Cracknames of domain '%s' -> RESOLVE_ERROR\n",
184                                  domain_name));
185                         talloc_free(tmp_ctx);
186                         return NT_STATUS_NO_SUCH_USER;
187                 default:
188                         DEBUG(2,("map_user_info: Cracknames of account '%s' -> unknown error %u\n",
189                                  domain_name, info1.status));
190                         talloc_free(tmp_ctx);
191                         return NT_STATUS_NO_SUCH_USER;
192                 }
193                 /* domain and account_name are filled in above */
194         }
195
196         *user_info_mapped = talloc_zero(mem_ctx, struct auth_usersupplied_info);
197         if (!*user_info_mapped) {
198                 talloc_free(tmp_ctx);
199                 return NT_STATUS_NO_MEMORY;
200         }
201         if (!talloc_reference(*user_info_mapped, user_info)) {
202                 talloc_free(tmp_ctx);
203                 return NT_STATUS_NO_MEMORY;
204         }
205         **user_info_mapped = *user_info;
206         (*user_info_mapped)->mapped_state = true;
207         (*user_info_mapped)->mapped.domain_name = talloc_strdup(*user_info_mapped, domain);
208         (*user_info_mapped)->mapped.account_name = talloc_strdup(*user_info_mapped, account_name);
209         talloc_free(tmp_ctx);
210         if (!(*user_info_mapped)->mapped.domain_name
211             || !(*user_info_mapped)->mapped.account_name) {
212                 return NT_STATUS_NO_MEMORY;
213         }
214
215         return NT_STATUS_OK;
216 }
217
218
219 /****************************************************************************
220  Create an auth_usersupplied_data structure after appropriate mapping.
221 ****************************************************************************/
222 NTSTATUS map_user_info(struct ldb_context *sam_ctx,
223                        TALLOC_CTX *mem_ctx,
224                        const char *default_domain,
225                        const struct auth_usersupplied_info *user_info,
226                        struct auth_usersupplied_info **user_info_mapped)
227 {
228         char *domain;
229         char *account_name;
230         char *d;
231         TALLOC_CTX *tmp_ctx;
232
233         if (sam_ctx != NULL) {
234                 /* if possible, use cracknames to parse the
235                    domain/account */
236                 return map_user_info_cracknames(sam_ctx, mem_ctx, default_domain, user_info, user_info_mapped);
237         }
238
239         DEBUG(0,("map_user_info: Mapping user [%s]\\[%s] from workstation [%s] default_domain=%s\n",
240                  user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name,
241                  default_domain));
242
243         tmp_ctx = talloc_new(mem_ctx);
244
245         account_name = talloc_strdup(tmp_ctx, user_info->client.account_name);
246         if (!account_name) {
247                 talloc_free(tmp_ctx);
248                 return NT_STATUS_NO_MEMORY;
249         }
250         
251         /* don't allow "" as a domain, fixes a Win9X bug where it
252            doesn't supply a domain for logon script 'net use'
253            commands.  */
254
255         /* Split user@realm names into user and realm components.
256          * This is TODO to fix with proper userprincipalname
257          * support */
258         if (user_info->client.domain_name && *user_info->client.domain_name) {
259                 domain = talloc_strdup(tmp_ctx, user_info->client.domain_name);
260         } else if (strchr_m(user_info->client.account_name, '@')) {
261                 d = strchr_m(account_name, '@');
262                 if (!d) {
263                         talloc_free(tmp_ctx);
264                         return NT_STATUS_INTERNAL_ERROR;
265                 }
266                 d[0] = '\0';
267                 d++;
268                 domain = d;
269         } else {
270                 domain = talloc_strdup(tmp_ctx, default_domain);
271         }
272
273         if (domain == NULL) {
274                 talloc_free(tmp_ctx);
275                 return NT_STATUS_NO_MEMORY;
276         }
277         *user_info_mapped = talloc_zero(mem_ctx, struct auth_usersupplied_info);
278         if (!*user_info_mapped) {
279                 talloc_free(tmp_ctx);
280                 return NT_STATUS_NO_MEMORY;
281         }
282         if (!talloc_reference(*user_info_mapped, user_info)) {
283                 talloc_free(tmp_ctx);
284                 return NT_STATUS_NO_MEMORY;
285         }
286         **user_info_mapped = *user_info;
287         (*user_info_mapped)->mapped_state = true;
288         (*user_info_mapped)->mapped.domain_name = talloc_strdup(*user_info_mapped, domain);
289         (*user_info_mapped)->mapped.account_name = talloc_strdup(*user_info_mapped, account_name);
290         talloc_free(tmp_ctx);
291         if (!(*user_info_mapped)->mapped.domain_name 
292             || !(*user_info_mapped)->mapped.account_name) {
293                 return NT_STATUS_NO_MEMORY;
294         }
295
296         return NT_STATUS_OK;
297 }
298
299 /****************************************************************************
300  Create an auth_usersupplied_data structure after appropriate mapping.
301 ****************************************************************************/
302
303 NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth4_context *auth_context, 
304                            enum auth_password_state to_state,
305                            const struct auth_usersupplied_info *user_info_in,
306                            const struct auth_usersupplied_info **user_info_encrypted)
307 {
308         NTSTATUS nt_status;
309         struct auth_usersupplied_info *user_info_temp;
310         switch (to_state) {
311         case AUTH_PASSWORD_RESPONSE:
312                 switch (user_info_in->password_state) {
313                 case AUTH_PASSWORD_PLAIN:
314                 {
315                         const struct auth_usersupplied_info *user_info_temp2;
316                         nt_status = encrypt_user_info(mem_ctx, auth_context, 
317                                                       AUTH_PASSWORD_HASH, 
318                                                       user_info_in, &user_info_temp2);
319                         if (!NT_STATUS_IS_OK(nt_status)) {
320                                 return nt_status;
321                         }
322                         user_info_in = user_info_temp2;
323                         /* fall through */
324                 }
325                 case AUTH_PASSWORD_HASH:
326                 {
327                         uint8_t chal[8];
328                         DATA_BLOB chall_blob;
329                         user_info_temp = talloc_zero(mem_ctx, struct auth_usersupplied_info);
330                         if (!user_info_temp) {
331                                 return NT_STATUS_NO_MEMORY;
332                         }
333                         if (!talloc_reference(user_info_temp, user_info_in)) {
334                                 return NT_STATUS_NO_MEMORY;
335                         }
336                         *user_info_temp = *user_info_in;
337                         user_info_temp->mapped_state = to_state;
338                         
339                         nt_status = auth_get_challenge(auth_context, chal);
340                         if (!NT_STATUS_IS_OK(nt_status)) {
341                                 return nt_status;
342                         }
343                         
344                         chall_blob = data_blob_talloc(mem_ctx, chal, 8);
345                         if (lpcfg_client_ntlmv2_auth(auth_context->lp_ctx)) {
346                                 DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx,  lpcfg_netbios_name(auth_context->lp_ctx), lpcfg_workgroup(auth_context->lp_ctx));
347                                 DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key;
348                                 
349                                 if (!SMBNTLMv2encrypt_hash(user_info_temp,
350                                                            user_info_in->client.account_name, 
351                                                            user_info_in->client.domain_name, 
352                                                            user_info_in->password.hash.nt->hash,
353                                                            &chall_blob,
354                                                            NULL, /* server_timestamp */
355                                                            &names_blob,
356                                                            &lmv2_response, &ntlmv2_response, 
357                                                            &lmv2_session_key, &ntlmv2_session_key)) {
358                                         data_blob_free(&names_blob);
359                                         return NT_STATUS_NO_MEMORY;
360                                 }
361                                 data_blob_free(&names_blob);
362                                 user_info_temp->password.response.lanman = lmv2_response;
363                                 user_info_temp->password.response.nt = ntlmv2_response;
364                                 
365                                 data_blob_free(&lmv2_session_key);
366                                 data_blob_free(&ntlmv2_session_key);
367                         } else {
368                                 DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24);
369                                 SMBOWFencrypt(user_info_in->password.hash.nt->hash, chal, blob.data);
370
371                                 user_info_temp->password.response.nt = blob;
372                                 if (lpcfg_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) {
373                                         DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24);
374                                         SMBOWFencrypt(user_info_in->password.hash.lanman->hash, chal, blob.data);
375                                         user_info_temp->password.response.lanman = lm_blob;
376                                 } else {
377                                         /* if not sending the LM password, send the NT password twice */
378                                         user_info_temp->password.response.lanman = user_info_temp->password.response.nt;
379                                 }
380                         }
381
382                         user_info_in = user_info_temp;
383                         /* fall through */
384                 }
385                 case AUTH_PASSWORD_RESPONSE:
386                         *user_info_encrypted = user_info_in;
387                 }
388                 break;
389         case AUTH_PASSWORD_HASH:
390         {       
391                 switch (user_info_in->password_state) {
392                 case AUTH_PASSWORD_PLAIN:
393                 {
394                         struct samr_Password lanman;
395                         struct samr_Password nt;
396                         
397                         user_info_temp = talloc_zero(mem_ctx, struct auth_usersupplied_info);
398                         if (!user_info_temp) {
399                                 return NT_STATUS_NO_MEMORY;
400                         }
401                         if (!talloc_reference(user_info_temp, user_info_in)) {
402                                 return NT_STATUS_NO_MEMORY;
403                         }
404                         *user_info_temp = *user_info_in;
405                         user_info_temp->mapped_state = to_state;
406                         
407                         if (E_deshash(user_info_in->password.plaintext, lanman.hash)) {
408                                 user_info_temp->password.hash.lanman = talloc(user_info_temp,
409                                                                               struct samr_Password);
410                                 *user_info_temp->password.hash.lanman = lanman;
411                         } else {
412                                 user_info_temp->password.hash.lanman = NULL;
413                         }
414                         
415                         E_md4hash(user_info_in->password.plaintext, nt.hash);
416                         user_info_temp->password.hash.nt = talloc(user_info_temp,
417                                                                    struct samr_Password);
418                         *user_info_temp->password.hash.nt = nt;
419                         
420                         user_info_in = user_info_temp;
421                         /* fall through */
422                 }
423                 case AUTH_PASSWORD_HASH:
424                         *user_info_encrypted = user_info_in;
425                         break;
426                 default:
427                         return NT_STATUS_INVALID_PARAMETER;
428                         break;
429                 }
430                 break;
431         }
432         default:
433                 return NT_STATUS_INVALID_PARAMETER;
434         }
435
436         return NT_STATUS_OK;
437 }