lib: Give lib/util/util_file.c its own header file
[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 "lib/util/util_file.h"
26 #include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
27 #include "auth/credentials/credentials.h"
28 #include "auth/credentials/credentials_internal.h"
29 #include "auth/gensec/gensec.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "tevent.h"
32 #include "param/param.h"
33 #include "system/filesys.h"
34 #include "system/passwd.h"
35
36 /**
37  * Create a new credentials structure
38  * @param mem_ctx TALLOC_CTX parent for credentials structure
39  */
40 _PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx)
41 {
42         struct cli_credentials *cred = talloc_zero(mem_ctx, struct cli_credentials);
43         if (cred == NULL) {
44                 return cred;
45         }
46
47         cred->winbind_separator = '\\';
48
49         cred->kerberos_state = CRED_USE_KERBEROS_DESIRED;
50
51         cred->signing_state = SMB_SIGNING_DEFAULT;
52
53         /*
54          * The default value of lpcfg_client_ipc_signing() is REQUIRED, so use
55          * the same value here.
56          */
57         cred->ipc_signing_state = SMB_SIGNING_REQUIRED;
58         cred->encryption_state = SMB_ENCRYPTION_DEFAULT;
59
60         return cred;
61 }
62
63 _PUBLIC_
64 struct cli_credentials *cli_credentials_init_server(TALLOC_CTX *mem_ctx,
65                                                     struct loadparm_context *lp_ctx)
66 {
67         struct cli_credentials *server_creds = NULL;
68         NTSTATUS status;
69         bool ok;
70
71         server_creds = cli_credentials_init(mem_ctx);
72         if (server_creds == NULL) {
73                 return NULL;
74         }
75
76         ok = cli_credentials_set_conf(server_creds, lp_ctx);
77         if (!ok) {
78                 TALLOC_FREE(server_creds);
79                 return NULL;
80         }
81
82         status = cli_credentials_set_machine_account(server_creds, lp_ctx);
83         if (!NT_STATUS_IS_OK(status)) {
84                 DEBUG(1, ("Failed to obtain server credentials: %s\n",
85                           nt_errstr(status)));
86                 TALLOC_FREE(server_creds);
87                 return NULL;
88         }
89
90         return server_creds;
91 }
92
93 _PUBLIC_ void cli_credentials_set_callback_data(struct cli_credentials *cred,
94                                                 void *callback_data)
95 {
96         cred->priv_data = callback_data;
97 }
98
99 _PUBLIC_ void *_cli_credentials_callback_data(struct cli_credentials *cred)
100 {
101         return cred->priv_data;
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_ bool cli_credentials_set_kerberos_state(struct cli_credentials *creds,
119                                                  enum credentials_use_kerberos kerberos_state,
120                                                  enum credentials_obtained obtained)
121 {
122         if (obtained >= creds->kerberos_state_obtained) {
123                 creds->kerberos_state = kerberos_state;
124                 creds->kerberos_state_obtained = obtained;
125
126                 return true;
127         }
128
129         return false;
130 }
131
132 _PUBLIC_ void cli_credentials_set_forced_sasl_mech(struct cli_credentials *creds,
133                                                    const char *sasl_mech)
134 {
135         TALLOC_FREE(creds->forced_sasl_mech);
136         creds->forced_sasl_mech = talloc_strdup(creds, sasl_mech);
137 }
138
139 _PUBLIC_ void cli_credentials_set_krb_forwardable(struct cli_credentials *creds,
140                                                   enum credentials_krb_forwardable krb_forwardable)
141 {
142         creds->krb_forwardable = krb_forwardable;
143 }
144
145 _PUBLIC_ enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds)
146 {
147         return creds->kerberos_state;
148 }
149
150 _PUBLIC_ const char *cli_credentials_get_forced_sasl_mech(struct cli_credentials *creds)
151 {
152         return creds->forced_sasl_mech;
153 }
154
155 _PUBLIC_ enum credentials_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds)
156 {
157         return creds->krb_forwardable;
158 }
159
160 _PUBLIC_ bool cli_credentials_set_gensec_features(struct cli_credentials *creds,
161                                                   uint32_t gensec_features,
162                                                   enum credentials_obtained obtained)
163 {
164         if (obtained >= creds->gensec_features_obtained) {
165                 creds->gensec_features_obtained = obtained;
166                 creds->gensec_features = gensec_features;
167
168                 return true;
169         }
170
171         return false;
172 }
173
174 _PUBLIC_ uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds)
175 {
176         return creds->gensec_features;
177 }
178
179
180 /**
181  * Obtain the username for this credentials context.
182  * @param cred credentials context
183  * @retval The username set on this context.
184  * @note Return value will never be NULL except by programmer error.
185  */
186 _PUBLIC_ const char *cli_credentials_get_username(struct cli_credentials *cred)
187 {
188         if (cred->machine_account_pending) {
189                 cli_credentials_set_machine_account(cred,
190                                         cred->machine_account_pending_lp_ctx);
191         }
192
193         if (cred->username_obtained == CRED_CALLBACK &&
194             !cred->callback_running) {
195                 cred->callback_running = true;
196                 cred->username = cred->username_cb(cred);
197                 cred->callback_running = false;
198                 if (cred->username_obtained == CRED_CALLBACK) {
199                         cred->username_obtained = CRED_CALLBACK_RESULT;
200                         cli_credentials_invalidate_ccache(cred, cred->username_obtained);
201                 }
202         }
203
204         return cred->username;
205 }
206
207 /**
208  * @brief Obtain the username for this credentials context.
209  *
210  * @param[in]  cred  The credential context.
211  *
212  * @param[in]  obtained  A pointer to store the obtained information.
213  *
214  * return The user name or NULL if an error occurred.
215  */
216 _PUBLIC_ const char *
217 cli_credentials_get_username_and_obtained(struct cli_credentials *cred,
218                                           enum credentials_obtained *obtained)
219 {
220         if (obtained != NULL) {
221                 *obtained = cred->username_obtained;
222         }
223
224         return cli_credentials_get_username(cred);
225 }
226
227 _PUBLIC_ bool cli_credentials_set_username(struct cli_credentials *cred,
228                                   const char *val, enum credentials_obtained obtained)
229 {
230         if (obtained >= cred->username_obtained) {
231                 cred->username = talloc_strdup(cred, val);
232                 cred->username_obtained = obtained;
233                 cli_credentials_invalidate_ccache(cred, cred->username_obtained);
234                 return true;
235         }
236
237         return false;
238 }
239
240 _PUBLIC_ bool cli_credentials_set_username_callback(struct cli_credentials *cred,
241                                   const char *(*username_cb) (struct cli_credentials *))
242 {
243         if (cred->username_obtained < CRED_CALLBACK) {
244                 cred->username_cb = username_cb;
245                 cred->username_obtained = CRED_CALLBACK;
246                 return true;
247         }
248
249         return false;
250 }
251
252 _PUBLIC_ bool cli_credentials_set_bind_dn(struct cli_credentials *cred,
253                                  const char *bind_dn)
254 {
255         cred->bind_dn = talloc_strdup(cred, bind_dn);
256         return true;
257 }
258
259 /**
260  * Obtain the BIND DN for this credentials context.
261  * @param cred credentials context
262  * @retval The username set on this context.
263  * @note Return value will be NULL if not specified explicitly
264  */
265 _PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred)
266 {
267         return cred->bind_dn;
268 }
269
270
271 /**
272  * Obtain the client principal for this credentials context.
273  * @param cred credentials context
274  * @retval The username set on this context.
275  * @note Return value will never be NULL except by programmer error.
276  */
277 _PUBLIC_ char *cli_credentials_get_principal_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained)
278 {
279         if (cred->machine_account_pending) {
280                 cli_credentials_set_machine_account(cred,
281                                         cred->machine_account_pending_lp_ctx);
282         }
283
284         if (cred->principal_obtained == CRED_CALLBACK &&
285             !cred->callback_running) {
286                 cred->callback_running = true;
287                 cred->principal = cred->principal_cb(cred);
288                 cred->callback_running = false;
289                 if (cred->principal_obtained == CRED_CALLBACK) {
290                         cred->principal_obtained = CRED_CALLBACK_RESULT;
291                         cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
292                 }
293         }
294
295         if (cred->principal_obtained < cred->username_obtained
296             || cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) {
297                 const char *effective_username = NULL;
298                 const char *effective_realm = NULL;
299                 enum credentials_obtained effective_obtained;
300
301                 effective_username = cli_credentials_get_username(cred);
302                 if (effective_username == NULL || strlen(effective_username) == 0) {
303                         *obtained = cred->username_obtained;
304                         return NULL;
305                 }
306
307                 if (cred->domain_obtained > cred->realm_obtained) {
308                         effective_realm = cli_credentials_get_domain(cred);
309                         effective_obtained = MIN(cred->domain_obtained,
310                                                  cred->username_obtained);
311                 } else {
312                         effective_realm = cli_credentials_get_realm(cred);
313                         effective_obtained = MIN(cred->realm_obtained,
314                                                  cred->username_obtained);
315                 }
316
317                 if (effective_realm == NULL || strlen(effective_realm) == 0) {
318                         effective_realm = cli_credentials_get_domain(cred);
319                         effective_obtained = MIN(cred->domain_obtained,
320                                                  cred->username_obtained);
321                 }
322
323                 if (effective_realm != NULL && strlen(effective_realm) != 0) {
324                         *obtained = effective_obtained;
325                         return talloc_asprintf(mem_ctx, "%s@%s",
326                                                effective_username,
327                                                effective_realm);
328                 }
329         }
330         *obtained = cred->principal_obtained;
331         return talloc_strdup(mem_ctx, cred->principal);
332 }
333
334 /**
335  * Obtain the client principal for this credentials context.
336  * @param cred credentials context
337  * @retval The username set on this context.
338  * @note Return value will never be NULL except by programmer error.
339  */
340 _PUBLIC_ char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
341 {
342         enum credentials_obtained obtained;
343         return cli_credentials_get_principal_and_obtained(cred, mem_ctx, &obtained);
344 }
345
346 _PUBLIC_ bool cli_credentials_set_principal(struct cli_credentials *cred,
347                                    const char *val,
348                                    enum credentials_obtained obtained)
349 {
350         if (obtained >= cred->principal_obtained) {
351                 cred->principal = talloc_strdup(cred, val);
352                 if (cred->principal == NULL) {
353                         return false;
354                 }
355                 cred->principal_obtained = obtained;
356
357                 cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
358                 return true;
359         }
360
361         return false;
362 }
363
364 /* Set a callback to get the principal.  This could be a popup dialog,
365  * a terminal prompt or similar.  */
366 _PUBLIC_ bool cli_credentials_set_principal_callback(struct cli_credentials *cred,
367                                   const char *(*principal_cb) (struct cli_credentials *))
368 {
369         if (cred->principal_obtained < CRED_CALLBACK) {
370                 cred->principal_cb = principal_cb;
371                 cred->principal_obtained = CRED_CALLBACK;
372                 return true;
373         }
374
375         return false;
376 }
377
378 /* Some of our tools are 'anonymous by default'.  This is a single
379  * function to determine if authentication has been explicitly
380  * requested */
381
382 _PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *cred)
383 {
384         uint32_t gensec_features = 0;
385
386         if (cred->bind_dn) {
387                 return true;
388         }
389
390         /*
391          * If we forced the mech we clearly want authentication. E.g. to use
392          * SASL/EXTERNAL which has no credentials.
393          */
394         if (cred->forced_sasl_mech) {
395                 return true;
396         }
397
398         if (cli_credentials_is_anonymous(cred)){
399                 return false;
400         }
401
402         if (cred->principal_obtained >= CRED_SPECIFIED) {
403                 return true;
404         }
405         if (cred->username_obtained >= CRED_SPECIFIED) {
406                 return true;
407         }
408
409         if (cli_credentials_get_kerberos_state(cred) == CRED_USE_KERBEROS_REQUIRED) {
410                 return true;
411         }
412
413         gensec_features = cli_credentials_get_gensec_features(cred);
414         if (gensec_features & GENSEC_FEATURE_NTLM_CCACHE) {
415                 return true;
416         }
417
418         if (gensec_features & GENSEC_FEATURE_SIGN) {
419                 return true;
420         }
421
422         if (gensec_features & GENSEC_FEATURE_SEAL) {
423                 return true;
424         }
425
426         return false;
427 }
428
429 /**
430  * Obtain the password for this credentials context.
431  * @param cred credentials context
432  * @retval If set, the cleartext password, otherwise NULL
433  */
434 _PUBLIC_ const char *cli_credentials_get_password(struct cli_credentials *cred)
435 {
436         if (cred->machine_account_pending) {
437                 cli_credentials_set_machine_account(cred,
438                                                     cred->machine_account_pending_lp_ctx);
439         }
440
441         if (cred->password_obtained == CRED_CALLBACK &&
442             !cred->callback_running &&
443             !cred->password_will_be_nt_hash) {
444                 cred->callback_running = true;
445                 cred->password = cred->password_cb(cred);
446                 cred->callback_running = false;
447                 if (cred->password_obtained == CRED_CALLBACK) {
448                         cred->password_obtained = CRED_CALLBACK_RESULT;
449                         cli_credentials_invalidate_ccache(cred, cred->password_obtained);
450                 }
451         }
452
453         return cred->password;
454 }
455
456 /**
457  * @brief Obtain the password for this credentials context.
458  *
459  * @param[in]  cred  The credential context.
460  *
461  * @param[in]  obtained  A pointer to store the obtained information.
462  *
463  * return The user name or NULL if an error occurred.
464  */
465 _PUBLIC_ const char *
466 cli_credentials_get_password_and_obtained(struct cli_credentials *cred,
467                                           enum credentials_obtained *obtained)
468 {
469         const char *password = cli_credentials_get_password(cred);
470
471         if (obtained != NULL) {
472                 *obtained = cred->password_obtained;
473         }
474
475         return password;
476 }
477
478 /* Set a password on the credentials context, including an indication
479  * of 'how' the password was obtained */
480
481 _PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred,
482                                   const char *val,
483                                   enum credentials_obtained obtained)
484 {
485         if (obtained >= cred->password_obtained) {
486
487                 cred->lm_response = data_blob_null;
488                 cred->nt_response = data_blob_null;
489                 cred->nt_hash = NULL;
490                 cred->password = NULL;
491
492                 cli_credentials_invalidate_ccache(cred, obtained);
493
494                 cred->password_tries = 0;
495
496                 if (val == NULL) {
497                         cred->password_obtained = obtained;
498                         return true;
499                 }
500
501                 if (cred->password_will_be_nt_hash) {
502                         struct samr_Password *nt_hash = NULL;
503                         size_t val_len = strlen(val);
504                         size_t converted;
505
506                         nt_hash = talloc(cred, struct samr_Password);
507                         if (nt_hash == NULL) {
508                                 return false;
509                         }
510
511                         converted = strhex_to_str((char *)nt_hash->hash,
512                                                   sizeof(nt_hash->hash),
513                                                   val, val_len);
514                         if (converted != sizeof(nt_hash->hash)) {
515                                 TALLOC_FREE(nt_hash);
516                                 return false;
517                         }
518
519                         cred->nt_hash = nt_hash;
520                         cred->password_obtained = obtained;
521                         return true;
522                 }
523
524                 cred->password = talloc_strdup(cred, val);
525                 if (cred->password == NULL) {
526                         return false;
527                 }
528
529                 /* Don't print the actual password in talloc memory dumps */
530                 talloc_set_name_const(cred->password,
531                         "password set via cli_credentials_set_password");
532                 cred->password_obtained = obtained;
533
534                 return true;
535         }
536
537         return false;
538 }
539
540 _PUBLIC_ bool cli_credentials_set_password_callback(struct cli_credentials *cred,
541                                            const char *(*password_cb) (struct cli_credentials *))
542 {
543         if (cred->password_obtained < CRED_CALLBACK) {
544                 cred->password_tries = 3;
545                 cred->password_cb = password_cb;
546                 cred->password_obtained = CRED_CALLBACK;
547                 cli_credentials_invalidate_ccache(cred, cred->password_obtained);
548                 return true;
549         }
550
551         return false;
552 }
553
554 /**
555  * Obtain the 'old' password for this credentials context (used for join accounts).
556  * @param cred credentials context
557  * @retval If set, the cleartext password, otherwise NULL
558  */
559 _PUBLIC_ const char *cli_credentials_get_old_password(struct cli_credentials *cred)
560 {
561         if (cred->machine_account_pending) {
562                 cli_credentials_set_machine_account(cred,
563                                                     cred->machine_account_pending_lp_ctx);
564         }
565
566         return cred->old_password;
567 }
568
569 _PUBLIC_ bool cli_credentials_set_old_password(struct cli_credentials *cred,
570                                       const char *val,
571                                       enum credentials_obtained obtained)
572 {
573         cred->old_password = talloc_strdup(cred, val);
574         if (cred->old_password) {
575                 /* Don't print the actual password in talloc memory dumps */
576                 talloc_set_name_const(cred->old_password, "password set via cli_credentials_set_old_password");
577         }
578         cred->old_nt_hash = NULL;
579         return true;
580 }
581
582 /**
583  * Obtain the password, in the form MD4(unicode(password)) for this credentials context.
584  *
585  * Sometimes we only have this much of the password, while the rest of
586  * the time this call avoids calling E_md4hash themselves.
587  *
588  * @param cred credentials context
589  * @retval If set, the cleartext password, otherwise NULL
590  */
591 _PUBLIC_ struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred,
592                                                            TALLOC_CTX *mem_ctx)
593 {
594         enum credentials_obtained password_obtained;
595         enum credentials_obtained ccache_threshold;
596         enum credentials_obtained client_gss_creds_threshold;
597         bool password_is_nt_hash;
598         const char *password = NULL;
599         struct samr_Password *nt_hash = NULL;
600
601         if (cred->nt_hash != NULL) {
602                 /*
603                  * If we already have a hash it's easy.
604                  */
605                 goto return_hash;
606         }
607
608         /*
609          * This is a bit tricky, with password_will_be_nt_hash
610          * we still need to get the value via the password_callback
611          * but if we did that we should not remember it's state
612          * in the long run so we need to undo it.
613          */
614
615         password_obtained = cred->password_obtained;
616         ccache_threshold = cred->ccache_threshold;
617         client_gss_creds_threshold = cred->client_gss_creds_threshold;
618         password_is_nt_hash = cred->password_will_be_nt_hash;
619
620         cred->password_will_be_nt_hash = false;
621         password = cli_credentials_get_password(cred);
622
623         cred->password_will_be_nt_hash = password_is_nt_hash;
624         if (password_is_nt_hash && password_obtained == CRED_CALLBACK) {
625                 /*
626                  * We got the nt_hash as string via the callback,
627                  * so we need to undo the state change.
628                  *
629                  * And also don't remember it as plaintext password.
630                  */
631                 cred->client_gss_creds_threshold = client_gss_creds_threshold;
632                 cred->ccache_threshold = ccache_threshold;
633                 cred->password_obtained = password_obtained;
634                 cred->password = NULL;
635         }
636
637         if (password == NULL) {
638                 return NULL;
639         }
640
641         nt_hash = talloc(cred, struct samr_Password);
642         if (nt_hash == NULL) {
643                 return NULL;
644         }
645
646         if (password_is_nt_hash) {
647                 size_t password_len = strlen(password);
648                 size_t converted;
649
650                 converted = strhex_to_str((char *)nt_hash->hash,
651                                           sizeof(nt_hash->hash),
652                                           password, password_len);
653                 if (converted != sizeof(nt_hash->hash)) {
654                         TALLOC_FREE(nt_hash);
655                         return NULL;
656                 }
657         } else {
658                 E_md4hash(password, nt_hash->hash);
659         }
660
661         cred->nt_hash = nt_hash;
662         nt_hash = NULL;
663
664 return_hash:
665         nt_hash = talloc(mem_ctx, struct samr_Password);
666         if (nt_hash == NULL) {
667                 return NULL;
668         }
669
670         *nt_hash = *cred->nt_hash;
671
672         return nt_hash;
673 }
674
675 /**
676  * Obtain the old password, in the form MD4(unicode(password)) for this credentials context.
677  *
678  * Sometimes we only have this much of the password, while the rest of
679  * the time this call avoids calling E_md4hash themselves.
680  *
681  * @param cred credentials context
682  * @retval If set, the cleartext password, otherwise NULL
683  */
684 _PUBLIC_ struct samr_Password *cli_credentials_get_old_nt_hash(struct cli_credentials *cred,
685                                                                TALLOC_CTX *mem_ctx)
686 {
687         const char *old_password = NULL;
688
689         if (cred->old_nt_hash != NULL) {
690                 struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password);
691                 if (!nt_hash) {
692                         return NULL;
693                 }
694
695                 *nt_hash = *cred->old_nt_hash;
696
697                 return nt_hash;
698         }
699
700         old_password = cli_credentials_get_old_password(cred);
701         if (old_password) {
702                 struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password);
703                 if (!nt_hash) {
704                         return NULL;
705                 }
706
707                 E_md4hash(old_password, nt_hash->hash);
708
709                 return nt_hash;
710         }
711
712         return NULL;
713 }
714
715 /**
716  * Obtain the 'short' or 'NetBIOS' domain for this credentials context.
717  * @param cred credentials context
718  * @retval The domain set on this context.
719  * @note Return value will never be NULL except by programmer error.
720  */
721 _PUBLIC_ const char *cli_credentials_get_domain(struct cli_credentials *cred)
722 {
723         if (cred->machine_account_pending) {
724                 cli_credentials_set_machine_account(cred,
725                                                     cred->machine_account_pending_lp_ctx);
726         }
727
728         if (cred->domain_obtained == CRED_CALLBACK &&
729             !cred->callback_running) {
730                 cred->callback_running = true;
731                 cred->domain = cred->domain_cb(cred);
732                 cred->callback_running = false;
733                 if (cred->domain_obtained == CRED_CALLBACK) {
734                         cred->domain_obtained = CRED_CALLBACK_RESULT;
735                         cli_credentials_invalidate_ccache(cred, cred->domain_obtained);
736                 }
737         }
738
739         return cred->domain;
740 }
741
742 /**
743  * @brief Obtain the domain for this credential context.
744  *
745  * @param[in] cred  The credential context.
746  *
747  * @param[out] obtained A pointer to store the obtained information.
748  *
749  * @return The domain name or NULL if an error occurred.
750  */
751 _PUBLIC_ const char *cli_credentials_get_domain_and_obtained(
752         struct cli_credentials *cred,
753         enum credentials_obtained *obtained)
754 {
755         const char *domain = cli_credentials_get_domain(cred);
756
757         if (obtained != NULL) {
758                 *obtained = cred->domain_obtained;
759         }
760
761         return domain;
762 }
763
764
765 _PUBLIC_ bool cli_credentials_set_domain(struct cli_credentials *cred,
766                                 const char *val,
767                                 enum credentials_obtained obtained)
768 {
769         if (obtained >= cred->domain_obtained) {
770                 /* it is important that the domain be in upper case,
771                  * particularly for the sensitive NTLMv2
772                  * calculations */
773                 cred->domain = strupper_talloc(cred, val);
774                 cred->domain_obtained = obtained;
775                 /* setting domain does not mean we have to invalidate ccache
776                  * because domain in not used for Kerberos operations.
777                  * If ccache invalidation is required, one will anyway specify
778                  * a password to kinit, and that will force invalidation of the ccache
779                  */
780                 return true;
781         }
782
783         return false;
784 }
785
786 bool cli_credentials_set_domain_callback(struct cli_credentials *cred,
787                                          const char *(*domain_cb) (struct cli_credentials *))
788 {
789         if (cred->domain_obtained < CRED_CALLBACK) {
790                 cred->domain_cb = domain_cb;
791                 cred->domain_obtained = CRED_CALLBACK;
792                 return true;
793         }
794
795         return false;
796 }
797
798 /**
799  * Obtain the Kerberos realm for this credentials context.
800  * @param cred credentials context
801  * @retval The realm set on this context.
802  * @note Return value will never be NULL except by programmer error.
803  */
804 _PUBLIC_ const char *cli_credentials_get_realm(struct cli_credentials *cred)
805 {
806         if (cred->machine_account_pending) {
807                 cli_credentials_set_machine_account(cred,
808                                                     cred->machine_account_pending_lp_ctx);
809         }
810
811         if (cred->realm_obtained == CRED_CALLBACK &&
812             !cred->callback_running) {
813                 cred->callback_running = true;
814                 cred->realm = cred->realm_cb(cred);
815                 cred->callback_running = false;
816                 if (cred->realm_obtained == CRED_CALLBACK) {
817                         cred->realm_obtained = CRED_CALLBACK_RESULT;
818                         cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
819                 }
820         }
821
822         return cred->realm;
823 }
824
825 /**
826  * Set the realm for this credentials context, and force it to
827  * uppercase for the sanity of our local kerberos libraries
828  */
829 _PUBLIC_ bool cli_credentials_set_realm(struct cli_credentials *cred,
830                                const char *val,
831                                enum credentials_obtained obtained)
832 {
833         if (obtained >= cred->realm_obtained) {
834                 cred->realm = strupper_talloc(cred, val);
835                 cred->realm_obtained = obtained;
836                 cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
837                 return true;
838         }
839
840         return false;
841 }
842
843 bool cli_credentials_set_realm_callback(struct cli_credentials *cred,
844                                         const char *(*realm_cb) (struct cli_credentials *))
845 {
846         if (cred->realm_obtained < CRED_CALLBACK) {
847                 cred->realm_cb = realm_cb;
848                 cred->realm_obtained = CRED_CALLBACK;
849                 return true;
850         }
851
852         return false;
853 }
854
855 /**
856  * Obtain the 'short' or 'NetBIOS' workstation name for this credentials context.
857  *
858  * @param cred credentials context
859  * @retval The workstation name set on this context.
860  * @note Return value will never be NULL except by programmer error.
861  */
862 _PUBLIC_ const char *cli_credentials_get_workstation(struct cli_credentials *cred)
863 {
864         if (cred->workstation_obtained == CRED_CALLBACK &&
865             !cred->callback_running) {
866                 cred->callback_running = true;
867                 cred->workstation = cred->workstation_cb(cred);
868                 cred->callback_running = false;
869                 if (cred->workstation_obtained == CRED_CALLBACK) {
870                         cred->workstation_obtained = CRED_CALLBACK_RESULT;
871                 }
872         }
873
874         return cred->workstation;
875 }
876
877 _PUBLIC_ bool cli_credentials_set_workstation(struct cli_credentials *cred,
878                                      const char *val,
879                                      enum credentials_obtained obtained)
880 {
881         if (obtained >= cred->workstation_obtained) {
882                 cred->workstation = talloc_strdup(cred, val);
883                 cred->workstation_obtained = obtained;
884                 return true;
885         }
886
887         return false;
888 }
889
890 bool cli_credentials_set_workstation_callback(struct cli_credentials *cred,
891                                               const char *(*workstation_cb) (struct cli_credentials *))
892 {
893         if (cred->workstation_obtained < CRED_CALLBACK) {
894                 cred->workstation_cb = workstation_cb;
895                 cred->workstation_obtained = CRED_CALLBACK;
896                 return true;
897         }
898
899         return false;
900 }
901
902 /**
903  * Given a string, typically obtained from a -U argument, parse it into domain, username, realm and password fields
904  *
905  * The format accepted is [domain\\]user[%password] or user[@realm][%password]
906  *
907  * @param credentials Credentials structure on which to set the password
908  * @param data the string containing the username, password etc
909  * @param obtained This enum describes how 'specified' this password is
910  */
911
912 _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained)
913 {
914         char *uname, *p;
915         char *uname_free = NULL;
916
917         if (strcmp("%",data) == 0) {
918                 cli_credentials_set_anonymous(credentials);
919                 return;
920         }
921
922         uname = talloc_strdup(credentials, data);
923         uname_free = uname;
924
925         if ((p = strchr_m(uname,'%'))) {
926                 *p = 0;
927                 cli_credentials_set_password(credentials, p+1, obtained);
928         }
929
930         if ((p = strchr_m(uname,'@'))) {
931                 /*
932                  * We also need to set username and domain
933                  * in order to undo the effect of
934                  * cli_credentials_guess().
935                  */
936                 cli_credentials_set_username(credentials, uname, obtained);
937                 cli_credentials_set_domain(credentials, "", obtained);
938
939                 cli_credentials_set_principal(credentials, uname, obtained);
940                 *p = 0;
941                 cli_credentials_set_realm(credentials, p+1, obtained);
942                 TALLOC_FREE(uname_free);
943                 return;
944         } else if ((p = strchr_m(uname,'\\'))
945                    || (p = strchr_m(uname, '/'))
946                    || (p = strchr_m(uname, credentials->winbind_separator)))
947         {
948                 const char *domain = NULL;
949
950                 domain = uname;
951                 *p = 0;
952                 uname = p+1;
953
954                 if (obtained == credentials->realm_obtained &&
955                     !strequal_m(credentials->domain, domain))
956                 {
957                         /*
958                          * We need to undo a former set with the same level
959                          * in order to get the expected result from
960                          * cli_credentials_get_principal().
961                          *
962                          * But we only need to do that if the domain
963                          * actually changes.
964                          */
965                         cli_credentials_set_realm(credentials, domain, obtained);
966                 }
967                 cli_credentials_set_domain(credentials, domain, obtained);
968         }
969         if (obtained == credentials->principal_obtained &&
970             !strequal_m(credentials->username, uname))
971         {
972                 /*
973                  * We need to undo a former set with the same level
974                  * in order to get the expected result from
975                  * cli_credentials_get_principal().
976                  *
977                  * But we only need to do that if the username
978                  * actually changes.
979                  */
980                 credentials->principal_obtained = CRED_UNINITIALISED;
981                 credentials->principal = NULL;
982         }
983         cli_credentials_set_username(credentials, uname, obtained);
984
985         TALLOC_FREE(uname_free);
986 }
987
988 /**
989  * Given a a credentials structure, print it as a string
990  *
991  * The format output is [domain\\]user[%password] or user[@realm][%password]
992  *
993  * @param credentials Credentials structure on which to set the password
994  * @param mem_ctx The memory context to place the result on
995  */
996
997 _PUBLIC_ char *cli_credentials_get_unparsed_name(struct cli_credentials *credentials, TALLOC_CTX *mem_ctx)
998 {
999         const char *bind_dn = cli_credentials_get_bind_dn(credentials);
1000         const char *domain = NULL;
1001         const char *username = NULL;
1002         char *name = NULL;
1003
1004         if (bind_dn) {
1005                 name = talloc_strdup(mem_ctx, bind_dn);
1006         } else {
1007                 cli_credentials_get_ntlm_username_domain(credentials, mem_ctx, &username, &domain);
1008                 if (domain && domain[0]) {
1009                         name = talloc_asprintf(mem_ctx, "%s\\%s",
1010                                                domain, username);
1011                 } else {
1012                         name = talloc_asprintf(mem_ctx, "%s",
1013                                                username);
1014                 }
1015         }
1016         return name;
1017 }
1018
1019
1020 /**
1021  * Specifies default values for domain, workstation and realm
1022  * from the smb.conf configuration file
1023  *
1024  * @param cred Credentials structure to fill in
1025  *
1026  * @return true on success, false on error.
1027  */
1028 _PUBLIC_ bool cli_credentials_set_conf(struct cli_credentials *cred,
1029                                        struct loadparm_context *lp_ctx)
1030 {
1031         const char *sep = NULL;
1032         const char *realm = lpcfg_realm(lp_ctx);
1033         enum credentials_client_protection protection =
1034                 lpcfg_client_protection(lp_ctx);
1035         const char *workgroup = lpcfg_workgroup(lp_ctx);
1036         const char *netbios_name = lpcfg_netbios_name(lp_ctx);
1037         bool ok;
1038
1039         (void)cli_credentials_set_username(cred, "", CRED_UNINITIALISED);
1040
1041         if (workgroup != NULL && strlen(workgroup) == 0) {
1042                 workgroup = NULL;
1043         }
1044
1045         if (workgroup != NULL) {
1046                 if (lpcfg_parm_is_cmdline(lp_ctx, "workgroup")) {
1047                         ok = cli_credentials_set_domain(cred,
1048                                                         workgroup,
1049                                                         CRED_SPECIFIED);
1050                         if (!ok) {
1051                                 DBG_ERR("Failed to set domain!\n");
1052                                 return false;
1053                         }
1054                 } else {
1055                         (void)cli_credentials_set_domain(cred,
1056                                                          workgroup,
1057                                                          CRED_SMB_CONF);
1058                 }
1059         }
1060
1061         if (netbios_name != NULL && strlen(netbios_name) == 0) {
1062                 netbios_name = NULL;
1063         }
1064
1065         if (netbios_name != NULL) {
1066                 if (lpcfg_parm_is_cmdline(lp_ctx, "netbios name")) {
1067                         ok = cli_credentials_set_workstation(cred,
1068                                                              netbios_name,
1069                                                              CRED_SPECIFIED);
1070                         if (!ok) {
1071                                 DBG_ERR("Failed to set workstation!\n");
1072                                 return false;
1073                         }
1074                 } else {
1075                         (void)cli_credentials_set_workstation(cred,
1076                                                               netbios_name,
1077                                                               CRED_SMB_CONF);
1078                 }
1079         }
1080
1081         if (realm != NULL && strlen(realm) == 0) {
1082                 realm = NULL;
1083         }
1084
1085         if (realm != NULL) {
1086                 if (lpcfg_parm_is_cmdline(lp_ctx, "realm")) {
1087                         ok = cli_credentials_set_realm(cred,
1088                                                        realm,
1089                                                        CRED_SPECIFIED);
1090                         if (!ok) {
1091                                 DBG_ERR("Failed to set realm!\n");
1092                                 return false;
1093                         }
1094                 } else {
1095                         (void)cli_credentials_set_realm(cred,
1096                                                         realm,
1097                                                         CRED_SMB_CONF);
1098                 }
1099         }
1100
1101         sep = lpcfg_winbind_separator(lp_ctx);
1102         if (sep != NULL && sep[0] != '\0') {
1103                 cred->winbind_separator = *lpcfg_winbind_separator(lp_ctx);
1104         }
1105
1106         if (cred->signing_state_obtained <= CRED_SMB_CONF) {
1107                 /* Will be set to default for invalid smb.conf values */
1108                 cred->signing_state = lpcfg_client_signing(lp_ctx);
1109                 if (cred->signing_state == SMB_SIGNING_DEFAULT) {
1110                         switch (protection) {
1111                         case CRED_CLIENT_PROTECTION_DEFAULT:
1112                                 break;
1113                         case CRED_CLIENT_PROTECTION_PLAIN:
1114                                 cred->signing_state = SMB_SIGNING_OFF;
1115                                 break;
1116                         case CRED_CLIENT_PROTECTION_SIGN:
1117                         case CRED_CLIENT_PROTECTION_ENCRYPT:
1118                                 cred->signing_state = SMB_SIGNING_REQUIRED;
1119                                 break;
1120                         }
1121                 }
1122
1123                 cred->signing_state_obtained = CRED_SMB_CONF;
1124         }
1125
1126         if (cred->ipc_signing_state_obtained <= CRED_SMB_CONF) {
1127                 /* Will be set to required for invalid smb.conf values */
1128                 cred->ipc_signing_state = lpcfg_client_ipc_signing(lp_ctx);
1129                 cred->ipc_signing_state_obtained = CRED_SMB_CONF;
1130         }
1131
1132         if (cred->encryption_state_obtained <= CRED_SMB_CONF) {
1133                 /* Will be set to default for invalid smb.conf values */
1134                 cred->encryption_state = lpcfg_client_smb_encrypt(lp_ctx);
1135                 if (cred->encryption_state == SMB_ENCRYPTION_DEFAULT) {
1136                         switch (protection) {
1137                         case CRED_CLIENT_PROTECTION_DEFAULT:
1138                                 break;
1139                         case CRED_CLIENT_PROTECTION_PLAIN:
1140                         case CRED_CLIENT_PROTECTION_SIGN:
1141                                 cred->encryption_state = SMB_ENCRYPTION_OFF;
1142                                 break;
1143                         case CRED_CLIENT_PROTECTION_ENCRYPT:
1144                                 cred->encryption_state = SMB_ENCRYPTION_REQUIRED;
1145                                 break;
1146                         }
1147                 }
1148         }
1149
1150         if (cred->kerberos_state_obtained <= CRED_SMB_CONF) {
1151                 /* Will be set to default for invalid smb.conf values */
1152                 cred->kerberos_state = lpcfg_client_use_kerberos(lp_ctx);
1153                 cred->kerberos_state_obtained = CRED_SMB_CONF;
1154         }
1155
1156         if (cred->gensec_features_obtained <= CRED_SMB_CONF) {
1157                 switch (protection) {
1158                 case CRED_CLIENT_PROTECTION_DEFAULT:
1159                         break;
1160                 case CRED_CLIENT_PROTECTION_PLAIN:
1161                         cred->gensec_features = 0;
1162                         break;
1163                 case CRED_CLIENT_PROTECTION_SIGN:
1164                         cred->gensec_features = GENSEC_FEATURE_SIGN;
1165                         break;
1166                 case CRED_CLIENT_PROTECTION_ENCRYPT:
1167                         cred->gensec_features =
1168                                 GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL;
1169                         break;
1170                 }
1171                 cred->gensec_features_obtained = CRED_SMB_CONF;
1172         }
1173
1174         return true;
1175 }
1176
1177 /**
1178  * Guess defaults for credentials from environment variables,
1179  * and from the configuration file
1180  *
1181  * @param cred Credentials structure to fill in
1182  */
1183 _PUBLIC_ bool cli_credentials_guess(struct cli_credentials *cred,
1184                                     struct loadparm_context *lp_ctx)
1185 {
1186         const char *error_string;
1187         const char *env = NULL;
1188         struct passwd *pwd = NULL;
1189         bool ok;
1190
1191         if (lp_ctx != NULL) {
1192                 ok = cli_credentials_set_conf(cred, lp_ctx);
1193                 if (!ok) {
1194                         return false;
1195                 }
1196         }
1197
1198         pwd = getpwuid(getuid());
1199         if (pwd != NULL) {
1200                 size_t len = strlen(pwd->pw_name);
1201
1202                 if (len > 0 && len <= 1024) {
1203                         (void)cli_credentials_parse_string(cred,
1204                                                            pwd->pw_name,
1205                                                            CRED_GUESS_ENV);
1206                 }
1207         }
1208
1209         env = getenv("LOGNAME");
1210         if (env != NULL) {
1211                 size_t len = strlen(env);
1212
1213                 if (len > 0 && len <= 1024) {
1214                         (void)cli_credentials_set_username(cred,
1215                                                            env,
1216                                                            CRED_GUESS_ENV);
1217                 }
1218         }
1219
1220         env = getenv("USER");
1221         if (env != NULL) {
1222                 size_t len = strlen(env);
1223
1224                 if (len > 0 && len <= 1024) {
1225                         char *p = NULL;
1226
1227                         (void)cli_credentials_parse_string(cred,
1228                                                            env,
1229                                                            CRED_GUESS_ENV);
1230                         if ((p = strchr_m(env, '%'))) {
1231                                 memset(p, '\0', strlen(cred->password));
1232                         }
1233                 }
1234         }
1235
1236         env = getenv("PASSWD");
1237         if (env != NULL) {
1238                 size_t len = strlen(env);
1239
1240                 if (len > 0 && len <= 1024) {
1241                         (void)cli_credentials_set_password(cred,
1242                                                            env,
1243                                                            CRED_GUESS_ENV);
1244                 }
1245         }
1246
1247         env = getenv("PASSWD_FD");
1248         if (env != NULL) {
1249                 size_t len = strlen(env);
1250
1251                 if (len > 0 && len <= 1024) {
1252                         int fd = atoi(env);
1253
1254                         (void)cli_credentials_parse_password_fd(cred,
1255                                                                 fd,
1256                                                                 CRED_GUESS_FILE);
1257                 }
1258         }
1259
1260         env = getenv("PASSWD_FILE");
1261         if (env != NULL) {
1262                 size_t len = strlen(env);
1263
1264                 if (len > 0 && len <= 4096) {
1265                         (void)cli_credentials_parse_password_file(cred,
1266                                                                   env,
1267                                                                   CRED_GUESS_FILE);
1268                 }
1269         }
1270
1271         if (lp_ctx != NULL &&
1272             cli_credentials_get_kerberos_state(cred) != CRED_USE_KERBEROS_DISABLED) {
1273                 (void)cli_credentials_set_ccache(cred,
1274                                                  lp_ctx,
1275                                                  NULL,
1276                                                  CRED_GUESS_FILE,
1277                                                  &error_string);
1278         }
1279
1280         return true;
1281 }
1282
1283 /**
1284  * Attach NETLOGON credentials for use with SCHANNEL
1285  */
1286
1287 _PUBLIC_ void cli_credentials_set_netlogon_creds(
1288         struct cli_credentials *cred,
1289         const struct netlogon_creds_CredentialState *netlogon_creds)
1290 {
1291         TALLOC_FREE(cred->netlogon_creds);
1292         if (netlogon_creds == NULL) {
1293                 return;
1294         }
1295         cred->netlogon_creds = netlogon_creds_copy(cred, netlogon_creds);
1296 }
1297
1298 /**
1299  * Return attached NETLOGON credentials
1300  */
1301
1302 _PUBLIC_ struct netlogon_creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred)
1303 {
1304         return cred->netlogon_creds;
1305 }
1306
1307 /**
1308  * Set NETLOGON secure channel type
1309  */
1310
1311 _PUBLIC_ void cli_credentials_set_secure_channel_type(struct cli_credentials *cred,
1312                                              enum netr_SchannelType secure_channel_type)
1313 {
1314         cred->secure_channel_type = secure_channel_type;
1315 }
1316
1317 /**
1318  * Return NETLOGON secure channel type
1319  */
1320
1321 _PUBLIC_ time_t cli_credentials_get_password_last_changed_time(struct cli_credentials *cred)
1322 {
1323         return cred->password_last_changed_time;
1324 }
1325
1326 /**
1327  * Set NETLOGON secure channel type
1328  */
1329
1330 _PUBLIC_ void cli_credentials_set_password_last_changed_time(struct cli_credentials *cred,
1331                                                              time_t last_changed_time)
1332 {
1333         cred->password_last_changed_time = last_changed_time;
1334 }
1335
1336 /**
1337  * Return NETLOGON secure channel type
1338  */
1339
1340 _PUBLIC_ enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred)
1341 {
1342         return cred->secure_channel_type;
1343 }
1344
1345 /**
1346  * Fill in a credentials structure as the anonymous user
1347  */
1348 _PUBLIC_ void cli_credentials_set_anonymous(struct cli_credentials *cred)
1349 {
1350         cli_credentials_set_username(cred, "", CRED_SPECIFIED);
1351         cli_credentials_set_domain(cred, "", CRED_SPECIFIED);
1352         cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
1353         cli_credentials_set_principal(cred, NULL, CRED_SPECIFIED);
1354         cli_credentials_set_realm(cred, NULL, CRED_SPECIFIED);
1355         cli_credentials_set_workstation(cred, "", CRED_UNINITIALISED);
1356         cli_credentials_set_kerberos_state(cred,
1357                                            CRED_USE_KERBEROS_DISABLED,
1358                                            CRED_SPECIFIED);
1359 }
1360
1361 /**
1362  * Describe a credentials context as anonymous or authenticated
1363  * @retval true if anonymous, false if a username is specified
1364  */
1365
1366 _PUBLIC_ bool cli_credentials_is_anonymous(struct cli_credentials *cred)
1367 {
1368         const char *username;
1369
1370         /* if bind dn is set it's not anonymous */
1371         if (cred->bind_dn) {
1372                 return false;
1373         }
1374
1375         if (cred->machine_account_pending) {
1376                 cli_credentials_set_machine_account(cred,
1377                                                     cred->machine_account_pending_lp_ctx);
1378         }
1379
1380         /* if principal is set, it's not anonymous */
1381         if ((cred->principal != NULL) && cred->principal_obtained >= cred->username_obtained) {
1382                 return false;
1383         }
1384
1385         username = cli_credentials_get_username(cred);
1386
1387         /* Yes, it is deliberate that we die if we have a NULL pointer
1388          * here - anonymous is "", not NULL, which is 'never specified,
1389          * never guessed', ie programmer bug */
1390         if (!username[0]) {
1391                 return true;
1392         }
1393
1394         return false;
1395 }
1396
1397 /**
1398  * Mark the current password for a credentials struct as wrong. This will
1399  * cause the password to be prompted again (if a callback is set).
1400  *
1401  * This will decrement the number of times the password can be tried.
1402  *
1403  * @retval whether the credentials struct is finished
1404  */
1405 _PUBLIC_ bool cli_credentials_wrong_password(struct cli_credentials *cred)
1406 {
1407         if (cred->password_obtained != CRED_CALLBACK_RESULT) {
1408                 return false;
1409         }
1410
1411         if (cred->password_tries == 0) {
1412                 return false;
1413         }
1414
1415         cred->password_tries--;
1416
1417         if (cred->password_tries == 0) {
1418                 return false;
1419         }
1420
1421         cred->password_obtained = CRED_CALLBACK;
1422         return true;
1423 }
1424
1425 _PUBLIC_ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
1426                                               const char **username,
1427                                               const char **domain)
1428 {
1429         if (cred->principal_obtained >= cred->username_obtained) {
1430                 *domain = talloc_strdup(mem_ctx, "");
1431                 *username = cli_credentials_get_principal(cred, mem_ctx);
1432         } else {
1433                 *domain = cli_credentials_get_domain(cred);
1434                 *username = cli_credentials_get_username(cred);
1435         }
1436 }
1437
1438 /**
1439  * Read a named file, and parse it for username, domain, realm and password
1440  *
1441  * @param credentials Credentials structure on which to set the password
1442  * @param file a named file to read the details from
1443  * @param obtained This enum describes how 'specified' this password is
1444  */
1445
1446 _PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const char *file, enum credentials_obtained obtained)
1447 {
1448         uint16_t len = 0;
1449         char *ptr, *val, *param;
1450         char **lines;
1451         int i, numlines;
1452         const char *realm = NULL;
1453         const char *domain = NULL;
1454         const char *password = NULL;
1455         const char *username = NULL;
1456
1457         lines = file_lines_load(file, &numlines, 0, NULL);
1458
1459         if (lines == NULL)
1460         {
1461                 /* fail if we can't open the credentials file */
1462                 d_printf("ERROR: Unable to open credentials file!\n");
1463                 return false;
1464         }
1465
1466         for (i = 0; i < numlines; i++) {
1467                 len = strlen(lines[i]);
1468
1469                 if (len == 0)
1470                         continue;
1471
1472                 /* break up the line into parameter & value.
1473                  * will need to eat a little whitespace possibly */
1474                 param = lines[i];
1475                 if (!(ptr = strchr_m (lines[i], '=')))
1476                         continue;
1477
1478                 val = ptr+1;
1479                 *ptr = '\0';
1480
1481                 /* eat leading white space */
1482                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
1483                         val++;
1484
1485                 if (strwicmp("password", param) == 0) {
1486                         password = val;
1487                 } else if (strwicmp("username", param) == 0) {
1488                         username = val;
1489                 } else if (strwicmp("domain", param) == 0) {
1490                         domain = val;
1491                 } else if (strwicmp("realm", param) == 0) {
1492                         realm = val;
1493                 }
1494
1495                 /*
1496                  * We need to readd '=' in order to let
1497                  * the strlen() work in the last loop
1498                  * that clears the memory.
1499                  */
1500                 *ptr = '=';
1501         }
1502
1503         if (realm != NULL && strlen(realm) != 0) {
1504                 /*
1505                  * only overwrite with a valid string
1506                  */
1507                 cli_credentials_set_realm(cred, realm, obtained);
1508         }
1509
1510         if (domain != NULL && strlen(domain) != 0) {
1511                 /*
1512                  * only overwrite with a valid string
1513                  */
1514                 cli_credentials_set_domain(cred, domain, obtained);
1515         }
1516
1517         if (password != NULL) {
1518                 /*
1519                  * Here we allow "".
1520                  */
1521                 cli_credentials_set_password(cred, password, obtained);
1522         }
1523
1524         if (username != NULL) {
1525                 /*
1526                  * The last "username" line takes preference
1527                  * if the string also contains domain, realm or
1528                  * password.
1529                  */
1530                 cli_credentials_parse_string(cred, username, obtained);
1531         }
1532
1533         for (i = 0; i < numlines; i++) {
1534                 len = strlen(lines[i]);
1535                 memset(lines[i], 0, len);
1536         }
1537         talloc_free(lines);
1538
1539         return true;
1540 }
1541
1542 /**
1543  * Read a named file, and parse it for a password
1544  *
1545  * @param credentials Credentials structure on which to set the password
1546  * @param file a named file to read the password from
1547  * @param obtained This enum describes how 'specified' this password is
1548  */
1549
1550 _PUBLIC_ bool cli_credentials_parse_password_file(struct cli_credentials *credentials, const char *file, enum credentials_obtained obtained)
1551 {
1552         int fd = open(file, O_RDONLY, 0);
1553         bool ret;
1554
1555         if (fd < 0) {
1556                 fprintf(stderr, "Error opening password file %s: %s\n",
1557                                 file, strerror(errno));
1558                 return false;
1559         }
1560
1561         ret = cli_credentials_parse_password_fd(credentials, fd, obtained);
1562
1563         close(fd);
1564
1565         return ret;
1566 }
1567
1568
1569 /**
1570  * Read a file descriptor, and parse it for a password (eg from a file or stdin)
1571  *
1572  * @param credentials Credentials structure on which to set the password
1573  * @param fd open file descriptor to read the password from
1574  * @param obtained This enum describes how 'specified' this password is
1575  */
1576
1577 _PUBLIC_ bool cli_credentials_parse_password_fd(struct cli_credentials *credentials,
1578                                        int fd, enum credentials_obtained obtained)
1579 {
1580         char *p;
1581         char pass[128];
1582
1583         if (credentials->password_obtained >= obtained) {
1584                 return false;
1585         }
1586
1587         for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
1588                 p && p - pass < sizeof(pass) - 1;) {
1589                 switch (read(fd, p, 1)) {
1590                 case 1:
1591                         if (*p != '\n' && *p != '\0') {
1592                                 *++p = '\0'; /* advance p, and null-terminate pass */
1593                                 break;
1594                         }
1595
1596                         FALL_THROUGH;
1597                 case 0:
1598                         if (p - pass) {
1599                                 *p = '\0'; /* null-terminate it, just in case... */
1600                                 p = NULL; /* then force the loop condition to become false */
1601                                 break;
1602                         }
1603
1604                         fprintf(stderr,
1605                                 "Error reading password from file descriptor "
1606                                 "%d: empty password\n",
1607                                 fd);
1608                         return false;
1609
1610                 default:
1611                         fprintf(stderr, "Error reading password from file descriptor %d: %s\n",
1612                                         fd, strerror(errno));
1613                         return false;
1614                 }
1615         }
1616
1617         cli_credentials_set_password(credentials, pass, obtained);
1618         return true;
1619 }
1620
1621 /**
1622  * @brief Set the SMB signing state to request for a SMB connection.
1623  *
1624  * @param[in]  creds          The credentials structure to update.
1625  *
1626  * @param[in]  signing_state  The signing state to set.
1627  *
1628  * @param obtained            This way the described signing state was specified.
1629  *
1630  * @return true if we could set the signing state, false otherwise.
1631  */
1632 _PUBLIC_ bool cli_credentials_set_smb_signing(struct cli_credentials *creds,
1633                                               enum smb_signing_setting signing_state,
1634                                               enum credentials_obtained obtained)
1635 {
1636         if (obtained >= creds->signing_state_obtained) {
1637                 creds->signing_state_obtained = obtained;
1638                 creds->signing_state = signing_state;
1639                 return true;
1640         }
1641
1642         return false;
1643 }
1644
1645 /**
1646  * @brief Obtain the SMB signing state from a credentials structure.
1647  *
1648  * @param[in]  creds  The credential structure to obtain the SMB signing state
1649  *                    from.
1650  *
1651  * @return The SMB signing state.
1652  */
1653 _PUBLIC_ enum smb_signing_setting
1654 cli_credentials_get_smb_signing(struct cli_credentials *creds)
1655 {
1656         return creds->signing_state;
1657 }
1658
1659 /**
1660  * @brief Set the SMB IPC signing state to request for a SMB connection.
1661  *
1662  * @param[in]  creds          The credentials structure to update.
1663  *
1664  * @param[in]  signing_state  The signing state to set.
1665  *
1666  * @param obtained            This way the described signing state was specified.
1667  *
1668  * @return true if we could set the signing state, false otherwise.
1669  */
1670 _PUBLIC_ bool
1671 cli_credentials_set_smb_ipc_signing(struct cli_credentials *creds,
1672                                     enum smb_signing_setting ipc_signing_state,
1673                                     enum credentials_obtained obtained)
1674 {
1675         if (obtained >= creds->ipc_signing_state_obtained) {
1676                 creds->ipc_signing_state_obtained = obtained;
1677                 creds->ipc_signing_state = ipc_signing_state;
1678                 return true;
1679         }
1680
1681         return false;
1682 }
1683
1684 /**
1685  * @brief Obtain the SMB IPC signing state from a credentials structure.
1686  *
1687  * @param[in]  creds  The credential structure to obtain the SMB IPC signing
1688  *                    state from.
1689  *
1690  * @return The SMB signing state.
1691  */
1692 _PUBLIC_ enum smb_signing_setting
1693 cli_credentials_get_smb_ipc_signing(struct cli_credentials *creds)
1694 {
1695         return creds->ipc_signing_state;
1696 }
1697
1698 /**
1699  * @brief Set the SMB encryption state to request for a SMB connection.
1700  *
1701  * @param[in]  creds  The credentials structure to update.
1702  *
1703  * @param[in]  encryption_state  The encryption state to set.
1704  *
1705  * @param obtained  This way the described encryption state was specified.
1706  *
1707  * @return true if we could set the encryption state, false otherwise.
1708  */
1709 _PUBLIC_ bool cli_credentials_set_smb_encryption(struct cli_credentials *creds,
1710                                                  enum smb_encryption_setting encryption_state,
1711                                                  enum credentials_obtained obtained)
1712 {
1713         if (obtained >= creds->encryption_state_obtained) {
1714                 creds->encryption_state_obtained = obtained;
1715                 creds->encryption_state = encryption_state;
1716                 return true;
1717         }
1718
1719         return false;
1720 }
1721
1722 static const char *obtained_to_str(enum credentials_obtained obtained)
1723 {
1724         switch (obtained) {
1725         case CRED_UNINITIALISED:
1726                 return "CRED_UNINITIALISED";
1727         case CRED_SMB_CONF:
1728                 return "CRED_SMB_CONF";
1729         case CRED_CALLBACK:
1730                 return "CRED_CALLBACK";
1731         case CRED_GUESS_ENV:
1732                 return "CRED_GUESS_ENV";
1733         case CRED_GUESS_FILE:
1734                 return "CRED_GUESS_FILE";
1735         case CRED_CALLBACK_RESULT:
1736                 return "CRED_CALLBACK_RESULT";
1737         case CRED_SPECIFIED:
1738                 return "CRED_SPECIFIED";
1739         }
1740
1741         /* Never reached */
1742         return "";
1743 }
1744
1745 static const char *krb5_state_to_str(enum credentials_use_kerberos krb5_state)
1746 {
1747         switch (krb5_state) {
1748         case CRED_USE_KERBEROS_DISABLED:
1749                 return "CRED_USE_KERBEROS_DISABLED";
1750         case CRED_USE_KERBEROS_DESIRED:
1751                 return "CRED_USE_KERBEROS_DESIRED";
1752         case CRED_USE_KERBEROS_REQUIRED:
1753                 return "CRED_USE_KERBEROS_REQUIRED";
1754         }
1755
1756         /* Never reached */
1757         return "";
1758 }
1759
1760 static const char *krb5_fwd_to_str(enum credentials_krb_forwardable krb5_fwd)
1761 {
1762         switch (krb5_fwd) {
1763         case CRED_AUTO_KRB_FORWARDABLE:
1764                 return "CRED_AUTO_KRB_FORWARDABLE";
1765         case CRED_NO_KRB_FORWARDABLE:
1766                 return "CRED_NO_KRB_FORWARDABLE";
1767         case CRED_FORCE_KRB_FORWARDABLE:
1768                 return "CRED_FORCE_KRB_FORWARDABLE";
1769         }
1770
1771         /* Never reached */
1772         return "";
1773 }
1774
1775 static const char *signing_state_to_str(enum smb_signing_setting signing_state)
1776 {
1777         switch(signing_state) {
1778         case SMB_SIGNING_IPC_DEFAULT:
1779                 return "SMB_SIGNING_IPC_DEFAULT";
1780         case SMB_SIGNING_DEFAULT:
1781                 return "SMB_SIGNING_DEFAULT";
1782         case SMB_SIGNING_OFF:
1783                 return "SMB_SIGNING_OFF";
1784         case SMB_SIGNING_IF_REQUIRED:
1785                 return "SMB_SIGNING_IF_REQUIRED";
1786         case SMB_SIGNING_DESIRED:
1787                 return "SMB_SIGNING_DESIRED";
1788         case SMB_SIGNING_REQUIRED:
1789                 return "SMB_SIGNING_REQUIRED";
1790         }
1791
1792         /* Never reached */
1793         return "";
1794 }
1795
1796 static const char *encryption_state_to_str(enum smb_encryption_setting encryption_state)
1797 {
1798         switch(encryption_state) {
1799         case SMB_ENCRYPTION_DEFAULT:
1800                 return "SMB_ENCRYPTION_DEFAULT";
1801         case SMB_ENCRYPTION_OFF:
1802                 return "SMB_ENCRYPTION_OFF";
1803         case SMB_ENCRYPTION_IF_REQUIRED:
1804                 return "SMB_ENCRYPTION_IF_REQUIRED";
1805         case SMB_ENCRYPTION_DESIRED:
1806                 return "SMB_ENCRYPTION_DESIRED";
1807         case SMB_ENCRYPTION_REQUIRED:
1808                 return "SMB_ENCRYPTION_REQUIRED";
1809         }
1810
1811         /* Never reached */
1812         return "";
1813 }
1814
1815 _PUBLIC_ void cli_credentials_dump(struct cli_credentials *creds)
1816 {
1817         DBG_ERR("CLI_CREDENTIALS:\n");
1818         DBG_ERR("\n");
1819         DBG_ERR("  Username: %s - %s\n",
1820                 creds->username,
1821                 obtained_to_str(creds->username_obtained));
1822         DBG_ERR("  Workstation: %s - %s\n",
1823                 creds->workstation,
1824                 obtained_to_str(creds->workstation_obtained));
1825         DBG_ERR("  Domain: %s - %s\n",
1826                 creds->domain,
1827                 obtained_to_str(creds->domain_obtained));
1828         DBG_ERR("  Password: %s - %s\n",
1829                 creds->password != NULL ? "*SECRET*" : "NULL",
1830                 obtained_to_str(creds->password_obtained));
1831         DBG_ERR("  Old password: %s\n",
1832                 creds->old_password != NULL ? "*SECRET*" : "NULL");
1833         DBG_ERR("  Password tries: %u\n",
1834                 creds->password_tries);
1835         DBG_ERR("  Realm: %s - %s\n",
1836                 creds->realm,
1837                 obtained_to_str(creds->realm_obtained));
1838         DBG_ERR("  Principal: %s - %s\n",
1839                 creds->principal,
1840                 obtained_to_str(creds->principal_obtained));
1841         DBG_ERR("  Salt principal: %s\n",
1842                 creds->salt_principal);
1843         DBG_ERR("  Impersonate principal: %s\n",
1844                 creds->impersonate_principal);
1845         DBG_ERR("  Self service: %s\n",
1846                 creds->self_service);
1847         DBG_ERR("  Target service: %s\n",
1848                 creds->target_service);
1849         DBG_ERR("  Kerberos state: %s - %s\n",
1850                 krb5_state_to_str(creds->kerberos_state),
1851                 obtained_to_str(creds->kerberos_state_obtained));
1852         DBG_ERR("  Kerberos forwardable ticket: %s\n",
1853                 krb5_fwd_to_str(creds->krb_forwardable));
1854         DBG_ERR("  Signing state: %s - %s\n",
1855                 signing_state_to_str(creds->signing_state),
1856                 obtained_to_str(creds->signing_state_obtained));
1857         DBG_ERR("  IPC signing state: %s - %s\n",
1858                 signing_state_to_str(creds->ipc_signing_state),
1859                 obtained_to_str(creds->ipc_signing_state_obtained));
1860         DBG_ERR("  Encryption state: %s - %s\n",
1861                 encryption_state_to_str(creds->encryption_state),
1862                 obtained_to_str(creds->encryption_state_obtained));
1863         DBG_ERR("  Gensec features: %#X\n",
1864                 creds->gensec_features);
1865         DBG_ERR("  Forced sasl mech: %s\n",
1866                 creds->forced_sasl_mech);
1867         DBG_ERR("  CCACHE: %p - %s\n",
1868                 creds->ccache,
1869                 obtained_to_str(creds->ccache_obtained));
1870         DBG_ERR("  CLIENT_GSS_CREDS: %p - %s\n",
1871                 creds->client_gss_creds,
1872                 obtained_to_str(creds->client_gss_creds_obtained));
1873         DBG_ERR("  SERVER_GSS_CREDS: %p - %s\n",
1874                 creds->server_gss_creds,
1875                 obtained_to_str(creds->server_gss_creds_obtained));
1876         DBG_ERR("  KEYTAB: %p - %s\n",
1877                 creds->keytab,
1878                 obtained_to_str(creds->keytab_obtained));
1879         DBG_ERR("  KVNO: %u\n",
1880                 creds->kvno);
1881         DBG_ERR("\n");
1882 }
1883
1884 /**
1885  * @brief Obtain the SMB encryption state from a credentials structure.
1886  *
1887  * @param[in]  creds  The credential structure to obtain the SMB encryption state
1888  *                    from.
1889  *
1890  * @return The SMB signing state.
1891  */
1892 _PUBLIC_ enum smb_encryption_setting
1893 cli_credentials_get_smb_encryption(struct cli_credentials *creds)
1894 {
1895         return creds->encryption_state;
1896 }
1897
1898 /**
1899  * Encrypt a data blob using the session key and the negotiated encryption
1900  * algorithm
1901  *
1902  * @param state Credential state, contains the session key and algorithm
1903  * @param data Data blob containing the data to be encrypted.
1904  *
1905  */
1906 _PUBLIC_ NTSTATUS netlogon_creds_session_encrypt(
1907         struct netlogon_creds_CredentialState *state,
1908         DATA_BLOB data)
1909 {
1910         NTSTATUS status;
1911
1912         if (data.data == NULL || data.length == 0) {
1913                 DBG_ERR("Nothing to encrypt "
1914                         "data.data == NULL or data.length == 0\n");
1915                 return NT_STATUS_INVALID_PARAMETER;
1916         }
1917         /*
1918          * Don't crypt an all-zero password it will give away the
1919          * NETLOGON pipe session key .
1920          */
1921         if (all_zero(data.data, data.length)) {
1922                 DBG_ERR("Supplied data all zeros, could leak session key\n");
1923                 return NT_STATUS_INVALID_PARAMETER;
1924         }
1925         if (state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1926                 status = netlogon_creds_aes_encrypt(state,
1927                                                     data.data,
1928                                                     data.length);
1929         } else if (state->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
1930                 status = netlogon_creds_arcfour_crypt(state,
1931                                                       data.data,
1932                                                       data.length);
1933         } else {
1934                 DBG_ERR("Unsupported encryption option negotiated\n");
1935                 status = NT_STATUS_NOT_SUPPORTED;
1936         }
1937         if (!NT_STATUS_IS_OK(status)) {
1938                 return status;
1939         }
1940         return NT_STATUS_OK;
1941 }
1942