~ubuntu-branches/ubuntu/vivid/cctools/vivid

« back to all changes in this revision

Viewing changes to chirp/src/chirp_acl.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Hanke
  • Date: 2011-05-07 09:05:00 UTC
  • Revision ID: james.westby@ubuntu.com-20110507090500-lqpmdtwndor6e7os
Tags: upstream-3.3.2
ImportĀ upstreamĀ versionĀ 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (C) 2003-2004 Douglas Thain and the University of Wisconsin
 
3
Copyright (C) 2005- The University of Notre Dame
 
4
This software is distributed under the GNU General Public License.
 
5
See the file COPYING for details.
 
6
*/
 
7
 
 
8
#include "chirp_acl.h"
 
9
#include "chirp_filesystem.h"
 
10
#include "chirp_group.h"
 
11
#include "chirp_protocol.h"
 
12
#include "chirp_ticket.h"
 
13
 
 
14
#include "debug.h"
 
15
#include "hash_table.h"
 
16
#include "md5.h"
 
17
#include "stringtools.h"
 
18
#include "username.h"
 
19
#include "xmalloc.h"
 
20
 
 
21
#include <assert.h>
 
22
#include <ctype.h>
 
23
#include <errno.h>
 
24
#include <string.h>
 
25
#include <sys/stat.h>
 
26
#include <sys/types.h>
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <unistd.h>
 
30
#include <fcntl.h>
 
31
#include <dirent.h>
 
32
 
 
33
/* Cygwin does not have 64-bit I/O, while Darwin has it by default. */
 
34
 
 
35
#if CCTOOLS_OPSYS_CYGWIN || CCTOOLS_OPSYS_DARWIN || CCTOOLS_OPSYS_FREEBSD
 
36
#define fopen64 fopen
 
37
#define open64 open
 
38
#define lseek64 lseek
 
39
#define stat64 stat
 
40
#define fstat64 fstat
 
41
#define lstat64 lstat
 
42
#define fseeko64 fseeko
 
43
#define ftruncate64 ftruncate
 
44
#define truncate64 truncate
 
45
#define statfs64 statfs
 
46
#define fstatfs64 fstatfs
 
47
#endif
 
48
 
 
49
#define unsigned_isspace(c) isspace((unsigned char) c)
 
50
 
 
51
#if CCTOOLS_OPSYS_DARWIN
 
52
#define lchown chown
 
53
#endif
 
54
 
 
55
static int read_only_mode = 0;
 
56
static const char *default_acl=0;
 
57
 
 
58
extern const char *chirp_super_user;
 
59
 
 
60
static int do_stat( const char *filename, struct chirp_stat *buf )
 
61
{
 
62
        int result;
 
63
        do {
 
64
                result = cfs->stat(filename,buf);
 
65
        } while( result==-1 && errno==EINTR );
 
66
        return result;
 
67
}
 
68
 
 
69
struct chirp_ticket {
 
70
  char *subject;
 
71
  char *ticket;
 
72
  time_t expiration;
 
73
  short expired;
 
74
  size_t nrights;
 
75
  struct chirp_ticket_rights {
 
76
    char *directory;
 
77
        int acl;
 
78
  } *rights;
 
79
};
 
80
 
 
81
static int readquote (const char **buffer, const char **s, size_t *l)
 
82
{
 
83
  while (unsigned_isspace(**buffer)) (*buffer)++;
 
84
  if (**buffer != '"') return 0;
 
85
  (*buffer)++;
 
86
  *l = 0;
 
87
  *s = *buffer;
 
88
  while (**buffer != '"' && **buffer != '\0') {
 
89
    (*buffer)++;
 
90
    (*l)++;
 
91
  }
 
92
  if (**buffer != '"') return 0;
 
93
  (*buffer)++;
 
94
  return 1;
 
95
}
 
96
 
 
97
static void ticket_free (struct chirp_ticket *ct)
 
98
{
 
99
  size_t n = 0;
 
100
  free(ct->subject);
 
101
  free(ct->ticket);
 
102
  while (n < ct->nrights) {
 
103
    free(ct->rights[n].directory);
 
104
    n++;
 
105
  }
 
106
  free(ct->rights);
 
107
}
 
108
 
 
109
static int ticket_write (const char *fname, struct chirp_ticket *ct)
 
110
{
 
111
        size_t n;
 
112
        CHIRP_FILE *ticketfile = cfs_fopen(fname, "w");
 
113
    if (!ticketfile) return 0;
 
114
 
 
115
        cfs_fprintf(ticketfile,"subject \"%s\"\n",ct->subject);
 
116
        cfs_fprintf(ticketfile,"ticket \"%s\"\n",ct->ticket);
 
117
        cfs_fprintf(ticketfile,"expiration \"%lu\"\n",(unsigned long) ct->expiration);
 
118
        for (n = 0; n < ct->nrights; n++) {
 
119
                cfs_fprintf(ticketfile,"rights \"%s\" \"%s\"\n",ct->rights[n].directory,chirp_acl_flags_to_text(ct->rights[n].acl));
 
120
        }
 
121
 
 
122
        cfs_fflush(ticketfile);
 
123
        int result = cfs_ferror(ticketfile);
 
124
        if (result) {
 
125
                errno = EACCES;
 
126
                return -1;
 
127
        }
 
128
        cfs_fclose(ticketfile);
 
129
        return 0;
 
130
}
 
131
 
 
132
static int ticket_read (const char *fname, struct chirp_ticket *ct)
 
