#include #include #include #include #include static struct spwd spwd; static FILE* f { nullptr }; static char s_buf[4096]; extern char* _strtok_once(char* str, const char* delim); extern "C" { struct spwd* getspent() { struct spwd* result; if (getspent_r(&spwd, s_buf, sizeof(s_buf), &result) < 0) return nullptr; return result; } int getspent_r(struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp) { *spbufp = nullptr; if (!f) { f = fopen("/etc/shadow", "r"); if (!f) return -1; fcntl(fileno(f), F_SETFD, FD_CLOEXEC); } return fgetspent_r(f, spbuf, buf, buflen, spbufp); } int fgetspent_r(FILE* stream, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp) { *spbufp = nullptr; while (true) { char* rc = fgets(buf, buflen, stream); if (!rc) return -1; char* name = _strtok_once(rc, ":\n"); if (!name) continue; char* passwd = _strtok_once(nullptr, ":\n"); if (!passwd) continue; char* lstchg = _strtok_once(nullptr, ":\n"); if (!lstchg) continue; char* min = _strtok_once(nullptr, ":\n"); if (!min) continue; char* max = _strtok_once(nullptr, ":\n"); if (!max) continue; char* warn = _strtok_once(nullptr, ":\n"); if (!warn) continue; char* inact = _strtok_once(nullptr, ":\n"); if (!inact) continue; char* expire = _strtok_once(nullptr, ":\n"); if (!expire) continue; char* flag = _strtok_once(nullptr, ":\n"); if (!flag) continue; spbuf->sp_namp = name; spbuf->sp_pwdp = passwd; spbuf->sp_lstchg = (long)strtol(lstchg, nullptr, 10); spbuf->sp_min = (long)strtol(min, nullptr, 10); spbuf->sp_max = (long)strtol(max, nullptr, 10); spbuf->sp_warn = (long)strtol(warn, nullptr, 10); spbuf->sp_inact = (long)strtol(inact, nullptr, 10); spbuf->sp_expire = (long)strtol(expire, nullptr, 10); spbuf->sp_flag = (unsigned long)strtoul(flag, nullptr, 10); *spbufp = spbuf; return 0; } } struct spwd* getspnam(const char* name) { setspent(); struct spwd* entry; while ((entry = getspent())) { if (!strcmp(entry->sp_namp, name)) { return entry; } } return entry; } void setspent() { if (f) rewind(f); } void endspent() { if (f) { fclose(f); f = nullptr; } } }