Rework source layout in preparation for modular sudo.

This commit is contained in:
Todd C. Miller
2010-02-20 09:14:01 -05:00
parent 28c24027ec
commit e90fa482f9
151 changed files with 0 additions and 0 deletions

128
plugins/sudoers/auth/API Normal file
View File

@@ -0,0 +1,128 @@
NOTE: the Sudo auth API is subject to change
Purpose: to provide a simple API for authentication methods that
encapsulates things nicely without turning into a maze
of #ifdef's
The sudo_auth struct looks like this:
typedef struct sudo_auth {
short flags; /* various flags, see below */
short status; /* status from verify routine */
char *name; /* name of the method in string form */
void *data; /* method-specific data pointer */
int (*init) __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int (*setup) __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int (*verify) __P((struct passwd *pw, char *p, sudo_auth *auth));
int (*cleanup) __P((struct passwd *pw, sudo_auth *auth));
} sudo_auth;
The variables in the struct are as follows:
flags Bitwise binary flags, see below.
status Contains the return value from the last run of
the "verify" function. Starts out as AUTH_FAILURE.
name The name of the authentication method as a C string.
data A pointer to method-specific data. This is passed to
all the functions of an auth method and is usually
initialized in the "init" or "setup" routines.
Possible values of sudo_auth.flags:
FLAG_USER Whether or not the auth functions should run with
the euid of the invoking user instead of 0.
FLAG_CONFIGURED If set then the auth method is assumed to have been
configured successfully. All auth methods start out
with this set. If an "init" or "setup" function
fails, this bit is cleared.
FLAG_ONEANDONLY If set, this indicates that the method is the
only one in use. Can be used by auth functions
to determine whether to return a fatal or nonfatal
error.
The member functions can return the following values:
AUTH_SUCCESS Function succeeded. For a ``verify'' function
this means the user correctly authenticated.
AUTH_FAILURE Function failed. If this is an ``init'' or
``setup'' routine, the auth method will be
marked as !configured.
AUTH_FATAL A fatal error occurred. The routine should have
written an error message to stderr and optionally
sent mail to the administrator. (If log_error()
is called to do this, the NO_EXIT flag must be used.)
When verify_user() gets AUTH_FATAL from an auth
function it does an exit(1).
The functions in the struct are as follows:
int init(struct passwd *pw, char **prompt, sudo_auth *auth)
Function to do any one-time initialization for the auth
method. All of the "init" functions are run before anything
else. A pointer to the prompt string may be used to add
method-specific info to the prompt.
int setup(struct passwd *pw, char **prompt, sudo_auth *auth)
Function to do method-specific setup. All the "setup"
routines are run before any of the "verify" routines. A
pointer to the prompt string may be used to add method-specific
info to the prompt.
int verify(struct passwd *pw, char *p, sudo_auth *auth)
Function to do user verification for this auth method. For
standalone auth methods ``p'' is the prompt string. For
normal auth methods, ``p'' is the password the user entered.
Note that standalone auth methods are responsible for
rerading the password themselves.
int cleanup(struct passwd *pw, sudo_auth *auth)
Function to do per-auth method cleanup. This is only run
at the end of the authentication process, after the user
has completely failed or succeeded to authenticate.
The ``auth->status'' variable contains the result of the
last authentication attempt which may be interesting.
A note about standalone methods. Some authentication methods can't
coexist with any others. This may be because they encapsulate other
methods (pam, sia) or because they have a special way of interacting
with the user (securid).
Adding a new authentication method:
Each method should live in its own file. Add prototypes for the functions
in sudo_auth.h.
If this is a standalone method, add it to the standalone #if cascade
in sudo_auth.h. For instance, for a method, ``fooauth'', add:
#elif defined(HAVE_FOOAUTH)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "foo", \
foo_init, foo_setup, foo_verify, foo_cleanup)
If the method needs to run as the user, not root, replace the first
parameter to AUTH_ENTRY (0) with FLAG_USER. If you don't have a
init/setup/cleanup routine, just use a NULL for that field.
For a normal authentication method, add it to the ``auth_switch'' in
sudo_auth.c. If ``fooauth'' is a normal auth method, its entry
would look like:
# ifdef HAVE_FOOAUTH
AUTH_ENTRY(0, "foo", foo_init, foo_setup, foo_verify, foo_cleanup)
# endif
Again, if the method doesn't need to run as root, replace the 0 with
FLAG_USER. Likewise, if you don't have a init/setup/cleanup routine,
just use a NULL for that field.
NOTE: You should not make a method both ``standalone'' and
``normal''. Just use the --without-passwd configure argument
to disable passwd/shadow file checking and then have your
auth routines check the FLAG_ONEANDONLY flag to see if
they are running standalone and act accordingly.

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 1999, 2001-2005, 2007
* Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/param.h>
#include <sys/types.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include "sudo.h"
#include "sudo_auth.h"
#include <afs/stds.h>
#include <afs/kautils.h>
int
afs_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
struct ktc_encryptionKey afs_key;
struct ktc_token afs_token;
/* Try to just check the password */
ka_StringToKey(pass, NULL, &afs_key);
if (ka_GetAdminToken(pw->pw_name, /* name */
NULL, /* instance */
NULL, /* realm */
&afs_key, /* key (contains password) */
0, /* lifetime */
&afs_token, /* token */
0) == 0) /* new */
return(AUTH_SUCCESS);
/* Fall back on old method XXX - needed? */
setpag();
if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
pw->pw_name, /* name */
NULL, /* instance */
NULL, /* realm */
pass, /* password */
0, /* lifetime */
NULL, /* expiration ptr (unused) */
0, /* spare */
NULL) == 0) /* reason */
return(AUTH_SUCCESS);
return(AUTH_FAILURE);
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 1999-2005, 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include "sudo.h"
#include "sudo_auth.h"
/*
* For a description of the AIX authentication API, see
* http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/authenticate.htm
*/
int
aixauth_verify(pw, prompt, auth)
struct passwd *pw;
char *prompt;
sudo_auth *auth;
{
char *pass;
char *message = NULL;
int reenter = 1;
int rval = AUTH_FAILURE;
pass = tgetpass(prompt, def_passwd_timeout * 60, tgetpass_flags);
if (pass) {
/* XXX - should probably print message on failure. */
if (authenticate(pw->pw_name, pass, &reenter, &message) == 0)
rval = AUTH_SUCCESS;
free(message);
zero_bytes(pass, strlen(pass));
}
return(rval);
}
int
aixauth_cleanup(pw, auth)
struct passwd *pw;
sudo_auth *auth;
{
/* Unset AUTHSTATE as it may not be correct for the runas user. */
unsetenv("AUTHSTATE");
return(AUTH_SUCCESS);
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2000-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <ctype.h>
#include <pwd.h>
#include <signal.h>
#include <login_cap.h>
#include <bsd_auth.h>
#include "sudo.h"
#include "sudo_auth.h"
extern char *login_style; /* from sudo.c */
int
bsdauth_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
static auth_session_t *as;
extern login_cap_t *lc; /* from sudo.c */
if ((as = auth_open()) == NULL) {
log_error(USE_ERRNO|NO_EXIT|NO_MAIL,
"unable to begin bsd authentication");
return(AUTH_FATAL);
}
/* XXX - maybe sanity check the auth style earlier? */
login_style = login_getstyle(lc, login_style, "auth-sudo");
if (login_style == NULL) {
log_error(NO_EXIT|NO_MAIL, "invalid authentication type");
auth_close(as);
return(AUTH_FATAL);
}
if (auth_setitem(as, AUTHV_STYLE, login_style) < 0 ||
auth_setitem(as, AUTHV_NAME, pw->pw_name) < 0 ||
auth_setitem(as, AUTHV_CLASS, login_class) < 0) {
log_error(NO_EXIT|NO_MAIL, "unable to setup authentication");
auth_close(as);
return(AUTH_FATAL);
}
auth->data = (void *) as;
return(AUTH_SUCCESS);
}
int
bsdauth_verify(pw, prompt, auth)
struct passwd *pw;
char *prompt;
sudo_auth *auth;
{
char *pass;
char *s;
size_t len;
int authok = 0;
sigaction_t sa, osa;
auth_session_t *as = (auth_session_t *) auth->data;
/* save old signal handler */
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_DFL;
(void) sigaction(SIGCHLD, &sa, &osa);
/*
* If there is a challenge then print that instead of the normal
* prompt. If the user just hits return we prompt again with echo
* turned on, which is useful for challenge/response things like
* S/Key.
*/
if ((s = auth_challenge(as)) == NULL) {
pass = tgetpass(prompt, def_passwd_timeout * 60, tgetpass_flags);
} else {
pass = tgetpass(s, def_passwd_timeout * 60, tgetpass_flags);
if (pass && *pass == '\0') {
if ((prompt = strrchr(s, '\n')))
prompt++;
else
prompt = s;
/*
* Append '[echo on]' to the last line of the challenge and
* reprompt with echo turned on.
*/
len = strlen(prompt) - 1;
while (isspace(prompt[len]) || prompt[len] == ':')
prompt[len--] = '\0';
easprintf(&s, "%s [echo on]: ", prompt);
pass = tgetpass(s, def_passwd_timeout * 60,
tgetpass_flags | TGP_ECHO);
free(s);
}
}
if (pass) {
authok = auth_userresponse(as, pass, 1);
zero_bytes(pass, strlen(pass));
}
/* restore old signal handler */
(void) sigaction(SIGCHLD, &osa, NULL);
if (authok)
return(AUTH_SUCCESS);
if (!pass)
return(AUTH_INTR);
if ((s = auth_getvalue(as, "errormsg")) != NULL)
log_error(NO_EXIT|NO_MAIL, "%s", s);
return(AUTH_FAILURE);
}
int
bsdauth_cleanup(pw, auth)
struct passwd *pw;
sudo_auth *auth;
{
auth_session_t *as = (auth_session_t *) auth->data;
auth_close(as);
return(AUTH_SUCCESS);
}

