Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : System QUOTA function wrappers
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 :
21 : #include "includes.h"
22 : #include "lib/util_file.h"
23 : #include "lib/util/smb_strtox.h"
24 :
25 : #undef DBGC_CLASS
26 : #define DBGC_CLASS DBGC_QUOTA
27 :
28 : #ifdef HAVE_SYS_QUOTAS
29 :
30 : #if defined(HAVE_QUOTACTL_4A)
31 :
32 : /*#endif HAVE_QUOTACTL_4A */
33 : #elif defined(HAVE_QUOTACTL_4B)
34 :
35 : /*#endif HAVE_QUOTACTL_4B */
36 : #elif defined(HAVE_QUOTACTL_3)
37 :
38 : #error HAVE_QUOTACTL_3 not implemented
39 :
40 : /* #endif HAVE_QUOTACTL_3 */
41 : #else /* NO_QUOTACTL_USED */
42 :
43 : #endif /* NO_QUOTACTL_USED */
44 :
45 : #if defined(HAVE_MNTENT) && defined(HAVE_REALPATH)
46 2338 : static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
47 : {
48 2338 : int ret = -1;
49 0 : SMB_STRUCT_STAT S;
50 0 : FILE *fp;
51 2338 : struct mntent *mnt = NULL;
52 0 : SMB_DEV_T devno;
53 2338 : char *stat_mntpath = NULL;
54 0 : char *p;
55 :
56 : /* find the block device file */
57 2338 : (*mntpath) = NULL;
58 2338 : (*bdev) = NULL;
59 2338 : (*fs) = NULL;
60 :
61 2338 : if (sys_stat(path, &S, false) != 0) {
62 0 : return -1;
63 : }
64 :
65 2338 : devno = S.st_ex_dev ;
66 :
67 2338 : stat_mntpath = sys_realpath(path);
68 2338 : if (stat_mntpath == NULL) {
69 0 : DBG_WARNING("realpath(%s) failed - %s\n", path,
70 : strerror(errno));
71 0 : goto out;
72 : }
73 :
74 2338 : if (sys_stat(stat_mntpath, &S, false) != 0) {
75 0 : DBG_WARNING("cannot stat real path %s - %s\n", stat_mntpath,
76 : strerror(errno));
77 0 : goto out;
78 : }
79 :
80 2338 : if (S.st_ex_dev != devno) {
81 0 : DBG_WARNING("device on real path has changed\n");
82 0 : goto out;
83 : }
84 :
85 14740 : while (true) {
86 0 : char save_ch;
87 :
88 17078 : p = strrchr(stat_mntpath, '/');
89 17078 : if (p == NULL) {
90 0 : DBG_ERR("realpath for %s does not begin with a '/'\n",
91 : path);
92 0 : goto out;
93 : }
94 :
95 17078 : if (p == stat_mntpath) {
96 2338 : ++p;
97 : }
98 :
99 17078 : save_ch = *p;
100 17078 : *p = 0;
101 17078 : if (sys_stat(stat_mntpath, &S, false) != 0) {
102 0 : DBG_WARNING("cannot stat real path component %s - %s\n",
103 : stat_mntpath, strerror(errno));
104 0 : goto out;
105 : }
106 17078 : if (S.st_ex_dev != devno) {
107 2338 : *p = save_ch;
108 2338 : break;
109 : }
110 :
111 14740 : if (p <= stat_mntpath + 1) {
112 0 : break;
113 : }
114 : }
115 :
116 2338 : fp = setmntent(MOUNTED,"r");
117 2338 : if (fp == NULL) {
118 0 : goto out;
119 : }
120 :
121 22846 : while ((mnt = getmntent(fp))) {
122 22846 : if (!strequal(mnt->mnt_dir, stat_mntpath)) {
123 20508 : continue;
124 : }
125 :
126 2338 : if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
127 0 : continue ;
128 :
129 2338 : if (S.st_ex_dev == devno) {
130 2338 : (*mntpath) = SMB_STRDUP(mnt->mnt_dir);
131 2338 : (*bdev) = SMB_STRDUP(mnt->mnt_fsname);
132 2338 : (*fs) = SMB_STRDUP(mnt->mnt_type);
133 2338 : if ((*mntpath)&&(*bdev)&&(*fs)) {
134 2338 : ret = 0;
135 : } else {
136 0 : SAFE_FREE(*mntpath);
137 0 : SAFE_FREE(*bdev);
138 0 : SAFE_FREE(*fs);
139 0 : ret = -1;
140 : }
141 :
142 2338 : break;
143 : }
144 : }
145 :
146 2338 : endmntent(fp) ;
147 :
148 2338 : out:
149 2338 : SAFE_FREE(stat_mntpath);
150 2338 : return ret;
151 : }
152 : /* #endif HAVE_MNTENT */
153 : #elif defined(HAVE_DEVNM)
154 :
155 : /* we have this on HPUX, ... */
156 : static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
157 : {
158 : int ret = -1;
159 : char dev_disk[256];
160 : SMB_STRUCT_STAT S;
161 :
162 : if (!path||!mntpath||!bdev||!fs)
163 : smb_panic("sys_path_to_bdev: called with NULL pointer");
164 :
165 : (*mntpath) = NULL;
166 : (*bdev) = NULL;
167 : (*fs) = NULL;
168 :
169 : /* find the block device file */
170 :
171 : if ((ret=sys_stat(path, &S, false))!=0) {
172 : return ret;
173 : }
174 :
175 : if ((ret=devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1))!=0) {
176 : return ret;
177 : }
178 :
179 : /* we should get the mntpath right...
180 : * but I don't know how
181 : * --metze
182 : */
183 : (*mntpath) = SMB_STRDUP(path);
184 : (*bdev) = SMB_STRDUP(dev_disk);
185 : if ((*mntpath)&&(*bdev)) {
186 : ret = 0;
187 : } else {
188 : SAFE_FREE(*mntpath);
189 : SAFE_FREE(*bdev);
190 : ret = -1;
191 : }
192 :
193 :
194 : return ret;
195 : }
196 :
197 : /* #endif HAVE_DEVNM */
198 : #else
199 : /* we should fake this up...*/
200 : static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
201 : {
202 : int ret = -1;
203 :
204 : if (!path||!mntpath||!bdev||!fs)
205 : smb_panic("sys_path_to_bdev: called with NULL pointer");
206 :
207 : (*mntpath) = NULL;
208 : (*bdev) = NULL;
209 : (*fs) = NULL;
210 :
211 : (*mntpath) = SMB_STRDUP(path);
212 : if (*mntpath) {
213 : ret = 0;
214 : } else {
215 : SAFE_FREE(*mntpath);
216 : ret = -1;
217 : }
218 :
219 : return ret;
220 : }
221 : #endif
222 :
223 : /*********************************************************************
224 : Now the list of all filesystem specific quota systems we have found
225 : **********************************************************************/
226 : static struct {
227 : const char *name;
228 : int (*get_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
229 : int (*set_quota)(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
230 : } sys_quota_backends[] = {
231 : #ifdef HAVE_JFS_QUOTA_H
232 : {"jfs2", sys_get_jfs2_quota, sys_set_jfs2_quota},
233 : #endif
234 : #if defined HAVE_XFS_QUOTAS
235 : {"xfs", sys_get_xfs_quota, sys_set_xfs_quota},
236 : {"gfs", sys_get_xfs_quota, sys_set_xfs_quota},
237 : {"gfs2", sys_get_xfs_quota, sys_set_xfs_quota},
238 : #endif /* HAVE_XFS_QUOTAS */
239 : #ifdef HAVE_NFS_QUOTAS
240 : {"nfs", sys_get_nfs_quota, sys_set_nfs_quota},
241 : {"nfs4", sys_get_nfs_quota, sys_set_nfs_quota},
242 : #endif /* HAVE_NFS_QUOTAS */
243 : {NULL, NULL, NULL}
244 : };
245 :
246 3254 : static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
247 : {
248 0 : const struct loadparm_substitution *lp_sub =
249 3254 : loadparm_s3_global_substitution();
250 0 : const char *get_quota_command;
251 3254 : char **lines = NULL;
252 :
253 3254 : get_quota_command = lp_get_quota_command(talloc_tos(), lp_sub);
254 3254 : if (get_quota_command && *get_quota_command) {
255 0 : const char *p;
256 0 : char *p2;
257 916 : int _id = -1;
258 916 : int error = 0;
259 916 : char **argl = NULL;
260 :
261 916 : switch(qtype) {
262 498 : case SMB_USER_QUOTA_TYPE:
263 : case SMB_USER_FS_QUOTA_TYPE:
264 498 : _id = id.uid;
265 498 : break;
266 418 : case SMB_GROUP_QUOTA_TYPE:
267 : case SMB_GROUP_FS_QUOTA_TYPE:
268 418 : _id = id.gid;
269 418 : break;
270 0 : default:
271 0 : DEBUG(0,("invalid quota type.\n"));
272 916 : return -1;
273 : }
274 :
275 916 : argl = str_list_make_empty(talloc_tos());
276 916 : str_list_add_printf(&argl, "%s", get_quota_command);
277 916 : str_list_add_printf(&argl, "%s", path);
278 916 : str_list_add_printf(&argl, "%d", qtype);
279 916 : str_list_add_printf(&argl, "%d", _id);
280 916 : if (argl == NULL) {
281 0 : return -1;
282 : }
283 :
284 916 : DBG_NOTICE("Running command %s %s %d %d\n",
285 : get_quota_command,
286 : path,
287 : qtype,
288 : _id);
289 :
290 916 : lines = file_lines_ploadv(talloc_tos(), argl, NULL);
291 916 : TALLOC_FREE(argl);
292 :
293 916 : if (lines) {
294 916 : char *line = lines[0];
295 :
296 916 : DEBUG (3, ("Read output from get_quota, \"%s\"\n", line));
297 :
298 : /* we need to deal with long long unsigned here, if supported */
299 :
300 916 : dp->qflags = smb_strtoul(line,
301 : &p2,
302 : 10,
303 : &error,
304 : SMB_STR_STANDARD);
305 916 : if (error != 0) {
306 0 : goto invalid_param;
307 : }
308 :
309 916 : p = p2;
310 1410 : while (p && *p && isspace(*p)) {
311 494 : p++;
312 : }
313 :
314 916 : if (p && *p) {
315 916 : dp->curblocks = STR_TO_SMB_BIG_UINT(p, &p);
316 : } else {
317 0 : goto invalid_param;
318 : }
319 :
320 1410 : while (p && *p && isspace(*p)) {
321 494 : p++;
322 : }
323 :
324 916 : if (p && *p) {
325 916 : dp->softlimit = STR_TO_SMB_BIG_UINT(p, &p);
326 : } else {
327 0 : goto invalid_param;
328 : }
329 :
330 1410 : while (p && *p && isspace(*p)) {
331 494 : p++;
332 : }
333 :
334 916 : if (p && *p) {
335 916 : dp->hardlimit = STR_TO_SMB_BIG_UINT(p, &p);
336 : } else {
337 0 : goto invalid_param;
338 : }
339 :
340 1410 : while (p && *p && isspace(*p)) {
341 494 : p++;
342 : }
343 :
344 916 : if (p && *p) {
345 916 : dp->curinodes = STR_TO_SMB_BIG_UINT(p, &p);
346 : } else {
347 0 : goto invalid_param;
348 : }
349 :
350 1410 : while (p && *p && isspace(*p)) {
351 494 : p++;
352 : }
353 :
354 916 : if (p && *p) {
355 916 : dp->isoftlimit = STR_TO_SMB_BIG_UINT(p, &p);
356 : } else {
357 0 : goto invalid_param;
358 : }
359 :
360 1410 : while (p && *p && isspace(*p)) {
361 494 : p++;
362 : }
363 :
364 916 : if (p && *p) {
365 916 : dp->ihardlimit = STR_TO_SMB_BIG_UINT(p, &p);
366 : } else {
367 0 : goto invalid_param;
368 : }
369 :
370 916 : while (p && *p && isspace(*p)) {
371 0 : p++;
372 : }
373 :
374 916 : if (p && *p) {
375 422 : dp->bsize = STR_TO_SMB_BIG_UINT(p, NULL);
376 : } else {
377 494 : dp->bsize = 1024;
378 : }
379 :
380 916 : TALLOC_FREE(lines);
381 916 : lines = NULL;
382 :
383 916 : DEBUG (3, ("Parsed output of get_quota, ...\n"));
384 :
385 916 : DEBUGADD (5,(
386 : "qflags:%"PRIu32" curblocks:%"PRIu64" softlimit:%"PRIu64" hardlimit:%"PRIu64"\n"
387 : "curinodes:%"PRIu64" isoftlimit:%"PRIu64" ihardlimit:%"PRIu64" bsize:%"PRIu64"\n",
388 : dp->qflags,dp->curblocks,
389 : dp->softlimit,dp->hardlimit,
390 : dp->curinodes,
391 : dp->isoftlimit,dp->ihardlimit,
392 : dp->bsize));
393 916 : return 0;
394 : }
395 :
396 0 : DEBUG (0, ("get_quota_command failed!\n"));
397 0 : return -1;
398 : }
399 :
400 2338 : errno = ENOSYS;
401 2338 : return -1;
402 :
403 0 : invalid_param:
404 :
405 0 : TALLOC_FREE(lines);
406 0 : DEBUG(0,("The output of get_quota_command is invalid!\n"));
407 0 : return -1;
408 : }
409 :
410 4 : static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
411 : {
412 0 : const struct loadparm_substitution *lp_sub =
413 4 : loadparm_s3_global_substitution();
414 0 : const char *set_quota_command;
415 :
416 4 : set_quota_command = lp_set_quota_command(talloc_tos(), lp_sub);
417 4 : if (set_quota_command && *set_quota_command) {
418 4 : char **lines = NULL;
419 4 : int _id = -1;
420 4 : char **argl = NULL;
421 :
422 4 : switch(qtype) {
423 4 : case SMB_USER_QUOTA_TYPE:
424 : case SMB_USER_FS_QUOTA_TYPE:
425 4 : _id = id.uid;
426 4 : break;
427 0 : case SMB_GROUP_QUOTA_TYPE:
428 : case SMB_GROUP_FS_QUOTA_TYPE:
429 0 : _id = id.gid;
430 0 : break;
431 0 : default:
432 0 : return -1;
433 : }
434 :
435 4 : argl = str_list_make_empty(talloc_tos());
436 4 : str_list_add_printf(&argl, "%s", set_quota_command);
437 4 : str_list_add_printf(&argl, "%s", path);
438 4 : str_list_add_printf(&argl, "%d", qtype);
439 4 : str_list_add_printf(&argl, "%d", _id);
440 4 : str_list_add_printf(&argl, "%u", dp->qflags);
441 4 : str_list_add_printf(
442 : &argl, "%"PRIu64, dp->softlimit);
443 4 : str_list_add_printf(
444 : &argl, "%"PRIu64, dp->hardlimit);
445 4 : str_list_add_printf(
446 : &argl, "%"PRIu64, dp->isoftlimit);
447 4 : str_list_add_printf(
448 : &argl, "%"PRIu64, dp->ihardlimit);
449 4 : str_list_add_printf(
450 : &argl, "%"PRIu64, dp->bsize);
451 4 : if (argl == NULL) {
452 0 : return -1;
453 : }
454 :
455 4 : DBG_NOTICE("Running command "
456 : "%s %s %d %d "
457 : "%"PRIu32" %"PRIu64" %"PRIu64" "
458 : "%"PRIu64" %"PRIu64" %"PRIu64"\n",
459 : set_quota_command,
460 : path,
461 : qtype,
462 : _id,
463 : dp->qflags,
464 : dp->softlimit,
465 : dp->hardlimit,
466 : dp->isoftlimit,
467 : dp->ihardlimit,
468 : dp->bsize);
469 :
470 4 : lines = file_lines_ploadv(talloc_tos(), argl, NULL);
471 4 : TALLOC_FREE(argl);
472 4 : if (lines) {
473 4 : char *line = lines[0];
474 :
475 4 : DEBUG (3, ("Read output from set_quota, \"%s\"\n", line));
476 :
477 4 : TALLOC_FREE(lines);
478 :
479 4 : return 0;
480 : }
481 0 : DEBUG (0, ("set_quota_command failed!\n"));
482 0 : return -1;
483 : }
484 :
485 0 : errno = ENOSYS;
486 0 : return -1;
487 : }
488 :
489 3254 : int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
490 : {
491 3254 : int ret = -1;
492 0 : int i;
493 3254 : bool ready = False;
494 3254 : char *mntpath = NULL;
495 3254 : char *bdev = NULL;
496 3254 : char *fs = NULL;
497 :
498 3254 : if (!path||!dp)
499 0 : smb_panic("sys_get_quota: called with NULL pointer");
500 :
501 3254 : if (command_get_quota(path, qtype, id, dp)==0) {
502 916 : return 0;
503 2338 : } else if (errno != ENOSYS) {
504 0 : return -1;
505 : }
506 :
507 2338 : if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
508 0 : DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
509 0 : return ret;
510 : }
511 :
512 2338 : errno = 0;
513 2338 : DEBUG(10,("sys_get_quota() uid(%u, %u), fs(%s)\n", (unsigned)getuid(), (unsigned)geteuid(), fs));
514 :
515 14028 : for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].get_quota);i++) {
516 11690 : if (strcmp(fs,sys_quota_backends[i].name)==0) {
517 0 : ret = sys_quota_backends[i].get_quota(mntpath, bdev, qtype, id, dp);
518 0 : if (ret!=0) {
519 0 : DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
520 : fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
521 : } else {
522 0 : DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
523 : fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
524 : }
525 0 : ready = True;
526 0 : break;
527 : }
528 : }
529 :
530 2338 : if (!ready) {
531 : /* use the default vfs quota functions */
532 2338 : ret=sys_get_vfs_quota(mntpath, bdev, qtype, id, dp);
533 2338 : if (ret!=0) {
534 0 : DEBUG(3,("sys_get_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s\n",
535 : "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
536 : } else {
537 2338 : DEBUG(10,("sys_get_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
538 : "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
539 : }
540 : }
541 :
542 2338 : SAFE_FREE(mntpath);
543 2338 : SAFE_FREE(bdev);
544 2338 : SAFE_FREE(fs);
545 :
546 2338 : return ret;
547 : }
548 :
549 4 : int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
550 : {
551 4 : int ret = -1;
552 0 : int i;
553 4 : bool ready = False;
554 4 : char *mntpath = NULL;
555 4 : char *bdev = NULL;
556 4 : char *fs = NULL;
557 :
558 : /* find the block device file */
559 :
560 4 : if (!path||!dp)
561 0 : smb_panic("get_smb_quota: called with NULL pointer");
562 :
563 4 : if (command_set_quota(path, qtype, id, dp)==0) {
564 4 : return 0;
565 0 : } else if (errno != ENOSYS) {
566 0 : return -1;
567 : }
568 :
569 0 : if ((ret=sys_path_to_bdev(path,&mntpath,&bdev,&fs))!=0) {
570 0 : DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
571 0 : return ret;
572 : }
573 :
574 0 : errno = 0;
575 0 : DEBUG(10,("sys_set_quota() uid(%u, %u)\n", (unsigned)getuid(), (unsigned)geteuid()));
576 :
577 0 : for (i=0;(fs && sys_quota_backends[i].name && sys_quota_backends[i].set_quota);i++) {
578 0 : if (strcmp(fs,sys_quota_backends[i].name)==0) {
579 0 : ret = sys_quota_backends[i].set_quota(mntpath, bdev, qtype, id, dp);
580 0 : if (ret!=0) {
581 0 : DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
582 : fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
583 : } else {
584 0 : DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
585 : fs,mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
586 : }
587 0 : ready = True;
588 0 : break;
589 : }
590 : }
591 :
592 0 : if (!ready) {
593 : /* use the default vfs quota functions */
594 0 : ret=sys_set_vfs_quota(mntpath, bdev, qtype, id, dp);
595 0 : if (ret!=0) {
596 0 : DEBUG(3,("sys_set_%s_quota() failed for mntpath[%s] bdev[%s] qtype[%d] id[%d]: %s.\n",
597 : "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid),strerror(errno)));
598 : } else {
599 0 : DEBUG(10,("sys_set_%s_quota() called for mntpath[%s] bdev[%s] qtype[%d] id[%d].\n",
600 : "vfs",mntpath,bdev,qtype,(qtype==SMB_GROUP_QUOTA_TYPE?id.gid:id.uid)));
601 : }
602 : }
603 :
604 0 : SAFE_FREE(mntpath);
605 0 : SAFE_FREE(bdev);
606 0 : SAFE_FREE(fs);
607 :
608 0 : return ret;
609 : }
610 :
611 : #else /* HAVE_SYS_QUOTAS */
612 : void dummy_sysquotas_c(void);
613 :
614 : void dummy_sysquotas_c(void)
615 : {
616 : return;
617 : }
618 : #endif /* HAVE_SYS_QUOTAS */
619 :
|