int chirp_acl_ticket_delete(const char *subject, const char *ticket_subject) { 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; } 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) { status = cfs->unlink(ticket_filename); } else { errno = EACCES; status = -1; } chirp_ticket_free(&ct); free(esubject); return status; }
static int ticket_translate(const char *name, char *ticket_subject) { char command[PATH_MAX * 2 + 4096]; const char *dummy; if(chirp_ticket_isticketsubject(name, &dummy)) { strcpy(ticket_subject, name); return 1; } char *pk = xxmalloc(65536); /* max size of public key */ sprintf(command, "sed '/^\\s*#/d' < '%s' | openssl rsa -pubout 2> /dev/null", name); FILE *pkf = popen(command, "r"); int length = fread(pk, sizeof(char), 65536, pkf); if(length <= 0) { pclose(pkf); return 0; } pk[length] = 0; pclose(pkf); /* load the digest */ const char *digest = chirp_ticket_digest(pk); sprintf(ticket_subject, "ticket:%s", digest); return 1; }
void chirp_ticket_filename(const char *root, char *ticket_filename, const char *ticket_subject, const char *digest) { if(digest == NULL) { assert(ticket_subject); int result = chirp_ticket_isticketsubject(ticket_subject, &digest); assert(result); } sprintf(ticket_filename, "%s/" TICKET_FILENAME_FORMAT, root, digest); }
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; }
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; }
int chirp_acl_ticket_get(const char *subject, const char *ticket_subject, char **ticket_esubject, char **ticket, time_t * ticket_expiration, char ***ticket_rights) { char *esubject; if(!chirp_acl_whoami(subject, &esubject)) return -1; const char *digest; if(!chirp_ticket_isticketsubject(ticket_subject, &digest)) { errno = EINVAL; return -1; } struct chirp_ticket ct; char ticket_filename[CHIRP_PATH_MAX]; chirp_ticket_filename(ticket_filename, ticket_subject, NULL); if(!ticket_read(ticket_filename, &ct)) { free(esubject); errno = EINVAL; return -1; } if(strcmp(ct.subject, subject) == 0 || strcmp(subject, chirp_super_user) == 0) { *ticket_esubject = xxstrdup(ct.subject); *ticket = xxstrdup(ct.ticket); time_t now; time(&now); now = mktime(gmtime(&now)); /* convert to UTC */ *ticket_expiration = ct.expiration - now; size_t n; *ticket_rights = (char **) xxmalloc(sizeof(char *) * 2 * (ct.nrights + 1)); for(n = 0; n < ct.nrights; n++) { (*ticket_rights)[n * 2 + 0] = xxstrdup(ct.rights[n].directory); (*ticket_rights)[n * 2 + 1] = xxstrdup(ct.rights[n].acl); } (*ticket_rights)[n * 2 + 0] = NULL; (*ticket_rights)[n * 2 + 1] = NULL; chirp_ticket_free(&ct); free(esubject); return 0; } else { chirp_ticket_free(&ct); free(esubject); errno = EACCES; return -1; } }
int chirp_acl_whoami(const char *subject, char **esubject) { const char *digest; if(chirp_ticket_isticketsubject(subject, &digest)) { /* open the ticket file */ struct chirp_ticket ct; char ticket_filename[CHIRP_PATH_MAX]; chirp_ticket_filename(ticket_filename, subject, NULL); if(!ticket_read(ticket_filename, &ct)) return 0; *esubject = xxstrdup(ct.subject); chirp_ticket_free(&ct); return 1; } else { *esubject = xxstrdup(subject); return 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 where[CHIRP_PATH_MAX]; path_collapse(ct.rights[i].directory, 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; }