s3:libsmb: make use of BVAL() and remove ugly LARGE_SMB_OFF_T ifdef's
[kai/samba.git] / source3 / libsmb / cliquota.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client quota functions
4    Copyright (C) Stefan (metze) Metzmacher      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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "../librpc/gen_ndr/ndr_security.h"
22 #include "fake_file.h"
23 #include "../libcli/security/security.h"
24 #include "trans2.h"
25
26 NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum)
27 {
28         return cli_ntcreate(cli, FAKE_FILE_NAME_QUOTA_WIN32,
29                  0x00000016, DESIRED_ACCESS_PIPE,
30                  0x00000000, FILE_SHARE_READ|FILE_SHARE_WRITE,
31                  FILE_OPEN, 0x00000000, 0x03, quota_fnum);
32 }
33
34 void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
35 {
36         if (!qt_list)
37                 return;
38
39         if ((*qt_list)->mem_ctx)
40                 talloc_destroy((*qt_list)->mem_ctx);
41
42         (*qt_list) = NULL;
43
44         return; 
45 }
46
47 static bool parse_user_quota_record(const uint8_t *rdata,
48                                     unsigned int rdata_count,
49                                     unsigned int *offset,
50                                     SMB_NTQUOTA_STRUCT *pqt)
51 {
52         int sid_len;
53         SMB_NTQUOTA_STRUCT qt;
54
55         ZERO_STRUCT(qt);
56
57         if (!rdata||!offset||!pqt) {
58                 smb_panic("parse_quota_record: called with NULL POINTER!");
59         }
60
61         if (rdata_count < 40) {
62                 return False;
63         }
64
65         /* offset to next quota record.
66          * 4 bytes IVAL(rdata,0)
67          * unused here...
68          */
69         *offset = IVAL(rdata,0);
70
71         /* sid len */
72         sid_len = IVAL(rdata,4);
73
74         if (rdata_count < 40+sid_len) {
75                 return False;           
76         }
77
78         /* unknown 8 bytes in pdata 
79          * maybe its the change time in NTTIME
80          */
81
82         /* the used space 8 bytes (uint64_t)*/
83         qt.usedspace = BVAL(rdata,16);
84
85         /* the soft quotas 8 bytes (uint64_t)*/
86         qt.softlim = BVAL(rdata,24);
87
88         /* the hard quotas 8 bytes (uint64_t)*/
89         qt.hardlim = BVAL(rdata,32);
90
91         if (!sid_parse((char *)rdata+40,sid_len,&qt.sid)) {
92                 return false;
93         }
94
95         qt.qtype = SMB_USER_QUOTA_TYPE;
96
97         *pqt = qt;
98
99         return True;
100 }
101
102 NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
103                             SMB_NTQUOTA_STRUCT *pqt)
104 {
105         uint16_t setup[1];
106         uint8_t params[16];
107         unsigned int data_len;
108         uint8_t data[SID_MAX_SIZE+8];
109         uint8_t *rparam, *rdata;
110         uint32_t rparam_count, rdata_count;
111         unsigned int sid_len;
112         unsigned int offset;
113         NTSTATUS status;
114
115         if (!cli||!pqt) {
116                 smb_panic("cli_get_user_quota() called with NULL Pointer!");
117         }
118
119         SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
120
121         SSVAL(params, 0,quota_fnum);
122         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID);
123         SIVAL(params, 4,0x00000024);
124         SIVAL(params, 8,0x00000000);
125         SIVAL(params,12,0x00000024);
126
127         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
128         data_len = sid_len+8;
129         SIVAL(data, 0, 0x00000000);
130         SIVAL(data, 4, sid_len);
131         sid_linearize((char *)data+8, sid_len, &pqt->sid);
132
133         status = cli_trans(talloc_tos(), cli, SMBnttrans,
134                            NULL, -1, /* name, fid */
135                            NT_TRANSACT_GET_USER_QUOTA, 0,
136                            setup, 1, 0, /* setup */
137                            params, 16, 4, /* params */
138                            data, data_len, 112, /* data */
139                            NULL,                /* recv_flags2 */
140                            NULL, 0, NULL,       /* rsetup */
141                            &rparam, 4, &rparam_count,
142                            &rdata, 8, &rdata_count);
143         if (!NT_STATUS_IS_OK(status)) {
144                 DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
145                           nt_errstr(status)));
146                 return status;
147         }
148
149         if (!parse_user_quota_record(rdata, rdata_count, &offset, pqt)) {
150                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
151                 DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
152         }
153
154         TALLOC_FREE(rparam);
155         TALLOC_FREE(rdata);
156         return status;
157 }
158
159 NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
160                             SMB_NTQUOTA_STRUCT *pqt)
161 {
162         uint16_t setup[1];
163         uint8_t params[2];
164         uint8_t data[112];
165         unsigned int sid_len;   
166         NTSTATUS status;
167
168         memset(data,'\0',112);
169
170         if (!cli||!pqt) {
171                 smb_panic("cli_set_user_quota() called with NULL Pointer!");
172         }
173
174         SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
175
176         SSVAL(params,0,quota_fnum);
177
178         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
179         SIVAL(data,0,0);
180         SIVAL(data,4,sid_len);
181         SBIG_UINT(data, 8,(uint64_t)0);
182         SBIG_UINT(data,16,pqt->usedspace);
183         SBIG_UINT(data,24,pqt->softlim);
184         SBIG_UINT(data,32,pqt->hardlim);
185         sid_linearize((char *)data+40, sid_len, &pqt->sid);
186
187         status = cli_trans(talloc_tos(), cli, SMBnttrans,
188                            NULL, -1, /* name, fid */
189                            NT_TRANSACT_SET_USER_QUOTA, 0,
190                            setup, 1, 0, /* setup */
191                            params, 2, 0, /* params */
192                            data, 112, 0, /* data */
193                            NULL,                /* recv_flags2 */
194                            NULL, 0, NULL,       /* rsetup */
195                            NULL, 0, NULL,       /* rparams */
196                            NULL, 0, NULL);      /* rdata */
197
198         if (!NT_STATUS_IS_OK(status)) {
199                 DEBUG(1, ("NT_TRANSACT_SET_USER_QUOTA failed: %s\n",
200                           nt_errstr(status)));
201         }
202
203         return status;
204 }
205
206 NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
207                              SMB_NTQUOTA_LIST **pqt_list)
208 {
209         uint16_t setup[1];
210         uint8_t params[16];
211         uint8_t *rparam=NULL, *rdata=NULL;
212         uint32_t rparam_count=0, rdata_count=0;
213         unsigned int offset;
214         const uint8_t *curdata = NULL;
215         unsigned int curdata_count = 0;
216         TALLOC_CTX *mem_ctx = NULL;
217         SMB_NTQUOTA_STRUCT qt;
218         SMB_NTQUOTA_LIST *tmp_list_ent;
219         NTSTATUS status;
220
221         if (!cli||!pqt_list) {
222                 smb_panic("cli_list_user_quota() called with NULL Pointer!");
223         }
224
225         SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
226
227         SSVAL(params, 0,quota_fnum);
228         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START);
229         SIVAL(params, 4,0x00000000);
230         SIVAL(params, 8,0x00000000);
231         SIVAL(params,12,0x00000000);
232
233         status = cli_trans(talloc_tos(), cli, SMBnttrans,
234                            NULL, -1, /* name, fid */
235                            NT_TRANSACT_GET_USER_QUOTA, 0,
236                            setup, 1, 0, /* setup */
237                            params, 16, 4, /* params */
238                            NULL, 0, 2048, /* data */
239                            NULL,                /* recv_flags2 */
240                            NULL, 0, NULL,       /* rsetup */
241                            &rparam, 0, &rparam_count,
242                            &rdata, 0, &rdata_count);
243
244         if (!NT_STATUS_IS_OK(status)) {
245                 DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
246                           nt_errstr(status)));
247                 goto cleanup;
248         }
249
250         if (rdata_count == 0) {
251                 *pqt_list = NULL;
252                 return NT_STATUS_OK;
253         }
254
255         if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
256                 DEBUG(0,("talloc_init() failed\n"));
257                 return NT_STATUS_NO_MEMORY;
258         }
259
260         offset = 1;
261         for (curdata=rdata,curdata_count=rdata_count;
262                 ((curdata)&&(curdata_count>=8)&&(offset>0));
263                 curdata +=offset,curdata_count -= offset) {
264                 ZERO_STRUCT(qt);
265                 if (!parse_user_quota_record((uint8_t *)curdata, curdata_count,
266                                              &offset, &qt)) {
267                         DEBUG(1,("Failed to parse the quota record\n"));
268                         goto cleanup;
269                 }
270
271                 if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
272                         DEBUG(0,("TALLOC_ZERO() failed\n"));
273                         talloc_destroy(mem_ctx);
274                         return NT_STATUS_NO_MEMORY;
275                 }
276
277                 if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
278                         DEBUG(0,("TALLOC_ZERO() failed\n"));
279                         talloc_destroy(mem_ctx);
280                         return NT_STATUS_NO_MEMORY;
281                 }
282
283                 memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
284                 tmp_list_ent->mem_ctx = mem_ctx;                
285
286                 DLIST_ADD((*pqt_list),tmp_list_ent);
287         }
288
289         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_CONTINUE); 
290         while(1) {
291
292                 TALLOC_FREE(rparam);
293                 TALLOC_FREE(rdata);
294
295                 status = cli_trans(talloc_tos(), cli, SMBnttrans,
296                                    NULL, -1, /* name, fid */
297                                    NT_TRANSACT_GET_USER_QUOTA, 0,
298                                    setup, 1, 0, /* setup */
299                                    params, 16, 4, /* params */
300                                    NULL, 0, 2048, /* data */
301                                    NULL,                /* recv_flags2 */
302                                    NULL, 0, NULL,       /* rsetup */
303                                    &rparam, 0, &rparam_count,
304                                    &rdata, 0, &rdata_count);
305
306                 if (!NT_STATUS_IS_OK(status)) {
307                         DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
308                                   nt_errstr(status)));
309                         goto cleanup;
310                 }
311
312                 if (rdata_count == 0) {
313                         break;
314                 }
315
316                 offset = 1;
317                 for (curdata=rdata,curdata_count=rdata_count;
318                         ((curdata)&&(curdata_count>=8)&&(offset>0));
319                         curdata +=offset,curdata_count -= offset) {
320                         ZERO_STRUCT(qt);
321                         if (!parse_user_quota_record((uint8_t *)curdata,
322                                                      curdata_count, &offset,
323                                                      &qt)) {
324                                 DEBUG(1,("Failed to parse the quota record\n"));
325                                 goto cleanup;
326                         }
327
328                         if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
329                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
330                                 talloc_destroy(mem_ctx);
331                                 goto cleanup;
332                         }
333
334                         if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
335                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
336                                 talloc_destroy(mem_ctx);
337                                 goto cleanup;
338                         }
339
340                         memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
341                         tmp_list_ent->mem_ctx = mem_ctx;                
342
343                         DLIST_ADD((*pqt_list),tmp_list_ent);
344                 }
345         }
346
347  cleanup:
348         TALLOC_FREE(rparam);
349         TALLOC_FREE(rdata);
350
351         return status;
352 }
353
354 NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
355                                SMB_NTQUOTA_STRUCT *pqt)
356 {
357         uint16_t setup[1];
358         uint8_t param[2];
359         uint8_t *rdata=NULL;
360         uint32_t rdata_count=0;
361         SMB_NTQUOTA_STRUCT qt;
362         NTSTATUS status;
363
364         ZERO_STRUCT(qt);
365
366         if (!cli||!pqt) {
367                 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
368         }
369
370         SSVAL(setup + 0, 0, TRANSACT2_QFSINFO);
371
372         SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
373
374         status = cli_trans(talloc_tos(), cli, SMBtrans2,
375                            NULL, -1, /* name, fid */
376                            0, 0,     /* function, flags */
377                            setup, 1, 0, /* setup */
378                            param, 2, 0, /* param */
379                            NULL, 0, 560, /* data */
380                            NULL,         /* recv_flags2 */
381                            NULL, 0, NULL, /* rsetup */
382                            NULL, 0, NULL, /* rparam */
383                            &rdata, 48, &rdata_count);
384
385         if (!NT_STATUS_IS_OK(status)) {
386                 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
387                           nt_errstr(status)));
388                 return status;
389         }
390
391         /* unknown_1 24 NULL bytes in pdata*/
392
393         /* the soft quotas 8 bytes (uint64_t)*/
394         qt.softlim = BVAL(rdata,24);
395
396         /* the hard quotas 8 bytes (uint64_t)*/
397         qt.hardlim = BVAL(rdata,32);
398
399         /* quota_flags 2 bytes **/
400         qt.qflags = SVAL(rdata,40);
401
402         qt.qtype = SMB_USER_FS_QUOTA_TYPE;
403
404         *pqt = qt;
405
406         TALLOC_FREE(rdata);
407         return status;
408 }
409
410 NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
411                                SMB_NTQUOTA_STRUCT *pqt)
412 {
413         uint16_t setup[1];
414         uint8_t param[4];
415         uint8_t data[48];
416         SMB_NTQUOTA_STRUCT qt;
417         NTSTATUS status;
418         ZERO_STRUCT(qt);
419         memset(data,'\0',48);
420
421         if (!cli||!pqt) {
422                 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
423         }
424
425         SSVAL(setup + 0, 0,TRANSACT2_SETFSINFO);
426
427         SSVAL(param,0,quota_fnum);
428         SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
429
430         /* Unknown1 24 NULL bytes*/
431
432         /* Default Soft Quota 8 bytes */
433         SBIG_UINT(data,24,pqt->softlim);
434
435         /* Default Hard Quota 8 bytes */
436         SBIG_UINT(data,32,pqt->hardlim);
437
438         /* Quota flag 2 bytes */
439         SSVAL(data,40,pqt->qflags);
440
441         /* Unknown3 6 NULL bytes */
442
443         status = cli_trans(talloc_tos(), cli, SMBtrans2,
444                            NULL, -1, /* name, fid */
445                            0, 0,     /* function, flags */
446                            setup, 1, 0, /* setup */
447                            param, 8, 0, /* param */
448                            data, 48, 0, /* data */
449                            NULL,         /* recv_flags2 */
450                            NULL, 0, NULL, /* rsetup */
451                            NULL, 0, NULL, /* rparam */
452                            NULL, 0, NULL); /* rdata */
453
454         if (!NT_STATUS_IS_OK(status)) {
455                 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
456                           nt_errstr(status)));
457         }
458
459         return status;
460 }