diff options
author | Dante Catalfamo | 2020-07-07 22:28:28 -0400 |
---|---|---|
committer | Dante Catalfamo | 2020-07-07 22:28:28 -0400 |
commit | 118b0019658890837ab8e19608ce0779cb6f4d9a (patch) | |
tree | f1146c980182a3fa19dcc37553a2932583e193f3 /content/posts/how-bsd-authentication-works | |
parent | a3bf350943b99c475a281b00a8354654fe4b26f9 (diff) | |
download | blog-118b0019658890837ab8e19608ce0779cb6f4d9a.tar.gz blog-118b0019658890837ab8e19608ce0779cb6f4d9a.tar.bz2 blog-118b0019658890837ab8e19608ce0779cb6f4d9a.zip |
Move WIP posts to WIP folders
Diffstat (limited to 'content/posts/how-bsd-authentication-works')
-rw-r--r-- | content/posts/how-bsd-authentication-works/graph.dot | 67 | ||||
-rw-r--r-- | content/posts/how-bsd-authentication-works/index.org | 473 |
2 files changed, 0 insertions, 540 deletions
diff --git a/content/posts/how-bsd-authentication-works/graph.dot b/content/posts/how-bsd-authentication-works/graph.dot deleted file mode 100644 index 6414b11..0000000 --- a/content/posts/how-bsd-authentication-works/graph.dot +++ /dev/null @@ -1,67 +0,0 @@ -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[label="fork()"]; - // 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 deleted file mode 100644 index 4126284..0000000 --- a/content/posts/how-bsd-authentication-works/index.org +++ /dev/null @@ -1,473 +0,0 @@ -#+TITLE: How BSD Authentication Works -#+DATE: 2020-06-26T18:31:36-04:00 -#+DRAFT: true -#+DESCRIPTION: -#+TAGS[]: openbsd -#+KEYWORDS[]: openbsd -#+SLUG: -#+SUMMARY: -#+SHOWTOC: true - -[[https://web.archive.org/web/20170327150148/http://www.penzin.net/bsdauth/]] -* History - - OpenBSD is quite different from many other Unix-like operating systems - in many ways, but one way which I find interesting is the - authentication system. Most systems from AIX, Solaris, and Linux to - most BSDs including MacOS use some form of a system called Pluggable - Authentication Module (PAM). The two main implementations of PAM are - [[http://www.linux-pam.org/][Linux PAM]] and [[https://www.openpam.org/][OpenPAM]]. PAM modules are created a dynamically loaded - shared objects, which communicate using a set of standard - interfaces ([[https://linux.die.net/man/3/pam][Linux-PAM]] and [[https://www.freebsd.org/cgi/man.cgi?query=pam&apropos=0&sektion=3&manpath=FreeBSD+12.1-RELEASE+and+Ports&arch=default&format=html][OpenPAM]]). PAM is configured using the [[https://linux.die.net/man/5/pam.d][pam.d]] - directory and [[https://www.freebsd.org/cgi/man.cgi?query=pam.conf&sektion=5&apropos=0&manpath=FreeBSD+12.1-RELEASE+and+Ports][pam.conf]]. - - OpenBSD on the other hand uses a mechanism called BSD - Authentication. It was originally developed for a proprietary - operating system called [[https://en.wikipedia.org/wiki/BSD/OS][BSD/OS]] by [[https://en.wikipedia.org/wiki/Berkeley_Software_Design][Berkeley Software Design Inc.]], who - later donated the system. It was adopted by OpenBSD in release - 2.9. BSD Auth is comparatively much simpler than PAM. Modules or, - authentication "styles", are instead stand alone applications or - scripts that communicate over IPC (=PF_LOCAL, SOCK_STREAM=, - specifically). The program or script has no ability to interfere - with the parent and can very easily revoke permissions using - [[https://man.openbsd.org/pledge][=pledge(2)=]] or [[https://man.openbsd.org/unveil][=unveil(2)=]]. The BSD Authentication system of - configured through [[https://man.openbsd.org/login.conf][=login.conf(5)=]]. - -* Why - - 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. - -* BSD Auth Modules - - These programs or scripts are located in =/usr/libexec/auth/= with the - naming convention =login_<style>=. They take arguments in the form of - - #+BEGIN_SRC shell - login_<style> [-s service] [-v key=value] user [class] - #+END_SRC - - - =<style>= is the authentication method. This could be =passwd=, - =radius=, =skey=, =yubikey=, etc. There's more information about - available styles in [[https://man.openbsd.org/login.conf][=login.conf(5)=]] under the [[https://man.openbsd.org/login.conf#AUTHENTICATION][=AUTHENTICATION=]] - header. - - =service= is the service type. Typically authentication methods will - accept one of three values here, =login=, =challenge=, or - =response=. =login= is the default if it's not specified, and is - usually the right choice. Read the style's man page for details. - - =-v key=value= is an optional argument. There is no limit to the - number of =-v= arguments. This is used to pass extra data to the - program under certain circumstances. - - =user= is the name of the user to be authenticated. - - =class= is optional and specifies the class of the user to be - authenticated. - - =login= and =su= pass in extra data as =-v= flags. - - #+CAPTION: Taken from [[https://man.openbsd.org/login.conf][=login.conf(5)=]] - #+BEGIN_SRC - The login(1) program provides the following through the -v option: - - auth_type The type of authentication to use. - - fqdn The hostname provided to login by the -h option. - - hostname The name login(1) will place in the utmp file for the - remote hostname. - - local_addr The local IP address given to login(1) by the -L option. - - lastchance Set to "yes" when a user's password has expired but the - user is being given one last chance to login and update - the password. - - login This is a new login session (as opposed to a simple - identity check). - - remote_addr The remote IP address given to login(1) by the -R option. - - style The style of authentication used for this user (see - approval scripts below). - - The su(1) program provides the following through the -v option: - - wheel Set to either "yes" or "no" to indicate if the user is in - group wheel when they are trying to become root. Some - authentication types require the user to be in group - wheel when using the su(1) program to become super user. - #+END_SRC - - The auth module communicates with its caller through file descriptor 3. - -* Documentation - - All of the high level authentication functions are described in - [[https://man.openbsd.org/authenticate][=authenticate(3)=]], with the lower level functions being described in - [[https://man.openbsd.org/auth_subr][=auth_subr(3)=]]. - -* auth_userokay - - The highest level function, and easiest to use is =auth_userokay=. It - 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 - - - =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 - =passwd=, =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 using =auth_close= and returns the value returned - from closing. - -* auth_session_t - - #+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 - -** auth_setdata - -** auth_setitem - -** auth_setoption - -** auth_setstate -* auth_open - - The =auth_open= function is used by several functions to create a - new auth session. It allocates an =auth_session_t= struct on the - heap, sets its default =service= to =login=, and it's =fd= to =-1=, - and returns the pointer. - -* auth_usercheck - - #+BEGIN_SRC c - auth_session_t *auth_usercheck(char *name, char *style, char *type, char *password) - #+END_SRC - - =auth_usercheck= checks the user name against the passwd db. It also - checks the login class against the =login.conf= db, along with - confirming the login styles available. - - If the password is non-=NULL=, then it creates a new session using - =auth_open=. With the new session, =auth_usercheck= calls (with =as= - as the session struct) - - #+BEGIN_SRC c - auth_setitem(as, AUTHV_SERVICE, "response"); - auth_setdata(as, "", 1); - auth_setdata(as, password, strlen(password) + 1); - #+END_SRC - - setting the service protocol to =response=, adding an empty line to - the session data, then adding the password as data. If the password is - =NULL=, it sets the =auth_session_t= pointer to =NULL=. It then passes - the user name, style, login class, and =NULL= char pointer to - =auth_verify=. The last two variables are received as variable - arguments. It then returns the auth session pointer the call - returns. - -* auth_verify - - #+BEGIN_SRC c - auth_session_t *auth_verify(auth_session_t *as, char *style, char *name, ...) - #+END_SRC - - =auth_verify= creates an auth session using =auth_open= if =as= is - =NULL=. It then sets the user name and style of the session, if the - respective arguments are non-=NULL=. It then copies its variable - arguments to the auth session's =va_list ap=, which is used inside - of =auth_call=. - - 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, the user name, and a =NULL= - character pointer. The return value of =auth_call= is ignored and a - pointer to the auth session is returned immediately afterwards. - - #+BEGIN_SRC c - auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s", - auth_getitem(as, AUTHV_SERVICE), "--", name, (char *)NULL); - #+END_SRC - -* auth_call - - #+BEGIN_SRC c - int auth_call(auth_session_t *as, char *path, ...) - #+END_SRC - - <<here>> - - --- - note: In the man page auth_subr it says - #+begin_quote - path The full path name of the login script to run. The call will - fail if path does not pass the requirements of the secure_path(3) - function. - #+end_quote - However I don't see this enforced anywhere, I even wrote a small test - script to prove that's the case on =vfwall ~/authtest=. - - The manpage also says the path is limited to =/bin/= and =/usr/bin=, - which is also not the case. - - Ask jcs about the file descriptor situation, I don't understand it - after reading both the man page and source. - --- - - 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 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 - - The [[https://man.openbsd.org/login.conf][=login.conf(5)=]] man page once again goes into greater detail on - these values. - - #+BEGIN_SRC - authorize The user has been authorized. - - authorize secure - The user has been authorized and root should be allowed to - login even if this is not a secure terminal. This should only - be sent by authentication styles that are secure over insecure - lines. - - reject Authorization is rejected. This overrides any indication that - the user was authorized (though one would question the wisdom - in sending both a reject and an authorize command). - - reject challenge - Authorization was rejected and a challenge has been made - available via the value challenge. - - reject silent - Authorization is rejected, but no error messages should be - generated. - - remove file - If the login session fails for any reason, remove file before - termination. - - setenv name value - If the login session succeeds, the environment variable name - should be set to the specified value. - - unsetenv name - If the login session succeeds, the environment variable name - should be removed. - - value name value - Set the internal variable name to the specified value. The - value should only contain printable characters. Several \ - sequences may be used to introduce non printing characters. - These are: - - \n A newline. - - \r A carriage return. - - \t A tab. - - \xxx The character represented by the octal value xxx. The - value may be one, two, or three octal digits. - - \c The string is replaced by the value of c. This allows - quoting an initial space or the \ character itself. - - - The following values are currently defined: - - challenge - See section on challenges below. - - errormsg - If set, the value is the reason authentication failed. - The calling program may choose to display this when - rejecting the user, but display is not required. - - #+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. - - #+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 - -** _auth_spool - -** _recv_fd - -* auth_close - =auth_close= is the function responsible for cleaning up the session - and taking care of the values returned though the back channel. - - It first sets the environment variables returned through the back - channel by passing the auth session to =auth_setenv=. It then goes - through the =rmlist= of the session, deleting the files if the - session reported a failure. It then zeroes out all sensitive - information, and frees the various structs associated with the current - =auth_session_t=, and then the session itself. Finally it returns - the session's state =&='ed with =AUTH_ALLOW=. -* grapgh? -# Setting env on auth_close(as) -# partual rewrite below - -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. |