summaryrefslogtreecommitdiffstats
path: root/content/posts/how-bsd-authentication-works
diff options
context:
space:
mode:
Diffstat (limited to 'content/posts/how-bsd-authentication-works')
-rw-r--r--content/posts/how-bsd-authentication-works/index.org545
1 files changed, 275 insertions, 270 deletions
diff --git a/content/posts/how-bsd-authentication-works/index.org b/content/posts/how-bsd-authentication-works/index.org
index 6eae6a5..76fe4a4 100644
--- a/content/posts/how-bsd-authentication-works/index.org
+++ b/content/posts/how-bsd-authentication-works/index.org
@@ -10,303 +10,308 @@
[[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]]) ([[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 =pledge(3)= or
-=unveil(3)=.
+
+ 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]]) ([[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 =pledge(3)= or
+ =unveil(3)=.
* 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.
+ 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 =login.conf(5)=
-- =service= is the service type. Typically authentication methods will
- accept three values here, =login=, =challenge=, or =response=. Some
- styles take different service arguments, read the style's man page
- for details.
- - =login= is typically the default method
-- =-v key=value= is an optional argument. 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.
+ 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 =login.conf(5)= under the =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. 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.
* Documentation
-All of the high level authentication functions are described in
-=authenticate(3)=, with the lower level functions being described in
-=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.
+ All of the high level authentication functions are described in
+ =authenticate(3)=, with the lower level functions being described in
+ =auth_subr(3)=.
-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
+* auth_userokay
-- =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.
+ 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
+ #+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_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 calls =auth_open=, which
-allocates and returns the pointer to an =auth_session_t=, and sets its
-default =service= to =login=, and it's =fd= to =-1=. After that's
-returned, =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.
+ #+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 calls =auth_open=, which
+ allocates and returns the pointer to an =auth_session_t=, and sets its
+ default =service= to =login=, and it's =fd= to =-1=. After that's
+ returned, =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
+ #+BEGIN_SRC c
+ auth_session_t *auth_verify(auth_session_t *as, char *style, char *name, ...)
+ #+END_SRC
-=auth_verify= creates an auth session 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=.
+ =auth_verify= creates an auth session 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=.
+ 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.
+ 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
+ #+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
-
-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
-
-
-This is the integer returned by
-=auth_userokay=.
+ #+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
+
+ 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
+
+
+ This is the integer returned by
+ =auth_userokay=.
* grapgh?
# Setting env on auth_close(as)