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