3 * UNFS3 user and group id handling
4 * (C) 2003, Pascal Schmidt
5 * see file LICENSE for license details
16 #include <sys/types.h>
26 #include "Config/exports.h"
28 /* user and group id we squash to */
29 static uid_t squash_uid = 65534;
30 static gid_t squash_gid = 65534;
32 /* whether we can use seteuid/setegid */
33 static int can_switch = TRUE;
36 * initialize group and user id used for squashing
38 void get_squash_ids(void)
40 backend_passwdstruct *passwd;
43 passwd = backend_getpwnam("nobody");
45 squash_uid = passwd->pw_uid;
46 squash_gid = passwd->pw_gid;
57 static int mangle(int id, int squash)
59 if (!can_switch || (exports_opts & OPT_ALL_SQUASH))
61 else if (exports_opts & OPT_NO_ROOT_SQUASH)
70 * Mangle a given user id according to current settings
72 int mangle_uid(int id)
74 int squash = squash_uid;
76 if (exports_anonuid() != ANON_NOTSPECIAL)
77 squash = exports_anonuid();
79 return mangle(id, squash);
83 * Mangle a given group id according to current settings
85 int mangle_gid(int id)
87 int squash = squash_gid;
89 if (exports_anongid() != ANON_NOTSPECIAL)
90 squash = exports_anongid();
92 return mangle(id, squash);
96 * return user id of a request
98 int get_uid(struct svc_req *req)
100 struct authunix_parms *auth = (void *) req->rq_clntcred;
101 int squash = squash_uid;
103 if (exports_anonuid() != ANON_NOTSPECIAL)
104 squash = exports_anonuid();
106 if (req->rq_cred.oa_flavor == AUTH_UNIX)
107 return mangle(auth->aup_uid, squash);
109 return squash; /* fallback if no uid given */
113 * return group id of a request
115 static int get_gid(struct svc_req *req)
117 struct authunix_parms *auth = (void *) req->rq_clntcred;
118 int squash = squash_gid;
120 if (exports_anongid() != ANON_NOTSPECIAL)
121 squash = exports_anongid();
123 if (req->rq_cred.oa_flavor == AUTH_UNIX)
124 return mangle(auth->aup_gid, squash);
126 return squash; /* fallback if no gid given */
130 * check whether a request comes from a given user id
132 int is_owner(int owner, struct svc_req *req)
134 return (int) (owner == get_uid(req));
138 * check if a request comes from somebody who has a given group id
140 int has_group(int group, struct svc_req *req)
142 struct authunix_parms *auth = (void *) req->rq_clntcred;
145 if (req->rq_cred.oa_flavor == AUTH_UNIX) {
146 if (mangle(auth->aup_gid, squash_gid) == group)
150 for (i = 0; i < auth->aup_len; i++)
151 if (mangle(auth->aup_gids[i], squash_gid) == group)
161 void switch_to_root()
171 * switch auxiliary group ids
173 static int switch_groups(struct svc_req *req)
175 struct authunix_parms *auth = (void *) req->rq_clntcred;
178 max = (auth->aup_len <= 32) ? auth->aup_len : 32;
180 for (i = 0; i < max; ++i) {
181 auth->aup_gids[i] = mangle(auth->aup_gids[i], squash_gid);
184 return backend_setgroups(max, auth->aup_gids);
188 * switch user and group id to values listed in request
190 void switch_user(struct svc_req *req)
197 if (opt_singleuser || (backend_getuid() != 0)) {
199 * have uid/gid functions behave correctly by squashing
200 * all user and group ids to the current values
202 * otherwise ACCESS would malfunction
204 squash_uid = backend_getuid();
205 squash_gid = backend_getgid();
213 gid = backend_setegid(get_gid(req));
214 aid = switch_groups(req);
215 uid = backend_seteuid(get_uid(req));
217 if (uid == -1 || gid == -1 || aid == -1) {
218 logmsg(LOG_EMERG, "euid/egid switching failed, aborting");
224 * re-switch to root for reading executable files
226 void read_executable(struct svc_req *req, backend_statstruct buf)
230 if (is_owner(buf.st_uid, req)) {
231 if (!(buf.st_mode & S_IRUSR) && (buf.st_mode & S_IXUSR))
233 } else if (has_group(buf.st_gid, req)) {
234 if (!(buf.st_mode & S_IRGRP) && (buf.st_mode & S_IXGRP))
237 if (!(buf.st_mode & S_IROTH) && (buf.st_mode & S_IXOTH))
248 * re-switch to root for reading owned file
250 void read_by_owner(struct svc_req *req, backend_statstruct buf)
255 have_owner = is_owner(buf.st_uid, req);
257 if (have_owner && (buf.st_mode & S_IRUSR)) {
259 } else if (has_group(buf.st_gid, req) && (buf.st_mode & S_IRGRP)) {
261 } else if (buf.st_mode & S_IROTH) {
265 if (have_owner && !have_read) {
272 * re-switch to root for writing owned file
274 void write_by_owner(struct svc_req *req, backend_statstruct buf)
279 have_owner = is_owner(buf.st_uid, req);
281 if (have_owner && (buf.st_mode & S_IWUSR)) {
283 } else if (has_group(buf.st_gid, req) && (buf.st_mode & S_IWGRP)) {
285 } else if (buf.st_mode & S_IWOTH) {
289 if (have_owner && !have_write) {