Put zlib license in all files
[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
51 #ifndef PAM_EXTERN
52 # ifdef PAM_STATIC
53 #  define PAM_EXTERN static
54 # else
55 #  define PAM_EXTERN extern
56 # endif
57 #endif
58
59 static struct _auth_chunk
60 token_key(const unsigned char *challenge, const int challengesize)
61 {
62         struct _auth_chunk ho = {0};
63         long rc;
64         int keysize = sizeof(ho.data);
65
66         if ((rc = pcsc_cr(challenge, challengesize, ho.data, &keysize))) {
67                 ho.err = pcsc_errstr(rc);
68         }
69         return ho;
70 }
71
72 static void update_nonce(char *nonce, const int nonsize)
73 {
74         int n = 0;
75
76         sscanf(nonce, "%d", &n);
77         snprintf(nonce, nonsize, "%d", n+1);
78 }
79
80 struct _cfg {
81         int noaskpass;
82         int verbose;
83         int injectauth;
84 };
85
86 void parse_cfg(struct _cfg * const cfg, int argc, const char *argv[])
87 {
88         int i;
89
90         for (i = 0; i < argc; i++) {
91                 if (strchr(argv[i],':') && strchr(argv[i],'='))
92                         pcsc_option(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);
98         }
99 }
100
101 PAM_EXTERN int
102 pam_sm_authenticate(pam_handle_t *pamh, int flags,
103         int argc, const char *argv[])
104 {
105         struct _cfg cfg = {0};
106         const char *tokenid = NULL;
107         const char *user;
108         const char *password;
109         struct _auth_obj ao;
110         int pam_err;
111
112         parse_cfg(&cfg, argc, argv);
113
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));
117                 return pam_err;
118         }
119         if (strspn(user, "0123456789") == strlen(user)) {
120                 tokenid = user;
121                 user = NULL;
122         }
123
124         if (!cfg.noaskpass) {
125 #ifdef _OPENPAM
126                 pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
127                                         (const char **)&password, NULL);
128 #else
129                 struct pam_conv *conv;
130                 struct pam_message msg;
131                 const struct pam_message *msgp;
132                 struct pam_response *resp;
133
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));
139                         return pam_err;
140                 }
141                 msg.msg_style = PAM_PROMPT_ECHO_OFF;
142                 msg.msg = "Token password:";
143                 msgp = &msg;
144                 resp = NULL;
145                 pam_err =  (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
146                 if (resp != NULL) {
147                         if (pam_err == PAM_SUCCESS) password = resp->resp;
148                         else free(resp->resp);
149                         free(resp);
150                 }
151 #endif
152                 if (pam_err) return pam_err;
153         } else {
154                 password = "";
155         }
156
157         ao = authfile(tokenid, user, password, update_nonce,
158                         NULL, 0, NULL, 0, token_key);
159         if (ao.err) {
160                 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
161                 return PAM_AUTH_ERR;
162         } else {
163                 if (!user)
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);
167                 return PAM_SUCCESS;
168         }
169 }
170
171 PAM_EXTERN int
172 pam_sm_setcred(pam_handle_t *pamh, int flags,
173         int argc, const char *argv[])
174 {
175         return PAM_SUCCESS;
176 }
177
178 PAM_EXTERN int
179 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
180         int argc, const char *argv[])
181 {
182         return PAM_SUCCESS;
183 }
184
185 PAM_EXTERN int
186 pam_sm_open_session(pam_handle_t *pamh, int flags,
187         int argc, const char *argv[])
188 {
189         return PAM_SUCCESS;
190 }
191
192 PAM_EXTERN int
193 pam_sm_close_session(pam_handle_t *pamh, int flags,
194         int argc, const char *argv[])
195 {
196         return PAM_SUCCESS;
197 }
198
199 PAM_EXTERN int
200 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
201         int argc, const char *argv[])
202 {
203         return PAM_SERVICE_ERR;
204 }
205
206 #ifdef PAM_MODULE_ENTRY
207 PAM_MODULE_ENTRY("pam_unix");
208 #endif
209
210 #ifdef PAM_STATIC
211 struct pam_module _pam_pcsc_cr_modstruct = {
212         "pam_pcsc_cr",
213         pam_sm_authenticate,
214         pam_sm_setcred,
215         pam_sm_acct_mgmt,
216         pam_sm_open_session,
217         pam_sm_close_session,
218         pam_sm_chauthtok
219 };
220 #endif