e05b64e686b8ff5854f4e3f044a41c83b473dbeb
[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 = (uint64_t)IVAL(rdata,16);
84 #ifdef LARGE_SMB_OFF_T
85         qt.usedspace |= (((uint64_t)IVAL(rdata,20)) << 32);
86 #else /* LARGE_SMB_OFF_T */
87         if ((IVAL(rdata,20) != 0)&&
88                 ((qt.usedspace != 0xFFFFFFFF)||
89                  (IVAL(rdata,20)!=0xFFFFFFFF))) {
90                 /* more than 32 bits? */
91                 return False;
92         }
93 #endif /* LARGE_SMB_OFF_T */
94
95         /* the soft quotas 8 bytes (uint64_t)*/
96         qt.softlim = (uint64_t)IVAL(rdata,24);
97 #ifdef LARGE_SMB_OFF_T
98         qt.softlim |= (((uint64_t)IVAL(rdata,28)) << 32);
99 #else /* LARGE_SMB_OFF_T */
100         if ((IVAL(rdata,28) != 0)&&
101                 ((qt.softlim != 0xFFFFFFFF)||
102                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
103                 /* more than 32 bits? */
104                 return False;
105         }
106 #endif /* LARGE_SMB_OFF_T */
107
108         /* the hard quotas 8 bytes (uint64_t)*/
109         qt.hardlim = (uint64_t)IVAL(rdata,32);
110 #ifdef LARGE_SMB_OFF_T
111         qt.hardlim |= (((uint64_t)IVAL(rdata,36)) << 32);
112 #else /* LARGE_SMB_OFF_T */
113         if ((IVAL(rdata,36) != 0)&&
114                 ((qt.hardlim != 0xFFFFFFFF)||
115                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
116                 /* more than 32 bits? */
117                 return False;
118         }
119 #endif /* LARGE_SMB_OFF_T */
120
121         if (!sid_parse((char *)rdata+40,sid_len,&qt.sid)) {
122                 return false;
123         }
124
125         qt.qtype = SMB_USER_QUOTA_TYPE;
126
127         *pqt = qt;
128
129         return True;
130 }
131
132 NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
133                             SMB_NTQUOTA_STRUCT *pqt)
134 {
135         uint16_t setup[1];
136         uint8_t params[16];
137         unsigned int data_len;
138         uint8_t data[SID_MAX_SIZE+8];
139         uint8_t *rparam, *rdata;
140         uint32_t rparam_count, rdata_count;
141         unsigned int sid_len;
142         unsigned int offset;
143         NTSTATUS status;
144
145         if (!cli||!pqt) {
146                 smb_panic("cli_get_user_quota() called with NULL Pointer!");
147         }
148
149         SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
150
151         SSVAL(params, 0,quota_fnum);
152         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID);
153         SIVAL(params, 4,0x00000024);
154         SIVAL(params, 8,0x00000000);
155         SIVAL(params,12,0x00000024);
156
157         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
158         data_len = sid_len+8;
159         SIVAL(data, 0, 0x00000000);
160         SIVAL(data, 4, sid_len);
161         sid_linearize((char *)data+8, sid_len, &pqt->sid);
162
163         status = cli_trans(talloc_tos(), cli, SMBnttrans,
164                            NULL, -1, /* name, fid */
165                            NT_TRANSACT_GET_USER_QUOTA, 0,
166                            setup, 1, 0, /* setup */
167                            params, 16, 4, /* params */
168                            data, data_len, 112, /* data */
169                            NULL,                /* recv_flags2 */
170                            NULL, 0, NULL,       /* rsetup */
171                            &rparam, 4, &rparam_count,
172                            &rdata, 8, &rdata_count);
173         if (!NT_STATUS_IS_OK(status)) {
174                 DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
175                           nt_errstr(status)));
176                 return status;
177         }
178
179         if (!parse_user_quota_record(rdata, rdata_count, &offset, pqt)) {
180                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
181                 DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
182         }
183
184         TALLOC_FREE(rparam);
185         TALLOC_FREE(rdata);
186         return status;
187 }
188
189 NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
190                             SMB_NTQUOTA_STRUCT *pqt)
191 {
192         uint16_t setup[1];
193         uint8_t params[2];
194         uint8_t data[112];
195         unsigned int sid_len;   
196         NTSTATUS status;
197
198         memset(data,'\0',112);
199
200         if (!cli||!pqt) {
201                 smb_panic("cli_set_user_quota() called with NULL Pointer!");
202         }
203
204         SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
205
206         SSVAL(params,0,quota_fnum);
207
208         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
209         SIVAL(data,0,0);
210         SIVAL(data,4,sid_len);
211         SBIG_UINT(data, 8,(uint64_t)0);
212         SBIG_UINT(data,16,pqt->usedspace);
213         SBIG_UINT(data,24,pqt->softlim);
214         SBIG_UINT(data,32,pqt->hardlim);
215         sid_linearize((char *)data+40, sid_len, &pqt->sid);
216
217         status = cli_trans(talloc_tos(), cli, SMBnttrans,
218                            NULL, -1, /* name, fid */
219                            NT_TRANSACT_SET_USER_QUOTA, 0,
220                            setup, 1, 0, /* setup */
221                            params, 2, 0, /* params */
222                            data, 112, 0, /* data */
223                            NULL,                /* recv_flags2 */
224                            NULL, 0, NULL,       /* rsetup */
225                            NULL, 0, NULL,       /* rparams */
226                            NULL, 0, NULL);      /* rdata */
227
228         if (!NT_STATUS_IS_OK(status)) {
229                 DEBUG(1, ("NT_TRANSACT_SET_USER_QUOTA failed: %s\n",
230                           nt_errstr(status)));
231         }
232
233         return status;
234 }
235
236 NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
237                              SMB_NTQUOTA_LIST **pqt_list)
238 {
239         uint16_t setup[1];
240         uint8_t params[16];
241         uint8_t *rparam=NULL, *rdata=NULL;
242         uint32_t rparam_count=0, rdata_count=0;
243         unsigned int offset;
244         const uint8_t *curdata = NULL;
245         unsigned int curdata_count = 0;
246         TALLOC_CTX *mem_ctx = NULL;
247         SMB_NTQUOTA_STRUCT qt;
248         SMB_NTQUOTA_LIST *tmp_list_ent;
249         NTSTATUS status;
250
251         if (!cli||!pqt_list) {
252                 smb_panic("cli_list_user_quota() called with NULL Pointer!");
253         }
254
255         SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
256
257         SSVAL(params, 0,quota_fnum);
258         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START);
259         SIVAL(params, 4,0x00000000);
260         SIVAL(params, 8,0x00000000);
261         SIVAL(params,12,0x00000000);
262
263         status = cli_trans(talloc_tos(), cli, SMBnttrans,
264                            NULL, -1, /* name, fid */
265                            NT_TRANSACT_GET_USER_QUOTA, 0,
266                            setup, 1, 0, /* setup */
267                            params, 16, 4, /* params */
268                            NULL, 0, 2048, /* data */
269                            NULL,                /* recv_flags2 */
270                            NULL, 0, NULL,       /* rsetup */
271                            &rparam, 0, &rparam_count,
272                            &rdata, 0, &rdata_count);
273
274         if (!NT_STATUS_IS_OK(status)) {
275                 DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
276                           nt_errstr(status)));
277                 goto cleanup;
278         }
279
280         if (rdata_count == 0) {
281                 *pqt_list = NULL;
282                 return NT_STATUS_OK;
283         }
284
285         if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
286                 DEBUG(0,("talloc_init() failed\n"));
287                 return NT_STATUS_NO_MEMORY;
288         }
289
290         offset = 1;
291         for (curdata=rdata,curdata_count=rdata_count;
292                 ((curdata)&&(curdata_count>=8)&&(offset>0));
293                 curdata +=offset,curdata_count -= offset) {
294                 ZERO_STRUCT(qt);
295                 if (!parse_user_quota_record((uint8_t *)curdata, curdata_count,
296                                              &offset, &qt)) {
297                         DEBUG(1,("Failed to parse the quota record\n"));
298                         goto cleanup;
299                 }
300
301                 if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
302                         DEBUG(0,("TALLOC_ZERO() failed\n"));
303                         talloc_destroy(mem_ctx);
304                         return NT_STATUS_NO_MEMORY;
305                 }
306
307                 if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
308                         DEBUG(0,("TALLOC_ZERO() failed\n"));
309                         talloc_destroy(mem_ctx);
310                         return NT_STATUS_NO_MEMORY;
311                 }
312
313                 memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
314                 tmp_list_ent->mem_ctx = mem_ctx;                
315
316                 DLIST_ADD((*pqt_list),tmp_list_ent);
317         }
318
319         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_CONTINUE); 
320         while(1) {
321
322                 TALLOC_FREE(rparam);
323                 TALLOC_FREE(rdata);
324
325                 status = cli_trans(talloc_tos(), cli, SMBnttrans,
326                                    NULL, -1, /* name, fid */
327                                    NT_TRANSACT_GET_USER_QUOTA, 0,
328                                    setup, 1, 0, /* setup */
329                                    params, 16, 4, /* params */
330                                    NULL, 0, 2048, /* data */
331                                    NULL,                /* recv_flags2 */
332                                    NULL, 0, NULL,       /* rsetup */
333                                    &rparam, 0, &rparam_count,
334                                    &rdata, 0, &rdata_count);
335
336                 if (!NT_STATUS_IS_OK(status)) {
337                         DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
338                                   nt_errstr(status)));
339                         goto cleanup;
340                 }
341
342                 if (rdata_count == 0) {
343                         break;
344                 }
345
346                 offset = 1;
347                 for (curdata=rdata,curdata_count=rdata_count;
348                         ((curdata)&&(curdata_count>=8)&&(offset>0));
349                         curdata +=offset,curdata_count -= offset) {
350                         ZERO_STRUCT(qt);
351                         if (!parse_user_quota_record((uint8_t *)curdata,
352                                                      curdata_count, &offset,
353                                                      &qt)) {
354                                 DEBUG(1,("Failed to parse the quota record\n"));
355                                 goto cleanup;
356                         }
357
358                         if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
359                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
360                                 talloc_destroy(mem_ctx);
361                                 goto cleanup;
362                         }
363
364                         if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
365                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
366                                 talloc_destroy(mem_ctx);
367                                 goto cleanup;
368                         }
369
370                         memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
371                         tmp_list_ent->mem_ctx = mem_ctx;                
372
373                         DLIST_ADD((*pqt_list),tmp_list_ent);
374                 }
375         }
376
377  cleanup:
378         TALLOC_FREE(rparam);
379         TALLOC_FREE(rdata);
380
381         return status;
382 }
383
384 NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
385                                SMB_NTQUOTA_STRUCT *pqt)
386 {
387         uint16_t setup[1];
388         uint8_t param[2];
389         uint8_t *rdata=NULL;
390         uint32_t rdata_count=0;
391         SMB_NTQUOTA_STRUCT qt;
392         NTSTATUS status;
393
394         ZERO_STRUCT(qt);
395
396         if (!cli||!pqt) {
397                 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
398         }
399
400         SSVAL(setup + 0, 0, TRANSACT2_QFSINFO);
401
402         SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
403
404         status = cli_trans(talloc_tos(), cli, SMBtrans2,
405                            NULL, -1, /* name, fid */
406                            0, 0,     /* function, flags */
407                            setup, 1, 0, /* setup */
408                            param, 2, 0, /* param */
409                            NULL, 0, 560, /* data */
410                            NULL,         /* recv_flags2 */
411                            NULL, 0, NULL, /* rsetup */
412                            NULL, 0, NULL, /* rparam */
413                            &rdata, 48, &rdata_count);
414
415         if (!NT_STATUS_IS_OK(status)) {
416                 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
417                           nt_errstr(status)));
418                 return status;
419         }
420
421         /* unknown_1 24 NULL bytes in pdata*/
422
423         /* the soft quotas 8 bytes (uint64_t)*/
424         qt.softlim = (uint64_t)IVAL(rdata,24);
425 #ifdef LARGE_SMB_OFF_T
426         qt.softlim |= (((uint64_t)IVAL(rdata,28)) << 32);
427 #else /* LARGE_SMB_OFF_T */
428         if ((IVAL(rdata,28) != 0)&&
429                 ((qt.softlim != 0xFFFFFFFF)||
430                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
431                 /* more than 32 bits? */
432                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
433                 goto cleanup;
434         }
435 #endif /* LARGE_SMB_OFF_T */
436
437         /* the hard quotas 8 bytes (uint64_t)*/
438         qt.hardlim = (uint64_t)IVAL(rdata,32);
439 #ifdef LARGE_SMB_OFF_T
440         qt.hardlim |= (((uint64_t)IVAL(rdata,36)) << 32);
441 #else /* LARGE_SMB_OFF_T */
442         if ((IVAL(rdata,36) != 0)&&
443                 ((qt.hardlim != 0xFFFFFFFF)||
444                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
445                 /* more than 32 bits? */
446                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
447                 goto cleanup;
448         }
449 #endif /* LARGE_SMB_OFF_T */
450
451         /* quota_flags 2 bytes **/
452         qt.qflags = SVAL(rdata,40);
453
454         qt.qtype = SMB_USER_FS_QUOTA_TYPE;
455
456         *pqt = qt;
457
458         TALLOC_FREE(rdata);
459         return status;
460 }
461
462 NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
463                                SMB_NTQUOTA_STRUCT *pqt)
464 {
465         uint16_t setup[1];
466         uint8_t param[4];
467         uint8_t data[48];
468         SMB_NTQUOTA_STRUCT qt;
469         NTSTATUS status;
470         ZERO_STRUCT(qt);
471         memset(data,'\0',48);
472
473         if (!cli||!pqt) {
474                 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
475         }
476
477         SSVAL(setup + 0, 0,TRANSACT2_SETFSINFO);
478
479         SSVAL(param,0,quota_fnum);
480         SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
481
482         /* Unknown1 24 NULL bytes*/
483
484         /* Default Soft Quota 8 bytes */
485         SBIG_UINT(data,24,pqt->softlim);
486
487         /* Default Hard Quota 8 bytes */
488         SBIG_UINT(data,32,pqt->hardlim);
489
490         /* Quota flag 2 bytes */
491         SSVAL(data,40,pqt->qflags);
492
493         /* Unknown3 6 NULL bytes */
494
495         status = cli_trans(talloc_tos(), cli, SMBtrans2,
496                            NULL, -1, /* name, fid */
497                            0, 0,     /* function, flags */
498                            setup, 1, 0, /* setup */
499                            param, 8, 0, /* param */
500                            data, 48, 0, /* data */
501                            NULL,         /* recv_flags2 */
502                            NULL, 0, NULL, /* rsetup */
503                            NULL, 0, NULL, /* rparam */
504                            NULL, 0, NULL); /* rdata */
505
506         if (!NT_STATUS_IS_OK(status)) {
507                 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
508                           nt_errstr(status)));
509         }
510
511         return status;
512 }