s3: Convert cli_set_fs_quota_info 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 NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
384                                SMB_NTQUOTA_STRUCT *pqt)
385 {
386         uint16_t setup[1];
387         uint8_t param[2];
388         uint8_t *rdata=NULL;
389         uint32_t rdata_count=0;
390         SMB_NTQUOTA_STRUCT qt;
391         NTSTATUS status;
392
393         ZERO_STRUCT(qt);
394
395         if (!cli||!pqt) {
396                 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
397         }
398
399         SSVAL(setup + 0, 0, TRANSACT2_QFSINFO);
400
401         SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
402
403         status = cli_trans(talloc_tos(), cli, SMBtrans2,
404                            NULL, -1, /* name, fid */
405                            0, 0,     /* function, flags */
406                            setup, 1, 0, /* setup */
407                            param, 2, 0, /* param */
408                            NULL, 0, 560, /* data */
409                            NULL,         /* recv_flags2 */
410                            NULL, 0, NULL, /* rsetup */
411                            NULL, 0, NULL, /* rparam */
412                            &rdata, 48, &rdata_count);
413
414         if (!NT_STATUS_IS_OK(status)) {
415                 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
416                           nt_errstr(status)));
417                 return status;
418         }
419
420         /* unknown_1 24 NULL bytes in pdata*/
421
422         /* the soft quotas 8 bytes (uint64_t)*/
423         qt.softlim = (uint64_t)IVAL(rdata,24);
424 #ifdef LARGE_SMB_OFF_T
425         qt.softlim |= (((uint64_t)IVAL(rdata,28)) << 32);
426 #else /* LARGE_SMB_OFF_T */
427         if ((IVAL(rdata,28) != 0)&&
428                 ((qt.softlim != 0xFFFFFFFF)||
429                  (IVAL(rdata,28)!=0xFFFFFFFF))) {
430                 /* more than 32 bits? */
431                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
432                 goto cleanup;
433         }
434 #endif /* LARGE_SMB_OFF_T */
435
436         /* the hard quotas 8 bytes (uint64_t)*/
437         qt.hardlim = (uint64_t)IVAL(rdata,32);
438 #ifdef LARGE_SMB_OFF_T
439         qt.hardlim |= (((uint64_t)IVAL(rdata,36)) << 32);
440 #else /* LARGE_SMB_OFF_T */
441         if ((IVAL(rdata,36) != 0)&&
442                 ((qt.hardlim != 0xFFFFFFFF)||
443                  (IVAL(rdata,36)!=0xFFFFFFFF))) {
444                 /* more than 32 bits? */
445                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
446                 goto cleanup;
447         }
448 #endif /* LARGE_SMB_OFF_T */
449
450         /* quota_flags 2 bytes **/
451         qt.qflags = SVAL(rdata,40);
452
453         qt.qtype = SMB_USER_FS_QUOTA_TYPE;
454
455         *pqt = qt;
456
457         TALLOC_FREE(rdata);
458         return status;
459 }
460
461 NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
462                                SMB_NTQUOTA_STRUCT *pqt)
463 {
464         uint16_t setup[1];
465         uint8_t param[4];
466         uint8_t data[48];
467         SMB_NTQUOTA_STRUCT qt;
468         NTSTATUS status;
469         ZERO_STRUCT(qt);
470         memset(data,'\0',48);
471
472         if (!cli||!pqt) {
473                 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
474         }
475
476         SSVAL(setup + 0, 0,TRANSACT2_SETFSINFO);
477
478         SSVAL(param,0,quota_fnum);
479         SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
480
481         /* Unknown1 24 NULL bytes*/
482
483         /* Default Soft Quota 8 bytes */
484         SBIG_UINT(data,24,pqt->softlim);
485
486         /* Default Hard Quota 8 bytes */
487         SBIG_UINT(data,32,pqt->hardlim);
488
489         /* Quota flag 2 bytes */
490         SSVAL(data,40,pqt->qflags);
491
492         /* Unknown3 6 NULL bytes */
493
494         status = cli_trans(talloc_tos(), cli, SMBtrans2,
495                            NULL, -1, /* name, fid */
496                            0, 0,     /* function, flags */
497                            setup, 1, 0, /* setup */
498                            param, 8, 0, /* param */
499                            data, 48, 0, /* data */
500                            NULL,         /* recv_flags2 */
501                            NULL, 0, NULL, /* rsetup */
502                            NULL, 0, NULL, /* rparam */
503                            NULL, 0, NULL); /* rdata */
504
505         if (!NT_STATUS_IS_OK(status)) {
506                 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
507                           nt_errstr(status)));
508         }
509
510         return status;
511 }
512
513 static const char *quota_str_static(uint64_t val, bool special, bool _numeric)
514 {
515         const char *result;
516
517         if (!_numeric&&special&&(val == SMB_NTQUOTAS_NO_LIMIT)) {
518                 return "NO LIMIT";
519         }
520         result = talloc_asprintf(talloc_tos(), "%"PRIu64, val);
521         SMB_ASSERT(result != NULL);
522         return result;
523 }
524
525 void dump_ntquota(SMB_NTQUOTA_STRUCT *qt, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, struct dom_sid *sid, bool _numeric))
526 {
527         TALLOC_CTX *frame = talloc_stackframe();
528
529         if (!qt) {
530                 smb_panic("dump_ntquota() called with NULL pointer");
531         }
532
533         switch (qt->qtype) {
534                 case SMB_USER_FS_QUOTA_TYPE:
535                         {
536                                 d_printf("File System QUOTAS:\n");
537                                 d_printf("Limits:\n");
538                                 d_printf(" Default Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
539                                 d_printf(" Default Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
540                                 d_printf("Quota Flags:\n");
541                                 d_printf(" Quotas Enabled: %s\n",
542                                         ((qt->qflags&QUOTAS_ENABLED)||(qt->qflags&QUOTAS_DENY_DISK))?"On":"Off");
543                                 d_printf(" Deny Disk:      %s\n",(qt->qflags&QUOTAS_DENY_DISK)?"On":"Off");
544                                 d_printf(" Log Soft Limit: %s\n",(qt->qflags&QUOTAS_LOG_THRESHOLD)?"On":"Off");
545                                 d_printf(" Log Hard Limit: %s\n",(qt->qflags&QUOTAS_LOG_LIMIT)?"On":"Off");
546                         }
547                         break;
548                 case SMB_USER_QUOTA_TYPE:
549                         {
550                                 fstring username_str = {0};
551
552                                 if (_sidtostring) {
553                                         _sidtostring(username_str,&qt->sid,_numeric);
554                                 } else {
555                                         sid_to_fstring(username_str, &qt->sid);
556                                 }
557
558                                 if (_verbose) { 
559                                         d_printf("Quotas for User: %s\n",username_str);
560                                         d_printf("Used Space: %15s\n",quota_str_static(qt->usedspace,False,_numeric));
561                                         d_printf("Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric));
562                                         d_printf("Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric));
563                                 } else {
564                                         d_printf("%-30s: ",username_str);
565                                         d_printf("%15s/",quota_str_static(qt->usedspace,False,_numeric));
566                                         d_printf("%15s/",quota_str_static(qt->softlim,True,_numeric));
567                                         d_printf("%15s\n",quota_str_static(qt->hardlim,True,_numeric));
568                                 }
569                         }
570                         break;
571                 default:
572                         d_printf("dump_ntquota() invalid qtype(%d)\n",qt->qtype);
573         }
574         TALLOC_FREE(frame);
575         return;
576 }
577
578 void dump_ntquota_list(SMB_NTQUOTA_LIST **qtl, bool _verbose, bool _numeric, void (*_sidtostring)(fstring str, struct dom_sid *sid, bool _numeric))
579 {
580         SMB_NTQUOTA_LIST *cur;
581
582         for (cur = *qtl;cur;cur = cur->next) {
583                 if (cur->quotas)
584                         dump_ntquota(cur->quotas,_verbose,_numeric,_sidtostring);
585         }       
586 }