diff options
author | Dante Catalfamo | 2020-06-26 23:57:57 -0400 |
---|---|---|
committer | Dante Catalfamo | 2020-06-27 02:17:36 -0400 |
commit | a4b6f07b0d0a58542c57d492165c15133b8cc1d6 (patch) | |
tree | a6dc30373efe3d9c61d961caf85772269e816cbc | |
parent | 0e0bbff4aa175f5142fe428051c3753bfe1396b0 (diff) | |
download | blog-a4b6f07b0d0a58542c57d492165c15133b8cc1d6.tar.gz blog-a4b6f07b0d0a58542c57d492165c15133b8cc1d6.tar.bz2 blog-a4b6f07b0d0a58542c57d492165c15133b8cc1d6.zip |
Add work draft of BSD Auth post
-rw-r--r-- | content/posts/how-bsd-authentication-works/graph.dot | 67 | ||||
-rw-r--r-- | content/posts/how-bsd-authentication-works/index.org | 230 |
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. |