202
plugins/sudoers/auth/dce.c Normal file
View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*
* The code below basically comes from the examples supplied on
* the OSF DCE 1.0.3 manpages for the sec_login routines, with
* enough additional polishing to make the routine work with the
* rest of sudo.
*
* This code is known to work on HP 700 and 800 series systems
* running HP-UX 9.X and 10.X, with either HP's version 1.2.1 of DCE.
* (aka, OSF DCE 1.0.3) or with HP's version 1.4 of DCE (aka, OSF
* DCE 1.1).
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <dce/rpc.h>
#include <dce/sec_login.h>
#include <dce/dce_error.h> /* required to call dce_error_inq_text routine */
#include "sudo.h"
#include "sudo_auth.h"
static int check_dce_status __P((error_status_t, char *));
int
dce_verify(pw, plain_pw, auth)
struct passwd *pw;
char *plain_pw;
sudo_auth *auth;
{
struct passwd temp_pw;
sec_passwd_rec_t password_rec;
sec_login_handle_t login_context;
boolean32 reset_passwd;
sec_login_auth_src_t auth_src;
error_status_t status;
/*
* Create the local context of the DCE principal necessary
* to perform authenticated network operations. The network
* identity set up by this operation cannot be used until it
* is validated via sec_login_validate_identity().
*/
if (sec_login_setup_identity((unsigned_char_p_t) pw->pw_name,
sec_login_no_flags, &login_context, &status)) {
if (check_dce_status(status, "sec_login_setup_identity(1):"))
return(AUTH_FAILURE);
password_rec.key.key_type = sec_passwd_plain;
password_rec.key.tagged_union.plain = (idl_char *) plain_pw;
password_rec.pepper = NULL;
password_rec.version_number = sec_passwd_c_version_none;
/* Validate the login context with the password */
if (sec_login_validate_identity(login_context, &password_rec,
&reset_passwd, &auth_src, &status)) {
if (check_dce_status(status, "sec_login_validate_identity(1):"))
return(AUTH_FAILURE);
/*
* Certify that the DCE Security Server used to set
* up and validate a login context is legitimate. Makes
* sure that we didn't get spoofed by another DCE server.
*/
if (!sec_login_certify_identity(login_context, &status)) {
(void) fprintf(stderr, "Whoa! Bogus authentication server!\n");
(void) check_dce_status(status,"sec_login_certify_identity(1):");
return(AUTH_FAILURE);
}
if (check_dce_status(status, "sec_login_certify_identity(2):"))
return(AUTH_FAILURE);
/*
* Sets the network credentials to those specified
* by the now validated login context.
*/
sec_login_set_context(login_context, &status);
if (check_dce_status(status, "sec_login_set_context:"))
return(AUTH_FAILURE);
/*
* Oops, your credentials were no good. Possibly
* caused by clock times out of adjustment between
* DCE client and DCE security server...
*/
if (auth_src != sec_login_auth_src_network) {
(void) fprintf(stderr,
"You have no network credentials.\n");
return(AUTH_FAILURE);
}
/* Check if the password has aged and is thus no good */
if (reset_passwd) {
(void) fprintf(stderr,
"Your DCE password needs resetting.\n");
return(AUTH_FAILURE);
}
/*
* We should be a valid user by this point. Pull the
* user's password structure from the DCE security
* server just to make sure. If we get it with no
* problems, then we really are legitimate...
*/
sec_login_get_pwent(login_context, (sec_login_passwd_t) &temp_pw,
&status);
if (check_dce_status(status, "sec_login_get_pwent:"))
return(AUTH_FAILURE);
/*
* If we get to here, then the pwent above properly fetched
* the password structure from the DCE registry, so the user
* must be valid. We don't really care what the user's
* registry password is, just that the user could be
* validated. In fact, if we tried to compare the local
* password to the DCE entry at this point, the operation
* would fail if the hidden password feature is turned on,
* because the password field would contain an asterisk.
* Also go ahead and destroy the user's DCE login context
* before we leave here (and don't bother checking the
* status), in order to clean up credentials files in
* /opt/dcelocal/var/security/creds. By doing this, we are
* assuming that the user will not need DCE authentication
* later in the program, only local authentication. If this
* is not true, then the login_context will have to be
* returned to the calling program, and the context purged
* somewhere later in the program.
*/
sec_login_purge_context(&login_context, &status);
return(AUTH_SUCCESS);
} else {
if(check_dce_status(status, "sec_login_validate_identity(2):"))
return(AUTH_FAILURE);
sec_login_purge_context(&login_context, &status);
if(check_dce_status(status, "sec_login_purge_context:"))
return(AUTH_FAILURE);
}
}
(void) check_dce_status(status, "sec_login_setup_identity(2):");
return(AUTH_FAILURE);
}
/* Returns 0 for DCE "ok" status, 1 otherwise */
static int
check_dce_status(input_status, comment)
error_status_t input_status;
char *comment;
{
int error_stat;
unsigned char error_string[dce_c_error_string_len];
if (input_status == rpc_s_ok)
return(0);
dce_error_inq_text(input_status, error_string, &error_stat);
(void) fprintf(stderr, "%s %s\n", comment, error_string);
return(1);
}

159
plugins/sudoers/auth/fwtk.c Normal file
View File

