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