]> www.average.org Git - pam_pcsc_cr.git/blob - pam_pcsc_cr.c
colorize svg picture
[pam_pcsc_cr.git] / pam_pcsc_cr.c
1 /*
2 Copyright (c) 2013 Eugene Crosser
3
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.
7
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:
11
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.
16
17     2. Altered source versions must be plainly marked as such, and must
18     not be misrepresented as being the original software.
19
20     3. This notice may not be removed or altered from any source
21     distribution.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <stdarg.h>
33 #include <syslog.h>
34 #include "authobj.h"
35 #include "authfile.h"
36 #include "pcsc_cr.h"
37
38 #ifndef PIC
39 # define PAM_STATIC
40 #endif
41
42 #define PAM_SM_AUTH
43
44 #ifdef HAVE_SECURITY_PAM_APPL_H
45 # include <security/pam_appl.h>
46 #endif
47 #ifdef HAVE_SECURITY_PAM_MODULES_H
48 # include <security/pam_modules.h>
49 #endif
50 #ifdef HAVE_SECURITY_PAM_EXT_H
51 # include <security/pam_ext.h>
52 #endif
53
54 #ifndef PAM_EXTERN
55 # ifdef PAM_STATIC
56 #  define PAM_EXTERN static
57 # else
58 #  define PAM_EXTERN extern
59 # endif
60 #endif
61
62 struct _cfg {
63         int noaskpass;
64         int verbose;
65         int injectauth;
66 };
67
68 #ifndef HAVE_PAM_GET_AUTHTOK
69 static int pam_get_authtok(pam_handle_t *pamh, int item, const char **authtok,
70                         const char *prompt)
71 {
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;
78         int pam_err;
79
80         (void)pam_get_data(pamh, "pcsc_cr_cfg_struct", (const void **)&cfg);
81
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));
87         } else {
88                 if (*authtok) return PAM_SUCCESS;
89         }
90
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));
96                 return pam_err;
97         }
98         msg.msg_style = PAM_PROMPT_ECHO_OFF;
99         msg.msg = prompt;
100         msgp = &msg;
101         resp = NULL;
102         pam_err =  (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
103         if (resp != NULL) {
104                 if (pam_err == PAM_SUCCESS) *authtok = resp->resp;
105                 else free(resp->resp);
106                 free(resp);
107         }
108         return pam_err;
109 }
110 #endif
111
112 static struct _auth_chunk
113 token_key(const unsigned char *challenge, const int challengesize)
114 {
115         struct _auth_chunk ho = {0};
116         long rc;
117         int keysize = sizeof(ho.data);
118
119         if ((rc = pcsc_cr(challenge, challengesize, ho.data, &keysize))) {
120                 ho.err = pcsc_errstr(rc);
121         }
122         return ho;
123 }
124
125 static void update_nonce(char *nonce, const int nonsize)
126 {
127         int n = 0;
128
129         sscanf(nonce, "%d", &n);
130         snprintf(nonce, nonsize, "%d", n+1);
131 }
132
133 void parse_cfg(struct _cfg * const cfg, int argc, const char *argv[])
134 {
135         int i;
136
137         for (i = 0; i < argc; i++) {
138                 if (strchr(argv[i],':') && strchr(argv[i],'=')) {
139                         if (pcsc_option(argv[i]))
140                                 syslog(LOG_ERR,
141                                 "unrecognized pcsc backedn option \"%s\"",
142                                                 argv[i]);
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]);
149
150                 if (cfg->verbose) syslog(LOG_DEBUG, "arg: \"%s\"", argv[i]);
151         }
152 }
153
154 PAM_EXTERN int
155 pam_sm_authenticate(pam_handle_t *pamh, int flags,
156         int argc, const char *argv[])
157 {
158         struct _cfg cfg = {0};
159         const char *tokenid = NULL;
160         const char *user;
161         const char *password;
162         struct _auth_obj ao;
163         int pam_err;
164
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);
168
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));
172                 return pam_err;
173         }
174         if (strspn(user, "0123456789") == strlen(user)) {
175                 tokenid = user;
176                 user = NULL;
177         }
178         if (cfg.verbose) syslog(LOG_DEBUG, "tokenid=\"%s\", user=\"%s\"",
179                                 tokenid?tokenid:"<none>", user?user:"<none>");
180
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));
188                         return pam_err;
189                 }
190         } else {
191                 password = "";
192         }
193
194         ao = authfile(tokenid, user, password, update_nonce,
195                         NULL, 0, NULL, 0, token_key);
196         if (ao.err) {
197                 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
198                 return PAM_AUTH_ERR;
199         } else {
200                 if (!user)
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");
205                 return PAM_SUCCESS;
206         }
207 }
208
209 PAM_EXTERN int
210 pam_sm_setcred(pam_handle_t *pamh, int flags,
211         int argc, const char *argv[])
212 {
213         return PAM_SUCCESS;
214 }
215
216 PAM_EXTERN int
217 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
218         int argc, const char *argv[])
219 {
220         return PAM_SUCCESS;
221 }
222
223 PAM_EXTERN int
224 pam_sm_open_session(pam_handle_t *pamh, int flags,
225         int argc, const char *argv[])
226 {
227         return PAM_SUCCESS;
228 }
229
230 PAM_EXTERN int
231 pam_sm_close_session(pam_handle_t *pamh, int flags,
232         int argc, const char *argv[])
233 {
234         return PAM_SUCCESS;
235 }
236
237 PAM_EXTERN int
238 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
239         int argc, const char *argv[])
240 {
241         return PAM_SERVICE_ERR;
242 }
243
244 #ifdef PAM_MODULE_ENTRY
245 PAM_MODULE_ENTRY("pam_pcsc_cr");
246 #endif
247
248 #ifdef PAM_STATIC
249 struct pam_module _pam_pcsc_cr_modstruct = {
250         "pam_pcsc_cr",
251         pam_sm_authenticate,
252         pam_sm_setcred,
253         pam_sm_acct_mgmt,
254         pam_sm_open_session,
255         pam_sm_close_session,
256         pam_sm_chauthtok
257 };
258 #endif