smbd: Fix CID 1035536 Uninitialized pointer read
[Samba.git] / source3 / lib / sysquotas_linux.c
blob5720328764b539812d0d2396072ec5b9552c05c5
1 /*
2 Unix SMB/CIFS implementation.
3 System QUOTA function wrappers for LINUX
4 Copyright (C) Stefan (metze) Metzmacher 2003
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.
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.
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/>.
21 #include "includes.h"
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_QUOTA
26 #ifndef HAVE_SYS_QUOTAS
27 #ifdef HAVE_QUOTACTL_LINUX
28 #undef HAVE_QUOTACTL_LINUX
29 #endif
30 #endif
32 #ifdef HAVE_QUOTACTL_LINUX
34 #include "samba_linux_quota.h"
36 /****************************************************************************
37 Abstract out the v1 Linux quota get calls.
38 ****************************************************************************/
39 static int sys_get_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
41 int ret = -1;
42 uint32 qflags = 0;
43 struct v1_kern_dqblk D;
44 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
46 ZERO_STRUCT(D);
48 switch (qtype) {
49 case SMB_USER_QUOTA_TYPE:
50 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
51 path, bdev, (unsigned)id.uid));
53 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
54 return ret;
57 break;
58 case SMB_GROUP_QUOTA_TYPE:
59 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
60 path, bdev, (unsigned)id.gid));
62 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
63 return ret;
66 break;
67 case SMB_USER_FS_QUOTA_TYPE:
68 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
69 path, bdev, (unsigned)id.uid));
71 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
72 qflags |= QUOTAS_DENY_DISK;
75 break;
76 case SMB_GROUP_FS_QUOTA_TYPE:
77 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
78 path, bdev, (unsigned)id.gid));
80 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
81 qflags |= QUOTAS_DENY_DISK;
84 break;
85 default:
86 errno = ENOSYS;
87 return -1;
90 dp->bsize = bsize;
91 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
92 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
93 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
94 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
95 dp->curinodes = (uint64_t)D.dqb_curinodes;
96 dp->curblocks = (uint64_t)D.dqb_curblocks;
99 dp->qflags = qflags;
101 return ret;
104 /****************************************************************************
105 Abstract out the v1 Linux quota set calls.
106 ****************************************************************************/
107 static int sys_set_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
109 int ret = -1;
110 uint32 qflags = 0;
111 uint32 oldqflags = 0;
112 struct v1_kern_dqblk D;
113 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
115 ZERO_STRUCT(D);
117 if (bsize == dp->bsize) {
118 D.dqb_bsoftlimit = dp->softlimit;
119 D.dqb_bhardlimit = dp->hardlimit;
120 D.dqb_ihardlimit = dp->ihardlimit;
121 D.dqb_isoftlimit = dp->isoftlimit;
122 } else {
123 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
124 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
125 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
126 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
129 qflags = dp->qflags;
131 switch (qtype) {
132 case SMB_USER_QUOTA_TYPE:
133 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
134 path, bdev, (unsigned)id.uid));
136 ret = quotactl(QCMD(Q_V1_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
137 break;
138 case SMB_GROUP_QUOTA_TYPE:
139 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
140 path, bdev, (unsigned)id.gid));
142 ret = quotactl(QCMD(Q_V1_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
143 break;
144 case SMB_USER_FS_QUOTA_TYPE:
145 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
146 path, bdev, (unsigned)id.uid));
148 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
149 oldqflags |= QUOTAS_DENY_DISK;
152 break;
153 case SMB_GROUP_FS_QUOTA_TYPE:
154 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
155 path, bdev, (unsigned)id.gid));
157 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
158 oldqflags |= QUOTAS_DENY_DISK;
161 break;
162 default:
163 errno = ENOSYS;
164 return -1;
167 return ret;
170 /****************************************************************************
171 Abstract out the v2 Linux quota get calls.
172 ****************************************************************************/
173 static int sys_get_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
175 int ret = -1;
176 uint32 qflags = 0;
177 struct v2_kern_dqblk D;
178 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
180 ZERO_STRUCT(D);
182 switch (qtype) {
183 case SMB_USER_QUOTA_TYPE:
184 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
185 path, bdev, (unsigned)id.uid));
187 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
188 return ret;
191 break;
192 case SMB_GROUP_QUOTA_TYPE:
193 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
194 path, bdev, (unsigned)id.gid));
196 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
197 return ret;
200 break;
201 case SMB_USER_FS_QUOTA_TYPE:
202 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
203 path, bdev, (unsigned)id.uid));
205 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
206 qflags |= QUOTAS_DENY_DISK;
209 break;
210 case SMB_GROUP_FS_QUOTA_TYPE:
211 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
212 path, bdev, (unsigned)id.gid));
214 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
215 qflags |= QUOTAS_DENY_DISK;
218 break;
219 default:
220 errno = ENOSYS;
221 return -1;
224 dp->bsize = bsize;
225 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
226 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
227 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
228 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
229 dp->curinodes = (uint64_t)D.dqb_curinodes;
230 dp->curblocks = (uint64_t)D.dqb_curspace/bsize;
233 dp->qflags = qflags;
235 return ret;
238 /****************************************************************************
239 Abstract out the v2 Linux quota set calls.
240 ****************************************************************************/
241 static int sys_set_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
243 int ret = -1;
244 uint32 qflags = 0;
245 uint32 oldqflags = 0;
246 struct v2_kern_dqblk D;
247 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
249 ZERO_STRUCT(D);
251 if (bsize == dp->bsize) {
252 D.dqb_bsoftlimit = dp->softlimit;
253 D.dqb_bhardlimit = dp->hardlimit;
254 D.dqb_ihardlimit = dp->ihardlimit;
255 D.dqb_isoftlimit = dp->isoftlimit;
256 } else {
257 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
258 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
259 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
260 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
263 qflags = dp->qflags;
265 switch (qtype) {
266 case SMB_USER_QUOTA_TYPE:
267 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
268 path, bdev, (unsigned)id.uid));
270 ret = quotactl(QCMD(Q_V2_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
271 break;
272 case SMB_GROUP_QUOTA_TYPE:
273 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
274 path, bdev, (unsigned)id.gid));
276 ret = quotactl(QCMD(Q_V2_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
277 break;
278 case SMB_USER_FS_QUOTA_TYPE:
279 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
280 path, bdev, (unsigned)id.uid));
282 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
283 oldqflags |= QUOTAS_DENY_DISK;
286 break;
287 case SMB_GROUP_FS_QUOTA_TYPE:
288 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
289 path, bdev, (unsigned)id.gid));
291 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
292 oldqflags |= QUOTAS_DENY_DISK;
295 break;
296 default:
297 errno = ENOSYS;
298 return -1;
301 return ret;
304 /****************************************************************************
305 Abstract out the generic Linux quota get calls.
306 ****************************************************************************/
307 static int sys_get_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
309 int ret = -1;
310 uint32 qflags = 0;
311 struct if_dqblk D;
312 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
314 ZERO_STRUCT(D);
316 switch (qtype) {
317 case SMB_USER_QUOTA_TYPE:
318 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
319 path, bdev, (unsigned)id.uid));
321 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
322 return ret;
325 break;
326 case SMB_GROUP_QUOTA_TYPE:
327 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
328 path, bdev, (unsigned)id.gid));
330 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
331 return ret;
334 break;
335 case SMB_USER_FS_QUOTA_TYPE:
336 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
337 path, bdev, (unsigned)id.uid));
339 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
340 qflags |= QUOTAS_DENY_DISK;
343 break;
344 case SMB_GROUP_FS_QUOTA_TYPE:
345 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
346 path, bdev, (unsigned)id.gid));
348 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
349 qflags |= QUOTAS_DENY_DISK;
352 break;
353 default:
354 errno = ENOSYS;
355 return -1;
358 dp->bsize = bsize;
359 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
360 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
361 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
362 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
363 dp->curinodes = (uint64_t)D.dqb_curinodes;
364 dp->curblocks = (uint64_t)D.dqb_curspace/bsize;
367 dp->qflags = qflags;
369 return ret;
372 /****************************************************************************
373 Abstract out the gen Linux quota set calls.
374 ****************************************************************************/
375 static int sys_set_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
377 int ret = -1;
378 uint32 qflags = 0;
379 uint32 oldqflags = 0;
380 struct if_dqblk D;
381 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
383 ZERO_STRUCT(D);
385 if (bsize == dp->bsize) {
386 D.dqb_bsoftlimit = dp->softlimit;
387 D.dqb_bhardlimit = dp->hardlimit;
388 D.dqb_ihardlimit = dp->ihardlimit;
389 D.dqb_isoftlimit = dp->isoftlimit;
390 } else {
391 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
392 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
393 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
394 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
396 D.dqb_valid = QIF_LIMITS;
398 qflags = dp->qflags;
400 switch (qtype) {
401 case SMB_USER_QUOTA_TYPE:
402 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
403 path, bdev, (unsigned)id.uid));
405 ret = quotactl(QCMD(Q_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
406 break;
407 case SMB_GROUP_QUOTA_TYPE:
408 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
409 path, bdev, (unsigned)id.gid));
411 ret = quotactl(QCMD(Q_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
412 break;
413 case SMB_USER_FS_QUOTA_TYPE:
414 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
415 path, bdev, (unsigned)id.uid));
417 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
418 oldqflags |= QUOTAS_DENY_DISK;
421 break;
422 case SMB_GROUP_FS_QUOTA_TYPE:
423 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
424 path, bdev, (unsigned)id.gid));
426 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
427 oldqflags |= QUOTAS_DENY_DISK;
430 break;
431 default:
432 errno = ENOSYS;
433 return -1;
436 return ret;
439 /****************************************************************************
440 Abstract out the Linux quota get calls.
441 ****************************************************************************/
442 int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
444 int ret = -1;
446 if (!path||!bdev||!dp)
447 smb_panic("sys_set_vfs_quota: called with NULL pointer");
449 ZERO_STRUCT(*dp);
450 dp->qtype = qtype;
452 switch (qtype) {
453 case SMB_USER_QUOTA_TYPE:
454 case SMB_GROUP_QUOTA_TYPE:
455 if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
456 if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
457 if ((ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
458 return ret;
463 if ((dp->curblocks==0)&&
464 (dp->softlimit==0)&&
465 (dp->hardlimit==0)) {
466 /* the upper layer functions don't want empty quota records...*/
467 return -1;
470 break;
471 case SMB_USER_FS_QUOTA_TYPE:
472 id.uid = getuid();
474 if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
475 if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
476 ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
480 ret = 0;
481 break;
482 case SMB_GROUP_FS_QUOTA_TYPE:
483 id.gid = getgid();
485 if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
486 if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
487 ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
491 ret = 0;
492 break;
493 default:
494 errno = ENOSYS;
495 return -1;
498 return ret;
501 /****************************************************************************
502 Abstract out the Linux quota set calls.
503 ****************************************************************************/
504 int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
506 int ret = -1;
507 uint32 oldqflags = 0;
509 if (!path||!bdev||!dp)
510 smb_panic("sys_set_vfs_quota: called with NULL pointer");
512 oldqflags = dp->qflags;
514 switch (qtype) {
515 case SMB_USER_QUOTA_TYPE:
516 case SMB_GROUP_QUOTA_TYPE:
517 if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
518 if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
519 if ((ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp))) {
520 return ret;
524 break;
525 case SMB_USER_FS_QUOTA_TYPE:
526 id.uid = getuid();
528 if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
529 if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
530 ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp);
534 if (oldqflags == dp->qflags) {
535 ret = 0;
536 } else {
537 ret = -1;
539 break;
540 case SMB_GROUP_FS_QUOTA_TYPE:
541 id.gid = getgid();
543 if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
544 if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
545 ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp);
549 if (oldqflags == dp->qflags) {
550 ret = 0;
551 } else {
552 ret = -1;
555 break;
556 default:
557 errno = ENOSYS;
558 return -1;
561 return ret;
564 #else /* HAVE_QUOTACTL_LINUX */
565 void dummy_sysquotas_linux(void);
567 void dummy_sysquotas_linux(void){}
568 #endif /* HAVE_QUOTACTL_LINUX */