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