Merge Samba3 and Samba4 together
[sfrench/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 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_krb5.h"
28 #include "libcli/auth/libcli_auth.h"
29 #include "lib/events/events.h"
30 #include "param/param.h"
31
32 /**
33  * Create a new credentials structure
34  * @param mem_ctx TALLOC_CTX parent for credentials structure 
35  */
36 _PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) 
37 {
38         struct cli_credentials *cred = talloc(mem_ctx, struct cli_credentials);
39         if (!cred) {
40                 return cred;
41         }
42
43         cred->netlogon_creds = NULL;
44         cred->machine_account_pending = false;
45         cred->workstation_obtained = CRED_UNINITIALISED;
46         cred->username_obtained = CRED_UNINITIALISED;
47         cred->password_obtained = CRED_UNINITIALISED;
48         cred->domain_obtained = CRED_UNINITIALISED;
49         cred->realm_obtained = CRED_UNINITIALISED;
50         cred->ccache_obtained = CRED_UNINITIALISED;
51         cred->client_gss_creds_obtained = CRED_UNINITIALISED;
52         cred->server_gss_creds_obtained = CRED_UNINITIALISED;
53         cred->keytab_obtained = CRED_UNINITIALISED;
54         cred->principal_obtained = CRED_UNINITIALISED;
55
56         cred->ccache_threshold = CRED_UNINITIALISED;
57         cred->client_gss_creds_threshold = CRED_UNINITIALISED;
58
59         cred->old_password = NULL;
60         cred->smb_krb5_context = NULL;
61         cred->salt_principal = NULL;
62         cred->machine_account = false;
63
64         cred->bind_dn = NULL;
65
66         cred->tries = 3;
67         cred->callback_running = false;
68
69         cli_credentials_set_kerberos_state(cred, CRED_AUTO_USE_KERBEROS);
70         cli_credentials_set_gensec_features(cred, 0);
71
72         return cred;
73 }
74
75 /**
76  * Create a new anonymous credential
77  * @param mem_ctx TALLOC_CTX parent for credentials structure 
78  */
79 _PUBLIC_ struct cli_credentials *cli_credentials_init_anon(TALLOC_CTX *mem_ctx)
80 {
81         struct cli_credentials *anon_credentials;
82
83         anon_credentials = cli_credentials_init(mem_ctx);
84         cli_credentials_set_anonymous(anon_credentials);
85
86         return anon_credentials;
87 }
88
89 _PUBLIC_ void cli_credentials_set_kerberos_state(struct cli_credentials *creds, 
90                                         enum credentials_use_kerberos use_kerberos)
91 {
92         creds->use_kerberos = use_kerberos;
93 }
94
95 _PUBLIC_ enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds)
96 {
97         return creds->use_kerberos;
98 }
99
100 _PUBLIC_ void cli_credentials_set_gensec_features(struct cli_credentials *creds, uint32_t gensec_features)
101 {
102         creds->gensec_features = gensec_features;
103 }
104
105 _PUBLIC_ uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds)
106 {
107         return creds->gensec_features;
108 }
109
110
111 /**
112  * Obtain the username for this credentials context.
113  * @param cred credentials context
114  * @retval The username set on this context.
115  * @note Return value will never be NULL except by programmer error.
116  */
117 _PUBLIC_ const char *cli_credentials_get_username(struct cli_credentials *cred)
118 {
119         if (cred->machine_account_pending) {
120                 cli_credentials_set_machine_account(cred, 
121                                         cred->machine_account_pending_lp_ctx);
122         }
123
124         if (cred->username_obtained == CRED_CALLBACK && 
125             !cred->callback_running) {
126                 cred->callback_running = true;
127                 cred->username = cred->username_cb(cred);
128                 cred->callback_running = false;
129                 cred->username_obtained = CRED_SPECIFIED;
130                 cli_credentials_invalidate_ccache(cred, cred->username_obtained);
131         }
132
133         return cred->username;
134 }
135
136 _PUBLIC_ bool cli_credentials_set_username(struct cli_credentials *cred, 
137                                   const char *val, enum credentials_obtained obtained)
138 {
139         if (obtained >= cred->username_obtained) {
140                 cred->username = talloc_strdup(cred, val);
141                 cred->username_obtained = obtained;
142                 cli_credentials_invalidate_ccache(cred, cred->username_obtained);
143                 return true;
144         }
145
146         return false;
147 }
148
149 bool cli_credentials_set_username_callback(struct cli_credentials *cred,
150                                   const char *(*username_cb) (struct cli_credentials *))
151 {
152         if (cred->username_obtained < CRED_CALLBACK) {
153                 cred->username_cb = username_cb;
154                 cred->username_obtained = CRED_CALLBACK;
155                 return true;
156         }
157
158         return false;
159 }
160
161 _PUBLIC_ bool cli_credentials_set_bind_dn(struct cli_credentials *cred, 
162                                  const char *bind_dn)
163 {
164         cred->bind_dn = talloc_strdup(cred, bind_dn);
165         return true;
166 }
167
168 /**
169  * Obtain the BIND DN for this credentials context.
170  * @param cred credentials context
171  * @retval The username set on this context.
172  * @note Return value will be NULL if not specified explictly
173  */
174 _PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred)
175 {
176         return cred->bind_dn;
177 }
178
179
180 /**
181  * Obtain the client principal for this credentials context.
182  * @param cred credentials context
183  * @retval The username set on this context.
184  * @note Return value will never be NULL except by programmer error.
185  */
186 _PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
187 {
188         if (cred->machine_account_pending) {
189                 cli_credentials_set_machine_account(cred,
190                                         cred->machine_account_pending_lp_ctx);
191         }
192
193         if (cred->principal_obtained == CRED_CALLBACK && 
194             !cred->callback_running) {
195                 cred->callback_running = true;
196                 cred->principal = cred->principal_cb(cred);
197                 cred->callback_running = false;
198                 cred->principal_obtained = CRED_SPECIFIED;
199                 cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
200         }
201
202         if (cred->principal_obtained < cred->username_obtained) {
203                 if (cred->domain_obtained > cred->realm_obtained) {
204                         return talloc_asprintf(mem_ctx, "%s@%s", 
205                                                cli_credentials_get_username(cred),
206                                                cli_credentials_get_domain(cred));
207                 } else {
208                         return talloc_asprintf(mem_ctx, "%s@%s", 
209                                                cli_credentials_get_username(cred),
210                                                cli_credentials_get_realm(cred));
211                 }
212         }
213         return talloc_reference(mem_ctx, cred->principal);
214 }
215
216 bool cli_credentials_set_principal(struct cli_credentials *cred, 
217                                    const char *val, 
218                                    enum credentials_obtained obtained)
219 {
220         if (obtained >= cred->principal_obtained) {
221                 cred->principal = talloc_strdup(cred, val);
222                 cred->principal_obtained = obtained;
223                 cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
224                 return true;
225         }
226
227         return false;
228 }
229
230 /* Set a callback to get the principal.  This could be a popup dialog,
231  * a terminal prompt or similar.  */
232 bool cli_credentials_set_principal_callback(struct cli_credentials *cred,
233                                   const char *(*principal_cb) (struct cli_credentials *))
234 {
235         if (cred->principal_obtained < CRED_CALLBACK) {
236                 cred->principal_cb = principal_cb;
237                 cred->principal_obtained = CRED_CALLBACK;
238                 return true;
239         }
240
241         return false;
242 }
243
244 /* Some of our tools are 'anonymous by default'.  This is a single
245  * function to determine if authentication has been explicitly
246  * requested */
247
248 _PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *cred) 
249 {
250         if (cred->bind_dn) {
251                 return true;
252         }
253
254         if (cli_credentials_is_anonymous(cred)){
255                 return false;
256         }
257
258         if (cred->principal_obtained >= CRED_SPECIFIED) {
259                 return true;
260         }
261         if (cred->username_obtained >= CRED_SPECIFIED) {
262                 return true;
263         }
264
265         if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
266                 return true;
267         }
268
269         return false;
270 }
271
272 /**
273  * Obtain the password for this credentials context.
274  * @param cred credentials context
275  * @retval If set, the cleartext password, otherwise NULL
276  */
277 _PUBLIC_ const char *cli_credentials_get_password(struct cli_credentials *cred)
278 {
279         if (cred->machine_account_pending) {
280                 cli_credentials_set_machine_account(cred,
281                                                     cred->machine_account_pending_lp_ctx);
282         }
283
284         if (cred->password_obtained == CRED_CALLBACK && 
285             !cred->callback_running) {
286                 cred->callback_running = true;
287                 cred->password = cred->password_cb(cred);
288                 cred->callback_running = false;
289                 cred->password_obtained = CRED_CALLBACK_RESULT;
290                 cli_credentials_invalidate_ccache(cred, cred->password_obtained);
291         }
292
293         return cred->password;
294 }
295
296 /* Set a password on the credentials context, including an indication
297  * of 'how' the password was obtained */
298
299 _PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred, 
300                                   const char *val, 
301                                   enum credentials_obtained obtained)
302 {
303         if (obtained >= cred->password_obtained) {
304                 cred->password = talloc_strdup(cred, val);
305                 cred->password_obtained = obtained;
306                 cli_credentials_invalidate_ccache(cred, cred->password_obtained);
307
308                 cred->nt_hash = NULL;
309                 cred->lm_response = data_blob(NULL, 0);
310                 cred->nt_response = data_blob(NULL, 0);
311                 return true;
312         }
313
314         return false;
315 }
316
317 _PUBLIC_ bool cli_credentials_set_password_callback(struct cli_credentials *cred,
318                                            const char *(*password_cb) (struct cli_credentials *))
319 {
320         if (cred->password_obtained < CRED_CALLBACK) {
321                 cred->password_cb = password_cb;
322                 cred->password_obtained = CRED_CALLBACK;
323                 cli_credentials_invalidate_ccache(cred, cred->password_obtained);
324                 return true;
325         }
326
327         return false;
328 }
329
330 /**
331  * Obtain the 'old' password for this credentials context (used for join accounts).
332  * @param cred credentials context
333  * @retval If set, the cleartext password, otherwise NULL
334  */
335 const char *cli_credentials_get_old_password(struct cli_credentials *cred)
336 {
337         if (cred->machine_account_pending) {
338                 cli_credentials_set_machine_account(cred,
339                                                     cred->machine_account_pending_lp_ctx);
340         }
341
342         return cred->old_password;
343 }
344
345 bool cli_credentials_set_old_password(struct cli_credentials *cred, 
346                                       const char *val, 
347                                       enum credentials_obtained obtained)
348 {
349         cred->old_password = talloc_strdup(cred, val);
350         return true;
351 }
352
353 /**
354  * Obtain the password, in the form MD4(unicode(password)) for this credentials context.
355  *
356  * Sometimes we only have this much of the password, while the rest of
357  * the time this call avoids calling E_md4hash themselves.
358  *
359  * @param cred credentials context
360  * @retval If set, the cleartext password, otherwise NULL
361  */
362 _PUBLIC_ const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, 
363                                                         TALLOC_CTX *mem_ctx)
364 {
365         const char *password = cli_credentials_get_password(cred);
366
367         if (password) {
368                 struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password);
369                 if (!nt_hash) {
370                         return NULL;
371                 }
372                 
373                 E_md4hash(password, nt_hash->hash);    
374
375                 return nt_hash;
376         } else {
377                 return cred->nt_hash;
378         }
379 }
380
381 /**
382  * Obtain the 'short' or 'NetBIOS' domain for this credentials context.
383  * @param cred credentials context
384  * @retval The domain set on this context. 
385  * @note Return value will never be NULL except by programmer error.
386  */
387 _PUBLIC_ const char *cli_credentials_get_domain(struct cli_credentials *cred)
388 {
389         if (cred->machine_account_pending) {
390                 cli_credentials_set_machine_account(cred,
391                                                     cred->machine_account_pending_lp_ctx);
392         }
393
394         if (cred->domain_obtained == CRED_CALLBACK && 
395             !cred->callback_running) {
396                 cred->callback_running = true;
397                 cred->domain = cred->domain_cb(cred);
398                 cred->callback_running = false;
399                 cred->domain_obtained = CRED_SPECIFIED;
400                 cli_credentials_invalidate_ccache(cred, cred->domain_obtained);
401         }
402
403         return cred->domain;
404 }
405
406
407 _PUBLIC_ bool cli_credentials_set_domain(struct cli_credentials *cred, 
408                                 const char *val, 
409                                 enum credentials_obtained obtained)
410 {
411         if (obtained >= cred->domain_obtained) {
412                 /* it is important that the domain be in upper case,
413                  * particularly for the sensitive NTLMv2
414                  * calculations */
415                 cred->domain = strupper_talloc(cred, val);
416                 cred->domain_obtained = obtained;
417                 cli_credentials_invalidate_ccache(cred, cred->domain_obtained);
418                 return true;
419         }
420
421         return false;
422 }
423
424 bool cli_credentials_set_domain_callback(struct cli_credentials *cred,
425                                          const char *(*domain_cb) (struct cli_credentials *))
426 {
427         if (cred->domain_obtained < CRED_CALLBACK) {
428                 cred->domain_cb = domain_cb;
429                 cred->domain_obtained = CRED_CALLBACK;
430                 return true;
431         }
432
433         return false;
434 }
435
436 /**
437  * Obtain the Kerberos realm for this credentials context.
438  * @param cred credentials context
439  * @retval The realm set on this context. 
440  * @note Return value will never be NULL except by programmer error.
441  */
442 _PUBLIC_ const char *cli_credentials_get_realm(struct cli_credentials *cred)
443 {       
444         if (cred->machine_account_pending) {
445                 cli_credentials_set_machine_account(cred,
446                                                     cred->machine_account_pending_lp_ctx);
447         }
448
449         if (cred->realm_obtained == CRED_CALLBACK && 
450             !cred->callback_running) {
451                 cred->callback_running = true;
452                 cred->realm = cred->realm_cb(cred);
453                 cred->callback_running = false;
454                 cred->realm_obtained = CRED_SPECIFIED;
455                 cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
456         }
457
458         return cred->realm;
459 }
460
461 /**
462  * Set the realm for this credentials context, and force it to
463  * uppercase for the sainity of our local kerberos libraries 
464  */
465 _PUBLIC_ bool cli_credentials_set_realm(struct cli_credentials *cred, 
466                                const char *val, 
467                                enum credentials_obtained obtained)
468 {
469         if (obtained >= cred->realm_obtained) {
470                 cred->realm = strupper_talloc(cred, val);
471                 cred->realm_obtained = obtained;
472                 cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
473                 return true;
474         }
475
476         return false;
477 }
478
479 bool cli_credentials_set_realm_callback(struct cli_credentials *cred,
480                                         const char *(*realm_cb) (struct cli_credentials *))
481 {
482         if (cred->realm_obtained < CRED_CALLBACK) {
483                 cred->realm_cb = realm_cb;
484                 cred->realm_obtained = CRED_CALLBACK;
485                 return true;
486         }
487
488         return false;
489 }
490
491 /**
492  * Obtain the 'short' or 'NetBIOS' workstation name for this credentials context.
493  *
494  * @param cred credentials context
495  * @retval The workstation name set on this context. 
496  * @note Return value will never be NULL except by programmer error.
497  */
498 _PUBLIC_ const char *cli_credentials_get_workstation(struct cli_credentials *cred)
499 {
500         if (cred->workstation_obtained == CRED_CALLBACK && 
501             !cred->callback_running) {
502                 cred->callback_running = true;
503                 cred->workstation = cred->workstation_cb(cred);
504                 cred->callback_running = false;
505                 cred->workstation_obtained = CRED_SPECIFIED;
506         }
507
508         return cred->workstation;
509 }
510
511 _PUBLIC_ bool cli_credentials_set_workstation(struct cli_credentials *cred, 
512                                      const char *val, 
513                                      enum credentials_obtained obtained)
514 {
515         if (obtained >= cred->workstation_obtained) {
516                 cred->workstation = talloc_strdup(cred, val);
517                 cred->workstation_obtained = obtained;
518                 return true;
519         }
520
521         return false;
522 }
523
524 bool cli_credentials_set_workstation_callback(struct cli_credentials *cred,
525                                               const char *(*workstation_cb) (struct cli_credentials *))
526 {
527         if (cred->workstation_obtained < CRED_CALLBACK) {
528                 cred->workstation_cb = workstation_cb;
529                 cred->workstation_obtained = CRED_CALLBACK;
530                 return true;
531         }
532
533         return false;
534 }
535
536 /**
537  * Given a string, typically obtained from a -U argument, parse it into domain, username, realm and password fields
538  *
539  * The format accepted is [domain\\]user[%password] or user[@realm][%password]
540  *
541  * @param credentials Credentials structure on which to set the password
542  * @param data the string containing the username, password etc
543  * @param obtained This enum describes how 'specified' this password is
544  */
545
546 _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained)
547 {
548         char *uname, *p;
549
550         if (strcmp("%",data) == 0) {
551                 cli_credentials_set_anonymous(credentials);
552                 return;
553         }
554
555         uname = talloc_strdup(credentials, data); 
556         if ((p = strchr_m(uname,'%'))) {
557                 *p = 0;
558                 cli_credentials_set_password(credentials, p+1, obtained);
559         }
560
561         if ((p = strchr_m(uname,'@'))) {
562                 cli_credentials_set_principal(credentials, uname, obtained);
563                 *p = 0;
564                 cli_credentials_set_realm(credentials, p+1, obtained);
565                 return;
566         } else if ((p = strchr_m(uname,'\\')) || (p = strchr_m(uname, '/'))) {
567                 *p = 0;
568                 cli_credentials_set_domain(credentials, uname, obtained);
569                 uname = p+1;
570         }
571         cli_credentials_set_username(credentials, uname, obtained);
572 }
573
574 /**
575  * Given a a credentials structure, print it as a string
576  *
577  * The format output is [domain\\]user[%password] or user[@realm][%password]
578  *
579  * @param credentials Credentials structure on which to set the password
580  * @param mem_ctx The memory context to place the result on
581  */
582
583 _PUBLIC_ const char *cli_credentials_get_unparsed_name(struct cli_credentials *credentials, TALLOC_CTX *mem_ctx)
584 {
585         const char *bind_dn = cli_credentials_get_bind_dn(credentials);
586         const char *domain;
587         const char *username;
588         const char *name;
589
590         if (bind_dn) {
591                 name = talloc_reference(mem_ctx, bind_dn);
592         } else {
593                 cli_credentials_get_ntlm_username_domain(credentials, mem_ctx, &username, &domain);
594                 if (domain && domain[0]) {
595                         name = talloc_asprintf(mem_ctx, "%s\\%s", 
596                                                domain, username);
597                 } else {
598                         name = talloc_asprintf(mem_ctx, "%s", 
599                                                username);
600                 }
601         }
602         return name;
603 }
604
605 /**
606  * Specifies default values for domain, workstation and realm
607  * from the smb.conf configuration file
608  *
609  * @param cred Credentials structure to fill in
610  */
611 _PUBLIC_ void cli_credentials_set_conf(struct cli_credentials *cred, 
612                               struct loadparm_context *lp_ctx)
613 {
614         cli_credentials_set_username(cred, "", CRED_UNINITIALISED);
615         cli_credentials_set_domain(cred, lp_workgroup(lp_ctx), CRED_UNINITIALISED);
616         cli_credentials_set_workstation(cred, lp_netbios_name(lp_ctx), CRED_UNINITIALISED);
617         cli_credentials_set_realm(cred, lp_realm(lp_ctx), CRED_UNINITIALISED);
618 }
619
620 /**
621  * Guess defaults for credentials from environment variables, 
622  * and from the configuration file
623  * 
624  * @param cred Credentials structure to fill in
625  */
626 _PUBLIC_ void cli_credentials_guess(struct cli_credentials *cred,
627                            struct loadparm_context *lp_ctx)
628 {
629         char *p;
630
631         if (lp_ctx != NULL) {
632                 cli_credentials_set_conf(cred, lp_ctx);
633         }
634         
635         if (getenv("LOGNAME")) {
636                 cli_credentials_set_username(cred, getenv("LOGNAME"), CRED_GUESS_ENV);
637         }
638
639         if (getenv("USER")) {
640                 cli_credentials_parse_string(cred, getenv("USER"), CRED_GUESS_ENV);
641                 if ((p = strchr_m(getenv("USER"),'%'))) {
642                         memset(p,0,strlen(cred->password));
643                 }
644         }
645
646         if (getenv("PASSWD")) {
647                 cli_credentials_set_password(cred, getenv("PASSWD"), CRED_GUESS_ENV);
648         }
649
650         if (getenv("PASSWD_FD")) {
651                 cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), 
652                                                   CRED_GUESS_FILE);
653         }
654         
655         p = getenv("PASSWD_FILE");
656         if (p && p[0]) {
657                 cli_credentials_parse_password_file(cred, p, CRED_GUESS_FILE);
658         }
659         
660         if (cli_credentials_get_kerberos_state(cred) != CRED_DONT_USE_KERBEROS) {
661                 cli_credentials_set_ccache(cred, event_context_find(cred), lp_ctx, NULL, CRED_GUESS_FILE);
662         }
663 }
664
665 /**
666  * Attach NETLOGON credentials for use with SCHANNEL
667  */
668
669 _PUBLIC_ void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, 
670                                         struct creds_CredentialState *netlogon_creds)
671 {
672         cred->netlogon_creds = talloc_reference(cred, netlogon_creds);
673 }
674
675 /**
676  * Return attached NETLOGON credentials 
677  */
678
679 struct creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred)
680 {
681         return cred->netlogon_creds;
682 }
683
684 /** 
685  * Set NETLOGON secure channel type
686  */
687
688 _PUBLIC_ void cli_credentials_set_secure_channel_type(struct cli_credentials *cred,
689                                              enum netr_SchannelType secure_channel_type)
690 {
691         cred->secure_channel_type = secure_channel_type;
692 }
693
694 /**
695  * Return NETLOGON secure chanel type
696  */
697
698 _PUBLIC_ enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred)
699 {
700         return cred->secure_channel_type;
701 }
702
703 /**
704  * Fill in a credentials structure as the anonymous user
705  */
706 _PUBLIC_ void cli_credentials_set_anonymous(struct cli_credentials *cred) 
707 {
708         cli_credentials_set_username(cred, "", CRED_SPECIFIED);
709         cli_credentials_set_domain(cred, "", CRED_SPECIFIED);
710         cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
711         cli_credentials_set_realm(cred, NULL, CRED_SPECIFIED);
712         cli_credentials_set_workstation(cred, "", CRED_UNINITIALISED);
713 }
714
715 /**
716  * Describe a credentials context as anonymous or authenticated
717  * @retval true if anonymous, false if a username is specified
718  */
719
720 _PUBLIC_ bool cli_credentials_is_anonymous(struct cli_credentials *cred)
721 {
722         const char *username;
723         
724         if (cred->machine_account_pending) {
725                 cli_credentials_set_machine_account(cred,
726                                                     cred->machine_account_pending_lp_ctx);
727         }
728
729         username = cli_credentials_get_username(cred);
730         
731         /* Yes, it is deliberate that we die if we have a NULL pointer
732          * here - anonymous is "", not NULL, which is 'never specified,
733          * never guessed', ie programmer bug */
734         if (!username[0]) {
735                 return true;
736         }
737
738         return false;
739 }
740
741 /**
742  * Mark the current password for a credentials struct as wrong. This will 
743  * cause the password to be prompted again (if a callback is set).
744  *
745  * This will decrement the number of times the password can be tried.
746  *
747  * @retval whether the credentials struct is finished
748  */
749 _PUBLIC_ bool cli_credentials_wrong_password(struct cli_credentials *cred)
750 {
751         if (cred->password_obtained != CRED_CALLBACK_RESULT) {
752                 return false;
753         }
754         
755         cred->password_obtained = CRED_CALLBACK;
756
757         cred->tries--;
758
759         return (cred->tries > 0);
760 }