75c49daeda87e96752afb8dccfcb3aea6c60c31f
[pam_pcsc_cr.git] / pam_pcsc_cr.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <stdarg.h>
10 #include <syslog.h>
11 #include "authobj.h"
12 #include "authfile.h"
13 #include "pcsc_cr.h"
14
15 #ifndef PIC
16 # define PAM_STATIC
17 #endif
18
19 #define PAM_SM_AUTH
20
21 #ifdef HAVE_SECURITY_PAM_APPL_H
22 # include <security/pam_appl.h>
23 #endif
24 #ifdef HAVE_SECURITY_PAM_MODULES_H
25 # include <security/pam_modules.h>
26 #endif
27
28 #ifndef PAM_EXTERN
29 # ifdef PAM_STATIC
30 #  define PAM_EXTERN static
31 # else
32 #  define PAM_EXTERN extern
33 # endif
34 #endif
35
36 static struct _auth_chunk
37 token_key(const unsigned char *challenge, const int challengesize)
38 {
39         struct _auth_chunk ho = {0};
40         long rc;
41         int keysize = sizeof(ho.data);
42
43         if ((rc = pcsc_cr(challenge, challengesize, ho.data, &keysize))) {
44                 ho.err = pcsc_errstr(rc);
45         }
46         return ho;
47 }
48
49 static void update_nonce(char *nonce, const int nonsize)
50 {
51         int n = 0;
52
53         sscanf(nonce, "%d", &n);
54         snprintf(nonce, nonsize, "%d", n+1);
55 }
56
57 struct _cfg {
58         int noaskpass;
59         int verbose;
60         int injectauth;
61 };
62
63 void parse_cfg(struct _cfg * const cfg, int argc, const char *argv[])
64 {
65         int i;
66
67         for (i = 0; i < argc; i++) {
68                 if (strchr(argv[i],':') && strchr(argv[i],'='))
69                         pcsc_option(argv[i]);
70                 else if (!strcmp(argv[i], "verbose")) cfg->verbose = 1;
71                 else if (!strcmp(argv[i], "noaskpass")) cfg->noaskpass = 1;
72                 else if (!strcmp(argv[i], "injectauth")) cfg->injectauth = 1;
73                 else if (!strncmp(argv[i], "path=", 5))
74                                         authfile_template(argv[i]+5);
75         }
76 }
77
78 PAM_EXTERN int
79 pam_sm_authenticate(pam_handle_t *pamh, int flags,
80         int argc, const char *argv[])
81 {
82         struct _cfg cfg = {0};
83         const char *tokenid = NULL;
84         const char *user;
85         const char *password;
86         struct _auth_obj ao;
87         int pam_err;
88
89         parse_cfg(&cfg, argc, argv);
90
91         if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
92                 if (cfg.verbose) syslog(LOG_ERR, "get_user failed: %s",
93                                         pam_strerror(pamh, pam_err));
94                 return pam_err;
95         }
96         if (strspn(user, "0123456789") == strlen(user)) {
97                 tokenid = user;
98                 user = NULL;
99         }
100
101         if (!cfg.noaskpass) {
102 #ifdef _OPENPAM
103                 pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
104                                         (const char **)&password, NULL);
105 #else
106                 struct pam_conv *conv;
107                 struct pam_message msg;
108                 const struct pam_message *msgp;
109                 struct pam_response *resp;
110
111                 if ((pam_err = pam_get_item(pamh, PAM_CONV,
112                                         (const void **)&conv))) {
113                         if (cfg.verbose) syslog(LOG_ERR,
114                                         "get_item failed: %s",
115                                         pam_strerror(pamh, pam_err));
116                         return pam_err;
117                 }
118                 msg.msg_style = PAM_PROMPT_ECHO_OFF;
119                 msg.msg = "Token password:";
120                 msgp = &msg;
121                 resp = NULL;
122                 pam_err =  (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
123                 if (resp != NULL) {
124                         if (pam_err == PAM_SUCCESS) password = resp->resp;
125                         else free(resp->resp);
126                         free(resp);
127                 }
128 #endif
129                 if (pam_err) return pam_err;
130         } else {
131                 password = "";
132         }
133
134         ao = authfile(tokenid, user, password, update_nonce,
135                         NULL, 0, NULL, 0, token_key);
136         if (ao.err) {
137                 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
138                 return PAM_AUTH_ERR;
139         } else {
140                 if (!user)
141                         pam_set_item(pamh, PAM_USER, ao.data);
142                 if (cfg.injectauth && ao.payload && ao.payload[0])
143                         pam_set_item(pamh, PAM_AUTHTOK, ao.payload);
144                 return PAM_SUCCESS;
145         }
146 }
147
148 PAM_EXTERN int
149 pam_sm_setcred(pam_handle_t *pamh, int flags,
150         int argc, const char *argv[])
151 {
152         return PAM_SUCCESS;
153 }
154
155 PAM_EXTERN int
156 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
157         int argc, const char *argv[])
158 {
159         return PAM_SUCCESS;
160 }
161
162 PAM_EXTERN int
163 pam_sm_open_session(pam_handle_t *pamh, int flags,
164         int argc, const char *argv[])
165 {
166         return PAM_SUCCESS;
167 }
168
169 PAM_EXTERN int
170 pam_sm_close_session(pam_handle_t *pamh, int flags,
171         int argc, const char *argv[])
172 {
173         return PAM_SUCCESS;
174 }
175
176 PAM_EXTERN int
177 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
178         int argc, const char *argv[])
179 {
180         return PAM_SERVICE_ERR;
181 }
182
183 #ifdef PAM_MODULE_ENTRY
184 PAM_MODULE_ENTRY("pam_unix");
185 #endif
186
187 #ifdef PAM_STATIC
188 struct pam_module _pam_pcsc_cr_modstruct = {
189         "pam_pcsc_cr",
190         pam_sm_authenticate,
191         pam_sm_setcred,
192         pam_sm_acct_mgmt,
193         pam_sm_open_session,
194         pam_sm_close_session,
195         pam_sm_chauthtok
196 };
197 #endif