> We can do more than drop id, we can use the same minimal pledge
> that will be enforced later since root doesn't need to call
> auth_userokay().
>
> In fact, root doesn't need proc or exec. Is this going too far?
That's a nice observation. Your diff looks fine to me as it is.
In the patch below I tried to refactor the code a little, so there is a
bit less branching depending on getuid() == 0 and argv == 1. The result
seems a bit easier to follow this way.
Index: skeyinit.c
===================================================================
RCS file: /var/cvs/src/usr.bin/skeyinit/skeyinit.c,v
retrieving revision 1.69
diff -u -p -r1.69 skeyinit.c
--- skeyinit.c 21 Feb 2016 22:53:40 -0000 1.69
+++ skeyinit.c 17 May 2016 18:46:44 -0000
@@ -39,6 +39,7 @@
#endif
void usage(void);
+void isskeyenabled(const char *, const char *, int);
void secure_mode(int *, char *, char *, size_t, char *, size_t);
void normal_mode(char *, int, char *, char *);
void enable_db(int);
@@ -50,7 +51,7 @@ main(int argc, char **argv)
char hostname[HOST_NAME_MAX+1];
char seed[SKEY_MAX_SEED_LEN + 1];
char buf[256], key[SKEY_BINKEY_SIZE], filename[PATH_MAX], *ht;
- char lastc, me[UT_NAMESIZE + 1], *p, *auth_type;
+ char lastc, *p, *auth_type;
const char *errstr;
struct skey skey;
struct passwd *pp;
@@ -117,41 +118,47 @@ main(int argc, char **argv)
exit(0);
}
- if (pledge("stdio rpath wpath cpath fattr flock tty proc exec getpw",
- NULL) == -1)
- err(1, "pledge");
+ if (getuid() != 0) {
+ if (pledge("stdio rpath wpath cpath fattr flock tty proc exec "
+ "getpw", NULL) == -1)
+ err(1, "pledge");
- /* Build up a default seed based on the hostname and some randomness */
- if (gethostname(hostname, sizeof(hostname)) < 0)
- err(1, "gethostname");
- for (i = 0, p = seed; hostname[i] && i < SKEY_NAMELEN; i++) {
- if (isalnum((unsigned char)hostname[i]))
- *p++ = tolower((unsigned char)hostname[i]);
- }
- for (i = 0; i < 5; i++)
- *p++ = arc4random_uniform(10) + '0';
- *p = '\0';
+ if ((pp = getpwuid(getuid())) == NULL)
+ err(1, "no user with uid %u", getuid());
+
+ if (argc == 1) {
+ char me[UT_NAMESIZE + 1];
+
+ (void)strlcpy(me, pp->pw_name, sizeof me);
+ if ((pp = getpwnam(argv[0])) == NULL)
+ errx(1, "User unknown: %s", argv[0]);
+ if (strcmp(pp->pw_name, me) != 0)
+ errx(1, "Permission denied.");
+ }
+ } else {
+ if (pledge("stdio rpath wpath cpath fattr flock tty getpw id",
+ NULL) == -1)
+ err(1, "pledge");
- if ((pp = getpwuid(getuid())) == NULL)
- err(1, "no user with uid %u", getuid());
- (void)strlcpy(me, pp->pw_name, sizeof me);
-
- /* Check for optional user string. */
- if (argc == 1) {
- if ((pp = getpwnam(argv[0])) == NULL) {
- if (getuid() == 0) {
+ if (argc == 1) {
+ if ((pp = getpwnam(argv[0])) == NULL) {
static struct passwd _pp;
_pp.pw_name = argv[0];
pp = &_pp;
warnx("Warning, user unknown: %s", argv[0]);
} else {
- errx(1, "User unknown: %s", argv[0]);
+ /* So the file ends up owned by the proper ID */
+ if (setresuid(-1, pp->pw_uid, -1) != 0)
+ errx(1, "unable to change user ID to %u",
+ pp->pw_uid);
}
- } else if (strcmp(pp->pw_name, me) != 0 && getuid() != 0) {
- /* Only root can change other's S/Keys. */
- errx(1, "Permission denied.");
- }
+ } else if ((pp = getpwuid(0)) == NULL)
+ err(1, "no user with uid %u", getuid());
+
+ if (pledge("stdio rpath wpath cpath fattr flock tty", NULL)
+ == -1)
+ err(1, "pledge");
}
switch (skey_haskey(pp->pw_name)) {
@@ -188,6 +195,17 @@ main(int argc, char **argv)
if (pledge("stdio rpath wpath cpath fattr flock tty", NULL) == -1)
err(1, "pledge");
+
+ /* Build up a default seed based on the hostname and some randomness */
+ if (gethostname(hostname, sizeof(hostname)) < 0)
+ err(1, "gethostname");
+ for (i = 0, p = seed; hostname[i] && i < SKEY_NAMELEN; i++) {
+ if (isalnum((unsigned char)hostname[i]))
+ *p++ = tolower((unsigned char)hostname[i]);
+ }
+ for (i = 0; i < 5; i++)
+ *p++ = arc4random_uniform(10) + '0';
+ *p = '\0';
/*
* Lookup and lock the record we are about to modify.