From 8391d75b6ee4d2d71d2208838aa44e09a61f2e62 Mon Sep 17 00:00:00 2001
From: Dante Catalfamo
Date: Sat, 29 May 2021 21:08:18 -0400
Subject: bsd-auth: add auth_approval definition
---
 .../WIP-how-bsd-authentication-works/index.org     | 149 +++++++++++++++++++++
 1 file changed, 149 insertions(+)
(limited to 'content/posts/WIP-how-bsd-authentication-works')
diff --git a/content/posts/WIP-how-bsd-authentication-works/index.org b/content/posts/WIP-how-bsd-authentication-works/index.org
index ec601ce..fce6768 100644
--- a/content/posts/WIP-how-bsd-authentication-works/index.org
+++ b/content/posts/WIP-how-bsd-authentication-works/index.org
@@ -2146,6 +2146,155 @@
 
   If a username is invalid, it is logged in the syslog.
 
+* auth_approval
+  :PROPERTIES:
+  :CUSTOM_ID: auth_approval
+  :END:
+
+  @@html:   @@
+  #+begin_src c
+  int auth_approval(auth_session_t *as, login_cap_t *lc, char *name, char *type)
+  #+end_src
+  @@html: 
 @@
+  #+begin_src c
+  {
+      int close_on_exit, close_lc_on_exit, len;
+      struct passwd pwstore, *pwd;
+      char *approve, *s, path[PATH_MAX], pwbuf[_PW_BUF_LEN];
+
+      pwd = NULL;
+      close_on_exit = as == NULL;
+      close_lc_on_exit = lc == NULL;
+
+      if (as != NULL && name == NULL)
+          name = auth_getitem(as, AUTHV_NAME);
+
+      if (as != NULL)
+          pwd = auth_getpwd(as);
+
+      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),
+                  &pwd);
+              if (pwd == NULL) {
+                  syslog(LOG_ERR, "no such user id %u", getuid());
+                  warnx("cannot approve who we don't recognize");
+                  return (0);
+              }
+              name = pwd->pw_name;
+          }
+      }
+
+      if (name == NULL)
+          name = pwd->pw_name;
+
+      if (lc == NULL) {
+          if (strlen(name) >= PATH_MAX) {
+              syslog(LOG_ERR, "username to login %.*s...",
+                  PATH_MAX, name);
+              warnx("username too long");
+              return (0);
+          }
+          if (pwd == NULL && (approve = strchr(name, '.')) != NULL) {
+              strlcpy(path, name, sizeof path);
+              path[approve - name] = '\0';
+              getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
+          }
+          lc = login_getclass(pwd ? pwd->pw_class : NULL);
+          if (lc == NULL) {
+              warnx("unable to classify user");
+              return (0);
+          }
+      }
+
+      if (!type)
+          type = LOGIN_DEFSERVICE;
+      else {
+          if (strncmp(type, "approve-", 8) == 0)
+              type += 8;
+
+          len = snprintf(path, sizeof(path), "approve-%s", type);
+          if (len < 0 || len >= sizeof(path)) {
+              if (close_lc_on_exit)
+                  login_close(lc);
+              syslog(LOG_ERR, "approval path too long %.*s...",
+                  PATH_MAX, type);
+              warnx("approval script path too long");
+              return (0);
+          }
+      }
+
+      if ((approve = login_getcapstr(lc, s = path, NULL, NULL)) == NULL)
+          approve = login_getcapstr(lc, s = "approve", NULL, NULL);
+
+      if (approve && approve[0] != '/') {
+          if (close_lc_on_exit)
+              login_close(lc);
+          syslog(LOG_ERR, "Invalid %s script: %s", s, approve);
+          warnx("invalid path to approval script");
+          free(approve);
+          return (0);
+      }
+
+      if (as == NULL && (as = auth_open()) == NULL) {
+          if (close_lc_on_exit)
+              login_close(lc);
+          syslog(LOG_ERR, "%m");
+          warn(NULL);
+          free(approve);
+          return (0);
+      }
+
+      auth_setstate(as, AUTH_OKAY);
+      if (auth_setitem(as, AUTHV_NAME, name) < 0) {
+          syslog(LOG_ERR, "%m");
+          warn(NULL);
+          goto out;
+      }
+      if (auth_check_expire(as) < 0)	/* is this account expired */
+          goto out;
+      if (_auth_checknologin(lc,
+          auth_getitem(as, AUTHV_INTERACTIVE) != NULL)) {
+          auth_setstate(as, (auth_getstate(as) & ~AUTH_ALLOW));
+          goto out;
+      }
+      if (login_getcapbool(lc, "requirehome", 0) && pwd && pwd->pw_dir &&
+          pwd->pw_dir[0]) {
+          struct stat sb;
+
+          if (stat(pwd->pw_dir, &sb) == -1 || !S_ISDIR(sb.st_mode) ||
+              (pwd->pw_uid && sb.st_uid == pwd->pw_uid &&
+              (sb.st_mode & S_IXUSR) == 0)) {
+              auth_setstate(as, (auth_getstate(as) & ~AUTH_ALLOW));
+              goto out;
+          }
+      }
+      if (approve)
+          auth_call(as, approve, strrchr(approve, '/') + 1, "--", name,
+              lc->lc_class, type, (char *)NULL);
+
+  out:
+      free(approve);
+      if (close_lc_on_exit)
+          login_close(lc);
+
+      if (close_on_exit)
+          return (auth_close(as));
+      return (auth_getstate(as) & AUTH_ALLOW);
+  }
+  #+end_src
+  @@html:   @@
+
+  =auth_approval= is
+
+  <>
+
 * COMMENT note                                                     :noexport:
 
  ---
-- 
cgit v1.2.3