base64: check sizes
[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
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));
171                 return pam_err;
172         }
173         if (strspn(user, "0123456789") == strlen(user)) {
174                 tokenid = user;
175                 user = NULL;
176         }
177         if (cfg.verbose) syslog(LOG_DEBUG, "tokenid=\"%s\", user=\"%s\"",
178                                 tokenid?tokenid:"<none>", user?user:"<none>");
179
180         if (!cfg.noaskpass) {
181                 if ((pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
182                                         (const char **)&password,
183                                         "Token password:"))) {
184                         if (cfg.verbose) syslog(LOG_ERR,
185                                                 "get_authtok failed: %s",
186                                                 pam_strerror(pamh, pam_err));
187                         return pam_err;
188                 }
189         } else {
190                 password = "";
191         }
192
193         ao = authfile(tokenid, user, password, update_nonce,
194                         NULL, 0, NULL, 0, token_key);
195         if (ao.err) {
196                 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
197                 return PAM_AUTH_ERR;
198         } else {
199                 if (!user)
200                         pam_set_item(pamh, PAM_USER, ao.data);
201                 if (cfg.injectauth && ao.payload && ao.payload[0])
202                         pam_set_item(pamh, PAM_AUTHTOK, ao.payload);
203                 if (cfg.verbose) syslog(LOG_DEBUG, "authenticated");
204                 return PAM_SUCCESS;
205         }
206 }
207
208 PAM_EXTERN int
209 pam_sm_setcred(pam_handle_t *pamh, int flags,
210         int argc, const char *argv[])
211 {
212         return PAM_SUCCESS;
213 }
214
215 PAM_EXTERN int
216 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
217         int argc, const char *argv[])
218 {
219         return PAM_SUCCESS;
220 }
221
222 PAM_EXTERN int
223 pam_sm_open_session(pam_handle_t *pamh, int flags,
224         int argc, const char *argv[])
225 {
226         return PAM_SUCCESS;
227 }
228
229 PAM_EXTERN int
230 pam_sm_close_session(pam_handle_t *pamh, int flags,
231         int argc, const char *argv[])
232 {
233         return PAM_SUCCESS;
234 }
235
236 PAM_EXTERN int
237 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
238         int argc, const char *argv[])
239 {
240         return PAM_SERVICE_ERR;
241 }
242
243 #ifdef PAM_MODULE_ENTRY
244 PAM_MODULE_ENTRY("pam_pcsc_cr");
245 #endif
246
247 #ifdef PAM_STATIC
248 struct pam_module _pam_pcsc_cr_modstruct = {
249         "pam_pcsc_cr",
250         pam_sm_authenticate,
251         pam_sm_setcred,
252         pam_sm_acct_mgmt,
253         pam_sm_open_session,
254         pam_sm_close_session,
255         pam_sm_chauthtok
256 };
257 #endif