133
{
 
134
        int status = 0;
 
135
 
 
136
        char *b;
 
137
        size_t l;
 
138
        CHIRP_FILE *ticketfile = cfs_fopen(fname, "r");
 
139
    if (!ticketfile) return 0;
 
140
    if (!cfs_freadall(ticketfile, &b, &l)) {
 
141
                cfs_fclose(ticketfile);
 
142
                return 0;
 
143
        }
 
144
        cfs_fclose(ticketfile);
 
145
 
 
146
        /* Ticket format (quoted strings may span multiple lines):
 
147
         * subject "<subject>"
 
148
         * ticket "<ticket>"
 
149
         * expiration "<UTC seconds since Epoch>"
 
150
         * rights "<directory>" "<acl>"
 
151
         * rights "<directory>" "<acl>"
 
152
         * ...
 
153
         */
 
154
        size_t n;
 
155
        const char *s;
 
156
        const char *buffer = b;
 
157
        time_t now = time(NULL);
 
158
        now = mktime(gmtime(&now)); /* convert to UTC */
 
159
        ct->subject = NULL;
 
160
        ct->ticket = NULL;
 
161
        ct->expiration = now; /* default expire now... */
 
162
        ct->expired = 1; /* default is expired */
 
163
        ct->nrights = 0;
 
164
        ct->rights = NULL;
 
165
        while (1) {
 
166
                while (unsigned_isspace(*buffer)) buffer++;
 
167
                if (strncmp(buffer, "subject", strlen("subject")) == 0) {
 
168
                        buffer += strlen("subject");
 
169
                        if (!readquote(&buffer, &s, &n)) break;
 
170
                        ct->subject = xxrealloc(ct->subject, n+1);
 
171
                        memcpy(ct->subject, s, n);
 
172
                        ct->subject[n] = '\0';
 
173
                } else if (strncmp(buffer, "ticket", strlen("ticket")) == 0) {
 
174
                        buffer += strlen("ticket");
 
175
                        if (!readquote(&buffer, &s, &n)) break;
 
176
                        ct->ticket = xxrealloc(ct->ticket, n+1);
 
177
                        memcpy(ct->ticket, s, n);
 
178
                        ct->ticket[n] = '\0';
 
179
                } else if (strncmp(buffer, "expiration", strlen("expiration")) == 0) {
 
180
                        buffer += strlen("expiration");
 
181
                        if (!readquote(&buffer, &s, &n)) break;
 
182
                        char *stime = xxmalloc(n+1);
 
183
                        memcpy(stime, s, n);
 
184
                        stime[n] = '\0';
 
185
                        ct->expiration = (time_t) strtoul(stime, NULL, 10);
 
186
                        ct->expired = (ct->expiration <= now);
 
187
                        free(stime);
 
188
                } else if (strncmp(buffer, "rights", strlen("rights")) == 0) {
 
189
                        buffer += strlen("rights");
 
190
                        if (!readquote(&buffer, &s, &n)) break;
 
191
                        ct->rights = xxrealloc(ct->rights, sizeof(*ct->rights)*(++ct->nrights)+1);
 
192
                        ct->rights[ct->nrights-1].directory = xxmalloc(n+1);
 
193
                        memcpy(ct->rights[ct->nrights-1].directory, s, n);
 
194
                        ct->rights[ct->nrights-1].directory[n] = '\0';
 
195
                        if (!readquote(&buffer, &s, &n)) break;
 
196
                        char *acl = xxmalloc(n+1);
 
197
                        memcpy(acl, s, n);
 
198
                        acl[n] = '\0';
 
199
                        ct->rights[ct->nrights-1].acl = chirp_acl_text_to_flags(acl);
 
200
                        free(acl);
 
201
                } else if (*buffer == '\0') {
 
202
                        if (ct->subject && ct->ticket && ct->nrights > 0) {
 
203
                                status = 1;
 
204
                        }
 
205
                        break;
 
206
                } else {
 
207
                        break;
 
208
                }
 
209
        }
 
210
        if (ct->rights == NULL) {
 
211
                assert(ct->nrights == 0);
 
212
                ct->rights = xxrealloc(ct->rights, sizeof(*ct->rights)*(++ct->nrights)+1);
 
213
                ct->rights[ct->nrights-1].directory = xstrdup("/");
 
214
                ct->rights[ct->nrights-1].acl = CHIRP_ACL_ALL;
 
215
                ct->nrights = 1;
 
216
        }
 
217
        free(b);
 
218
        /* fprintf(stderr, "TICKET:\n\tsubject = %s\n\texpiration = %lu %lu %d\n\tticket = %s\n\trights[0] = %s %s\n", ct->subject, now, ct->expiration, ct->expired, ct->ticket, ct->rights[0].directory, chirp_acl_flags_to_text(ct->rights[0].acl)); */
 
219
        return status && !ct->expired;
 
220
}
 
221
 
 
222
static void chirp_acl_ticket_name ( const char *root, const char *ticket, char *name, char *fname )
 
223
{
 
224
  unsigned char digest[CHIRP_TICKET_DIGEST_LENGTH];
 
225
  md5_context_t context;
 
226
  md5_init(&context);
 
227
  md5_update(&context, (const unsigned char *) ticket, strlen(ticket));
 
228
  md5_final(digest, &context);
 
229
  strcpy(name, "ticket:");
 
230
  strcat(name, md5_string(digest));
 
231
  sprintf(fname,"%s/%s%s",root,CHIRP_TICKET_PREFIX,name);
 
232
}
 
233
 
 
234
void chirp_acl_force_readonly()
 
235
{
 
236
        read_only_mode = 1;
 
237
}
 
238
 
 
239
void chirp_acl_default( const char *d )
 
240
{
 
241
        default_acl = d;
 
242
}
 
243
 
 
244
static int is_a_directory( const char *filename )
 
245
{
 
246
        struct chirp_stat info;
 
247
 
 
248
        if(do_stat(filename,&info)==0) {
 
249
                if(S_ISDIR(info.cst_mode)) {
 
250
                        return 1;
 
251
                } else {
 
252
                        return 0;
 
253
                }
 
254
        } else {
 
255
                return 0;
 
256
        }
 
257
}
 
258
 
 
259
static void make_acl_name( const char *filename, int get_parent, char *aclname )
 
260
{
 
261
        char tmp[CHIRP_PATH_MAX];
 
262
        sprintf(tmp,"%s/%s",filename,CHIRP_ACL_BASE_NAME);
 
263
        string_collapse_path(tmp,aclname,1);
 
264
}
 
265
 
 
266
/*
 
267
do_chirp_acl_get returns the acl flags associated with a subject and directory.
 
268
If the subject has rights there, they are returned and errno is undefined.
 
269
If the directory exists, but the subject has no rights, returns zero with errno=0.
 
270
If the rights cannot be obtained, returns zero with errno set appropriately.
 
271
*/
 
272
 
 
273
static int do_chirp_acl_get( const char *root, const char *dirname, const char *subject, int *totalflags )
 
