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