From 32b6f4c4aeddfdda9343d59fba02ae7fe3e0b24c Mon Sep 17 00:00:00 2001 From: tpearson Date: Tue, 20 Sep 2011 20:01:11 +0000 Subject: Use new smartauthmon C++ program instead of the old bash script for smartcard authentication This plugs several possible security holes git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/smartcardauth@1254687 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- src/ckpass.c | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 src/ckpass.c (limited to 'src/ckpass.c') diff --git a/src/ckpass.c b/src/ckpass.c new file mode 100644 index 0000000..1da83c6 --- /dev/null +++ b/src/ckpass.c @@ -0,0 +1,284 @@ +/* $Id: ckpasswd.c 7565 2006-08-28 02:42:54Z eagle $ +** +** The default username/password authenticator. +** +** This program is intended to be run by nnrpd and handle usernames and +** passwords. It can authenticate against a regular flat file (the type +** managed by htpasswd), a DBM file, the system password file or shadow file, +** or PAM. +*/ + +/* Used for unused parameters to silence gcc warnings. */ +#define UNUSED __attribute__((__unused__)) + +/* Make available the bool type. */ +#if INN_HAVE_STDBOOL_H +# include +#else +# undef true +# undef false +# define true (1) +# define false (0) +# ifndef __cplusplus +# define bool int +# endif +#endif /* INN_HAVE_STDBOOL_H */ + +#include +#include +#include +#include +#include +#include + +#define DB_DBM_HSEARCH 1 +#include +#define OPT_DBM "d:" + +#if HAVE_GETSPNAM +# include +# define OPT_SHADOW "s" +#else +# define OPT_SHADOW "" +#endif + +/* The functions are actually macros so that we can pick up the file and line + number information for debugging error messages without the user having to + pass those in every time. */ +#define xcalloc(n, size) x_calloc((n), (size), __FILE__, __LINE__) +#define xmalloc(size) x_malloc((size), __FILE__, __LINE__) +#define xrealloc(p, size) x_realloc((p), (size), __FILE__, __LINE__) +#define xstrdup(p) x_strdup((p), __FILE__, __LINE__) +#define xstrndup(p, size) x_strndup((p), (size), __FILE__, __LINE__) + +#include + +/* Holds the authentication information from nnrpd. */ +struct auth_info { + char *username; + char *password; +}; + +/* +** The PAM conversation function. +** +** Since we already have all the information and can't ask the user +** questions, we can't quite follow the real PAM protocol. Instead, we just +** return the password in response to every question that PAM asks. There +** appears to be no generic way to determine whether the message in question +** is indeed asking for the password.... +** +** This function allocates an array of struct pam_response to return to the +** PAM libraries that's never freed. For this program, this isn't much of an +** issue, since it will likely only be called once and then the program will +** exit. This function uses malloc and strdup instead of xmalloc and xstrdup +** intentionally so that the PAM conversation will be closed cleanly if we +** run out of memory rather than simply terminated. +** +** appdata_ptr contains the password we were given. +*/ +static int pass_conv(int num_msg, const struct pam_message **msgm UNUSED, struct pam_response **response, void *appdata_ptr) +{ + int i; + + *response = malloc(num_msg * sizeof(struct pam_response)); + if (*response == NULL) + return PAM_CONV_ERR; + for (i = 0; i < num_msg; i++) { + (*response)[i].resp = strdup((char *)appdata_ptr); + (*response)[i].resp_retcode = 0; + } + return PAM_SUCCESS; +} + + +/* +** Authenticate a user via PAM. +** +** Attempts to authenticate a user with PAM, returning true if the user +** successfully authenticates and false otherwise. Note that this function +** doesn't attempt to handle any remapping of the authenticated user by the +** PAM stack, but just assumes that the authenticated user was the same as +** the username given. +** +** Right now, all failures are handled via die. This may be worth revisiting +** in case we want to try other authentication methods if this fails for a +** reason other than the system not having PAM support. +*/ + +static bool auth_pam(const char *username, char *password) +{ + pam_handle_t *pamh; + struct pam_conv conv; + int status; + + conv.conv = pass_conv; + conv.appdata_ptr = password; + status = pam_start("nnrpd", username, &conv, &pamh); + if (status != PAM_SUCCESS) + die("pam_start failed: %s", pam_strerror(pamh, status)); + status = pam_authenticate(pamh, PAM_SILENT); + if (status != PAM_SUCCESS) + die("pam_authenticate failed: %s", pam_strerror(pamh, status)); + status = pam_acct_mgmt(pamh, PAM_SILENT); + if (status != PAM_SUCCESS) + die("pam_acct_mgmt failed: %s", pam_strerror(pamh, status)); + status = pam_end(pamh, status); + if (status != PAM_SUCCESS) + die("pam_end failed: %s", pam_strerror(pamh, status)); + + /* If we get to here, the user successfully authenticated. */ + return true; +} + + +/* +** Try to get a password out of a dbm file. The dbm file should have the +** username for the key and the crypted password as the value. The crypted +** password, if found, is returned as a newly allocated string; otherwise, +** NULL is returned. +*/ +#if !(defined(HAVE_DBM) || defined(HAVE_BDB_DBM)) +static char * +password_dbm(char *user UNUSED, const char *file UNUSED) +{ + return NULL; +} +#else +static char * +password_dbm(char *name, const char *file) +{ + datum key, value; + DBM *database; + char *password; + + database = dbm_open(file, O_RDONLY, 0600); + if (database == NULL) + return NULL; + key.dptr = name; + key.dsize = strlen(name); + value = dbm_fetch(database, key); + if (value.dptr == NULL) { + dbm_close(database); + return NULL; + } + password = xmalloc(value.dsize + 1); + strlcpy(password, value.dptr, value.dsize + 1); + dbm_close(database); + return password; +} +#endif /* HAVE_DBM || HAVE_BDB_DBM */ + + +/* +** Try to get a password out of the system /etc/shadow file. The crypted +** password, if found, is returned as a newly allocated string; otherwise, +** NULL is returned. +*/ +#if !HAVE_GETSPNAM +static char * +password_shadow(const char *user UNUSED) +{ + return NULL; +} +#else +static char * +password_shadow(const char *user) +{ + struct spwd *spwd; + + spwd = getspnam(user); + if (spwd != NULL) + return xstrdup(spwd->sp_pwdp); + return NULL; +} +#endif /* HAVE_GETSPNAM */ + + +/* +** Try to get a password out of the system password file. The crypted +** password, if found, is returned as a newly allocated string; otherwise, +** NULL is returned. +*/ +static char * +password_system(const char *username) +{ + struct passwd *pwd; + + pwd = getpwnam(username); + if (pwd != NULL) + return xstrdup(pwd->pw_passwd); + return NULL; +} + + +/* +** Try to get the name of a user's primary group out of the system group +** file. The group, if found, is returned as a newly allocated string; +** otherwise, NULL is returned. If the username is not found, NULL is +** returned. +*/ +static char * +group_system(const char *username) +{ + struct passwd *pwd; + struct group *gr; + + pwd = getpwnam(username); + if (pwd == NULL) + return NULL; + gr = getgrgid(pwd->pw_gid); + if (gr == NULL) + return NULL; + return xstrdup(gr->gr_name); +} + + +/* +** Output username (and group, if desired) in correct return format. +*/ +static void +output_user(const char *username, bool wantgroup) +{ + if (wantgroup) { + char *group = group_system(username); + if (group == NULL) + die("group info for user %s not available", username); + printf("User:%s@%s\n", username, group); + } + else + printf("User:%s\n", username); +} + + +/* +** Main routines. +** +** We handle the variences between systems with #if blocks above, so that +** this code can look fairly clean. +*/ + +int +check_password(const char* username, const char* password) +{ + bool wantgroup = false; + struct auth_info *authinfo = NULL; + + authinfo = xmalloc(sizeof(struct auth_info)); + authinfo->username = username; + authinfo->password = password; + + if (auth_pam(authinfo->username, authinfo->password)) { + output_user(authinfo->username, wantgroup); + return 0; + } + password = password_system(authinfo->username); + if (password == NULL) + return 1; + if (strcmp(password, crypt(authinfo->password, password)) != 0) + return 1; + + /* The password matched. */ + output_user(authinfo->username, wantgroup); + return 0; +} \ No newline at end of file -- cgit v1.2.1