@@ -0,0 +1,159 @@
/*
* Copyright (c) 1999-2005, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <auth.h>
#include <firewall.h>
#include "sudo.h"
#include "sudo_auth.h"
int
fwtk_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
static Cfg *confp; /* Configuration entry struct */
char resp[128]; /* Response from the server */
if ((confp = cfg_read("sudo")) == (Cfg *)-1) {
warningx("cannot read fwtk config");
return(AUTH_FATAL);
}
if (auth_open(confp)) {
warningx("cannot connect to authentication server");
return(AUTH_FATAL);
}
/* Get welcome message from auth server */
if (auth_recv(resp, sizeof(resp))) {
warningx("lost connection to authentication server");
return(AUTH_FATAL);
}
if (strncmp(resp, "Authsrv ready", 13) != 0) {
warningx("authentication server error:\n%s", resp);
return(AUTH_FATAL);
}
return(AUTH_SUCCESS);
}
int
fwtk_verify(pw, prompt, auth)
struct passwd *pw;
char *prompt;
sudo_auth *auth;
{
char *pass; /* Password from the user */
char buf[SUDO_PASS_MAX + 12]; /* General prupose buffer */
char resp[128]; /* Response from the server */
int error;
/* Send username to authentication server. */
(void) snprintf(buf, sizeof(buf), "authorize %s 'sudo'", pw->pw_name);
restart:
if (auth_send(buf) || auth_recv(resp, sizeof(resp))) {
warningx("lost connection to authentication server");
return(AUTH_FATAL);
}
/* Get the password/response from the user. */
if (strncmp(resp, "challenge ", 10) == 0) {
(void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]);
pass = tgetpass(buf, def_passwd_timeout * 60, tgetpass_flags);
if (pass && *pass == '\0') {
pass = tgetpass("Response [echo on]: ",
def_passwd_timeout * 60, tgetpass_flags | TGP_ECHO);
}
} else if (strncmp(resp, "chalnecho ", 10) == 0) {
pass = tgetpass(&resp[10], def_passwd_timeout * 60, tgetpass_flags);
} else if (strncmp(resp, "password", 8) == 0) {
pass = tgetpass(prompt, def_passwd_timeout * 60,
tgetpass_flags);
} else if (strncmp(resp, "display ", 8) == 0) {
fprintf(stderr, "%s\n", &resp[8]);
strlcpy(buf, "response dummy", sizeof(buf));
goto restart;
} else {
warningx("%s", resp);
return(AUTH_FATAL);
}
if (!pass) { /* ^C or error */
return(AUTH_INTR);
}
/* Send the user's response to the server */
(void) snprintf(buf, sizeof(buf), "response '%s'", pass);
if (auth_send(buf) || auth_recv(resp, sizeof(resp))) {
warningx("lost connection to authentication server");
error = AUTH_FATAL;
goto done;
}
if (strncmp(resp, "ok", 2) == 0) {
error = AUTH_SUCCESS;
goto done;
}
/* Main loop prints "Permission Denied" or insult. */
if (strcmp(resp, "Permission Denied.") != 0)
warningx("%s", resp);
error = AUTH_FAILURE;
done:
zero_bytes(pass, strlen(pass));
zero_bytes(buf, strlen(buf));
return(error);
}
int
fwtk_cleanup(pw, auth)
struct passwd *pw;
sudo_auth *auth;
{
auth_close();
return(AUTH_SUCCESS);
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <krb.h>
#include "sudo.h"
#include "sudo_auth.h"
int
kerb4_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
static char realm[REALM_SZ];
/* Don't try to verify root */
if (pw->pw_uid == 0)
return(AUTH_FAILURE);
/* Get the local realm, or retrun failure (no krb.conf) */
if (krb_get_lrealm(realm, 1) != KSUCCESS)
return(AUTH_FAILURE);
/* Stash a pointer to the realm (used in kerb4_verify) */
auth->data = (void *) realm;
return(AUTH_SUCCESS);
}
int
kerb4_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
char tkfile[sizeof(_PATH_SUDO_TIMEDIR) + 4 + MAX_UID_T_LEN];
char *realm = (char *) auth->data;
int error;
/*
* Set the ticket file to be in sudo sudo timedir so we don't
* wipe out other (real) kerberos tickets.
*/
(void) snprintf(tkfile, sizeof(tkfile), "%s/tkt%lu",
_PATH_SUDO_TIMEDIR, (unsigned long) pw->pw_uid);
(void) krb_set_tkt_string(tkfile);
/* Convert the password to a ticket given. */
error = krb_get_pw_in_tkt(pw->pw_name, "", realm, "krbtgt", realm,
DEFAULT_TKT_LIFE, pass);
switch (error) {
case INTK_OK:
dest_tkt(); /* we are done with the temp ticket */
return(AUTH_SUCCESS);
break;
case INTK_BADPW:
case KDC_PR_UNKNOWN:
break;
default:
(void) fprintf(stderr, "Warning: Kerberos error: %s\n",
krb_err_txt[error]);
}
return(AUTH_FAILURE);
}

View File

