diff options
Diffstat (limited to 'usr.bin/sudo/auth')
-rw-r--r-- | usr.bin/sudo/auth/API | 128 | ||||
-rw-r--r-- | usr.bin/sudo/auth/afs.c | 98 | ||||
-rw-r--r-- | usr.bin/sudo/auth/aix_auth.c | 75 | ||||
-rw-r--r-- | usr.bin/sudo/auth/dce.c | 214 | ||||
-rw-r--r-- | usr.bin/sudo/auth/fwtk.c | 156 | ||||
-rw-r--r-- | usr.bin/sudo/auth/kerb4.c | 119 | ||||
-rw-r--r-- | usr.bin/sudo/auth/kerb5.c | 312 | ||||
-rw-r--r-- | usr.bin/sudo/auth/pam.c | 171 | ||||
-rw-r--r-- | usr.bin/sudo/auth/passwd.c | 79 | ||||
-rw-r--r-- | usr.bin/sudo/auth/rfc1938.c | 150 | ||||
-rw-r--r-- | usr.bin/sudo/auth/secureware.c | 110 | ||||
-rw-r--r-- | usr.bin/sudo/auth/securid.c | 111 | ||||
-rw-r--r-- | usr.bin/sudo/auth/sia.c | 147 | ||||
-rw-r--r-- | usr.bin/sudo/auth/sudo_auth.c | 243 | ||||
-rw-r--r-- | usr.bin/sudo/auth/sudo_auth.h | 123 |
15 files changed, 2236 insertions, 0 deletions
diff --git a/usr.bin/sudo/auth/API b/usr.bin/sudo/auth/API new file mode 100644 index 00000000000..4b336cc8c83 --- /dev/null +++ b/usr.bin/sudo/auth/API @@ -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. diff --git a/usr.bin/sudo/auth/afs.c b/usr.bin/sudo/auth/afs.c new file mode 100644 index 00000000000..e9f6070ca4b --- /dev/null +++ b/usr.bin/sudo/auth/afs.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> + +#include <afs/stds.h> +#include <afs/kautils.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: afs.c,v 1.5 1999/08/14 15:36:45 millert Exp $"; +#endif /* lint */ + +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); +} diff --git a/usr.bin/sudo/auth/aix_auth.c b/usr.bin/sudo/auth/aix_auth.c new file mode 100644 index 00000000000..670c0fb6a7c --- /dev/null +++ b/usr.bin/sudo/auth/aix_auth.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: aix_auth.c,v 1.7 1999/10/07 21:21:07 millert Exp $"; +#endif /* lint */ + +int +aixauth_verify(pw, prompt, auth) + struct passwd *pw; + char *prompt; + sudo_auth *auth; +{ + char *message, *pass; + int reenter = 1; + + pass = tgetpass(prompt, def_ival(I_PW_TIMEOUT) * 60, 1); + if (authenticate(pw->pw_name, pass, &reenter, &message) == 0) + return(AUTH_SUCCESS); + else + return(AUTH_FAILURE); +} diff --git a/usr.bin/sudo/auth/dce.c b/usr.bin/sudo/auth/dce.c new file mode 100644 index 00000000000..012467b4836 --- /dev/null +++ b/usr.bin/sudo/auth/dce.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 1996, 1998, 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * This code is derived from software contributed by Jeff Earickson + * of Colby College, Waterville, ME <jaearick@colby.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ +/* + * 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 <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.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" + +#ifndef lint +static const char rcsid[] = "$Sudo: dce.c,v 1.7 1999/08/31 09:39:17 millert Exp $"; +#endif /* lint */ + +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); +} diff --git a/usr.bin/sudo/auth/fwtk.c b/usr.bin/sudo/auth/fwtk.c new file mode 100644 index 00000000000..448faf87f97 --- /dev/null +++ b/usr.bin/sudo/auth/fwtk.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> + +#include <auth.h> +#include <firewall.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: fwtk.c,v 1.9 1999/10/12 00:53:41 millert Exp $"; +#endif /* lint */ + +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) { + (void) fprintf(stderr, "%s: cannot read fwtk config.\n", Argv[0]); + return(AUTH_FATAL); + } + + if (auth_open(confp)) { + (void) fprintf(stderr, "%s: cannot connect to authentication server.\n", + Argv[0]); + return(AUTH_FATAL); + } + + /* Get welcome message from auth server */ + if (auth_recv(resp, sizeof(resp))) { + (void) fprintf(stderr, + "%s: lost connection to authentication server.\n", Argv[0]); + return(AUTH_FATAL); + } + if (strncmp(resp, "Authsrv ready", 13) != 0) { + (void) fprintf(stderr, + "%s: authentication server error.\n%s\n", Argv[0], 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 */ + extern int nil_pw; + + /* Send username to authentication server. */ + (void) snprintf(buf, sizeof(buf), "authorize %s 'sudo'", pw->pw_name); + if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { + (void) fprintf(stderr, + "%s: lost connection to authentication server.\n", Argv[0]); + 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_ival(I_PW_TIMEOUT) * 60, 0); + } else if (strncmp(resp, "password", 8) == 0) { + pass = tgetpass(prompt, def_ival(I_PW_TIMEOUT) * 60, 1); + } else { + (void) fprintf(stderr, "%s: %s\n", Argv[0], resp); + return(AUTH_FATAL); + } + if (!pass || *pass == '\0') + nil_pw = 1; /* empty password */ + + /* 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))) { + (void) fprintf(stderr, + "%s: lost connection to authentication server.\n", Argv[0]); + return(AUTH_FATAL); + } + + if (strncmp(resp, "ok", 2) == 0) + return(AUTH_SUCCESS); + + /* Main loop prints "Permission Denied" or insult. */ + if (strcmp(resp, "Permission Denied.") != 0) + fprintf(stderr, "%s: %s\n", Argv[0], resp); + return(AUTH_FAILURE); +} + +int +fwtk_cleanup(pw, auth) + struct passwd *pw; + sudo_auth *auth; +{ + + auth_close(); + return(AUTH_SUCCESS); +} diff --git a/usr.bin/sudo/auth/kerb4.c b/usr.bin/sudo/auth/kerb4.c new file mode 100644 index 00000000000..2791ec9aef5 --- /dev/null +++ b/usr.bin/sudo/auth/kerb4.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> +#include <krb.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: kerb4.c,v 1.5 1999/08/14 15:36:46 millert Exp $"; +#endif /* lint */ + +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) sprintf(tkfile, "%s/tkt%ld", _PATH_SUDO_TIMEDIR, (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); +} diff --git a/usr.bin/sudo/auth/kerb5.c b/usr.bin/sudo/auth/kerb5.c new file mode 100644 index 00000000000..f9adb3dcaea --- /dev/null +++ b/usr.bin/sudo/auth/kerb5.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * This code is derived from software contributed by Frank Cusack + * <fcusack@fcusack.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> +#include <krb5.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: kerb5.c,v 1.10 1999/10/13 02:34:55 millert Exp $"; +#endif /* lint */ + +static int verify_krb_v5_tgt __P((krb5_context, krb5_ccache, char *)); +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; + +extern krb5_cc_ops krb5_mcc_ops; + +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 */ + + if (error = krb5_init_context(&(sudo_krb5_data.sudo_context))) { + log_error(NO_EXIT|NO_MAIL, + "%s: unable to initialize context: %s", auth->name, + error_message(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 + + /* For CNS compatibility */ + if (error = krb5_cc_register(sudo_context, &krb5_mcc_ops, FALSE)) { + if (error != KRB5_CC_TYPE_EXISTS) { + log_error(NO_EXIT|NO_MAIL, + "%s: unable to use Memory ccache: %s", auth->name, + error_message(error)); + return(AUTH_FAILURE); + } + } + + (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; + + 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)); + return(AUTH_FAILURE); + } + + return(AUTH_SUCCESS); +} + +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_creds creds; + krb5_error_code error; + krb5_get_init_creds_opt opts; + char cache_name[64]; + + sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context; + princ = ((sudo_krb5_datap) auth->data)->princ; + ccache = ((sudo_krb5_datap) auth->data)->ccache; + + /* Initialize options to defaults */ + krb5_get_init_creds_opt_init(&opts); + + /* Note that we always obtain a new TGT to verify the user */ + if (error = krb5_get_init_creds_password(sudo_context, &creds, princ, + pass, krb5_prompter_posix, + NULL, 0, NULL, &opts)) { + if (error == KRB5KRB_AP_ERR_BAD_INTEGRITY) /* Bad password */ + return(AUTH_FAILURE); + /* Some other error */ + log_error(NO_EXIT|NO_MAIL, + "%s: unable to get credentials: %s", auth->name, + error_message(error)); + return(AUTH_FAILURE); + } + + /* Stash the TGT so we can verify it. */ + if (error = krb5_cc_store_cred(sudo_context, ccache, &creds)) { + log_error(NO_EXIT|NO_MAIL, + "%s: unable to store credentials: %s", auth->name, + error_message(error)); + } else { + error = verify_krb_v5_tgt(sudo_context, ccache, auth->name); + } + + krb5_free_cred_contents(sudo_context, &creds); + return (error ? AUTH_FAILURE : AUTH_SUCCESS); +} + +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); +} + +/* + * This routine with some modification is from the MIT V5B6 appl/bsd/login.c + * + * 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). If the host/<host> service is unknown (i.e., + * the local keytab doesn't have it), return success but log the error. + * + * This needs to run as root (to read the host service ticket). + * + * Returns 0 for successful authentication, non-zero for failure. + */ +static int +verify_krb_v5_tgt(sudo_context, ccache, auth_name) + krb5_context sudo_context; + krb5_ccache ccache; + char *auth_name; /* For error reporting */ +{ + char phost[BUFSIZ]; + krb5_error_code error; + krb5_principal princ; + krb5_data packet; + krb5_keyblock *keyblock = 0; + krb5_auth_context auth_context = NULL; + + packet.data = 0; + + /* + * 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, &princ)) { + log_error(NO_EXIT|NO_MAIL, + "%s: unable to get host principal: %s", auth_name, + error_message(error)); + return(-1); + } + + /* Extract the name directly. Yow. */ + strncpy(phost, krb5_princ_component(sudo_context, princ, 1)->data, + sizeof(phost) - 1); + phost[sizeof(phost) - 1] = '\0'; + + /* + * Do we have host/<host> keys? + * (use default keytab, kvno IGNORE_VNO to get the first match, + * and enctype is currently ignored anyhow.) + */ + if (error = krb5_kt_read_service_key(sudo_context, NULL, princ, 0, + ENCTYPE_DES_CBC_MD5, &keyblock)) { + /* Keytab or service key does not exist. */ + log_error(NO_EXIT, + "%s: host service key not found: %s", auth_name, + error_message(error)); + error = 0; + goto cleanup; + } + if (keyblock) + krb5_free_keyblock(sudo_context, keyblock); + + /* Talk to the kdc and construct the ticket. */ + error = krb5_mk_req(sudo_context, &auth_context, 0, "host", phost, + NULL, ccache, &packet); + if (auth_context) { + krb5_auth_con_free(sudo_context, auth_context); + auth_context = NULL; /* setup for rd_req */ + } + + /* Try to use the ticket. */ + if (!error) + error = krb5_rd_req(sudo_context, &auth_context, &packet, princ, + NULL, NULL, NULL); +cleanup: + if (packet.data) + krb5_free_data_contents(sudo_context, &packet); + krb5_free_principal(sudo_context, princ); + + if (error) + log_error(NO_EXIT|NO_MAIL, + "%s: Cannot verify TGT! Possible attack!: %s", auth_name, + error_message(error)); + return(error); +} diff --git a/usr.bin/sudo/auth/pam.c b/usr.bin/sudo/auth/pam.c new file mode 100644 index 00000000000..623dcab742d --- /dev/null +++ b/usr.bin/sudo/auth/pam.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> + +#include <security/pam_appl.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: pam.c,v 1.10 1999/10/07 21:21:07 millert Exp $"; +#endif /* lint */ + +static int sudo_conv __P((int, PAM_CONST struct pam_message **, + struct pam_response **, VOID *)); +static char *def_prompt; + +int +pam_init(pw, promptp, auth) + struct passwd *pw; + char **promptp; + sudo_auth *auth; +{ + static struct pam_conv pam_conv; + pam_handle_t *pamh; + + /* Initial PAM setup */ + pam_conv.conv = sudo_conv; + if (pam_start("sudo", pw->pw_name, &pam_conv, &pamh) != PAM_SUCCESS) { + log_error(USE_ERRNO|NO_EXIT|NO_MAIL, + "unable to initialize PAM"); + return(AUTH_FATAL); + } + auth->data = (VOID *) pamh; + return(AUTH_SUCCESS); +} + +int +pam_verify(pw, prompt, auth) + struct passwd *pw; + char *prompt; + sudo_auth *auth; +{ + pam_handle_t *pamh = (pam_handle_t *) auth->data; + + def_prompt = prompt; /* for sudo_conv */ + + /* PAM_SILENT prevents error messages from going to syslog(3) */ + if (pam_authenticate(pamh, PAM_SILENT) == PAM_SUCCESS) + return(AUTH_SUCCESS); + else + return(AUTH_FAILURE); +} + +int +pam_cleanup(pw, auth) + struct passwd *pw; + sudo_auth *auth; +{ + pam_handle_t *pamh = (pam_handle_t *) auth->data; + + if (pam_end(pamh, (auth->status == AUTH_SUCCESS)) == PAM_SUCCESS) + return(AUTH_SUCCESS); + else + return(AUTH_FAILURE); +} + +/* + * ``Conversation function'' for PAM. + */ +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; + struct pam_message *pm; + char *p = def_prompt; + int echo = 0; + extern int nil_pw; + + if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL) + return(PAM_CONV_ERR); + (void) memset((VOID *)*response, 0, num_msg * sizeof(struct pam_response)); + + for (pr = *response, pm = *msg; num_msg--; pr++, pm++) { + switch (pm->msg_style) { + case PAM_PROMPT_ECHO_ON: + echo = 1; + case PAM_PROMPT_ECHO_OFF: + /* Override default prompt for unix auth */ + if (strcmp(p, "Password: ") && strcmp(p, "Password:")) + p = (char *) pm->msg; + pr->resp = estrdup((char *) tgetpass(p, + def_ival(I_PW_TIMEOUT) * 60, !echo)); + if (*pr->resp == '\0') + nil_pw = 1; /* empty password */ + 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: + /* Something odd happened */ + /* XXX - should free non-NULL response members */ + free(*response); + *response = NULL; + return(PAM_CONV_ERR); + break; + } + } + + return(PAM_SUCCESS); +} diff --git a/usr.bin/sudo/auth/passwd.c b/usr.bin/sudo/auth/passwd.c new file mode 100644 index 00000000000..62f3a126584 --- /dev/null +++ b/usr.bin/sudo/auth/passwd.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: passwd.c,v 1.4 1999/08/14 15:36:46 millert Exp $"; +#endif /* lint */ + +int +passwd_verify(pw, pass, auth) + struct passwd *pw; + char *pass; + sudo_auth *auth; +{ + +#ifdef HAVE_GETAUTHUID + /* Ultrix shadow passwords may use crypt16() */ + if (!strcmp(pw->pw_passwd, (char *) crypt16(pass, pw->pw_passwd))) + return(AUTH_SUCCESS); +#endif /* HAVE_GETAUTHUID */ + + /* Normal UN*X password check */ + if (!strcmp(pw->pw_passwd, (char *) crypt(pass, pw->pw_passwd))) + return(AUTH_SUCCESS); + + return(AUTH_FAILURE); +} diff --git a/usr.bin/sudo/auth/rfc1938.c b/usr.bin/sudo/auth/rfc1938.c new file mode 100644 index 00000000000..bad20d24dca --- /dev/null +++ b/usr.bin/sudo/auth/rfc1938.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1994-1996,1998-1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> + +#if defined(HAVE_SKEY) +#include <skey.h> +#define RFC1938 skey +#define rfc1938challenge skeychallenge +#define rfc1938verify skeyverify +#elif defined(HAVE_OPIE) +#include <opie.h> +#define RFC1938 opie +#define rfc1938challenge opiechallenge +#define rfc1938verify opieverify +#endif + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: rfc1938.c,v 1.8 1999/10/07 21:21:07 millert Exp $"; +#endif /* lint */ + +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) != 0) { + if (IS_ONEANDONLY(auth)) { + (void) fprintf(stderr, + "%s: You do not exist in the %s database.\n", + Argv[0], 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_flag(I_LONG_OTP_PROMPT)) + (void) sprintf(new_prompt, "%s\n%s", challenge, orig_prompt); + else + (void) sprintf(new_prompt, "%.*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); +} diff --git a/usr.bin/sudo/auth/secureware.c b/usr.bin/sudo/auth/secureware.c new file mode 100644 index 00000000000..ddba29fbc9b --- /dev/null +++ b/usr.bin/sudo/auth/secureware.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1998, 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.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" + +#ifndef lint +static const char rcsid[] = "$Sudo: secureware.c,v 1.7 1999/08/22 09:59:28 millert Exp $"; +#endif /* lint */ + +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); +} diff --git a/usr.bin/sudo/auth/securid.c b/usr.bin/sudo/auth/securid.c new file mode 100644 index 00000000000..dff22632cca --- /dev/null +++ b/usr.bin/sudo/auth/securid.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * This code is derived from software contributed by Giles Todd + * <giles@gt.demon.co.uk>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> + +#include <sdi_athd.h> +#include <sdconf.h> +#include <sdacmvls.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: securid.c,v 1.5 1999/08/14 15:36:46 millert Exp $"; +#endif /* lint */ + +union config_record configure; + +int +securid_init(pw, promptp, auth) + struct passwd *pw; + char **promptp; + sudo_auth *auth; +{ + + creadcfg(); /* Only read config file once */ + return(AUTH_SUCCESS); +} + +int +securid_setup(pw, promptp, auth) + struct passwd *pw; + char **promptp; + sudo_auth *auth; +{ + static SD_CLIENT sd_dat; /* SecurID data block */ + + /* Re-initialize SecurID every time. */ + auth->data = (VOID *) &sd_dat; + if (sd_init(sd) == 0) + return(AUTH_SUCCESS); + else { + (void) fprintf(stderr, "%s: Cannot contact SecurID server\n", Argv[0]); + 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; + + if (sd_auth(sd) == ACM_OK) + return(AUTH_SUCCESS); + else + return(AUTH_FAILURE); +} diff --git a/usr.bin/sudo/auth/sia.c b/usr.bin/sudo/auth/sia.c new file mode 100644 index 00000000000..d41263c9603 --- /dev/null +++ b/usr.bin/sudo/auth/sia.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * This code is derived from software contributed by Spider Boardman + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> +#include <siad.h> + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: sia.c,v 1.8 1999/10/07 21:21:07 millert Exp $"; +#endif /* lint */ + +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_ival(I_PW_TIMEOUT) * 60) + timeout = def_ival(I_PW_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; + + 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); +} diff --git a/usr.bin/sudo/auth/sudo_auth.c b/usr.bin/sudo/auth/sudo_auth.c new file mode 100644 index 00000000000..74a20ce509b --- /dev/null +++ b/usr.bin/sudo/auth/sudo_auth.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <sys/param.h> +#include <sys/types.h> +#include <pwd.h> +#include <time.h> + +#include "sudo.h" +#include "sudo_auth.h" +#include "insults.h" + +#ifndef lint +static const char rcsid[] = "$Sudo: sudo_auth.c,v 1.15 1999/10/13 02:34:55 millert Exp $"; +#endif /* lint */ + +sudo_auth auth_switch[] = { +#ifdef AUTH_STANDALONE + AUTH_STANDALONE +#else +# ifndef WITHOUT_PASSWD + AUTH_ENTRY(0, "passwd", NULL, NULL, passwd_verify, NULL) +# endif +# if defined(HAVE_SECUREWARE) && !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) +}; + +int nil_pw; /* I hate resorting to globals like this... */ + +void +verify_user(prompt) + char *prompt; +{ + short counter = def_ival(I_PW_TRIES) + 1; + short success = AUTH_FAILURE; + short status; + char *p; + sudo_auth *auth; + + /* Make sure we have at least one auth method. */ + if (auth_switch[0].name == NULL) + 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) + 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, 0); + + status = (auth->init)(sudo_user.pw, &prompt, auth); + if (status == AUTH_FAILURE) + auth->flags &= ~FLAG_CONFIGURED; + else if (status == AUTH_FATAL) /* XXX log */ + exit(1); /* assume error msg already printed */ + + if (NEEDS_USER(auth)) + set_perms(PERM_ROOT, 0); + } + } + + 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, 0); + + status = (auth->setup)(sudo_user.pw, &prompt, auth); + if (status == AUTH_FAILURE) + auth->flags &= ~FLAG_CONFIGURED; + else if (status == AUTH_FATAL) /* XXX log */ + exit(1); /* assume error msg already printed */ + + if (NEEDS_USER(auth)) + set_perms(PERM_ROOT, 0); + } + } + + /* Get the password unless the auth function will do it for us */ + nil_pw = 0; +#ifdef AUTH_STANDALONE + p = prompt; +#else + p = (char *) tgetpass(prompt, def_ival(I_PW_TIMEOUT) * 60, 1); + if (!p || *p == '\0') + nil_pw = 1; +#endif /* AUTH_STANDALONE */ + + /* Call authentication functions. */ + for (auth = auth_switch; auth->name; auth++) { + if (!IS_CONFIGURED(auth)) + continue; + + if (NEEDS_USER(auth)) + set_perms(PERM_USER, 0); + + success = auth->status = (auth->verify)(sudo_user.pw, p, auth); + + if (NEEDS_USER(auth)) + set_perms(PERM_ROOT, 0); + + if (auth->status != AUTH_FAILURE) + goto cleanup; + } +#ifndef AUTH_STANDALONE + (void) memset(p, 0, strlen(p)); +#endif + + /* Exit loop on nil password, but give it a chance to match first. */ + if (nil_pw) { + if (counter == def_ival(I_PW_TRIES)) + exit(1); + else + break; + } + + 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, 0); + + status = (auth->cleanup)(sudo_user.pw, auth); + if (status == AUTH_FATAL) /* XXX log */ + exit(1); /* assume error msg already printed */ + + if (NEEDS_USER(auth)) + set_perms(PERM_ROOT, 0); + } + } + + switch (success) { + case AUTH_SUCCESS: + return; + case AUTH_FAILURE: + log_error(NO_MAIL, "%d incorrect password attempt%s", + def_ival(I_PW_TRIES) - counter, + (def_ival(I_PW_TRIES) - counter == 1) ? "" : "s"); + case AUTH_FATAL: + exit(1); + } +} + +void +pass_warn(fp) + FILE *fp; +{ + +#ifdef USE_INSULTS + (void) fprintf(fp, "%s\n", INSULT); +#else + (void) fprintf(fp, "%s\n", def_str(I_BADPASS_MSG)); +#endif /* USE_INSULTS */ +} + +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'); +} diff --git a/usr.bin/sudo/auth/sudo_auth.h b/usr.bin/sudo/auth/sudo_auth.h new file mode 100644 index 00000000000..0b9486d8254 --- /dev/null +++ b/usr.bin/sudo/auth/sudo_auth.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1999 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 4. Products derived from this software may not be called "Sudo" nor + * may "Sudo" appear in their names without specific prior written + * permission from the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * 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. + * + * $Sudo: sudo_auth.h,v 1.15 1999/10/13 02:34:55 millert Exp $ + */ + +#ifndef SUDO_AUTH_H +#define SUDO_AUTH_H + +/* Auth function return values. */ +#define AUTH_SUCCESS 0 +#define AUTH_FAILURE 1 +#define AUTH_FATAL 2 + +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 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)); + +/* Prototypes for normal methods */ +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) +# define AUTH_STANDALONE \ + AUTH_ENTRY(0, "sia", \ + NULL, sia_setup, sia_verify, sia_cleanup) +#elif defined(HAVE_AUTHENTICATE) +# define AUTH_STANDALONE \ + AUTH_ENTRY(0, "aixauth", \ + NULL, NULL, aixauth_verify, NULL) +#elif defined(HAVE_FWTK) +# define AUTH_STANDALONE \ + AUTH_ENTRY(0, "fwtk", fwtk_init, \ + NULL, fwtk_verify, fwtk_cleanup) +#endif + +#endif /* SUDO_AUTH_H */ |