gitignore *.a
[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 };
61
62 void parse_cfg(struct _cfg * const cfg, int argc, const char *argv[])
63 {
64         int i;
65
66         for (i = 0; i < argc; i++) {
67                 if (strchr(argv[i],':') && strchr(argv[i],'='))
68                         pcsc_option(argv[i]);
69                 else if (!strcmp(argv[i], "verbose")) cfg->verbose = 1;
70                 else if (!strcmp(argv[i], "noaskpass")) cfg->noaskpass = 1;
71         }
72 }
73
74 PAM_EXTERN int
75 pam_sm_authenticate(pam_handle_t *pamh, int flags,
76         int argc, const char *argv[])
77 {
78         struct _cfg cfg = {0};
79         const char *tokenid = NULL;
80         const char *user;
81         const char *password;
82         struct _auth_obj ao;
83         int pam_err;
84
85         parse_cfg(&cfg, argc, argv);
86
87         if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
88                 if (cfg.verbose) syslog(LOG_ERR, "get_user failed: %s",
89                                         pam_strerror(pamh, pam_err));
90                 return (pam_err);
91         }
92         if (strspn(user, "0123456789") == strlen(user)) {
93                 tokenid = user;
94                 user = NULL;
95         }
96
97         if (!cfg.noaskpass) {
98 #ifdef _OPENPAM
99                 pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
100                                         (const char **)&password, NULL);
101 #else
102                 struct pam_conv *conv;
103                 struct pam_message msg;
104                 const struct pam_message *msgp;
105                 struct pam_response *resp;
106
107                 if ((pam_err = pam_get_item(pamh, PAM_CONV,
108                                         (const void **)&conv))) {
109                         if (cfg.verbose) syslog(LOG_ERR,
110                                         "get_item failed: %s",
111                                         pam_strerror(pamh, pam_err));
112                         return pam_err;
113                 }
114                 msg.msg_style = PAM_PROMPT_ECHO_OFF;
115                 msg.msg = "Token password:";
116                 msgp = &msg;
117                 resp = NULL;
118                 pam_err =  (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
119                 if (resp != NULL) {
120                         if (pam_err == PAM_SUCCESS) password = resp->resp;
121                         else free(resp->resp);
122                         free(resp);
123                 }
124 #endif
125                 if (pam_err) return pam_err;
126         } else {
127                 password = "";
128         }
129
130         ao = authfile(tokenid, user, password, update_nonce,
131                         NULL, 0, NULL, 0, token_key);
132         if (ao.err) {
133                 if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err);
134                 return PAM_AUTH_ERR;
135         } else {
136                 if (!user)
137                         pam_set_item(pamh, PAM_USER, ao.data);
138                 if (ao.payload && ao.payload[0])
139                         pam_set_item(pamh, PAM_AUTHTOK, ao.payload);
140                 return PAM_SUCCESS;
141         }
142 }
143
144 PAM_EXTERN int
145 pam_sm_setcred(pam_handle_t *pamh, int flags,
146         int argc, const char *argv[])
147 {
148         return PAM_SUCCESS;
149 }
150
151 PAM_EXTERN int
152 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
153         int argc, const char *argv[])
154 {
155         return PAM_SUCCESS;
156 }
157
158 PAM_EXTERN int
159 pam_sm_open_session(pam_handle_t *pamh, int flags,
160         int argc, const char *argv[])
161 {
162         return PAM_SUCCESS;
163 }
164
165 PAM_EXTERN int
166 pam_sm_close_session(pam_handle_t *pamh, int flags,
167         int argc, const char *argv[])
168 {
169         return PAM_SUCCESS;
170 }
171
172 PAM_EXTERN int
173 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
174         int argc, const char *argv[])
175 {
176         return PAM_SERVICE_ERR;
177 }
178
179 #ifdef PAM_MODULE_ENTRY
180 PAM_MODULE_ENTRY("pam_unix");
181 #endif
182
183 #ifdef PAM_STATIC
184 struct pam_module _pam_pcsc_cr_modstruct = {
185         "pam_pcsc_cr",
186         pam_sm_authenticate,
187         pam_sm_setcred,
188         pam_sm_acct_mgmt,
189         pam_sm_open_session,
190         pam_sm_close_session,
191         pam_sm_chauthtok
192 };
193 #endif