auth/credentials: let cli_credentials_parse_file() handle 'username' with cli_credent...
[vlendec/samba-autobuild/.git] / 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 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 "librpc/gen_ndr/samr.h" /* for struct samrPassword */
26 #include "auth/credentials/credentials.h"
27 #include "auth/credentials/credentials_internal.h"
28 #include "libcli/auth/libcli_auth.h"
29 #include "tevent.h"
30 #include "param/param.h"
31 #include "system/filesys.h"
32
33 /**
34  * Create a new credentials structure
35  * @param mem_ctx TALLOC_CTX parent for credentials structure 
36  */
37 _PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) 
38 {
39         struct cli_credentials *cred = talloc_zero(mem_ctx, struct cli_credentials);
40         if (cred == NULL) {
41                 return cred;
42         }
43
44         cred->winbind_separator = '\\';
45
46         return cred;
47 }
48
49 _PUBLIC_ void cli_credentials_set_callback_data(struct cli_credentials *cred,
50                                                 void *callback_data)
51 {
52         cred->priv_data = callback_data;
53 }
54
55 _PUBLIC_ void *_cli_credentials_callback_data(struct cli_credentials *cred)
56 {
57         return cred->priv_data;
58 }
59
60 /**
61  * Create a new anonymous credential
62  * @param mem_ctx TALLOC_CTX parent for credentials structure 
63  */
64 _PUBLIC_ struct cli_credentials *cli_credentials_init_anon(TALLOC_CTX *mem_ctx)
65 {
66         struct cli_credentials *anon_credentials;
67
68         anon_credentials = cli_credentials_init(mem_ctx);
69         cli_credentials_set_anonymous(anon_credentials);
70
71         return anon_credentials;
72 }
73
74 _PUBLIC_ void cli_credentials_set_kerberos_state(struct cli_credentials *creds, 
75                                         enum credentials_use_kerberos use_kerberos)
76 {
77         creds->use_kerberos = use_kerberos;
78 }
79
80 _PUBLIC_ void cli_credentials_set_forced_sasl_mech(struct cli_credentials *creds,
81                                                    const char *sasl_mech)
82 {
83         TALLOC_FREE(creds->forced_sasl_mech);
84         creds->forced_sasl_mech = talloc_strdup(creds, sasl_mech);
85 }
86
87 _PUBLIC_ void cli_credentials_set_krb_forwardable(struct cli_credentials *creds,
88                                                   enum credentials_krb_forwardable krb_forwardable)
89 {
90         creds->krb_forwardable = krb_forwardable;
91 }
92
93 _PUBLIC_ enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds)
94 {
95         return creds->use_kerberos;
96 }
97
98 _PUBLIC_ const char *cli_credentials_get_forced_sasl_mech(struct cli_credentials *creds)
99 {
100         return creds->forced_sasl_mech;
101 }
102
103 _PUBLIC_ enum credentials_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds)
104 {
105         return creds->krb_forwardable;
106 }
107
108 _PUBLIC_ void cli_credentials_set_gensec_features(struct cli_credentials *creds, uint32_t gensec_features)
109 {
110         creds->gensec_features = gensec_features;
111 }
112
113 _PUBLIC_ uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds)
114 {
115         return creds->gensec_features;
116 }
117
118
119 /**
120  * Obtain the username for this credentials context.
121  * @param cred credentials context
122  * @retval The username set on this context.
123  * @note Return value will never be NULL except by programmer error.
124  */
125 _PUBLIC_ const char *cli_credentials_get_username(struct cli_credentials *cred)
126 {
127         if (cred->machine_account_pending) {
128                 cli_credentials_set_machine_account(cred, 
129                                         cred->machine_account_pending_lp_ctx);
130         }
131
132         if (cred->username_obtained == CRED_CALLBACK && 
133             !cred->callback_running) {
134                 cred->callback_running = true;
135                 cred->username = cred->username_cb(cred);
136                 cred->callback_running = false;
137                 if (cred->username_obtained == CRED_CALLBACK) {
138                         cred->username_obtained = CRED_CALLBACK_RESULT;
139                         cli_credentials_invalidate_ccache(cred, cred->username_obtained);
140                 }
141         }
142
143         return cred->username;
144 }
145
146 _PUBLIC_ bool cli_credentials_set_username(struct cli_credentials *cred, 
147                                   const char *val, enum credentials_obtained obtained)
148 {
149         if (obtained >= cred->username_obtained) {
150                 cred->username = talloc_strdup(cred, val);
151                 cred->username_obtained = obtained;
152                 cli_credentials_invalidate_ccache(cred, cred->username_obtained);
153                 return true;
154         }
155
156         return false;
157 }
158
159 _PUBLIC_ bool cli_credentials_set_username_callback(struct cli_credentials *cred,
160                                   const char *(*username_cb) (struct cli_credentials *))
161 {
162         if (cred->username_obtained < CRED_CALLBACK) {
163                 cred->username_cb = username_cb;
164                 cred->username_obtained = CRED_CALLBACK;
165                 return true;
166         }
167
168         return false;
169 }
170
171 _PUBLIC_ bool cli_credentials_set_bind_dn(struct cli_credentials *cred, 
172                                  const char *bind_dn)
173 {
174         cred->bind_dn = talloc_strdup(cred, bind_dn);
175         return true;
176 }
177
178 /**
179  * Obtain the BIND DN for this credentials context.
180  * @param cred credentials context
181  * @retval The username set on this context.
182  * @note Return value will be NULL if not specified explictly
183  */
184 _PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred)
185 {
186         return cred->bind_dn;
187 }
188
189
190 /**
191  * Obtain the client principal for this credentials context.
192  * @param cred credentials context
193  * @retval The username set on this context.
194  * @note Return value will never be NULL except by programmer error.
195  */
196 _PUBLIC_ const char *cli_credentials_get_principal_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained)
197 {
198         if (cred->machine_account_pending) {
199                 cli_credentials_set_machine_account(cred,
200                                         cred->machine_account_pending_lp_ctx);
201         }
202
203         if (cred->principal_obtained == CRED_CALLBACK && 
204             !cred->callback_running) {
205                 cred->callback_running = true;
206                 cred->principal = cred->principal_cb(cred);
207                 cred->callback_running = false;
208                 if (cred->principal_obtained == CRED_CALLBACK) {
209                         cred->principal_obtained = CRED_CALLBACK_RESULT;
210                         cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
211                 }
212         }
213
214         if (cred->principal_obtained < cred->username_obtained
215             || cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) {
216                 const char *effective_username = NULL;
217                 const char *effective_realm = NULL;
218                 enum credentials_obtained effective_obtained;
219
220                 effective_username = cli_credentials_get_username(cred);
221                 if (effective_username == NULL || strlen(effective_username) == 0) {
222                         *obtained = cred->username_obtained;
223                         return NULL;
224                 }
225
226                 if (cred->domain_obtained > cred->realm_obtained) {
227                         effective_realm = cli_credentials_get_domain(cred);
228                         effective_obtained = MIN(cred->domain_obtained,
229                                                  cred->username_obtained);
230                 } else {
231                         effective_realm = cli_credentials_get_realm(cred);
232                         effective_obtained = MIN(cred->realm_obtained,
233                                                  cred->username_obtained);
234                 }
235
236                 if (effective_realm == NULL || strlen(effective_realm) == 0) {
237                         effective_realm = cli_credentials_get_domain(cred);
238                         effective_obtained = MIN(cred->domain_obtained,
239                                                  cred->username_obtained);
240                 }
241
242                 if (effective_realm != NULL && strlen(effective_realm) != 0) {
243                         *obtained = effective_obtained;
244                         return talloc_asprintf(mem_ctx, "%s@%s", 
245                                                effective_username,
246                                                effective_realm);
247                 }
248         }
249         *obtained = cred->principal_obtained;
250         return talloc_strdup(mem_ctx, cred->principal);
251 }
252
253 /**
254  * Obtain the client principal for this credentials context.
255  * @param cred credentials context
256  * @retval The username set on this context.
257  * @note Return value will never be NULL except by programmer error.
258  */
259 _PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
260 {
261         enum credentials_obtained obtained;
262         return cli_credentials_get_principal_and_obtained(cred, mem_ctx, &obtained);
263 }
264
265 _PUBLIC_ bool cli_credentials_set_principal(struct cli_credentials *cred, 
266                                    const char *val, 
267                                    enum credentials_obtained obtained)
268 {
269         if (obtained >= cred->principal_obtained) {
270                 cred->principal = talloc_strdup(cred, val);
271                 cred->principal_obtained = obtained;
272                 cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
273                 return true;
274         }
275
276         return false;
277 }
278
279 /* Set a callback to get the principal.  This could be a popup dialog,
280  * a terminal prompt or similar.  */
281 _PUBLIC_ bool cli_credentials_set_principal_callback(struct cli_credentials *cred,
282                                   const char *(*principal_cb) (struct cli_credentials *))
283 {
284         if (cred->principal_obtained < CRED_CALLBACK) {
285                 cred->principal_cb = principal_cb;
286                 cred->principal_obtained = CRED_CALLBACK;
287                 return true;
288         }
289
290         return false;
291 }
292
293 /* Some of our tools are 'anonymous by default'.  This is a single
294  * function to determine if authentication has been explicitly
295  * requested */
296
297 _PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *cred) 
298 {
299         if (cred->bind_dn) {
300                 return true;
301         }
302
303         /*
304          * If we forced the mech we clearly want authentication. E.g. to use
305          * SASL/EXTERNAL which has no credentials.
306          */
307         if (cred->forced_sasl_mech) {
308                 return true;
309         }
310
311         if (cli_credentials_is_anonymous(cred)){
312                 return false;
313         }
314
315         if (cred->principal_obtained >= CRED_SPECIFIED) {
316                 return true;
317         }
318         if (cred->username_obtained >= CRED_SPECIFIED) {
319                 return true;
320         }
321
322         if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
323                 return true;
324         }
325
326         return false;
327 }
328
329 /**
330  * Obtain the password for this credentials context.
331  * @param cred credentials context
332  * @retval If set, the cleartext password, otherwise NULL
333  */
334 _PUBLIC_ const char *cli_credentials_get_password(struct cli_credentials *cred)
335 {
336         if (cred->machine_account_pending) {
337                 cli_credentials_set_machine_account(cred,
338                                                     cred->machine_account_pending_lp_ctx);
339         }
340
341         if (cred->password_obtained == CRED_CALLBACK && 
342             !cred->callback_running &&
343             !cred->password_will_be_nt_hash) {
344                 cred->callback_running = true;
345                 cred->password = cred->password_cb(cred);
346                 cred->callback_running = false;
347                 if (cred->password_obtained == CRED_CALLBACK) {
348                         cred->password_obtained = CRED_CALLBACK_RESULT;
349                         cli_credentials_invalidate_ccache(cred, cred->password_obtained);
350                 }
351         }
352
353         return cred->password;
354 }
355
356 /* Set a password on the credentials context, including an indication
357  * of 'how' the password was obtained */
358
359 _PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred, 
360                                   const char *val, 
361                                   enum credentials_obtained obtained)
362 {
363         if (obtained >= cred->password_obtained) {
364
365                 cred->lm_response = data_blob_null;
366                 cred->nt_response = data_blob_null;
367                 cred->nt_hash = NULL;
368                 cred->password = NULL;
369
370                 cli_credentials_invalidate_ccache(cred, obtained);
371
372                 cred->password_tries = 0;
373
374                 if (val == NULL) {
375                         cred->password_obtained = obtained;
376                         return true;
377                 }
378
379                 if (cred->password_will_be_nt_hash) {
380                         struct samr_Password *nt_hash = NULL;
381                         size_t val_len = strlen(val);
382                         size_t converted;
383
384                         nt_hash = talloc(cred, struct samr_Password);
385                         if (nt_hash == NULL) {
386                                 return false;
387                         }
388
389                         converted = strhex_to_str((char *)nt_hash->hash,
390                                                   sizeof(nt_hash->hash),
391                                                   val, val_len);
392                         if (converted != sizeof(nt_hash->hash)) {
393                                 TALLOC_FREE(nt_hash);
394                                 return false;
395                         }
396
397                         cred->nt_hash = nt_hash;
398                         cred->password_obtained = obtained;
399                         return true;
400                 }
401
402                 cred->password = talloc_strdup(cred, val);
403                 if (cred->password == NULL) {
404                         return false;
405                 }
406
407                 /* Don't print the actual password in talloc memory dumps */
408                 talloc_set_name_const(cred->password,
409                         "password set via cli_credentials_set_password");
410                 cred->password_obtained = obtained;
411
412                 return true;
413         }
414
415         return false;
416 }
417
418 _PUBLIC_ bool cli_credentials_set_password_callback(struct cli_credentials *cred,
419                                            const char *(*password_cb) (struct cli_credentials *))
420 {
421         if (cred->password_obtained < CRED_CALLBACK) {
422                 cred->password_tries = 3;
423                 cred->password_cb = password_cb;
424                 cred->password_obtained = CRED_CALLBACK;
425                 cli_credentials_invalidate_ccache(cred, cred->password_obtained);
426                 return true;
427         }
428
429         return false;
430 }
431
432 /**
433  * Obtain the 'old' password for this credentials context (used for join accounts).
434  * @param cred credentials context
435  * @retval If set, the cleartext password, otherwise NULL
436  */
437 _PUBLIC_ const char *cli_credentials_get_old_password(struct cli_credentials *cred)
438 {
439         if (cred->machine_account_pending) {
440                 cli_credentials_set_machine_account(cred,
441                                                     cred->machine_account_pending_lp_ctx);
442         }
443
444         return cred->old_password;
445 }
446
447 _PUBLIC_ bool cli_credentials_set_old_password(struct cli_credentials *cred, 
448                                       const char *val, 
449                                       enum credentials_obtained obtained)
450 {
451         cred->old_password = talloc_strdup(cred, val);
452         if (cred->old_password) {
453                 /* Don't print the actual password in talloc memory dumps */
454                 talloc_set_name_const(cred->old_password, "password set via cli_credentials_set_old_password");
455         }
456         cred->old_nt_hash = NULL;
457         return true;
458 }
459
460 /**
461  * Obtain the password, in the form MD4(unicode(password)) for this credentials context.
462  *
463  * Sometimes we only have this much of the password, while the rest of
464  * the time this call avoids calling E_md4hash themselves.
465  *
466  * @param cred credentials context
467  * @retval If set, the cleartext password, otherwise NULL
468  */
469 _PUBLIC_ struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred,
470                                                            TALLOC_CTX *mem_ctx)
471 {
472         enum credentials_obtained password_obtained;
473         enum credentials_obtained ccache_threshold;
474         enum credentials_obtained client_gss_creds_threshold;
475         bool password_is_nt_hash;
476         const char *password = NULL;
477         struct samr_Password *nt_hash = NULL;
478
479         if (cred->nt_hash != NULL) {
480                 /*
481                  * If we already have a hash it's easy.
482                  */
483                 goto return_hash;
484         }
485
486         /*
487          * This is a bit tricky, with password_will_be_nt_hash
488          * we still need to get the value via the password_callback
489          * but if we did that we should not remember it's state
490          * in the long run so we need to undo it.
491          */
492
493         password_obtained = cred->password_obtained;
494         ccache_threshold = cred->ccache_threshold;
495         client_gss_creds_threshold = cred->client_gss_creds_threshold;
496         password_is_nt_hash = cred->password_will_be_nt_hash;
497
498         cred->password_will_be_nt_hash = false;
499         password = cli_credentials_get_password(cred);
500
501         cred->password_will_be_nt_hash = password_is_nt_hash;
502         if (password_is_nt_hash && password_obtained == CRED_CALLBACK) {
503                 /*
504                  * We got the nt_hash as string via the callback,
505                  * so we need to undo the state change.
506                  *
507                  * And also don't remember it as plaintext password.
508                  */
509                 cred->client_gss_creds_threshold = client_gss_creds_threshold;
510                 cred->ccache_threshold = ccache_threshold;
511                 cred->password_obtained = password_obtained;
512                 cred->password = NULL;
513         }
514
515         if (password == NULL) {
516                 return NULL;
517         }
518
519         nt_hash = talloc(cred, struct samr_Password);
520         if (nt_hash == NULL) {
521                 return NULL;
522         }
523
524         if (password_is_nt_hash) {
525                 size_t password_len = strlen(password);
526                 size_t converted;
527
528                 converted = strhex_to_str((char *)nt_hash->hash,
529                                           sizeof(nt_hash->hash),
530                                           password, password_len);
531                 if (converted != sizeof(nt_hash->hash)) {
532                         TALLOC_FREE(nt_hash);
533                         return false;
534                 }
535         } else {
536                 E_md4hash(password, nt_hash->hash);
537         }
538
539         cred->nt_hash = nt_hash;
540         nt_hash = NULL;
541
542 return_hash:
543         nt_hash = talloc(mem_ctx, struct samr_Password);
544         if (nt_hash == NULL) {
545                 return NULL;
546         }
547
548         *nt_hash = *cred->nt_hash;
549
550         return nt_hash;
551 }
552
553 /**
554  * Obtain the old password, in the form MD4(unicode(password)) for this credentials context.
555  *
556  * Sometimes we only have this much of the password, while the rest of
557  * the time this call avoids calling E_md4hash themselves.
558  *
559  * @param cred credentials context
560  * @retval If set, the cleartext password, otherwise NULL
561  */
562 _PUBLIC_ struct samr_Password *cli_credentials_get_old_nt_hash(struct cli_credentials *cred,
563                                                                TALLOC_CTX *mem_ctx)
564 {
565         const char *old_password = NULL;
566
567         if (cred->old_nt_hash != NULL) {
568                 struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password);
569                 if (!nt_hash) {
570                         return NULL;
571                 }
572
573                 *nt_hash = *cred->old_nt_hash;
574
575                 return nt_hash;
576         }
577
578         old_password = cli_credentials_get_old_password(cred);
579         if (old_password) {
580                 struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password);
581                 if (!nt_hash) {
582                         return NULL;
583                 }
584
585                 E_md4hash(old_password, nt_hash->hash);
586
587                 return nt_hash;
588         }
589
590         return NULL;
591 }
592
593 /**
594  * Obtain the 'short' or 'NetBIOS' domain for this credentials context.
595  * @param cred credentials context
596  * @retval The domain set on this context. 
597  * @note Return value will never be NULL except by programmer error.
598  */
599 _PUBLIC_ const char *cli_credentials_get_domain(struct cli_credentials *cred)
600 {
601         if (cred->machine_account_pending) {
602                 cli_credentials_set_machine_account(cred,
603                                                     cred->machine_account_pending_lp_ctx);
604         }
605
606         if (cred->domain_obtained == CRED_CALLBACK && 
607             !cred->callback_running) {
608                 cred->callback_running = true;
609                 cred->domain = cred->domain_cb(cred);
610                 cred->callback_running = false;
611                 if (cred->domain_obtained == CRED_CALLBACK) {
612                         cred->domain_obtained = CRED_CALLBACK_RESULT;
613                         cli_credentials_invalidate_ccache(cred, cred->domain_obtained);
614                 }
615         }
616
617         return cred->domain;
618 }
619
620
621 _PUBLIC_ bool cli_credentials_set_domain(struct cli_credentials *cred, 
622                                 const char *val, 
623                                 enum credentials_obtained obtained)
624 {
625         if (obtained >= cred->domain_obtained) {
626                 /* it is important that the domain be in upper case,
627                  * particularly for the sensitive NTLMv2
628                  * calculations */
629                 cred->domain = strupper_talloc(cred, val);
630                 cred->domain_obtained = obtained;
631                 /* setting domain does not mean we have to invalidate ccache 
632                  * because domain in not used for Kerberos operations.
633                  * If ccache invalidation is required, one will anyway specify
634                  * a password to kinit, and that will force invalidation of the ccache
635                  */
636                 return true;
637         }
638
639         return false;
640 }
641
642 bool cli_credentials_set_domain_callback(struct cli_credentials *cred,
643                                          const char *(*domain_cb) (struct cli_credentials *))
644 {
645         if (cred->domain_obtained < CRED_CALLBACK) {
646                 cred->domain_cb = domain_cb;
647                 cred->domain_obtained = CRED_CALLBACK;
648                 return true;
649         }
650
651         return false;
652 }
653
654 /**
655  * Obtain the Kerberos realm for this credentials context.
656  * @param cred credentials context
657  * @retval The realm set on this context. 
658  * @note Return value will never be NULL except by programmer error.
659  */
660 _PUBLIC_ const char *cli_credentials_get_realm(struct cli_credentials *cred)
661 {       
662         if (cred->machine_account_pending) {
663                 cli_credentials_set_machine_account(cred,
664                                                     cred->machine_account_pending_lp_ctx);
665         }
666
667         if (cred->realm_obtained == CRED_CALLBACK && 
668             !cred->callback_running) {
669                 cred->callback_running = true;
670                 cred->realm = cred->realm_cb(cred);
671                 cred->callback_running = false;
672                 if (cred->realm_obtained == CRED_CALLBACK) {
673                         cred->realm_obtained = CRED_CALLBACK_RESULT;
674                         cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
675                 }
676         }
677
678         return cred->realm;
679 }
680
681 /**
682  * Set the realm for this credentials context, and force it to
683  * uppercase for the sainity of our local kerberos libraries 
684  */
685 _PUBLIC_ bool cli_credentials_set_realm(struct cli_credentials *cred, 
686                                const char *val, 
687                                enum credentials_obtained obtained)
688 {
689         if (obtained >= cred->realm_obtained) {
690                 cred->realm = strupper_talloc(cred, val);
691                 cred->realm_obtained = obtained;
692                 cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
693                 return true;
694         }
695
696         return false;
697 }
698
699 bool cli_credentials_set_realm_callback(struct cli_credentials *cred,
700                                         const char *(*realm_cb) (struct cli_credentials *))
701 {
702         if (cred->realm_obtained < CRED_CALLBACK) {
703                 cred->realm_cb = realm_cb;
704                 cred->realm_obtained = CRED_CALLBACK;
705                 return true;
706         }
707
708         return false;
709 }
710
711 /**
712  * Obtain the 'short' or 'NetBIOS' workstation name for this credentials context.
713  *
714  * @param cred credentials context
715  * @retval The workstation name set on this context. 
716  * @note Return value will never be NULL except by programmer error.
717  */
718 _PUBLIC_ const char *cli_credentials_get_workstation(struct cli_credentials *cred)
719 {
720         if (cred->workstation_obtained == CRED_CALLBACK && 
721             !cred->callback_running) {
722                 cred->callback_running = true;
723                 cred->workstation = cred->workstation_cb(cred);
724                 cred->callback_running = false;
725                 if (cred->workstation_obtained == CRED_CALLBACK) {
726                         cred->workstation_obtained = CRED_CALLBACK_RESULT;
727                 }
728         }
729
730         return cred->workstation;
731 }
732
733 _PUBLIC_ bool cli_credentials_set_workstation(struct cli_credentials *cred, 
734                                      const char *val, 
735                                      enum credentials_obtained obtained)
736 {
737         if (obtained >= cred->workstation_obtained) {
738                 cred->workstation = talloc_strdup(cred, val);
739                 cred->workstation_obtained = obtained;
740                 return true;
741         }
742
743         return false;
744 }
745
746 bool cli_credentials_set_workstation_callback(struct cli_credentials *cred,
747                                               const char *(*workstation_cb) (struct cli_credentials *))
748 {
749         if (cred->workstation_obtained < CRED_CALLBACK) {
750                 cred->workstation_cb = workstation_cb;
751                 cred->workstation_obtained = CRED_CALLBACK;
752                 return true;
753         }
754
755         return false;
756 }
757
758 /**
759  * Given a string, typically obtained from a -U argument, parse it into domain, username, realm and password fields
760  *
761  * The format accepted is [domain\\]user[%password] or user[@realm][%password]
762  *
763  * @param credentials Credentials structure on which to set the password
764  * @param data the string containing the username, password etc
765  * @param obtained This enum describes how 'specified' this password is
766  */
767
768 _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained)
769 {
770         char *uname, *p;
771
772         if (strcmp("%",data) == 0) {
773                 cli_credentials_set_anonymous(credentials);
774                 return;
775         }
776
777         uname = talloc_strdup(credentials, data); 
778         if ((p = strchr_m(uname,'%'))) {
779                 *p = 0;
780                 cli_credentials_set_password(credentials, p+1, obtained);
781         }
782
783         if ((p = strchr_m(uname,'@'))) {
784                 /*
785                  * We also need to set username and domain
786                  * in order to undo the effect of
787                  * cli_credentials_guess().
788                  */
789                 cli_credentials_set_username(credentials, uname, obtained);
790                 cli_credentials_set_domain(credentials, "", obtained);
791
792                 cli_credentials_set_principal(credentials, uname, obtained);
793                 *p = 0;
794                 cli_credentials_set_realm(credentials, p+1, obtained);
795                 return;
796         } else if ((p = strchr_m(uname,'\\'))
797                    || (p = strchr_m(uname, '/'))
798                    || (p = strchr_m(uname, credentials->winbind_separator)))
799         {
800                 const char *domain = NULL;
801
802                 domain = uname;
803                 *p = 0;
804                 uname = p+1;
805
806                 if (obtained == credentials->realm_obtained &&
807                     !strequal_m(credentials->domain, domain))
808                 {
809                         /*
810                          * We need to undo a former set with the same level
811                          * in order to get the expected result from
812                          * cli_credentials_get_principal().
813                          *
814                          * But we only need to do that if the domain
815                          * actually changes.
816                          */
817                         cli_credentials_set_realm(credentials, domain, obtained);
818                 }
819                 cli_credentials_set_domain(credentials, domain, obtained);
820         }
821         if (obtained == credentials->principal_obtained &&
822             !strequal_m(credentials->username, uname))
823         {
824                 /*
825                  * We need to undo a former set with the same level
826                  * in order to get the expected result from
827                  * cli_credentials_get_principal().
828                  *
829                  * But we only need to do that if the username
830                  * actually changes.
831                  */
832                 credentials->principal_obtained = CRED_UNINITIALISED;
833                 credentials->principal = NULL;
834         }
835         cli_credentials_set_username(credentials, uname, obtained);
836 }
837
838 /**
839  * Given a a credentials structure, print it as a string
840  *
841  * The format output is [domain\\]user[%password] or user[@realm][%password]
842  *
843  * @param credentials Credentials structure on which to set the password
844  * @param mem_ctx The memory context to place the result on
845  */
846
847 _PUBLIC_ const char *cli_credentials_get_unparsed_name(struct cli_credentials *credentials, TALLOC_CTX *mem_ctx)
848 {
849         const char *bind_dn = cli_credentials_get_bind_dn(credentials);
850         const char *domain;
851         const char *username;
852         const char *name;
853
854         if (bind_dn) {
855                 name = talloc_strdup(mem_ctx, bind_dn);
856         } else {
857                 cli_credentials_get_ntlm_username_domain(credentials, mem_ctx, &username, &domain);
858                 if (domain && domain[0]) {
859                         name = talloc_asprintf(mem_ctx, "%s\\%s", 
860                                                domain, username);
861                 } else {
862                         name = talloc_asprintf(mem_ctx, "%s", 
863                                                username);
864                 }
865         }
866         return name;
867 }
868
869 /**
870  * Specifies default values for domain, workstation and realm
871  * from the smb.conf configuration file
872  *
873  * @param cred Credentials structure to fill in
874  */
875 _PUBLIC_ void cli_credentials_set_conf(struct cli_credentials *cred, 
876                               struct loadparm_context *lp_ctx)
877 {
878         const char *sep = NULL;
879         const char *realm = lpcfg_realm(lp_ctx);
880
881         cli_credentials_set_username(cred, "", CRED_UNINITIALISED);
882         if (lpcfg_parm_is_cmdline(lp_ctx, "workgroup")) {
883                 cli_credentials_set_domain(cred, lpcfg_workgroup(lp_ctx), CRED_SPECIFIED);
884         } else {
885                 cli_credentials_set_domain(cred, lpcfg_workgroup(lp_ctx), CRED_UNINITIALISED);
886         }
887         if (lpcfg_parm_is_cmdline(lp_ctx, "netbios name")) {
888                 cli_credentials_set_workstation(cred, lpcfg_netbios_name(lp_ctx), CRED_SPECIFIED);
889         } else {
890                 cli_credentials_set_workstation(cred, lpcfg_netbios_name(lp_ctx), CRED_UNINITIALISED);
891         }
892         if (realm != NULL && strlen(realm) == 0) {
893                 realm = NULL;
894         }
895         if (lpcfg_parm_is_cmdline(lp_ctx, "realm")) {
896                 cli_credentials_set_realm(cred, realm, CRED_SPECIFIED);
897         } else {
898                 cli_credentials_set_realm(cred, realm, CRED_UNINITIALISED);
899         }
900
901         sep = lpcfg_winbind_separator(lp_ctx);
902         if (sep != NULL && sep[0] != '\0') {
903                 cred->winbind_separator = *lpcfg_winbind_separator(lp_ctx);
904         }
905 }
906
907 /**
908  * Guess defaults for credentials from environment variables, 
909  * and from the configuration file
910  * 
911  * @param cred Credentials structure to fill in
912  */
913 _PUBLIC_ void cli_credentials_guess(struct cli_credentials *cred,
914                            struct loadparm_context *lp_ctx)
915 {
916         char *p;
917         const char *error_string;
918
919         if (lp_ctx != NULL) {
920                 cli_credentials_set_conf(cred, lp_ctx);
921         }
922         
923         if (getenv("LOGNAME")) {
924                 cli_credentials_set_username(cred, getenv("LOGNAME"), CRED_GUESS_ENV);
925         }
926
927         if (getenv("USER")) {
928                 cli_credentials_parse_string(cred, getenv("USER"), CRED_GUESS_ENV);
929                 if ((p = strchr_m(getenv("USER"),'%'))) {
930                         memset(p,0,strlen(cred->password));
931                 }
932         }
933
934         if (getenv("PASSWD")) {
935                 cli_credentials_set_password(cred, getenv("PASSWD"), CRED_GUESS_ENV);
936         }
937
938         if (getenv("PASSWD_FD")) {
939                 cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), 
940                                                   CRED_GUESS_FILE);
941         }
942         
943         p = getenv("PASSWD_FILE");
944         if (p && p[0]) {
945                 cli_credentials_parse_password_file(cred, p, CRED_GUESS_FILE);
946         }
947         
948         if (cli_credentials_get_kerberos_state(cred) != CRED_DONT_USE_KERBEROS) {
949                 cli_credentials_set_ccache(cred, lp_ctx, NULL, CRED_GUESS_FILE,
950                                            &error_string);
951         }
952 }
953
954 /**
955  * Attach NETLOGON credentials for use with SCHANNEL
956  */
957
958 _PUBLIC_ void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, 
959                                                  struct netlogon_creds_CredentialState *netlogon_creds)
960 {
961         TALLOC_FREE(cred->netlogon_creds);
962         if (netlogon_creds == NULL) {
963                 return;
964         }
965         cred->netlogon_creds = netlogon_creds_copy(cred, netlogon_creds);
966 }
967
968 /**
969  * Return attached NETLOGON credentials 
970  */
971
972 _PUBLIC_ struct netlogon_creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred)
973 {
974         return cred->netlogon_creds;
975 }
976
977 /** 
978  * Set NETLOGON secure channel type
979  */
980
981 _PUBLIC_ void cli_credentials_set_secure_channel_type(struct cli_credentials *cred,
982                                              enum netr_SchannelType secure_channel_type)
983 {
984         cred->secure_channel_type = secure_channel_type;
985 }
986
987 /**
988  * Return NETLOGON secure chanel type
989  */
990
991 _PUBLIC_ time_t cli_credentials_get_password_last_changed_time(struct cli_credentials *cred)
992 {
993         return cred->password_last_changed_time;
994 }
995
996 /** 
997  * Set NETLOGON secure channel type
998  */
999
1000 _PUBLIC_ void cli_credentials_set_password_last_changed_time(struct cli_credentials *cred,
1001                                                              time_t last_changed_time)
1002 {
1003         cred->password_last_changed_time = last_changed_time;
1004 }
1005
1006 /**
1007  * Return NETLOGON secure chanel type
1008  */
1009
1010 _PUBLIC_ enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred)
1011 {
1012         return cred->secure_channel_type;
1013 }
1014
1015 /**
1016  * Fill in a credentials structure as the anonymous user
1017  */
1018 _PUBLIC_ void cli_credentials_set_anonymous(struct cli_credentials *cred) 
1019 {
1020         cli_credentials_set_username(cred, "", CRED_SPECIFIED);
1021         cli_credentials_set_domain(cred, "", CRED_SPECIFIED);
1022         cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
1023         cli_credentials_set_principal(cred, NULL, CRED_SPECIFIED);
1024         cli_credentials_set_realm(cred, NULL, CRED_SPECIFIED);
1025         cli_credentials_set_workstation(cred, "", CRED_UNINITIALISED);
1026         cli_credentials_set_kerberos_state(cred, CRED_DONT_USE_KERBEROS);
1027 }
1028
1029 /**
1030  * Describe a credentials context as anonymous or authenticated
1031  * @retval true if anonymous, false if a username is specified
1032  */
1033
1034 _PUBLIC_ bool cli_credentials_is_anonymous(struct cli_credentials *cred)
1035 {
1036         const char *username;
1037         
1038         /* if bind dn is set it's not anonymous */
1039         if (cred->bind_dn) {
1040                 return false;
1041         }
1042
1043         if (cred->machine_account_pending) {
1044                 cli_credentials_set_machine_account(cred,
1045                                                     cred->machine_account_pending_lp_ctx);
1046         }
1047
1048         /* if principal is set, it's not anonymous */
1049         if ((cred->principal != NULL) && cred->principal_obtained >= cred->username_obtained) {
1050                 return false;
1051         }
1052
1053         username = cli_credentials_get_username(cred);
1054         
1055         /* Yes, it is deliberate that we die if we have a NULL pointer
1056          * here - anonymous is "", not NULL, which is 'never specified,
1057          * never guessed', ie programmer bug */
1058         if (!username[0]) {
1059                 return true;
1060         }
1061
1062         return false;
1063 }
1064
1065 /**
1066  * Mark the current password for a credentials struct as wrong. This will 
1067  * cause the password to be prompted again (if a callback is set).
1068  *
1069  * This will decrement the number of times the password can be tried.
1070  *
1071  * @retval whether the credentials struct is finished
1072  */
1073 _PUBLIC_ bool cli_credentials_wrong_password(struct cli_credentials *cred)
1074 {
1075         if (cred->password_obtained != CRED_CALLBACK_RESULT) {
1076                 return false;
1077         }
1078
1079         if (cred->password_tries == 0) {
1080                 return false;
1081         }
1082
1083         cred->password_tries--;
1084
1085         if (cred->password_tries == 0) {
1086                 return false;
1087         }
1088
1089         cred->password_obtained = CRED_CALLBACK;
1090         return true;
1091 }
1092
1093 _PUBLIC_ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
1094                                               const char **username, 
1095                                               const char **domain) 
1096 {
1097         if (cred->principal_obtained > cred->username_obtained) {
1098                 *domain = talloc_strdup(mem_ctx, "");
1099                 *username = cli_credentials_get_principal(cred, mem_ctx);
1100         } else {
1101                 *domain = cli_credentials_get_domain(cred);
1102                 *username = cli_credentials_get_username(cred);
1103         }
1104 }
1105
1106 /**
1107  * Read a named file, and parse it for username, domain, realm and password
1108  *
1109  * @param credentials Credentials structure on which to set the password
1110  * @param file a named file to read the details from 
1111  * @param obtained This enum describes how 'specified' this password is
1112  */
1113
1114 _PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const char *file, enum credentials_obtained obtained) 
1115 {
1116         uint16_t len = 0;
1117         char *ptr, *val, *param;
1118         char **lines;
1119         int i, numlines;
1120
1121         lines = file_lines_load(file, &numlines, 0, NULL);
1122
1123         if (lines == NULL)
1124         {
1125                 /* fail if we can't open the credentials file */
1126                 d_printf("ERROR: Unable to open credentials file!\n");
1127                 return false;
1128         }
1129
1130         for (i = 0; i < numlines; i++) {
1131                 len = strlen(lines[i]);
1132
1133                 if (len == 0)
1134                         continue;
1135
1136                 /* break up the line into parameter & value.
1137                  * will need to eat a little whitespace possibly */
1138                 param = lines[i];
1139                 if (!(ptr = strchr_m (lines[i], '=')))
1140                         continue;
1141
1142                 val = ptr+1;
1143                 *ptr = '\0';
1144
1145                 /* eat leading white space */
1146                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
1147                         val++;
1148
1149                 if (strwicmp("password", param) == 0) {
1150                         cli_credentials_set_password(cred, val, obtained);
1151                 } else if (strwicmp("username", param) == 0) {
1152                         cli_credentials_parse_string(cred, val, obtained);
1153                 } else if (strwicmp("domain", param) == 0) {
1154                         cli_credentials_set_domain(cred, val, obtained);
1155                 } else if (strwicmp("realm", param) == 0) {
1156                         cli_credentials_set_realm(cred, val, obtained);
1157                 }
1158                 memset(lines[i], 0, len);
1159         }
1160
1161         talloc_free(lines);
1162
1163         return true;
1164 }
1165
1166 /**
1167  * Read a named file, and parse it for a password
1168  *
1169  * @param credentials Credentials structure on which to set the password
1170  * @param file a named file to read the password from 
1171  * @param obtained This enum describes how 'specified' this password is
1172  */
1173
1174 _PUBLIC_ bool cli_credentials_parse_password_file(struct cli_credentials *credentials, const char *file, enum credentials_obtained obtained)
1175 {
1176         int fd = open(file, O_RDONLY, 0);
1177         bool ret;
1178
1179         if (fd < 0) {
1180                 fprintf(stderr, "Error opening password file %s: %s\n",
1181                                 file, strerror(errno));
1182                 return false;
1183         }
1184
1185         ret = cli_credentials_parse_password_fd(credentials, fd, obtained);
1186
1187         close(fd);
1188         
1189         return ret;
1190 }
1191
1192
1193 /**
1194  * Read a file descriptor, and parse it for a password (eg from a file or stdin)
1195  *
1196  * @param credentials Credentials structure on which to set the password
1197  * @param fd open file descriptor to read the password from 
1198  * @param obtained This enum describes how 'specified' this password is
1199  */
1200
1201 _PUBLIC_ bool cli_credentials_parse_password_fd(struct cli_credentials *credentials, 
1202                                        int fd, enum credentials_obtained obtained)
1203 {
1204         char *p;
1205         char pass[128];
1206
1207         for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
1208                 p && p - pass < sizeof(pass);) {
1209                 switch (read(fd, p, 1)) {
1210                 case 1:
1211                         if (*p != '\n' && *p != '\0') {
1212                                 *++p = '\0'; /* advance p, and null-terminate pass */
1213                                 break;
1214                         }
1215                         /* fall through */
1216                 case 0:
1217                         if (p - pass) {
1218                                 *p = '\0'; /* null-terminate it, just in case... */
1219                                 p = NULL; /* then force the loop condition to become false */
1220                                 break;
1221                         } else {
1222                                 fprintf(stderr, "Error reading password from file descriptor %d: %s\n", fd, "empty password\n");
1223                                 return false;
1224                         }
1225
1226                 default:
1227                         fprintf(stderr, "Error reading password from file descriptor %d: %s\n",
1228                                         fd, strerror(errno));
1229                         return false;
1230                 }
1231         }
1232
1233         cli_credentials_set_password(credentials, pass, obtained);
1234         return true;
1235 }
1236
1237