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