274
{
 
275
        CHIRP_FILE *aclfile;
 
276
        char aclsubject[CHIRP_LINE_MAX];
 
277
        int aclflags;
 
278
 
 
279
        errno = 0;
 
280
        *totalflags = 0;
 
281
 
 
282
        /* if the subject is a ticket, then we need the rights we have for the
 
283
         * directory along with the rights of the subject in that directory
 
284
         */
 
285
        const char *digest;
 
286
    if (chirp_ticket_isticketsubject(subject, &digest)) {
 
287
                /* open the ticket file, read the public key */
 
288
                char ticketfilename[CHIRP_PATH_MAX];
 
289
                struct chirp_ticket ct;
 
290
                strcpy(ticketfilename, CHIRP_TICKET_PREFIX);
 
291
                strcat(ticketfilename, subject);
 
292
                if (!ticket_read(ticketfilename, &ct)) return 0;
 
293
                if (!do_chirp_acl_get(root, dirname, ct.subject, totalflags)) {
 
294
                        ticket_free(&ct);
 
295
                        return 0;
 
296
                }
 
297
                size_t i;
 
298
                size_t longest = 0;
 
299
                int mask = 0;
 
300
                for (i = 0; i < ct.nrights; i++) {
 
301
                        char safewhere[CHIRP_PATH_MAX];
 
302
                        char where[CHIRP_PATH_MAX];
 
303
                        sprintf(safewhere, "%s/%s", root, ct.rights[i].directory);
 
304
                        string_collapse_path(safewhere, where, 1);
 
305
 
 
306
                        if (strncmp(dirname, where, strlen(where)) == 0) {
 
307
                                if (strlen(where) > longest) {
 
308
                                        longest = strlen(where);
 
309
                                        mask = ct.rights[i].acl;
 
310
                                }
 
311
                        }
 
312
                }
 
313
                *totalflags &= mask;
 
314
    } else {
 
315
                aclfile = chirp_acl_open(dirname);
 
316
                if(aclfile) {
 
317
                        while(chirp_acl_read(aclfile,aclsubject,&aclflags)) {
 
318
                                if(string_match(aclsubject,subject)) {
 
319
                                        *totalflags |= aclflags;
 
320
                                } else if(!strncmp(aclsubject,"group:",6)) {
 
321
                                        if(chirp_group_lookup(aclsubject,subject)) {
 
322
                                                *totalflags |= aclflags;
 
323
                                        }
 
324
                                }
 
325
                        }
 
326
                        chirp_acl_close(aclfile);
 
327
                } else {
 
328
                        return 0;
 
329
                }
 
330
        }
 
331
 
 
332
        if(read_only_mode) {
 
333
                *totalflags &= CHIRP_ACL_READ|CHIRP_ACL_LIST;
 
334
        }
 
335
 
 
336
        return 1;
 
337
}
 
338
 
 
339
 
 
340
int chirp_acl_check_dir( const char *root, const char *dirname, const char *subject, int flags )
 
341
{
 
342
        int myflags;
 
343
        
 
344
        if (!do_chirp_acl_get(root,dirname,subject,&myflags))
 
345
          return 0;
 
346
 
 
347
        /* The superuser can implicitly list and admin */
 
348
 
 
349
        if(chirp_super_user && !strcmp(subject,chirp_super_user)) {
 
350
                myflags |= CHIRP_ACL_LIST|CHIRP_ACL_ADMIN;
 
351
        }
 
352
 
 
353
        if( ( flags & myflags ) == flags ) {
 
354
                return 1;
 
355
        } else {
 
356
                errno = EACCES;
 
357
                return 0;
 
358
        }
 
359
}
 
360
 
 
361
static int do_chirp_acl_check( const char *root, const char *filename, const char *subject, int flags, int follow_links )
 
362
{
 
363
        char linkname[CHIRP_PATH_MAX];
 
364
        char temp[CHIRP_PATH_MAX];
 
365
        char dirname[CHIRP_PATH_MAX];
 
366
 
 
367
        /*
 
368
        Symbolic links require special handling.
 
369
        If requested, follow the link and look for rights in that directory.
 
370
        */
 
371
 
 
372
        if(follow_links && flags!=CHIRP_ACL_DELETE) {
 
373
                int length = cfs->readlink(filename,linkname,sizeof(linkname));
 
374
                if(length>0) {
 
375
                        linkname[length] = 0;
 
376
 
 
377
                        /* If the link is relative, construct a full path */
 
378
 
 
379
                        if(linkname[0]!='/') {
 
380
                                sprintf(temp,"%s/../%s",filename,linkname);
 
381
                                string_collapse_path(temp,linkname,1);
 
382
                        }
 
383
 
 
384
                        /* Use the linkname now to look up the ACL */
 
385
 
 
386
                        debug(D_DEBUG,"symlink %s points to %s",filename,linkname);
 
387
                        filename = linkname;
 
388
                }
 
389
        }
 
390
 
 
391
        /*
 
392
        If the file being checked is an ACL file,
 
393
        then it may be written with the admin flag, but never deleted.
 
394
        */
 
395
 
 
396
        if(!strcmp(string_back(filename,CHIRP_ACL_BASE_LENGTH),CHIRP_ACL_BASE_NAME)) {
 
397
                if(flags&CHIRP_ACL_DELETE) {
 
398
                        errno = EACCES;
 
399
                        return 0;
 
400
                }
 
401
                if(flags&CHIRP_ACL_WRITE) {
 
402
                        flags &= ~CHIRP_ACL_WRITE;
 
403
                        flags |= CHIRP_ACL_ADMIN;
 
404
                }
 
405
        }
 
406
 
 
407
        /* Now get the name of the directory containing the file */
 
408
 
 
409
        string_collapse_path(filename,temp,1);
 
410
        if(!is_a_directory(temp))
 
411
                string_dirname(temp,dirname);
 
412
        else
 
413
                strcpy(dirname,temp);
 
414
 
 
415
        /* Perform the permissions check on that directory. */
 
416
 
 
417
        return chirp_acl_check_dir(root,dirname,subject,flags);
 
418
}
 
419
 
 
420
int chirp_acl_check( const char *root, const char *filename, const char *subject, int flags )
 
421
{
 
422
        return do_chirp_acl_check(root,filename,subject,flags,1);
 
423
}
 
424
 
 
425
int chirp_acl_check_link( const char *root, const char *filename, const char *subject, int flags )
 
426
{
 
427
        return do_chirp_acl_check(root,filename,subject,flags,0);
 
428
}
 
429
 
 
430
int chirp_acl_gettickets (const char *dirname, struct hash_table *ticket)
 
