r11649: - add support for ntcancel replies (they only happen in error cases,
[jelmer/samba4-debian.git] / source / libcli / raw / rawnotify.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client change notify operations
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "dlinklist.h"
24
25 /****************************************************************************
26 change notify (async send)
27 ****************************************************************************/
28 struct smbcli_request *smb_raw_changenotify_send(struct smbcli_tree *tree, struct smb_notify *parms)
29 {
30         struct smb_nttrans nt;
31         uint16_t setup[4];
32
33         nt.in.max_setup = 0;
34         nt.in.max_param = parms->in.buffer_size;
35         nt.in.max_data = 0;
36         nt.in.setup_count = 4;
37         nt.in.setup = setup;
38         SIVAL(setup, 0, parms->in.completion_filter);
39         SSVAL(setup, 4, parms->in.fnum);
40         SSVAL(setup, 6, parms->in.recursive);   
41         nt.in.function = NT_TRANSACT_NOTIFY_CHANGE;
42         nt.in.params = data_blob(NULL, 0);
43         nt.in.data = data_blob(NULL, 0);
44
45         return smb_raw_nttrans_send(tree, &nt);
46 }
47
48 /****************************************************************************
49 change notify (async recv)
50 ****************************************************************************/
51 NTSTATUS smb_raw_changenotify_recv(struct smbcli_request *req, 
52                                    TALLOC_CTX *mem_ctx, struct smb_notify *parms)
53 {
54         struct smb_nttrans nt;
55         NTSTATUS status;
56         uint32_t ofs, i;
57         struct smbcli_session *session = req?req->session:NULL;
58
59         status = smb_raw_nttrans_recv(req, mem_ctx, &nt);
60         if (!NT_STATUS_IS_OK(status)) {
61                 return status;
62         }
63
64         parms->out.changes = NULL;
65         parms->out.num_changes = 0;
66         
67         /* count them */
68         for (ofs=0; nt.out.params.length - ofs > 12; ) {
69                 uint32_t next = IVAL(nt.out.params.data, ofs);
70                 parms->out.num_changes++;
71                 if (next == 0 ||
72                     ofs + next >= nt.out.params.length) break;
73                 ofs += next;
74         }
75
76         /* allocate array */
77         parms->out.changes = talloc_array(mem_ctx, struct notify_changes, parms->out.num_changes);
78         if (!parms->out.changes) {
79                 return NT_STATUS_NO_MEMORY;
80         }
81
82         for (i=ofs=0; i<parms->out.num_changes; i++) {
83                 parms->out.changes[i].action = IVAL(nt.out.params.data, ofs+4);
84                 smbcli_blob_pull_string(session, mem_ctx, &nt.out.params, 
85                                      &parms->out.changes[i].name, 
86                                      ofs+8, ofs+12, STR_UNICODE);
87                 ofs += IVAL(nt.out.params.data, ofs);
88         }
89
90         return NT_STATUS_OK;
91 }
92
93 /****************************************************************************
94   handle ntcancel replies from the server,
95   as the MID of the real reply and the ntcancel reply is the same
96   we need to do find out to what request the reply belongs
97 ****************************************************************************/
98 struct smbcli_request *smbcli_handle_ntcancel_reply(struct smbcli_request *req,
99                                                     uint_t len, const uint8_t *hdr)
100 {
101         struct smbcli_request *ntcancel;
102
103         if (!req) return req;
104
105         if (!req->ntcancel) return req;
106
107         if (len >= MIN_SMB_SIZE + NBT_HDR_SIZE &&
108             (CVAL(hdr, HDR_FLG) & FLAG_REPLY) &&
109              CVAL(hdr,HDR_COM) == SMBntcancel) {
110                 ntcancel = req->ntcancel;
111                 DLIST_REMOVE(req->ntcancel, ntcancel);
112
113                 /*
114                  * TODO: untill we understand how the 
115                  *       smb_signing works for this case we 
116                  *       return NULL, to just ignore the packet
117                  */
118                 /*return ntcancel;*/
119                 return NULL;
120         }
121
122         return req;
123 }
124
125 /****************************************************************************
126  Send a NT Cancel request - used to hurry along a pending request. Usually
127  used to cancel a pending change notify request
128  note that this request does not expect a response!
129 ****************************************************************************/
130 NTSTATUS smb_raw_ntcancel(struct smbcli_request *oldreq)
131 {
132         struct smbcli_request *req;
133
134         req = smbcli_request_setup_transport(oldreq->transport, SMBntcancel, 0, 0);
135
136         SSVAL(req->out.hdr, HDR_MID, SVAL(oldreq->out.hdr, HDR_MID));   
137         SSVAL(req->out.hdr, HDR_PID, SVAL(oldreq->out.hdr, HDR_PID));   
138         SSVAL(req->out.hdr, HDR_TID, SVAL(oldreq->out.hdr, HDR_TID));   
139         SSVAL(req->out.hdr, HDR_UID, SVAL(oldreq->out.hdr, HDR_UID));   
140
141         /* this request does not expect a reply, so tell the signing
142            subsystem not to allocate an id for a reply */
143         req->sign_single_increment = 1;
144         req->one_way_request = 1;
145
146         /* 
147          * smbcli_request_send() free's oneway requests
148          * but we want to keep it under oldreq->ntcancel
149          */
150         if (!talloc_reference(oldreq, req)) {
151                 talloc_free(req);
152                 return NT_STATUS_NO_MEMORY;
153         }
154
155         smbcli_request_send(req);
156
157         DLIST_ADD_END(oldreq->ntcancel, req, struct smbcli_request *);
158
159         return NT_STATUS_OK;
160 }