s3: Convert cli_list_user_quota to cli_trans
[metze/samba/wip.git] / source3 / libsmb / cliquota.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client quota functions
4    Copyright (C) Stefan (metze) Metzmacher      2003
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "../librpc/gen_ndr/ndr_security.h"
22 #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 uint8_t *rdata,
47                                     unsigned int rdata_count,
48                                     unsigned int *offset,
49                                     SMB_NTQUOTA_STRUCT *pqt)
50 {
51         int sid_len;
52         SMB_NTQUOTA_STRUCT qt;
53
54         ZERO_STRUCT(qt);
55
56         if (!rdata||!offset||!pqt) {
57                 smb_panic("parse_quota_record: called with NULL POINTER!");
58         }
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 (uint64_t)*/
82         qt.usedspace = (uint64_t)IVAL(rdata,16);
83 #ifdef LARGE_SMB_OFF_T
84         qt.usedspace |= (((uint64_t)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 (uint64_t)*/
95         qt.softlim = (uint64_t)IVAL(rdata,24);
96 #ifdef LARGE_SMB_OFF_T
97         qt.softlim |= (((uint64_t)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 (uint64_t)*/
108         qt.hardlim = (uint64_t)IVAL(rdata,32);
109 #ifdef LARGE_SMB_OFF_T
110         qt.hardlim |= (((uint64_t)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         if (!sid_parse((char *)rdata+40,sid_len,&qt.sid)) {
121                 return false;
122         }
123
124         qt.qtype = SMB_USER_QUOTA_TYPE;
125
126         *pqt = qt;
127
128         return True;
129 }
130
131 NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
132                             SMB_NTQUOTA_STRUCT *pqt)
133 {
134         uint16_t setup[1];
135         uint8_t params[16];
136         unsigned int data_len;
137         uint8_t data[SID_MAX_SIZE+8];
138         uint8_t *rparam, *rdata;
139         uint32_t rparam_count, rdata_count;
140         unsigned int sid_len;
141         unsigned int offset;
142         NTSTATUS status;
143
144         if (!cli||!pqt) {
145                 smb_panic("cli_get_user_quota() called with NULL Pointer!");
146         }
147
148         SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
149
150         SSVAL(params, 0,quota_fnum);
151         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID);
152         SIVAL(params, 4,0x00000024);
153         SIVAL(params, 8,0x00000000);
154         SIVAL(params,12,0x00000024);
155
156         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
157         data_len = sid_len+8;
158         SIVAL(data, 0, 0x00000000);
159         SIVAL(data, 4, sid_len);
160         sid_linearize((char *)data+8, sid_len, &pqt->sid);
161
162         status = cli_trans(talloc_tos(), cli, SMBnttrans,
163                            NULL, -1, /* name, fid */
164                            NT_TRANSACT_GET_USER_QUOTA, 0,
165                            setup, 1, 0, /* setup */
166                            params, 16, 4, /* params */
167                            data, data_len, 112, /* data */
168                            NULL,                /* recv_flags2 */
169                            NULL, 0, NULL,       /* rsetup */
170                            &rparam, 4, &rparam_count,
171                            &rdata, 8, &rdata_count);
172         if (!NT_STATUS_IS_OK(status)) {
173                 DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
174                           nt_errstr(status)));
175                 return status;
176         }
177
178         if (!parse_user_quota_record(rdata, rdata_count, &offset, pqt)) {
179                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
180                 DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
181         }
182
183         TALLOC_FREE(rparam);
184         TALLOC_FREE(rdata);
185         return status;
186 }
187
188 NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
189                             SMB_NTQUOTA_STRUCT *pqt)
190 {
191         uint16_t setup[1];
192         uint8_t params[2];
193         uint8_t data[112];
194         unsigned int sid_len;   
195         NTSTATUS status;
196
197         memset(data,'\0',112);
198
199         if (!cli||!pqt) {
200                 smb_panic("cli_set_user_quota() called with NULL Pointer!");
201         }
202
203         SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
204
205         SSVAL(params,0,quota_fnum);
206
207         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
208         SIVAL(data,0,0);
209         SIVAL(data,4,sid_len);
210         SBIG_UINT(data, 8,(uint64_t)0);
211         SBIG_UINT(data,16,pqt->usedspace);
212         SBIG_UINT(data,24,pqt->softlim);
213         SBIG_UINT(data,32,pqt->hardlim);
214         sid_linearize((char *)data+40, sid_len, &pqt->sid);
215
216         status = cli_trans(talloc_tos(), cli, SMBnttrans,
217                            NULL, -1, /* name, fid */
218                            NT_TRANSACT_SET_USER_QUOTA, 0,
219                            setup, 1, 0, /* setup */
220                            params, 2, 0, /* params */
221                            data, 112, 0, /* data */
222                            NULL,                /* recv_flags2 */
223                            NULL, 0, NULL,       /* rsetup */
224                            NULL, 0, NULL,       /* rparams */
225                            NULL, 0, NULL);      /* rdata */
226
227         if (!NT_STATUS_IS_OK(status)) {
228                 DEBUG(1, ("NT_TRANSACT_SET_USER_QUOTA failed: %s\n",
229                           nt_errstr(status)));
230         }
231
232         return status;
233 }
234
235 NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
236                              SMB_NTQUOTA_LIST **pqt_list)
237 {
238         uint16_t setup[1];
239         uint8_t params[16];
240         uint8_t *rparam=NULL, *rdata=NULL;
241         uint32_t rparam_count=0, rdata_count=0;
242         unsigned int offset;
243         const uint8_t *curdata = NULL;
244         unsigned int curdata_count = 0;
245         TALLOC_CTX *mem_ctx = NULL;
246         SMB_NTQUOTA_STRUCT qt;
247         SMB_NTQUOTA_LIST *tmp_list_ent;
248         NTSTATUS status;
249
250         if (!cli||!pqt_list) {
251                 smb_panic("cli_list_user_quota() called with NULL Pointer!");
252         }
253
254         SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
255
256         SSVAL(params, 0,quota_fnum);
257         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START);
258         SIVAL(params, 4,0x00000000);
259         SIVAL(params, 8,0x00000000);
260         SIVAL(params,12,0x00000000);
261
262         status = cli_trans(talloc_tos(), cli, SMBnttrans,
263                            NULL, -1, /* name, fid */
264                            NT_TRANSACT_GET_USER_QUOTA, 0,
265                            setup, 1, 0, /* setup */
266                            params, 16, 4, /* params */
267                            NULL, 0, 2048, /* data */
268                            NULL,                /* recv_flags2 */
269                            NULL, 0, NULL,       /* rsetup */
270                            &rparam, 0, &rparam_count,
271                            &rdata, 0, &rdata_count);
272
273         if (!NT_STATUS_IS_OK(status)) {
274                 DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
275                           nt_errstr(status)));
276                 goto cleanup;
277         }
278
279         if (rdata_count == 0) {
280                 *pqt_list = NULL;
281                 return NT_STATUS_OK;
282         }
283
284         if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
285                 DEBUG(0,("talloc_init() failed\n"));
286                 return NT_STATUS_NO_MEMORY;
287         }
288
289         offset = 1;
290         for (curdata=rdata,curdata_count=rdata_count;
291                 ((curdata)&&(curdata_count>=8)&&(offset>0));
292                 curdata +=offset,curdata_count -= offset) {
293                 ZERO_STRUCT(qt);
294                 if (!parse_user_quota_record((uint8_t *)curdata, curdata_count,
295                                              &offset, &qt)) {
296                         DEBUG(1,("Failed to parse the quota record\n"));
297                         goto cleanup;
298                 }
299
300                 if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
301                         DEBUG(0,("TALLOC_ZERO() failed\n"));
302                         talloc_destroy(mem_ctx);
303                         return NT_STATUS_NO_MEMORY;
304                 }
305
306                 if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
307                         DEBUG(0,("TALLOC_ZERO() failed\n"));
308                         talloc_destroy(mem_ctx);
309                         return NT_STATUS_NO_MEMORY;
310                 }
311
312                 memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
313                 tmp_list_ent->mem_ctx = mem_ctx;                
314
315                 DLIST_ADD((*pqt_list),tmp_list_ent);
316         }
317
318         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_CONTINUE); 
319         while(1) {
320
321                 TALLOC_FREE(rparam);
322                 TALLOC_FREE(rdata);
323
324                 status = cli_trans(talloc_tos(), cli, SMBnttrans,
325                                    NULL, -1, /* name, fid */
326                                    NT_TRANSACT_GET_USER_QUOTA, 0,
327                                    setup, 1, 0, /* setup */
328                                    params, 16, 4, /* params */
329                                    NULL, 0, 2048, /* data */
330                                    NULL,                /* recv_flags2 */
331                                    NULL, 0, NULL,       /* rsetup */
332                                    &rparam, 0, &rparam_count,
333                                    &rdata, 0, &rdata_count);
334
335                 if (!NT_STATUS_IS_OK(status)) {
336                         DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
337                                   nt_errstr(status)));
338                         goto cleanup;
339                 }
340
341                 if (rdata_count == 0) {
342                         break;
343                 }
344
345                 offset = 1;
346                 for (curdata=rdata,curdata_count=rdata_count;
347                         ((curdata)&&(curdata_count>=8)&&(offset>0));
348                         curdata +=offset,curdata_count -= offset) {
349                         ZERO_STRUCT(qt);
350                         if (!parse_user_quota_record((uint8_t *)curdata,
351                                                      curdata_count, &offset,
352                                                      &qt)) {
353                                 DEBUG(1,("Failed to parse the quota record\n"));
354                                 goto cleanup;
355                         }
356
357                         if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
358                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
359                                 talloc_destroy(mem_ctx);
360                                 goto cleanup;
361                         }
362
363                         if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
364                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
365                                 talloc_destroy(mem_ctx);
366                                 goto cleanup;
367                         }
368
369                         memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
370                         tmp_list_ent->mem_ctx = mem_ctx;                
371
372                         DLIST_ADD((*pqt_list),tmp_list_ent);
373                 }
374         }
375
376  cleanup:
377         TALLOC_FREE(rparam);
378         TALLOC_FREE(rdata);
379
380         return status;
381 }
382
383 bool cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
384 {
385         bool ret = False;
386         uint16 setup;
387         char param[2];
388         char *rparam=NULL, *rdata=NULL;
389         unsigned int rparam_count=0, rdata_count=0;
390         SMB_NTQUOTA_STRUCT qt;
391         ZERO_STRUCT(qt);
392
393         if (!cli||!pqt) {
394                 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
395         }
396
397         setup = TRANSACT2_QFSINFO;
398
399         SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
400
401         if (!cli_send_trans(cli, SMBtrans2, 
402                     NULL, 
403                     0, 0,
404                     &setup, 1, 0,
405                     param, 2, 0,
406                     NULL, 0, 560)) {
407                 goto cleanup;
408         }
409
410         if (!cli_receive_trans(cli, SMBtrans2,
411                               &rparam, &rparam_count,
412                               &rdata, &rdata_count)) {
413                 goto cleanup;
414         }
415
416         if (cli_is_error(cli)) {
417                 ret = False;
418                 goto cleanup;
419         } else {
420                 ret = True;
421         }
422
423         if (rdata_count < 48) {
424                 goto cleanup;
425         }
426
427         /* unknown_1 24 NULL bytes in pdata*/
428
429         /* the soft quotas 8 bytes (uint64_t)*/
430         qt.softlim = (uint64_t)IVAL(rdata,24);
431 #ifdef LARGE_SMB_OFF_T
432         qt.softlim |= (((uint64_t)IVAL(rdata,28)) << 32);
433 #else /* LARGE_SMB_OFF_T */
434         if ((IVAL(rdata,28) != 0)&&
435                 ((qt.softlim != 0xFFFFFFFF)||
436                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
437                 /* more than 32 bits? */
438                 goto cleanup;
439         }
440 #endif /* LARGE_SMB_OFF_T */
441
442         /* the hard quotas 8 bytes (uint64_t)*/
443         qt.hardlim = (uint64_t)IVAL(rdata,32);
444 #ifdef LARGE_SMB_OFF_T
445         qt.hardlim |= (((uint64_t)IVAL(rdata,36)) << 32);
446 #else /* LARGE_SMB_OFF_T */
447         if ((IVAL(rdata,36) != 0)&&
448                 ((qt.hardlim != 0xFFFFFFFF)||
449                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
450                 /* more than 32 bits? */
451                 goto cleanup;
452         }
453 #endif /* LARGE_SMB_OFF_T */
454
455         /* quota_flags 2 bytes **/
456         qt.qflags = SVAL(rdata,40);
457
458         qt.qtype = SMB_USER_FS_QUOTA_TYPE;
459
460         *pqt = qt;
461
462         ret = True;
463 cleanup:
464         SAFE_FREE(rparam);
465         SAFE_FREE(rdata);
466
467         return ret;     
468 }
469
470 bool cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
471 {
472         bool ret = False;
473         uint16 setup;
474         char param[4];
475         char data[48];
476         char *rparam=NULL, *rdata=NULL;
477         unsigned int rparam_count=0, rdata_count=0;
478         SMB_NTQUOTA_STRUCT qt;
479         ZERO_STRUCT(qt);
480         memset(data,'\0',48);
481
482         if (!cli||!pqt) {
483                 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
484         }
485
486         setup = TRANSACT2_SETFSINFO;
487
488         SSVAL(param,0,quota_fnum);
489         SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
490
491         /* Unknown1 24 NULL bytes*/
492
493         /* Default Soft Quota 8 bytes */
494         SBIG_UINT(data,24,pqt->softlim);
495
496         /* Default Hard Quota 8 bytes */
497         SBIG_UINT(data,32,pqt->hardlim);
498
499         /* Quota flag 2 bytes */
500         SSVAL(data,40,pqt->qflags);
501
502         /* Unknown3 6 NULL bytes */
503
504         if (!cli_send_trans(cli, SMBtrans2, 
505                     NULL, 
506                     0, 0,
507                     &setup, 1, 0,
508                     param, 4, 0,
509                     data, 48, 0)) {
510                 goto cleanup;
511         }
512
513         if (!cli_receive_trans(cli, SMBtrans2,
514                               &rparam, &rparam_count,
515                               &rdata, &rdata_count)) {
516                 goto cleanup;
517         }
518
519         if (cli_is_error(cli)) {
520                 ret = False;
521                 goto cleanup;
522         } else {
523                 ret = True;
524         }
525
526 cleanup:
527         SAFE_FREE(rparam);
528         SAFE_FREE(rdata);
529
530         return ret;     
531 }
532
533 static const char *quota_str_static(uint64_t val, bool special, bool _numeric)
534 {
535         const char *result;
536
537         if (!_numeric&&special&&(val == SMB_NTQUOTAS_NO_LIMIT)) {
538                 return "NO LIMIT";
539         }
540         result = talloc_asprintf(talloc_tos(), "%"PRIu64, val);
541         SMB_ASSERT(result != NULL);
542         return result;
543 }
544
545 void dump_ntquota(SMB_NTQUOTA_STRUCT *qt, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, struct dom_sid *sid, bool _numeric))
546 {
547         TALLOC_CTX *frame = talloc_stackframe();
548
549         if (!qt) {
550                 smb_panic("dump_ntquota() called with NULL pointer");
551         }
552
553         switch (qt->qtype) {
554                 case SMB_USER_FS_QUOTA_TYPE:
555                         {
556                                 d_printf("File System QUOTAS:\n");
557                                 d_printf("Limits:\n");
558                                 d_printf(" Default Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
559                                 d_printf(" Default Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
560                                 d_printf("Quota Flags:\n");
561                                 d_printf(" Quotas Enabled: %s\n",
562                                         ((qt->qflags&QUOTAS_ENABLED)||(qt->qflags&QUOTAS_DENY_DISK))?"On":"Off");
563                                 d_printf(" Deny Disk:      %s\n",(qt->qflags&QUOTAS_DENY_DISK)?"On":"Off");
564                                 d_printf(" Log Soft Limit: %s\n",(qt->qflags&QUOTAS_LOG_THRESHOLD)?"On":"Off");
565                                 d_printf(" Log Hard Limit: %s\n",(qt->qflags&QUOTAS_LOG_LIMIT)?"On":"Off");
566                         }
567                         break;
568                 case SMB_USER_QUOTA_TYPE:
569                         {
570                                 fstring username_str = {0};
571
572                                 if (_sidtostring) {
573                                         _sidtostring(username_str,&qt->sid,_numeric);
574                                 } else {
575                                         sid_to_fstring(username_str, &qt->sid);
576                                 }
577
578                                 if (_verbose) { 
579                                         d_printf("Quotas for User: %s\n",username_str);
580                                         d_printf("Used Space: %15s\n",quota_str_static(qt->usedspace,False,_numeric));
581                                         d_printf("Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
582                                         d_printf("Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
583                                 } else {
584                                         d_printf("%-30s: ",username_str);
585                                         d_printf("%15s/",quota_str_static(qt->usedspace,False,_numeric));
586                                         d_printf("%15s/",quota_str_static(qt->softlim,True,_numeric));
587                                         d_printf("%15s\n",quota_str_static(qt->hardlim,True,_numeric));
588                                 }
589                         }
590                         break;
591                 default:
592                         d_printf("dump_ntquota() invalid qtype(%d)\n",qt->qtype);
593         }
594         TALLOC_FREE(frame);
595         return;
596 }
597
598 void dump_ntquota_list(SMB_NTQUOTA_LIST **qtl, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, struct dom_sid *sid, bool _numeric))
599 {
600         SMB_NTQUOTA_LIST *cur;
601
602         for (cur = *qtl;cur;cur = cur->next) {
603                 if (cur->quotas)
604                         dump_ntquota(cur->quotas,_verbose,_numeric,_sidtostring);
605         }       
606 }