431
{
 
432
        if (!is_a_directory(dirname)) {
 
433
                errno = ENOTDIR;
 
434
                return -1;
 
435
        }
 
436
 
 
437
        const char *entry;
 
438
        void *dir;
 
439
 
 
440
        dir = cfs->opendir(dirname);
 
441
        if (!dir) {
 
442
                return -1;
 
443
        }
 
444
        while ((entry = cfs->readdir(dir))) {
 
445
                char path[CHIRP_PATH_MAX];
 
446
                if (!strcmp(entry, ".")) continue;
 
447
                if (!strcmp(entry, "..")) continue;
 
448
                sprintf(path,"%s/%s", dirname, entry);
 
449
                const char *digest;
 
450
                if (strncmp(entry, CHIRP_TICKET_PREFIX, CHIRP_TICKET_PREFIX_LENGTH) == 0 && chirp_ticket_isticketsubject(entry+CHIRP_TICKET_PREFIX_LENGTH, &digest)) {
 
451
                        /* open the ticket file, read the public key */
 
452
                        struct chirp_ticket ct;
 
453
                        if (!ticket_read(path, &ct)) continue;
 
454
                        debug(D_CHIRP, "adding %s to known tickets", digest);
 
455
                        hash_table_insert(ticket, digest, xstrdup(ct.ticket));
 
456
                        ticket_free(&ct);
 
457
                }
 
458
        }
 
459
        cfs->closedir(dir);
 
460
        return 0;
 
461
}
 
462
 
 
463
int chirp_acl_ticket_delete( const char *root, const char *subject, const char *ticket_subject )
 
464
{
 
465
        char ticket_file[CHIRP_PATH_MAX];
 
466
    const char *digest;
 
467
    char *esubject;
 
468
    struct chirp_ticket ct;
 
469
        int status = 0;
 
470
 
 
471
        if (!chirp_ticket_isticketsubject(ticket_subject,&digest)) {
 
472
                errno = EINVAL;
 
473
                return -1;
 
474
        }
 
475
    if (!chirp_acl_whoami(subject, &esubject)) return -1;
 
476
 
 
477
        sprintf(ticket_file,"%s/%s%s",root,CHIRP_TICKET_PREFIX,ticket_subject);
 
478
 
 
479
        if (!ticket_read(ticket_file, &ct)) {
 
480
                free(esubject);
 
481
                return -1;
 
482
        }
 
483
 
 
484
        if (strcmp(esubject,ct.subject) == 0 || strcmp(chirp_super_user, subject) == 0) {
 
485
                status = cfs->unlink(ticket_file);
 
486
        } else {
 
487
                errno = EACCES;
 
488
                status = -1;
 
489
        }
 
490
        ticket_free(&ct);
 
491
        free(esubject);
 
492
        return status;
 
493
}
 
494
 
 
495
int chirp_acl_ticket_get (const char *root, const char *subject, const char *ticket_subject, char **ticket_esubject, char **ticket, time_t *ticket_expiration, char ***ticket_rights)
 
496
{
 
497
        char *esubject;
 
498
    if (!chirp_acl_whoami(subject, &esubject)) return -1;
 
499
 
 
500
    const char *digest;
 
501
        if (!chirp_ticket_isticketsubject(ticket_subject,&digest)) {
 
502
                errno = EINVAL;
 
503
                return -1;
 
504
        }
 
505
 
 
506
        struct chirp_ticket ct;
 
507
        char ticket_file[CHIRP_PATH_MAX];
 
508
        sprintf(ticket_file,"%s/%s%s",root,CHIRP_TICKET_PREFIX,ticket_subject);
 
509
        if (!ticket_read(ticket_file, &ct)) {
 
510
                free(esubject);
 
511
                errno = EINVAL;
 
512
                return -1;
 
513
        }
 
514
        if (strcmp(ct.subject, subject) == 0 || strcmp(subject, chirp_super_user) == 0) {
 
515
                *ticket_esubject = xstrdup(ct.subject);
 
516
                *ticket = xstrdup(ct.ticket);
 
517
 
 
518
                time_t now;
 
519
                time(&now);
 
520
                now = mktime(gmtime(&now)); /* convert to UTC */
 
521
                *ticket_expiration = ct.expiration-now;
 
522
 
 
523
                size_t n;
 
524
                *ticket_rights = (char **) xxmalloc(sizeof(char *)*2*(ct.nrights+1));
 
525
                for (n = 0; n < ct.nrights; n++) {
 
526
                        (*ticket_rights)[n*2+0] = xstrdup(ct.rights[n].directory);
 
527
                        (*ticket_rights)[n*2+1] = xstrdup(chirp_acl_flags_to_text(ct.rights[n].acl));
 
528
                }
 
529
                (*ticket_rights)[n*2+0] = NULL;
 
530
                (*ticket_rights)[n*2+1] = NULL;
 
531
                
 
532
                ticket_free(&ct);
 
533
                free(esubject);
 
534
                return 0;
 
535
        } else {
 
536
                ticket_free(&ct);
 
537
                free(esubject);
 
538
                errno = EACCES;
 
539
                return -1;
 
540
        }
 
541
}
 
542
 
 
543
int chirp_acl_ticket_list (const char *root, const char *subject, char ***ticket_subjects)
 
544
{
 
545
        size_t n = 0;
 
546
        *ticket_subjects = NULL;
 
547
 
 
548
        const char *entry;
 
549
        void *dir;
 
550
        dir = cfs->opendir(root);
 
551
        if (dir == NULL) return -1;
 
552
 
 
553
        while ((entry = cfs->readdir(dir))) {
 
554
                if (strcmp(entry, ".") == 0 || strcmp(entry, "..") == 0) continue;
 
555
                char path[CHIRP_PATH_MAX];
 
556
                sprintf(path,"%s/%s", root, entry);
 
557
                const char *digest;
 
558
                if (strncmp(entry, CHIRP_TICKET_PREFIX, CHIRP_TICKET_PREFIX_LENGTH) == 0 && chirp_ticket_isticketsubject(entry+CHIRP_TICKET_PREFIX_LENGTH, &digest)) {
 
559
                        struct chirp_ticket ct;
 
560
                        if (!ticket_read(path, &ct)) continue; /* expired? */
 
561
                        if (strcmp(subject, ct.subject) == 0 || strcmp(subject, "all") == 0) {
 
562
                            n = n+1;
 
563
                                *ticket_subjects = (char **) xxrealloc(*ticket_subjects, (n+1)*sizeof(char *));
 
564
                                (*ticket_subjects)[n-1] = xstrdup(entry+CHIRP_TICKET_PREFIX_LENGTH);
 
565
                                (*ticket_subjects)[n] = NULL;
 
566
                        }
 
567
                        ticket_free(&ct);
 
568
                }
 
569
        }
 
570
        cfs->closedir(dir);
 
571
 
 
572
        return 0;
 
573
}
 
