2 Copyright (c) 2013 Eugene Crosser
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must
13 not claim that you wrote the original software. If you use this
14 software in a product, an acknowledgment in the product documentation
15 would be appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must
18 not be misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source
44 #ifdef HAVE_SECURITY_PAM_APPL_H
45 # include <security/pam_appl.h>
47 #ifdef HAVE_SECURITY_PAM_MODULES_H
48 # include <security/pam_modules.h>
50 #ifdef HAVE_SECURITY_PAM_EXT_H
51 # include <security/pam_ext.h>
56 # define PAM_EXTERN static
58 # define PAM_EXTERN extern
68 #ifndef HAVE_PAM_GET_AUTHTOK
69 static int pam_get_authtok(pam_handle_t *pamh, int item, const char **authtok,
72 struct _cfg dfl_cfg = {0};
73 struct _cfg *cfg = &dfl_cfg;
74 struct pam_conv *conv;
75 struct pam_message msg;
76 const struct pam_message *msgp;
77 struct pam_response *resp;
80 (void)pam_get_data(pamh, "pcsc_cr_cfg_struct", (const void **)&cfg);
82 if ((pam_err = pam_get_item(pamh, PAM_AUTHTOK,
83 (const void **)authtok))) {
84 if (cfg->verbose) syslog(LOG_ERR,
85 "get_item(PAM_AUTHTOK) failed: %s",
86 pam_strerror(pamh, pam_err));
88 if (*authtok) return PAM_SUCCESS;
91 if ((pam_err = pam_get_item(pamh, PAM_CONV,
92 (const void **)&conv))) {
93 if (cfg->verbose) syslog(LOG_ERR,
94 "get_item(PAM_CONV) failed: %s",
95 pam_strerror(pamh, pam_err));
98 msg.msg_style = PAM_PROMPT_ECHO_OFF;
102 pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
104 if (pam_err == PAM_SUCCESS) *authtok = resp->resp;
105 else free(resp->resp);
112 static struct _auth_chunk
113 token_key(const unsigned char *challenge, const int challengesize)
115 struct _auth_chunk ho = {0};
117 int keysize = sizeof(ho.data);
119 if ((rc = pcsc_cr(challenge, challengesize, ho.data, &keysize))) {
120 ho.err = pcsc_errstr(rc);
125 static void update_nonce(char *nonce, const int nonsize)
129 sscanf(nonce, "%d", &n);
130 snprintf(nonce, nonsize, "%d", n+1);
133 void parse_cfg(struct _cfg * const cfg, int argc, const char *argv[])
137 for (i = 0; i < argc; i++) {
138 if (strchr(argv[i],':') && strchr(argv[i],'=')) {
139 if (pcsc_option(argv[i]))
141 "unrecognized pcsc backedn option \"%s\"",
143 } else if (!strcmp(argv[i], "verbose")) cfg->verbose = 1;
144 else if (!strcmp(argv[i], "noaskpass")) cfg->noaskpass = 1;
145 else if (!strcmp(argv[i], "injectauth")) cfg->injectauth = 1;
146 else if (!strncmp(argv[i], "path=", 5))
147 authfile_template(argv[i]+5);
148 else syslog(LOG_ERR, "unrecognized arg: \"%s\"", argv[i]);
150 if (cfg->verbose) syslog(LOG_DEBUG, "arg: \"%s\"", argv[i]);
155 pam_sm_authenticate(pam_handle_t *pamh, int flags,
156 int argc, const char *argv[])
158 struct _cfg cfg = {0};
160 const char *password;
164 parse_cfg(&cfg, argc, argv);
165 (void)pam_set_data(pamh, "pcsc_cr_cfg_struct", &cfg, NULL);
166 if (cfg.verbose) syslog(LOG_INFO, "auth with %s", PACKAGE_STRING);
168 if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
169 if (cfg.verbose) syslog(LOG_ERR, "get_user failed: %s",
170 pam_strerror(pamh, pam_err));
173 if (cfg.verbose) syslog(LOG_DEBUG, "user=\"%s\"", user?user:"<none>");
175 if (!cfg.noaskpass) {
176 if ((pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
177 (const char **)&password,
178 "Token password:"))) {
179 if (cfg.verbose) syslog(LOG_ERR,
180 "get_authtok failed: %s",
181 pam_strerror(pamh, pam_err));
188 ao = authfile(user, password, update_nonce,
189 NULL, 0, NULL, 0, token_key);
191 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
194 /* Just because we can. Probably not much use for that. */
195 /* Userid written in authfile may differ from the login one. */
196 pam_set_item(pamh, PAM_USER, ao.data);
197 if (cfg.injectauth && ao.payload && ao.payload[0])
198 pam_set_item(pamh, PAM_AUTHTOK, ao.payload);
199 if (cfg.verbose) syslog(LOG_DEBUG, "authenticated");
205 pam_sm_setcred(pam_handle_t *pamh, int flags,
206 int argc, const char *argv[])
212 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
213 int argc, const char *argv[])
219 pam_sm_open_session(pam_handle_t *pamh, int flags,
220 int argc, const char *argv[])
226 pam_sm_close_session(pam_handle_t *pamh, int flags,
227 int argc, const char *argv[])
233 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
234 int argc, const char *argv[])
236 return PAM_SERVICE_ERR;
239 #ifdef PAM_MODULE_ENTRY
240 PAM_MODULE_ENTRY("pam_pcsc_cr");
244 struct pam_module _pam_pcsc_cr_modstruct = {
250 pam_sm_close_session,