include base64 encoder
[pam_pcsc_cr.git] / pam_cr_setup.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 "authobj.h"
34 #include "authfile.h"
35 #include "pcsc_cr.h"
36
37 static struct _auth_chunk
38 token_key(const unsigned char *challenge, const int challengesize)
39 {
40         struct _auth_chunk ho = {0};
41         long rc;
42         int keysize = sizeof(ho.data);
43
44         if ((rc = pcsc_cr(challenge, challengesize, ho.data, &keysize))) {
45                 ho.err = pcsc_errstr(rc);
46         }
47         return ho;
48 }
49
50 static char *mynonce = NULL;
51
52 static void update_nonce(char *nonce, const int nonsize)
53 {
54         if (mynonce) {
55                 snprintf(nonce, nonsize, "%s", mynonce);
56         } else {
57                 int n = 0;
58
59                 sscanf(nonce, "%d", &n);
60                 snprintf(nonce, nonsize, "%d", n+1);
61         }
62 }
63
64 static void usage(const char * const cmd)
65 {
66         fprintf(stderr,
67                 "usage: %s [options] [username]\n"
68                 "    -h                - show this help and exit\n"
69                 "    -o backend-option - token option \"backend:key=val\"\n"
70                 "    -f template       - template for auth state filepath\n"
71                 "    -a secret | -A file-with-secret | -A -\n"
72                 "                      - 40-character hexadecimal secret\n"
73                 "    -s token-serial   - public I.D. of the token\n"
74                 "    -n nonce          - initial nonce\n"
75                 "    -l payload        - keyring unlock password\n"
76                 "    -p password       - login password\n"
77                 "    -v                - show returned data\n"
78                 , cmd);
79 }
80
81 int main(int argc, char *argv[])
82 {
83         struct _auth_obj ao;
84         int c;
85         int verbose = 0;
86         char *hsecret = NULL;
87         char *secfn = NULL;
88         char secbuf[43];
89         unsigned char bsecret[20];
90         unsigned char *secret = NULL;
91         int i;
92         char *tokenid = NULL;
93         char *userid = getlogin();
94         char *payload = NULL;
95         char *password = "";
96
97         while ((c = getopt(argc, argv, "ho:f:a:A:s:n:l:p:v")) != -1)
98             switch (c) {
99         case 'h':
100                 usage(argv[0]);
101                 exit(EXIT_SUCCESS);
102         case 'o':
103                 if (pcsc_option(optarg)) {
104                         fprintf(stderr, "Option \"%s\" bad", optarg);
105                         exit(EXIT_FAILURE);
106                 }
107                 break;
108         case 'f':
109                 authfile_template(optarg);
110                 break;
111         case 'a':
112                 if (!secfn) {
113                         hsecret = optarg;
114                 } else {
115                         fprintf(stderr, "-a and -A are mutually exclusive");
116                         exit(EXIT_FAILURE);
117                 }
118                 break;
119         case 'A':
120                 if (!hsecret) {
121                         secfn = optarg;
122                 } else {
123                         fprintf(stderr, "-A and -a are mutually exclusive");
124                         exit(EXIT_FAILURE);
125                 }
126                 break;
127         case 's':
128                 tokenid = optarg;
129                 break;
130         case 'n':
131                 mynonce = optarg;
132                 break;
133         case 'l':
134                 payload = optarg;
135                 break;
136         case 'p':
137                 password = optarg;
138                 break;
139         case 'v':
140                 verbose = 1;
141                 break;
142         default:
143                 usage(argv[0]);
144                 exit(EXIT_FAILURE);
145         }
146         if (optind == (argc - 1)) {
147                 userid = argv[optind];
148                 optind++;
149         }
150         if (optind != argc) {
151                 usage(argv[0]);
152                 exit(EXIT_FAILURE);
153         }
154         if (!userid) {
155                 fprintf(stderr, "cannot determine userid");
156                 exit(EXIT_FAILURE);
157         }
158         if (secfn) {
159                 FILE *sfp;
160                 char *p;
161
162                 if (!strcmp(secfn, "-")) sfp = stdin;
163                 else sfp = fopen(secfn, "r");
164                 if (!sfp) {
165                         fprintf(stderr, "cannot open \"%s\": %s",
166                                 secfn, strerror(errno));
167                         exit(EXIT_FAILURE);
168                 }
169                 if (!fgets(secbuf, sizeof(secbuf), sfp)) {
170                         fprintf(stderr, "cannot read \"%s\": %s",
171                                 secfn, strerror(errno));
172                         exit(EXIT_FAILURE);
173                 }
174                 for (p = secbuf + strlen(secbuf) - 1;
175                         *p == '\n' || *p == '\r'; p--) *p = '\n';
176
177                 fclose(sfp);
178                 hsecret = secbuf;
179         }
180         if (hsecret) {
181                 if (strlen(hsecret) != 40) {
182                         fprintf(stderr,
183                                 "secret wrong, must be exactly 40 chars\n");
184                         exit(EXIT_FAILURE);
185                 }
186                 if (strspn(hsecret, "0123456789abcdefABCDEF") != 40) {
187                         fprintf(stderr,
188                                 "secret wrong, must be hexadecimal string\n");
189                         exit(EXIT_FAILURE);
190                 }
191                 for (i = 0; i < 20; i++)
192                         sscanf(hsecret + i * 2, "%2hhx", &bsecret[i]);
193                 secret = bsecret;
194         }
195         ao = authfile(tokenid, userid, password, update_nonce,
196                         secret, secret ? sizeof(bsecret) : 0,
197                         (unsigned char *)payload, payload ? strlen(payload) : 0,
198                         token_key);
199         memset(bsecret, 0, sizeof(bsecret));
200         if (ao.err) {
201                 fprintf(stderr, "%s\n", ao.err);
202                 exit(EXIT_FAILURE);
203         } else if (verbose) {
204                 printf("userid : \"%.*s\"\n", ao.datasize, ao.data);
205                 printf("payload: \"%.*s\"\n", ao.paylsize, ao.payload);
206         }
207         if (ao.buffer) free(ao.buffer);
208         return 0;
209 }