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};
159 const char *tokenid = NULL;
161 const char *password;
165 parse_cfg(&cfg, argc, argv);
166 (void)pam_set_data(pamh, "pcsc_cr_cfg_struct", &cfg, NULL);
167 if (cfg.verbose) syslog(LOG_INFO, "auth with %s", PACKAGE_STRING);
169 if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
170 if (cfg.verbose) syslog(LOG_ERR, "get_user failed: %s",
171 pam_strerror(pamh, pam_err));
174 if (strspn(user, "0123456789") == strlen(user)) {
178 if (cfg.verbose) syslog(LOG_DEBUG, "tokenid=\"%s\", user=\"%s\"",
179 tokenid?tokenid:"<none>", user?user:"<none>");
181 if (!cfg.noaskpass) {
182 if ((pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
183 (const char **)&password,
184 "Token password:"))) {
185 if (cfg.verbose) syslog(LOG_ERR,
186 "get_authtok failed: %s",
187 pam_strerror(pamh, pam_err));
194 ao = authfile(tokenid, user, password, update_nonce,
195 NULL, 0, NULL, 0, token_key);
197 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
201 pam_set_item(pamh, PAM_USER, ao.data);
202 if (cfg.injectauth && ao.payload && ao.payload[0])
203 pam_set_item(pamh, PAM_AUTHTOK, ao.payload);
204 if (cfg.verbose) syslog(LOG_DEBUG, "authenticated");
210 pam_sm_setcred(pam_handle_t *pamh, int flags,
211 int argc, const char *argv[])
217 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
218 int argc, const char *argv[])
224 pam_sm_open_session(pam_handle_t *pamh, int flags,
225 int argc, const char *argv[])
231 pam_sm_close_session(pam_handle_t *pamh, int flags,
232 int argc, const char *argv[])
238 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
239 int argc, const char *argv[])
241 return PAM_SERVICE_ERR;
244 #ifdef PAM_MODULE_ENTRY
245 PAM_MODULE_ENTRY("pam_pcsc_cr");
249 struct pam_module _pam_pcsc_cr_modstruct = {
255 pam_sm_close_session,