574
 
 
575
int chirp_acl_gctickets (const char *root)
 
576
{
 
577
        void *dir;
 
578
        const char *entry;
 
579
 
 
580
        dir = cfs->opendir(root);
 
581
        if (!dir) {
 
582
                return -1;
 
583
        }
 
584
        while ((entry = cfs->readdir(dir))) {
 
585
                const char *digest;
 
586
                if (strncmp(entry, CHIRP_TICKET_PREFIX, CHIRP_TICKET_PREFIX_LENGTH) == 0 && chirp_ticket_isticketsubject(entry+CHIRP_TICKET_PREFIX_LENGTH, &digest)) {
 
587
                        /* open the ticket file, read the public key */
 
588
                        struct chirp_ticket ct;
 
589
                        char path[CHIRP_PATH_MAX];
 
590
                        sprintf(path, "%s/%s", root, entry);
 
591
                        if (ticket_read(path, &ct)) {
 
592
                                ticket_free(&ct);
 
593
                                continue;
 
594
            }
 
595
                        debug(D_CHIRP, "ticket %s expired (or corrupt), garbage collecting", digest);
 
596
                        cfs->unlink(path);
 
597
                }
 
598
        }
 
599
        cfs->closedir(dir);
 
600
        return 0;
 
601
}
 
602
 
 
603
int chirp_acl_ticket_create ( const char *root, const char *subject, const char *newsubject, const char *ticket, const char *duration)
 
604
{
 
605
    time_t now; /*, delta; */
 
606
        time_t offset = (time_t) strtoul(duration, NULL, 10);
 
607
        const char *digest;
 
608
        char ticket_name[CHIRP_PATH_MAX];
 
609
        char ticket_file[CHIRP_PATH_MAX];
 
610
    char expiration[128];
 
611
 
 
612
        now = time(NULL);
 
613
        now = mktime(gmtime(&now)); /* convert to UTC */
 
614
    sprintf(expiration, "%lu", (unsigned long) (now+offset));
 
615
 
 
616
    /* Note about tickets making tickets:
 
617
     * A ticket created by a ticket authenticated user has the same effective
 
618
     * subject (see the ticket_register RPC in chirp_server.c). Also, the
 
619
     * expiration time is less than or equal to the expiration time of the
 
620
     * ticket used to authenticate.
 
621
     */
 
622
        if (chirp_ticket_isticketsubject(subject,&digest)) {
 
623
                struct chirp_ticket ct;
 
624
                sprintf(ticket_file,"%s/%s%s",root,CHIRP_TICKET_PREFIX,subject);
 
625
                if (!ticket_read(ticket_file, &ct)) return -1;
 
626
                if (ct.expiration < now+offset) {
 
627
                sprintf(expiration, "%lu", (unsigned long) ct.expiration);
 
628
                }
 
629
                ticket_free(&ct);
 
630
    }
 
631
 
 
632
        if(!is_a_directory(root)) {
 
633
                errno = ENOTDIR;
 
634
                return -1;
 
635
        }
 
636
 
 
637
        chirp_acl_ticket_name(root,ticket,ticket_name,ticket_file);
 
638
 
 
639
        CHIRP_FILE *f = cfs_fopen(ticket_file,"w");
 
640
        if (!f) {
 
641
                errno = EACCES;
 
642
                return -1;
 
643
        }
 
644
        cfs_fprintf(f,"subject \"%s\"\n",newsubject);
 
645
        cfs_fprintf(f,"expiration \"%s\"\n",expiration);
 
646
        cfs_fprintf(f,"ticket \"%s\"\n",ticket);
 
647
    cfs_fprintf(f,"rights \"/\" \"\"\n");
 
648
 
 
649
        cfs_fflush(f);
 
650
        int result = cfs_ferror(f);
 
651
        if (result) {
 
652
                errno = EACCES;
 
653
                return -1;
 
654
        }
 
655
        cfs_fclose(f);
 
656
    return 0;
 
657
}
 
658
 
 
659
int chirp_acl_ticket_modify ( const char *root, const char *subject, const char *ticket_subject, const char *path, int flags )
 
660
{
 
661
        char ticket_file[CHIRP_PATH_MAX];
 
662
    const char *digest;
 
663
    char *esubject;
 
664
    struct chirp_ticket ct;
 
665
        int status = 0;
 
666
 
 
667
        if (!chirp_ticket_isticketsubject(ticket_subject,&digest)) {
 
668
                errno = EINVAL;
 
669
                return -1;
 
670
        }
 
671
    /* Note about tickets making tickets:
 
672
     * We check whether the ticket has the rights associated with the mask in
 
673
     * the next line. So, a ticket can only make a ticket with rights it
 
674
     * already has.
 
675
     */
 
676
    if (!chirp_acl_check_dir(root,path,subject,flags)) return -1; /* you don't have the rights for the mask */
 
677
    if (!chirp_acl_whoami(subject, &esubject)) return -1;
 
678
 
 
679
        sprintf(ticket_file,"%s/%s%s",root,CHIRP_TICKET_PREFIX,ticket_subject);
 
680
 
 
681
        if (!ticket_read(ticket_file, &ct)) {
 
682
                free(esubject);
 
683
                return -1;
 
684
        }
 
685
 
 
686
        if (strcmp(esubject,ct.subject) == 0 || strcmp(chirp_super_user, subject) == 0) {
 
687
                size_t n;
 
688
                int replaced = 0;
 
689
                for (n = 0; n < ct.nrights; n++) {
 
690
                        char safewhere[CHIRP_PATH_MAX];
 
691
                        char where[CHIRP_PATH_MAX];
 
692
                        sprintf(safewhere, "%s/%s", root, ct.rights[n].directory);
 
693
                        string_collapse_path(safewhere, where, 1);
 
694
 
 
695
                        if (strcmp(where, path) == 0) {
 
696
                                ct.rights[n].acl = flags; /* replace old acl mask */
 
697
                                replaced = 1;
 
698
                        }
 
699
                }
 
700
                if (!replaced) {
 
701
                        assert(strlen(path) >= strlen(root));
 
702
                        ct.rights = xxrealloc(ct.rights, sizeof(*ct.rights)*(++ct.nrights)+1);
 
703
                        char directory[CHIRP_PATH_MAX];
 
704
                        char collapsed_directory[CHIRP_PATH_MAX];
 
705
                        sprintf(directory, "/%s", path+strlen(root));
 
706
                        string_collapse_path(directory, collapsed_directory, 1);
 
707
                        ct.rights[ct.nrights-1].directory = xstrdup(collapsed_directory);
 
708
                        ct.rights[ct.nrights-1].acl = flags;
 
709
                }
 
710
                status = ticket_write(ticket_file, &ct);
 
711
        } else {
 
712
                errno = EACCES;
 
713
                status = -1;
 
714
        }
 
715
        ticket_free(&ct);
 
716
        free(esubject);
 
717
        return status;
 
718
}
 
