2 Unix SMB/Netbios implementation.
4 handle NLTMSSP, server side
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett 2001-2003
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * Print out the NTLMSSP flags for debugging
28 * @param neg_flags The flags from the packet
31 void debug_ntlmssp_flags(uint32 neg_flags
)
33 DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags
));
35 if (neg_flags
& NTLMSSP_NEGOTIATE_UNICODE
)
36 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n"));
37 if (neg_flags
& NTLMSSP_NEGOTIATE_OEM
)
38 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n"));
39 if (neg_flags
& NTLMSSP_REQUEST_TARGET
)
40 DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n"));
41 if (neg_flags
& NTLMSSP_NEGOTIATE_SIGN
)
42 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n"));
43 if (neg_flags
& NTLMSSP_NEGOTIATE_SEAL
)
44 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n"));
45 if (neg_flags
& NTLMSSP_NEGOTIATE_LM_KEY
)
46 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n"));
47 if (neg_flags
& NTLMSSP_NEGOTIATE_NETWARE
)
48 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n"));
49 if (neg_flags
& NTLMSSP_NEGOTIATE_NTLM
)
50 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n"));
51 if (neg_flags
& NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED
)
52 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n"));
53 if (neg_flags
& NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED
)
54 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n"));
55 if (neg_flags
& NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL
)
56 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
57 if (neg_flags
& NTLMSSP_NEGOTIATE_ALWAYS_SIGN
)
58 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
59 if (neg_flags
& NTLMSSP_NEGOTIATE_NTLM2
)
60 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n"));
61 if (neg_flags
& NTLMSSP_CHAL_TARGET_INFO
)
62 DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n"));
63 if (neg_flags
& NTLMSSP_NEGOTIATE_128
)
64 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n"));
65 if (neg_flags
& NTLMSSP_NEGOTIATE_KEY_EXCH
)
66 DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
70 * Default challenge generation code.
74 static const uint8
*get_challenge(struct ntlmssp_state
*ntlmssp_state
)
77 generate_random_buffer(chal
, sizeof(chal
), False
);
83 * Determine correct target name flags for reply, given server role
84 * and negotiated flags
86 * @param ntlmssp_state NTLMSSP State
87 * @param neg_flags The flags from the packet
88 * @param chal_flags The flags to be set in the reply packet
89 * @return The 'target name' string.
92 static const char *ntlmssp_target_name(struct ntlmssp_state
*ntlmssp_state
,
93 uint32 neg_flags
, uint32
*chal_flags
)
95 if (neg_flags
& NTLMSSP_REQUEST_TARGET
) {
96 *chal_flags
|= NTLMSSP_CHAL_TARGET_INFO
;
97 *chal_flags
|= NTLMSSP_REQUEST_TARGET
;
98 if (ntlmssp_state
->server_role
== ROLE_STANDALONE
) {
99 *chal_flags
|= NTLMSSP_TARGET_TYPE_SERVER
;
100 return ntlmssp_state
->get_global_myname();
102 *chal_flags
|= NTLMSSP_TARGET_TYPE_DOMAIN
;
103 return ntlmssp_state
->get_domain();
111 * Next state function for the Negotiate packet
113 * @param ntlmssp_state NTLMSSP State
114 * @param request The request, as a DATA_BLOB
115 * @param request The reply, as an allocated DATA_BLOB, caller to free.
116 * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent.
119 static NTSTATUS
ntlmssp_server_negotiate(struct ntlmssp_state
*ntlmssp_state
,
120 const DATA_BLOB request
, DATA_BLOB
*reply
)
122 DATA_BLOB struct_blob
;
123 fstring dnsname
, dnsdomname
;
124 uint32 neg_flags
= 0;
125 uint32 ntlmssp_command
, chal_flags
;
126 char *cliname
=NULL
, *domname
=NULL
;
127 const uint8
*cryptkey
;
128 const char *target_name
;
130 /* parse the NTLMSSP packet */
132 file_save("ntlmssp_negotiate.dat", request
.data
, request
.length
);
135 if (request
.length
) {
136 if (!msrpc_parse(&request
, "CddAA",
142 DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP:\n"));
143 dump_data(2, request
.data
, request
.length
);
144 return NT_STATUS_INVALID_PARAMETER
;
150 debug_ntlmssp_flags(neg_flags
);
153 cryptkey
= ntlmssp_state
->get_challenge(ntlmssp_state
);
155 data_blob_free(&ntlmssp_state
->chal
);
156 ntlmssp_state
->chal
= data_blob(cryptkey
, 8);
158 /* Give them the challenge. For now, ignore neg_flags and just
159 return the flags we want. Obviously this is not correct */
162 NTLMSSP_NEGOTIATE_128
|
163 NTLMSSP_NEGOTIATE_NTLM
;
165 if (neg_flags
& NTLMSSP_NEGOTIATE_UNICODE
) {
166 chal_flags
|= NTLMSSP_NEGOTIATE_UNICODE
;
167 ntlmssp_state
->unicode
= True
;
169 chal_flags
|= NTLMSSP_NEGOTIATE_OEM
;
172 target_name
= ntlmssp_target_name(ntlmssp_state
,
173 neg_flags
, &chal_flags
);
175 /* This should be a 'netbios domain -> DNS domain' mapping */
176 dnsdomname
[0] = '\0';
177 get_mydomname(dnsdomname
);
178 strlower(dnsdomname
);
181 get_myfullname(dnsname
);
184 if (chal_flags
& NTLMSSP_CHAL_TARGET_INFO
)
186 const char *target_name_dns
= "";
187 if (chal_flags
|= NTLMSSP_TARGET_TYPE_DOMAIN
) {
188 target_name_dns
= dnsdomname
;
189 } else if (chal_flags
|= NTLMSSP_TARGET_TYPE_SERVER
) {
190 target_name_dns
= dnsname
;
193 /* the numbers here are the string type flags */
194 msrpc_gen(&struct_blob
, "aaaaa",
195 ntlmssp_state
->unicode
, NTLMSSP_NAME_TYPE_DOMAIN
, target_name
,
196 ntlmssp_state
->unicode
, NTLMSSP_NAME_TYPE_SERVER
, ntlmssp_state
->get_global_myname(),
197 ntlmssp_state
->unicode
, NTLMSSP_NAME_TYPE_DOMAIN_DNS
, target_name_dns
,
198 ntlmssp_state
->unicode
, NTLMSSP_NAME_TYPE_SERVER_DNS
, dnsdomname
,
199 ntlmssp_state
->unicode
, 0, "");
201 struct_blob
= data_blob(NULL
, 0);
205 const char *gen_string
;
206 if (ntlmssp_state
->unicode
) {
207 gen_string
= "CdUdbddB";
209 gen_string
= "CdAdbddB";
212 msrpc_gen(reply
, gen_string
,
219 struct_blob
.data
, struct_blob
.length
);
222 data_blob_free(&struct_blob
);
224 ntlmssp_state
->expected_state
= NTLMSSP_AUTH
;
226 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
230 * Next state function for the Authenticate packet
232 * @param ntlmssp_state NTLMSSP State
233 * @param request The request, as a DATA_BLOB
234 * @param request The reply, as an allocated DATA_BLOB, caller to free.
235 * @return Errors or NT_STATUS_OK.
238 static NTSTATUS
ntlmssp_server_auth(struct ntlmssp_state
*ntlmssp_state
,
239 const DATA_BLOB request
, DATA_BLOB
*reply
)
242 uint32 ntlmssp_command
, neg_flags
;
245 const char *parse_string
;
247 /* parse the NTLMSSP packet */
249 file_save("ntlmssp_auth.dat", request
.data
, request
.length
);
252 if (ntlmssp_state
->unicode
) {
253 parse_string
= "CdBBUUUBd";
255 parse_string
= "CdBBAAABd";
258 data_blob_free(&ntlmssp_state
->lm_resp
);
259 data_blob_free(&ntlmssp_state
->nt_resp
);
261 SAFE_FREE(ntlmssp_state
->user
);
262 SAFE_FREE(ntlmssp_state
->domain
);
263 SAFE_FREE(ntlmssp_state
->workstation
);
265 /* now the NTLMSSP encoded auth hashes */
266 if (!msrpc_parse(&request
, parse_string
,
269 &ntlmssp_state
->lm_resp
,
270 &ntlmssp_state
->nt_resp
,
271 &ntlmssp_state
->domain
,
272 &ntlmssp_state
->user
,
273 &ntlmssp_state
->workstation
,
276 DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n"));
277 dump_data(2, request
.data
, request
.length
);
278 return NT_STATUS_INVALID_PARAMETER
;
281 data_blob_free(&sess_key
);
283 DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%d len2=%d\n",
284 ntlmssp_state
->user
, ntlmssp_state
->domain
, ntlmssp_state
->workstation
, ntlmssp_state
->lm_resp
.length
, ntlmssp_state
->nt_resp
.length
));
287 file_save("nthash1.dat", &ntlmssp_state
->nt_resp
.data
, &ntlmssp_state
->nt_resp
.length
);
288 file_save("lmhash1.dat", &ntlmssp_state
->lm_resp
.data
, &ntlmssp_state
->lm_resp
.length
);
291 nt_status
= ntlmssp_state
->check_password(ntlmssp_state
);
293 *reply
= data_blob(NULL
, 0);
299 * Create an NTLMSSP state machine
301 * @param ntlmssp_state NTLMSSP State, allocated by this function
304 NTSTATUS
ntlmssp_server_start(NTLMSSP_STATE
**ntlmssp_state
)
308 mem_ctx
= talloc_init("NTLMSSP context");
310 *ntlmssp_state
= talloc_zero(mem_ctx
, sizeof(**ntlmssp_state
));
311 if (!*ntlmssp_state
) {
312 DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
313 talloc_destroy(mem_ctx
);
314 return NT_STATUS_NO_MEMORY
;
317 (*ntlmssp_state
)->mem_ctx
= mem_ctx
;
318 (*ntlmssp_state
)->get_challenge
= get_challenge
;
320 (*ntlmssp_state
)->get_global_myname
= global_myname
;
321 (*ntlmssp_state
)->get_domain
= lp_workgroup
;
322 (*ntlmssp_state
)->server_role
= ROLE_DOMAIN_MEMBER
; /* a good default */
324 (*ntlmssp_state
)->expected_state
= NTLMSSP_NEGOTIATE
;
330 * End an NTLMSSP state machine
332 * @param ntlmssp_state NTLMSSP State, free()ed by this function
335 NTSTATUS
ntlmssp_server_end(NTLMSSP_STATE
**ntlmssp_state
)
337 TALLOC_CTX
*mem_ctx
= (*ntlmssp_state
)->mem_ctx
;
339 data_blob_free(&(*ntlmssp_state
)->chal
);
340 data_blob_free(&(*ntlmssp_state
)->lm_resp
);
341 data_blob_free(&(*ntlmssp_state
)->nt_resp
);
343 SAFE_FREE((*ntlmssp_state
)->user
);
344 SAFE_FREE((*ntlmssp_state
)->domain
);
345 SAFE_FREE((*ntlmssp_state
)->workstation
);
347 talloc_destroy(mem_ctx
);
348 *ntlmssp_state
= NULL
;
353 * Next state function for the NTLMSSP state machine
355 * @param ntlmssp_state NTLMSSP State
356 * @param request The request, as a DATA_BLOB
357 * @param request The reply, as an allocated DATA_BLOB, caller to free.
358 * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK.
361 NTSTATUS
ntlmssp_server_update(NTLMSSP_STATE
*ntlmssp_state
,
362 const DATA_BLOB request
, DATA_BLOB
*reply
)
364 uint32 ntlmssp_command
;
365 *reply
= data_blob(NULL
, 0);
367 if (request
.length
) {
368 if (!msrpc_parse(&request
, "Cd",
371 return NT_STATUS_INVALID_PARAMETER
;
374 /* 'datagram' mode - no neg packet */
375 ntlmssp_command
= NTLMSSP_NEGOTIATE
;
378 if (ntlmssp_command
!= ntlmssp_state
->expected_state
) {
379 DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command
, ntlmssp_state
->expected_state
));
380 return NT_STATUS_INVALID_PARAMETER
;
383 if (ntlmssp_command
== NTLMSSP_NEGOTIATE
) {
384 return ntlmssp_server_negotiate(ntlmssp_state
, request
, reply
);
385 } else if (ntlmssp_command
== NTLMSSP_AUTH
) {
386 return ntlmssp_server_auth(ntlmssp_state
, request
, reply
);
388 DEBUG(1, ("unknown NTLMSSP command %u, expected %u\n", ntlmssp_command
, ntlmssp_state
->expected_state
));
389 return NT_STATUS_INVALID_PARAMETER
;
393 /*********************************************************************
395 *********************************************************************/
398 * Next state function for the Initial packet
400 * @param ntlmssp_state NTLMSSP State
401 * @param request The request, as a DATA_BLOB. reply.data must be NULL
402 * @param request The reply, as an allocated DATA_BLOB, caller to free.
403 * @return Errors or NT_STATUS_OK.
406 static NTSTATUS
ntlmssp_client_initial(struct ntlmssp_client_state
*ntlmssp_state
,
407 DATA_BLOB reply
, DATA_BLOB
*next_request
)
409 if (ntlmssp_state
->unicode
) {
410 ntlmssp_state
->neg_flags
|= NTLMSSP_NEGOTIATE_UNICODE
;
413 /* generate the ntlmssp negotiate packet */
414 msrpc_gen(next_request
, "CddAA",
417 ntlmssp_state
->neg_flags
,
418 ntlmssp_state
->get_domain(),
419 ntlmssp_state
->get_global_myname());
421 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
425 * Next state function for the Challenge Packet. Generate an auth packet.
427 * @param ntlmssp_state NTLMSSP State
428 * @param request The request, as a DATA_BLOB. reply.data must be NULL
429 * @param request The reply, as an allocated DATA_BLOB, caller to free.
430 * @return Errors or NT_STATUS_OK.
433 static NTSTATUS
ntlmssp_client_challenge(struct ntlmssp_client_state
*ntlmssp_state
,
434 const DATA_BLOB reply
, DATA_BLOB
*next_request
)
436 uint32 chal_flags
, ntlmssp_command
, unkn1
, unkn2
;
437 DATA_BLOB server_domain_blob
;
438 DATA_BLOB challenge_blob
;
439 DATA_BLOB struct_blob
;
441 const char *chal_parse_string
;
442 const char *auth_gen_string
;
443 DATA_BLOB lm_response
= data_blob(NULL
, 0);
444 DATA_BLOB nt_response
= data_blob(NULL
, 0);
445 DATA_BLOB session_key
= data_blob(NULL
, 0);
446 uint8 datagram_sess_key
[16];
448 generate_random_buffer(datagram_sess_key
, sizeof(datagram_sess_key
), False
);
450 if (!msrpc_parse(&reply
, "CdBd",
455 DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
456 return NT_STATUS_INVALID_PARAMETER
;
459 data_blob_free(&server_domain_blob
);
461 if (chal_flags
& NTLMSSP_NEGOTIATE_UNICODE
) {
462 chal_parse_string
= "CdUdbddB";
463 auth_gen_string
= "CdBBUUUBd";
464 ntlmssp_state
->unicode
= True
;
465 ntlmssp_state
->neg_flags
|= NTLMSSP_NEGOTIATE_UNICODE
;
466 ntlmssp_state
->neg_flags
&= ~NTLMSSP_NEGOTIATE_OEM
;
467 } else if (chal_flags
& NTLMSSP_NEGOTIATE_OEM
) {
468 chal_parse_string
= "CdAdbddB";
469 auth_gen_string
= "CdBBAAABd";
470 ntlmssp_state
->unicode
= False
;
471 ntlmssp_state
->neg_flags
&= ~NTLMSSP_NEGOTIATE_UNICODE
;
472 ntlmssp_state
->neg_flags
|= NTLMSSP_NEGOTIATE_OEM
;
474 return NT_STATUS_INVALID_PARAMETER
;
477 if (!msrpc_parse(&reply
, chal_parse_string
,
485 DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
486 return NT_STATUS_INVALID_PARAMETER
;
489 SAFE_FREE(server_domain
);
490 data_blob_free(&struct_blob
);
492 if (challenge_blob
.length
!= 8) {
493 return NT_STATUS_INVALID_PARAMETER
;
496 if (ntlmssp_state
->use_ntlmv2
) {
498 /* TODO: if the remote server is standalone, then we should replace 'domain'
499 with the server name as supplied above */
501 if (!SMBNTLMv2encrypt(ntlmssp_state
->user
,
502 ntlmssp_state
->domain
,
503 ntlmssp_state
->password
, challenge_blob
,
504 &lm_response
, &nt_response
, &session_key
)) {
505 data_blob_free(&challenge_blob
);
506 return NT_STATUS_NO_MEMORY
;
510 E_md4hash(ntlmssp_state
->password
, nt_hash
);
512 /* non encrypted password supplied. Ignore ntpass. */
513 if (lp_client_lanman_auth()) {
514 lm_response
= data_blob(NULL
, 24);
515 SMBencrypt(ntlmssp_state
->password
,challenge_blob
.data
,
519 nt_response
= data_blob(NULL
, 24);
520 SMBNTencrypt(ntlmssp_state
->password
,challenge_blob
.data
,
522 session_key
= data_blob(NULL
, 16);
523 SMBsesskeygen_ntv1(nt_hash
, NULL
, session_key
.data
);
526 /* this generates the actual auth packet */
527 if (!msrpc_gen(next_request
, auth_gen_string
,
530 lm_response
.data
, lm_response
.length
,
531 nt_response
.data
, nt_response
.length
,
532 ntlmssp_state
->domain
,
534 ntlmssp_state
->get_global_myname(),
535 datagram_sess_key
, 16,
536 ntlmssp_state
->neg_flags
)) {
538 data_blob_free(&lm_response
);
539 data_blob_free(&nt_response
);
540 data_blob_free(&session_key
);
541 return NT_STATUS_NO_MEMORY
;
544 data_blob_free(&ntlmssp_state
->chal
);
545 data_blob_free(&ntlmssp_state
->lm_resp
);
546 data_blob_free(&ntlmssp_state
->nt_resp
);
547 data_blob_free(&ntlmssp_state
->session_key
);
549 ntlmssp_state
->chal
= challenge_blob
;
550 ntlmssp_state
->lm_resp
= lm_response
;
551 ntlmssp_state
->nt_resp
= nt_response
;
552 ntlmssp_state
->session_key
= session_key
;
554 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
557 NTSTATUS
ntlmssp_client_start(NTLMSSP_CLIENT_STATE
**ntlmssp_state
)
561 mem_ctx
= talloc_init("NTLMSSP Client context");
563 *ntlmssp_state
= talloc_zero(mem_ctx
, sizeof(**ntlmssp_state
));
564 if (!*ntlmssp_state
) {
565 DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
566 talloc_destroy(mem_ctx
);
567 return NT_STATUS_NO_MEMORY
;
570 (*ntlmssp_state
)->mem_ctx
= mem_ctx
;
572 (*ntlmssp_state
)->get_global_myname
= global_myname
;
573 (*ntlmssp_state
)->get_domain
= lp_workgroup
;
575 (*ntlmssp_state
)->unicode
= True
;
577 (*ntlmssp_state
)->neg_flags
=
578 NTLMSSP_NEGOTIATE_128
|
579 NTLMSSP_NEGOTIATE_NTLM
|
580 NTLMSSP_REQUEST_TARGET
;
582 (*ntlmssp_state
)->ref_count
= 1;
587 NTSTATUS
ntlmssp_client_end(NTLMSSP_CLIENT_STATE
**ntlmssp_state
)
589 TALLOC_CTX
*mem_ctx
= (*ntlmssp_state
)->mem_ctx
;
591 (*ntlmssp_state
)->ref_count
--;
593 if ((*ntlmssp_state
)->ref_count
== 0) {
594 data_blob_free(&(*ntlmssp_state
)->chal
);
595 data_blob_free(&(*ntlmssp_state
)->lm_resp
);
596 data_blob_free(&(*ntlmssp_state
)->nt_resp
);
597 data_blob_free(&(*ntlmssp_state
)->session_key
);
598 talloc_destroy(mem_ctx
);
601 *ntlmssp_state
= NULL
;
605 NTSTATUS
ntlmssp_client_update(NTLMSSP_CLIENT_STATE
*ntlmssp_state
,
606 DATA_BLOB reply
, DATA_BLOB
*next_request
)
608 uint32 ntlmssp_command
;
609 *next_request
= data_blob(NULL
, 0);
612 return ntlmssp_client_initial(ntlmssp_state
, reply
, next_request
);
615 if (!msrpc_parse(&reply
, "Cd",
618 return NT_STATUS_INVALID_PARAMETER
;
621 if (ntlmssp_command
== NTLMSSP_CHALLENGE
) {
622 return ntlmssp_client_challenge(ntlmssp_state
, reply
, next_request
);
624 return NT_STATUS_INVALID_PARAMETER
;
627 NTSTATUS
ntlmssp_set_username(NTLMSSP_CLIENT_STATE
*ntlmssp_state
, const char *user
)
629 ntlmssp_state
->user
= talloc_strdup(ntlmssp_state
->mem_ctx
, user
);
630 if (!ntlmssp_state
->user
) {
631 return NT_STATUS_NO_MEMORY
;
636 NTSTATUS
ntlmssp_set_password(NTLMSSP_CLIENT_STATE
*ntlmssp_state
, const char *password
)
638 ntlmssp_state
->password
= talloc_strdup(ntlmssp_state
->mem_ctx
, password
);
639 if (!ntlmssp_state
->password
) {
640 return NT_STATUS_NO_MEMORY
;
645 NTSTATUS
ntlmssp_set_domain(NTLMSSP_CLIENT_STATE
*ntlmssp_state
, const char *domain
)
647 ntlmssp_state
->domain
= talloc_strdup(ntlmssp_state
->mem_ctx
, domain
);
648 if (!ntlmssp_state
->domain
) {
649 return NT_STATUS_NO_MEMORY
;