/* * range_exists: Check whether @owner owns any ranges * * @db: database to query * @owner: owner being queried * * Returns true if @owner owns any subuid ranges, false otherwise. */ static const bool range_exists(struct commonio_db *db, const char *owner) { const struct subordinate_range *range; commonio_rewind(db); while ((range = commonio_next(db)) != NULL) { if (0 == strcmp(range->owner, owner)) return true; } return false; }
/* * find_free_range: find an unused consecutive sequence of ids to allocate * to a user. * @db: database to search * @min: the first uid in the range to find * @max: the highest uid to find * @count: the number of uids needed * * Return the lowest new uid, or ULONG_MAX on failure. */ static unsigned long find_free_range(struct commonio_db *db, unsigned long min, unsigned long max, unsigned long count) { const struct subordinate_range *range; unsigned long low, high; /* When given invalid parameters fail */ if ((count == 0) || (max < min)) goto fail; /* Sort by range then by owner */ commonio_sort (db, subordinate_range_cmp); commonio_rewind(db); low = min; while ((range = commonio_next(db)) != NULL) { unsigned long first = range->start; unsigned long last = first + range->count - 1; /* Find the top end of the hole before this range */ high = first; /* Don't allocate IDs after max (included) */ if (high > max + 1) { high = max + 1; } /* Is the hole before this range large enough? */ if ((high > low) && ((high - low) >= count)) return low; /* Compute the low end of the next hole */ if (low < (last + 1)) low = last + 1; if (low > max) goto fail; } /* Is the remaining unclaimed area large enough? */ if (((max - low) + 1) >= count) return low; fail: return ULONG_MAX; }
int spw_rewind(void) { return commonio_rewind(&shadow_db); }
int gr_rewind (void) { return commonio_rewind (&group_db); }
/* * find_range: find a range which @owner is authorized to use which includes * subuid @val. * * @db: database to query * @owner: owning uid being queried * @val: subuid being searched for. * * Returns a range of subuids belonging to @owner and including the subuid * @val, or NULL if no such range exists. */ static const struct subordinate_range *find_range(struct commonio_db *db, const char *owner, unsigned long val) { const struct subordinate_range *range; /* * Search for exact username/group specification * * This is the original method - go fast through the db, doing only * exact username/group string comparison. Therefore we leave it as-is * for the time being, in order to keep it equally fast as it was * before. */ commonio_rewind(db); while ((range = commonio_next(db)) != NULL) { unsigned long first = range->start; unsigned long last = first + range->count - 1; if (0 != strcmp(range->owner, owner)) continue; if ((val >= first) && (val <= last)) return range; } /* * We only do special handling for these two files */ if ((0 != strcmp(db->filename, "/etc/subuid")) && (0 != strcmp(db->filename, "/etc/subgid"))) return NULL; /* * Search loop above did not produce any result. Let's rerun it, * but this time try to match actual UIDs. The first entry that * matches is considered a success. * (It may be specified as literal UID or as another username which * has the same UID as the username we are looking for.) */ struct passwd *pwd; uid_t owner_uid; char owner_uid_string[33] = ""; /* Get UID of the username we are looking for */ pwd = getpwnam(owner); if (NULL == pwd) { /* Username not defined in /etc/passwd, or error occured during lookup */ return NULL; } owner_uid = pwd->pw_uid; sprintf(owner_uid_string, "%lu", (unsigned long int)owner_uid); commonio_rewind(db); while ((range = commonio_next(db)) != NULL) { unsigned long first = range->start; unsigned long last = first + range->count - 1; /* For performance reasons check range before using getpwnam() */ if ((val < first) || (val > last)) { continue; } /* * Range matches. Check if range owner is specified * as numeric UID and if it matches. */ if (0 == strcmp(range->owner, owner_uid_string)) { return range; } /* * Ok, this range owner is not specified as numeric UID * we are looking for. It may be specified as another * UID or as a literal username. * * If specified as another UID, the call to getpwnam() * will return NULL. * * If specified as literal username, we will get its * UID and compare that to UID we are looking for. */ const struct passwd *range_owner_pwd; range_owner_pwd = getpwnam(range->owner); if (NULL == range_owner_pwd) { continue; } if (owner_uid == range_owner_pwd->pw_uid) { return range; } } return NULL; }
int pw_rewind (void) { return commonio_rewind (&passwd_db); }
int sgr_rewind (void) { return commonio_rewind (&gshadow_db); }