source: vendor/current/auth/credentials/credentials.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 31.5 KB
Line 
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
618bool 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
675bool 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
722bool 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 /* if principal is set, it's not anonymous */
971 if ((cred->principal != NULL) && cred->principal_obtained >= cred->username_obtained) {
972 return false;
973 }
974
975 username = cli_credentials_get_username(cred);
976
977 /* Yes, it is deliberate that we die if we have a NULL pointer
978 * here - anonymous is "", not NULL, which is 'never specified,
979 * never guessed', ie programmer bug */
980 if (!username[0]) {
981 return true;
982 }
983
984 return false;
985}
986
987/**
988 * Mark the current password for a credentials struct as wrong. This will
989 * cause the password to be prompted again (if a callback is set).
990 *
991 * This will decrement the number of times the password can be tried.
992 *
993 * @retval whether the credentials struct is finished
994 */
995_PUBLIC_ bool cli_credentials_wrong_password(struct cli_credentials *cred)
996{
997 if (cred->password_obtained != CRED_CALLBACK_RESULT) {
998 return false;
999 }
1000
1001 if (cred->password_tries == 0) {
1002 return false;
1003 }
1004
1005 cred->password_tries--;
1006
1007 if (cred->password_tries == 0) {
1008 return false;
1009 }
1010
1011 cred->password_obtained = CRED_CALLBACK;
1012 return true;
1013}
1014
1015_PUBLIC_ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
1016 const char **username,
1017 const char **domain)
1018{
1019 if (cred->principal_obtained > cred->username_obtained) {
1020 *domain = talloc_strdup(mem_ctx, "");
1021 *username = cli_credentials_get_principal(cred, mem_ctx);
1022 } else {
1023 *domain = cli_credentials_get_domain(cred);
1024 *username = cli_credentials_get_username(cred);
1025 }
1026}
1027
1028/**
1029 * Read a named file, and parse it for username, domain, realm and password
1030 *
1031 * @param credentials Credentials structure on which to set the password
1032 * @param file a named file to read the details from
1033 * @param obtained This enum describes how 'specified' this password is
1034 */
1035
1036_PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const char *file, enum credentials_obtained obtained)
1037{
1038 uint16_t len = 0;
1039 char *ptr, *val, *param;
1040 char **lines;
1041 int i, numlines;
1042
1043 lines = file_lines_load(file, &numlines, 0, NULL);
1044
1045 if (lines == NULL)
1046 {
1047 /* fail if we can't open the credentials file */
1048 d_printf("ERROR: Unable to open credentials file!\n");
1049 return false;
1050 }
1051
1052 for (i = 0; i < numlines; i++) {
1053 len = strlen(lines[i]);
1054
1055 if (len == 0)
1056 continue;
1057
1058 /* break up the line into parameter & value.
1059 * will need to eat a little whitespace possibly */
1060 param = lines[i];
1061 if (!(ptr = strchr_m (lines[i], '=')))
1062 continue;
1063
1064 val = ptr+1;
1065 *ptr = '\0';
1066
1067 /* eat leading white space */
1068 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
1069 val++;
1070
1071 if (strwicmp("password", param) == 0) {
1072 cli_credentials_set_password(cred, val, obtained);
1073 } else if (strwicmp("username", param) == 0) {
1074 cli_credentials_set_username(cred, val, obtained);
1075 } else if (strwicmp("domain", param) == 0) {
1076 cli_credentials_set_domain(cred, val, obtained);
1077 } else if (strwicmp("realm", param) == 0) {
1078 cli_credentials_set_realm(cred, val, obtained);
1079 }
1080 memset(lines[i], 0, len);
1081 }
1082
1083 talloc_free(lines);
1084
1085 return true;
1086}
1087
1088/**
1089 * Read a named file, and parse it for a password
1090 *
1091 * @param credentials Credentials structure on which to set the password
1092 * @param file a named file to read the password from
1093 * @param obtained This enum describes how 'specified' this password is
1094 */
1095
1096_PUBLIC_ bool cli_credentials_parse_password_file(struct cli_credentials *credentials, const char *file, enum credentials_obtained obtained)
1097{
1098 int fd = open(file, O_RDONLY, 0);
1099 bool ret;
1100
1101 if (fd < 0) {
1102 fprintf(stderr, "Error opening password file %s: %s\n",
1103 file, strerror(errno));
1104 return false;
1105 }
1106
1107 ret = cli_credentials_parse_password_fd(credentials, fd, obtained);
1108
1109 close(fd);
1110
1111 return ret;
1112}
1113
1114
1115/**
1116 * Read a file descriptor, and parse it for a password (eg from a file or stdin)
1117 *
1118 * @param credentials Credentials structure on which to set the password
1119 * @param fd open file descriptor to read the password from
1120 * @param obtained This enum describes how 'specified' this password is
1121 */
1122
1123_PUBLIC_ bool cli_credentials_parse_password_fd(struct cli_credentials *credentials,
1124 int fd, enum credentials_obtained obtained)
1125{
1126 char *p;
1127 char pass[128];
1128
1129 for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
1130 p && p - pass < sizeof(pass);) {
1131 switch (read(fd, p, 1)) {
1132 case 1:
1133 if (*p != '\n' && *p != '\0') {
1134 *++p = '\0'; /* advance p, and null-terminate pass */
1135 break;
1136 }
1137 /* fall through */
1138 case 0:
1139 if (p - pass) {
1140 *p = '\0'; /* null-terminate it, just in case... */
1141 p = NULL; /* then force the loop condition to become false */
1142 break;
1143 } else {
1144 fprintf(stderr, "Error reading password from file descriptor %d: %s\n", fd, "empty password\n");
1145 return false;
1146 }
1147
1148 default:
1149 fprintf(stderr, "Error reading password from file descriptor %d: %s\n",
1150 fd, strerror(errno));
1151 return false;
1152 }
1153 }
1154
1155 cli_credentials_set_password(credentials, pass, obtained);
1156 return true;
1157}
1158
1159
Note: See TracBrowser for help on using the repository browser.