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