@@ -0,0 +1,319 @@
/*
* Copyright (c) 1999-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <krb5.h>
#ifdef HAVE_HEIMDAL
#include <com_err.h>
#endif
#include "sudo.h"
#include "sudo_auth.h"
#ifdef HAVE_HEIMDAL
# define extract_name(c, p) krb5_principal_get_comp_string(c, p, 1)
# define krb5_free_data_contents(c, d) krb5_data_free(d)
#else
# define extract_name(c, p) (krb5_princ_component(c, p, 1)->data)
#endif
#ifndef HAVE_KRB5_VERIFY_USER
static int verify_krb_v5_tgt __P((krb5_context, krb5_creds *, char *));
#endif
static struct _sudo_krb5_data {
krb5_context sudo_context;
krb5_principal princ;
krb5_ccache ccache;
} sudo_krb5_data = { NULL, NULL, NULL };
typedef struct _sudo_krb5_data *sudo_krb5_datap;
#ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
static krb5_error_code
krb5_get_init_creds_opt_alloc(context, opts)
krb5_context context;
krb5_get_init_creds_opt **opts;
{
*opts = emalloc(sizeof(krb5_get_init_creds_opt));
krb5_get_init_creds_opt_init(*opts);
return 0;
}
static void
krb5_get_init_creds_opt_free(opts)
krb5_get_init_creds_opt *opts;
{
free(opts);
}
#endif
int
kerb5_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
krb5_context sudo_context;
krb5_ccache ccache;
krb5_principal princ;
krb5_error_code error;
char cache_name[64];
char *pname;
auth->data = (void *) &sudo_krb5_data; /* Stash all our data here */
#ifdef HAVE_KRB5_INIT_SECURE_CONTEXT
error = krb5_init_secure_context(&(sudo_krb5_data.sudo_context));
#else
error = krb5_init_context(&(sudo_krb5_data.sudo_context));
#endif
if (error)
return(AUTH_FAILURE);
sudo_context = sudo_krb5_data.sudo_context;
if ((error = krb5_parse_name(sudo_context, pw->pw_name,
&(sudo_krb5_data.princ)))) {
log_error(NO_EXIT|NO_MAIL,
"%s: unable to parse '%s': %s", auth->name, pw->pw_name,
error_message(error));
return(AUTH_FAILURE);
}
princ = sudo_krb5_data.princ;
/*
* Really, we need to tell the caller not to prompt for password.
* The API does not currently provide this unless the auth is standalone.
*/
#if 1
if ((error = krb5_unparse_name(sudo_context, princ, &pname))) {
log_error(NO_EXIT|NO_MAIL,
"%s: unable to unparse princ ('%s'): %s", auth->name,
pw->pw_name, error_message(error));
return(AUTH_FAILURE);
}
/* Only rewrite prompt if user didn't specify their own. */
/*if (!strcmp(prompt, PASSPROMPT)) { */
easprintf(promptp, "Password for %s: ", pname);
/*}*/
free(pname);
#endif
(void) snprintf(cache_name, sizeof(cache_name), "MEMORY:sudocc_%ld",
(long) getpid());
if ((error = krb5_cc_resolve(sudo_context, cache_name,
&(sudo_krb5_data.ccache)))) {
log_error(NO_EXIT|NO_MAIL,
"%s: unable to resolve ccache: %s", auth->name,
error_message(error));
return(AUTH_FAILURE);
}
ccache = sudo_krb5_data.ccache;
return(AUTH_SUCCESS);
}
#ifdef HAVE_KRB5_VERIFY_USER
int
kerb5_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
krb5_context sudo_context;
krb5_principal princ;
krb5_ccache ccache;
krb5_error_code error;
sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
princ = ((sudo_krb5_datap) auth->data)->princ;
ccache = ((sudo_krb5_datap) auth->data)->ccache;
error = krb5_verify_user(sudo_context, princ, ccache, pass, 1, NULL);
return (error ? AUTH_FAILURE : AUTH_SUCCESS);
}
#else
int
kerb5_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
krb5_context sudo_context;
krb5_principal princ;
krb5_creds credbuf, *creds = NULL;
krb5_ccache ccache;
krb5_error_code error;
krb5_get_init_creds_opt *opts = NULL;
sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
princ = ((sudo_krb5_datap) auth->data)->princ;
ccache = ((sudo_krb5_datap) auth->data)->ccache;
/* Set default flags based on the local config file. */
error = krb5_get_init_creds_opt_alloc(sudo_context, &opts);
if (error) {
log_error(NO_EXIT|NO_MAIL,
"%s: unable to allocate options: %s", auth->name,
error_message(error));
goto done;
}
#ifdef HAVE_HEIMDAL
krb5_get_init_creds_opt_set_default_flags(sudo_context, NULL,
krb5_principal_get_realm(sudo_context, princ), opts);
#endif
/* Note that we always obtain a new TGT to verify the user */
if ((error = krb5_get_init_creds_password(sudo_context, &credbuf, princ,
pass, krb5_prompter_posix,
NULL, 0, NULL, opts))) {
/* Don't print error if just a bad password */
if (error != KRB5KRB_AP_ERR_BAD_INTEGRITY)
log_error(NO_EXIT|NO_MAIL,
"%s: unable to get credentials: %s", auth->name,
error_message(error));
goto done;
}
creds = &credbuf;
/* Verify the TGT to prevent spoof attacks. */
if ((error = verify_krb_v5_tgt(sudo_context, creds, auth->name)))
goto done;
/* Store cred in cred cache. */
if ((error = krb5_cc_initialize(sudo_context, ccache, princ))) {
log_error(NO_EXIT|NO_MAIL,
"%s: unable to initialize ccache: %s", auth->name,
error_message(error));
} else if ((error = krb5_cc_store_cred(sudo_context, ccache, creds))) {
log_error(NO_EXIT|NO_MAIL,
"%s: unable to store cred in ccache: %s", auth->name,
error_message(error));
}
done:
if (opts) {
#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS
krb5_get_init_creds_opt_free(sudo_context, opts);
#else
krb5_get_init_creds_opt_free(opts);
#endif
}
if (creds)
krb5_free_cred_contents(sudo_context, creds);
return (error ? AUTH_FAILURE : AUTH_SUCCESS);
}
#endif
int
kerb5_cleanup(pw, auth)
struct passwd *pw;
sudo_auth *auth;
{
krb5_context sudo_context;
krb5_principal princ;
krb5_ccache ccache;
sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
princ = ((sudo_krb5_datap) auth->data)->princ;
ccache = ((sudo_krb5_datap) auth->data)->ccache;
if (sudo_context) {
if (ccache)
krb5_cc_destroy(sudo_context, ccache);
if (princ)
krb5_free_principal(sudo_context, princ);
krb5_free_context(sudo_context);
}
return(AUTH_SUCCESS);
}
#ifndef HAVE_KRB5_VERIFY_USER
/*
* Verify the Kerberos ticket-granting ticket just retrieved for the
* user. If the Kerberos server doesn't respond, assume the user is
* trying to fake us out (since we DID just get a TGT from what is
* supposedly our KDC).
*
* Returns 0 for successful authentication, non-zero for failure.
*/
static int
verify_krb_v5_tgt(sudo_context, cred, auth_name)
krb5_context sudo_context;
krb5_creds *cred;
char *auth_name; /* For error reporting */
{
krb5_error_code error;
krb5_principal server;
krb5_verify_init_creds_opt vopt;
/*
* Get the server principal for the local host.
* (Use defaults of "host" and canonicalized local name.)
*/
if ((error = krb5_sname_to_principal(sudo_context, NULL, NULL,
KRB5_NT_SRV_HST, &server))) {
log_error(NO_EXIT|NO_MAIL,
"%s: unable to get host principal: %s", auth_name,
error_message(error));
return(-1);
}
/* Initialize verify opts and set secure mode */
krb5_verify_init_creds_opt_init(&vopt);
krb5_verify_init_creds_opt_set_ap_req_nofail(&vopt, 1);
/* verify the Kerberos ticket-granting ticket we just retrieved */
error = krb5_verify_init_creds(sudo_context, cred, server, NULL,
NULL, &vopt);
krb5_free_principal(sudo_context, server);
if (error)
log_error(NO_EXIT|NO_MAIL,
"%s: Cannot verify TGT! Possible attack!: %s", auth_name,
error_message(error));
return(error);
}
#endif

336
plugins/sudoers/auth/pam.c Normal file
View File

