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_modify(const char *subject, const char *ticket_subject, const char *path, int flags) { char ticket_filename[CHIRP_PATH_MAX]; const char *digest; char *esubject; struct chirp_ticket ct; int status = 0; if(!chirp_ticket_isticketsubject(ticket_subject, &digest)) { errno = EINVAL; return -1; } /* Note about tickets making tickets: * We check whether the ticket has the rights associated with the mask in * the next line. So, a ticket can only make a ticket with rights it * already has. */ if(!chirp_acl_check_dir(path, subject, flags)) return -1; /* you don't have the rights for the mask */ if(!chirp_acl_whoami(subject, &esubject)) return -1; chirp_ticket_filename(ticket_filename, ticket_subject, NULL); if(!ticket_read(ticket_filename, &ct)) { free(esubject); return -1; } if(strcmp(esubject, ct.subject) == 0 || strcmp(chirp_super_user, subject) == 0) { size_t n; int replaced = 0; for(n = 0; n < ct.nrights; n++) { if(strcmp(ct.rights[n].directory, path) == 0) { free(ct.rights[n].acl); ct.rights[n].acl = xxstrdup(chirp_acl_flags_to_text(flags)); /* replace old acl mask */ replaced = 1; } } if(!replaced) { char directory[CHIRP_PATH_MAX]; assert(strlen(path)); ct.rights = xxrealloc(ct.rights, sizeof(*ct.rights) * (++ct.nrights) + 1); path_collapse(path, directory, 1); ct.rights[ct.nrights - 1].directory = xxstrdup(directory); ct.rights[ct.nrights - 1].acl = xxstrdup(chirp_acl_flags_to_text(flags)); } status = ticket_write(ticket_filename, &ct); } else { errno = EACCES; status = -1; } chirp_ticket_free(&ct); free(esubject); return status; }
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; }
static INT64_T chirp_thirdput_recursive(const char *subject, const char *lpath, const char *hostname, const char *rpath, const char *hostsubject, time_t stoptime) { struct chirp_stat info; INT64_T size = 0, result; char newlpath[CHIRP_PATH_MAX]; char newrpath[CHIRP_PATH_MAX]; int save_errno; int my_target_acl = 0; result = cfs->lstat(lpath, &info); if(result < 0) return result; if(S_ISDIR(info.cst_mode)) { CHIRP_FILE *aclfile; struct chirp_dir *dir; struct chirp_dirent *d; char aclsubject[CHIRP_PATH_MAX]; int aclflags; if(!chirp_acl_check_dir(lpath, subject, CHIRP_ACL_LIST)) return -1; // create the directory, but do not fail if it already exists result = chirp_reli_mkdir(hostname, rpath, 0700, stoptime); if(result < 0 && errno != EEXIST) return result; // set the access control to include the initiator result = chirp_reli_setacl(hostname, rpath, subject, "rwldax", stoptime); if(result < 0 && errno != EACCES) return result; // transfer each of the directory contents recurisvely dir = cfs->opendir(lpath); while((d = cfs->readdir(dir))) { if(!strcmp(d->name, ".")) continue; if(!strcmp(d->name, "..")) continue; if(!strncmp(d->name, ".__", 3)) continue; sprintf(newlpath, "%s/%s", lpath, d->name); sprintf(newrpath, "%s/%s", rpath, d->name); result = chirp_thirdput_recursive(subject, newlpath, hostname, newrpath, hostsubject, stoptime); if(result >= 0) { size += result; } else { result = -1; break; } } save_errno = errno; // finally, set the acl to duplicate the source directory, // but do not take away permissions from me or the initiator cfs->closedir(dir); aclfile = chirp_acl_open(lpath); if(!aclfile) return -1; while(chirp_acl_read(aclfile, aclsubject, &aclflags)) { // wait until the last minute to take away my permissions if(!strcmp(aclsubject, hostsubject)) { my_target_acl = aclflags; } // do not take permissions away from the initiator if(!strcmp(aclsubject, subject)) { continue; } chirp_reli_setacl(hostname, rpath, aclsubject, chirp_acl_flags_to_text(aclflags), stoptime); } chirp_acl_close(aclfile); // after setting everything else, then set my permissions from the ACL chirp_reli_setacl(hostname, rpath, hostsubject, chirp_acl_flags_to_text(my_target_acl), stoptime); errno = save_errno; if(result >= 0) { return size; } else { return -1; } } else if(S_ISLNK(info.cst_mode)) { if(!chirp_acl_check(lpath, subject, CHIRP_ACL_READ)) return -1; result = cfs->readlink(lpath, newlpath, sizeof(newlpath)); if(result < 0) return -1; return chirp_reli_symlink(hostname, newlpath, rpath, stoptime); } else if(S_ISREG(info.cst_mode)) { if(!chirp_acl_check(lpath, subject, CHIRP_ACL_READ)) return -1; int fd = cfs->open(lpath, O_RDONLY, 0); if(fd >= 0) { struct chirp_file *F = chirp_reli_open(hostname, rpath, O_WRONLY|O_CREAT|O_TRUNC, info.cst_mode, stoptime); if(F) { char buffer[65536]; INT64_T offset = 0; INT64_T nread; while ((nread = cfs->pread(fd, buffer, sizeof(buffer), offset)) > 0) { INT64_T nwritten = 0; while (nwritten < nread) { INT64_T nwrite = chirp_reli_pwrite(F, buffer+nwritten, nread-nwritten, offset, stoptime); if (nwrite == -1) { save_errno = errno; cfs->close(fd); chirp_reli_close(F, stoptime); errno = save_errno; return -1; } nwritten += nwrite; offset += nwrite; } } if(nread == -1) offset = -1; save_errno = errno; cfs->close(fd); chirp_reli_close(F, stoptime); errno = save_errno; return offset; } else { save_errno = errno; cfs->close(fd); errno = save_errno; return -1; } } else { return -1; } } else { return 0; } return -1; }
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; }