untrusted comment: verify with openbsd-65-base.pub
RWSZaRmt1LEQTx1EA3Isgvt8ZkZgBpCtyvKjj4NUrxm2/w/5Ov22iA4VbHkm83mgJogiSYLXjkh1HpE1i0s7RsEFMeeZJ3qCYwU=

OpenBSD 6.5 errata 021, December 3, 2019:

libc's authentication layer performed insufficient username validation.

Apply by doing:
    signify -Vep /etc/signify/openbsd-65-base.pub -x 021_libcauth.patch.sig \
        -m - | (cd /usr/src && patch -p0)

And then rebuild and install libc, su and login:
    cd /usr/src/lib/libc
    make obj
    make
    make install
    cd /usr/src/usr.bin/su
    make obj
    make
    make install
    cd /usr/src/usr.bin/login
    make obj
    make
    make install

Index: lib/libc/gen/auth_subr.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/auth_subr.c,v
diff -u -p -u -r1.52 auth_subr.c
--- lib/libc/gen/auth_subr.c	23 Mar 2019 17:03:00 -0000	1.52
+++ lib/libc/gen/auth_subr.c	3 Dec 2019 18:04:09 -0000
@@ -304,7 +304,7 @@ auth_challenge(auth_session_t *as)
 	char path[PATH_MAX];
 	int len;
 
-	if (as == NULL || as->style == NULL || as->name == NULL)
+	if (as == NULL || as->style == NULL || !_auth_validuser(as->name))
 		return (NULL);
 
 	len = snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", as->style);
@@ -316,7 +316,7 @@ auth_challenge(auth_session_t *as)
 	free(as->challenge);
 	as->challenge = NULL;
 
