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>
53 # define PAM_EXTERN static
55 # define PAM_EXTERN extern
59 static struct _auth_chunk
60 token_key(const unsigned char *challenge, const int challengesize)
62 struct _auth_chunk ho = {0};
64 int keysize = sizeof(ho.data);
66 if ((rc = pcsc_cr(challenge, challengesize, ho.data, &keysize))) {
67 ho.err = pcsc_errstr(rc);
72 static void update_nonce(char *nonce, const int nonsize)
76 sscanf(nonce, "%d", &n);
77 snprintf(nonce, nonsize, "%d", n+1);
86 void parse_cfg(struct _cfg * const cfg, int argc, const char *argv[])
90 for (i = 0; i < argc; i++) {
91 if (strchr(argv[i],':') && strchr(argv[i],'='))
93 else if (!strcmp(argv[i], "verbose")) cfg->verbose = 1;
94 else if (!strcmp(argv[i], "noaskpass")) cfg->noaskpass = 1;
95 else if (!strcmp(argv[i], "injectauth")) cfg->injectauth = 1;
96 else if (!strncmp(argv[i], "path=", 5))
97 authfile_template(argv[i]+5);
102 pam_sm_authenticate(pam_handle_t *pamh, int flags,
103 int argc, const char *argv[])
105 struct _cfg cfg = {0};
106 const char *tokenid = NULL;
108 const char *password;
112 parse_cfg(&cfg, argc, argv);
114 if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
115 if (cfg.verbose) syslog(LOG_ERR, "get_user failed: %s",
116 pam_strerror(pamh, pam_err));
119 if (strspn(user, "0123456789") == strlen(user)) {
124 if (!cfg.noaskpass) {
126 pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
127 (const char **)&password, NULL);
129 struct pam_conv *conv;
130 struct pam_message msg;
131 const struct pam_message *msgp;
132 struct pam_response *resp;
134 if ((pam_err = pam_get_item(pamh, PAM_CONV,
135 (const void **)&conv))) {
136 if (cfg.verbose) syslog(LOG_ERR,
137 "get_item failed: %s",
138 pam_strerror(pamh, pam_err));
141 msg.msg_style = PAM_PROMPT_ECHO_OFF;
142 msg.msg = "Token password:";
145 pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
147 if (pam_err == PAM_SUCCESS) password = resp->resp;
148 else free(resp->resp);
152 if (pam_err) return pam_err;
157 ao = authfile(tokenid, user, password, update_nonce,
158 NULL, 0, NULL, 0, token_key);
160 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
164 pam_set_item(pamh, PAM_USER, ao.data);
165 if (cfg.injectauth && ao.payload && ao.payload[0])
166 pam_set_item(pamh, PAM_AUTHTOK, ao.payload);
172 pam_sm_setcred(pam_handle_t *pamh, int flags,
173 int argc, const char *argv[])
179 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
180 int argc, const char *argv[])
186 pam_sm_open_session(pam_handle_t *pamh, int flags,
187 int argc, const char *argv[])
193 pam_sm_close_session(pam_handle_t *pamh, int flags,
194 int argc, const char *argv[])
200 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
201 int argc, const char *argv[])
203 return PAM_SERVICE_ERR;
206 #ifdef PAM_MODULE_ENTRY
207 PAM_MODULE_ENTRY("pam_unix");
211 struct pam_module _pam_pcsc_cr_modstruct = {
217 pam_sm_close_session,