From cbd712a43b8702517a1b4cbe50df6a0b8a39bae6 Mon Sep 17 00:00:00 2001 From: Jakob Kaivo Date: Wed, 1 Apr 2020 03:01:09 -0400 Subject: initial pass with some hard-coded values --- user.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 1 deletion(-) diff --git a/user.c b/user.c index 9a019a7..9eaa7e1 100644 --- a/user.c +++ b/user.c @@ -20,4 +20,166 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. - */ \ No newline at end of file + */ + +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USERS_DIRECTORY "/var/secure/users" +static DIR *users_dir = NULL; + +struct user { + struct passwd pw; + char *gecos; + char *password; +}; + +enum selection { UID, NAME, ALL }; + +static struct user *user_read(char *name) +{ + static struct user u = { 0 }; + + int user = openat(dirfd(users_dir), name, O_SEARCH); + if (user == -1) { + return NULL; + } + + struct stat st; + if (fstat(user, &st) != 0) { + close(user); + return NULL; + } + + u.pw.pw_name = name; + u.pw.pw_uid = st.st_uid; + u.pw.pw_gid = st.st_gid; + u.pw.pw_dir = "/"; // TODO: read symlink at userfd, home + u.pw.pw_shell = "/bin/sh"; // TOOD: read symlink at userfd, shell + u.gecos = name; // TODO: read file at userfd, gecos + u.password = ""; // TODO: read file at userfd, password + + close(user); + + return &u; +} + +static char *user_uid(uid_t uid) +{ + char *name = NULL; + + struct dirent *de; + while ((de = readdir(users_dir)) != NULL) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { + continue; + } + + struct stat st; + if (fstatat(dirfd(users_dir), de->d_name, &st, 0) != 0) { + continue; + } + + if (st.st_uid == uid) { + name = de->d_name; + break; + } + } + + return name; +} + +static struct user *user_find(enum selection sel, char *name, uid_t uid) +{ + if (sel == UID) { + name = user_uid(uid); + } + + return user_read(name); +} + +static void user_print(const struct user *u) +{ + if (u == NULL) { + return; + } + + printf("%s:%s:%jd:%jd:%s:%s:%s\n", u->pw.pw_name, u->password, + (intmax_t)u->pw.pw_uid, (intmax_t)u->pw.pw_gid, + u->gecos, u->pw.pw_dir, u->pw.pw_shell); +} + +int main(int argc, char *argv[]) +{ + char *name = getlogin(); + uid_t uid = getuid(); + enum selection sel = NAME;; + enum { LIST, PASSWORD } action = LIST; + + int c; + while ((c = getopt(argc, argv, "LN:U:p")) != -1) { + switch (c) { + case 'L': + sel = ALL; + break; + + case 'N': + sel = NAME; + name = optarg; + break; + + case 'U': + sel = UID; + uid = atoi(optarg); + break; + + case 'p': + action = PASSWORD; + break; + + default: + return 1; + } + } + + if (action == PASSWORD && sel == ALL) { + fprintf(stderr, "user: -L and -p are incompatible\n"); + return 1; + } + + users_dir = opendir(USERS_DIRECTORY); + if (users_dir == NULL) { + fprintf(stderr, "user: no users directory\n"); + return 1; + } + + if (action == PASSWORD) { + printf("TODO: interactively change password\n"); + return 0; + } + + if (sel == ALL) { + struct dirent *de = NULL; + while ((de = readdir(users_dir)) != NULL) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { + continue; + } + user_print(user_read(de->d_name)); + } + return 0; + } + + struct user *u = user_find(sel, name, uid); + if (u == NULL) { + fprintf(stderr, "user: not found\n"); + return 1; + } + user_print(u); +} -- cgit v1.2.1