From 169d85ac9e0b1b518b53564166b431bb34753f40 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sun, 11 Jul 1999 00:32:11 +0000 Subject: [PATCH] New authentication API and methods --- auth/afs.c | 85 ++++++++++++++++++ auth/fwtk.c | 144 ++++++++++++++++++++++++++++++ auth/kerb4.c | 109 +++++++++++++++++++++++ auth/kerb5.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++ auth/opie.c | 114 ++++++++++++++++++++++++ auth/pam.c | 167 +++++++++++++++++++++++++++++++++++ auth/passwd.c | 66 ++++++++++++++ auth/secureware.c | 96 ++++++++++++++++++++ auth/securid.c | 87 ++++++++++++++++++ auth/skey.c | 118 +++++++++++++++++++++++++ auth/sudo_auth.c | 180 +++++++++++++++++++++++++++++++++++++ auth/sudo_auth.h | 64 ++++++++++++++ 12 files changed, 1451 insertions(+) create mode 100644 auth/afs.c create mode 100644 auth/fwtk.c create mode 100644 auth/kerb4.c create mode 100644 auth/kerb5.c create mode 100644 auth/opie.c create mode 100644 auth/pam.c create mode 100644 auth/passwd.c create mode 100644 auth/secureware.c create mode 100644 auth/securid.c create mode 100644 auth/skey.c create mode 100644 auth/sudo_auth.c create mode 100644 auth/sudo_auth.h diff --git a/auth/afs.c b/auth/afs.c new file mode 100644 index 000000000..08f31b7ca --- /dev/null +++ b/auth/afs.c @@ -0,0 +1,85 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include + +#include +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +int +afs_verify(pw, pass, data) + struct passwd *pw; + char *pass; + void **data; +{ + 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(user_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, + user_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/auth/fwtk.c b/auth/fwtk.c new file mode 100644 index 000000000..d38b34950 --- /dev/null +++ b/auth/fwtk.c @@ -0,0 +1,144 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include + +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +int +fwtk_setup(pw, promptp, data) + struct passwd *pw; + char **promptp; + void **data; +{ + static Cfg *confp; /* Configuration entry struct */ + char resp[128]; /* Response from the server */ + + if (confp) + return(AUTH_SUCCESS); /* Already initialized */ + + if ((confp = cfg_read("sudo")) == (Cfg *)-1) { + fprintf(stderr, "%s: cannot read fwtk config.\n", Argv[0]); + return(AUTH_FATAL); + } + + if (auth_open(confp)) { + 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))) { + fprintf(stderr, "%s: lost connection to authentication server.\n", + Argv[0]); + return(AUTH_FATAL); + } + if (strncmp(resp, "Authsrv ready", 13) != 0) { + fprintf(stderr, "%s: authentication server error.\n%s\n", Argv[0], resp); + return(AUTH_FATAL); + } + + return(AUTH_SUCCESS); +} + +int +fwtk_verify(pw, prompt, data) + struct passwd *pw; + char *prompt; + void **data; +{ + 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) sprintf(buf,"authorize %s 'sudo'", pw->pw_name); + if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { + 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) { + sprintf(buf, "%s\nResponse: ", &resp[10]); + pass = tgetpass(buf, PASSWORD_TIMEOUT * 60, 0); + } else if (strncmp(resp, "password", 8) == 0) { + pass = tgetpass(prompt, PASSWORD_TIMEOUT * 60, 1); + } else { + 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 */ + sprintf(buf, "response '%s'", pass); + if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { + 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, status, data) + struct passwd *pw; + int status; + void **data; +{ + + auth_close(); +} diff --git a/auth/kerb4.c b/auth/kerb4.c new file mode 100644 index 000000000..025c7f15d --- /dev/null +++ b/auth/kerb4.c @@ -0,0 +1,109 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +int +kerb4_setup(pw, promptp, data) + struct passwd *pw; + char **promptp; + void **data; +{ + static char realm[REALM_SZ]; + + if (*data) + return(AUTH_SUCCESS); /* Already initialized */ + + /* 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) */ + *data = realm; + + return(AUTH_SUCCESS); +} + +int +kerb4_verify(pw, pass, data) + struct passwd *pw; + char *pass; + void **data; +{ + char tkfile[sizeof(_PATH_SUDO_TIMEDIR) + 4 + MAX_UID_T_LEN]; + char *realm = *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/auth/kerb5.c b/auth/kerb5.c new file mode 100644 index 000000000..46c67149a --- /dev/null +++ b/auth/kerb5.c @@ -0,0 +1,221 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +char *realm = 0 +static int xrealm = 0 +static krb5_context sudo_context = 0 + +static int verify_krb_v5_tgt __P((krb5_ccache)); + +/* XXX - not done yet, need changes to sudo.c */ +int +kerb5_setup(pw, promptp, data) + struct passwd *pw; + char **promptp; + void **data; +{ + krb5_error_code retval; + static char *lrealm; + + if (lrealm) + return(AUTH_SUCCESS); /* Already initialized */ + + /* XXX - make these errors non-fatal? */ + if (retval = krb5_init_context(&sudo_context)) { + set_perms(PERM_USER, 0); + log_error(GLOBAL_KRB5_INIT_ERR); + inform_user(GLOBAL_KRB5_INIT_ERR); + return(AUTH_FATAL); + } + + krb5_init_ets(sudo_context); + + if (retval = krb5_get_default_realm(sudo_context, &lrealm)) { + set_perms(PERM_USER, 0); + log_error(GLOBAL_KRB5_INIT_ERR); + inform_user(GLOBAL_KRB5_INIT_ERR); + return(AUTH_FATAL); + } + + if (realm) { + if (strcmp(realm, lrealm) != 0) + xrealm = 1; /* User supplied realm is not the system default */ + free(lrealm); + } else + realm = lrealm; + + /* XXX - different default prompt for kerb5 */ +} + +int +kerb5_verify(pw, pass, data) + struct passwd *pw; + char *pass; + void **data; +{ + krb5_error_code retval; + krb5_principal princ; + krb5_creds creds; + krb5_ccache ccache; + char cache_name[64]; + char *princ_name; + krb5_get_init_creds_opt opts; + + /* Initialize */ + if (!sudo_context) + return -1; + krb5_get_init_creds_opt_init(&opts); + + princ_name = emalloc(strlen(pw->pw_name) + strlen(realm) + 2); + (void) sprintf(princ_name, "%s@%s", pw->pw_name, realm); + if (krb5_parse_name(sudo_context, princ_name, &princ)) + return(AUTH_FAILURE); + + /* Set the ticket file to be in /tmp so we don't need to change perms. */ + (void) sprintf(cache_name, "FILE:/tmp/sudocc_%ld", getpid()); + if (krb5_cc_resolve(sudo_context, cache_name, &ccache) + return(AUTH_FAILURE); + + if (krb5_get_init_creds_password(sudo_context, &creds, princ, pass, + krb5_prompter_posix, NULL, 0, NULL, &opts)) + return(AUTH_FAILURE); + + /* Stash the TGT so we can verify it. */ + if (krb5_cc_initialize(sudo_context, ccache, princ)) + return(AUTH_FAILURE); + if (krb5_cc_store_cred(sudo_context, ccache, &creds)) { + (void) krb5_cc_destroy(sudo_context, ccache); + return(AUTH_FAILURE); + } + + retval = verify_krb_v5_tgt(ccache); + (void) krb5_cc_destroy(sudo_context, ccache); + return (retval ? AUTH_FAILURE : 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/ service is unknown (i.e., + * the local keytab doesn't have it), let her in. + * + * Returns 1 for confirmation, -1 for failure, 0 for uncertainty. + */ +static int +verify_krb_v5_tgt(ccache) + krb5_ccache ccache; +{ + char phost[BUFSIZ]; + krb5_error_code retval; + krb5_principal princ; + krb5_keyblock * keyblock = 0; + krb5_data packet; + 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 (krb5_sname_to_principal(sudo_context, NULL, NULL, + KRB5_NT_SRV_HST, &princ)) + return -1; + + /* Extract the name directly. */ + strncpy(phost, krb5_princ_component(c, princ, 1)->data, BUFSIZ); + phost[BUFSIZ - 1] = '\0'; + + /* + * Do we have host/ keys? + * (use default keytab, kvno IGNORE_VNO to get the first match, + * and enctype is currently ignored anyhow.) + */ + if (retval = krb5_kt_read_service_key(sudo_context, NULL, princ, 0, + ENCTYPE_DES_CBC_MD5, &keyblock)) { + /* Keytab or service key does not exist */ + if (xrealm) + retval = -1; + else + retval = 0; + goto cleanup; + } + if (keyblock) + krb5_free_keyblock(sudo_context, keyblock); + + /* Talk to the kdc and construct the ticket. */ + retval = 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 */ + } + if (retval) { + retval = -1; + goto cleanup; + } + + /* Try to use the ticket. */ + retval = krb5_rd_req(sudo_context, &auth_context, &packet, princ, + NULL, NULL, NULL); + if (retval) { + retval = -1; + } else { + retval = 1; + } + +cleanup: + if (packet.data) + krb5_free_data_contents(sudo_context, &packet); + krb5_free_principal(sudo_context, princ); + return retval; + +} diff --git a/auth/opie.c b/auth/opie.c new file mode 100644 index 000000000..74f28690c --- /dev/null +++ b/auth/opie.c @@ -0,0 +1,114 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#include + +#include "sudo.h" +#include "sudo_auth.h" + +int +opie_setup(pw, promptp, data) + struct passwd *pw; + char **promptp; + void **data; +{ + char challenge[OPIE_CHALLENGE_MAX]; + static char *orig_prompt = NULL, *new_prompt = NULL; + static int op_len, np_size; + static struct opie opie; + + /* Stash a pointer to the opie struct if we have not initialized */ + if (!*data) + *data = &opie; + + /* 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--; + } + + /* Get the opie part of the prompt */ + if (opiechallenge(&opie, user_name, challenge) != 0) { +#ifdef OTP_ONLY + (void) fprintf(stderr, + "%s: You do not exist in the s/key database.\n", + Argv[0]); + return(AUTH_FATAL); +#else + return(AUTH_FAILURE); +#endif /* OTP_ONLY */ + } + + /* Get space for new prompt with embedded S/Key challenge */ + if (np_size < op_len + strlen(challenge) + 7) { + np_size = op_len + strlen(challenge) + 7; + new_prompt = (char *) erealloc(new_prompt, np_size); + } + +#ifdef 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); +#endif /* LONG_OTP_PROMPT */ + + *promptp = new_prompt; + return(AUTH_SUCCESS); +} + +int +opie_verify(pw, pass, data) + struct passwd *pw; + char *pass; + void **data; +{ + struct opie *opiep = (struct opie *) (*data); + + if (opieverify(opiep, pass) == 0) + return(AUTH_SUCCESS); + else + return(AUTH_FAILURE); +} diff --git a/auth/pam.c b/auth/pam.c new file mode 100644 index 000000000..8f3290dde --- /dev/null +++ b/auth/pam.c @@ -0,0 +1,167 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include + +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +static int sudo_conv __P((int, PAM_CONST struct pam_message **, + struct pam_response **, void *)); +static char *def_prompt; + +int +pam_setup(pw, promptp, data) + struct passwd *pw; + char **promptp; + void **data; +{ + static struct pam_conv pam_conv; + pam_handle_t *pamh; + + if (*data) + return(AUTH_SUCCESS); /* Already initialized */ + + /* Stash prompt */ + def_prompt = *promptp; + + /* Initial PAM setup */ + pam_conv.conv = sudo_conv; + PAM_nullpw = 0; + if (pam_start("sudo", user_name, &pam_conv, &pamh) != PAM_SUCCESS) { + set_perms(PERM_USER, 0); + log_error(BAD_AUTH_INIT); + inform_user(BAD_AUTH_INIT); + return(AUTH_FATAL); + } + *data = pamh; + return(AUTH_SUCCESS); +} + +int +pam_verify(pw, pass, data) + struct passwd *pw; + char *pass; + void **data; +{ + pam_handle_t *pamh = (pam_handle_t *)(*data); + + /* 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, status, data) + struct passwd *pw; + int status; + void **data; +{ + pam_handle_t *pamh = (pam_handle_t *)(*data); + + if (pam_end(pamh, (status == AUTH_SUCCESS)) == PAM_SUCCESS) + return(AUTH_SUCCESS); + else + return(AUTH_FAILURE); +} + +/* + * sudo_conv() + * + * ``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 = 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, + PASSWORD_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/auth/passwd.c b/auth/passwd.c new file mode 100644 index 000000000..8d78ba3c5 --- /dev/null +++ b/auth/passwd.c @@ -0,0 +1,66 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +int +passwd_verify(pw, pass, data) + struct passwd *pw; + char *pass; + void **data; +{ + +#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/auth/secureware.c b/auth/secureware.c new file mode 100644 index 000000000..4a2889171 --- /dev/null +++ b/auth/secureware.c @@ -0,0 +1,96 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#ifdef __hpux +# include +#else +# include +#endif /* __hpux */ +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +int +secureware_setup(pw, promptp, data) + struct passwd *pw; + char **promptp; + void **data; +{ +#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, data) + struct passwd *pw; + char *pass; + void **data; +{ +#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/auth/securid.c b/auth/securid.c new file mode 100644 index 000000000..e93c32414 --- /dev/null +++ b/auth/securid.c @@ -0,0 +1,87 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include + +#include +#include +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +union config_record configure; + +int +securid_setup(pw, promptp, data) + struct passwd *pw; + char **promptp; + void **data; +{ + static SD_CLIENT sd_dat; /* SecurID data block */ + + if (!*data) + creadcfg(); /* Only read config file once */ + + /* Initialize SecurID every time. */ + *data = &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, data) + struct passwd *pw; + char *pass; + void **data; +{ + struct SD_CLIENT *sd = (struct SD_CLIENT *)(*data); + + if (sd_auth(sd) == ACM_OK) + return(AUTH_SUCCESS); + else + return(AUTH_FAILURE); +} diff --git a/auth/skey.c b/auth/skey.c new file mode 100644 index 000000000..c930a24bc --- /dev/null +++ b/auth/skey.c @@ -0,0 +1,118 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#include + +#include "sudo.h" +#include "sudo_auth.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +int +skey_setup(pw, promptp, data) + struct passwd *pw; + char **promptp; + void **data; +{ + char challenge[256]; + static char *orig_prompt = NULL, *new_prompt = NULL; + static int op_len, np_size; + static struct skey skey; + + /* Stash a pointer to the skey struct if we have not initialized */ + if (!*data) + *data = &skey; + + /* 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--; + } + + /* Close old stream */ + if (skey.keyfile) + (void) fclose(skey.keyfile); + + /* Get the skey part of the prompt */ + if (skeychallenge(&skey, user_name, challenge) != 0) { +#ifdef OTP_ONLY + (void) fprintf(stderr, + "%s: You do not exist in the s/key database.\n", + Argv[0]); + return(AUTH_FATAL); +#else + return(AUTH_FAILURE); +#endif /* OTP_ONLY */ + } + + /* Get space for new prompt with embedded S/Key challenge */ + if (np_size < op_len + strlen(challenge) + 7) { + np_size = op_len + strlen(challenge) + 7; + new_prompt = (char *) erealloc(new_prompt, np_size); + } + +#ifdef 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); +#endif /* LONG_OTP_PROMPT */ + + *promptp = new_prompt; + return(AUTH_SUCCESS); +} + +int +skey_verify(pw, pass, data) + struct passwd *pw; + char *pass; + void **data; +{ + struct skey *skeyp = (struct skey *) (*data); + + if (skeyverify(skeyp, pass) == 0) + return(AUTH_SUCCESS); + else + return(AUTH_FAILURE); +} diff --git a/auth/sudo_auth.c b/auth/sudo_auth.c new file mode 100644 index 000000000..c5780d2cf --- /dev/null +++ b/auth/sudo_auth.c @@ -0,0 +1,180 @@ +/* + * CU sudo version 1.6 + * Copyright (c) 1999 Todd C. Miller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please send bugs, changes, problems to sudo-bugs@courtesan.com + */ + +#include "config.h" + +#include +#ifdef STDC_HEADERS +#include +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include + +#include "sudo.h" +#include "sudo_auth.h" +#include "insults.h" + +#ifndef lint +static const char rcsid[] = "$Sudo$"; +#endif /* lint */ + +sudo_auth auth_switch[] = { +#ifdef AUTH_STANDALONE + AUTH_STANDALONE +#else + AUTH_ENTRY(0, "passwd", NULL, passwd_verify, NULL) +# ifdef HAVE_SECUREWARE + AUTH_ENTRY(0, "secureware", secureware_setup, secureware_verify, NULL) +# endif +# ifdef HAVE_SKEY + AUTH_ENTRY(1, "skey", skey_setup, skey_verify, NULL) +# endif +# ifdef HAVE_OPIE + AUTH_ENTRY(1, "opie", opie_setup, opie_verify, NULL) +# endif +# ifdef HAVE_AFS + AUTH_ENTRY(1, "afs", NULL, afs_verify, NULL) +# endif +# ifdef HAVE_KERB4 + AUTH_ENTRY(1, "kerb4", kerb4_setup, kerb4_verify, NULL) +# endif +# ifdef HAVE_KERB5 + AUTH_ENTRY(1, "kerb5", kerb5_setup, kerb5_verify, NULL) +# endif +#endif /* AUTH_STANDALONE */ + AUTH_ENTRY(0, NULL, NULL, NULL, NULL) +}; + +int nil_pw; /* bad global, bad (oh well) */ + +void +/* verify_user() */ +check_passwd() +{ + int counter = TRIES_FOR_PASSWORD + 1; + int status, success = AUTH_FAILURE; + char *p; + sudo_auth *auth; + + while (--counter) { + /* Do any per-method setup and unconfigure the method if needed */ + for (auth = auth_switch; auth->name; auth++) { + if (auth->setup && auth->configured) { + if (auth->need_root) + set_perms(PERM_ROOT, 0); + + status = (auth->setup)(user_pw_ent, &prompt, &auth->data); + if (status == AUTH_FAILURE) + auth->configured = 0; + else if (status == AUTH_FATAL) /* XXX log */ + exit(1); /* assume error msg already printed */ + + if (auth->need_root) + set_perms(PERM_USER, 0); + } + } + + /* Get the password unless the auth function will do it for us */ + nil_pw = 0; +#if defined(AUTH_STANDALONE) && !defined(AUTH_STANDALONE_GETPASS) + p = prompt; +#else + p = (char *) tgetpass(prompt, PASSWORD_TIMEOUT * 60, 1); + if (!p || *p == '\0') + nil_pw = 1; +#endif /* AUTH_STANDALONE */ + + /* Call authentication functions. */ + for (auth = auth_switch; auth->name; auth++) { + if (!auth->configured) + continue; + + if (auth->need_root) + set_perms(PERM_ROOT, 0); + + success = auth->status = (auth->verify)(user_pw_ent, p, &auth->data); + + if (auth->need_root) + set_perms(PERM_USER, 0); + + if (auth->status != AUTH_FAILURE) + goto cleanup; + } + + /* Exit loop on nil password, but give it a chance to match first. */ + if (nil_pw) { + if (counter == TRIES_FOR_PASSWORD) + exit(1); + else + break; + } + + pass_warn(stderr); + } + +cleanup: + /* Call cleanup routines. */ + for (auth = auth_switch; auth->name; auth++) { + if (auth->cleanup && auth->configured) { + if (auth->need_root) + set_perms(PERM_ROOT, 0); + + status = (auth->cleanup)(user_pw_ent, auth->status, &auth->data); + if (status == AUTH_FATAL) /* XXX log */ + exit(1); /* assume error msg already printed */ + + if (auth->need_root) + set_perms(PERM_USER, 0); + } + } + + switch (success) { + case AUTH_SUCCESS: + return; + case AUTH_FAILURE: + log_error(counter ? PASSWORD_NOT_CORRECT : PASSWORDS_NOT_CORRECT); + inform_user(counter ? PASSWORD_NOT_CORRECT : PASSWORDS_NOT_CORRECT); + 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", INCORRECT_PASSWORD); +#endif /* USE_INSULTS */ +} diff --git a/auth/sudo_auth.h b/auth/sudo_auth.h new file mode 100644 index 000000000..1974c8aee --- /dev/null +++ b/auth/sudo_auth.h @@ -0,0 +1,64 @@ +#ifndef SUDO_AUTH_H +#define SUDO_AUTH_H + +#define AUTH_SUCCESS 0 +#define AUTH_FAILURE 1 +#define AUTH_FATAL 2 + +typedef struct sudo_auth { + int need_root; /* must run as root? */ + int configured; /* auth type configured on this host? */ + int status; /* status from verify routine */ + char *name; + void *data; /* method-specific data pointer */ + int (*setup) __P((struct passwd *pw, char **prompt, void **data)); + int (*verify) __P((struct passwd *pw, char *p, void **data)); + int (*cleanup) __P((struct passwd *pw, int status, void **data)); +} sudo_auth; + +/* Prototypes for standalone methods */ +int fwtk_setup __P((struct passwd *pw, char **prompt, void **data)); +int fwtk_verify __P((struct passwd *pw, char *prompt, void **data)); +int fwtk_cleanup __P((struct passwd *pw, int status, void **data)); +int pam_setup __P((struct passwd *pw, char **prompt, void **data)); +int pam_verify __P((struct passwd *pw, char *prompt, void **data)); +int pam_cleanup __P((struct passwd *pw, int status, void **data)); + +/* Prototypes for normal methods */ +int passwd_verify __P((struct passwd *pw, char *pass, void **data)); +int secureware_setup __P((struct passwd *pw, char **prompt, void **data)); +int secureware_verify __P((struct passwd *pw, char *pass, void **data)); +int skey_setup __P((struct passwd *pw, char **prompt, void **data)); +int skey_verify __P((struct passwd *pw, char *pass, void **data)); +int opie_setup __P((struct passwd *pw, char **prompt, void **data)); +int opie_verify __P((struct passwd *pw, char *pass, void **data)); +int afs_verify __P((struct passwd *pw, char *pass, void **data)); +int kerb4_setup __P((struct passwd *pw, char **prompt, void **data)); +int kerb4_verify __P((struct passwd *pw, char *pass, void **data)); +int kerb5_setup __P((struct passwd *pw, char **prompt, void **data)); +int kerb5_verify __P((struct passwd *pw, char *pass, void **data)); + +/* Fields: need_root, name, setup, verify, cleanup */ +#define AUTH_ENTRY(r, n, s, v, c) { r, 1, AUTH_FAILURE, n, NULL, s, v, c }, + +/* Some methods cannots (or should not) interoperate with any others */ +#if defined(HAVE_PAM) +# define AUTH_STANDALONE \ + AUTH_ENTRY(1, "pam", pam_setup, passwd_verify, pam_cleanup) +#elif defined(HAVE_SECURID) +# define AUTH_STANDALONE \ + AUTH_ENTRY(1, "SecurId", securid_setup, securid_verify, NULL) +#elif defined(HAVE_FWTK) +# define AUTH_STANDALONE \ + AUTH_ENTRY(1, "fwtk", fwtk_setup, fwtk_verify, fwtk_cleanup) +#elif defined(HAVE_SKEY) && defined(OTP_ONLY) +# define AUTH_STANDALONE \ + AUTH_ENTRY(1, "skey", skey_setup, skey_verify, NULL) +# define AUTH_STANDALONE_GETPASS +#elif defined(HAVE_OPIE) && defined(OTP_ONLY) +# define AUTH_STANDALONE \ + AUTH_ENTRY(1, "opie", opie_setup, opie_verify, NULL) +# define AUTH_STANDALONE_GETPASS +#endif + +#endif /* SUDO_AUTH_H */ -- 2.40.0