@@ -0,0 +1,336 @@
/*
* Copyright (c) 1999-2005, 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
# include <memory.h>
# endif
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <errno.h>
#ifdef HAVE_PAM_PAM_APPL_H
# include <pam/pam_appl.h>
#else
# include <security/pam_appl.h>
#endif
#ifdef HAVE_DGETTEXT
# include <libintl.h>
# if defined(__LINUX_PAM__)
# define PAM_TEXT_DOMAIN "Linux-PAM"
# elif defined(__sun__)
# define PAM_TEXT_DOMAIN "SUNW_OST_SYSOSPAM"
# endif
#endif
#include "sudo.h"
#include "sudo_auth.h"
/* Only OpenPAM and Linux PAM use const qualifiers. */
#if defined(_OPENPAM) || defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__)
# define PAM_CONST const
#else
# define PAM_CONST
#endif
static int sudo_conv __P((int, PAM_CONST struct pam_message **,
struct pam_response **, void *));
static char *def_prompt = "Password:";
static int gotintr;
#ifndef PAM_DATA_SILENT
#define PAM_DATA_SILENT 0
#endif
static pam_handle_t *pamh; /* global due to pam_prep_user() */
int
pam_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
static struct pam_conv pam_conv;
static int pam_status;
/* Initial PAM setup */
if (auth != NULL)
auth->data = (void *) &pam_status;
pam_conv.conv = sudo_conv;
pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh);
if (pam_status != PAM_SUCCESS) {
log_error(USE_ERRNO|NO_EXIT|NO_MAIL, "unable to initialize PAM");
return(AUTH_FATAL);
}
/*
* Set PAM_RUSER to the invoking user (the "from" user).
* We set PAM_RHOST to avoid a bug in Solaris 7 and below.
*/
(void) pam_set_item(pamh, PAM_RUSER, user_name);
(void) pam_set_item(pamh, PAM_RHOST, user_host);
/*
* Some versions of pam_lastlog have a bug that
* will cause a crash if PAM_TTY is not set so if
* there is no tty, set PAM_TTY to the empty string.
*/
if (user_ttypath == NULL)
(void) pam_set_item(pamh, PAM_TTY, "");
else
(void) pam_set_item(pamh, PAM_TTY, user_ttypath);
return(AUTH_SUCCESS);
}
int
pam_verify(pw, prompt, auth)
struct passwd *pw;
char *prompt;
sudo_auth *auth;
{
const char *s;
int *pam_status = (int *) auth->data;
def_prompt = prompt; /* for sudo_conv */
/* PAM_SILENT prevents the authentication service from generating output. */
*pam_status = pam_authenticate(pamh, PAM_SILENT);
switch (*pam_status) {
case PAM_SUCCESS:
*pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
switch (*pam_status) {
case PAM_SUCCESS:
return(AUTH_SUCCESS);
case PAM_AUTH_ERR:
log_error(NO_EXIT|NO_MAIL, "pam_acct_mgmt: %d",
*pam_status);
return(AUTH_FAILURE);
case PAM_NEW_AUTHTOK_REQD:
log_error(NO_EXIT|NO_MAIL, "%s, %s",
"Account or password is expired",
"reset your password and try again");
*pam_status = pam_chauthtok(pamh,
PAM_CHANGE_EXPIRED_AUTHTOK);
if (*pam_status == PAM_SUCCESS)
return(AUTH_SUCCESS);
if ((s = pam_strerror(pamh, *pam_status)))
log_error(NO_EXIT|NO_MAIL, "pam_chauthtok: %s", s);
return(AUTH_FAILURE);
case PAM_AUTHTOK_EXPIRED:
log_error(NO_EXIT|NO_MAIL,
"Password expired, contact your system administrator");
return(AUTH_FATAL);
case PAM_ACCT_EXPIRED:
log_error(NO_EXIT|NO_MAIL, "%s %s",
"Account expired or PAM config lacks an \"account\"",
"section for sudo, contact your system administrator");
return(AUTH_FATAL);
}
/* FALLTHROUGH */
case PAM_AUTH_ERR:
if (gotintr) {
/* error or ^C from tgetpass() */
return(AUTH_INTR);
}
case PAM_MAXTRIES:
case PAM_PERM_DENIED:
return(AUTH_FAILURE);
default:
if ((s = pam_strerror(pamh, *pam_status)))
log_error(NO_EXIT|NO_MAIL, "pam_authenticate: %s", s);
return(AUTH_FATAL);
}
}
int
pam_cleanup(pw, auth)
struct passwd *pw;
sudo_auth *auth;
{
int *pam_status = (int *) auth->data;
/* If successful, we can't close the session until pam_prep_user() */
if (auth->status == AUTH_SUCCESS)
return(AUTH_SUCCESS);
*pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT);
return(*pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
}
int
pam_prep_user(pw)
struct passwd *pw;
{
int eval;
if (pamh == NULL)
pam_init(pw, NULL, NULL);
/*
* Update PAM_USER to reference the user we are running the command
* as, as opposed to the user we authenticated as.
*/
(void) pam_set_item(pamh, PAM_USER, pw->pw_name);
/*
* Set credentials (may include resource limits, device ownership, etc).
* We don't check the return value here because in Linux-PAM 0.75
* it returns the last saved return code, not the return code
* for the setcred module. Because we haven't called pam_authenticate(),
* this is not set and so pam_setcred() returns PAM_PERM_DENIED.
* We can't call pam_acct_mgmt() with Linux-PAM for a similar reason.
*/
(void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
#ifndef NO_PAM_SESSION
/*
* To fully utilize PAM sessions we would need to keep a
* sudo process around until the command exits. However, we
* can at least cause pam_limits to be run by opening and then
* immediately closing the session.
*/
if ((eval = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
(void) pam_end(pamh, eval | PAM_DATA_SILENT);
return(AUTH_FAILURE);
}
(void) pam_close_session(pamh, 0);
#endif
if (pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT) == PAM_SUCCESS)
return(AUTH_SUCCESS);
else
return(AUTH_FAILURE);
}
/*
* ``Conversation function'' for PAM.
* XXX - does not handle PAM_BINARY_PROMPT
*/
static int
sudo_conv(num_msg, msg, response, appdata_ptr)
int num_msg;
PAM_CONST struct pam_message **msg;
struct pam_response **response;
void *appdata_ptr;
{
struct pam_response *pr;
PAM_CONST struct pam_message *pm;
const char *prompt;
char *pass;
int n, flags, std_prompt;
if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
return(PAM_SYSTEM_ERR);
zero_bytes(*response, num_msg * sizeof(struct pam_response));
for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
flags = tgetpass_flags;
switch (pm->msg_style) {
case PAM_PROMPT_ECHO_ON:
SET(flags, TGP_ECHO);
case PAM_PROMPT_ECHO_OFF:
prompt = def_prompt;
/* Is the sudo prompt standard? (If so, we'l just use PAM's) */
std_prompt = strncmp(def_prompt, "Password:", 9) == 0 &&
(def_prompt[9] == '\0' ||
(def_prompt[9] == ' ' && def_prompt[10] == '\0'));
/* Only override PAM prompt if it matches /^Password: ?/ */
#if defined(PAM_TEXT_DOMAIN) && defined(HAVE_DGETTEXT)
if (!def_passprompt_override && (std_prompt ||
(strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password: ")) &&
strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password:")))))
prompt = pm->msg;
#else
if (!def_passprompt_override && (std_prompt ||
strncmp(pm->msg, "Password:", 9) || (pm->msg[9] != '\0'
&& (pm->msg[9] != ' ' || pm->msg[10] != '\0'))))
prompt = pm->msg;
#endif
/* Read the password unless interrupted. */
pass = tgetpass(prompt, def_passwd_timeout * 60, flags);
if (pass == NULL) {
/* We got ^C instead of a password; abort quickly. */
if (errno == EINTR)
gotintr = 1;
#if defined(__darwin__) || defined(__APPLE__)
pass = "";
#else
goto err;
#endif
}
pr->resp = estrdup(pass);
zero_bytes(pass, strlen(pass));
break;
case PAM_TEXT_INFO:
if (pm->msg)
(void) puts(pm->msg);
break;
case PAM_ERROR_MSG:
if (pm->msg) {
(void) fputs(pm->msg, stderr);
(void) fputc('\n', stderr);
}
break;
default:
goto err;
}
}
return(PAM_SUCCESS);
err:
/* Zero and free allocated memory and return an error. */
for (pr = *response, n = num_msg; n--; pr++) {
if (pr->resp != NULL) {
zero_bytes(pr->resp, strlen(pr->resp));
free(pr->resp);
pr->resp = NULL;
}
}
zero_bytes(*response, num_msg * sizeof(struct pam_response));
free(*response);
*response = NULL;
return(gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR);
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include "sudo.h"
#include "sudo_auth.h"
#define DESLEN 13
#define HAS_AGEINFO(p, l) (l == 18 && p[DESLEN] == ',')
int
passwd_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
#ifdef HAVE_SKEYACCESS
if (skeyaccess(pw, user_tty, NULL, NULL) == 0)
return(AUTH_FAILURE);
#endif
return(AUTH_SUCCESS);
}
int
passwd_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
char sav, *epass;
size_t pw_len;
int error;
pw_len = strlen(pw->pw_passwd);
#ifdef HAVE_GETAUTHUID
/* Ultrix shadow passwords may use crypt16() */
error = strcmp(pw->pw_passwd, (char *) crypt16(pass, pw->pw_passwd));
if (!error)
return(AUTH_SUCCESS);
#endif /* HAVE_GETAUTHUID */
/*
* Truncate to 8 chars if standard DES since not all crypt()'s do this.
* If this turns out not to be safe we will have to use OS #ifdef's (sigh).
*/
sav = pass[8];
if (pw_len == DESLEN || HAS_AGEINFO(pw->pw_passwd, pw_len))
pass[8] = '\0';
/*
* Normal UN*X password check.
* HP-UX may add aging info (separated by a ',') at the end so
* only compare the first DESLEN characters in that case.
*/
epass = (char *) crypt(pass, pw->pw_passwd);
pass[8] = sav;
if (HAS_AGEINFO(pw->pw_passwd, pw_len) && strlen(epass) == DESLEN)
error = strncmp(pw->pw_passwd, epass, DESLEN);
else
error = strcmp(pw->pw_passwd, epass);
return(error ? AUTH_FAILURE : AUTH_SUCCESS);
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 1994-1996, 1998-2005
* Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#if defined(HAVE_SKEY)
# include <skey.h>
# define RFC1938 skey
# ifdef __NetBSD__
# define rfc1938challenge(a,b,c,d) skeychallenge((a),(b),(c),(d))
# else
# define rfc1938challenge(a,b,c,d) skeychallenge((a),(b),(c))
# endif
# define rfc1938verify(a,b) skeyverify((a),(b))
#elif defined(HAVE_OPIE)
# include <opie.h>
# define RFC1938 opie
# define rfc1938challenge(a,b,c,d) opiechallenge((a),(b),(c))
# define rfc1938verify(a,b) opieverify((a),(b))
#endif
#include "sudo.h"
#include "sudo_auth.h"
int
rfc1938_setup(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
char challenge[256];
static char *orig_prompt = NULL, *new_prompt = NULL;
static int op_len, np_size;
static struct RFC1938 rfc1938;
/* Stash a pointer to the rfc1938 struct if we have not initialized */
if (!auth->data)
auth->data = &rfc1938;
/* Save the original prompt */
if (orig_prompt == NULL) {
orig_prompt = *promptp;
op_len = strlen(orig_prompt);
/* Ignore trailing colon (we will add our own) */
if (orig_prompt[op_len - 1] == ':')
op_len--;
else if (op_len >= 2 && orig_prompt[op_len - 1] == ' '
&& orig_prompt[op_len - 2] == ':')
op_len -= 2;
}
#ifdef HAVE_SKEY
/* Close old stream */
if (rfc1938.keyfile)
(void) fclose(rfc1938.keyfile);
#endif
/*
* Look up the user and get the rfc1938 challenge.
* If the user is not in the OTP db, only post a fatal error if
* we are running alone (since they may just use a normal passwd).
*/
if (rfc1938challenge(&rfc1938, pw->pw_name, challenge, sizeof(challenge))) {
if (IS_ONEANDONLY(auth)) {
warningx("you do not exist in the %s database", auth->name);
return(AUTH_FATAL);
} else {
return(AUTH_FAILURE);
}
}
/* Get space for new prompt with embedded challenge */
if (np_size < op_len + strlen(challenge) + 7) {
np_size = op_len + strlen(challenge) + 7;
new_prompt = (char *) erealloc(new_prompt, np_size);
}
if (def_long_otp_prompt)
(void) snprintf(new_prompt, np_size, "%s\n%s", challenge, orig_prompt);
else
(void) snprintf(new_prompt, np_size, "%.*s [ %s ]:", op_len,
orig_prompt, challenge);
*promptp = new_prompt;
return(AUTH_SUCCESS);
}
int
rfc1938_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
if (rfc1938verify((struct RFC1938 *) auth->data, pass) == 0)
return(AUTH_SUCCESS);
else
return(AUTH_FAILURE);
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#ifdef __hpux
# undef MAXINT
# include <hpsecurity.h>
#else
# include <sys/security.h>
#endif /* __hpux */
#include <prot.h>
#include "sudo.h"
#include "sudo_auth.h"
int
secureware_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
#ifdef __alpha
extern int crypt_type;
if (crypt_type == INT_MAX)
return(AUTH_FAILURE); /* no shadow */
#endif
return(AUTH_SUCCESS);
}
int
secureware_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
#ifdef __alpha
extern int crypt_type;
# ifdef HAVE_DISPCRYPT
if (strcmp(user_passwd, dispcrypt(pass, user_passwd, crypt_type)) == 0)
return(AUTH_SUCCESS);
# else
if (crypt_type == AUTH_CRYPT_BIGCRYPT) {
if (strcmp(user_passwd, bigcrypt(pass, user_passwd)) == 0)
return(AUTH_SUCCESS);
} else if (crypt_type == AUTH_CRYPT_CRYPT16) {
if (strcmp(user_passwd, crypt(pass, user_passwd)) == 0)
return(AUTH_SUCCESS);
}
# endif /* HAVE_DISPCRYPT */
#elif defined(HAVE_BIGCRYPT)
if (strcmp(user_passwd, bigcrypt(pass, user_passwd)) == 0)
return(AUTH_SUCCESS);
#endif /* __alpha */
return(AUTH_FAILURE);
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <sdi_athd.h>
#include <sdconf.h>
#include <sdacmvls.h>
#include "sudo.h"
#include "sudo_auth.h"
union config_record configure;
int
securid_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
static struct SD_CLIENT sd_dat; /* SecurID data block */
auth->data = (void *) &sd_dat; /* For method-specific data */
if (creadcfg() == 0)
return(AUTH_SUCCESS);
else
return(AUTH_FATAL);
}
int
securid_setup(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data;
/* Re-initialize SecurID every time. */
if (sd_init(sd) == 0) {
/* The programmer's guide says username is 32 bytes */
strlcpy(sd->username, pw->pw_name, 32);
return(AUTH_SUCCESS);
} else {
warningx("unable to contact the SecurID server");
return(AUTH_FATAL);
}
}
int
securid_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data;
int rval;
rval = sd_auth(sd);
sd_close();
if (rval == ACM_OK)
return(AUTH_SUCCESS);
else
return(AUTH_FAILURE);
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
* Copyright (c) 2002 Michael Stroucken <michael@stroucken.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
/* Needed for SecurID v5.0 Authentication on UNIX */
#define UNIX 1
#include <acexport.h>
#include <sdacmvls.h>
#include "sudo.h"
#include "sudo_auth.h"
/*
* securid_init - Initialises communications with ACE server
* Arguments in:
* pw - UNUSED
* promptp - UNUSED
* auth - sudo authentication structure
*
* Results out:
* auth - auth->data contains pointer to new SecurID handle
* return code - Fatal if initialization unsuccessful, otherwise
* success.
*/
int
securid_init(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
static SDI_HANDLE sd_dat; /* SecurID handle */
auth->data = (void *) &sd_dat; /* For method-specific data */
/* Start communications */
if (AceInitialize() != SD_FALSE)
return(AUTH_SUCCESS);
warningx("failed to initialise the ACE API library");
return(AUTH_FATAL);
}
/*
* securid_setup - Initialises a SecurID transaction and locks out other
* ACE servers
*
* Arguments in:
* pw - struct passwd for username
* promptp - UNUSED
* auth - sudo authentication structure for SecurID handle
*
* Results out:
* return code - Success if transaction started correctly, fatal
* otherwise
*/
int
securid_setup(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
SDI_HANDLE *sd = (SDI_HANDLE *) auth->data;
int retval;
/* Re-initialize SecurID every time. */
if (SD_Init(sd) != ACM_OK) {
warningx("unable to contact the SecurID server");
return(AUTH_FATAL);
}
/* Lock new PIN code */
retval = SD_Lock(*sd, pw->pw_name);
switch (retval) {
case ACM_OK:
warningx("User ID locked for SecurID Authentication");
return(AUTH_SUCCESS);
case ACE_UNDEFINED_USERNAME:
warningx("invalid username length for SecurID");
return(AUTH_FATAL);
case ACE_ERR_INVALID_HANDLE:
warningx("invalid Authentication Handle for SecurID");
return(AUTH_FATAL);
case ACM_ACCESS_DENIED:
warningx("SecurID communication failed");
return(AUTH_FATAL);
default:
warningx("unknown SecurID error");
return(AUTH_FATAL);
}
}
/*
* securid_verify - Authenticates user and handles ACE responses
*
* Arguments in:
* pw - struct passwd for username
* pass - UNUSED
* auth - sudo authentication structure for SecurID handle
*
* Results out:
* return code - Success on successful authentication, failure on
* incorrect authentication, fatal on errors
*/
int
securid_verify(pw, pass, auth)
struct passwd *pw;
char *pass;
sudo_auth *auth;
{
SDI_HANDLE *sd = (SDI_HANDLE *) auth->data;
int rval;
pass = (char *) tgetpass("Enter your PASSCODE: ",
def_passwd_timeout * 60, tgetpass_flags);
/* Have ACE verify password */
switch (SD_Check(*sd, pass, pw->pw_name)) {
case ACM_OK:
rval = AUTH_SUCESS;
break;
case ACE_UNDEFINED_PASSCODE:
warningx("invalid passcode length for SecurID");
rval = AUTH_FATAL;
break;
case ACE_UNDEFINED_USERNAME:
warningx("invalid username length for SecurID");
rval = AUTH_FATAL;
break;
case ACE_ERR_INVALID_HANDLE:
warningx("invalid Authentication Handle for SecurID");
rval = AUTH_FATAL;
break;
case ACM_ACCESS_DENIED:
rval = AUTH_FAILURE;
break;
case ACM_NEXT_CODE_REQUIRED:
/* Sometimes (when current token close to expire?)
ACE challenges for the next token displayed
(entered without the PIN) */
pass = (char *) tgetpass("\
!!! ATTENTION !!!\n\
Wait for the token code to change, \n\
then enter the new token code.\n", \
def_passwd_timeout * 60, tgetpass_flags);
if (SD_Next(*sd, pass) == ACM_OK) {
rval = AUTH_SUCCESS;
break;
}
rval = AUTH_FAILURE;
break;
case ACM_NEW_PIN_REQUIRED:
/*
* This user's SecurID has not been activated yet,
* or the pin has been reset
*/
/* XXX - Is setting up a new PIN within sudo's scope? */
SD_Pin(*sd, "");
fprintf(stderr, "Your SecurID access has not yet been set up.\n");
fprintf(stderr, "Please set up a PIN before you try to authenticate.\n");
rval = AUTH_FATAL;
break;
default:
warningx("unknown SecurID error");
rval = AUTH_FATAL;
break;
}
/* Free resources */
SD_Close(*sd);
/* Return stored state to calling process */
return(rval);
}

137
plugins/sudoers/auth/sia.c Normal file
View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 1999-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <siad.h>
#include "sudo.h"
#include "sudo_auth.h"
static int sudo_collect __P((int, int, uchar_t *, int, prompt_t *));
static char *def_prompt;
/*
* Collection routine (callback) for limiting the timeouts in SIA
* prompts and (possibly) setting a custom prompt.
*/
static int
sudo_collect(timeout, rendition, title, nprompts, prompts)
int timeout;
int rendition;
uchar_t *title;
int nprompts;
prompt_t *prompts;
{
switch (rendition) {
case SIAFORM:
case SIAONELINER:
if (timeout <= 0 || timeout > def_passwd_timeout * 60)
timeout = def_passwd_timeout * 60;
/*
* Substitute custom prompt if a) the sudo prompt is not "Password:"
* and b) the SIA prompt is "Password:" (so we know it is safe).
* This keeps us from overwriting things like S/Key challenges.
*/
if (strcmp((char *)prompts[0].prompt, "Password:") == 0 &&
strcmp(def_prompt, "Password:") != 0)
prompts[0].prompt = (unsigned char *)def_prompt;
break;
default:
break;
}
return sia_collect_trm(timeout, rendition, title, nprompts, prompts);
}
int
sia_setup(pw, promptp, auth)
struct passwd *pw;
char **promptp;
sudo_auth *auth;
{
SIAENTITY *siah = NULL;
extern int Argc;
extern char **Argv;
if (sia_ses_init(&siah, Argc, Argv, NULL, pw->pw_name, ttyname(0), 1, NULL)
!= SIASUCCESS) {
log_error(USE_ERRNO|NO_EXIT|NO_MAIL,
"unable to initialize SIA session");
return(AUTH_FATAL);
}
auth->data = (void *) siah;
return(AUTH_SUCCESS);
}
int
sia_verify(pw, prompt, auth)
struct passwd *pw;
char *prompt;
sudo_auth *auth;
{
SIAENTITY *siah = (SIAENTITY *) auth->data;
def_prompt = prompt; /* for sudo_collect */
/* XXX - need a way to detect user hitting return or EOF at prompt */
if (sia_ses_reauthent(sudo_collect, siah) == SIASUCCESS)
return(AUTH_SUCCESS);
else
return(AUTH_FAILURE);
}
int
sia_cleanup(pw, auth)
struct passwd *pw;
sudo_auth *auth;
{
SIAENTITY *siah = (SIAENTITY *) auth->data;
(void) sia_ses_release(&siah);
return(AUTH_SUCCESS);
}

View File

@@ -0,0 +1,269 @@
/*
* Copyright (c) 1999-2005, 2008-2009 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
# include <memory.h>
# endif
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif /* HAVE_STRING_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
#include <time.h>
#include <signal.h>
#include "sudo.h"
#include "sudo_auth.h"
#include "insults.h"
sudo_auth auth_switch[] = {
#ifdef AUTH_STANDALONE
AUTH_STANDALONE
#else
# ifndef WITHOUT_PASSWD
AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, NULL)
# endif
# if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, NULL)
# endif
# ifdef HAVE_AFS
AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL)
# endif
# ifdef HAVE_DCE
AUTH_ENTRY(0, "dce", NULL, NULL, dce_verify, NULL)
# endif
# ifdef HAVE_KERB4
AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL)
# endif
# ifdef HAVE_KERB5
AUTH_ENTRY(0, "kerb5", kerb5_init, NULL, kerb5_verify, kerb5_cleanup)
# endif
# ifdef HAVE_SKEY
AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL)
# endif
# ifdef HAVE_OPIE
AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL)
# endif
#endif /* AUTH_STANDALONE */
AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL)
};
void
verify_user(pw, prompt)
struct passwd *pw;
char *prompt;
{
int counter = def_passwd_tries + 1;
int success = AUTH_FAILURE;
int status;
int flags;
char *p;
sudo_auth *auth;
sigaction_t sa, osa;
#ifdef HAVE_BSM_AUDIT
extern char **NewArgv;
#endif
/* Enable suspend during password entry. */
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_DFL;
(void) sigaction(SIGTSTP, &sa, &osa);
/* Make sure we have at least one auth method. */
if (auth_switch[0].name == NULL) {
#ifdef HAVE_BSM_AUDIT
audit_failure(NewArgv, "no authentication methods");
#endif
log_error(0, "%s %s %s",
"There are no authentication methods compiled into sudo!",
"If you want to turn off authentication, use the",
"--disable-authentication configure option.");
}
/* Set FLAG_ONEANDONLY if there is only one auth method. */
if (auth_switch[1].name == NULL)
SET(auth_switch[0].flags, FLAG_ONEANDONLY);
/* Initialize auth methods and unconfigure the method if necessary. */
for (auth = auth_switch; auth->name; auth++) {
if (auth->init && IS_CONFIGURED(auth)) {
if (NEEDS_USER(auth))
set_perms(PERM_USER);
status = (auth->init)(pw, &prompt, auth);
if (status == AUTH_FAILURE)
CLR(auth->flags, FLAG_CONFIGURED);
else if (status == AUTH_FATAL) { /* XXX log */
#ifdef HAVE_BSM_AUDIT
audit_failure(NewArgv, "authentication failure");
#endif
exit(1); /* assume error msg already printed */
}
if (NEEDS_USER(auth))
set_perms(PERM_ROOT);
}
}
while (--counter) {
/* Do any per-method setup and unconfigure the method if needed */
for (auth = auth_switch; auth->name; auth++) {
if (auth->setup && IS_CONFIGURED(auth)) {
if (NEEDS_USER(auth))
set_perms(PERM_USER);
status = (auth->setup)(pw, &prompt, auth);
if (status == AUTH_FAILURE)
CLR(auth->flags, FLAG_CONFIGURED);
else if (status == AUTH_FATAL) {/* XXX log */
#ifdef HAVE_BSM_AUDIT
audit_failure(NewArgv, "authentication failure");
#endif
exit(1); /* assume error msg already printed */
}
if (NEEDS_USER(auth))
set_perms(PERM_ROOT);
}
}
/* Get the password unless the auth function will do it for us */
#ifdef AUTH_STANDALONE
p = prompt;
#else
p = (char *) tgetpass(prompt, def_passwd_timeout * 60,
tgetpass_flags);
#endif /* AUTH_STANDALONE */
/* Call authentication functions. */
for (auth = auth_switch; p && auth->name; auth++) {
if (!IS_CONFIGURED(auth))
continue;
if (NEEDS_USER(auth))
set_perms(PERM_USER);
success = auth->status = (auth->verify)(pw, (char *)p, auth);
if (NEEDS_USER(auth))
set_perms(PERM_ROOT);
if (auth->status != AUTH_FAILURE)
goto cleanup;
}
#ifndef AUTH_STANDALONE
if (p)
zero_bytes(p, strlen(p));
#endif
if (!ISSET(tgetpass_flags, TGP_ASKPASS))
pass_warn(stderr);
}
cleanup:
/* Call cleanup routines. */
for (auth = auth_switch; auth->name; auth++) {
if (auth->cleanup && IS_CONFIGURED(auth)) {
if (NEEDS_USER(auth))
set_perms(PERM_USER);
status = (auth->cleanup)(pw, auth);
if (status == AUTH_FATAL) { /* XXX log */
#ifdef HAVE_BSM_AUDIT
audit_failure(NewArgv, "authentication failure");
#endif
exit(1); /* assume error msg already printed */
}
if (NEEDS_USER(auth))
set_perms(PERM_ROOT);
}
}
switch (success) {
case AUTH_SUCCESS:
(void) sigaction(SIGTSTP, &osa, NULL);
return;
case AUTH_INTR:
case AUTH_FAILURE:
if (counter != def_passwd_tries) {
if (def_mail_badpass || def_mail_always)
flags = 0;
else
flags = NO_MAIL;
#ifdef HAVE_BSM_AUDIT
audit_failure(NewArgv, "authentication failure");
#endif
log_error(flags, "%d incorrect password attempt%s",
def_passwd_tries - counter,
(def_passwd_tries - counter == 1) ? "" : "s");
}
/* FALLTHROUGH */
case AUTH_FATAL:
#ifdef HAVE_BSM_AUDIT
audit_failure(NewArgv, "authentication failure");
#endif
exit(1);
}
/* NOTREACHED */
}
void
pass_warn(fp)
FILE *fp;
{
#ifdef INSULT
if (def_insults)
(void) fprintf(fp, "%s\n", INSULT);
else
#endif
(void) fprintf(fp, "%s\n", def_badpass_message);
}
void
dump_auth_methods()
{
sudo_auth *auth;
(void) fputs("Authentication methods:", stdout);
for (auth = auth_switch; auth->name; auth++)
(void) printf(" '%s'", auth->name);
(void) putchar('\n');
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 1999-2005, 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef SUDO_AUTH_H
#define SUDO_AUTH_H
/* Auth function return values. */
#define AUTH_SUCCESS 0
#define AUTH_FAILURE 1
#define AUTH_INTR 2
#define AUTH_FATAL 3
typedef struct sudo_auth {
short flags; /* various flags, see below */
short status; /* status from verify routine */
char *name; /* name of the method as a string */
void *data; /* method-specific data pointer */
int (*init) __P((struct passwd *pw, char **prompt, struct sudo_auth *auth));
int (*setup) __P((struct passwd *pw, char **prompt, struct sudo_auth *auth));
int (*verify) __P((struct passwd *pw, char *p, struct sudo_auth *auth));
int (*cleanup) __P((struct passwd *pw, struct sudo_auth *auth));
} sudo_auth;
/* Values for sudo_auth.flags. */
/* XXX - these names are too long for my liking */
#define FLAG_USER 0x01 /* functions must run as the user, not root */
#define FLAG_CONFIGURED 0x02 /* method configured ok */
#define FLAG_ONEANDONLY 0x04 /* one and only auth method */
/* Shortcuts for using the flags above. */
#define NEEDS_USER(x) ((x)->flags & FLAG_USER)
#define IS_CONFIGURED(x) ((x)->flags & FLAG_CONFIGURED)
#define IS_ONEANDONLY(x) ((x)->flags & FLAG_ONEANDONLY)
/* Prototypes for standalone methods */
int fwtk_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int fwtk_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth));
int fwtk_cleanup __P((struct passwd *pw, sudo_auth *auth));
int pam_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int pam_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth));
int pam_cleanup __P((struct passwd *pw, sudo_auth *auth));
int sia_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int sia_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth));
int sia_cleanup __P((struct passwd *pw, sudo_auth *auth));
int aixauth_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
int aixauth_cleanup __P((struct passwd *pw, sudo_auth *auth));
int bsdauth_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int bsdauth_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth));
int bsdauth_cleanup __P((struct passwd *pw, sudo_auth *auth));
/* Prototypes for normal methods */
int passwd_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int passwd_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
int secureware_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int secureware_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
int rfc1938_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int rfc1938_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
int afs_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
int dce_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
int kerb4_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int kerb4_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
int kerb5_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int kerb5_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
int kerb5_cleanup __P((struct passwd *pw, sudo_auth *auth));
int securid_init __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int securid_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth));
int securid_verify __P((struct passwd *pw, char *pass, sudo_auth *auth));
/* Fields: need_root, name, init, setup, verify, cleanup */
#define AUTH_ENTRY(r, n, i, s, v, c) \
{ (r|FLAG_CONFIGURED), AUTH_FAILURE, n, NULL, i, s, v, c },
/* Some methods cannots (or should not) interoperate with any others */
#if defined(HAVE_PAM)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "pam", \
pam_init, NULL, pam_verify, pam_cleanup)
#elif defined(HAVE_SECURID)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "SecurId", \
securid_init, securid_setup, securid_verify, NULL)
#elif defined(HAVE_SIA_SES_INIT)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "sia", \
NULL, sia_setup, sia_verify, sia_cleanup)
#elif defined(HAVE_AIXAUTH)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "aixauth", \
NULL, NULL, aixauth_verify, aixauth_cleanup)
#elif defined(HAVE_FWTK)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "fwtk", \
fwtk_init, NULL, fwtk_verify, fwtk_cleanup)
#elif defined(HAVE_BSD_AUTH_H)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "bsdauth", \
bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup)
#endif
#endif /* SUDO_AUTH_H */