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