int read_pseudo_def(struct pseudo **pseudo, char *def) { int n, bytes; unsigned int major = 0, minor = 0, mode; char filename[2048], type, suid[100], sgid[100], *ptr; long long uid, gid; struct pseudo_dev *dev; n = sscanf(def, "%s %c %o %s %s %n", filename, &type, &mode, suid, sgid, &bytes); if(n < 5) { ERROR("Not enough or invalid arguments in pseudo file " "definition\n"); goto error; } switch(type) { case 'b': case 'c': n = sscanf(def + bytes, "%u %u", &major, &minor); if(n < 2) { ERROR("Not enough or invalid arguments in pseudo file " "definition\n"); goto error; } if(major > 0xfff) { ERROR("Major %d out of range\n", major); goto error; } if(minor > 0xfffff) { ERROR("Minor %d out of range\n", minor); goto error; } case 'f': if(def[bytes] == '\0') { ERROR("Not enough arguments in pseudo file " "definition\n"); goto error; } break; case 'd': case 'm': break; default: ERROR("Unsupported type %c\n", type); goto error; } if(mode > 07777) { ERROR("Mode %o out of range\n", mode); goto error; } uid = strtoll(suid, &ptr, 10); if(*ptr == '\0') { if(uid < 0 || uid > ((1LL << 32) - 1)) { ERROR("Uid %s out of range\n", suid); goto error; } } else { struct passwd *pwuid = getpwnam(suid); if(pwuid) uid = pwuid->pw_uid; else { ERROR("Uid %s invalid uid or unknown user\n", suid); goto error; } } gid = strtoll(sgid, &ptr, 10); if(*ptr == '\0') { if(gid < 0 || gid > ((1LL << 32) - 1)) { ERROR("Gid %s out of range\n", sgid); goto error; } } else { struct group *grgid = getgrnam(sgid); if(grgid) gid = grgid->gr_gid; else { ERROR("Gid %s invalid uid or unknown user\n", sgid); goto error; } } switch(type) { case 'b': mode |= S_IFBLK; break; case 'c': mode |= S_IFCHR; break; case 'd': mode |= S_IFDIR; break; case 'f': mode |= S_IFREG; break; } dev = malloc(sizeof(struct pseudo_dev)); if(dev == NULL) BAD_ERROR("Failed to create pseudo_dev\n"); dev->type = type; dev->mode = mode; dev->uid = uid; dev->gid = gid; dev->major = major; dev->minor = minor; if(type == 'f') { int res; printf("Executing dynamic pseudo file\n"); printf("\t\"%s\"\n", def); res = exec_file(def + bytes, dev); if(res == -1) { ERROR("Failed to execute dynamic pseudo file definition" " \"%s\"\n", def); return FALSE; } add_pseudo_file(dev); } *pseudo = add_pseudo(*pseudo, dev, filename, filename); return TRUE; error: ERROR("Bad pseudo file definition \"%s\"\n", def); return FALSE; }
/* * Add pseudo device target to the set of pseudo devices. Pseudo_dev * describes the pseudo device attributes. */ struct pseudo *add_pseudo(struct pseudo *pseudo, struct pseudo_dev *pseudo_dev, char *target, char *alltarget) { char targname[1024]; int i; target = get_component(target, targname); if(pseudo == NULL) { if((pseudo = malloc(sizeof(struct pseudo))) == NULL) BAD_ERROR("failed to allocate pseudo file\n"); pseudo->names = 0; pseudo->count = 0; pseudo->name = NULL; } for(i = 0; i < pseudo->names; i++) if(strcmp(pseudo->name[i].name, targname) == 0) break; if(i == pseudo->names) { /* allocate new name entry */ pseudo->names ++; pseudo->name = realloc(pseudo->name, (i + 1) * sizeof(struct pseudo_entry)); if(pseudo->name == NULL) BAD_ERROR("failed to allocate pseudo file\n"); pseudo->name[i].name = strdup(targname); if(target[0] == '\0') { /* at leaf pathname component */ pseudo->name[i].pseudo = NULL; pseudo->name[i].pathname = strdup(alltarget); pseudo->name[i].dev = pseudo_dev; } else { /* recurse adding child components */ pseudo->name[i].dev = NULL; pseudo->name[i].pseudo = add_pseudo(NULL, pseudo_dev, target, alltarget); } } else { /* existing matching entry */ if(pseudo->name[i].pseudo == NULL) { /* No sub-directory which means this is the leaf * component of a pre-existing pseudo file. */ if(target[0] != '\0') { /* entry must exist as a 'd' type pseudo file */ if(pseudo->name[i].dev->type == 'd') /* recurse adding child components */ pseudo->name[i].pseudo = add_pseudo(NULL, pseudo_dev, target, alltarget); else ERROR("%s already exists as a non " "directory. Ignoring %s!\n", targname, alltarget); } else if(memcmp(pseudo_dev, pseudo->name[i].dev, sizeof(struct pseudo_dev)) != 0) ERROR("%s already exists as a different pseudo " "definition. Ignoring!\n", alltarget); else ERROR("%s already exists as an identical " "pseudo definition!\n", alltarget); } else { /* sub-directory exists which means this can only be a * 'd' type pseudo file */ if(target[0] == '\0') { if(pseudo->name[i].dev == NULL && pseudo_dev->type == 'd') { pseudo->name[i].pathname = strdup(alltarget); pseudo->name[i].dev = pseudo_dev; } else ERROR("%s already exists as a " "directory. Ignoring %s!\n", targname, alltarget); } else /* recurse adding child components */ add_pseudo(pseudo->name[i].pseudo, pseudo_dev, target, alltarget); } } return pseudo; }
int read_pseudo_def(char *def) { int n, bytes; unsigned int major = 0, minor = 0, mode; char type, *ptr; char suid[100], sgid[100]; /* overflow safe */ char *filename, *name; char *orig_def = def; long long uid, gid; struct pseudo_dev *dev; /* * Scan for filename, don't use sscanf() and "%s" because * that can't handle filenames with spaces */ filename = malloc(strlen(def) + 1); if(filename == NULL) MEM_ERROR(); for(name = filename; !isspace(*def) && *def != '\0';) { if(*def == '\\') { def ++; if (*def == '\0') break; } *name ++ = *def ++; } *name = '\0'; if(*filename == '\0') { ERROR("Not enough or invalid arguments in pseudo file " "definition \"%s\"\n", orig_def); goto error; } n = sscanf(def, " %c %o %99s %99s %n", &type, &mode, suid, sgid, &bytes); def += bytes; if(n < 4) { ERROR("Not enough or invalid arguments in pseudo file " "definition \"%s\"\n", orig_def); switch(n) { case -1: /* FALLTHROUGH */ case 0: ERROR("Read filename, but failed to read or match " "type\n"); break; case 1: ERROR("Read filename and type, but failed to read or " "match octal mode\n"); break; case 2: ERROR("Read filename, type and mode, but failed to " "read or match uid\n"); break; default: ERROR("Read filename, type, mode and uid, but failed " "to read or match gid\n"); break; } goto error; } switch(type) { case 'b': /* FALLTHROUGH */ case 'c': n = sscanf(def, "%u %u %n", &major, &minor, &bytes); def += bytes; if(n < 2) { ERROR("Not enough or invalid arguments in %s device " "pseudo file definition \"%s\"\n", type == 'b' ? "block" : "character", orig_def); if(n < 1) ERROR("Read filename, type, mode, uid and gid, " "but failed to read or match major\n"); else ERROR("Read filename, type, mode, uid, gid " "and major, but failed to read or " "match minor\n"); goto error; } if(major > 0xfff) { ERROR("Major %d out of range\n", major); goto error; } if(minor > 0xfffff) { ERROR("Minor %d out of range\n", minor); goto error; } /* FALLTHROUGH */ case 'd': /* FALLTHROUGH */ case 'm': /* * Check for trailing junk after expected arguments */ if(def[0] != '\0') { ERROR("Unexpected tailing characters in pseudo file " "definition \"%s\"\n", orig_def); goto error; } break; case 'f': if(def[0] == '\0') { ERROR("Not enough arguments in dynamic file pseudo " "definition \"%s\"\n", orig_def); ERROR("Expected command, which can be an executable " "or a piece of shell script\n"); goto error; } break; default: ERROR("Unsupported type %c\n", type); goto error; } if(mode > 07777) { ERROR("Mode %o out of range\n", mode); goto error; } uid = strtoll(suid, &ptr, 10); if(*ptr == '\0') { if(uid < 0 || uid > ((1LL << 32) - 1)) { ERROR("Uid %s out of range\n", suid); goto error; } } else { struct passwd *pwuid = getpwnam(suid); if(pwuid) uid = pwuid->pw_uid; else { ERROR("Uid %s invalid uid or unknown user\n", suid); goto error; } } gid = strtoll(sgid, &ptr, 10); if(*ptr == '\0') { if(gid < 0 || gid > ((1LL << 32) - 1)) { ERROR("Gid %s out of range\n", sgid); goto error; } } else { struct group *grgid = getgrnam(sgid); if(grgid) gid = grgid->gr_gid; else { ERROR("Gid %s invalid uid or unknown user\n", sgid); goto error; } } switch(type) { case 'b': mode |= S_IFBLK; break; case 'c': mode |= S_IFCHR; break; case 'd': mode |= S_IFDIR; break; case 'f': mode |= S_IFREG; break; } dev = malloc(sizeof(struct pseudo_dev)); if(dev == NULL) MEM_ERROR(); dev->type = type; dev->mode = mode; dev->uid = uid; dev->gid = gid; dev->major = major; dev->minor = minor; if(type == 'f') { dev->command = strdup(def); add_pseudo_file(dev); } pseudo = add_pseudo(pseudo, dev, filename, filename); free(filename); return TRUE; error: ERROR("Pseudo definitions should be of format\n"); ERROR("\tfilename d mode uid gid\n"); ERROR("\tfilename m mode uid gid\n"); ERROR("\tfilename b mode uid gid major minor\n"); ERROR("\tfilename c mode uid gid major minor\n"); ERROR("\tfilename f mode uid command\n"); free(filename); return FALSE; }
/* * Add pseudo device target to the set of pseudo devices. Pseudo_dev * describes the pseudo device attributes. */ struct pseudo *add_pseudo(struct pseudo *pseudo, struct pseudo_dev *pseudo_dev, char *target, char *alltarget) { char *targname; int i; target = get_component(target, &targname); if(pseudo == NULL) { pseudo = malloc(sizeof(struct pseudo)); if(pseudo == NULL) MEM_ERROR(); pseudo->names = 0; pseudo->count = 0; pseudo->name = NULL; } for(i = 0; i < pseudo->names; i++) if(strcmp(pseudo->name[i].name, targname) == 0) break; if(i == pseudo->names) { /* allocate new name entry */ pseudo->names ++; pseudo->name = realloc(pseudo->name, (i + 1) * sizeof(struct pseudo_entry)); if(pseudo->name == NULL) MEM_ERROR(); pseudo->name[i].name = targname; if(target[0] == '\0') { /* at leaf pathname component */ pseudo->name[i].pseudo = NULL; pseudo->name[i].pathname = strdup(alltarget); pseudo->name[i].dev = pseudo_dev; } else { /* recurse adding child components */ pseudo->name[i].dev = NULL; pseudo->name[i].pseudo = add_pseudo(NULL, pseudo_dev, target, alltarget); } } else { /* existing matching entry */ free(targname); if(pseudo->name[i].pseudo == NULL) { /* No sub-directory which means this is the leaf * component of a pre-existing pseudo file. */ if(target[0] != '\0') { /* * entry must exist as either a 'd' type or * 'm' type pseudo file */ if(pseudo->name[i].dev->type == 'd' || pseudo->name[i].dev->type == 'm') /* recurse adding child components */ pseudo->name[i].pseudo = add_pseudo(NULL, pseudo_dev, target, alltarget); else { ERROR_START("%s already exists as a " "non directory.", pseudo->name[i].name); ERROR_EXIT(". Ignoring %s!\n", alltarget); } } else if(memcmp(pseudo_dev, pseudo->name[i].dev, sizeof(struct pseudo_dev)) != 0) { ERROR_START("%s already exists as a different " "pseudo definition.", alltarget); ERROR_EXIT(" Ignoring!\n"); } else { ERROR_START("%s already exists as an identical " "pseudo definition!", alltarget); ERROR_EXIT(" Ignoring!\n"); } } else { if(target[0] == '\0') { /* * sub-directory exists, which means we can only * add a pseudo file of type 'd' or type 'm' */ if(pseudo->name[i].dev == NULL && (pseudo_dev->type == 'd' || pseudo_dev->type == 'm')) { pseudo->name[i].pathname = strdup(alltarget); pseudo->name[i].dev = pseudo_dev; } else { ERROR_START("%s already exists as a " "different pseudo definition.", pseudo->name[i].name); ERROR_EXIT(" Ignoring %s!\n", alltarget); } } else /* recurse adding child components */ add_pseudo(pseudo->name[i].pseudo, pseudo_dev, target, alltarget); } } return pseudo; }
int read_pseudo_def(struct pseudo **pseudo, char *def) { int n; unsigned int major = 0, minor = 0, mode; char filename[2048], type, suid[100], sgid[100], *ptr; long long uid, gid; struct pseudo_dev dev; n = sscanf(def, "%s %c %o %s %s %u %u", filename, &type, &mode, suid, sgid, &major, &minor); if(n < 5) { ERROR("Not enough or invalid arguments in pseudo file " "definition\n"); goto error; } switch(type) { case 'b': case 'c': if(n < 7) { ERROR("Not enough or invalid arguments in pseudo file " "definition\n"); goto error; } if(major > 0xfff) { ERROR("Major %d out of range\n", major); goto error; } if(minor > 0xfffff) { ERROR("Minor %d out of range\n", minor); goto error; } /* fall through */ case 'd': if(mode > 0777) { ERROR("Mode %o out of range\n", mode); goto error; } uid = strtoll(suid, &ptr, 10); if(*ptr == '\0') { if(uid < 0 || uid > ((1LL << 32) - 1)) { ERROR("Uid %s out of range\n", suid); goto error; } } else { struct passwd *pwuid = getpwnam(suid); if(pwuid) uid = pwuid->pw_uid; else { ERROR("Uid %s invalid uid or unknown user\n", suid); goto error; } } gid = strtoll(sgid, &ptr, 10); if(*ptr == '\0') { if(gid < 0 || gid > ((1LL << 32) - 1)) { ERROR("Gid %s out of range\n", sgid); goto error; } } else { struct group *grgid = getgrnam(sgid); if(grgid) gid = grgid->gr_gid; else { ERROR("Gid %s invalid uid or unknown user\n", sgid); goto error; } } break; default: ERROR("Unsupported type %c\n", type); goto error; } switch(type) { case 'b': mode |= S_IFBLK; break; case 'c': mode |= S_IFCHR; break; case 'd': mode |= S_IFDIR; break; } dev.type = type; dev.mode = mode; dev.uid = uid; dev.gid = gid; dev.major = major; dev.minor = minor; *pseudo = add_pseudo(*pseudo, &dev, filename, filename); return TRUE; error: ERROR("Bad pseudo file definition \"%s\"\n", def); return FALSE; }