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