change serialization interface
[pam_pcsc_cr.git] / authfile.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <alloca.h>
12 #include "authobj.h"
13 #include "authfile.h"
14 #include "pcsc_cr.h"
15
16 #define OBJSIZE 256
17
18 int update_authfile(const char *fn, const char *tokenid, const char *id,
19                 const char *password, const char *nonce,
20                 const unsigned char *secret, const int secsize,
21                 const unsigned char *payload, const int paysize)
22 {
23         FILE *fp;
24         int rc;
25         int i;
26         unsigned char key[20];
27         int keysize = sizeof(key);
28         unsigned char *mysecret = secret;
29         int mysecsize = secsize;
30         unsigned char *myload = payload;
31         int myloadsize = paysize;
32         unsigned char *authobj = NULL;
33         int authsize = 0;
34         char *buf = NULL;
35         char *mytokenid = NULL;
36         char *myid = NULL;
37         char *mynonce = NULL;
38         char *hauthobj = NULL;
39         unsigned char *oldauthobj = NULL;
40         int oldauthsize;
41
42         if ((fp = fopen(fn, "r"))) {
43                 struct stat st;
44                 int fd = fileno(fp);
45
46                 if (fstat(fd, &st)) {
47                         eprint("fstat \"%s\" (fd %d) error: %s",
48                                 fn, fd, strerror(errno));
49                         st.st_size = 2047;
50                 }
51                 if (st.st_size > 2047) st.st_size = 2047;
52                 buf = alloca(st.st_size + 1);
53                 if (fgets(buf, st.st_size + 1, fp)) {
54                         char *p;
55
56                         p = &buf[strlen(buf) - 1];
57                         while (*p == '\n' || *p == '\r') *p-- = '\0';
58                         mytokenid = strtok(buf, ":");
59                         myid = strtok(NULL, ":");
60                         mynonce = strtok(NULL, ":");
61                         hauthobj = strtok(NULL, ":");
62                 } else {
63                         eprint("error reading from %s: %s",
64                                 fn, strerror(errno));
65                 }
66                 fclose(fp);
67         }
68         if (hauthobj) {
69                 int hlen;
70
71                 hlen = strlen(hauthobj);
72                 if (hlen % 32 != 0) {
73                         eprint("error: auth string has wrong length");
74                 } else if (hlen !=
75                                 strspn(hauthobj, "0123456789abcdefABCDEF")) {
76                         eprint("error: auth string not hexadecimal");
77                 } else {
78                         oldauthsize = hlen/2;
79                         oldauthobj = alloca(oldauthsize);
80                         for (i = 0; i < oldauthsize; i++)
81                                 sscanf(&hauthobj[i*2], "%2hhx", &oldauthobj[i]);
82                 }
83         }
84
85         if (!secret) {
86                 unsigned char chal[64];
87                 int csize = sizeof(chal);
88                 long rc;
89
90                 if (!oldauthobj || !password) {
91                         eprint("if no secret given, old auth file must"
92                                 " be present and password must be given");
93                         return -1;
94                 }
95                 rc = make_challenge(myid, password, mynonce, chal, &csize);
96                 if (rc) {
97                         eprint("cannot make challenge");
98                         return -1;
99                 }
100                 rc = pcsc_cr(chal, csize, key, &keysize);
101                 if (rc) {
102                         eprint("error querying token: %s", pcsc_errstr(rc));
103                         return -1;
104                 }
105                 mysecsize = oldauthsize;
106                 mysecret = alloca(mysecsize);
107                 myloadsize  = oldauthsize;
108                 myload = alloca(myloadsize);
109                 rc = parse_authobj(key, keysize, oldauthobj, oldauthsize,
110                         mysecret, &mysecsize, myload, &myloadsize);
111                 if (rc) {
112                         eprint("cannot parse old authobj: %d", rc);
113                         return -1;
114                 }
115         }
116         if (tokenid) mytokenid = tokenid;
117         if (id) myid = id;
118         if (nonce) mynonce = nonce;
119         else {
120                 unsigned int prev = atoi(mynonce);
121                 mynonce = alloca(16);
122                 sprintf(mynonce, "%d", prev + 1);
123         }
124
125         authsize = ((mysecsize + myloadsize + 16 + 4 * sizeof(short) - 1) /
126                         16 + 1) * 16;
127         authobj = alloca(authsize);
128         rc = make_authobj(myid, password, mynonce, mysecret, mysecsize,
129                         myload, myloadsize, authobj, &authsize);
130         if (rc) {
131                 eprint("make_authobj error %d", rc);
132                 return -1;
133         }
134
135         if ((fp = fopen(fn, "w"))) {
136                 if (fprintf(fp, "%s:%s:%s:", mytokenid, myid, mynonce) < 0) {
137                         eprint("cannot write to \"%s\": %s",
138                                 fn, strerror(errno));
139                         return -1;
140                 }
141                 for (i = 0; i < authsize; i++)
142                     if (fprintf(fp, "%02x", authobj[i]) < 0) {
143                         eprint("cannot write to \"%s\": %s",
144                                 fn, strerror(errno));
145                         return -1;
146                 }
147                 fprintf(fp, "\n");
148                 if (fclose(fp) < 0) {
149                         eprint("cannot close \"%s\": %s",
150                                 fn, strerror(errno));
151                         return -1;
152                 }
153         } else {
154                 eprint("cannot open \"%s\": %s",
155                         fn, strerror(errno));
156                 return -1;
157         }
158         return 0;
159 }