Added initial unfs3 sources for version 0.9.22+dfsg-1maemo2
[unfs3] / unfs3 / user.c
1
2 /*
3  * UNFS3 user and group id handling
4  * (C) 2003, Pascal Schmidt
5  * see file LICENSE for license details
6  */
7
8 #include "config.h"
9
10 #ifndef WIN32
11 #include <pwd.h>
12 #include <grp.h>
13 #include <syslog.h>
14 #include <unistd.h>
15 #endif                                 /* WIN32 */
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <rpc/rpc.h>
19 #include <stdlib.h>
20
21 #include "nfs.h"
22 #include "mount.h"
23 #include "daemon.h"
24 #include "user.h"
25 #include "backend.h"
26 #include "Config/exports.h"
27
28 /* user and group id we squash to */
29 static uid_t squash_uid = 65534;
30 static gid_t squash_gid = 65534;
31
32 /* whether we can use seteuid/setegid */
33 static int can_switch = TRUE;
34
35 /*
36  * initialize group and user id used for squashing
37  */
38 void get_squash_ids(void)
39 {
40     backend_passwdstruct *passwd;
41
42     if (can_switch) {
43         passwd = backend_getpwnam("nobody");
44         if (passwd) {
45             squash_uid = passwd->pw_uid;
46             squash_gid = passwd->pw_gid;
47         } else {
48             squash_uid = 65534;
49             squash_gid = 65534;
50         }
51     }
52 }
53
54 /*
55  * mangle an id
56  */
57 static int mangle(int id, int squash)
58 {
59     if (!can_switch || (exports_opts & OPT_ALL_SQUASH))
60         return squash;
61     else if (exports_opts & OPT_NO_ROOT_SQUASH)
62         return id;
63     else if (id == 0)
64         return squash;
65     else
66         return id;
67 }
68
69 /*
70  * Mangle a given user id according to current settings
71  */
72 int mangle_uid(int id)
73 {
74     int squash = squash_uid;
75
76     if (exports_anonuid() != ANON_NOTSPECIAL)
77         squash = exports_anonuid();
78
79     return mangle(id, squash);
80 }
81
82 /*
83  * Mangle a given group id according to current settings
84  */
85 int mangle_gid(int id)
86 {
87     int squash = squash_gid;
88
89     if (exports_anongid() != ANON_NOTSPECIAL)
90         squash = exports_anongid();
91
92     return mangle(id, squash);
93 }
94
95 /*
96  * return user id of a request
97  */
98 int get_uid(struct svc_req *req)
99 {
100     struct authunix_parms *auth = (void *) req->rq_clntcred;
101     int squash = squash_uid;
102
103     if (exports_anonuid() != ANON_NOTSPECIAL)
104         squash = exports_anonuid();
105
106     if (req->rq_cred.oa_flavor == AUTH_UNIX)
107         return mangle(auth->aup_uid, squash);
108     else
109         return squash;                 /* fallback if no uid given */
110 }
111
112 /*
113  * return group id of a request
114  */
115 static int get_gid(struct svc_req *req)
116 {
117     struct authunix_parms *auth = (void *) req->rq_clntcred;
118     int squash = squash_gid;
119
120     if (exports_anongid() != ANON_NOTSPECIAL)
121         squash = exports_anongid();
122
123     if (req->rq_cred.oa_flavor == AUTH_UNIX)
124         return mangle(auth->aup_gid, squash);
125     else
126         return squash;                 /* fallback if no gid given */
127 }
128
129 /*
130  * check whether a request comes from a given user id
131  */
132 int is_owner(int owner, struct svc_req *req)
133 {
134     return (int) (owner == get_uid(req));
135 }
136
137 /*
138  * check if a request comes from somebody who has a given group id
139  */
140 int has_group(int group, struct svc_req *req)
141 {
142     struct authunix_parms *auth = (void *) req->rq_clntcred;
143     unsigned int i;
144
145     if (req->rq_cred.oa_flavor == AUTH_UNIX) {
146         if (mangle(auth->aup_gid, squash_gid) == group)
147             return TRUE;
148
149         /* search groups */
150         for (i = 0; i < auth->aup_len; i++)
151             if (mangle(auth->aup_gids[i], squash_gid) == group)
152                 return TRUE;
153     }
154
155     return FALSE;
156 }
157
158 /*
159  * switch to root
160  */
161 void switch_to_root()
162 {
163     if (!can_switch)
164         return;
165
166     backend_setegid(0);
167     backend_seteuid(0);
168 }
169
170 /*
171  * switch auxiliary group ids
172  */
173 static int switch_groups(struct svc_req *req)
174 {
175     struct authunix_parms *auth = (void *) req->rq_clntcred;
176     unsigned int i, max;
177
178     max = (auth->aup_len <= 32) ? auth->aup_len : 32;
179
180     for (i = 0; i < max; ++i) {
181         auth->aup_gids[i] = mangle(auth->aup_gids[i], squash_gid);
182     }
183
184     return backend_setgroups(max, auth->aup_gids);
185 }
186
187 /*
188  * switch user and group id to values listed in request
189  */
190 void switch_user(struct svc_req *req)
191 {
192     int uid, gid, aid;
193
194     if (!can_switch)
195         return;
196
197     if (opt_singleuser || (backend_getuid() != 0)) {
198         /* 
199          * have uid/gid functions behave correctly by squashing
200          * all user and group ids to the current values
201          *
202          * otherwise ACCESS would malfunction
203          */
204         squash_uid = backend_getuid();
205         squash_gid = backend_getgid();
206
207         can_switch = FALSE;
208         return;
209     }
210
211     backend_setegid(0);
212     backend_seteuid(0);
213     gid = backend_setegid(get_gid(req));
214     aid = switch_groups(req);
215     uid = backend_seteuid(get_uid(req));
216
217     if (uid == -1 || gid == -1 || aid == -1) {
218         logmsg(LOG_EMERG, "euid/egid switching failed, aborting");
219         daemon_exit(CRISIS);
220     }
221 }
222
223 /*
224  * re-switch to root for reading executable files
225  */
226 void read_executable(struct svc_req *req, backend_statstruct buf)
227 {
228     int have_exec = 0;
229
230     if (is_owner(buf.st_uid, req)) {
231         if (!(buf.st_mode & S_IRUSR) && (buf.st_mode & S_IXUSR))
232             have_exec = 1;
233     } else if (has_group(buf.st_gid, req)) {
234         if (!(buf.st_mode & S_IRGRP) && (buf.st_mode & S_IXGRP))
235             have_exec = 1;
236     } else {
237         if (!(buf.st_mode & S_IROTH) && (buf.st_mode & S_IXOTH))
238             have_exec = 1;
239     }
240
241     if (have_exec) {
242         backend_setegid(0);
243         backend_seteuid(0);
244     }
245 }
246
247 /*
248  * re-switch to root for reading owned file
249  */
250 void read_by_owner(struct svc_req *req, backend_statstruct buf)
251 {
252     int have_owner = 0;
253     int have_read = 0;
254
255     have_owner = is_owner(buf.st_uid, req);
256
257     if (have_owner && (buf.st_mode & S_IRUSR)) {
258         have_read = 1;
259     } else if (has_group(buf.st_gid, req) && (buf.st_mode & S_IRGRP)) {
260         have_read = 1;
261     } else if (buf.st_mode & S_IROTH) {
262         have_read = 1;
263     }
264
265     if (have_owner && !have_read) {
266         backend_setegid(0);
267         backend_seteuid(0);
268     }
269 }
270
271 /*
272  * re-switch to root for writing owned file
273  */
274 void write_by_owner(struct svc_req *req, backend_statstruct buf)
275 {
276     int have_owner = 0;
277     int have_write = 0;
278
279     have_owner = is_owner(buf.st_uid, req);
280
281     if (have_owner && (buf.st_mode & S_IWUSR)) {
282         have_write = 1;
283     } else if (has_group(buf.st_gid, req) && (buf.st_mode & S_IWGRP)) {
284         have_write = 1;
285     } else if (buf.st_mode & S_IWOTH) {
286         have_write = 1;
287     }
288
289     if (have_owner && !have_write) {
290         backend_setegid(0);
291         backend_seteuid(0);
292     }
293 }