s3: Convert cli_set_user_quota to cli_trans
[bbaumbach/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 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 bool cli_list_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST **pqt_list)
236 {
237         bool ret = False;
238         uint16 setup;
239         char params[16];
240         char *rparam=NULL, *rdata=NULL;
241         unsigned int rparam_count=0, rdata_count=0;
242         unsigned int offset;
243         const char *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
249         if (!cli||!pqt_list) {
250                 smb_panic("cli_list_user_quota() called with NULL Pointer!");
251         }
252
253         setup = NT_TRANSACT_GET_USER_QUOTA;
254
255         SSVAL(params, 0,quota_fnum);
256         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START);
257         SIVAL(params, 4,0x00000000);
258         SIVAL(params, 8,0x00000000);
259         SIVAL(params,12,0x00000000);
260
261         if (!cli_send_nt_trans(cli, 
262                                NT_TRANSACT_GET_USER_QUOTA, 
263                                0, 
264                                &setup, 1, 0,
265                                params, 16, 4,
266                                NULL, 0, 2048)) {
267                 DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
268                 goto cleanup;
269         }
270
271
272         if (!cli_receive_nt_trans(cli,
273                                   &rparam, &rparam_count,
274                                   &rdata, &rdata_count)) {
275                 DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
276                 goto cleanup;
277         }
278
279         if (cli_is_error(cli)) {
280                 ret = False;
281                 goto cleanup;
282         } else {
283                 ret = True;
284         }
285
286         if (rdata_count == 0) {
287                 *pqt_list = NULL;
288                 return True;
289         }
290
291         if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
292                 DEBUG(0,("talloc_init() failed\n"));
293                 return (-1);
294         }
295
296         offset = 1;
297         for (curdata=rdata,curdata_count=rdata_count;
298                 ((curdata)&&(curdata_count>=8)&&(offset>0));
299                 curdata +=offset,curdata_count -= offset) {
300                 ZERO_STRUCT(qt);
301                 if (!parse_user_quota_record((uint8_t *)curdata, curdata_count,
302                                              &offset, &qt)) {
303                         DEBUG(1,("Failed to parse the quota record\n"));
304                         goto cleanup;
305                 }
306
307                 if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
308                         DEBUG(0,("TALLOC_ZERO() failed\n"));
309                         talloc_destroy(mem_ctx);
310                         return (-1);
311                 }
312
313                 if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
314                         DEBUG(0,("TALLOC_ZERO() failed\n"));
315                         talloc_destroy(mem_ctx);
316                         return (-1);
317                 }
318
319                 memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
320                 tmp_list_ent->mem_ctx = mem_ctx;                
321
322                 DLIST_ADD((*pqt_list),tmp_list_ent);
323         }
324
325         SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_CONTINUE); 
326         while(1) {
327                 if (!cli_send_nt_trans(cli, 
328                                        NT_TRANSACT_GET_USER_QUOTA, 
329                                        0, 
330                                        &setup, 1, 0,
331                                        params, 16, 4,
332                                        NULL, 0, 2048)) {
333                         DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n"));
334                         goto cleanup;
335                 }
336
337                 SAFE_FREE(rparam);
338                 SAFE_FREE(rdata);
339                 if (!cli_receive_nt_trans(cli,
340                                           &rparam, &rparam_count,
341                                           &rdata, &rdata_count)) {
342                         DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n"));
343                         goto cleanup;
344                 }
345
346                 if (cli_is_error(cli)) {
347                         ret = False;
348                         goto cleanup;
349                 } else {
350                         ret = True;
351                 }
352
353                 if (rdata_count == 0) {
354                         break;  
355                 }
356
357                 offset = 1;
358                 for (curdata=rdata,curdata_count=rdata_count;
359                         ((curdata)&&(curdata_count>=8)&&(offset>0));
360                         curdata +=offset,curdata_count -= offset) {
361                         ZERO_STRUCT(qt);
362                         if (!parse_user_quota_record((uint8_t *)curdata,
363                                                      curdata_count, &offset,
364                                                      &qt)) {
365                                 DEBUG(1,("Failed to parse the quota record\n"));
366                                 goto cleanup;
367                         }
368
369                         if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
370                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
371                                 talloc_destroy(mem_ctx);
372                                 goto cleanup;
373                         }
374
375                         if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
376                                 DEBUG(0,("TALLOC_ZERO() failed\n"));
377                                 talloc_destroy(mem_ctx);
378                                 goto cleanup;
379                         }
380
381                         memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
382                         tmp_list_ent->mem_ctx = mem_ctx;                
383
384                         DLIST_ADD((*pqt_list),tmp_list_ent);
385                 }
386         }
387
388
389         ret = True;
390  cleanup:
391         SAFE_FREE(rparam);
392         SAFE_FREE(rdata);
393
394         return ret;
395 }
396
397 bool cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
398 {
399         bool ret = False;
400         uint16 setup;
401         char param[2];
402         char *rparam=NULL, *rdata=NULL;
403         unsigned int rparam_count=0, rdata_count=0;
404         SMB_NTQUOTA_STRUCT qt;
405         ZERO_STRUCT(qt);
406
407         if (!cli||!pqt) {
408                 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
409         }
410
411         setup = TRANSACT2_QFSINFO;
412
413         SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
414
415         if (!cli_send_trans(cli, SMBtrans2, 
416                     NULL, 
417                     0, 0,
418                     &setup, 1, 0,
419                     param, 2, 0,
420                     NULL, 0, 560)) {
421                 goto cleanup;
422         }
423
424         if (!cli_receive_trans(cli, SMBtrans2,
425                               &rparam, &rparam_count,
426                               &rdata, &rdata_count)) {
427                 goto cleanup;
428         }
429
430         if (cli_is_error(cli)) {
431                 ret = False;
432                 goto cleanup;
433         } else {
434                 ret = True;
435         }
436
437         if (rdata_count < 48) {
438                 goto cleanup;
439         }
440
441         /* unknown_1 24 NULL bytes in pdata*/
442
443         /* the soft quotas 8 bytes (uint64_t)*/
444         qt.softlim = (uint64_t)IVAL(rdata,24);
445 #ifdef LARGE_SMB_OFF_T
446         qt.softlim |= (((uint64_t)IVAL(rdata,28)) << 32);
447 #else /* LARGE_SMB_OFF_T */
448         if ((IVAL(rdata,28) != 0)&&
449                 ((qt.softlim != 0xFFFFFFFF)||
450                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
451                 /* more than 32 bits? */
452                 goto cleanup;
453         }
454 #endif /* LARGE_SMB_OFF_T */
455
456         /* the hard quotas 8 bytes (uint64_t)*/
457         qt.hardlim = (uint64_t)IVAL(rdata,32);
458 #ifdef LARGE_SMB_OFF_T
459         qt.hardlim |= (((uint64_t)IVAL(rdata,36)) << 32);
460 #else /* LARGE_SMB_OFF_T */
461         if ((IVAL(rdata,36) != 0)&&
462                 ((qt.hardlim != 0xFFFFFFFF)||
463                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
464                 /* more than 32 bits? */
465                 goto cleanup;
466         }
467 #endif /* LARGE_SMB_OFF_T */
468
469         /* quota_flags 2 bytes **/
470         qt.qflags = SVAL(rdata,40);
471
472         qt.qtype = SMB_USER_FS_QUOTA_TYPE;
473
474         *pqt = qt;
475
476         ret = True;
477 cleanup:
478         SAFE_FREE(rparam);
479         SAFE_FREE(rdata);
480
481         return ret;     
482 }
483
484 bool cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt)
485 {
486         bool ret = False;
487         uint16 setup;
488         char param[4];
489         char data[48];
490         char *rparam=NULL, *rdata=NULL;
491         unsigned int rparam_count=0, rdata_count=0;
492         SMB_NTQUOTA_STRUCT qt;
493         ZERO_STRUCT(qt);
494         memset(data,'\0',48);
495
496         if (!cli||!pqt) {
497                 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
498         }
499
500         setup = TRANSACT2_SETFSINFO;
501
502         SSVAL(param,0,quota_fnum);
503         SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
504
505         /* Unknown1 24 NULL bytes*/
506
507         /* Default Soft Quota 8 bytes */
508         SBIG_UINT(data,24,pqt->softlim);
509
510         /* Default Hard Quota 8 bytes */
511         SBIG_UINT(data,32,pqt->hardlim);
512
513         /* Quota flag 2 bytes */
514         SSVAL(data,40,pqt->qflags);
515
516         /* Unknown3 6 NULL bytes */
517
518         if (!cli_send_trans(cli, SMBtrans2, 
519                     NULL, 
520                     0, 0,
521                     &setup, 1, 0,
522                     param, 4, 0,
523                     data, 48, 0)) {
524                 goto cleanup;
525         }
526
527         if (!cli_receive_trans(cli, SMBtrans2,
528                               &rparam, &rparam_count,
529                               &rdata, &rdata_count)) {
530                 goto cleanup;
531         }
532
533         if (cli_is_error(cli)) {
534                 ret = False;
535                 goto cleanup;
536         } else {
537                 ret = True;
538         }
539
540 cleanup:
541         SAFE_FREE(rparam);
542         SAFE_FREE(rdata);
543
544         return ret;     
545 }
546
547 static const char *quota_str_static(uint64_t val, bool special, bool _numeric)
548 {
549         const char *result;
550
551         if (!_numeric&&special&&(val == SMB_NTQUOTAS_NO_LIMIT)) {
552                 return "NO LIMIT";
553         }
554         result = talloc_asprintf(talloc_tos(), "%"PRIu64, val);
555         SMB_ASSERT(result != NULL);
556         return result;
557 }
558
559 void dump_ntquota(SMB_NTQUOTA_STRUCT *qt, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, struct dom_sid *sid, bool _numeric))
560 {
561         TALLOC_CTX *frame = talloc_stackframe();
562
563         if (!qt) {
564                 smb_panic("dump_ntquota() called with NULL pointer");
565         }
566
567         switch (qt->qtype) {
568                 case SMB_USER_FS_QUOTA_TYPE:
569                         {
570                                 d_printf("File System QUOTAS:\n");
571                                 d_printf("Limits:\n");
572                                 d_printf(" Default Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
573                                 d_printf(" Default Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
574                                 d_printf("Quota Flags:\n");
575                                 d_printf(" Quotas Enabled: %s\n",
576                                         ((qt->qflags&QUOTAS_ENABLED)||(qt->qflags&QUOTAS_DENY_DISK))?"On":"Off");
577                                 d_printf(" Deny Disk:      %s\n",(qt->qflags&QUOTAS_DENY_DISK)?"On":"Off");
578                                 d_printf(" Log Soft Limit: %s\n",(qt->qflags&QUOTAS_LOG_THRESHOLD)?"On":"Off");
579                                 d_printf(" Log Hard Limit: %s\n",(qt->qflags&QUOTAS_LOG_LIMIT)?"On":"Off");
580                         }
581                         break;
582                 case SMB_USER_QUOTA_TYPE:
583                         {
584                                 fstring username_str = {0};
585
586                                 if (_sidtostring) {
587                                         _sidtostring(username_str,&qt->sid,_numeric);
588                                 } else {
589                                         sid_to_fstring(username_str, &qt->sid);
590                                 }
591
592                                 if (_verbose) { 
593                                         d_printf("Quotas for User: %s\n",username_str);
594                                         d_printf("Used Space: %15s\n",quota_str_static(qt->usedspace,False,_numeric));
595                                         d_printf("Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
596                                         d_printf("Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
597                                 } else {
598                                         d_printf("%-30s: ",username_str);
599                                         d_printf("%15s/",quota_str_static(qt->usedspace,False,_numeric));
600                                         d_printf("%15s/",quota_str_static(qt->softlim,True,_numeric));
601                                         d_printf("%15s\n",quota_str_static(qt->hardlim,True,_numeric));
602                                 }
603                         }
604                         break;
605                 default:
606                         d_printf("dump_ntquota() invalid qtype(%d)\n",qt->qtype);
607         }
608         TALLOC_FREE(frame);
609         return;
610 }
611
612 void dump_ntquota_list(SMB_NTQUOTA_LIST **qtl, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, struct dom_sid *sid, bool _numeric))
613 {
614         SMB_NTQUOTA_LIST *cur;
615
616         for (cur = *qtl;cur;cur = cur->next) {
617                 if (cur->quotas)
618                         dump_ntquota(cur->quotas,_verbose,_numeric,_sidtostring);
619         }       
620 }