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