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 *ticket_dir, 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++) { char safewhere[CHIRP_PATH_MAX]; char where[CHIRP_PATH_MAX]; sprintf(safewhere, "%s/%s", ticket_dir, ct.rights[n].directory); string_collapse_path(safewhere, where, 1); if(strcmp(where, 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) { assert(strlen(path) >= strlen(ticket_dir)); ct.rights = xxrealloc(ct.rights, sizeof(*ct.rights) * (++ct.nrights) + 1); char directory[CHIRP_PATH_MAX]; char collapsed_directory[CHIRP_PATH_MAX]; sprintf(directory, "/%s", path + strlen(ticket_dir)); string_collapse_path(directory, collapsed_directory, 1); ct.rights[ct.nrights - 1].directory = xxstrdup(collapsed_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 void make_acl_name(const char *filename, int get_parent, char *aclname) { char tmp[CHIRP_PATH_MAX]; sprintf(tmp, "%s/%s", filename, CHIRP_ACL_BASE_NAME); string_collapse_path(tmp, aclname, 1); }
static int do_chirp_acl_get(const char *dirname, const char *subject, int *totalflags) { CHIRP_FILE *aclfile; char aclsubject[CHIRP_LINE_MAX]; int aclflags; errno = 0; *totalflags = 0; /* if the subject is a ticket, then we need the rights we have for the * directory along with the rights of the subject in that directory */ const char *digest; if(chirp_ticket_isticketsubject(subject, &digest)) { /* open the ticket file, read the public key */ char ticket_filename[CHIRP_PATH_MAX]; struct chirp_ticket ct; chirp_ticket_filename(ticket_filename, subject, NULL); if(!ticket_read(ticket_filename, &ct)) return 0; if(!do_chirp_acl_get(dirname, ct.subject, totalflags)) { chirp_ticket_free(&ct); return 0; } size_t i; size_t longest = 0; int mask = 0; for(i = 0; i < ct.nrights; i++) { char safewhere[CHIRP_PATH_MAX]; char where[CHIRP_PATH_MAX]; sprintf(safewhere, "%s/%s", chirp_ticket_path, ct.rights[i].directory); string_collapse_path(safewhere, where, 1); if(strncmp(dirname, where, strlen(where)) == 0) { if(strlen(where) > longest) { longest = strlen(where); mask = chirp_acl_text_to_flags(ct.rights[i].acl); } } } *totalflags &= mask; } else { aclfile = chirp_acl_open(dirname); if(aclfile) { while(chirp_acl_read(aclfile, aclsubject, &aclflags)) { if(string_match(aclsubject, subject)) { *totalflags |= aclflags; } else if(!strncmp(aclsubject, "group:", 6)) { if(chirp_group_lookup(aclsubject, subject)) { *totalflags |= aclflags; } } } chirp_acl_close(aclfile); } else { return 0; } } if(read_only_mode) { *totalflags &= CHIRP_ACL_READ | CHIRP_ACL_LIST; } return 1; }