Initial import
[samba] / source / 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 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
23 BOOL cli_get_quota_handle(struct cli_state *cli, int *quota_fnum)
24 {
25         *quota_fnum = cli_nt_create_full(cli, FAKE_FILE_NAME_QUOTA_WIN32,
26                  0x00000016, DESIRED_ACCESS_PIPE,
27                  0x00000000, FILE_SHARE_READ|FILE_SHARE_WRITE,
28                  FILE_OPEN, 0x00000000, 0x03);
29                  
30         if (*quota_fnum == (-1)) {
31                 return False;
32         }
33
34         return True;
35 }
36
37 void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
38 {
39         if (!qt_list)
40                 return;
41                 
42         if ((*qt_list)->mem_ctx)
43                 talloc_destroy((*qt_list)->mem_ctx);
44
45         (*qt_list) = NULL;
46
47         return; 
48 }
49
50 static BOOL parse_user_quota_record(const char *rdata, unsigned int rdata_count, unsigned int *offset, 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!\n");
59
60         if (rdata_count < 40) {
61                 return False;
62         }
63                 
64         /* offset to next quota record.
65          * 4 bytes IVAL(rdata,0)
66          * unused here...
67          */
68         *offset = IVAL(rdata,0);
69
70         /* sid len */
71         sid_len = IVAL(rdata,4);
72
73         if (rdata_count < 40+sid_len) {
74                 return False;           
75         }
76
77         /* unknown 8 bytes in pdata 
78          * maybe its the change time in NTTIME
79          */
80
81         /* the used space 8 bytes (SMB_BIG_UINT)*/
82         qt.usedspace = (SMB_BIG_UINT)IVAL(rdata,16);
83 #ifdef LARGE_SMB_OFF_T
84         qt.usedspace |= (((SMB_BIG_UINT)IVAL(rdata,20)) << 32);
85 #else /* LARGE_SMB_OFF_T */
86         if ((IVAL(rdata,20) != 0)&&
87                 ((qt.usedspace != 0xFFFFFFFF)||
88                  (IVAL(rdata,20)!=0xFFFFFFFF))) {
89                 /* more than 32 bits? */
90                 return False;
91         }
92 #endif /* LARGE_SMB_OFF_T */
93
94         /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
95         qt.softlim = (SMB_BIG_UINT)IVAL(rdata,24);
96 #ifdef LARGE_SMB_OFF_T
97         qt.softlim |= (((SMB_BIG_UINT)IVAL(rdata,28)) << 32);
98 #else /* LARGE_SMB_OFF_T */
99         if ((IVAL(rdata,28) != 0)&&
100                 ((qt.softlim != 0xFFFFFFFF)||
101                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
102                 /* more than 32 bits? */
103                 return False;
104         }
105 #endif /* LARGE_SMB_OFF_T */
106
107         /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
108         qt.hardlim = (SMB_BIG_UINT)IVAL(rdata,32);
109 #ifdef LARGE_SMB_OFF_T
110         qt.hardlim |= (((SMB_BIG_UINT)IVAL(rdata,36)) << 32);
111 #else /* LARGE_SMB_OFF_T */
112         if ((IVAL(rdata,36) != 0)&&
113                 ((qt.hardlim != 0xFFFFFFFF)||
114                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
115                 /* more than 32 bits? */
116                 return False;
117         }
118 #endif /* LARGE_SMB_OFF_T */
119         
120         sid_parse(rdata+40,sid_len,&qt.sid);
121
122         qt.qtype = SMB_USER_QUOTA_TYPE;
123
124         *pqt = qt;
125
126         return True;
127 }
128
129 BOOL cli_get_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
130 {
131         BOOL ret = False;
132         uint16 setup;
133         char params[16];
134         unsigned int data_len;
135         char data[SID_MAX_SIZE+8];
136         char *rparam=NULL, *rdata=NULL;
137         unsigned int rparam_count=0, rdata_count=0;
138         unsigned int sid_len;
139         unsigned int offset;
140
141         if (!cli||!pqt)
142                 smb_panic("cli_get_user_quota() called with NULL Pointer!");
143
144         setup = NT_TRANSACT_GET_USER_QUOTA;
145
146         SSVAL(params, 0,quota_fnum);
147         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID);
148         SIVAL(params, 4,0x00000024);
149         SIVAL(params, 8,0x00000000);
150         SIVAL(params,12,0x00000024);
151         
152         sid_len = sid_size(&pqt->sid);
153         data_len = sid_len+8;
154         SIVAL(data, 0, 0x00000000);
155         SIVAL(data, 4, sid_len);
156         sid_linearize(data+8, sid_len, &pqt->sid);
157         
158         if (!cli_send_nt_trans(cli, 
159                                NT_TRANSACT_GET_USER_QUOTA, 
160                                0, 
161                                &setup, 1, 0,
162                                params, 16, 4,
163                                data, data_len, 112)) {
164                 DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
165                 goto cleanup;
166         }
167
168
169         if (!cli_receive_nt_trans(cli,
170                                   &rparam, &rparam_count,
171                                   &rdata, &rdata_count)) {
172                 DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
173                 goto cleanup;
174         }
175
176         if (cli_is_error(cli)) {
177                 ret = False;
178                 goto cleanup;
179         } else {
180                 ret = True;
181         }
182
183         if ((rparam&&rdata)&&(rparam_count>=4&&rdata_count>=8)) {
184                 ret = parse_user_quota_record(rdata, rdata_count, &offset, pqt);
185         } else {
186                 DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
187                 ret = False; 
188         }
189
190  cleanup:
191         SAFE_FREE(rparam);
192         SAFE_FREE(rdata); 
193         return ret;
194 }
195
196 BOOL cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
197 {
198         BOOL ret = False;
199         uint16 setup;
200         char params[2];
201         char data[112];
202         char *rparam=NULL, *rdata=NULL;
203         unsigned int rparam_count=0, rdata_count=0;
204         unsigned int sid_len;   
205         memset(data,'\0',112);
206         
207         if (!cli||!pqt)
208                 smb_panic("cli_set_user_quota() called with NULL Pointer!");
209
210         setup = NT_TRANSACT_SET_USER_QUOTA;
211
212         SSVAL(params,0,quota_fnum);
213
214         sid_len = sid_size(&pqt->sid);
215         SIVAL(data,0,0);
216         SIVAL(data,4,sid_len);
217         SBIG_UINT(data, 8,(SMB_BIG_UINT)0);
218         SBIG_UINT(data,16,pqt->usedspace);
219         SBIG_UINT(data,24,pqt->softlim);
220         SBIG_UINT(data,32,pqt->hardlim);
221         sid_linearize(data+40, sid_len, &pqt->sid);
222         
223         if (!cli_send_nt_trans(cli, 
224                                NT_TRANSACT_SET_USER_QUOTA, 
225                                0, 
226                                &setup, 1, 0,
227                                params, 2, 0,
228                                data, 112, 0)) {
229                 DEBUG(1,("Failed to send NT_TRANSACT_SET_USER_QUOTA\n"));
230                 goto cleanup;
231         }
232
233
234         if (!cli_receive_nt_trans(cli, 
235                                   &rparam, &rparam_count,
236                                   &rdata, &rdata_count)) {
237                 DEBUG(1,("NT_TRANSACT_SET_USER_QUOTA failed\n"));
238                 goto cleanup;
239         }
240
241         if (cli_is_error(cli)) {
242                 ret = False;
243                 goto cleanup;
244         } else {
245                 ret = True;
246         }
247
248   cleanup:
249         SAFE_FREE(rparam);
250         SAFE_FREE(rdata);
251         return ret;
252 }
253
254 BOOL cli_list_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST **pqt_list)
255 {
256         BOOL ret = False;
257         uint16 setup;
258         char params[16];
259         char *rparam=NULL, *rdata=NULL;
260         unsigned int rparam_count=0, rdata_count=0;
261         unsigned int offset;
262         const char *curdata = NULL;
263         unsigned int curdata_count = 0;
264         TALLOC_CTX *mem_ctx = NULL;
265         SMB_NTQUOTA_STRUCT qt;
266         SMB_NTQUOTA_LIST *tmp_list_ent;
267
268         if (!cli||!pqt_list)
269                 smb_panic("cli_list_user_quota() called with NULL Pointer!");
270
271         setup = NT_TRANSACT_GET_USER_QUOTA;
272
273         SSVAL(params, 0,quota_fnum);
274         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START);
275         SIVAL(params, 4,0x00000000);
276         SIVAL(params, 8,0x00000000);
277         SIVAL(params,12,0x00000000);
278         
279         if (!cli_send_nt_trans(cli, 
280                                NT_TRANSACT_GET_USER_QUOTA, 
281                                0, 
282                                &setup, 1, 0,
283                                params, 16, 4,
284                                NULL, 0, 2048)) {
285                 DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
286                 goto cleanup;
287         }
288
289
290         if (!cli_receive_nt_trans(cli,
291                                   &rparam, &rparam_count,
292                                   &rdata, &rdata_count)) {
293                 DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
294                 goto cleanup;
295         }
296
297         if (cli_is_error(cli)) {
298                 ret = False;
299                 goto cleanup;
300         } else {
301                 ret = True;
302         }
303
304         if (rdata_count == 0) {
305                 *pqt_list = NULL;
306                 return True;
307         }
308
309         if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
310                 DEBUG(0,("talloc_init() failed\n"));
311                 return (-1);
312         }
313
314         offset = 1;
315         for (curdata=rdata,curdata_count=rdata_count;
316                 ((curdata)&&(curdata_count>=8)&&(offset>0));
317                 curdata +=offset,curdata_count -= offset) {
318                 ZERO_STRUCT(qt);
319                 if (!parse_user_quota_record(curdata, curdata_count, &offset, &qt)) {
320                         DEBUG(1,("Failed to parse the quota record\n"));
321                         goto cleanup;
322                 }
323
324                 if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
325                         DEBUG(0,("talloc_zero() failed\n"));
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                         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         setup = TRANSACT2_QFSINFO;
424         
425         SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
426         
427         if (!cli_send_trans(cli, SMBtrans2, 
428                     NULL, 
429                     0, 0,
430                     &setup, 1, 0,
431                     param, 2, 0,
432                     NULL, 0, 560)) {
433                 goto cleanup;
434         }
435         
436         if (!cli_receive_trans(cli, SMBtrans2,
437                               &rparam, &rparam_count,
438                               &rdata, &rdata_count)) {
439                 goto cleanup;
440         }
441
442         if (cli_is_error(cli)) {
443                 ret = False;
444                 goto cleanup;
445         } else {
446                 ret = True;
447         }
448
449         if (rdata_count < 48) {
450                 goto cleanup;
451         }
452         
453         /* unknown_1 24 NULL bytes in pdata*/
454
455         /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
456         qt.softlim = (SMB_BIG_UINT)IVAL(rdata,24);
457 #ifdef LARGE_SMB_OFF_T
458         qt.softlim |= (((SMB_BIG_UINT)IVAL(rdata,28)) << 32);
459 #else /* LARGE_SMB_OFF_T */
460         if ((IVAL(rdata,28) != 0)&&
461                 ((qt.softlim != 0xFFFFFFFF)||
462                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
463                 /* more than 32 bits? */
464                 goto cleanup;
465         }
466 #endif /* LARGE_SMB_OFF_T */
467
468         /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
469         qt.hardlim = (SMB_BIG_UINT)IVAL(rdata,32);
470 #ifdef LARGE_SMB_OFF_T
471         qt.hardlim |= (((SMB_BIG_UINT)IVAL(rdata,36)) << 32);
472 #else /* LARGE_SMB_OFF_T */
473         if ((IVAL(rdata,36) != 0)&&
474                 ((qt.hardlim != 0xFFFFFFFF)||
475                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
476                 /* more than 32 bits? */
477                 goto cleanup;
478         }
479 #endif /* LARGE_SMB_OFF_T */
480
481         /* quota_flags 2 bytes **/
482         qt.qflags = SVAL(rdata,40);
483
484         qt.qtype = SMB_USER_FS_QUOTA_TYPE;
485
486         *pqt = qt;
487
488         ret = True;
489 cleanup:
490         SAFE_FREE(rparam);
491         SAFE_FREE(rdata);
492
493         return ret;     
494 }
495
496 BOOL cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
497 {
498         BOOL ret = False;
499         uint16 setup;
500         char param[4];
501         char data[48];
502         char *rparam=NULL, *rdata=NULL;
503         unsigned int rparam_count=0, rdata_count=0;
504         SMB_NTQUOTA_STRUCT qt;
505         ZERO_STRUCT(qt);
506         memset(data,'\0',48);
507
508         if (!cli||!pqt)
509                 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
510
511         setup = TRANSACT2_SETFSINFO;
512
513         SSVAL(param,0,quota_fnum);
514         SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
515
516         /* Unknown1 24 NULL bytes*/
517
518         /* Default Soft Quota 8 bytes */
519         SBIG_UINT(data,24,pqt->softlim);
520
521         /* Default Hard Quota 8 bytes */
522         SBIG_UINT(data,32,pqt->hardlim);
523
524         /* Quota flag 2 bytes */
525         SSVAL(data,40,pqt->qflags);
526
527         /* Unknown3 6 NULL bytes */
528
529         if (!cli_send_trans(cli, SMBtrans2, 
530                     NULL, 
531                     0, 0,
532                     &setup, 1, 0,
533                     param, 4, 0,
534                     data, 48, 0)) {
535                 goto cleanup;
536         }
537         
538         if (!cli_receive_trans(cli, SMBtrans2,
539                               &rparam, &rparam_count,
540                               &rdata, &rdata_count)) {
541                 goto cleanup;
542         }
543
544         if (cli_is_error(cli)) {
545                 ret = False;
546                 goto cleanup;
547         } else {
548                 ret = True;
549         }
550
551 cleanup:
552         SAFE_FREE(rparam);
553         SAFE_FREE(rdata);
554
555         return ret;     
556 }
557
558 static char *quota_str_static(SMB_BIG_UINT val, BOOL special, BOOL _numeric)
559 {
560         static fstring buffer;
561         
562         memset(buffer,'\0',sizeof(buffer));
563
564         if (!_numeric&&special&&(val == SMB_NTQUOTAS_NO_LIMIT)) {
565                 fstr_sprintf(buffer,"NO LIMIT");
566                 return buffer;
567         }
568 #if defined(HAVE_LONGLONG)
569         fstr_sprintf(buffer,"%llu",val);
570 #else
571         fstr_sprintf(buffer,"%lu",val);
572 #endif  
573         return buffer;
574 }
575
576 void dump_ntquota(SMB_NTQUOTA_STRUCT *qt, BOOL _verbose, BOOL _numeric, void (*_sidtostring)(fstring str, DOM_SID *sid, BOOL _numeric))
577 {
578         if (!qt)
579                 smb_panic("dump_ntquota() called with NULL pointer");
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                                         fstrcpy(username_str,sid_string_static(&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                         return;
622         }
623 }
624
625 void dump_ntquota_list(SMB_NTQUOTA_LIST **qtl, BOOL _verbose, BOOL _numeric, void (*_sidtostring)(fstring str, 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 }