1 /* $NetBSD: rquotad.c,v 1.30 2011/09/16 16:13:17 plunky Exp $ */ 2 3 /* 4 * by Manuel Bouyer (bouyer@ensta.fr). Public domain. 5 */ 6 7 #include <sys/cdefs.h> 8 #ifndef lint 9 __RCSID("$NetBSD: rquotad.c,v 1.30 2011/09/16 16:13:17 plunky Exp $"); 10 #endif 11 12 #include <sys/param.h> 13 #include <sys/types.h> 14 #include <sys/mount.h> 15 #include <sys/file.h> 16 #include <sys/stat.h> 17 #include <sys/socket.h> 18 #include <signal.h> 19 20 #include <stdio.h> 21 #include <fstab.h> 22 #include <ctype.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <pwd.h> 26 #include <grp.h> 27 #include <errno.h> 28 #include <unistd.h> 29 30 #include <syslog.h> 31 32 #include <quota/quotaprop.h> 33 #include <quota/quota.h> 34 #include <rpc/rpc.h> 35 #include <rpcsvc/rquota.h> 36 #include <arpa/inet.h> 37 38 static void rquota_service(struct svc_req *request, SVCXPRT *transp); 39 static void ext_rquota_service(struct svc_req *request, SVCXPRT *transp); 40 static void sendquota(struct svc_req *request, int vers, SVCXPRT *transp); 41 __dead static void cleanup(int); 42 43 static int from_inetd = 1; 44 45 static uint32_t 46 qlim2rqlim(uint64_t lim) 47 { 48 if (lim == UQUAD_MAX) 49 return 0; 50 else 51 return (lim + 1); 52 } 53 54 static void 55 cleanup(int dummy) 56 { 57 58 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL); 59 (void)rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL); 60 exit(0); 61 } 62 63 int 64 main(int argc, char *argv[]) 65 { 66 SVCXPRT *transp; 67 struct sockaddr_storage from; 68 socklen_t fromlen; 69 70 fromlen = sizeof(from); 71 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) 72 from_inetd = 0; 73 74 if (!from_inetd) { 75 daemon(0, 0); 76 77 (void) rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL); 78 (void) rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL); 79 (void) signal(SIGINT, cleanup); 80 (void) signal(SIGTERM, cleanup); 81 (void) signal(SIGHUP, cleanup); 82 } 83 84 openlog("rpc.rquotad", LOG_PID, LOG_DAEMON); 85 86 /* create and register the service */ 87 if (from_inetd) { 88 transp = svc_dg_create(0, 0, 0); 89 if (transp == NULL) { 90 syslog(LOG_ERR, "couldn't create udp service."); 91 exit(1); 92 } 93 if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, rquota_service, 94 NULL)) { 95 syslog(LOG_ERR, 96 "unable to register (RQUOTAPROG, RQUOTAVERS)."); 97 exit(1); 98 } 99 if (!svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS, 100 ext_rquota_service, NULL)) { 101 syslog(LOG_ERR, 102 "unable to register (RQUOTAPROG, EXT_RQUOTAVERS)."); 103 exit(1); 104 } 105 } else { 106 if (!svc_create(rquota_service, RQUOTAPROG, RQUOTAVERS, "udp")){ 107 syslog(LOG_ERR, 108 "unable to create (RQUOTAPROG, RQUOTAVERS)."); 109 exit(1); 110 } 111 if (!svc_create(ext_rquota_service, RQUOTAPROG, 112 EXT_RQUOTAVERS, "udp")){ 113 syslog(LOG_ERR, 114 "unable to create (RQUOTAPROG, EXT_RQUOTAVERS)."); 115 exit(1); 116 } 117 } 118 119 svc_run(); 120 syslog(LOG_ERR, "svc_run returned"); 121 exit(1); 122 } 123 124 static void 125 rquota_service(struct svc_req *request, SVCXPRT *transp) 126 { 127 switch (request->rq_proc) { 128 case NULLPROC: 129 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 130 break; 131 132 case RQUOTAPROC_GETQUOTA: 133 case RQUOTAPROC_GETACTIVEQUOTA: 134 sendquota(request, RQUOTAVERS, transp); 135 break; 136 137 default: 138 svcerr_noproc(transp); 139 break; 140 } 141 if (from_inetd) 142 exit(0); 143 } 144 145 static void 146 ext_rquota_service(struct svc_req *request, SVCXPRT *transp) 147 { 148 switch (request->rq_proc) { 149 case NULLPROC: 150 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 151 break; 152 153 case RQUOTAPROC_GETQUOTA: 154 case RQUOTAPROC_GETACTIVEQUOTA: 155 sendquota(request, EXT_RQUOTAVERS, transp); 156 break; 157 158 default: 159 svcerr_noproc(transp); 160 break; 161 } 162 if (from_inetd) 163 exit(0); 164 } 165 166 /* read quota for the specified id, and send it */ 167 static void 168 sendquota(struct svc_req *request, int vers, SVCXPRT *transp) 169 { 170 struct getquota_args getq_args; 171 struct ext_getquota_args ext_getq_args; 172 struct getquota_rslt getq_rslt; 173 struct ufs_quota_entry qe[QUOTA_NLIMITS]; 174 const char *class; 175 struct timeval timev; 176 177 memset((char *)&getq_args, 0, sizeof(getq_args)); 178 memset((char *)&ext_getq_args, 0, sizeof(ext_getq_args)); 179 switch (vers) { 180 case RQUOTAVERS: 181 if (!svc_getargs(transp, xdr_getquota_args, 182 (caddr_t)&getq_args)) { 183 svcerr_decode(transp); 184 return; 185 } 186 ext_getq_args.gqa_pathp = getq_args.gqa_pathp; 187 ext_getq_args.gqa_id = getq_args.gqa_uid; 188 ext_getq_args.gqa_type = RQUOTA_USRQUOTA; 189 break; 190 case EXT_RQUOTAVERS: 191 if (!svc_getargs(transp, xdr_ext_getquota_args, 192 (caddr_t)&ext_getq_args)) { 193 svcerr_decode(transp); 194 return; 195 } 196 break; 197 } 198 switch (ext_getq_args.gqa_type) { 199 case RQUOTA_USRQUOTA: 200 class = QUOTADICT_CLASS_USER; 201 break; 202 case RQUOTA_GRPQUOTA: 203 class = QUOTADICT_CLASS_GROUP; 204 break; 205 default: 206 getq_rslt.status = Q_NOQUOTA; 207 goto out; 208 } 209 if (request->rq_cred.oa_flavor != AUTH_UNIX) { 210 /* bad auth */ 211 getq_rslt.status = Q_EPERM; 212 } else if (!getufsquota(ext_getq_args.gqa_pathp, qe, 213 ext_getq_args.gqa_id, class)) { 214 /* failed, return noquota */ 215 getq_rslt.status = Q_NOQUOTA; 216 } else { 217 gettimeofday(&timev, NULL); 218 getq_rslt.status = Q_OK; 219 getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE; 220 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE; 221 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit = 222 qlim2rqlim(qe[QUOTA_LIMIT_BLOCK].ufsqe_hardlimit); 223 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit = 224 qlim2rqlim(qe[QUOTA_LIMIT_BLOCK].ufsqe_softlimit); 225 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks = 226 qe[QUOTA_LIMIT_BLOCK].ufsqe_cur; 227 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit = 228 qlim2rqlim(qe[QUOTA_LIMIT_FILE].ufsqe_hardlimit); 229 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit = 230 qlim2rqlim(qe[QUOTA_LIMIT_FILE].ufsqe_softlimit); 231 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles = 232 qe[QUOTA_LIMIT_FILE].ufsqe_cur; 233 getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft = 234 qe[QUOTA_LIMIT_BLOCK].ufsqe_time - timev.tv_sec; 235 getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft = 236 qe[QUOTA_LIMIT_FILE].ufsqe_time - timev.tv_sec; 237 } 238 out: 239 if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, (char *)&getq_rslt)) 240 svcerr_systemerr(transp); 241 if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) { 242 syslog(LOG_ERR, "unable to free arguments"); 243 exit(1); 244 } 245 } 246