-	auth_call(as, path, as->style, "-s", "challenge", as->name,
+	auth_call(as, path, as->style, "-s", "challenge", "--", as->name,
 	    as->class, (char *)NULL);
 	if (as->state & AUTH_CHALLENGE)
 		as->challenge = auth_getvalue(as, "challenge");
@@ -476,6 +476,10 @@ auth_setitem(auth_session_t *as, auth_it
 	case AUTHV_NAME:
 		if (value == as->name)
 			return (0);
+		if (value != NULL && !_auth_validuser(value)) {
+			errno = EINVAL;
+			return (-1);
+		}
 		if (value != NULL && (value = strdup(value)) == NULL)
 			return (-1);
 		free(as->name);
@@ -821,6 +825,7 @@ auth_call(auth_session_t *as, char *path
 		argv[argc++] = "-v";
 		argv[argc++] = "fd=4";		/* AUTH_FD, see below */
 	}
+	/* XXX - fail if out of space in argv */
 	for (opt = as->optlist; opt != NULL; opt = opt->next) {
 		if (argc < Nargc - 2) {
 			argv[argc++] = "-v";
Index: lib/libc/gen/authenticate.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/authenticate.c,v
diff -u -p -u -r1.26 authenticate.c
--- lib/libc/gen/authenticate.c	26 May 2016 15:51:37 -0000	1.26
+++ lib/libc/gen/authenticate.c	3 Dec 2019 01:33:38 -0000
@@ -174,6 +174,17 @@ auth_cat(char *file)
 DEF_WEAK(auth_cat);
 
 int
+_auth_validuser(const char *name)
+{
+	/* User name must be specified and may not start with a '-'. */
+	if (name == NULL || *name == '\0' || *name == '-') {
+		syslog(LOG_ERR, "invalid user name %s", name ? name : "(NULL)");
+		return 0;
+	}
+	return 1;
+}
+
+int
 auth_approval(auth_session_t *as, login_cap_t *lc, char *name, char *type)
 {
 	int close_on_exit, close_lc_on_exit, len;
@@ -192,6 +203,10 @@ auth_approval(auth_session_t *as, login_
 
 	if (pwd == NULL) {
 		if (name != NULL) {
+			if (!_auth_validuser(name)) {
+				warnx("cannot approve who we don't recognize");
+				return (0);
+			}
 			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
 		} else {
 			getpwuid_r(getuid(), &pwstore, pwbuf, sizeof(pwbuf),
@@ -217,7 +232,7 @@ auth_approval(auth_session_t *as, login_
 		}
 		if (pwd == NULL && (approve = strchr(name, '.')) != NULL) {
 			strlcpy(path, name, sizeof path);
-			path[approve-name] = '\0';
+			path[approve - name] = '\0';
 			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
 		}
 		lc = login_getclass(pwd ? pwd->pw_class : NULL);
@@ -290,7 +305,7 @@ auth_approval(auth_session_t *as, login_
 		}
 	}
 	if (approve)
-		auth_call(as, approve, strrchr(approve, '/') + 1, name,
+		auth_call(as, approve, strrchr(approve, '/') + 1, "--", name,
 		    lc->lc_class, type, (char *)NULL);
 
 out:
@@ -314,6 +329,8 @@ auth_usercheck(char *name, char *style, 
 	struct passwd pwstore, *pwd = NULL;
 	char *slash;
 
+	if (!_auth_validuser(name))
+		return (NULL);
 	if (strlcpy(namebuf, name, sizeof(namebuf)) >= sizeof(namebuf))
 		return (NULL);
 	name = namebuf;
@@ -382,6 +399,8 @@ auth_userchallenge(char *name, char *sty
 	struct passwd pwstore, *pwd = NULL;
 	char *slash, pwbuf[_PW_BUF_LEN];
 
+	if (!_auth_validuser(name))
+		return (NULL);
 	if (strlen(name) >= sizeof(namebuf))
 		return (NULL);
 	strlcpy(namebuf, name, sizeof namebuf);
@@ -440,7 +459,8 @@ auth_userresponse(auth_session_t *as, ch
 	auth_setstate(as, 0);
 
 	if ((style = auth_getitem(as, AUTHV_STYLE)) == NULL ||
-	    (name = auth_getitem(as, AUTHV_NAME)) == NULL) {
+	    (name = auth_getitem(as, AUTHV_NAME)) == NULL ||
+	    !_auth_validuser(name)) {
 		if (more == 0)
 			return (auth_close(as));
 		return(0);
@@ -466,7 +486,8 @@ auth_userresponse(auth_session_t *as, ch
 	} else
 		auth_setdata(as, "", 1);
 
-	auth_call(as, path, style, "-s", "response", name, class, (char *)NULL);
+	auth_call(as, path, style, "-s", "response", "--", name,
+	    class, (char *)NULL);
 
 	/*
 	 * If they authenticated then make sure they did not expire
@@ -495,7 +516,7 @@ auth_verify(auth_session_t *as, char *st
 	char path[PATH_MAX];
 
 	if ((name == NULL || style == NULL) && as == NULL)
-		return (as);
+		return (NULL);
 
 	if (as == NULL && (as = auth_open()) == NULL)
 		return (NULL);
@@ -509,12 +530,14 @@ auth_verify(auth_session_t *as, char *st
 
 	style = auth_getitem(as, AUTHV_STYLE);
 	name = auth_getitem(as, AUTHV_NAME);
+	if (!_auth_validuser(name))
+		return (as);
 
 	snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
 	va_start(ap, name);
 	auth_set_va_list(as, ap);
 	auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s",
-	    auth_getitem(as, AUTHV_SERVICE), name, (char *)NULL);
+	    auth_getitem(as, AUTHV_SERVICE), "--", name, (char *)NULL);
 	va_end(ap);
 	return (as);
 }
Index: lib/libc/hidden/bsd_auth.h
===================================================================
RCS file: /cvs/src/lib/libc/hidden/bsd_auth.h,v
diff -u -p -u -r1.1 bsd_auth.h
--- lib/libc/hidden/bsd_auth.h	12 Sep 2015 15:20:14 -0000	1.1
+++ lib/libc/hidden/bsd_auth.h	3 Dec 2019 01:33:38 -0000
@@ -20,6 +20,10 @@
 
 #include_next <bsd_auth.h>
 
+__BEGIN_HIDDEN_DECLS
+int _auth_validuser(const char *name);
+__END_HIDDEN_DECLS
+
 PROTO_NORMAL(auth_approval);
 PROTO_NORMAL(auth_call);
 PROTO_NORMAL(auth_cat);
Index: usr.bin/su/su.c
===================================================================
RCS file: /cvs/src/usr.bin/su/su.c,v
diff -u -p -u -r1.73 su.c
--- usr.bin/su/su.c	28 Jan 2019 01:38:06 -0000	1.73
+++ usr.bin/su/su.c	3 Dec 2019 01:33:38 -0000
@@ -149,11 +149,11 @@ main(int argc, char **argv)
 	if (pwd == NULL)
 		auth_errx(as, 1, "who are you?");
 	if ((username = strdup(pwd->pw_name)) == NULL)
-		auth_errx(as, 1, "can't allocate memory");
+		auth_err(as, 1, NULL);
 	if (asme && !altshell) {
 		if (pwd->pw_shell && *pwd->pw_shell) {
 			if ((shell = strdup(pwd->pw_shell)) == NULL)
-				auth_errx(as, 1, "can't allocate memory");
+				auth_err(as, 1, NULL);
 		} else {
 			shell = _PATH_BSHELL;
 			iscsh = NO;
@@ -194,7 +194,7 @@ main(int argc, char **argv)
 		auth_clean(as);
 		if (auth_setitem(as, AUTHV_INTERACTIVE, "True") != 0 ||
 		    auth_setitem(as, AUTHV_NAME, user) != 0)
-			auth_errx(as, 1, "can't allocate memory");
+			auth_err(as, 1, NULL);
 		if ((user = auth_getitem(as, AUTHV_NAME)) == NULL)
 			auth_errx(as, 1, "internal error");
 		if (auth_setpwd(as, NULL) || (pwd = auth_getpwd(as)) == NULL) {
@@ -223,6 +223,8 @@ main(int argc, char **argv)
 		}
 		fprintf(stderr, "Login incorrect\n");
 	}
+	if (pwd == NULL)
+		auth_errx(as, 1, "internal error");
 
 	if (pledge("stdio unveil rpath getpw exec id", NULL) == -1)
 		err(1, "pledge");
@@ -234,7 +236,7 @@ main(int argc, char **argv)
 				auth_errx(as, 1, "permission denied (shell).");
 		} else if (pwd->pw_shell && *pwd->pw_shell) {
 			if ((shell = strdup(pwd->pw_shell)) == NULL)
-				auth_errx(as, 1, "can't allocate memory");
+				auth_err(as, 1, NULL);
 			iscsh = UNSET;
 		} else {
 			shell = _PATH_BSHELL;
Index: usr.bin/login/login.c
===================================================================
RCS file: /cvs/src/usr.bin/login/login.c,v
diff -u -p -u -r1.70 login.c
--- usr.bin/login/login.c	15 Aug 2018 19:38:47 -0000	1.70
+++ usr.bin/login/login.c	3 Dec 2019 03:45:01 -0000
@@ -340,8 +340,13 @@ main(int argc, char *argv[])
 		}
 		shell = strrchr(script, '/') + 1;
 		auth_setstate(as, AUTH_OKAY);
-		auth_call(as, script, shell,
-		    fflag ? "-f" : username, fflag ? username : 0, (char *)0);
+		if (fflag) {
+			auth_call(as, script, shell, "-f", "--", username,
+			    (char *)NULL);
+		} else {
+			auth_call(as, script, shell, "--", username,
+			    (char *)NULL);
+		}
 		if (!(auth_getstate(as) & AUTH_ALLOW))
 			quickexit(1);
 		auth_setenv(as);
@@ -367,7 +372,7 @@ main(int argc, char *argv[])
 	}
 
 	/*
-	 * Request the things like the approval script print things
+	 * Request that things like the approval script print things
 	 * to stdout (in particular, the nologins files)
 	 */
 	auth_setitem(as, AUTHV_INTERACTIVE, "True");