source: trunk/athena/bin/discuss/server/acl_core.c @ 1939

Revision 1939, 8.9 KB checked in by srz, 36 years ago (diff)
Added standard copyright notice.
Line 
1/*
2 *
3 *      Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
4 *      Developed by the MIT Student Information Processing Board (SIPB).
5 *      For copying information, see the file mit-copyright.h in this release.
6 *
7 */
8/*
9 *      $Source: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/acl_core.c,v $
10 *      $Header: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/acl_core.c,v 1.11 1989-06-03 00:41:41 srz Exp $
11 *
12 *      Routines for use in a server to edit access control lists remotely.
13 *      Originally written for the discuss system by Bill Sommerfeld
14 *
15 *      $Log: not supported by cvs2svn $
16 * Revision 1.10  89/01/04  22:27:42  raeburn
17 * Fixed includes
18 *
19 * Revision 1.9  88/10/08  01:36:18  raeburn
20 * Minor changes: include files, type names.
21 *
22 * Revision 1.8  88/05/31  17:43:49  srz
23 * Bill's changes broke expunge.  Fixed to work if has_privs is set.
24 *
25 * Revision 1.7  87/10/24  07:01:03  wesommer
26 * Rearrange to allow access routines to work on meeting-group acls as
27 * well.
28 *
29 * Revision 1.6  87/04/06  02:18:19  wesommer
30 * Make sure that chair doesn't terminate himself.
31 *
32 * Revision 1.5  87/03/25  15:03:51  srz
33 * toma change:  Can look at own access control list entry without 's' to
34 * the meeting.
35 *
36 * Revision 1.4  87/03/17  02:26:11  srz
37 * Changed set_acl not to return static storage.  Also, let has_privs
38 * bypass access checks (in case of linked in programs)
39 *
40 * Revision 1.3  87/02/04  15:53:41  srz
41 * uid_t lossage
42 *
43 * Revision 1.2  86/11/22  06:19:08  spook
44 * Changed to make lint happy.
45 *
46 * Revision 1.1  86/11/16  06:03:56  wesommer
47 * Initial revision
48 *
49 */
50
51#include <discuss/types.h>
52#include <discuss/dsc_et.h>
53#include <discuss/acl.h>
54#include "internal.h"
55#include <sys/file.h>
56#include <errno.h>
57#include <stdio.h>
58#include <sys/param.h>
59#include <string.h>
60#include "ansi.h"
61
62#ifndef lint
63static const char rcsid_acl_core_c[] =
64    "$Header: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/acl_core.c,v 1.11 1989-06-03 00:41:41 srz Exp $";
65#endif lint
66
67extern dsc_acl *mtg_acl;
68extern char rpc_caller [];
69extern int errno;
70extern int has_privs;
71extern char *new_string();
72
73/*
74 * Routines provided:
75 *      get_acl(obj_name) returns(code, acl)
76 *              Return the access control list for an object (meeting).
77 *      get_access(obj_name, princ_name) returns(code, modes)
78 *              Returns the access allowed for a given principal
79 *      set_access(obj_name, princ_name, modes) returns(code)
80 *              Sets the access on an object for a specific principal.
81 *      delete_access(obj_name, princ_name) returns(code)
82 *              Deletes princ_name from the access control list;
83 */
84
85/*
86 *      Locking protocol:
87 *      It is assumed that the ACL is in a file in a known directory;
88 *      the following locking protocol is used when modifying ACL's
89 *      to ensure consistancy.
90 *      1) flock EXCLUSIVE parent directory.
91 *      2) open acl for read, read ACL.
92 *      3) modify ACL in core.
93 *      4) open #acl for write, write ACL.
94 *      5) rename #acl to acl (this is assumed to be atomic)
95 *      6) unlock parent directory.
96 *
97 *      The directory is locked, rather than the acl, because the file is
98 *      recreated and deleted (for atomicity reasons) on every transaction
99 *      (thank god UNIX files are lightweight). 
100 *
101 *      Since the acl in place is always consistant (and file opens
102 *      are atomic), there is no need to read-lock when getting the ACL.
103 */
104       
105static dsc_acl *read_acl(mtg_name, code_ptr, check)
106        char *mtg_name;
107        int *code_ptr;
108        int check;
109{
110        int fd = -1;
111        dsc_acl *list = NULL;
112        int result = 0;
113        int mtg_name_len = strlen(mtg_name);
114        char acl_name[MAXPATHLEN];
115       
116        if (mtg_name[0] != '/' || mtg_name_len == 0 ||
117            mtg_name_len > MAXPATHLEN || mtg_name [mtg_name_len-1] == '/') {
118                result = BAD_PATH;
119                goto punt;
120        }
121        strcpy(acl_name, mtg_name);
122        strcat(acl_name, "/acl");
123       
124        if((fd = open(acl_name, O_RDONLY, 0700)) < 0) {
125                result = errno;
126                goto punt;
127        }
128
129        errno = 0;
130        if ((list = acl_read(fd)) == (dsc_acl *) NULL) {
131                result = errno?errno:NO_ACCESS;
132                goto punt;
133        }
134       
135        if (check && !acl_check(list, rpc_caller, "s")) {
136                result = NO_ACCESS;
137                goto punt;
138        }
139        close(fd);
140        *code_ptr = result;
141        return (list);
142punt:
143        *code_ptr = result;
144        if (list) acl_destroy(list);
145        close(fd);
146       
147        return NULL;
148}
149
150get_acl(mtg_name, code, list)
151        char *mtg_name;
152        int *code;              /* RETURN */
153        dsc_acl **list;         /* RETURN */
154{
155        *list = read_acl(mtg_name, code, !has_privs);
156        return;
157}
158
159get_access(mtg_name, princ_name, modes, code)
160        char *mtg_name;
161        char *princ_name;
162        char **modes;           /* RETURN */
163        int *code;              /* RETURN */
164{
165        dsc_acl *list;
166        *modes = NULL;
167       
168        *code = 0;
169        list = read_acl(mtg_name, code, !has_privs && (strcmp(princ_name, rpc_caller) != 0));
170        if (*code) return;
171       
172        *modes = new_string(acl_get_access(list, princ_name));
173        acl_destroy(list);
174        return;
175}
176
177/*
178 * Set access.
179 */
180
181set_access(mtg_name, princ_name, modes, code)
182        char *mtg_name;
183        char *princ_name;
184        char *modes;
185        int *code;              /* RETURN */
186{
187        int lockfd;
188        char acl_name[MAXPATHLEN];
189        dsc_acl *acl;
190        char *n_modes;
191        /*
192         * We do not use open_mtg here; it does more than what we need.
193         */
194
195        n_modes = acl_canon(modes, "acdorsw", code);
196        if (*code) goto punt;
197
198        /* steps 1 and 2 performed by locked_open_mtg */
199        if ((*code = locked_open_mtg(mtg_name, &lockfd, acl_name, &acl))
200            != 0) {
201                goto punt;
202        }
203
204        /* step 3: modify ACL in core */
205        if (!has_privs && !acl_check(acl,rpc_caller,"c")) {
206                *code = NO_ACCESS;
207                locked_abort(mtg_name, lockfd, acl_name, acl);
208                goto punt;
209        }
210
211        acl_replace_access(acl, princ_name, n_modes);
212                           
213        /* step 4, 5, 6 performed by locked_close_mtg */
214        if((*code = locked_close_mtg(mtg_name, lockfd, acl_name, acl))
215           != 0) {
216                   goto punt;
217        }
218        *code = 0;
219 punt:
220        (void) free(n_modes);
221        return;
222}
223
224/*
225 * Delete access.  This should look a lot like the above..
226 */
227
228delete_access(mtg_name, princ_name, code)
229        char *mtg_name;
230        char *princ_name;
231        int *code;              /* RETURN */
232{
233        int lockfd;
234        char acl_name[MAXPATHLEN];
235        dsc_acl *acl;
236
237        /*
238         * We do not use open_mtg here; it does more than what we need.
239         */
240
241        /* steps 1 and 2 performed by locked_open_mtg */
242        if ((*code = locked_open_mtg(mtg_name, &lockfd, acl_name, &acl))
243            != 0) {
244                return;
245        }
246
247        /* step 3: modify ACL in core */
248        if (!has_privs && !acl_check(acl,rpc_caller,"c")) {
249                *code = NO_ACCESS;
250                locked_abort(mtg_name, lockfd, acl_name, acl);
251                return;
252        }
253
254        if(!acl_delete_access(acl, princ_name)) {
255                *code = NO_PRINC;
256                locked_abort(mtg_name, lockfd, acl_name, acl);
257                return;
258        }
259       
260        /* step 4, 5, 6 performed by locked_close_mtg */
261        if((*code = locked_close_mtg(mtg_name, lockfd, acl_name, acl))
262           != 0) {
263                return;
264        }
265        *code = 0;
266        return;
267}
268
269int
270locked_open_mtg(mtg_name, lockfd, acl_name, acl)
271        char *mtg_name;
272        int *lockfd;            /* RETURN */
273        char *acl_name;         /* RETURN - address of buffer */
274        dsc_acl **acl;          /* RETURN */
275{
276        int mtg_name_len = strlen (mtg_name);
277        int result;
278        int u_acl_f;
279       
280        *lockfd = -1;
281        u_acl_f = -1;
282        /* XXX historical magic number should be MAXPATHLEN */
283        if (mtg_name[0] != '/' || mtg_name_len == 0 ||
284            mtg_name_len > MAXPATHLEN || mtg_name [mtg_name_len-1] == '/') {
285                result = BAD_PATH;
286                goto punt;
287        }
288        if((*lockfd = open(mtg_name, O_RDONLY, 0700)) < 0) {
289                result = errno;
290                goto punt;
291        }
292        if((flock(*lockfd, LOCK_EX)) != 0) { /* may block... */
293                result = errno;
294                goto punt;
295        }
296        (void) strcpy (acl_name, mtg_name);
297        (void) strcat (acl_name, "/acl");
298
299        if ((u_acl_f = open(acl_name, O_RDONLY, 0700)) < 0) {
300                if (errno == ENOENT)
301                        result = NO_SUCH_MTG;
302                else if (errno == EACCES)
303                        result = NO_ACCESS;
304                else
305                        result = BAD_PATH;
306                goto punt;
307        }
308        if (!fis_owner (u_acl_f, (int)geteuid())) {
309                result = NO_ACCESS;
310                goto punt;
311        }
312
313        *acl = acl_read (u_acl_f);
314        (void) close(u_acl_f);
315        u_acl_f = 0;
316        return 0;
317punt:
318        if (*lockfd >= 0) (void) close(*lockfd);
319        if (u_acl_f >= 0) (void) close(u_acl_f);
320        if (*acl) acl_destroy(*acl);
321
322        return result;
323}
324
325locked_abort(mtg_name, lockfd, acl_name, acl)
326        char *mtg_name;
327        int lockfd;
328        char *acl_name;
329        dsc_acl *acl;
330{
331        (void) close(lockfd);   /* unlocks, too */
332        acl_destroy(acl);
333}
334
335/*
336 * Here's the hairy one.
337 */
338
339int
340locked_close_mtg(mtg_name, lockfd, acl_name, acl)
341        char *mtg_name;
342        int lockfd;
343        char *acl_name;
344        dsc_acl *acl;
345{
346        int u_acl_f = -1;
347        int result;
348        char acl_nname[MAXPATHLEN];
349
350        /* Check for stupidity */
351        if (!has_privs && !acl_check(acl,rpc_caller,"c")) {
352                result = YOU_TWIT;
353                goto punt;
354        }
355        /*
356         * 4: Open up acl file for writing and write new acl.
357         */
358        (void) strcpy(acl_nname, acl_name);
359        (void) strcat(acl_nname, "~");
360
361        if ((u_acl_f = open(acl_nname, O_WRONLY|O_TRUNC|O_CREAT, 0600)) < 0) {
362                result = errno; /*XXX*/
363                goto punt;
364        }
365
366        if(!acl_write(u_acl_f, acl)) {
367                result = errno; /*XXX*/
368                goto punt;
369        }
370
371        (void) close(u_acl_f); u_acl_f = -1;
372       
373        /*
374         * 5: the commit point; rename the file.
375         */
376       
377        if(rename(acl_nname, acl_name) != 0)  {
378                result = errno;
379                goto punt;
380        }
381        /*
382         * 6: Cleanup.
383         */
384
385        result = 0;
386 punt:
387        (void) close(lockfd);   /* unlock */
388        acl_destroy(acl);       /* kaboom */
389        if (u_acl_f >= 0)
390                (void) close(u_acl_f);
391        return result;
392}
Note: See TracBrowser for help on using the repository browser.