r11358: Ensure domains are always upper-case as well. Helps NTLMv2.
[ab/samba.git/.git] / source4 / auth / credentials / credentials.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    User credentials handling
5
6    Copyright (C) Jelmer Vernooij 2005
7    Copyright (C) Tim Potter 2001
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 "lib/ldb/include/ldb.h"
27 #include "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */
28
29
30 /**
31  * Create a new credentials structure
32  * @param mem_ctx TALLOC_CTX parent for credentials structure 
33  */
34 struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) 
35 {
36         struct cli_credentials *cred = talloc(mem_ctx, struct cli_credentials);
37         if (!cred) {
38                 return cred;
39         }
40
41         cred->netlogon_creds = NULL;
42         cred->machine_account_pending = False;
43         cred->workstation_obtained = CRED_UNINITIALISED;
44         cred->username_obtained = CRED_UNINITIALISED;
45         cred->password_obtained = CRED_UNINITIALISED;
46         cred->domain_obtained = CRED_UNINITIALISED;
47         cred->realm_obtained = CRED_UNINITIALISED;
48         cred->ccache_obtained = CRED_UNINITIALISED;
49         cred->keytab_obtained = CRED_UNINITIALISED;
50         cred->principal_obtained = CRED_UNINITIALISED;
51
52         cred->old_password = NULL;
53         cred->smb_krb5_context = NULL;
54         cred->salt_principal = NULL;
55
56         return cred;
57 }
58
59 /**
60  * Obtain the username for this credentials context.
61  * @param cred credentials context
62  * @retval The username set on this context.
63  * @note Return value will never be NULL except by programmer error.
64  */
65 const char *cli_credentials_get_username(struct cli_credentials *cred)
66 {
67         if (cred->machine_account_pending) {
68                 cli_credentials_set_machine_account(cred);
69         }
70
71         if (cred->username_obtained == CRED_CALLBACK) {
72                 cred->username = cred->username_cb(cred);
73                 cred->username_obtained = CRED_SPECIFIED;
74         }
75
76         return cred->username;
77 }
78
79 BOOL cli_credentials_set_username(struct cli_credentials *cred, 
80                                   const char *val, enum credentials_obtained obtained)
81 {
82         if (obtained >= cred->username_obtained) {
83                 cred->username = talloc_strdup(cred, val);
84                 cred->username_obtained = obtained;
85                 return True;
86         }
87
88         return False;
89 }
90
91 BOOL cli_credentials_set_username_callback(struct cli_credentials *cred,
92                                   const char *(*username_cb) (struct cli_credentials *))
93 {
94         if (cred->username_obtained < CRED_CALLBACK) {
95                 cred->username_cb = username_cb;
96                 cred->username_obtained = CRED_CALLBACK;
97                 return True;
98         }
99
100         return False;
101 }
102
103
104
105 /**
106  * Obtain the client principal for this credentials context.
107  * @param cred credentials context
108  * @retval The username set on this context.
109  * @note Return value will never be NULL except by programmer error.
110  */
111 const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
112 {
113         if (cred->machine_account_pending) {
114                 cli_credentials_set_machine_account(cred);
115         }
116
117         if (cred->principal_obtained == CRED_CALLBACK) {
118                 cred->principal = cred->principal_cb(cred);
119                 cred->principal_obtained = CRED_SPECIFIED;
120         }
121
122         if (cred->principal_obtained < cred->username_obtained) {
123                 if (cred->domain_obtained > cred->realm_obtained) {
124                         return talloc_asprintf(mem_ctx, "%s@%s", 
125                                                cli_credentials_get_username(cred),
126                                                cli_credentials_get_domain(cred));
127                 } else {
128                         return talloc_asprintf(mem_ctx, "%s@%s", 
129                                                cli_credentials_get_username(cred),
130                                                cli_credentials_get_realm(cred));
131                 }
132         }
133         return talloc_reference(mem_ctx, cred->principal);
134 }
135
136 BOOL cli_credentials_set_principal(struct cli_credentials *cred, 
137                                    const char *val, 
138                                    enum credentials_obtained obtained)
139 {
140         if (obtained >= cred->principal_obtained) {
141                 cred->principal = talloc_strdup(cred, val);
142                 cred->principal_obtained = obtained;
143                 return True;
144         }
145
146         return False;
147 }
148
149 BOOL cli_credentials_set_principal_callback(struct cli_credentials *cred,
150                                   const char *(*principal_cb) (struct cli_credentials *))
151 {
152         if (cred->principal_obtained < CRED_CALLBACK) {
153                 cred->principal_cb = principal_cb;
154                 cred->principal_obtained = CRED_CALLBACK;
155                 return True;
156         }
157
158         return False;
159 }
160
161 BOOL cli_credentials_authentication_requested(struct cli_credentials *cred) 
162 {
163         if (cred->principal_obtained >= CRED_SPECIFIED) {
164                 return True;
165         }
166         if (cred->username_obtained >= CRED_SPECIFIED) {
167                 return True;
168         }
169         return False;
170 }
171
172 /**
173  * Obtain the password for this credentials context.
174  * @param cred credentials context
175  * @retval If set, the cleartext password, otherwise NULL
176  */
177 const char *cli_credentials_get_password(struct cli_credentials *cred)
178 {
179         if (cred->machine_account_pending) {
180                 cli_credentials_set_machine_account(cred);
181         }
182
183         if (cred->password_obtained == CRED_CALLBACK) {
184                 cred->password = cred->password_cb(cred);
185                 cred->password_obtained = CRED_SPECIFIED;
186         }
187
188         return cred->password;
189 }
190
191 BOOL cli_credentials_set_password(struct cli_credentials *cred, 
192                                   const char *val, 
193                                   enum credentials_obtained obtained)
194 {
195         if (obtained >= cred->password_obtained) {
196                 cred->password = talloc_strdup(cred, val);
197                 cred->password_obtained = obtained;
198
199                 cred->nt_hash = NULL;
200                 return True;
201         }
202
203         return False;
204 }
205
206 BOOL cli_credentials_set_password_callback(struct cli_credentials *cred,
207                                            const char *(*password_cb) (struct cli_credentials *))
208 {
209         if (cred->password_obtained < CRED_CALLBACK) {
210                 cred->password_cb = password_cb;
211                 cred->password_obtained = CRED_CALLBACK;
212                 return True;
213         }
214
215         return False;
216 }
217
218 /**
219  * Obtain the 'old' password for this credentials context (used for join accounts).
220  * @param cred credentials context
221  * @retval If set, the cleartext password, otherwise NULL
222  */
223 const char *cli_credentials_get_old_password(struct cli_credentials *cred)
224 {
225         if (cred->machine_account_pending) {
226                 cli_credentials_set_machine_account(cred);
227         }
228
229         return cred->old_password;
230 }
231
232 BOOL cli_credentials_set_old_password(struct cli_credentials *cred, 
233                                       const char *val, 
234                                       enum credentials_obtained obtained)
235 {
236         cred->old_password = talloc_strdup(cred, val);
237         return True;
238 }
239
240 /**
241  * Obtain the password for this credentials context.
242  * @param cred credentials context
243  * @retval If set, the cleartext password, otherwise NULL
244  */
245 const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, 
246                                                         TALLOC_CTX *mem_ctx)
247 {
248         const char *password = cli_credentials_get_password(cred);
249
250         if (password) {
251                 struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password);
252                 if (!nt_hash) {
253                         return NULL;
254                 }
255                 
256                 E_md4hash(password, nt_hash->hash);    
257
258                 return nt_hash;
259         } else {
260                 return cred->nt_hash;
261         }
262 }
263
264 BOOL cli_credentials_set_nt_hash(struct cli_credentials *cred,
265                                  const struct samr_Password *nt_hash, 
266                                  enum credentials_obtained obtained)
267 {
268         if (obtained >= cred->password_obtained) {
269                 cli_credentials_set_password(cred, NULL, obtained);
270                 cred->nt_hash = talloc(cred, struct samr_Password);
271                 *cred->nt_hash = *nt_hash;
272                 return True;
273         }
274
275         return False;
276 }
277
278 /**
279  * Obtain the 'short' or 'NetBIOS' domain for this credentials context.
280  * @param cred credentials context
281  * @retval The domain set on this context. 
282  * @note Return value will never be NULL except by programmer error.
283  */
284 const char *cli_credentials_get_domain(struct cli_credentials *cred)
285 {
286         if (cred->machine_account_pending) {
287                 cli_credentials_set_machine_account(cred);
288         }
289
290         if (cred->domain_obtained == CRED_CALLBACK) {
291                 cred->domain = cred->domain_cb(cred);
292                 cred->domain_obtained = CRED_SPECIFIED;
293         }
294
295         return cred->domain;
296 }
297
298
299 BOOL cli_credentials_set_domain(struct cli_credentials *cred, 
300                                 const char *val, 
301                                 enum credentials_obtained obtained)
302 {
303         if (obtained >= cred->domain_obtained) {
304                 /* it is important that the domain be in upper case,
305                  * particularly for the sensitive NTLMv2
306                  * calculations */
307                 cred->domain = strupper_talloc(cred, val);
308                 cred->domain_obtained = obtained;
309                 return True;
310         }
311
312         return False;
313 }
314
315 BOOL cli_credentials_set_domain_callback(struct cli_credentials *cred,
316                                          const char *(*domain_cb) (struct cli_credentials *))
317 {
318         if (cred->domain_obtained < CRED_CALLBACK) {
319                 cred->domain_cb = domain_cb;
320                 cred->domain_obtained = CRED_CALLBACK;
321                 return True;
322         }
323
324         return False;
325 }
326
327 /**
328  * Obtain the Kerberos realm for this credentials context.
329  * @param cred credentials context
330  * @retval The realm set on this context. 
331  * @note Return value will never be NULL except by programmer error.
332  */
333 const char *cli_credentials_get_realm(struct cli_credentials *cred)
334 {       
335         if (cred->machine_account_pending) {
336                 cli_credentials_set_machine_account(cred);
337         }
338
339         if (cred->realm_obtained == CRED_CALLBACK) {
340                 cred->realm = cred->realm_cb(cred);
341                 cred->realm_obtained = CRED_SPECIFIED;
342         }
343
344         return cred->realm;
345 }
346
347 /**
348  * Set the realm for this credentials context, and force it to
349  * uppercase for the sainity of our local kerberos libraries 
350  */
351 BOOL cli_credentials_set_realm(struct cli_credentials *cred, 
352                                const char *val, 
353                                enum credentials_obtained obtained)
354 {
355         if (obtained >= cred->realm_obtained) {
356                 cred->realm = strupper_talloc(cred, val);
357                 cred->realm_obtained = obtained;
358                 return True;
359         }
360
361         return False;
362 }
363
364 BOOL cli_credentials_set_realm_callback(struct cli_credentials *cred,
365                                         const char *(*realm_cb) (struct cli_credentials *))
366 {
367         if (cred->realm_obtained < CRED_CALLBACK) {
368                 cred->realm_cb = realm_cb;
369                 cred->realm_obtained = CRED_CALLBACK;
370                 return True;
371         }
372
373         return False;
374 }
375
376 /**
377  * Obtain the 'short' or 'NetBIOS' workstation name for this credentials context.
378  *
379  * @param cred credentials context
380  * @retval The workstation name set on this context. 
381  * @note Return value will never be NULL except by programmer error.
382  */
383 const char *cli_credentials_get_workstation(struct cli_credentials *cred)
384 {
385         if (cred->workstation_obtained == CRED_CALLBACK) {
386                 cred->workstation = cred->workstation_cb(cred);
387                 cred->workstation_obtained = CRED_SPECIFIED;
388         }
389
390         return cred->workstation;
391 }
392
393 BOOL cli_credentials_set_workstation(struct cli_credentials *cred, 
394                                      const char *val, 
395                                      enum credentials_obtained obtained)
396 {
397         if (obtained >= cred->workstation_obtained) {
398                 cred->workstation = talloc_strdup(cred, val);
399                 cred->workstation_obtained = obtained;
400                 return True;
401         }
402
403         return False;
404 }
405
406 BOOL cli_credentials_set_workstation_callback(struct cli_credentials *cred,
407                                               const char *(*workstation_cb) (struct cli_credentials *))
408 {
409         if (cred->workstation_obtained < CRED_CALLBACK) {
410                 cred->workstation_cb = workstation_cb;
411                 cred->workstation_obtained = CRED_CALLBACK;
412                 return True;
413         }
414
415         return False;
416 }
417
418 /**
419  * Given a string, typically obtained from a -U argument, parse it into domain, username, realm and password fields
420  *
421  * The format accepted is [domain\\]user[%password] or user[@realm][%password]
422  *
423  * @param credentials Credentials structure on which to set the password
424  * @param data the string containing the username, password etc
425  * @param obtained This enum describes how 'specified' this password is
426  */
427
428 void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained)
429 {
430         char *uname, *p;
431
432         if (strcmp("%",data) == 0) {
433                 cli_credentials_set_anonymous(credentials);
434                 return;
435         }
436
437         uname = talloc_strdup(credentials, data); 
438         if ((p = strchr_m(uname,'%'))) {
439                 *p = 0;
440                 cli_credentials_set_password(credentials, p+1, obtained);
441         }
442
443         if ((p = strchr_m(uname,'@'))) {
444                 cli_credentials_set_principal(credentials, uname, obtained);
445                 *p = 0;
446                 cli_credentials_set_realm(credentials, p+1, obtained);
447                 return;
448         } else if ((p = strchr_m(uname,'\\')) || (p = strchr_m(uname, '/'))) {
449                 *p = 0;
450                 cli_credentials_set_domain(credentials, uname, obtained);
451                 uname = p+1;
452         }
453         cli_credentials_set_username(credentials, uname, obtained);
454 }
455
456 /**
457  * Specifies default values for domain, workstation and realm
458  * from the smb.conf configuration file
459  *
460  * @param cred Credentials structure to fill in
461  */
462 void cli_credentials_set_conf(struct cli_credentials *cred)
463 {
464         cli_credentials_set_username(cred, "", CRED_UNINITIALISED);
465         cli_credentials_set_domain(cred, lp_workgroup(), CRED_UNINITIALISED);
466         cli_credentials_set_workstation(cred, lp_netbios_name(), CRED_UNINITIALISED);
467         cli_credentials_set_realm(cred, lp_realm(), CRED_UNINITIALISED);
468 }
469
470 /**
471  * Guess defaults for credentials from environment variables, 
472  * and from the configuration file
473  * 
474  * @param cred Credentials structure to fill in
475  */
476 void cli_credentials_guess(struct cli_credentials *cred)
477 {
478         char *p;
479
480         cli_credentials_set_conf(cred);
481         
482         if (getenv("LOGNAME")) {
483                 cli_credentials_set_username(cred, getenv("LOGNAME"), CRED_GUESS_ENV);
484         }
485
486         if (getenv("USER")) {
487                 cli_credentials_parse_string(cred, getenv("USER"), CRED_GUESS_ENV);
488                 if ((p = strchr_m(getenv("USER"),'%'))) {
489                         memset(p,0,strlen(cred->password));
490                 }
491         }
492
493         if (getenv("DOMAIN")) {
494                 cli_credentials_set_domain(cred, getenv("DOMAIN"), CRED_GUESS_ENV);
495         }
496
497         if (getenv("PASSWD")) {
498                 cli_credentials_set_password(cred, getenv("PASSWD"), CRED_GUESS_ENV);
499         }
500
501         if (getenv("PASSWD_FD")) {
502                 cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), CRED_GUESS_FILE);
503         }
504         
505         if (getenv("PASSWD_FILE")) {
506                 cli_credentials_parse_password_file(cred, getenv("PASSWD_FILE"), CRED_GUESS_FILE);
507         }
508
509         cli_credentials_set_ccache(cred, NULL, CRED_GUESS_FILE);
510 }
511
512 /**
513  * Attach NETLOGON credentials for use with SCHANNEL
514  */
515
516 void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, 
517                                         struct creds_CredentialState *netlogon_creds)
518 {
519         cred->netlogon_creds = talloc_reference(cred, netlogon_creds);
520 }
521
522 /**
523  * Return attached NETLOGON credentials 
524  */
525
526 struct creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred)
527 {
528         return cred->netlogon_creds;
529 }
530
531 /** 
532  * Set NETLOGON secure channel type
533  */
534
535 void cli_credentials_set_secure_channel_type(struct cli_credentials *cred,
536                                              enum netr_SchannelType secure_channel_type)
537 {
538         cred->secure_channel_type = secure_channel_type;
539 }
540
541 /**
542  * Return NETLOGON secure chanel type
543  */
544
545 enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred)
546 {
547         return cred->secure_channel_type;
548 }
549
550 /**
551  * Fill in a credentials structure as the anonymous user
552  */
553 void cli_credentials_set_anonymous(struct cli_credentials *cred) 
554 {
555         cli_credentials_set_username(cred, "", CRED_SPECIFIED);
556         cli_credentials_set_domain(cred, "", CRED_SPECIFIED);
557         cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
558 }
559
560 /**
561  * Describe a credentials context as anonymous or authenticated
562  * @retval True if anonymous, False if a username is specified
563  */
564
565 BOOL cli_credentials_is_anonymous(struct cli_credentials *cred)
566 {
567         const char *username = cli_credentials_get_username(cred);
568         
569         /* Yes, it is deliberate that we die if we have a NULL pointer
570          * here - anonymous is "", not NULL, which is 'never specified,
571          * never guessed', ie programmer bug */
572         if (!username[0]) {
573                 return True;
574         }
575
576         return False;
577 }