719
 
 
720
int chirp_acl_whoami( const char *subject, char **esubject )
 
721
{
 
722
        const char *digest;
 
723
        if (chirp_ticket_isticketsubject(subject, &digest)) {
 
724
                /* open the ticket file */
 
725
                struct chirp_ticket ct;
 
726
                char ticketfilename[CHIRP_PATH_MAX];
 
727
                strcpy(ticketfilename, CHIRP_TICKET_PREFIX);
 
728
                strcat(ticketfilename, subject);
 
729
                if (!ticket_read(ticketfilename, &ct)) return 0;
 
730
                *esubject = xstrdup(ct.subject);
 
731
                ticket_free(&ct);
 
732
                return 1;
 
733
        } else {
 
734
                *esubject = xstrdup(subject);
 
735
                return 1;
 
736
        }
 
737
}
 
738
 
 
739
int chirp_acl_set( const char *dirname, const char *subject, int flags, int reset_acl )
 
740
{
 
741
        char aclname[CHIRP_PATH_MAX];
 
742
        char newaclname[CHIRP_PATH_MAX];
 
743
        char aclsubject[CHIRP_LINE_MAX];
 
744
        int aclflags;
 
745
        CHIRP_FILE *aclfile, *newaclfile;
 
746
        int result;
 
747
        int replaced_acl_entry=0;
 
748
 
 
749
        if(!is_a_directory(dirname)) {
 
750
                errno = ENOTDIR;
 
751
                return -1;
 
752
        }
 
753
 
 
754
        sprintf(aclname,"%s/%s",dirname,CHIRP_ACL_BASE_NAME);
 
755
        sprintf(newaclname,"%s/%s.%d",dirname,CHIRP_ACL_BASE_NAME,(int)getpid());
 
756
 
 
757
        if(reset_acl) {
 
758
                aclfile = cfs_fopen("/dev/null","r");
 
759
        } else {
 
760
                aclfile = cfs_fopen(aclname,"r");
 
761
 
 
762
                /* If the acl never existed, then we can simply create it. */
 
763
                if(!aclfile && errno==ENOENT) {
 
764
                        if(default_acl) {
 
765
                                aclfile = cfs_fopen(default_acl,"r");
 
766
                        } else {
 
767
                                aclfile = cfs_fopen("/dev/null","r"); /* use local... */
 
768
                        }
 
769
                }
 
770
        }
 
771
 
 
772
        if(!aclfile) {
 
773
                errno = EACCES;
 
774
                return -1;
 
775
        }
 
776
 
 
777
        replaced_acl_entry = 0;
 
778
 
 
779
        newaclfile = cfs_fopen(newaclname,"w");
 
780
        if(!newaclfile) {
 
781
                cfs_fclose(aclfile);
 
782
                errno = EACCES;
 
783
                return -1;
 
784
        }
 
785
 
 
786
        while(chirp_acl_read(aclfile,aclsubject,&aclflags)) {
 
787
                if(!strcmp(subject,aclsubject)) {
 
788
                        aclflags = flags;
 
789
                        replaced_acl_entry = 1;
 
790
                }
 
791
                if(aclflags!=0) {
 
792
                        cfs_fprintf(newaclfile,"%s %s\n",aclsubject,chirp_acl_flags_to_text(aclflags));
 
793
                }
 
794
        }
 
795
        cfs_fclose(aclfile);
 
796
 
 
797
        if(!replaced_acl_entry) {
 
798
                cfs_fprintf(newaclfile,"%s %s\n",subject,chirp_acl_flags_to_text(flags));
 
799
        }
 
800
 
 
801
        /* Need to force a write in order to get response from ferror */
 
802
 
 
803
        cfs_fflush(newaclfile);
 
804
    result = cfs_ferror(newaclfile);
 
805
        cfs_fclose(newaclfile);
 
806
 
 
807
        if(result) {
 
808
                errno = EACCES;
 
809
                result = -1;
 
810
        } else {
 
811
                result = cfs->rename(newaclname,aclname);
 
812
                if(result<0) {
 
813
                        cfs->unlink(newaclname);
 
814
                        errno = EACCES;
 
815
                        result = -1;
 
816
                }
 
817
        }
 
818
 
 
819
        return result;
 
820
}
 
821
 
 
822
CHIRP_FILE *chirp_acl_open( const char *dirname )
 
823
{
 
824
        char aclname[CHIRP_PATH_MAX];
 
825
        CHIRP_FILE *file;
 
826
 
 
827
        if(!is_a_directory(dirname)) {
 
828
                if (errno == ENOENT && default_acl) {
 
829
                        file = cfs_fopen(default_acl, "r");
 
830
                        return file;
 
831
                }
 
832
        else if (errno == ENOTDIR) /* component directory missing */
 
833
                        return NULL;
 
834
                errno = ENOENT;
 
835
                return 0;
 
836
        } else {
 
837
                make_acl_name(dirname,0,aclname);
 
838
                file = cfs_fopen(aclname,"r");
 
839
                if(!file && default_acl) file = cfs_fopen(default_acl, "r");
 
840
                return file;
 
841
        }
 
842
}
 
843
 
 
844
int chirp_acl_read( CHIRP_FILE *aclfile, char *subject, int *flags )
 
845
{
 
846
        char acl[CHIRP_LINE_MAX];
 
847
        char tmp[CHIRP_LINE_MAX];
 
848
 
 
849
        while(cfs_fgets(acl,sizeof(acl),aclfile)) {
 
850
                if(sscanf(acl,"%[^ ] %[rwldpvax()]",subject,tmp)==2) {
 
851
                        *flags = chirp_acl_text_to_flags(tmp);
 
852
                        return 1;
 
853
                } else {
 
854
                        continue;
 
855
                }
 
856
        }
 
857
 
 
858
        return 0;
 
859
}
 
860
 
 
861
void chirp_acl_close( CHIRP_FILE *aclfile )
 
