summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorDante Catalfamo2020-06-26 23:57:57 -0400
committerDante Catalfamo2020-06-27 02:17:36 -0400
commita4b6f07b0d0a58542c57d492165c15133b8cc1d6 (patch)
treea6dc30373efe3d9c61d961caf85772269e816cbc /content
parent0e0bbff4aa175f5142fe428051c3753bfe1396b0 (diff)
downloadblog-a4b6f07b0d0a58542c57d492165c15133b8cc1d6.tar.gz
blog-a4b6f07b0d0a58542c57d492165c15133b8cc1d6.tar.bz2
blog-a4b6f07b0d0a58542c57d492165c15133b8cc1d6.zip
Add work draft of BSD Auth post
Diffstat (limited to 'content')
-rw-r--r--content/posts/how-bsd-authentication-works/graph.dot67
-rw-r--r--content/posts/how-bsd-authentication-works/index.org230
2 files changed, 297 insertions, 0 deletions
diff --git a/content/posts/how-bsd-authentication-works/graph.dot b/content/posts/how-bsd-authentication-works/graph.dot
new file mode 100644
index 0000000..a07e3ec
--- /dev/null
+++ b/content/posts/how-bsd-authentication-works/graph.dot
@@ -0,0 +1,67 @@
+digraph G {
+ subgraph cluster_authenticate {
+ label = "authenticate.c"
+ auth_userokay;
+ auth_usercheck;
+ auth_verify;
+ }
+
+ subgraph cluster_auth_subr {
+ label = "auth_subr.c"
+ auth_open;
+ auth_call;
+ auth_close;
+ // auth_setitem;
+ // auth_setdata;
+ // auth_setopts;
+ auth_set[label="auth_set*"];
+ auth_setstate;
+ // _auth_spool;
+ }
+
+ subgraph cluster_login_cap {
+ label = "libc/login_cap.c"
+ login_getclass
+ login_getstyle
+ }
+
+ subgraph cluster_getpwent {
+ label = "libc/getpwent.c"
+ getpwnam_r;
+ }
+
+ subgraph cluster_exec {
+ login[label="login_*"];
+ execve;
+ }
+
+
+ start -> auth_userokay;
+ auth_userokay -> auth_usercheck;
+ auth_usercheck -> getpwnam_r;
+ auth_usercheck -> login_getclass;
+ auth_usercheck -> login_getstyle;
+ // if password given
+ auth_usercheck -> auth_open;
+ // auth_usercheck -> auth_setitem;
+ // auth_usercheck -> auth_setdata;
+ auth_usercheck -> auth_set;
+ // fi
+ auth_usercheck -> auth_verify;
+
+ auth_verify -> auth_setstate;
+ auth_verify -> auth_call;
+
+ auth_call -> execve;
+ // auth_call -> _auth_spool;
+
+ execve -> login;
+ login -> auth_call[label="back channel"];
+ // login -> _auth_spool[label="back channel"];
+
+
+ // auth_usercheck -> { auth_setitem auth_setdata auth_setopts }
+
+ // auth_call -> auth_userokay;
+ auth_userokay -> auth_close;
+}
diff --git a/content/posts/how-bsd-authentication-works/index.org b/content/posts/how-bsd-authentication-works/index.org
new file mode 100644
index 0000000..20b825f
--- /dev/null
+++ b/content/posts/how-bsd-authentication-works/index.org
@@ -0,0 +1,230 @@
+#+TITLE: How BSD Authentication Works
+#+DATE: 2020-06-26T18:31:36-04:00
+#+DRAFT: true
+#+DESCRIPTION:
+#+TAGS[]:
+#+KEYWORDS[]:
+#+SLUG:
+#+SUMMARY:
+
+[[https://web.archive.org/web/20170327150148/http://www.penzin.net/bsdauth/]]
+
+This one is pretty difficult, since there seems to be very little
+information about how BSD Auth works apart from the source code
+itself. This is my best attempt to understand the flow of BSD Auth
+from what I've read.
+
+All of the high level authentication functions are described in
+=authenticate(3)=.
+
+~#include <bsd_auth.h>~
+
+The highest level function, and easiest to use is =auth_userokay=
+which takes four character arrays as arguments, =name=, =style=,
+=type=, and =password=. It returns either a =0= for failure, of a
+non-zero value for success.
+
+This function lives inside =/lib/libc/gen/authenticate.c=
+
+#+BEGIN_SRC c
+int auth_userokay(char *name, char *style, char *type, char *password);
+#+END_SRC
+
+The return codes are defined inside of =login_cap.h= as
+
+#+BEGIN_SRC c
+/*
+* bits which can be returned by authenticate()/auth_scan()
+*/
+#define AUTH_OKAY 0x01 /* user authenticated */
+#define AUTH_ROOTOKAY 0x02 /* authenticated as root */
+#define AUTH_SECURE 0x04 /* secure login */
+#define AUTH_SILENT 0x08 /* silent rejection */
+#define AUTH_CHALLENGE 0x10 /* a challenge was given */
+#define AUTH_EXPIRED 0x20 /* account expired */
+#define AUTH_PWEXPIRED 0x40 /* password expired */
+#+END_SRC
+
+- =name= is the name of the user to be authenticated
+- =style= is the login method to be used
+ - If =style= is =NULL=, the user's default login style will be
+ used. By default this is =passwd= on normal accounts.
+ - The style can be one of the installed authentication methods,
+ like =radius=, =skey=, =yubikey=, etc.
+ - There's more information about available styles in =login.conf(5)=
+ - Styles can also be installed through BSD Auth module packages
+- =type= is the authentication type
+ - Types are defined in =login.conf= and define a group of allowed
+ auth styles
+ - If =type= is =NULL=, use the auth type for the user's login
+ class. The default type is =auth-default=, which allows
+ =psaswd= and =skey= auth methods.
+ - There's more information about how to add methods in =login.conf(5)=
+- =password= is the password to test
+ - If =password= is =NULL=, then the user is interactively
+ prompted. This is required for auth styles using
+ challenge-response methods.
+ - If =password= is specified, then it's non-interactively tested
+
+=auth_userokay= is just a wrapper around =auth_usercheck=, which
+returns a finished auth session of type =auth_session_t=. It closes
+the auth session and returns the value returned from =auth_close=.
+
+=auth_usercheck=
+
+From there it calls a couple other functions, constructing and
+filling out an =auth_session_t= struct using the =auth_set*=
+functions from =auth_subr(3)=. It contains things like the user
+name, login class, along with other details required to
+authenticate the user.
+
+# FILL THIS PART OUT MORE!
+
+#+BEGIN_SRC c
+struct auth_session_t {
+ char *name; /* name of use being authenticated */
+ char *style; /* style of authentication used */
+ char *class; /* class of user */
+ char *service; /* type of service being performed */
+ char *challenge; /* last challenge issued */
+ int flags; /* see below */
+ struct passwd *pwd; /* password entry for user */
+ struct timeval now; /* time of authentication */
+
+ int state; /* authenticated state */
+
+ struct rmfiles *rmlist; /* list of files to remove on failure */
+ struct authopts *optlist; /* list of options to scripts */
+ struct authdata *data; /* additional data to send to scripts */
+
+ char spool[MAXSPOOLSIZE]; /* data returned from login script */
+ int index; /* how much returned thus far */
+
+ int fd; /* connection to authenticator */
+
+ va_list ap0; /* argument list to auth_call */
+ va_list ap; /* additional arguments to auth_call */
+};
+#+END_SRC
+
+Where =authdata=, =authopts=, and =rmfiles= are defined as
+
+#+BEGIN_SRC c
+struct rmfiles {
+ struct rmfiles *next;
+ char *file;
+};
+
+struct authopts {
+ struct authopts *next;
+ char *opt;
+};
+
+struct authdata {
+ struct authdata *next;
+ void *ptr;
+ size_t len;
+};
+#+END_SRC
+
+
+After that it constructs the path of the authentication module by
+combining =_PATH_AUTHPROG=, which is defined in =login_cap.h= as
+=/usr/libexec/auth/login_=, and the authentication style. For the
+case of auth style =passwd=, it would result in the path
+=/usr/libexec/auth/login_passwd=.
+
+Then =auth_call= is called with the struct, the path to the auth
+module, the auth style, the "-s" flag followed by the service
+(login, challenge, response), a double dash, and the user name.
+
+#+BEGIN_SRC c
+auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s",
+ auth_getitem(as, AUTHV_SERVICE), "--", name, (char *)NULL);
+#+END_SRC
+
+Inside of =auth_call=, a socket pair of type =PF_LOCAL,
+SOCK_STREAM= is created. This is called the "back channel", and is
+used to communicate between with the authentication module. The
+process then forks, calling ~execve(path, argv, auth_environ)~,
+where the =argv= is everything after =path= in the =auth_call=
+arguments. Any =authopts= set in the auth session are also passed
+as arguments in the format =-v opt1 -v opt2 -v opt3=,
+etc. =auth_environ= is defined at the top of the file as
+
+#+BEGIN_SRC c
+static char *auth_environ[] = {
+ "PATH=" _PATH_DEFPATH,
+ "SHELL=" _PATH_BSHELL,
+ NULL,
+};
+#+END_SRC
+
+Where both constants are defined in =paths.h= as
+
+#+BEGIN_SRC c
+#define _PATH_DEFPATH "/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin"
+#define _PATH_BSHELL "/bin/sh"
+#+END_SRC
+
+
+The =exec='d process then listens on FD 3, which is one half of the
+=sockpair= that was created earlier.
+
+In the non-exec'd process, first the contents of the auth session's
+=*data= are read in one at a time.
+
+The data received through the back channel is then put into the
+=spool= of the auth session using =_auth_spool(as, pfd[0])=. After
+that the spooled data is scanned for key words defined in
+=login_cap.h=.
+
+#+BEGIN_SRC c
+#define BI_AUTH "authorize" /* Accepted authentication */
+#define BI_REJECT "reject" /* Rejected authentication */
+#define BI_CHALLENGE "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_UNSETENV "unsetenv" /* unset environment variable */
+#define BI_VALUE "value" /* set local variable */
+#define BI_EXPIRED "reject expired" /* account expired */
+#define BI_PWEXPIRED "reject pwexpired" /* password expired */
+#define BI_FDPASS "fd" /* child is passing an fd */
+#+END_SRC
+
+It is looking for lines that start with either =BI_AUTH=
+(=authorize=), or =BI_REJECT= (=reject=). If the line is still longer,
+it continues to scan for any other qualifiers such as =pwexpired= or
+=silent=. The struct's =state= is set to one using the =AUTH_= values
+from =login_cap.h= accordingly.
+
+This is the integer returned by
+=auth_userokay=.
+
+# Setting env on auth_close(as)
+
+The call graph for =auth_userokay= looks something like this:
+
+#+BEGIN_SRC c
+int auth_userokay(char *name, char *style, char *type, char *password)
+#+END_SRC
+
+calls ~auth_usercheck~ and then calls ~auth_close~ on the returned
+~auth_session_t~. The value returned from ~auth_close~ is then
+returned.
+
+#+BEGIN_SRC c
+auth_session_t *auth_usercheck(char *name, char *style, char *type, char *password)
+#+END_SRC
+
+Validates the checks that the user exists, gets the user's login
+class, verifies the auth type, and that the auth style can be used.
+
+It creates an auth session struct.
+
+If the password is provided it sets the service type to =response=,
+and adds the adds the password to the auth data. Otherwise it
+leaves it empty.