r2655: fixed an error in the shutdown of the sock->transport->session->tree
[samba.git] / source4 / libcli / raw / clisession.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB client session context management functions
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) James Myers 2003 <myersjj@samba.org>
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 #define SETUP_REQUEST_SESSION(cmd, wct, buflen) do { \
25         req = smbcli_request_setup_session(session, cmd, wct, buflen); \
26         if (!req) return NULL; \
27 } while (0)
28
29 /****************************************************************************
30  Initialize the session context
31 ****************************************************************************/
32 struct smbcli_session *smbcli_session_init(struct smbcli_transport *transport)
33 {
34         struct smbcli_session *session;
35
36         session = talloc_p(transport, struct smbcli_session);
37         if (!session) {
38                 return NULL;
39         }
40
41         ZERO_STRUCTP(session);
42         session->transport = transport;
43         session->pid = (uint16_t)getpid();
44         session->vuid = UID_FIELD_INVALID;
45         session->transport->reference_count++;
46
47         return session;
48 }
49
50 /****************************************************************************
51 reduce reference_count and destroy is <= 0
52 ****************************************************************************/
53 void smbcli_session_close(struct smbcli_session *session)
54 {
55         session->reference_count--;
56         if (session->reference_count <= 0) {
57                 smbcli_transport_close(session->transport);
58         }
59 }
60
61 /****************************************************************************
62  Perform a session setup (async send)
63 ****************************************************************************/
64 struct smbcli_request *smb_raw_session_setup_send(struct smbcli_session *session, union smb_sesssetup *parms) 
65 {
66         struct smbcli_request *req = NULL;
67
68         switch (parms->generic.level) {
69         case RAW_SESSSETUP_GENERIC:
70                 /* handled elsewhere */
71                 return NULL;
72
73         case RAW_SESSSETUP_OLD:
74                 SETUP_REQUEST_SESSION(SMBsesssetupX, 10, 0);
75                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
76                 SSVAL(req->out.vwv, VWV(1), 0);
77                 SSVAL(req->out.vwv,VWV(2),parms->old.in.bufsize);
78                 SSVAL(req->out.vwv,VWV(3),parms->old.in.mpx_max);
79                 SSVAL(req->out.vwv,VWV(4),parms->old.in.vc_num);
80                 SIVAL(req->out.vwv,VWV(5),parms->old.in.sesskey);
81                 SSVAL(req->out.vwv,VWV(7),parms->old.in.password.length);
82                 SIVAL(req->out.vwv,VWV(8), 0); /* reserved */
83                 smbcli_req_append_blob(req, &parms->old.in.password);
84                 smbcli_req_append_string(req, parms->old.in.user, STR_TERMINATE);
85                 smbcli_req_append_string(req, parms->old.in.domain, STR_TERMINATE|STR_UPPER);
86                 smbcli_req_append_string(req, parms->old.in.os, STR_TERMINATE);
87                 smbcli_req_append_string(req, parms->old.in.lanman, STR_TERMINATE);
88                 break;
89
90         case RAW_SESSSETUP_NT1:
91                 SETUP_REQUEST_SESSION(SMBsesssetupX, 13, 0);
92                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
93                 SSVAL(req->out.vwv, VWV(1), 0);
94                 SSVAL(req->out.vwv, VWV(2), parms->nt1.in.bufsize);
95                 SSVAL(req->out.vwv, VWV(3), parms->nt1.in.mpx_max);
96                 SSVAL(req->out.vwv, VWV(4), parms->nt1.in.vc_num);
97                 SIVAL(req->out.vwv, VWV(5), parms->nt1.in.sesskey);
98                 SSVAL(req->out.vwv, VWV(7), parms->nt1.in.password1.length);
99                 SSVAL(req->out.vwv, VWV(8), parms->nt1.in.password2.length);
100                 SIVAL(req->out.vwv, VWV(9), 0); /* reserved */
101                 SIVAL(req->out.vwv, VWV(11), parms->nt1.in.capabilities);
102                 smbcli_req_append_blob(req, &parms->nt1.in.password1);
103                 smbcli_req_append_blob(req, &parms->nt1.in.password2);
104                 smbcli_req_append_string(req, parms->nt1.in.user, STR_TERMINATE);
105                 smbcli_req_append_string(req, parms->nt1.in.domain, STR_TERMINATE|STR_UPPER);
106                 smbcli_req_append_string(req, parms->nt1.in.os, STR_TERMINATE);
107                 smbcli_req_append_string(req, parms->nt1.in.lanman, STR_TERMINATE);
108                 break;
109
110         case RAW_SESSSETUP_SPNEGO:
111                 SETUP_REQUEST_SESSION(SMBsesssetupX, 12, 0);
112                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
113                 SSVAL(req->out.vwv, VWV(1), 0);
114                 SSVAL(req->out.vwv, VWV(2), parms->spnego.in.bufsize);
115                 SSVAL(req->out.vwv, VWV(3), parms->spnego.in.mpx_max);
116                 SSVAL(req->out.vwv, VWV(4), parms->spnego.in.vc_num);
117                 SIVAL(req->out.vwv, VWV(5), parms->spnego.in.sesskey);
118                 SSVAL(req->out.vwv, VWV(7), parms->spnego.in.secblob.length);
119                 SIVAL(req->out.vwv, VWV(8), 0); /* reserved */
120                 SIVAL(req->out.vwv, VWV(10), parms->spnego.in.capabilities);
121                 smbcli_req_append_blob(req, &parms->spnego.in.secblob);
122                 smbcli_req_append_string(req, parms->spnego.in.os, STR_TERMINATE);
123                 smbcli_req_append_string(req, parms->spnego.in.lanman, STR_TERMINATE);
124                 smbcli_req_append_string(req, parms->spnego.in.domain, STR_TERMINATE);
125                 break;
126         }
127
128         if (!smbcli_request_send(req)) {
129                 smbcli_request_destroy(req);
130                 return NULL;
131         }
132
133         return req;
134 }
135
136
137 /****************************************************************************
138  Perform a session setup (async recv)
139 ****************************************************************************/
140 NTSTATUS smb_raw_session_setup_recv(struct smbcli_request *req, 
141                                     TALLOC_CTX *mem_ctx, 
142                                     union smb_sesssetup *parms) 
143 {
144         uint16_t len;
145         char *p;
146
147         if (!smbcli_request_receive(req)) {
148                 return smbcli_request_destroy(req);
149         }
150         
151         if (!NT_STATUS_IS_OK(req->status) &&
152             !NT_STATUS_EQUAL(req->status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
153                 return smbcli_request_destroy(req);
154         }
155
156         switch (parms->generic.level) {
157         case RAW_SESSSETUP_GENERIC:
158                 /* handled elsewhere */
159                 return NT_STATUS_INVALID_LEVEL;
160
161         case RAW_SESSSETUP_OLD:
162                 SMBCLI_CHECK_WCT(req, 3);
163                 ZERO_STRUCT(parms->old.out);
164                 parms->old.out.vuid = SVAL(req->in.hdr, HDR_UID);
165                 parms->old.out.action = SVAL(req->in.vwv, VWV(2));
166                 p = req->in.data;
167                 if (p) {
168                         p += smbcli_req_pull_string(req, mem_ctx, &parms->old.out.os, p, -1, STR_TERMINATE);
169                         p += smbcli_req_pull_string(req, mem_ctx, &parms->old.out.lanman, p, -1, STR_TERMINATE);
170                         p += smbcli_req_pull_string(req, mem_ctx, &parms->old.out.domain, p, -1, STR_TERMINATE);
171                 }
172                 break;
173
174         case RAW_SESSSETUP_NT1:
175                 SMBCLI_CHECK_WCT(req, 3);
176                 ZERO_STRUCT(parms->nt1.out);
177                 parms->nt1.out.vuid   = SVAL(req->in.hdr, HDR_UID);
178                 parms->nt1.out.action = SVAL(req->in.vwv, VWV(2));
179                 p = req->in.data;
180                 if (p) {
181                         p += smbcli_req_pull_string(req, mem_ctx, &parms->nt1.out.os, p, -1, STR_TERMINATE);
182                         p += smbcli_req_pull_string(req, mem_ctx, &parms->nt1.out.lanman, p, -1, STR_TERMINATE);
183                         if (p < (req->in.data + req->in.data_size)) {
184                                 p += smbcli_req_pull_string(req, mem_ctx, &parms->nt1.out.domain, p, -1, STR_TERMINATE);
185                         }
186                 }
187                 break;
188
189         case RAW_SESSSETUP_SPNEGO:
190                 SMBCLI_CHECK_WCT(req, 4);
191                 ZERO_STRUCT(parms->spnego.out);
192                 parms->spnego.out.vuid   = SVAL(req->in.hdr, HDR_UID);
193                 parms->spnego.out.action = SVAL(req->in.vwv, VWV(2));
194                 len                      = SVAL(req->in.vwv, VWV(3));
195                 p = req->in.data;
196                 if (!p) {
197                         break;
198                 }
199
200                 parms->spnego.out.secblob = smbcli_req_pull_blob(req, mem_ctx, p, len);
201                 p += parms->spnego.out.secblob.length;
202                 p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE);
203                 p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE);
204                 p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.domain, p, -1, STR_TERMINATE);
205                 break;
206         }
207
208 failed:
209         return smbcli_request_destroy(req);
210 }
211
212 /*
213   form an encrypted lanman password from a plaintext password
214   and the server supplied challenge
215 */
216 static DATA_BLOB lanman_blob(const char *pass, DATA_BLOB challenge)
217 {
218         DATA_BLOB blob = data_blob(NULL, 24);
219         SMBencrypt(pass, challenge.data, blob.data);
220         return blob;
221 }
222
223 /*
224   form an encrypted NT password from a plaintext password
225   and the server supplied challenge
226 */
227 static DATA_BLOB nt_blob(const char *pass, DATA_BLOB challenge)
228 {
229         DATA_BLOB blob = data_blob(NULL, 24);
230         SMBNTencrypt(pass, challenge.data, blob.data);
231         return blob;
232 }
233
234 /*
235   store the user session key for a transport
236 */
237 void smbcli_session_set_user_session_key(struct smbcli_session *session,
238                                    const DATA_BLOB *session_key)
239 {
240         session->user_session_key = data_blob_talloc(session, 
241                                                      session_key->data, 
242                                                      session_key->length);
243 }
244
245 /*
246   setup signing for a NT1 style session setup
247 */
248 static void use_nt1_session_keys(struct smbcli_session *session, 
249                                  const char *password, const DATA_BLOB  *nt_response)
250 {
251         struct smbcli_transport *transport = session->transport; 
252         uint8_t nt_hash[16];
253         DATA_BLOB session_key = data_blob(NULL, 16);
254
255         E_md4hash(password, nt_hash);
256         SMBsesskeygen_ntv1(nt_hash, session_key.data);
257
258         smbcli_transport_simple_set_signing(transport, session_key, *nt_response);
259
260         smbcli_session_set_user_session_key(session, &session_key);
261         data_blob_free(&session_key);
262 }
263
264 /****************************************************************************
265  Perform a session setup (sync interface) using generic interface and the old
266  style sesssetup call
267 ****************************************************************************/
268 static NTSTATUS smb_raw_session_setup_generic_old(struct smbcli_session *session, 
269                                                   TALLOC_CTX *mem_ctx, 
270                                                   union smb_sesssetup *parms) 
271 {
272         NTSTATUS status;
273         union smb_sesssetup s2;
274
275         /* use the old interface */
276         s2.generic.level = RAW_SESSSETUP_OLD;
277         s2.old.in.bufsize = ~0;
278         s2.old.in.mpx_max = 50;
279         s2.old.in.vc_num = 1;
280         s2.old.in.sesskey = parms->generic.in.sesskey;
281         s2.old.in.domain = parms->generic.in.domain;
282         s2.old.in.user = parms->generic.in.user;
283         s2.old.in.os = "Unix";
284         s2.old.in.lanman = "Samba";
285         
286         if (!parms->generic.in.password) {
287                 s2.old.in.password = data_blob(NULL, 0);
288         } else if (session->transport->negotiate.sec_mode & 
289                    NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
290                 s2.old.in.password = lanman_blob(parms->generic.in.password, 
291                                                  session->transport->negotiate.secblob);
292         } else {
293                 s2.old.in.password = data_blob(parms->generic.in.password, 
294                                                strlen(parms->generic.in.password));
295         }
296         
297         status = smb_raw_session_setup(session, mem_ctx, &s2);
298         
299         data_blob_free(&s2.old.in.password);
300         
301         if (!NT_STATUS_IS_OK(status)) {
302                 return status;
303         }
304         
305         parms->generic.out.vuid = s2.old.out.vuid;
306         parms->generic.out.os = s2.old.out.os;
307         parms->generic.out.lanman = s2.old.out.lanman;
308         parms->generic.out.domain = s2.old.out.domain;
309         
310         return NT_STATUS_OK;
311 }
312
313 /****************************************************************************
314  Perform a session setup (sync interface) using generic interface and the NT1
315  style sesssetup call
316 ****************************************************************************/
317 static NTSTATUS smb_raw_session_setup_generic_nt1(struct smbcli_session *session, 
318                                                   TALLOC_CTX *mem_ctx,
319                                                   union smb_sesssetup *parms) 
320 {
321         NTSTATUS status;
322         union smb_sesssetup s2;
323
324         s2.generic.level = RAW_SESSSETUP_NT1;
325         s2.nt1.in.bufsize = ~0;
326         s2.nt1.in.mpx_max = 50;
327         s2.nt1.in.vc_num = 1;
328         s2.nt1.in.sesskey = parms->generic.in.sesskey;
329         s2.nt1.in.capabilities = parms->generic.in.capabilities;
330         s2.nt1.in.domain = parms->generic.in.domain;
331         s2.nt1.in.user = parms->generic.in.user;
332         s2.nt1.in.os = "Unix";
333         s2.nt1.in.lanman = "Samba";
334
335         if (!parms->generic.in.password) {
336                 s2.nt1.in.password1 = data_blob(NULL, 0);
337                 s2.nt1.in.password2 = data_blob(NULL, 0);
338         } else if (session->transport->negotiate.sec_mode & 
339                    NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
340                 s2.nt1.in.password1 = lanman_blob(parms->generic.in.password, 
341                                                   session->transport->negotiate.secblob);
342                 s2.nt1.in.password2 = nt_blob(parms->generic.in.password, 
343                                               session->transport->negotiate.secblob);
344                 use_nt1_session_keys(session, parms->generic.in.password, &s2.nt1.in.password2);
345
346         } else {
347                 s2.nt1.in.password1 = data_blob(parms->generic.in.password, 
348                                                 strlen(parms->generic.in.password));
349                 s2.nt1.in.password2 = data_blob(NULL, 0);
350         }
351
352         status = smb_raw_session_setup(session, mem_ctx, &s2);
353                 
354         data_blob_free(&s2.nt1.in.password1);
355         data_blob_free(&s2.nt1.in.password2);
356                 
357         if (!NT_STATUS_IS_OK(status)) {
358                 return status;
359         }
360
361         parms->generic.out.vuid = s2.nt1.out.vuid;
362         parms->generic.out.os = s2.nt1.out.os;
363         parms->generic.out.lanman = s2.nt1.out.lanman;
364         parms->generic.out.domain = s2.nt1.out.domain;
365
366         return NT_STATUS_OK;
367 }
368
369 /****************************************************************************
370  Perform a session setup (sync interface) using generic interface and the SPNEGO
371  style sesssetup call
372 ****************************************************************************/
373 static NTSTATUS smb_raw_session_setup_generic_spnego(struct smbcli_session *session, 
374                                                   TALLOC_CTX *mem_ctx,
375                                                   union smb_sesssetup *parms) 
376 {
377         NTSTATUS status;
378         NTSTATUS session_key_err = NT_STATUS_NO_USER_SESSION_KEY;
379         union smb_sesssetup s2;
380         DATA_BLOB session_key = data_blob(NULL, 0);
381         DATA_BLOB null_data_blob = data_blob(NULL, 0);
382         const char *chosen_oid;
383
384         s2.generic.level = RAW_SESSSETUP_SPNEGO;
385         s2.spnego.in.bufsize = ~0;
386         s2.spnego.in.mpx_max = 50;
387         s2.spnego.in.vc_num = 1;
388         s2.spnego.in.sesskey = parms->generic.in.sesskey;
389         s2.spnego.in.capabilities = parms->generic.in.capabilities;
390         s2.spnego.in.domain = parms->generic.in.domain;
391         s2.spnego.in.os = "Unix";
392         s2.spnego.in.lanman = "Samba";
393         s2.spnego.out.vuid = session->vuid;
394
395         smbcli_temp_set_signing(session->transport);
396
397         status = gensec_client_start(session, &session->gensec);
398         if (!NT_STATUS_IS_OK(status)) {
399                 DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
400                 goto done;
401         }
402
403         gensec_want_feature(session->gensec, GENSEC_WANT_SESSION_KEY);
404
405         status = gensec_set_domain(session->gensec, parms->generic.in.domain);
406         if (!NT_STATUS_IS_OK(status)) {
407                 DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", 
408                           parms->generic.in.domain, nt_errstr(status)));
409                 goto done;
410         }
411
412         status = gensec_set_username(session->gensec, parms->generic.in.user);
413         if (!NT_STATUS_IS_OK(status)) {
414                 DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", 
415                           parms->generic.in.user, nt_errstr(status)));
416                 goto done;
417         }
418
419         status = gensec_set_password(session->gensec, parms->generic.in.password);
420         if (!NT_STATUS_IS_OK(status)) {
421                 DEBUG(1, ("Failed to start set GENSEC client password: %s\n", 
422                           nt_errstr(status)));
423                 goto done;
424         }
425
426         status = gensec_set_target_hostname(session->gensec, session->transport->socket->hostname);
427         if (!NT_STATUS_IS_OK(status)) {
428                 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
429                           nt_errstr(status)));
430                 goto done;
431         }
432
433         if (session->transport->negotiate.secblob.length) {
434                 chosen_oid = OID_SPNEGO;
435         } else {
436                 /* without a sec blob, means raw NTLMSSP */
437                 chosen_oid = OID_NTLMSSP;
438         }
439
440         status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
441         if (!NT_STATUS_IS_OK(status)) {
442                 DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism %s: %s\n",
443                           gensec_get_name_by_oid(chosen_oid), nt_errstr(status)));
444                 goto done;
445         }
446         
447         status = gensec_update(session->gensec, mem_ctx,
448                                session->transport->negotiate.secblob,
449                                &s2.spnego.in.secblob);
450
451         while(1) {
452                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
453                         break;
454                 }
455
456                 if (!NT_STATUS_IS_OK(session_key_err)) {
457                         session_key_err = gensec_session_key(session->gensec, &session_key);
458                 }
459                 if (NT_STATUS_IS_OK(session_key_err)) {
460                         smbcli_transport_simple_set_signing(session->transport, session_key, null_data_blob);
461                 }
462                 
463                 if (NT_STATUS_IS_OK(status) && s2.spnego.in.secblob.length == 0) {
464                         break;
465                 }
466
467                 session->vuid = s2.spnego.out.vuid;
468                 status = smb_raw_session_setup(session, mem_ctx, &s2);
469                 session->vuid = UID_FIELD_INVALID;
470                 if (!NT_STATUS_IS_OK(status) &&
471                     !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
472                         break;
473                 }
474
475                 status = gensec_update(session->gensec, mem_ctx,
476                                        s2.spnego.out.secblob,
477                                        &s2.spnego.in.secblob);
478
479         }
480
481 done:
482         if (NT_STATUS_IS_OK(status)) {
483                 if (!NT_STATUS_IS_OK(session_key_err)) {
484                         DEBUG(1, ("Failed to get user session key: %s\n", nt_errstr(session_key_err)));
485                         return session_key_err;
486                 }
487
488                 smbcli_session_set_user_session_key(session, &session_key);
489
490                 parms->generic.out.vuid = s2.spnego.out.vuid;
491                 parms->generic.out.os = s2.spnego.out.os;
492                 parms->generic.out.lanman = s2.spnego.out.lanman;
493                 parms->generic.out.domain = s2.spnego.out.domain;
494         } else {
495                 gensec_end(&session->gensec);
496                 DEBUG(1, ("Failed to login with %s: %s\n", gensec_get_name_by_oid(chosen_oid), nt_errstr(status)));
497                 return status;
498         }
499
500         return status;
501 }
502
503 /****************************************************************************
504  Perform a session setup (sync interface) using generic interface
505 ****************************************************************************/
506 static NTSTATUS smb_raw_session_setup_generic(struct smbcli_session *session, 
507                                               TALLOC_CTX *mem_ctx,
508                                               union smb_sesssetup *parms) 
509 {
510         if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) {
511                 /* no session setup at all in earliest protocols */
512                 ZERO_STRUCT(parms->generic.out);
513                 return NT_STATUS_OK;
514         }
515
516         /* see if we need to use the original session setup interface */
517         if (session->transport->negotiate.protocol < PROTOCOL_NT1) {
518                 return smb_raw_session_setup_generic_old(session, mem_ctx, parms);
519         }
520
521         /* see if we should use the NT1 interface */
522         if (!session->transport->options.use_spnego ||
523             !(parms->generic.in.capabilities & CAP_EXTENDED_SECURITY)) {
524                 return smb_raw_session_setup_generic_nt1(session, mem_ctx, parms);
525         }
526
527         /* default to using SPNEGO/NTLMSSP */
528         return smb_raw_session_setup_generic_spnego(session, mem_ctx, parms);
529 }
530
531
532 /****************************************************************************
533  Perform a session setup (sync interface)
534 this interface allows for RAW_SESSSETUP_GENERIC to auto-select session
535 setup variant based on negotiated protocol options
536 ****************************************************************************/
537 NTSTATUS smb_raw_session_setup(struct smbcli_session *session, TALLOC_CTX *mem_ctx, 
538                                union smb_sesssetup *parms) 
539 {
540         struct smbcli_request *req;
541
542         if (parms->generic.level == RAW_SESSSETUP_GENERIC) {
543                 NTSTATUS ret = smb_raw_session_setup_generic(session, mem_ctx, parms);
544
545                 if (NT_STATUS_IS_OK(ret) 
546                     && parms->generic.in.user 
547                     && *parms->generic.in.user) {
548                         if (!session->transport->negotiate.sign_info.doing_signing 
549                             && session->transport->negotiate.sign_info.mandatory_signing) {
550                                 DEBUG(0, ("SMB signing required, but server does not support it\n"));
551                                 return NT_STATUS_ACCESS_DENIED;
552                         }
553                 }
554                 return ret;
555         }
556
557         req = smb_raw_session_setup_send(session, parms);
558         return smb_raw_session_setup_recv(req, mem_ctx, parms);
559 }
560
561
562 /****************************************************************************
563  Send a uloggoff (async send)
564 *****************************************************************************/
565 struct smbcli_request *smb_raw_ulogoff_send(struct smbcli_session *session)
566 {
567         struct smbcli_request *req;
568
569         SETUP_REQUEST_SESSION(SMBulogoffX, 2, 0);
570
571         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
572         SSVAL(req->out.vwv, VWV(1), 0);
573
574         if (!smbcli_request_send(req)) {
575                 smbcli_request_destroy(req);
576                 return NULL;
577         }
578
579         return req;
580 }
581
582 /****************************************************************************
583  Send a uloggoff (sync interface)
584 *****************************************************************************/
585 NTSTATUS smb_raw_ulogoff(struct smbcli_session *session)
586 {
587         struct smbcli_request *req = smb_raw_ulogoff_send(session);
588         return smbcli_request_simple_recv(req);
589 }
590
591
592 /****************************************************************************
593  Send a SMBexit
594 ****************************************************************************/
595 NTSTATUS smb_raw_exit(struct smbcli_session *session)
596 {
597         struct smbcli_request *req;
598
599         req = smbcli_request_setup_session(session, SMBexit, 0, 0);
600
601         if (smbcli_request_send(req)) {
602                 smbcli_request_receive(req);
603         }
604         return smbcli_request_destroy(req);
605 }