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