862
{
 
863
        cfs_fclose(aclfile);
 
864
}
 
865
 
 
866
 
 
867
const char * chirp_acl_flags_to_text( int flags )
 
868
{
 
869
        static char text[20];
 
870
 
 
871
        text[0] = 0;
 
872
 
 
873
        if(flags&CHIRP_ACL_READ)    strcat(text,"r");
 
874
        if(flags&CHIRP_ACL_WRITE)   strcat(text,"w");
 
875
        if(flags&CHIRP_ACL_LIST)    strcat(text,"l");
 
876
        if(flags&CHIRP_ACL_DELETE)  strcat(text,"d");
 
877
        if(flags&CHIRP_ACL_PUT)     strcat(text,"p");
 
878
        if(flags&CHIRP_ACL_ADMIN)   strcat(text,"a");
 
879
        if(flags&CHIRP_ACL_EXECUTE) strcat(text,"x");
 
880
        if(flags&CHIRP_ACL_RESERVE) {
 
881
                strcat(text,"v");
 
882
                strcat(text,"(");
 
883
                if(flags&CHIRP_ACL_RESERVE_READ)    strcat(text,"r");
 
884
                if(flags&CHIRP_ACL_RESERVE_WRITE)   strcat(text,"w");
 
885
                if(flags&CHIRP_ACL_RESERVE_LIST)    strcat(text,"l");
 
886
                if(flags&CHIRP_ACL_RESERVE_DELETE)  strcat(text,"d");
 
887
                if(flags&CHIRP_ACL_RESERVE_PUT)     strcat(text,"p");
 
888
                if(flags&CHIRP_ACL_RESERVE_RESERVE) strcat(text,"v");
 
889
                if(flags&CHIRP_ACL_RESERVE_ADMIN)   strcat(text,"a");
 
890
                if(flags&CHIRP_ACL_RESERVE_EXECUTE) strcat(text,"x");
 
891
                strcat(text,")");
 
892
        }
 
893
 
 
894
        if(text[0]==0) {
 
895
                strcpy(text,"n");
 
896
        }
 
897
 
 
898
        return text;
 
899
}
 
900
 
 
901
int chirp_acl_text_to_flags( const char *t )
 
902
{
 
903
        int flags=0;
 
904
 
 
905
        while(*t) {
 
906
                if( *t=='r' ) flags|=CHIRP_ACL_READ;
 
907
                if( *t=='w' ) flags|=CHIRP_ACL_WRITE;
 
908
                if( *t=='l' ) flags|=CHIRP_ACL_LIST;
 
909
                if( *t=='d' ) flags|=CHIRP_ACL_DELETE;
 
910
                if( *t=='p' ) flags|=CHIRP_ACL_PUT;
 
911
                if( *t=='a' ) flags|=CHIRP_ACL_ADMIN;
 
912
                if( *t=='x' ) flags|=CHIRP_ACL_EXECUTE;
 
913
                if( *t=='v' ) {
 
914
                        flags |= CHIRP_ACL_RESERVE;
 
915
                        if( t[1] == '(' ) {
 
916
                                t += 2;
 
917
                                while(*t && *t != ')'){
 
918
                                        if( *t=='r' ) flags|=CHIRP_ACL_RESERVE_READ;
 
919
                                        if( *t=='w' ) flags|=CHIRP_ACL_RESERVE_WRITE;
 
920
                                        if( *t=='l' ) flags|=CHIRP_ACL_RESERVE_LIST;
 
921
                                        if( *t=='d' ) flags|=CHIRP_ACL_RESERVE_DELETE;
 
922
                                        if( *t=='p' ) flags|=CHIRP_ACL_RESERVE_PUT;
 
923
                                        if( *t=='v' ) flags|=CHIRP_ACL_RESERVE_RESERVE;
 
924
                                        if( *t=='a' ) flags|=CHIRP_ACL_RESERVE_ADMIN;
 
925
                                        if( *t=='x' ) flags|=CHIRP_ACL_RESERVE_EXECUTE;
 
926
                                        ++t;
 
927
                                }
 
928
                        }
 
929
                }
 
930
                ++t;
 
931
        }
 
932
 
 
933
        return flags;
 
934
}
 
935
 
 
936
int chirp_acl_from_access_flags( int flags )
 
937
{
 
938
        int acl=0;
 
939
        if(flags&R_OK) acl|=CHIRP_ACL_READ;
 
940
        if(flags&W_OK) acl|=CHIRP_ACL_WRITE;
 
941
        if(flags&X_OK) acl|=CHIRP_ACL_EXECUTE;
 
942
        if(flags&F_OK) acl|=CHIRP_ACL_READ;
 
943
        if(acl==0)     acl|=CHIRP_ACL_READ;
 
944
        return acl;
 
945
}
 
946
 
 
947
int chirp_acl_from_open_flags( int flags )
 
948
{
 
949
        int acl = 0;
 
950
        if(flags&O_WRONLY) acl|=CHIRP_ACL_WRITE;
 
951
        if(flags&O_RDWR)   acl|=CHIRP_ACL_READ|CHIRP_ACL_WRITE;
 
952
        if(flags&O_CREAT)  acl|=CHIRP_ACL_WRITE;
 
953
        if(flags&O_TRUNC)  acl|=CHIRP_ACL_WRITE;
 
954
        if(flags&O_APPEND) acl|=CHIRP_ACL_WRITE;
 
955
        if(acl==0)         acl|=CHIRP_ACL_READ;
 
956
        return acl;
 
957
}
 
958
 
 
959
int chirp_acl_init_root( const char *path )
 
960
{
 
961
        char aclpath[CHIRP_PATH_MAX];
 
962
        char username[USERNAME_MAX];
 
963
        CHIRP_FILE *file;
 
964
 
 
965
        file = chirp_acl_open(path);
 
966
        if(file) {
 
967
                chirp_acl_close(file);
 
968
                return 1;
 
969
        }
 
970
 
 
971
        username_get(username);
 
972
 
 
973
        sprintf(aclpath,"%s/%s",path,CHIRP_ACL_BASE_NAME);
 
974
        file = cfs_fopen(aclpath,"w");
 
975
        if(file) {
 
976
                cfs_fprintf(file,"unix:%s %s\n",username,chirp_acl_flags_to_text(CHIRP_ACL_READ|CHIRP_ACL_WRITE|CHIRP_ACL_DELETE|CHIRP_ACL_LIST|CHIRP_ACL_ADMIN));
 
977
                cfs_fclose(file);
 
978
                return 1;
 
979
        } else {
 
980
                return 0;
 
981
        }
 
982
}
 
