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

Revision 15700, 7.9 KB checked in by ghudson, 24 years ago (diff)
From kolya: fix buffer overflows.
RevLine 
[149]1/*
[1939]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/*
[15700]9 *      $Id: acl_core.c,v 1.22 2001-02-28 20:44:23 ghudson Exp $
[149]10 *
11 *      Routines for use in a server to edit access control lists remotely.
12 *      Originally written for the discuss system by Bill Sommerfeld
13 *
14 */
15
[1625]16#include <discuss/types.h>
17#include <discuss/dsc_et.h>
18#include <discuss/acl.h>
19#include "internal.h"
[149]20#include <sys/file.h>
21#include <errno.h>
22#include <stdio.h>
23#include <sys/param.h>
[1625]24#include <string.h>
25#include "ansi.h"
[12439]26#if HAVE_FCNTL_H
[6570]27#include <fcntl.h>
[12439]28#endif
[149]29#ifndef lint
[1505]30static const char rcsid_acl_core_c[] =
[15700]31    "$Id: acl_core.c,v 1.22 2001-02-28 20:44:23 ghudson Exp $";
[12459]32#endif /* lint */
[149]33
[1505]34extern dsc_acl *mtg_acl;
[149]35extern char rpc_caller [];
36extern int errno;
[259]37extern int has_privs;
[822]38extern char *new_string();
[149]39
40/*
41 * Routines provided:
42 *      get_acl(obj_name) returns(code, acl)
43 *              Return the access control list for an object (meeting).
44 *      get_access(obj_name, princ_name) returns(code, modes)
45 *              Returns the access allowed for a given principal
46 *      set_access(obj_name, princ_name, modes) returns(code)
47 *              Sets the access on an object for a specific principal.
48 *      delete_access(obj_name, princ_name) returns(code)
49 *              Deletes princ_name from the access control list;
50 */
51
52/*
53 *      Locking protocol:
54 *      It is assumed that the ACL is in a file in a known directory;
55 *      the following locking protocol is used when modifying ACL's
56 *      to ensure consistancy.
[8516]57 *      1) exclusively lock the control file
[149]58 *      2) open acl for read, read ACL.
59 *      3) modify ACL in core.
60 *      4) open #acl for write, write ACL.
61 *      5) rename #acl to acl (this is assumed to be atomic)
[8516]62 *      6) unlock control file.
[149]63 *
64 *      The directory is locked, rather than the acl, because the file is
65 *      recreated and deleted (for atomicity reasons) on every transaction
66 *      (thank god UNIX files are lightweight). 
67 *
68 *      Since the acl in place is always consistant (and file opens
69 *      are atomic), there is no need to read-lock when getting the ACL.
70 */
[822]71       
[1505]72static dsc_acl *read_acl(mtg_name, code_ptr, check)
[822]73        char *mtg_name;
74        int *code_ptr;
75        int check;
76{
77        int fd = -1;
[1505]78        dsc_acl *list = NULL;
[822]79        int result = 0;
80        int mtg_name_len = strlen(mtg_name);
81        char acl_name[MAXPATHLEN];
82       
83        if (mtg_name[0] != '/' || mtg_name_len == 0 ||
[15700]84            mtg_name_len+5 >= MAXPATHLEN || mtg_name [mtg_name_len-1] == '/') {
[822]85                result = BAD_PATH;
86                goto punt;
87        }
88        strcpy(acl_name, mtg_name);
89        strcat(acl_name, "/acl");
90       
91        if((fd = open(acl_name, O_RDONLY, 0700)) < 0) {
92                result = errno;
93                goto punt;
94        }
[149]95
[822]96        errno = 0;
[1505]97        if ((list = acl_read(fd)) == (dsc_acl *) NULL) {
[822]98                result = errno?errno:NO_ACCESS;
99                goto punt;
100        }
101       
102        if (check && !acl_check(list, rpc_caller, "s")) {
103                result = NO_ACCESS;
104                goto punt;
105        }
106        close(fd);
107        *code_ptr = result;
108        return (list);
109punt:
110        *code_ptr = result;
111        if (list) acl_destroy(list);
112        close(fd);
113       
114        return NULL;
115}
116
[149]117get_acl(mtg_name, code, list)
118        char *mtg_name;
119        int *code;              /* RETURN */
[1505]120        dsc_acl **list;         /* RETURN */
[149]121{
[1147]122        *list = read_acl(mtg_name, code, !has_privs);
[149]123        return;
124}
125
126get_access(mtg_name, princ_name, modes, code)
127        char *mtg_name;
128        char *princ_name;
129        char **modes;           /* RETURN */
130        int *code;              /* RETURN */
131{
[1505]132        dsc_acl *list;
[149]133        *modes = NULL;
[822]134       
[149]135        *code = 0;
[1147]136        list = read_acl(mtg_name, code, !has_privs && (strcmp(princ_name, rpc_caller) != 0));
[822]137        if (*code) return;
138       
139        *modes = new_string(acl_get_access(list, princ_name));
140        acl_destroy(list);
[149]141        return;
142}
143
144/*
145 * Set access.
146 */
147
148set_access(mtg_name, princ_name, modes, code)
149        char *mtg_name;
150        char *princ_name;
151        char *modes;
152        int *code;              /* RETURN */
153{
154        int lockfd;
155        char acl_name[MAXPATHLEN];
[1505]156        dsc_acl *acl;
[149]157        char *n_modes;
158        /*
159         * We do not use open_mtg here; it does more than what we need.
160         */
161
162        n_modes = acl_canon(modes, "acdorsw", code);
163        if (*code) goto punt;
164
165        /* steps 1 and 2 performed by locked_open_mtg */
166        if ((*code = locked_open_mtg(mtg_name, &lockfd, acl_name, &acl))
167            != 0) {
168                goto punt;
169        }
170
171        /* step 3: modify ACL in core */
[259]172        if (!has_privs && !acl_check(acl,rpc_caller,"c")) {
[149]173                *code = NO_ACCESS;
174                locked_abort(mtg_name, lockfd, acl_name, acl);
175                goto punt;
176        }
177
178        acl_replace_access(acl, princ_name, n_modes);
179                           
180        /* step 4, 5, 6 performed by locked_close_mtg */
181        if((*code = locked_close_mtg(mtg_name, lockfd, acl_name, acl))
182           != 0) {
183                   goto punt;
184        }
185        *code = 0;
186 punt:
[167]187        (void) free(n_modes);
[149]188        return;
189}
190
191/*
192 * Delete access.  This should look a lot like the above..
193 */
194
195delete_access(mtg_name, princ_name, code)
196        char *mtg_name;
197        char *princ_name;
198        int *code;              /* RETURN */
199{
200        int lockfd;
201        char acl_name[MAXPATHLEN];
[1505]202        dsc_acl *acl;
[149]203
204        /*
205         * We do not use open_mtg here; it does more than what we need.
206         */
207
208        /* steps 1 and 2 performed by locked_open_mtg */
209        if ((*code = locked_open_mtg(mtg_name, &lockfd, acl_name, &acl))
210            != 0) {
211                return;
212        }
213
214        /* step 3: modify ACL in core */
[259]215        if (!has_privs && !acl_check(acl,rpc_caller,"c")) {
[149]216                *code = NO_ACCESS;
217                locked_abort(mtg_name, lockfd, acl_name, acl);
218                return;
219        }
220
221        if(!acl_delete_access(acl, princ_name)) {
222                *code = NO_PRINC;
223                locked_abort(mtg_name, lockfd, acl_name, acl);
224                return;
225        }
226       
227        /* step 4, 5, 6 performed by locked_close_mtg */
228        if((*code = locked_close_mtg(mtg_name, lockfd, acl_name, acl))
229           != 0) {
230                return;
231        }
232        *code = 0;
233        return;
234}
235
236int
237locked_open_mtg(mtg_name, lockfd, acl_name, acl)
238        char *mtg_name;
239        int *lockfd;            /* RETURN */
240        char *acl_name;         /* RETURN - address of buffer */
[1505]241        dsc_acl **acl;          /* RETURN */
[149]242{
243        int mtg_name_len = strlen (mtg_name);
244        int result;
[8516]245        int u_acl_f;
246        struct flock lock;
247        char control_name[MAXPATHLEN];
248       
[149]249        *lockfd = -1;
[8516]250        u_acl_f = -1;
[149]251        /* XXX historical magic number should be MAXPATHLEN */
252        if (mtg_name[0] != '/' || mtg_name_len == 0 ||
[15700]253            mtg_name_len+9 >= MAXPATHLEN || mtg_name [mtg_name_len-1] == '/') {
[149]254                result = BAD_PATH;
255                goto punt;
256        }
[8516]257        (void) strcpy (control_name, mtg_name);
258        (void) strcat (control_name, "/control");
259        if((*lockfd = open(control_name, O_RDWR, 0700)) < 0) {
260                result = errno;
[149]261                goto punt;
262        }
[8516]263        lock.l_type = F_WRLCK;
264        lock.l_start = 0;
265        lock.l_whence = 0;
266        lock.l_len = 0;
267        if (fcntl(*lockfd, F_SETLK, &lock) != 0)  {
[149]268                result = errno;
269                goto punt;
270        }
[8516]271        (void) strcpy (acl_name, mtg_name);
272        (void) strcat (acl_name, "/acl");
[149]273
[8516]274        if ((u_acl_f = open(acl_name, O_RDONLY, 0700)) < 0) {
275                if (errno == ENOENT)
276                        result = NO_SUCH_MTG;
277                else if (errno == EACCES)
278                        result = NO_ACCESS;
279                else
280                        result = BAD_PATH;
281                goto punt;
282        }
283        if (!fis_owner (u_acl_f, (int)geteuid())) {
[149]284                result = NO_ACCESS;
285                goto punt;
286        }
287
[8516]288        *acl = acl_read (u_acl_f);
289        (void) close(u_acl_f);
290        u_acl_f = 0;
[149]291        return 0;
292punt:
[167]293        if (*lockfd >= 0) (void) close(*lockfd);
[8516]294        if (u_acl_f >= 0) (void) close(u_acl_f);
295        if (*acl) acl_destroy(*acl);
[149]296
297        return result;
298}
299
300locked_abort(mtg_name, lockfd, acl_name, acl)
301        char *mtg_name;
302        int lockfd;
303        char *acl_name;
[1505]304        dsc_acl *acl;
[149]305{
[167]306        (void) close(lockfd);   /* unlocks, too */
[149]307        acl_destroy(acl);
308}
309
310/*
311 * Here's the hairy one.
312 */
313
314int
315locked_close_mtg(mtg_name, lockfd, acl_name, acl)
316        char *mtg_name;
317        int lockfd;
318        char *acl_name;
[1505]319        dsc_acl *acl;
[149]320{
321        int u_acl_f = -1;
322        int result;
323        char acl_nname[MAXPATHLEN];
324
[299]325        /* Check for stupidity */
326        if (!has_privs && !acl_check(acl,rpc_caller,"c")) {
327                result = YOU_TWIT;
328                goto punt;
329        }
[149]330        /*
331         * 4: Open up acl file for writing and write new acl.
332         */
[167]333        (void) strcpy(acl_nname, acl_name);
334        (void) strcat(acl_nname, "~");
[149]335
336        if ((u_acl_f = open(acl_nname, O_WRONLY|O_TRUNC|O_CREAT, 0600)) < 0) {
337                result = errno; /*XXX*/
338                goto punt;
339        }
340
341        if(!acl_write(u_acl_f, acl)) {
342                result = errno; /*XXX*/
343                goto punt;
344        }
345
[167]346        (void) close(u_acl_f); u_acl_f = -1;
[149]347       
348        /*
349         * 5: the commit point; rename the file.
350         */
351       
352        if(rename(acl_nname, acl_name) != 0)  {
353                result = errno;
354                goto punt;
355        }
356        /*
357         * 6: Cleanup.
358         */
359
360        result = 0;
361 punt:
[167]362        (void) close(lockfd);   /* unlock */
[149]363        acl_destroy(acl);       /* kaboom */
[167]364        if (u_acl_f >= 0)
365                (void) close(u_acl_f);
[149]366        return result;
367}
Note: See TracBrowser for help on using the repository browser.