6642cf0f930dbb576a389562fe5742b91db3adec
[metze/samba/wip.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
23 NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum)
24 {
25         return cli_ntcreate(cli, FAKE_FILE_NAME_QUOTA_WIN32,
26                  0x00000016, DESIRED_ACCESS_PIPE,
27                  0x00000000, FILE_SHARE_READ|FILE_SHARE_WRITE,
28                  FILE_OPEN, 0x00000000, 0x03, quota_fnum);
29 }
30
31 void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
32 {
33         if (!qt_list)
34                 return;
35
36         if ((*qt_list)->mem_ctx)
37                 talloc_destroy((*qt_list)->mem_ctx);
38
39         (*qt_list) = NULL;
40
41         return; 
42 }
43
44 static bool parse_user_quota_record(const char *rdata, unsigned int rdata_count, unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt)
45 {
46         int sid_len;
47         SMB_NTQUOTA_STRUCT qt;
48
49         ZERO_STRUCT(qt);
50
51         if (!rdata||!offset||!pqt) {
52                 smb_panic("parse_quota_record: called with NULL POINTER!");
53         }
54
55         if (rdata_count < 40) {
56                 return False;
57         }
58
59         /* offset to next quota record.
60          * 4 bytes IVAL(rdata,0)
61          * unused here...
62          */
63         *offset = IVAL(rdata,0);
64
65         /* sid len */
66         sid_len = IVAL(rdata,4);
67
68         if (rdata_count < 40+sid_len) {
69                 return False;           
70         }
71
72         /* unknown 8 bytes in pdata 
73          * maybe its the change time in NTTIME
74          */
75
76         /* the used space 8 bytes (uint64_t)*/
77         qt.usedspace = (uint64_t)IVAL(rdata,16);
78 #ifdef LARGE_SMB_OFF_T
79         qt.usedspace |= (((uint64_t)IVAL(rdata,20)) << 32);
80 #else /* LARGE_SMB_OFF_T */
81         if ((IVAL(rdata,20) != 0)&&
82                 ((qt.usedspace != 0xFFFFFFFF)||
83                  (IVAL(rdata,20)!=0xFFFFFFFF))) {
84                 /* more than 32 bits? */
85                 return False;
86         }
87 #endif /* LARGE_SMB_OFF_T */
88
89         /* the soft quotas 8 bytes (uint64_t)*/
90         qt.softlim = (uint64_t)IVAL(rdata,24);
91 #ifdef LARGE_SMB_OFF_T
92         qt.softlim |= (((uint64_t)IVAL(rdata,28)) << 32);
93 #else /* LARGE_SMB_OFF_T */
94         if ((IVAL(rdata,28) != 0)&&
95                 ((qt.softlim != 0xFFFFFFFF)||
96                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
97                 /* more than 32 bits? */
98                 return False;
99         }
100 #endif /* LARGE_SMB_OFF_T */
101
102         /* the hard quotas 8 bytes (uint64_t)*/
103         qt.hardlim = (uint64_t)IVAL(rdata,32);
104 #ifdef LARGE_SMB_OFF_T
105         qt.hardlim |= (((uint64_t)IVAL(rdata,36)) << 32);
106 #else /* LARGE_SMB_OFF_T */
107         if ((IVAL(rdata,36) != 0)&&
108                 ((qt.hardlim != 0xFFFFFFFF)||
109                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
110                 /* more than 32 bits? */
111                 return False;
112         }
113 #endif /* LARGE_SMB_OFF_T */
114
115         sid_parse(rdata+40,sid_len,&qt.sid);
116
117         qt.qtype = SMB_USER_QUOTA_TYPE;
118
119         *pqt = qt;
120
121         return True;
122 }
123
124 bool cli_get_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
125 {
126         bool ret = False;
127         uint16 setup;
128         char params[16];
129         unsigned int data_len;
130         char data[SID_MAX_SIZE+8];
131         char *rparam=NULL, *rdata=NULL;
132         unsigned int rparam_count=0, rdata_count=0;
133         unsigned int sid_len;
134         unsigned int offset;
135
136         if (!cli||!pqt) {
137                 smb_panic("cli_get_user_quota() called with NULL Pointer!");
138         }
139
140         setup = NT_TRANSACT_GET_USER_QUOTA;
141
142         SSVAL(params, 0,quota_fnum);
143         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID);
144         SIVAL(params, 4,0x00000024);
145         SIVAL(params, 8,0x00000000);
146         SIVAL(params,12,0x00000024);
147
148         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
149         data_len = sid_len+8;
150         SIVAL(data, 0, 0x00000000);
151         SIVAL(data, 4, sid_len);
152         sid_linearize(data+8, sid_len, &pqt->sid);
153
154         if (!cli_send_nt_trans(cli, 
155                                NT_TRANSACT_GET_USER_QUOTA, 
156                                0, 
157                                &setup, 1, 0,
158                                params, 16, 4,
159                                data, data_len, 112)) {
160                 DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
161                 goto cleanup;
162         }
163
164
165         if (!cli_receive_nt_trans(cli,
166                                   &rparam, &rparam_count,
167                                   &rdata, &rdata_count)) {
168                 DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
169                 goto cleanup;
170         }
171
172         if (cli_is_error(cli)) {
173                 ret = False;
174                 goto cleanup;
175         } else {
176                 ret = True;
177         }
178
179         if ((rparam&&rdata)&&(rparam_count>=4&&rdata_count>=8)) {
180                 ret = parse_user_quota_record(rdata, rdata_count, &offset, pqt);
181         } else {
182                 DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
183                 ret = False; 
184         }
185
186  cleanup:
187         SAFE_FREE(rparam);
188         SAFE_FREE(rdata); 
189         return ret;
190 }
191
192 bool cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
193 {
194         bool ret = False;
195         uint16 setup;
196         char params[2];
197         char data[112];
198         char *rparam=NULL, *rdata=NULL;
199         unsigned int rparam_count=0, rdata_count=0;
200         unsigned int sid_len;   
201         memset(data,'\0',112);
202
203         if (!cli||!pqt) {
204                 smb_panic("cli_set_user_quota() called with NULL Pointer!");
205         }
206
207         setup = NT_TRANSACT_SET_USER_QUOTA;
208
209         SSVAL(params,0,quota_fnum);
210
211         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
212         SIVAL(data,0,0);
213         SIVAL(data,4,sid_len);
214         SBIG_UINT(data, 8,(uint64_t)0);
215         SBIG_UINT(data,16,pqt->usedspace);
216         SBIG_UINT(data,24,pqt->softlim);
217         SBIG_UINT(data,32,pqt->hardlim);
218         sid_linearize(data+40, sid_len, &pqt->sid);
219
220         if (!cli_send_nt_trans(cli, 
221                                NT_TRANSACT_SET_USER_QUOTA, 
222                                0, 
223                                &setup, 1, 0,
224                                params, 2, 0,
225                                data, 112, 0)) {
226                 DEBUG(1,("Failed to send NT_TRANSACT_SET_USER_QUOTA\n"));
227                 goto cleanup;
228         }
229
230
231         if (!cli_receive_nt_trans(cli, 
232                                   &rparam, &rparam_count,
233                                   &rdata, &rdata_count)) {
234                 DEBUG(1,("NT_TRANSACT_SET_USER_QUOTA failed\n"));
235                 goto cleanup;
236         }
237
238         if (cli_is_error(cli)) {
239                 ret = False;
240                 goto cleanup;
241         } else {
242                 ret = True;
243         }
244
245   cleanup:
246         SAFE_FREE(rparam);
247         SAFE_FREE(rdata);
248         return ret;
249 }
250
251 bool cli_list_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST **pqt_list)
252 {
253         bool ret = False;
254         uint16 setup;
255         char params[16];
256         char *rparam=NULL, *rdata=NULL;
257         unsigned int rparam_count=0, rdata_count=0;
258         unsigned int offset;
259         const char *curdata = NULL;
260         unsigned int curdata_count = 0;
261         TALLOC_CTX *mem_ctx = NULL;
262         SMB_NTQUOTA_STRUCT qt;
263         SMB_NTQUOTA_LIST *tmp_list_ent;
264
265         if (!cli||!pqt_list) {
266                 smb_panic("cli_list_user_quota() called with NULL Pointer!");
267         }
268
269         setup = NT_TRANSACT_GET_USER_QUOTA;
270
271         SSVAL(params, 0,quota_fnum);
272         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START);
273         SIVAL(params, 4,0x00000000);
274         SIVAL(params, 8,0x00000000);
275         SIVAL(params,12,0x00000000);
276
277         if (!cli_send_nt_trans(cli, 
278                                NT_TRANSACT_GET_USER_QUOTA, 
279                                0, 
280                                &setup, 1, 0,
281                                params, 16, 4,
282                                NULL, 0, 2048)) {
283                 DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
284                 goto cleanup;
285         }
286
287
288         if (!cli_receive_nt_trans(cli,
289                                   &rparam, &rparam_count,
290                                   &rdata, &rdata_count)) {
291                 DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
292                 goto cleanup;
293         }
294
295         if (cli_is_error(cli)) {
296                 ret = False;
297                 goto cleanup;
298         } else {
299                 ret = True;
300         }
301
302         if (rdata_count == 0) {
303                 *pqt_list = NULL;
304                 return True;
305         }
306
307         if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
308                 DEBUG(0,("talloc_init() failed\n"));
309                 return (-1);
310         }
311
312         offset = 1;
313         for (curdata=rdata,curdata_count=rdata_count;
314                 ((curdata)&&(curdata_count>=8)&&(offset>0));
315                 curdata +=offset,curdata_count -= offset) {
316                 ZERO_STRUCT(qt);
317                 if (!parse_user_quota_record(curdata, curdata_count, &offset, &qt)) {
318                         DEBUG(1,("Failed to parse the quota record\n"));
319                         goto cleanup;
320                 }
321
322                 if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
323                         DEBUG(0,("TALLOC_ZERO() failed\n"));
324                         talloc_destroy(mem_ctx);
325                         return (-1);
326                 }
327
328                 if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
329                         DEBUG(0,("TALLOC_ZERO() failed\n"));
330                         talloc_destroy(mem_ctx);
331                         return (-1);
332                 }
333
334                 memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
335                 tmp_list_ent->mem_ctx = mem_ctx;                
336
337                 DLIST_ADD((*pqt_list),tmp_list_ent);
338         }
339
340         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_CONTINUE); 
341         while(1) {
342                 if (!cli_send_nt_trans(cli, 
343                                        NT_TRANSACT_GET_USER_QUOTA, 
344                                        0, 
345                                        &setup, 1, 0,
346                                        params, 16, 4,
347                                        NULL, 0, 2048)) {
348                         DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
349                         goto cleanup;
350                 }
351
352                 SAFE_FREE(rparam);
353                 SAFE_FREE(rdata);
354                 if (!cli_receive_nt_trans(cli,
355                                           &rparam, &rparam_count,
356                                           &rdata, &rdata_count)) {
357                         DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
358                         goto cleanup;
359                 }
360
361                 if (cli_is_error(cli)) {
362                         ret = False;
363                         goto cleanup;
364                 } else {
365                         ret = True;
366                 }
367
368                 if (rdata_count == 0) {
369                         break;  
370                 }
371
372                 offset = 1;
373                 for (curdata=rdata,curdata_count=rdata_count;
374                         ((curdata)&&(curdata_count>=8)&&(offset>0));
375                         curdata +=offset,curdata_count -= offset) {
376                         ZERO_STRUCT(qt);
377                         if (!parse_user_quota_record(curdata, curdata_count, &offset, &qt)) {
378                                 DEBUG(1,("Failed to parse the quota record\n"));
379                                 goto cleanup;
380                         }
381
382                         if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
383                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
384                                 talloc_destroy(mem_ctx);
385                                 goto cleanup;
386                         }
387
388                         if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
389                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
390                                 talloc_destroy(mem_ctx);
391                                 goto cleanup;
392                         }
393
394                         memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
395                         tmp_list_ent->mem_ctx = mem_ctx;                
396
397                         DLIST_ADD((*pqt_list),tmp_list_ent);
398                 }
399         }
400
401
402         ret = True;
403  cleanup:
404         SAFE_FREE(rparam);
405         SAFE_FREE(rdata);
406
407         return ret;
408 }
409
410 bool cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
411 {
412         bool ret = False;
413         uint16 setup;
414         char param[2];
415         char *rparam=NULL, *rdata=NULL;
416         unsigned int rparam_count=0, rdata_count=0;
417         SMB_NTQUOTA_STRUCT qt;
418         ZERO_STRUCT(qt);
419
420         if (!cli||!pqt) {
421                 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
422         }
423
424         setup = TRANSACT2_QFSINFO;
425
426         SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
427
428         if (!cli_send_trans(cli, SMBtrans2, 
429                     NULL, 
430                     0, 0,
431                     &setup, 1, 0,
432                     param, 2, 0,
433                     NULL, 0, 560)) {
434                 goto cleanup;
435         }
436
437         if (!cli_receive_trans(cli, SMBtrans2,
438                               &rparam, &rparam_count,
439                               &rdata, &rdata_count)) {
440                 goto cleanup;
441         }
442
443         if (cli_is_error(cli)) {
444                 ret = False;
445                 goto cleanup;
446         } else {
447                 ret = True;
448         }
449
450         if (rdata_count < 48) {
451                 goto cleanup;
452         }
453
454         /* unknown_1 24 NULL bytes in pdata*/
455
456         /* the soft quotas 8 bytes (uint64_t)*/
457         qt.softlim = (uint64_t)IVAL(rdata,24);
458 #ifdef LARGE_SMB_OFF_T
459         qt.softlim |= (((uint64_t)IVAL(rdata,28)) << 32);
460 #else /* LARGE_SMB_OFF_T */
461         if ((IVAL(rdata,28) != 0)&&
462                 ((qt.softlim != 0xFFFFFFFF)||
463                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
464                 /* more than 32 bits? */
465                 goto cleanup;
466         }
467 #endif /* LARGE_SMB_OFF_T */
468
469         /* the hard quotas 8 bytes (uint64_t)*/
470         qt.hardlim = (uint64_t)IVAL(rdata,32);
471 #ifdef LARGE_SMB_OFF_T
472         qt.hardlim |= (((uint64_t)IVAL(rdata,36)) << 32);
473 #else /* LARGE_SMB_OFF_T */
474         if ((IVAL(rdata,36) != 0)&&
475                 ((qt.hardlim != 0xFFFFFFFF)||
476                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
477                 /* more than 32 bits? */
478                 goto cleanup;
479         }
480 #endif /* LARGE_SMB_OFF_T */
481
482         /* quota_flags 2 bytes **/
483         qt.qflags = SVAL(rdata,40);
484
485         qt.qtype = SMB_USER_FS_QUOTA_TYPE;
486
487         *pqt = qt;
488
489         ret = True;
490 cleanup:
491         SAFE_FREE(rparam);
492         SAFE_FREE(rdata);
493
494         return ret;     
495 }
496
497 bool cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
498 {
499         bool ret = False;
500         uint16 setup;
501         char param[4];
502         char data[48];
503         char *rparam=NULL, *rdata=NULL;
504         unsigned int rparam_count=0, rdata_count=0;
505         SMB_NTQUOTA_STRUCT qt;
506         ZERO_STRUCT(qt);
507         memset(data,'\0',48);
508
509         if (!cli||!pqt) {
510                 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
511         }
512
513         setup = TRANSACT2_SETFSINFO;
514
515         SSVAL(param,0,quota_fnum);
516         SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
517
518         /* Unknown1 24 NULL bytes*/
519
520         /* Default Soft Quota 8 bytes */
521         SBIG_UINT(data,24,pqt->softlim);
522
523         /* Default Hard Quota 8 bytes */
524         SBIG_UINT(data,32,pqt->hardlim);
525
526         /* Quota flag 2 bytes */
527         SSVAL(data,40,pqt->qflags);
528
529         /* Unknown3 6 NULL bytes */
530
531         if (!cli_send_trans(cli, SMBtrans2, 
532                     NULL, 
533                     0, 0,
534                     &setup, 1, 0,
535                     param, 4, 0,
536                     data, 48, 0)) {
537                 goto cleanup;
538         }
539
540         if (!cli_receive_trans(cli, SMBtrans2,
541                               &rparam, &rparam_count,
542                               &rdata, &rdata_count)) {
543                 goto cleanup;
544         }
545
546         if (cli_is_error(cli)) {
547                 ret = False;
548                 goto cleanup;
549         } else {
550                 ret = True;
551         }
552
553 cleanup:
554         SAFE_FREE(rparam);
555         SAFE_FREE(rdata);
556
557         return ret;     
558 }
559
560 static const char *quota_str_static(uint64_t val, bool special, bool _numeric)
561 {
562         const char *result;
563
564         if (!_numeric&&special&&(val == SMB_NTQUOTAS_NO_LIMIT)) {
565                 return "NO LIMIT";
566         }
567         result = talloc_asprintf(talloc_tos(), "%"PRIu64, val);
568         SMB_ASSERT(result != NULL);
569         return result;
570 }
571
572 void dump_ntquota(SMB_NTQUOTA_STRUCT *qt, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, struct dom_sid *sid, bool _numeric))
573 {
574         TALLOC_CTX *frame = talloc_stackframe();
575
576         if (!qt) {
577                 smb_panic("dump_ntquota() called with NULL pointer");
578         }
579
580         switch (qt->qtype) {
581                 case SMB_USER_FS_QUOTA_TYPE:
582                         {
583                                 d_printf("File System QUOTAS:\n");
584                                 d_printf("Limits:\n");
585                                 d_printf(" Default Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
586                                 d_printf(" Default Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
587                                 d_printf("Quota Flags:\n");
588                                 d_printf(" Quotas Enabled: %s\n",
589                                         ((qt->qflags&QUOTAS_ENABLED)||(qt->qflags&QUOTAS_DENY_DISK))?"On":"Off");
590                                 d_printf(" Deny Disk:      %s\n",(qt->qflags&QUOTAS_DENY_DISK)?"On":"Off");
591                                 d_printf(" Log Soft Limit: %s\n",(qt->qflags&QUOTAS_LOG_THRESHOLD)?"On":"Off");
592                                 d_printf(" Log Hard Limit: %s\n",(qt->qflags&QUOTAS_LOG_LIMIT)?"On":"Off");
593                         }
594                         break;
595                 case SMB_USER_QUOTA_TYPE:
596                         {
597                                 fstring username_str = {0};
598
599                                 if (_sidtostring) {
600                                         _sidtostring(username_str,&qt->sid,_numeric);
601                                 } else {
602                                         sid_to_fstring(username_str, &qt->sid);
603                                 }
604
605                                 if (_verbose) { 
606                                         d_printf("Quotas for User: %s\n",username_str);
607                                         d_printf("Used Space: %15s\n",quota_str_static(qt->usedspace,False,_numeric));
608                                         d_printf("Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
609                                         d_printf("Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
610                                 } else {
611                                         d_printf("%-30s: ",username_str);
612                                         d_printf("%15s/",quota_str_static(qt->usedspace,False,_numeric));
613                                         d_printf("%15s/",quota_str_static(qt->softlim,True,_numeric));
614                                         d_printf("%15s\n",quota_str_static(qt->hardlim,True,_numeric));
615                                 }
616                         }
617                         break;
618                 default:
619                         d_printf("dump_ntquota() invalid qtype(%d)\n",qt->qtype);
620         }
621         TALLOC_FREE(frame);
622         return;
623 }
624
625 void dump_ntquota_list(SMB_NTQUOTA_LIST **qtl, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, struct dom_sid *sid, bool _numeric))
626 {
627         SMB_NTQUOTA_LIST *cur;
628
629         for (cur = *qtl;cur;cur = cur->next) {
630                 if (cur->quotas)
631                         dump_ntquota(cur->quotas,_verbose,_numeric,_sidtostring);
632         }       
633 }