983
 
 
984
int chirp_acl_init_copy( const char *path )
 
985
{
 
986
        char oldpath[CHIRP_LINE_MAX];
 
987
        char newpath[CHIRP_LINE_MAX];
 
988
        char subject[CHIRP_LINE_MAX];
 
989
        CHIRP_FILE *oldfile;
 
990
        CHIRP_FILE *newfile;
 
991
        int result = 0;
 
992
        int flags;
 
993
 
 
994
        sprintf(oldpath,"%s/..",path);
 
995
        sprintf(newpath,"%s/%s",path,CHIRP_ACL_BASE_NAME);
 
996
 
 
997
        oldfile = chirp_acl_open(oldpath);
 
998
        if(oldfile) {
 
999
                newfile = cfs_fopen(newpath,"w");
 
1000
                if(newfile) {
 
1001
                        while(chirp_acl_read(oldfile,subject,&flags)) {
 
1002
                                cfs_fprintf(newfile,"%s %s\n",subject,chirp_acl_flags_to_text(flags));
 
1003
                        }
 
1004
                        cfs_fclose(newfile);
 
1005
                        result = 1;
 
1006
                }
 
1007
                chirp_acl_close(oldfile);
 
1008
        }
 
1009
 
 
1010
        return result;
 
1011
}
 
1012
 
 
1013
int chirp_acl_init_reserve( const char *root, const char *path, const char *subject )
 
1014
{
 
1015
        char dirname[CHIRP_PATH_MAX];
 
1016
        char aclpath[CHIRP_PATH_MAX];
 
1017
        CHIRP_FILE *file;
 
1018
        int newflags = 0;
 
1019
        int aclflags;
 
1020
 
 
1021
        string_dirname(path,dirname);
 
1022
 
 
1023
        if (!do_chirp_acl_get(root,dirname,subject,&aclflags))
 
1024
                return 0;
 
1025
 
 
1026
        if(aclflags&CHIRP_ACL_RESERVE_READ)
 
1027
                newflags|=CHIRP_ACL_READ;
 
1028
        if(aclflags&CHIRP_ACL_RESERVE_WRITE)
 
1029
                newflags|=CHIRP_ACL_WRITE;
 
1030
        if(aclflags&CHIRP_ACL_RESERVE_LIST)
 
1031
                newflags|=CHIRP_ACL_LIST;
 
1032
        if(aclflags&CHIRP_ACL_RESERVE_DELETE)
 
1033
                newflags|=CHIRP_ACL_DELETE;
 
1034
        if(aclflags&CHIRP_ACL_RESERVE_PUT)
 
1035
                newflags|=CHIRP_ACL_PUT;
 
1036
        if(aclflags&CHIRP_ACL_RESERVE_RESERVE)
 
1037
                newflags|=CHIRP_ACL_RESERVE;
 
1038
        if(aclflags&CHIRP_ACL_RESERVE_ADMIN)
 
1039
                newflags|=CHIRP_ACL_ADMIN;
 
1040
        if(aclflags&CHIRP_ACL_RESERVE_EXECUTE)
 
1041
                newflags|=CHIRP_ACL_EXECUTE;
 
1042
 
 
1043
        /*
 
1044
        compatibility note:
 
1045
        If no sub-rights are associated with the v right,
 
1046
        then give all of the ordinary subrights.
 
1047
        */
 
1048
 
 
1049
        if(newflags==0) newflags = CHIRP_ACL_READ|CHIRP_ACL_WRITE|CHIRP_ACL_LIST|CHIRP_ACL_DELETE|CHIRP_ACL_ADMIN;
 
1050
 
 
1051
        sprintf(aclpath,"%s/%s",path,CHIRP_ACL_BASE_NAME);
 
1052
        file = cfs_fopen(aclpath,"w");
 
1053
        if(file) {
 
1054
                cfs_fprintf(file,"%s %s\n",subject,chirp_acl_flags_to_text(newflags));
 
1055
                cfs_fclose(file);
 
1056
                return 1;
 
1057
        } else {
 
1058
                return 0;
 
1059
        }
 
1060
}
 
1061
 
 
1062
static int delete_dir (const char *path)
 
1063
{
 
1064
  int result = 1;
 
1065
  const char *entry;
 
1066
  void *dir;
 
1067
 
 
1068
  dir = cfs->opendir(path);
 
1069
  if (!dir) {
 
1070
    if (errno == ENOTDIR)
 
1071
      return cfs->unlink(path) == 0;
 
1072
    else
 
1073
      return errno == ENOENT;
 
1074
  }
 
1075
  while ((entry = cfs->readdir(dir))) {
 
1076
    char subdir[PATH_MAX];
 
1077
    if (!strcmp(entry, ".")) continue;
 
1078
    if (!strcmp(entry, "..")) continue;
 
1079
    sprintf(subdir,"%s/%s",path,entry);
 
1080
    if(!delete_dir(subdir)) {
 
1081
      result = 0;
 
1082
    }
 
1083
  }
 
1084
  cfs->closedir(dir);
 
1085
  return cfs->rmdir(path) == 0 ? result : 0;
 
1086
}
 
1087
 
 
1088
/*
 
1089
  Because each directory now contains an ACL,
 
1090
  a simple rmdir will not work on a (perceived) empty directory.
 
1091
  This function checks to see if the directory is empty,
 
1092
  save for the ACL file, and deletes it if so.
 
1093
  Otherwise, it determines an errno and returns with failure.
 
1094
*/
 
1095
 
 
1096
int chirp_acl_rmdir( const char *path )
 
1097
{
 
1098
        void *dir;
 
1099
        char *d;
 
1100
 
 
1101
        dir = cfs->opendir(path);
 
1102
        if(dir) {
 
1103
                while((d=cfs->readdir(dir))) {
 
1104
                        if(!strcmp(d,".")) continue;
 
1105
                        if(!strcmp(d,"..")) continue;
 
1106
                        if(!strcmp(d,CHIRP_ACL_BASE_NAME)) continue;
 
1107
                        cfs->closedir(dir);
 
1108
                        errno = ENOTEMPTY;
 
1109
                        return -1;
 
1110
                }
 
1111
                cfs->closedir(dir);
 
1112
                delete_dir(dir);
 
1113
                return 0;
 
1114
        } else {
 
1115
                errno = ENOENT;
 
1116
                return -1;
 
1117
        }
 
1118
}