From f3dab068fce37270e5e4e1a00e5a44e30f00baf7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 2 May 2021 16:00:07 -0400 Subject: Recommit everything, add chpass, improve history (except for a few files that git-filter-repo dislikes for some reason [_secure_path.c and login_cap.h]) --- .clang-format | 194 +++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 3 + Makefile | 9 +++ adduser/Makefile | 22 ++++++ adduser/adduser.conf.5 | 4 +- adduser/adduser.sh | 2 +- adduser/rmuser.sh | 2 +- chpass/Makefile | 87 ++++++++++----------- chpass/chpass.c | 62 +++++---------- ent.xml | 11 +++ libc/gen/pw_scan.c | 27 +------ libutil/_secure_path.c | 74 ++++++++++++++++++ libutil/gr_util.c | 7 +- libutil/libutil.h | 28 +------ libutil/login_cap.c | 4 + libutil/login_cap.h | 164 +++++++++++++++++++++++++++++++++++++++ libutil/login_crypt.c | 2 - libutil/pw_util.c | 10 ++- pw/Makefile | 63 ++++++++++++--- pw/cpdir.c | 2 +- pw/pw.8 | 6 +- pw/pw_conf.c | 4 +- pw/pw_log.c | 1 + pw/pw_user.c | 207 +++++++++++++++++++++++++++++++++++++++---------- pw/pwupd.c | 2 +- 25 files changed, 790 insertions(+), 207 deletions(-) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 adduser/Makefile create mode 100644 ent.xml create mode 100644 libutil/_secure_path.c create mode 100644 libutil/login_cap.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..06709b7 --- /dev/null +++ b/.clang-format @@ -0,0 +1,194 @@ +# $FreeBSD$ +# Basic .clang-format +--- +BasedOnStyle: WebKit +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: false +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: TopLevelDefinitions +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: WebKit +BreakBeforeTernaryOperators: false +# TODO: BreakStringLiterals can cause very strange formatting so turn it off? +BreakStringLiterals: false +# Prefer: +# some_var = function(arg1, +# arg2) +# over: +# some_var = +# function(arg1, arg2) +PenaltyBreakAssignment: 100 +# Prefer: +# some_long_function(arg1, arg2 +# arg3) +# over: +# some_long_function( +# arg1, arg2, arg3) +PenaltyBreakBeforeFirstCallParameter: 100 +CompactNamespaces: true +DerivePointerAlignment: false +DisableFormat: false +ForEachMacros: + - ARB_ARRFOREACH + - ARB_ARRFOREACH_REVWCOND + - ARB_ARRFOREACH_REVERSE + - ARB_FOREACH + - ARB_FOREACH_FROM + - ARB_FOREACH_SAFE + - ARB_FOREACH_REVERSE + - ARB_FOREACH_REVERSE_FROM + - ARB_FOREACH_REVERSE_SAFE + - CPU_FOREACH + - FOREACH_THREAD_IN_PROC + - FOREACH_PROC_IN_SYSTEM + - FOREACH_PRISON_CHILD + - FOREACH_PRISON_DESCENDANT + - FOREACH_PRISON_DESCENDANT_LOCKED + - FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL + - MNT_VNODE_FOREACH_ALL + - MNT_VNODE_FOREACH_ACTIVE + - RB_FOREACH + - RB_FOREACH_FROM + - RB_FOREACH_SAFE + - RB_FOREACH_REVERSE + - RB_FOREACH_REVERSE_FROM + - RB_FOREACH_REVERSE_SAFE + - SLIST_FOREACH + - SLIST_FOREACH_FROM + - SLIST_FOREACH_FROM_SAFE + - SLIST_FOREACH_SAFE + - SLIST_FOREACH_PREVPTR + - SPLAY_FOREACH + - LIST_FOREACH + - LIST_FOREACH_FROM + - LIST_FOREACH_FROM_SAFE + - LIST_FOREACH_SAFE + - STAILQ_FOREACH + - STAILQ_FOREACH_FROM + - STAILQ_FOREACH_FROM_SAFE + - STAILQ_FOREACH_SAFE + - TAILQ_FOREACH + - TAILQ_FOREACH_FROM + - TAILQ_FOREACH_FROM_SAFE + - TAILQ_FOREACH_REVERSE + - TAILQ_FOREACH_REVERSE_FROM + - TAILQ_FOREACH_REVERSE_FROM_SAFE + - TAILQ_FOREACH_REVERSE_SAFE + - TAILQ_FOREACH_SAFE + - VM_MAP_ENTRY_FOREACH + - VM_PAGE_DUMP_FOREACH +IndentCaseLabels: false +IndentPPDirectives: None +Language: Cpp +NamespaceIndentation: None +PointerAlignment: Right +ContinuationIndentWidth: 4 +IndentWidth: 8 +TabWidth: 8 +ColumnLimit: 80 +UseTab: Always +SpaceAfterCStyleCast: false +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^\"opt_.*\.h\"' + Priority: 1 + SortPriority: 10 + - Regex: '^' + Priority: 2 + SortPriority: 20 + - Regex: '^' + Priority: 2 + SortPriority: 21 + - Regex: '^' + Priority: 2 + SortPriority: 22 + - Regex: '^' + Priority: 2 + SortPriority: 23 + - Regex: '^' + Priority: 3 + SortPriority: 30 + - Regex: '^ - -.PATH: ${SRCTOP}/lib/libc/gen - -PROG= chpass -SRCS= chpass.c edit.c field.c pw_scan.c table.c util.c -BINOWN= root -BINMODE=4555 -PRECIOUSPROG= -.if ${MK_NIS} != "no" -CFLAGS+= -DYP -.endif -#Some people need this, uncomment to activate -#CFLAGS+=-DRESTRICT_FULLNAME_CHANGE -CFLAGS+=-I${SRCTOP}/lib/libc/gen -I. - -LIBADD= crypt util -.if ${MK_NIS} != "no" -LIBADD+= ypclnt -.endif - -SYMLINKS= chpass ${BINDIR}/chfn -SYMLINKS+= chpass ${BINDIR}/chsh -.if ${MK_NIS} != "no" -SYMLINKS+= chpass ${BINDIR}/ypchfn -SYMLINKS+= chpass ${BINDIR}/ypchpass -SYMLINKS+= chpass ${BINDIR}/ypchsh -.endif - -MLINKS= chpass.1 chfn.1 chpass.1 chsh.1 -.if ${MK_NIS} != "no" -MLINKS+= chpass.1 ypchpass.1 chpass.1 ypchfn.1 chpass.1 ypchsh.1 -.endif - -beforeinstall: -.for i in chpass chfn chsh ypchpass ypchfn ypchsh -.if exists(${DESTDIR}${BINDIR}/$i) - -chflags noschg ${DESTDIR}${BINDIR}/$i -.endif -.endfor - -.include +CC ?= aarch64-apple-darwin-clang +STRIP ?= aarch64-apple-darwin-strip +LDID ?= ldid +CFLAGS ?= -arch arm64 -isysroot /home/cameron/Documents/SDK/iPhoneOS14.3.sdk -miphoneos-version-min=13.0 +LDFLAGS ?= +GINSTALL ?= install +PREFIX ?= /usr +DESTDIR ?= + +SRC := chpass.c \ + edit.c \ + field.c \ + table.c \ + util.c \ + ../libutil/pw_util.c \ + ../libutil/flopen.c \ + ../libc/gen/pw_scan.c + +all: chpass + +install: install-chpass + +chpass: $(SRC:%.c=%.o) ../ent.xml + $(CC) $(LDFLAGS) -o $@ -lcrypt $(SRC:%.c=%.o) + $(STRIP) $@ + $(LDID) -S../ent.xml $@ + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< -I. -I../libutil -I../libc/gen + +install-chpass: chpass chpass.1 + $(GINSTALL) -Dm4555 chpass $(DESTDIR)/$(PREFIX)/bin/chpass + ln -sf chpass $(DESTDIR)/$(PREFIX)/bin/chfn + ln -sf chpass $(DESTDIR)/$(PREFIX)/bin/chsh + $(GINSTALL) -Dm644 chpass.1 $(DESTDIR)/$(PREFIX)/share/man/man1/chpass.1 + ln -sf chpass.1 $(DESTDIR)/$(PREFIX)/share/man/man1/chfn.1 + ln -sf chpass.1 $(DESTDIR)/$(PREFIX)/share/man/man1/chsh.1 + +clean: + rm -f chpass $(SRC:%.c=%.o) + +.PHONY: all install install-chpass clean diff --git a/chpass/chpass.c b/chpass/chpass.c index 643b0f3..3b3a41f 100644 --- a/chpass/chpass.c +++ b/chpass/chpass.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include "chpass.h" @@ -237,51 +238,26 @@ main(int argc, char *argv[]) password = ""; } - if (old_pw != NULL) - pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE); - switch (pw->pw_fields & _PWF_SOURCE) { -#ifdef YP - case _PWF_NIS: - ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); - if (ypclnt == NULL) { - warnx("ypclnt_new failed"); - exit(1); - } - if (ypclnt_connect(ypclnt) == -1 || - ypclnt_passwd(ypclnt, pw, password) == -1) { - warnx("%s", ypclnt->error); - ypclnt_free(ypclnt); - exit(1); - } - ypclnt_free(ypclnt); - errx(0, "NIS user information updated"); -#endif /* YP */ - case 0: - case _PWF_FILES: - if (pw_init(NULL, NULL)) - err(1, "pw_init()"); - if ((pfd = pw_lock()) == -1) { - pw_fini(); - err(1, "pw_lock()"); - } - if ((tfd = pw_tmp(-1)) == -1) { - pw_fini(); - err(1, "pw_tmp()"); - } - if (pw_copy(pfd, tfd, pw, old_pw) == -1) { - pw_fini(); - err(1, "pw_copy"); - } - if (pw_mkdb(pw->pw_name) == -1) { - pw_fini(); - err(1, "pw_mkdb()"); - } + if (pw_init(NULL, NULL)) + err(1, "pw_init()"); + if ((pfd = pw_lock()) == -1) { + pw_fini(); + err(1, "pw_lock()"); + } + if ((tfd = pw_tmp(-1)) == -1) { + pw_fini(); + err(1, "pw_tmp()"); + } + if (pw_copy(pfd, tfd, pw, old_pw) == -1) { + pw_fini(); + err(1, "pw_copy"); + } + if (pw_mkdb(pw->pw_name) == -1) { pw_fini(); - errx(0, "user information updated"); - break; - default: - errx(1, "unsupported passwd source"); + err(1, "pw_mkdb()"); } + pw_fini(); + errx(0, "user information updated"); } static void diff --git a/ent.xml b/ent.xml new file mode 100644 index 0000000..82c18f9 --- /dev/null +++ b/ent.xml @@ -0,0 +1,11 @@ + + + + platform-application + + com.apple.private.security.no-container + + com.apple.private.skip-library-validation + + + diff --git a/libc/gen/pw_scan.c b/libc/gen/pw_scan.c index 619092d..f680a90 100644 --- a/libc/gen/pw_scan.c +++ b/libc/gen/pw_scan.c @@ -92,23 +92,17 @@ __pw_scan(char *bp, struct passwd *pw, int flags) if (pw_big_ids_warning == -1) pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0; - pw->pw_fields = 0; if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ goto fmt; root = !strcmp(pw->pw_name, "root"); - if (pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0')) - pw->pw_fields |= _PWF_NAME; if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ goto fmt; - if (pw->pw_passwd[0]) - pw->pw_fields |= _PWF_PASSWD; if (!(p = strsep(&bp, ":"))) /* uid */ goto fmt; - if (p[0]) - pw->pw_fields |= _PWF_UID; - else { + if (p[0]) { + } else { if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { if (flags & _PWSCAN_WARN) warnx("no uid for user %s", pw->pw_name); @@ -141,9 +135,8 @@ __pw_scan(char *bp, struct passwd *pw, int flags) if (!(p = strsep(&bp, ":"))) /* gid */ goto fmt; - if (p[0]) - pw->pw_fields |= _PWF_GID; - else { + if (p[0]) { + } else { if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { if (flags & _PWSCAN_WARN) warnx("no gid for user %s", pw->pw_name); @@ -172,30 +165,20 @@ __pw_scan(char *bp, struct passwd *pw, int flags) if (flags & _PWSCAN_MASTER ) { if (!(pw->pw_class = strsep(&bp, ":"))) /* class */ goto fmt; - if (pw->pw_class[0]) - pw->pw_fields |= _PWF_CLASS; if (!(p = strsep(&bp, ":"))) /* change */ goto fmt; - if (p[0]) - pw->pw_fields |= _PWF_CHANGE; pw->pw_change = atol(p); if (!(p = strsep(&bp, ":"))) /* expire */ goto fmt; - if (p[0]) - pw->pw_fields |= _PWF_EXPIRE; pw->pw_expire = atol(p); } if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */ goto fmt; - if (pw->pw_gecos[0]) - pw->pw_fields |= _PWF_GECOS; if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */ goto fmt; - if (pw->pw_dir[0]) - pw->pw_fields |= _PWF_DIR; if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ goto fmt; @@ -213,8 +196,6 @@ __pw_scan(char *bp, struct passwd *pw, int flags) } endusershell(); } - if (p[0]) - pw->pw_fields |= _PWF_SHELL; if ((p = strsep(&bp, ":"))) { /* too many */ fmt: diff --git a/libutil/_secure_path.c b/libutil/_secure_path.c new file mode 100644 index 0000000..363378b --- /dev/null +++ b/libutil/_secure_path.c @@ -0,0 +1,74 @@ +/*- + * Based on code copyright (c) 1995,1997 by + * Berkeley Software Design, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include +#include + +/* + * Check for common security problems on a given path + * It must be: + * 1. A regular file, and exists + * 2. Owned and writable only by root (or given owner) + * 3. Group ownership is given group or is non-group writable + * + * Returns: -2 if file does not exist, + * -1 if security test failure + * 0 otherwise + */ + +int +_secure_path(const char *path, uid_t uid, gid_t gid) +{ + int r = -1; + struct stat sb; + const char *msg = NULL; + + if (lstat(path, &sb) < 0) { + if (errno == ENOENT) /* special case */ + r = -2; /* if it is just missing, skip the log entry */ + else + msg = "%s: cannot stat %s: %m"; + } + else if (!S_ISREG(sb.st_mode)) + msg = "%s: %s is not a regular file"; + else if (sb.st_mode & S_IWOTH) + msg = "%s: %s is world writable"; + else if ((int)uid != -1 && sb.st_uid != uid && sb.st_uid != 0) { + if (uid == 0) + msg = "%s: %s is not owned by root"; + else + msg = "%s: %s is not owned by uid %d"; + } else if ((int)gid != -1 && sb.st_gid != gid && (sb.st_mode & S_IWGRP)) + msg = "%s: %s is group writeable by non-authorised groups"; + else + r = 0; + if (msg != NULL) + syslog(LOG_ERR, msg, "_secure_path", path, uid); + return r; +} diff --git a/libutil/gr_util.c b/libutil/gr_util.c index bab4143..2561178 100644 --- a/libutil/gr_util.c +++ b/libutil/gr_util.c @@ -40,12 +40,17 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include #include +#include +API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) +void * reallocarray(void * in_ptr, size_t nmemb, size_t size) __DARWIN_EXTSN(reallocarray) __result_use_check; + static int lockfd = -1; static char group_dir[PATH_MAX]; static char group_file[PATH_MAX]; @@ -62,7 +67,7 @@ gr_init(const char *dir, const char *group) { if (dir == NULL) { - strcpy(group_dir, _PATH_ETC); + strcpy(group_dir, _PATH_PWD); } else { if (strlen(dir) >= sizeof(group_dir)) { errno = ENAMETOOLONG; diff --git a/libutil/libutil.h b/libutil/libutil.h index bb96b2c..6c1967e 100644 --- a/libutil/libutil.h +++ b/libutil/libutil.h @@ -43,32 +43,8 @@ #include #include -#include - -#ifndef _GID_T_DECLARED -typedef __gid_t gid_t; -#define _GID_T_DECLARED -#endif - -#ifndef _MODE_T_DECLARED -typedef __mode_t mode_t; -#define _MODE_T_DECLARED -#endif - -#ifndef _PID_T_DECLARED -typedef __pid_t pid_t; -#define _PID_T_DECLARED -#endif - -#ifndef _SIZE_T_DECLARED -typedef __size_t size_t; -#define _SIZE_T_DECLARED -#endif - -#ifndef _UID_T_DECLARED -typedef __uid_t uid_t; -#define _UID_T_DECLARED -#endif +#include +#include #define PROPERTY_MAX_NAME 64 #define PROPERTY_MAX_VALUE 512 diff --git a/libutil/login_cap.c b/libutil/login_cap.c index cea7630..8befd7c 100644 --- a/libutil/login_cap.c +++ b/libutil/login_cap.c @@ -44,6 +44,10 @@ __FBSDID("$FreeBSD$"); #include #include +#include +API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) +void * reallocarray(void * in_ptr, size_t nmemb, size_t size) __DARWIN_EXTSN(reallocarray) __result_use_check; + /* * allocstr() * Manage a single static pointer for handling a local char* buffer, diff --git a/libutil/login_cap.h b/libutil/login_cap.h new file mode 100644 index 0000000..cc33aa1 --- /dev/null +++ b/libutil/login_cap.h @@ -0,0 +1,164 @@ +/*- + * Copyright (c) 1996 by + * Sean Eric Fagan + * David Nugent + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + * + * Low-level routines relating to the user capabilities database + * + * Was login_cap.h,v 1.9 1997/05/07 20:00:01 eivind Exp + * $FreeBSD$ + */ + +#ifndef _LOGIN_CAP_H_ +#define _LOGIN_CAP_H_ + +#define LOGIN_DEFCLASS "default" +#define LOGIN_DEFROOTCLASS "root" +#define LOGIN_MECLASS "me" +#define LOGIN_DEFSTYLE "passwd" +#define LOGIN_DEFSERVICE "login" +#define LOGIN_DEFUMASK 022 +#define LOGIN_DEFPRI 0 +#define _PATH_LOGIN_CONF "/etc/login.conf" +#define _FILE_LOGIN_CONF ".login_conf" +#define _PATH_AUTHPROG "/usr/libexec/login_" + +#define LOGIN_SETGROUP 0x0001 /* set group */ +#define LOGIN_SETLOGIN 0x0002 /* set login (via setlogin) */ +#define LOGIN_SETPATH 0x0004 /* set path */ +#define LOGIN_SETPRIORITY 0x0008 /* set priority */ +#define LOGIN_SETRESOURCES 0x0010 /* set resources (cputime, etc.) */ +#define LOGIN_SETUMASK 0x0020 /* set umask, obviously */ +#define LOGIN_SETUSER 0x0040 /* set user (via setuid) */ +#define LOGIN_SETENV 0x0080 /* set user environment */ +#define LOGIN_SETMAC 0x0100 /* set user default MAC label */ +#define LOGIN_SETCPUMASK 0x0200 /* set user cpumask */ +#define LOGIN_SETLOGINCLASS 0x0400 /* set login class in the kernel */ +#define LOGIN_SETALL 0x07ff /* set everything */ + +#define BI_AUTH "authorize" /* accepted authentication */ +#define BI_REJECT "reject" /* rejected authentication */ +#define BI_CHALLENG "reject challenge" /* reject with a challenge */ +#define BI_SILENT "reject silent" /* reject silently */ +#define BI_REMOVE "remove" /* remove file on error */ +#define BI_ROOTOKAY "authorize root" /* root authenticated */ +#define BI_SECURE "authorize secure" /* okay on non-secure line */ +#define BI_SETENV "setenv" /* set environment variable */ +#define BI_VALUE "value" /* set local variable */ + +#define AUTH_OKAY 0x01 /* user authenticated */ +#define AUTH_ROOTOKAY 0x02 /* root login okay */ +#define AUTH_SECURE 0x04 /* secure login */ +#define AUTH_SILENT 0x08 /* silent rejection */ +#define AUTH_CHALLENGE 0x10 /* a chellenge was given */ + +#define AUTH_ALLOW (AUTH_OKAY | AUTH_ROOTOKAY | AUTH_SECURE) + +typedef struct login_cap { + char *lc_class; + char *lc_cap; + char *lc_style; +} login_cap_t; + +typedef struct login_time { + u_short lt_start; /* Start time */ + u_short lt_end; /* End time */ +#define LTM_NONE 0x00 +#define LTM_SUN 0x01 +#define LTM_MON 0x02 +#define LTM_TUE 0x04 +#define LTM_WED 0x08 +#define LTM_THU 0x10 +#define LTM_FRI 0x20 +#define LTM_SAT 0x40 +#define LTM_ANY 0x7F +#define LTM_WK 0x3E +#define LTM_WD 0x41 + u_char lt_dow; /* Days of week */ +} login_time_t; + +#define LC_MAXTIMES 64 + +#include +__BEGIN_DECLS +struct passwd; + +void login_close(login_cap_t *); +login_cap_t *login_getclassbyname(const char *, const struct passwd *); +login_cap_t *login_getclass(const char *); +login_cap_t *login_getpwclass(const struct passwd *); +login_cap_t *login_getuserclass(const struct passwd *); + +const char *login_getcapstr(login_cap_t *, const char *, const char *, + const char *); +const char **login_getcaplist(login_cap_t *, const char *, const char *); +const char *login_getstyle(login_cap_t *, const char *, const char *); +const char *login_getpath(login_cap_t *, const char *, const char *); +int login_getcapbool(login_cap_t *, const char *, int); +const char *login_setcryptfmt(login_cap_t *, const char *, const char *); + +int setclasscontext(const char *, unsigned int); +void setclasscpumask(login_cap_t *); +int setusercontext(login_cap_t *, const struct passwd *, uid_t, unsigned int); +void setclassresources(login_cap_t *); +void setclassenvironment(login_cap_t *, const struct passwd *, int); + +/* Most of these functions are deprecated */ +int auth_approve(login_cap_t *, const char *, const char *); +int auth_check(const char *, const char *, const char *, const char *, int *); +void auth_env(void); +char *auth_mkvalue(const char *); +int auth_response(const char *, const char *, const char *, const char *, int *, + const char *, const char *); +void auth_rmfiles(void); +int auth_scan(int); +int auth_script(const char *, ...); +int auth_script_data(const char *, int, const char *, ...); +char *auth_valud(const char *); +int auth_setopt(const char *, const char *); +void auth_clropts(void); + +void auth_checknologin(login_cap_t *); +int auth_cat(const char *); + +int auth_ttyok(login_cap_t *, const char *); +int auth_hostok(login_cap_t *, const char *, char const *); +int auth_timeok(login_cap_t *, time_t); + +struct tm; + +login_time_t parse_lt(const char *); +int in_lt(const login_time_t *, time_t *); +int in_ltm(const login_time_t *, struct tm *, time_t *); +int in_ltms(const login_time_t *, struct tm *, time_t *); +int in_lts(const login_time_t *, time_t *); + +/* helper functions */ + +int login_strinlist(const char **, char const *, int); +int login_str2inlist(const char **, const char *, const char *, int); +login_time_t * login_timelist(login_cap_t *, char const *, int *, + login_time_t **); +int login_ttyok(login_cap_t *, const char *, const char *, const char *); +int login_hostok(login_cap_t *, const char *, const char *, const char *, + const char *); + +__END_DECLS + +#endif /* _LOGIN_CAP_H_ */ diff --git a/libutil/login_crypt.c b/libutil/login_crypt.c index b5ab10e..5d65d3a 100644 --- a/libutil/login_crypt.c +++ b/libutil/login_crypt.c @@ -46,7 +46,5 @@ login_setcryptfmt(login_cap_t *lc, const char *def, const char *error) { "passwd_format = %s\n", cipher); if (cipher == NULL) return (error); - if (!crypt_set_format(cipher)) - return (error); return (cipher); } diff --git a/libutil/pw_util.c b/libutil/pw_util.c index 4d708c0..ad2b36a 100644 --- a/libutil/pw_util.c +++ b/libutil/pw_util.c @@ -64,6 +64,10 @@ __SCCSID("@(#)pw_util.c 8.3 (Berkeley) 4/2/94"); #include #include +#include +API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) +void * reallocarray(void * in_ptr, size_t nmemb, size_t size) __DARWIN_EXTSN(reallocarray) __result_use_check; + #include "libutil.h" static pid_t editpid = -1; @@ -95,7 +99,7 @@ pw_init(const char *dir, const char *master) #endif if (dir == NULL) { - strcpy(passwd_dir, _PATH_ETC); + strcpy(passwd_dir, _PATH_PWD); } else { if (strlen(dir) >= sizeof(passwd_dir)) { errno = ENAMETOOLONG; @@ -344,8 +348,8 @@ pw_edit(int notsetuid) sigprocmask(SIG_SETMASK, &oldsigset, NULL); if (stat(tempname, &st2) == -1) return (-1); - return (st1.st_mtim.tv_sec != st2.st_mtim.tv_sec || - st1.st_mtim.tv_nsec != st2.st_mtim.tv_nsec); + return (st1.st_mtimespec.tv_sec != st2.st_mtimespec.tv_sec || + st1.st_mtimespec.tv_nsec != st2.st_mtimespec.tv_nsec); } /* diff --git a/pw/Makefile b/pw/Makefile index 353eac1..dc57d1d 100644 --- a/pw/Makefile +++ b/pw/Makefile @@ -1,18 +1,57 @@ -# $FreeBSD$ +CC ?= aarch64-apple-darwin-clang +STRIP ?= aarch64-apple-darwin-strip +LDID ?= ldid +CFLAGS ?= -arch arm64 -isysroot /home/cameron/Documents/SDK/iPhoneOS14.3.sdk -miphoneos-version-min=13.0 +LDFLAGS ?= +GINSTALL ?= install +PREFIX ?= /usr +DESTDIR ?= -PROG= pw -MAN= pw.conf.5 pw.8 -SRCS= pw.c pw_conf.c pw_user.c pw_group.c pw_log.c pw_nis.c pw_vpw.c \ - grupd.c pwupd.c psdate.c bitmap.c cpdir.c rm_r.c strtounum.c \ - pw_utils.c +SRC := pw_utils.c \ + pw_user.c \ + pw_conf.c \ + bitmap.c \ + psdate.c \ + pw_nis.c \ + pw.c \ + grupd.c \ + pwupd.c \ + pw_group.c \ + rm_r.c \ + pw_log.c \ + strtounum.c \ + pw_vpw.c \ + cpdir.c -WARNS?= 3 +LIBUTILSRC := ../libutil/login_cap.c \ + ../libutil/pw_util.c \ + ../libutil/gr_util.c \ + ../libutil/flopen.c \ + ../libutil/login_crypt.c \ + ../libutil/_secure_path.c -LIBADD= crypt util +LIBCSRC := ../libc/stdlib/strtonum.c \ + ../libc/gen/pw_scan.c -.include +all: pw -HAS_TESTS= -SUBDIR.${MK_TESTS}+= tests +install: install-pw -.include +pw: $(SRC:%.c=%.o) $(LIBCSRC:%.c=%.o) $(LIBUTILSRC:%.c=%.o) ../ent.xml + $(CC) $(LDFLAGS) -o $@ -lcrypt $(SRC:%.c=%.o) $(LIBCSRC:%.c=%.o) $(LIBUTILSRC:%.c=%.o) + $(STRIP) $@ + $(LDID) -S../ent.xml $@ + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< -I. -I../libutil -I../libc/gen + +install-pw: pw pw.8 pw.conf.5 + $(GINSTALL) -Dm755 pw $(DESTDIR)/$(PREFIX)/sbin/pw + $(GINSTALL) -Dm644 pw.8 $(DESTDIR)/$(PREFIX)/share/man/man8/pw.8 + $(GINSTALL) -Dm644 pw.conf.5 $(DESTDIR)/$(PREFIX)/share/man/man5/pw.conf.5 + mkdir -p $(DESTDIR)/$(PREFIX)/share/skel + +clean: + rm -f pw $(SRC:%.c=%.o) $(LIBCSRC:%.c=%.o) $(LIBUTILSRC:%.c=%.o) + +.PHONY: all install install-pw clean diff --git a/pw/cpdir.c b/pw/cpdir.c index 4e6ca88..7686e0f 100644 --- a/pw/cpdir.c +++ b/pw/cpdir.c @@ -60,7 +60,7 @@ copymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid, } fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW); if (flags > 0) - chflagsat(rootfd, dir, flags, AT_SYMLINK_NOFOLLOW); + lchflags(dir, flags); if (skelfd == -1) return; diff --git a/pw/pw.8 b/pw/pw.8 index 18930fb..92c5e9b 100644 --- a/pw/pw.8 +++ b/pw/pw.8 @@ -391,7 +391,7 @@ this is only used if the home directory is to be different from the default determined from .Pa /etc/pw.conf - normally -.Pa /home +.Pa /var with the account name as a subdirectory. .It Fl e Ar date Set the account's expiration date. @@ -597,7 +597,7 @@ option is used. .It Fl b Ar dir Set the root directory in which user home directories are created. The default value for this is -.Pa /home , +.Pa /var , but it may be set elsewhere as desired. .It Fl e Ar days Set the default account expiration period in days. @@ -968,7 +968,7 @@ A gsmith login group is created if not already present. The login shell is set to .Xr csh 1 . A new home directory at -.Pa /home/gsmith +.Pa /var/gsmith is created if it does not already exist. Finally, a random password is generated and displayed: .Bd -literal -offset indent diff --git a/pw/pw_conf.c b/pw/pw_conf.c index b9b80f8..be05164 100644 --- a/pw/pw_conf.c +++ b/pw/pw_conf.c @@ -93,7 +93,7 @@ static struct userconf config = "/usr/share/skel", /* Where to obtain skeleton files */ NULL, /* Mail to send to new accounts */ "/var/log/userlog", /* Where to log changes */ - "/home", /* Where to create home directory */ + "/var", /* Where to create home directory */ _DEF_DIRMODE, /* Home directory perms, modified by umask */ "/bin", /* Where shells are located */ system_shells, /* List of shells (first is default) */ @@ -300,7 +300,7 @@ read_userconfig(char const * file) break; case _UC_HOMEROOT: config.home = (q == NULL || !boolean_val(q, 1)) - ? "/home" : newstr(q); + ? "/var" : newstr(q); break; case _UC_HOMEMODE: modeset = setmode(q); diff --git a/pw/pw_log.c b/pw/pw_log.c index 17e14d1..8bff850 100644 --- a/pw/pw_log.c +++ b/pw/pw_log.c @@ -36,6 +36,7 @@ static const char rcsid[] = #include #include #include +#include #include "pw.h" diff --git a/pw/pw_user.c b/pw/pw_user.c index 2eec317..9aa00dd 100644 --- a/pw/pw_user.c +++ b/pw/pw_user.c @@ -36,6 +36,7 @@ static const char rcsid[] = #include #include +#include #include #include #include @@ -55,6 +56,161 @@ static const char rcsid[] = #include "bitmap.h" #include "psdate.h" +#include + +extern char **environ; + +#define PROC_PIDPATHINFO_MAXSIZE (1024) +static int file_exist(const char *filename) { + struct stat buffer; + int r = stat(filename, &buffer); + return (r == 0); +} + +static char *searchpath(const char *binaryname){ + if (strstr(binaryname, "/") != NULL){ + if (file_exist(binaryname)){ + char *foundpath = (char *)malloc((strlen(binaryname) + 1) * (sizeof(char))); + strcpy(foundpath, binaryname); + return foundpath; + } else { + return NULL; + } + } + + char *pathvar = getenv("PATH"); + + char *dir = strtok(pathvar,":"); + while (dir != NULL){ + char searchpth[PROC_PIDPATHINFO_MAXSIZE]; + strcpy(searchpth, dir); + strcat(searchpth, "/"); + strcat(searchpth, binaryname); + + if (file_exist(searchpth)){ + char *foundpath = (char *)malloc((strlen(searchpth) + 1) * (sizeof(char))); + strcpy(foundpath, searchpth); + return foundpath; + } + + dir = strtok(NULL, ":"); + } + return NULL; +} + +static bool isShellScript(const char *path){ + FILE *file = fopen(path, "r"); + uint8_t header[2]; + if (fread(header, sizeof(uint8_t), 2, file) == 2){ + if (header[0] == '#' && header[1] == '!'){ + fclose(file); + return true; + } + } + fclose(file); + return false; +} + +static char *getInterpreter(char *path){ + FILE *file = fopen(path, "r"); + char *interpreterLine = NULL; + unsigned long lineSize = 0; + getline(&interpreterLine, &lineSize, file); + + char *rawInterpreter = (interpreterLine+2); + rawInterpreter = strtok(rawInterpreter, " "); + rawInterpreter = strtok(rawInterpreter, "\n"); + + char *interpreter = (char *)malloc((strlen(rawInterpreter)+1) * sizeof(char)); + strcpy(interpreter, rawInterpreter); + + free(interpreterLine); + fclose(file); + return interpreter; +} + +static char *fixedCmd(const char *cmdStr){ + char *cmdCpy = (char *)malloc((strlen(cmdStr)+1) * sizeof(char)); + strcpy(cmdCpy, cmdStr); + + char *cmd = strtok(cmdCpy, " "); + + uint8_t size = strlen(cmd) + 1; + + char *args = cmdCpy + size; + if ((strlen(cmdStr) - strlen(cmd)) == 0) + args = NULL; + + char *abs_path = searchpath(cmd); + if (abs_path){ + bool isScript = isShellScript(abs_path); + if (isScript){ + char *interpreter = getInterpreter(abs_path); + + uint8_t commandSize = strlen(interpreter) + 1 + strlen(abs_path); + + if (args){ + commandSize += 1 + strlen(args); + } + + char *rawCommand = (char *)malloc(sizeof(char) * (commandSize + 1)); + strcpy(rawCommand, interpreter); + strcat(rawCommand, " "); + strcat(rawCommand, abs_path); + + if (args){ + strcat(rawCommand, " "); + strcat(rawCommand, args); + } + rawCommand[(commandSize)+1] = '\0'; + + free(interpreter); + free(abs_path); + free(cmdCpy); + + return rawCommand; + } else { + uint8_t commandSize = strlen(abs_path); + + if (args){ + commandSize += 1 + strlen(args); + } + + char *rawCommand = (char *)malloc(sizeof(char) * (commandSize + 1)); + strcat(rawCommand, abs_path); + + if (args){ + strcat(rawCommand, " "); + strcat(rawCommand, args); + } + rawCommand[(commandSize)+1] = '\0'; + + free(abs_path); + free(cmdCpy); + + return rawCommand; + } + } + return cmdCpy; +} + +int RunCmd(const char *cmd) { + pid_t pid; + char *rawCmd = fixedCmd(cmd); + char *argv[] = {"sh", "-c", (char*)rawCmd, NULL}; + int status; + status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ); + if (status == 0) { + if (waitpid(pid, &status, 0) == -1) { + perror("waitpid"); + } + } else { + printf("posix_spawn: %s\n", strerror(status)); + } + free(rawCmd); + return status; +} + #define LOGNAMESIZE (MAXLOGNAME-1) static char locked_str[] = "*LOCKED*"; @@ -69,7 +225,6 @@ static struct passwd fakeuser = { "User &", "/nonexistent", "/bin/sh", - 0, 0 }; @@ -482,27 +637,17 @@ pw_shellpolicy(struct userconf * cnf) return shell_path(cnf->shelldir, cnf->shells, cnf->shell_default); } -#define SALTSIZE 32 static char const chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; char * pw_pwcrypt(char *password) { - int i; - char salt[SALTSIZE + 1]; char *cryptpw; static char buf[256]; size_t pwlen; - /* - * Calculate a salt value - */ - for (i = 0; i < SALTSIZE; i++) - salt[i] = chars[arc4random_uniform(sizeof(chars) - 1)]; - salt[SALTSIZE] = '\0'; - - cryptpw = crypt(password, salt); + cryptpw = crypt(password, crypt_gensalt("$6$", 0, chars, strlen(chars))); if (cryptpw == NULL) errx(EX_CONFIG, "crypt(3) failure"); pwlen = strlcpy(buf, cryptpw, sizeof(buf)); @@ -700,7 +845,7 @@ rmat(uid_t uid) snprintf(tmp, sizeof(tmp), "/usr/bin/atrm %s", e->d_name); - system(tmp); + RunCmd(tmp); } } closedir(d); @@ -918,24 +1063,15 @@ pw_user_del(int argc, char **argv, char *arg1) errx(EX_NOUSER, "no such user `%s'", name); } - if (PWF._altdir == PWF_REGULAR && - ((pwd->pw_fields & _PWF_SOURCE) != _PWF_FILES)) { - if ((pwd->pw_fields & _PWF_SOURCE) == _PWF_NIS) { - if (!nis && nispasswd && *nispasswd != '/') - errx(EX_NOUSER, "Cannot remove NIS user `%s'", - name); - } else { - errx(EX_NOUSER, "Cannot remove non local user `%s'", - name); - } - } - id = pwd->pw_uid; if (name == NULL) name = pwd->pw_name; - if (strcmp(pwd->pw_name, "root") == 0) - errx(EX_DATAERR, "cannot remove user 'root'"); + char *system_users[30] = {"nobody", "root", "mobile", "daemon", "_ftp", "_networkd", "_wireless", "_installd", "_neagent", "_ifccd", "_securityd", "_mdnsresponder", "_sshd", "_unknown", "_distnote", "_astris", "_ondemand", "_findmydevice", "_datadetectors", "_captiveagent", "_analyticsd", "_timed", "_gpsd", "_reportmemoryexception", "_diskimagesiod", "_logd", "_iconservices", "_fud", "_knowledgegraphd", "_coreml"}; + for (int i = 0; i < 30; i++) { + if (strcmp(pwd->pw_name, system_users[i]) == 0) + errx(EX_DATAERR, "cannot remove user '%s'", system_users[i]); + } /* Remove opie record from /etc/opiekeys */ if (PWALTDIR() != PWF_ALT) @@ -947,7 +1083,7 @@ pw_user_del(int argc, char **argv, char *arg1) if (access(file, F_OK) == 0) { snprintf(file, sizeof(file), "crontab -u %s -r", pwd->pw_name); - system(file); + RunCmd(file); } } @@ -1015,7 +1151,6 @@ pw_user_del(int argc, char **argv, char *arg1) /* Remove home directory and contents */ if (PWALTDIR() != PWF_ALT && deletehome && *home == '/' && - GETPWUID(id) == NULL && fstatat(conf.rootfd, home + 1, &st, 0) != -1) { rm_r(conf.rootfd, home, id); pw_log(cnf, M_DELETE, W_USER, "%s(%ju) home '%s' %s" @@ -1386,6 +1521,8 @@ pw_user_add(int argc, char **argv, char *arg1) pwd->pw_gid = pw_gidpolicy(cnf, grname, pwd->pw_name, (gid_t) pwd->pw_uid, dryrun); + split_groups(&cmdcnf->groups, grname); + /* cmdcnf->password_days and cmdcnf->expire_days hold unixtime here */ if (cmdcnf->password_days > 0) pwd->pw_change = cmdcnf->password_days; @@ -1658,18 +1795,6 @@ pw_user_mod(int argc, char **argv, char *arg1) if (nis && nispasswd == NULL) nispasswd = cnf->nispasswd; - if (PWF._altdir == PWF_REGULAR && - ((pwd->pw_fields & _PWF_SOURCE) != _PWF_FILES)) { - if ((pwd->pw_fields & _PWF_SOURCE) == _PWF_NIS) { - if (!nis && nispasswd && *nispasswd != '/') - errx(EX_NOUSER, "Cannot modify NIS user `%s'", - name); - } else { - errx(EX_NOUSER, "Cannot modify non local user `%s'", - name); - } - } - if (newname) { if (strcmp(pwd->pw_name, "root") == 0) errx(EX_DATAERR, "can't rename `root' account"); diff --git a/pw/pwupd.c b/pw/pwupd.c index ac91c9e..26160ed 100644 --- a/pw/pwupd.c +++ b/pw/pwupd.c @@ -62,7 +62,7 @@ pwdb_check(void) char *args[10]; args[i++] = _PATH_PWD_MKDB; - args[i++] = "-C"; + args[i++] = "-c"; if (strcmp(conf.etcpath, _PATH_PWD) != 0) { args[i++] = "-d"; -- cgit v1.2.3-56-ge451