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. | 
