diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 4aed2c8219774f5d797760606b8489a92ddc5163 (patch) | |
tree | 3f8c130f7d269626bf6a9447407ef6c35954426a /kcheckpass/checkpass_pam.c | |
download | tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kcheckpass/checkpass_pam.c')
-rw-r--r-- | kcheckpass/checkpass_pam.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/kcheckpass/checkpass_pam.c b/kcheckpass/checkpass_pam.c new file mode 100644 index 000000000..6f281165f --- /dev/null +++ b/kcheckpass/checkpass_pam.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 1998 Caldera, Inc. + * Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org> + * + * 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 2 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kcheckpass.h" + +#ifdef HAVE_PAM + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> + +#ifdef HAVE_PAM_PAM_APPL_H +#include <pam/pam_appl.h> +#else +#include <security/pam_appl.h> +#endif + +struct pam_data { + char *(*conv) (ConvRequest, const char *); + int abort:1; + int classic:1; +}; + +#ifdef PAM_MESSAGE_NONCONST +typedef struct pam_message pam_message_type; +typedef void *pam_gi_type; +#else +typedef const struct pam_message pam_message_type; +typedef const void *pam_gi_type; +#endif + +static int +PAM_conv (int num_msg, pam_message_type **msg, + struct pam_response **resp, + void *appdata_ptr) +{ + int count; + struct pam_response *repl; + struct pam_data *pd = (struct pam_data *)appdata_ptr; + + if (!(repl = calloc(num_msg, sizeof(struct pam_response)))) + return PAM_CONV_ERR; + + for (count = 0; count < num_msg; count++) + switch (msg[count]->msg_style) { + case PAM_TEXT_INFO: + pd->conv(ConvPutInfo, msg[count]->msg); + break; + case PAM_ERROR_MSG: + pd->conv(ConvPutError, msg[count]->msg); + break; + default: + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: + repl[count].resp = pd->conv(ConvGetNormal, msg[count]->msg); + break; + case PAM_PROMPT_ECHO_OFF: + repl[count].resp = + pd->conv(ConvGetHidden, pd->classic ? 0 : msg[count]->msg); + break; +#ifdef PAM_BINARY_PROMPT + case PAM_BINARY_PROMPT: + repl[count].resp = pd->conv(ConvGetBinary, msg[count]->msg); + break; +#endif + default: + /* Must be an error of some sort... */ + goto conv_err; + } + if (!repl[count].resp) { + pd->abort = 1; + goto conv_err; + } + repl[count].resp_retcode = PAM_SUCCESS; + break; + } + *resp = repl; + return PAM_SUCCESS; + + conv_err: + for (; count >= 0; count--) + if (repl[count].resp) + switch (msg[count]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + dispose(repl[count].resp); + break; +#ifdef PAM_BINARY_PROMPT + case PAM_BINARY_PROMPT: /* handle differently? */ +#endif + case PAM_PROMPT_ECHO_ON: + free(repl[count].resp); + break; + } + free(repl); + return PAM_CONV_ERR; +} + +static struct pam_data PAM_data; + +static struct pam_conv PAM_conversation = { + &PAM_conv, + &PAM_data +}; + +#ifdef PAM_FAIL_DELAY +static void +fail_delay(int retval ATTR_UNUSED, unsigned usec_delay ATTR_UNUSED, + void *appdata_ptr ATTR_UNUSED) +{} +#endif + + +AuthReturn Authenticate(const char *caller, const char *method, + const char *user, char *(*conv) (ConvRequest, const char *)) +{ + const char *tty; + pam_handle_t *pamh; + pam_gi_type pam_item; + const char *pam_service; + char pservb[64]; + int pam_error; + + openlog("kcheckpass", LOG_PID, LOG_AUTH); + + PAM_data.conv = conv; + if (strcmp(method, "classic")) { + sprintf(pservb, "%.31s-%.31s", caller, method); + pam_service = pservb; + } else { + PAM_data.classic = 1; + pam_service = caller; + } + pam_error = pam_start(pam_service, user, &PAM_conversation, &pamh); + if (pam_error != PAM_SUCCESS) + return AuthError; + + tty = ttyname(0); + if (!tty) + tty = getenv ("DISPLAY"); + + pam_error = pam_set_item (pamh, PAM_TTY, tty); + if (pam_error != PAM_SUCCESS) { + pam_end(pamh, pam_error); + return AuthError; + } + +# ifdef PAM_FAIL_DELAY + pam_set_item (pamh, PAM_FAIL_DELAY, (void *)fail_delay); +# endif + + pam_error = pam_authenticate(pamh, 0); + if (pam_error != PAM_SUCCESS) { + pam_end(pamh, pam_error); + switch (pam_error) { + case PAM_USER_UNKNOWN: + case PAM_AUTH_ERR: + case PAM_MAXTRIES: /* should handle this better ... */ + case PAM_AUTHINFO_UNAVAIL: /* returned for unknown users ... bogus */ + return AuthBad; + default: + return AuthError; + } + } + + /* just in case some module is stupid enough to ignore a preset PAM_USER */ + pam_error = pam_get_item (pamh, PAM_USER, &pam_item); + if (pam_error != PAM_SUCCESS) { + pam_end(pamh, pam_error); + return AuthError; + } + if (strcmp((const char *)pam_item, user)) { + pam_end(pamh, PAM_SUCCESS); /* maybe use PAM_AUTH_ERR? */ + return AuthBad; + } + + pam_error = pam_setcred(pamh, PAM_REFRESH_CRED); + /* ignore errors on refresh credentials. If this did not work we use the old once. */ + + pam_end(pamh, PAM_SUCCESS); + return AuthOk; +} + +#endif |