int chirp_acl_check_dir(const char *dirname, const char *subject, int flags) { int myflags = 0; int paflags = 0; if(cfs->do_acl_check() == 0) return 1; /* If flags is CHIRP_ACL_DELETE, then check if we have delete permissions in the *containing directory*. */ if (flags & CHIRP_ACL_DELETE) { char dir[CHIRP_PATH_MAX]; path_dirname(dirname, dir); if(!do_chirp_acl_get(dir, subject, &paflags)) { /* Applications are very sensitive to this error condition. A * missing ACL file indicates permission denied, but a missing * directory entirely indicates no such entry. */ if(cfs_isdir(dirname)) { errno = EACCES; } else { errno = ENOENT; } return 0; } } /* other flags require checking the actual directory... */ if ((flags & ~CHIRP_ACL_DELETE)) { if(!do_chirp_acl_get(dirname, subject, &myflags)) { /* Applications are very sensitive to this error condition. A * missing ACL file indicates permission denied, but a missing * directory entirely indicates no such entry. */ if(cfs_isdir(dirname)) { errno = EACCES; } else { errno = ENOENT; } return 0; } } myflags |= (paflags & CHIRP_ACL_DELETE); /* The superuser can implicitly list and admin */ if(strcmp(subject, chirp_super_user) == 0) { myflags |= CHIRP_ACL_LIST | CHIRP_ACL_ADMIN; } if((flags & myflags) == flags) { return 1; } else { errno = EACCES; return 0; } }
int chirp_acl_check_dir(const char *dirname, const char *subject, int flags) { int myflags; if(cfs->do_acl_check() == 0) return 1; if(!do_chirp_acl_get(dirname, subject, &myflags)) { /* Applications are very sensitive to this error condition. A missing ACL file indicates permission denied, but a missing directory entirely indicates no such entry. */ if(cfs_isdir(dirname)) { errno = EACCES; } else { errno = ENOENT; } return 0; } /* The superuser can implicitly list and admin */ if(chirp_super_user && !strcmp(subject, chirp_super_user)) { myflags |= CHIRP_ACL_LIST | CHIRP_ACL_ADMIN; } if((flags & myflags) == flags) { return 1; } else { errno = EACCES; return 0; } }
static int do_chirp_acl_check(const char *filename, const char *subject, int flags, int follow_links) { char linkname[CHIRP_PATH_MAX]; char temp[CHIRP_PATH_MAX]; char dirname[CHIRP_PATH_MAX]; if(cfs->do_acl_check()==0) return 1; /* Symbolic links require special handling. If requested, follow the link and look for rights in that directory. */ if(follow_links && flags != CHIRP_ACL_DELETE) { int length = cfs->readlink(filename, linkname, sizeof(linkname)); if(length > 0) { linkname[length] = 0; /* If the link is relative, construct a full path */ if(linkname[0] != '/') { sprintf(temp, "%s/../%s", filename, linkname); string_collapse_path(temp, linkname, 1); } /* Use the linkname now to look up the ACL */ debug(D_DEBUG, "symlink %s points to %s", filename, linkname); filename = linkname; } } /* If the file being checked is an ACL file, then it may be written with the admin flag, but never deleted. */ if(!strcmp(string_back(filename, CHIRP_ACL_BASE_LENGTH), CHIRP_ACL_BASE_NAME)) { if(flags & CHIRP_ACL_DELETE) { errno = EACCES; return 0; } if(flags & CHIRP_ACL_WRITE) { flags &= ~CHIRP_ACL_WRITE; flags |= CHIRP_ACL_ADMIN; } } /* Now get the name of the directory containing the file */ string_collapse_path(filename, temp, 1); if(!cfs_isdir(temp)) string_dirname(temp, dirname); else strcpy(dirname, temp); /* Perform the permissions check on that directory. */ return chirp_acl_check_dir(dirname, subject, flags); }
int chirp_acl_ticket_create(const char *subject, const char *newsubject, const char *ticket, const char *duration) { time_t now; /*, delta; */ time_t offset = (time_t) strtoul(duration, NULL, 10); const char *digest; char ticket_subject[CHIRP_PATH_MAX]; char ticket_filename[CHIRP_PATH_MAX]; char expiration[128]; now = time(NULL); now = mktime(gmtime(&now)); /* convert to UTC */ sprintf(expiration, "%lu", (unsigned long) (now + offset)); /* Note about tickets making tickets: * A ticket created by a ticket authenticated user has the same effective * subject (see the ticket_register RPC in chirp_server.c). Also, the * expiration time is less than or equal to the expiration time of the * ticket used to authenticate. */ if(chirp_ticket_isticketsubject(subject, &digest)) { struct chirp_ticket ct; chirp_ticket_filename(ticket_filename, subject, NULL); if(!ticket_read(ticket_filename, &ct)) return -1; if(ct.expiration < now + offset) { sprintf(expiration, "%lu", (unsigned long) ct.expiration); } chirp_ticket_free(&ct); } if(!cfs_isdir("/")) { errno = ENOTDIR; return -1; } chirp_ticket_name(ticket, ticket_subject, ticket_filename); CHIRP_FILE *f = cfs_fopen(ticket_filename, "w"); if(!f) { errno = EACCES; return -1; } cfs_fprintf(f, "subject \"%s\"\n", newsubject); cfs_fprintf(f, "expiration \"%s\"\n", expiration); cfs_fprintf(f, "ticket \"%s\"\n", ticket); cfs_fprintf(f, "rights \"/\" \"n\"\n"); cfs_fflush(f); int result = cfs_ferror(f); if(result) { errno = EACCES; return -1; } cfs_fclose(f); return 0; }
static int search_directory(const char *subject, const char *const base, char fullpath[CHIRP_PATH_MAX], const char *pattern, int flags, struct link *l, time_t stoptime) { if(strlen(pattern) == 0) return 0; debug(D_DEBUG, "search_directory(subject = `%s', base = `%s', fullpath = `%s', pattern = `%s', flags = %d, ...)", subject, base, fullpath, pattern, flags); int access_flags = search_to_access(flags); int includeroot = flags & CHIRP_SEARCH_INCLUDEROOT; int metadata = flags & CHIRP_SEARCH_METADATA; int stopatfirst = flags & CHIRP_SEARCH_STOPATFIRST; int result = 0; struct chirp_dir *dirp = cfs->opendir(fullpath); char *current = fullpath + strlen(fullpath); /* point to end to current directory */ if(dirp) { errno = 0; struct chirp_dirent *entry; while((entry = cfs->readdir(dirp))) { char *name = entry->name; if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0 || strncmp(name, ".__", 3) == 0) continue; sprintf(current, "/%s", name); if(search_match_file(pattern, base)) { const char *matched; if(includeroot) { if(base - fullpath == 1 && fullpath[0] == '/') { matched = base; } else { matched = fullpath; } } else { matched = base; } result += 1; if(access_flags == F_OK || cfs->access(fullpath, access_flags) == 0) { if(metadata) { /* A match was found, but the matched file couldn't be statted. Generate a result and an error. */ if(entry->lstatus == -1) { link_putfstring(l, "0:%s::\n", stoptime, matched); // FIXME is this a bug? link_putfstring(l, "%d:%d:%s:\n", stoptime, errno, CHIRP_SEARCH_ERR_STAT, matched); } else { BUFFER_STACK_ABORT(B, 4096) chirp_stat_encode(B, &entry->info); link_putfstring(l, "0:%s:%s:\n", stoptime, matched, buffer_tostring(B)); if(stopatfirst) return 1; } } else { link_putfstring(l, "0:%s::\n", stoptime, matched); if(stopatfirst) return 1; } } /* FIXME access failure */ } if(cfs_isdir(fullpath) && search_should_recurse(base, pattern)) { if(chirp_acl_check_dir(fullpath, subject, CHIRP_ACL_LIST)) { int n = search_directory(subject, base, fullpath, pattern, flags, l, stoptime); if(n > 0) { result += n; if(stopatfirst) return result; } } else { link_putfstring(l, "%d:%d:%s:\n", stoptime, EPERM, CHIRP_SEARCH_ERR_OPEN, fullpath); } } *current = '\0'; /* clear current entry */ errno = 0; } if(errno) link_putfstring(l, "%d:%d:%s:\n", stoptime, errno, CHIRP_SEARCH_ERR_READ, fullpath); errno = 0; cfs->closedir(dirp); if(errno) link_putfstring(l, "%d:%d:%s:\n", stoptime, errno, CHIRP_SEARCH_ERR_CLOSE, fullpath); } else { link_putfstring(l, "%d:%d:%s:\n", stoptime, errno, CHIRP_SEARCH_ERR_OPEN, fullpath); } return result; }
int chirp_acl_set(const char *dirname, const char *subject, int flags, int reset_acl) { char aclname[CHIRP_PATH_MAX]; char newaclname[CHIRP_PATH_MAX]; char aclsubject[CHIRP_LINE_MAX]; int aclflags; CHIRP_FILE *aclfile, *newaclfile; int result; int replaced_acl_entry = 0; if(!cfs_isdir(dirname)) { errno = ENOTDIR; return -1; } sprintf(aclname, "%s/%s", dirname, CHIRP_ACL_BASE_NAME); sprintf(newaclname, "%s/%s.%d", dirname, CHIRP_ACL_BASE_NAME, (int) getpid()); if(reset_acl) { aclfile = cfs_fopen_local("/dev/null", "r"); } else { aclfile = chirp_acl_open(dirname); /* If the acl never existed, then we can simply create it. */ if(!aclfile && errno == ENOENT) { aclfile = cfs_fopen_local("/dev/null", "r"); /* use local... */ } } if(!aclfile) { errno = EACCES; return -1; } replaced_acl_entry = 0; newaclfile = cfs_fopen(newaclname, "w"); if(!newaclfile) { cfs_fclose(aclfile); errno = EACCES; return -1; } while(chirp_acl_read(aclfile, aclsubject, &aclflags)) { if(!strcmp(subject, aclsubject)) { aclflags = flags; replaced_acl_entry = 1; } if(aclflags != 0) { cfs_fprintf(newaclfile, "%s %s\n", aclsubject, chirp_acl_flags_to_text(aclflags)); } } cfs_fclose(aclfile); if(!replaced_acl_entry) { cfs_fprintf(newaclfile, "%s %s\n", subject, chirp_acl_flags_to_text(flags)); } /* Need to force a write in order to get response from ferror */ cfs_fflush(newaclfile); result = cfs_ferror(newaclfile); cfs_fclose(newaclfile); if(result) { errno = EACCES; result = -1; } else { result = cfs->rename(newaclname, aclname); if(result < 0) { cfs->unlink(newaclname); errno = EACCES; result = -1; } } return result; }
static int search_directory(const char *subject, const char * const base, char *fullpath, const char *pattern, int flags, struct link *l, time_t stoptime) { if(strlen(pattern) == 0) return 0; debug(D_DEBUG, "search_directory(subject = `%s', base = `%s', fullpath = `%s', pattern = `%s', flags = %d, ...)", subject, base, fullpath, pattern, flags); int access_flags = search_to_access(flags); int includeroot = flags & CHIRP_SEARCH_INCLUDEROOT; int metadata = flags & CHIRP_SEARCH_METADATA; int stopatfirst = flags & CHIRP_SEARCH_STOPATFIRST; int result = 0; void *dirp = chirp_fs_local_opendir(fullpath); char *current = fullpath + strlen(fullpath); /* point to end to current directory */ if(dirp) { errno = 0; struct chirp_dirent *entry; while((entry = chirp_fs_local_readdir(dirp))) { char *name = entry->name; if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0 || strncmp(name, ".__", 3) == 0) continue; sprintf(current, "/%s", name); if(search_match_file(pattern, base)) { const char *matched = includeroot ? fullpath+strlen(chirp_root_path) : base; /* add strlen(chirp_root_path) to strip out */ result += 1; if (access_flags == F_OK || chirp_fs_local_access(fullpath, access_flags) == 0) { if(metadata) { /* A match was found, but the matched file couldn't be statted. Generate a result and an error. */ struct chirp_stat buf; if((chirp_fs_local_stat(fullpath, &buf)) == -1) { link_putfstring(l, "0:%s::\n", stoptime, matched); // FIXME is this a bug? link_putfstring(l, "%d:%d:%s:\n", stoptime, errno, CHIRP_SEARCH_ERR_STAT, matched); } else { link_putfstring(l, "0:%s:%s:\n", stoptime, matched, chirp_stat_string(&buf)); if(stopatfirst) return 1; } } else { link_putfstring(l, "0:%s::\n", stoptime, matched); if(stopatfirst) return 1; } } /* FIXME access failure */ } if(cfs_isdir(fullpath) && search_should_recurse(base, pattern)) { if(chirp_acl_check_dir(fullpath, subject, CHIRP_ACL_LIST)) { int n = search_directory(subject, base, fullpath, pattern, flags, l, stoptime); if(n > 0) { result += n; if(stopatfirst) return result; } } else { link_putfstring(l, "%d:%d:%s:\n", stoptime, EPERM, CHIRP_SEARCH_ERR_OPEN, fullpath); } } *current = '\0'; /* clear current entry */ errno = 0; } if(errno) link_putfstring(l, "%d:%d:%s:\n", stoptime, errno, CHIRP_SEARCH_ERR_READ, fullpath); errno = 0; chirp_alloc_closedir(dirp); if(errno) link_putfstring(l, "%d:%d:%s:\n", stoptime, errno, CHIRP_SEARCH_ERR_CLOSE, fullpath); } else { link_putfstring(l, "%d:%d:%s:\n", stoptime, errno, CHIRP_SEARCH_ERR_OPEN, fullpath); } return result; }