get rid of tokenid altogether
[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 *user;
160         const char *password;
161         struct _auth_obj ao;
162         int pam_err;
163
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);
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 (cfg.verbose) syslog(LOG_DEBUG, "user=\"%s\"", user?user:"<none>");
174
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));
182                         return pam_err;
183                 }
184         } else {
185                 password = "";
186         }
187
188         ao = authfile(user, password, update_nonce,
189                         NULL, 0, NULL, 0, token_key);
190         if (ao.err) {
191                 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
192                 return PAM_AUTH_ERR;
193         } else {
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");
200                 return PAM_SUCCESS;
201         }
202 }
203
204 PAM_EXTERN int
205 pam_sm_setcred(pam_handle_t *pamh, int flags,
206         int argc, const char *argv[])
207 {
208         return PAM_SUCCESS;
209 }
210
211 PAM_EXTERN int
212 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
213         int argc, const char *argv[])
214 {
215         return PAM_SUCCESS;
216 }
217
218 PAM_EXTERN int
219 pam_sm_open_session(pam_handle_t *pamh, int flags,
220         int argc, const char *argv[])
221 {
222         return PAM_SUCCESS;
223 }
224
225 PAM_EXTERN int
226 pam_sm_close_session(pam_handle_t *pamh, int flags,
227         int argc, const char *argv[])
228 {
229         return PAM_SUCCESS;
230 }
231
232 PAM_EXTERN int
233 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
234         int argc, const char *argv[])
235 {
236         return PAM_SERVICE_ERR;
237 }
238
239 #ifdef PAM_MODULE_ENTRY
240 PAM_MODULE_ENTRY("pam_pcsc_cr");
241 #endif
242
243 #ifdef PAM_STATIC
244 struct pam_module _pam_pcsc_cr_modstruct = {
245         "pam_pcsc_cr",
246         pam_sm_authenticate,
247         pam_sm_setcred,
248         pam_sm_acct_mgmt,
249         pam_sm_open_session,
250         pam_sm_close_session,
251         pam_sm_chauthtok
252 };
253 #endif