$NetBSD: patch-etc_afpd_quota_c,v 1.1 2014/06/11 11:03:56 hauke Exp $ Use the netbsd-6 quota API, not the prerelease stuff from 5.99.x. Fix some glaring bugs in the code for the 5.99.x quotas (seteuid'ing to group ids, using uninitialized group quota values, etc.) --- etc/afpd/quota.c.orig 2011-08-18 12:23:44.000000000 +0000 +++ etc/afpd/quota.c @@ -48,14 +48,18 @@ char *strchr (), *strrchr (); #include "unix.h" #ifdef HAVE_LIBQUOTA -#include +#include + static int getfreespace(struct vol *vol, VolSpace *bfree, VolSpace *btotal, - uid_t uid, const char *classq) + id_t id, int idtype) { - int retq; - struct ufs_quota_entry ufsq[QUOTA_NLIMITS]; + uid_t prevuid; + const char *msg; + struct quotahandle *qh; + struct quotakey qk; + struct quotaval qv; time_t now; if (time(&now) == -1) { @@ -64,65 +68,107 @@ getfreespace(struct vol *vol, VolSpace * return -1; } + prevuid = geteuid(); + if (prevuid == -1) { + LOG(log_info, logtype_afpd, "geteuid(): %s", + strerror(errno)); + return -1; + } + if ( seteuid( getuid() ) != 0 ) { LOG(log_info, logtype_afpd, "seteuid(): %s", strerror(errno)); return -1; } - if ((retq = getfsquota(vol->v_path, ufsq, uid, classq)) < 0) { - LOG(log_info, logtype_afpd, "getfsquota(%s, %s): %s", - vol->v_path, classq, strerror(errno)); + + /* + * In a tidier world we might keep the quotahandle open for longer... + */ + qh = quota_open(vol->v_path); + if (qh == NULL) { + if (errno == EOPNOTSUPP || errno == ENXIO) { + /* no quotas on this volume */ + seteuid( prevuid ); + return 0; + } + + LOG(log_info, logtype_afpd, "quota_open(%s): %s", vol->v_path, + strerror(errno)); + seteuid( prevuid ); + return -1; } - seteuid( uid ); - if (retq < 1) - return retq; - switch(QL_STATUS(quota_check_limit(ufsq[QUOTA_LIMIT_BLOCK].ufsqe_cur, 1, - ufsq[QUOTA_LIMIT_BLOCK].ufsqe_softlimit, - ufsq[QUOTA_LIMIT_BLOCK].ufsqe_hardlimit, - ufsq[QUOTA_LIMIT_BLOCK].ufsqe_time, now))) { - case QL_S_DENY_HARD: - case QL_S_DENY_GRACE: + qk.qk_idtype = idtype; + qk.qk_id = id; + qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; + if (quota_get(qh, &qk, &qv) < 0) { + if (errno == ENOENT) { + /* no quotas for this id */ + quota_close(qh); + seteuid( prevuid ); + return 0; + } + msg = strerror(errno); + LOG(log_info, logtype_afpd, "quota_get(%s, %s): %s", + vol->v_path, quota_idtype_getname(qh, idtype), msg); + quota_close(qh); + seteuid( prevuid ); + return -1; + } + + quota_close(qh); + + seteuid( prevuid ); + + if (qv.qv_usage >= qv.qv_hardlimit || + (qv.qv_usage >= qv.qv_softlimit && now > qv.qv_expiretime)) { *bfree = 0; - *btotal = dbtob(ufsq[QUOTA_LIMIT_BLOCK].ufsqe_cur); - break; - default: - *bfree = dbtob(ufsq[QUOTA_LIMIT_BLOCK].ufsqe_hardlimit - - ufsq[QUOTA_LIMIT_BLOCK].ufsqe_cur); - *btotal = dbtob(ufsq[QUOTA_LIMIT_BLOCK].ufsqe_hardlimit); - break; + *btotal = dbtob(qv.qv_usage); + } + else { + *bfree = dbtob(qv.qv_hardlimit - qv.qv_usage); + *btotal = dbtob(qv.qv_hardlimit); } + return 1; } int uquota_getvolspace( struct vol *vol, VolSpace *bfree, VolSpace *btotal, const u_int32_t bsize) { - int uretq, gretq; + int uret, gret; VolSpace ubfree, ubtotal; VolSpace gbfree, gbtotal; - uretq = getfreespace(vol, &ubfree, &ubtotal, - uuid, QUOTADICT_CLASS_USER); - LOG(log_info, logtype_afpd, "getfsquota(%s): %d %d", - vol->v_path, (int)ubfree, (int)ubtotal); + uret = getfreespace(vol, &ubfree, &ubtotal, + uuid, QUOTA_IDTYPE_USER); + if (uret == 1) { + LOG(log_info, logtype_afpd, "quota_get(%s, user): %d %d", + vol->v_path, (int)ubfree, (int)ubtotal); + } + if (ngroups >= 1) { - gretq = getfreespace(vol, &ubfree, &ubtotal, - groups[0], QUOTADICT_CLASS_GROUP); + gret = getfreespace(vol, &gbfree, &gbtotal, + groups[0], QUOTA_IDTYPE_GROUP); + if (gret == 1) { + LOG(log_info, logtype_afpd, "quota_get(%s, group): %d %d", + vol->v_path, (int)gbfree, (int)gbtotal); + } } else - gretq = -1; - if (uretq < 1 && gretq < 1) { /* no quota for this fs */ + gret = 0; + + if (uret < 1 && gret < 1) { /* no quota for this fs */ return AFPERR_PARAM; } - if (uretq < 1) { - /* use group quotas */ + if (uret < 1) { + /* no user quotas, but group quotas; use them */ *bfree = gbfree; *btotal = gbtotal; - } else if (gretq < 1) { - /* use user quotas */ + } else if (gret < 1) { + /* no group quotas, but user quotas; use them */ *bfree = ubfree; *btotal = ubtotal; } else { - /* return smallest remaining space of user and group */ + /* both; return smallest remaining space of user and group */ if (ubfree < gbfree) { *bfree = ubfree; *btotal = ubtotal;