add manpage for the module
[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                 "    -n nonce          - initial nonce\n"
74                 "    -l payload        - keyring unlock password\n"
75                 "    -p password       - login password\n"
76                 "    -v                - show returned data\n"
77                 , cmd);
78 }
79
80 int main(int argc, char *argv[])
81 {
82         struct _auth_obj ao;
83         int c;
84         int verbose = 0;
85         char *hsecret = NULL;
86         char *secfn = NULL;
87         char secbuf[43];
88         unsigned char bsecret[20];
89         unsigned char *secret = NULL;
90         int i;
91         char *userid = getlogin();
92         char *payload = NULL;
93         char *password = "";
94
95         while ((c = getopt(argc, argv, "ho:f:a:A:n:l:p:v")) != -1)
96             switch (c) {
97         case 'h':
98                 usage(argv[0]);
99                 exit(EXIT_SUCCESS);
100         case 'o':
101                 if (pcsc_option(optarg)) {
102                         fprintf(stderr, "Option \"%s\" bad", optarg);
103                         exit(EXIT_FAILURE);
104                 }
105                 break;
106         case 'f':
107                 authfile_template(optarg);
108                 break;
109         case 'a':
110                 if (!secfn) {
111                         hsecret = optarg;
112                 } else {
113                         fprintf(stderr, "-a and -A are mutually exclusive");
114                         exit(EXIT_FAILURE);
115                 }
116                 break;
117         case 'A':
118                 if (!hsecret) {
119                         secfn = optarg;
120                 } else {
121                         fprintf(stderr, "-A and -a are mutually exclusive");
122                         exit(EXIT_FAILURE);
123                 }
124                 break;
125         case 'n':
126                 mynonce = optarg;
127                 break;
128         case 'l':
129                 payload = optarg;
130                 break;
131         case 'p':
132                 password = optarg;
133                 break;
134         case 'v':
135                 verbose = 1;
136                 break;
137         default:
138                 usage(argv[0]);
139                 exit(EXIT_FAILURE);
140         }
141         if (optind == (argc - 1)) {
142                 userid = argv[optind];
143                 optind++;
144         }
145         if (optind != argc) {
146                 usage(argv[0]);
147                 exit(EXIT_FAILURE);
148         }
149         if (!userid) {
150                 fprintf(stderr, "cannot determine userid");
151                 exit(EXIT_FAILURE);
152         }
153         if (secfn) {
154                 FILE *sfp;
155                 char *p;
156
157                 if (!strcmp(secfn, "-")) sfp = stdin;
158                 else sfp = fopen(secfn, "r");
159                 if (!sfp) {
160                         fprintf(stderr, "cannot open \"%s\": %s",
161                                 secfn, strerror(errno));
162                         exit(EXIT_FAILURE);
163                 }
164                 if (!fgets(secbuf, sizeof(secbuf), sfp)) {
165                         fprintf(stderr, "cannot read \"%s\": %s",
166                                 secfn, strerror(errno));
167                         exit(EXIT_FAILURE);
168                 }
169                 for (p = secbuf + strlen(secbuf) - 1;
170                         *p == '\n' || *p == '\r'; p--) *p = '\n';
171
172                 fclose(sfp);
173                 hsecret = secbuf;
174         }
175         if (hsecret) {
176                 if (strlen(hsecret) != 40) {
177                         fprintf(stderr,
178                                 "secret wrong, must be exactly 40 chars\n");
179                         exit(EXIT_FAILURE);
180                 }
181                 if (strspn(hsecret, "0123456789abcdefABCDEF") != 40) {
182                         fprintf(stderr,
183                                 "secret wrong, must be hexadecimal string\n");
184                         exit(EXIT_FAILURE);
185                 }
186                 for (i = 0; i < 20; i++)
187                         sscanf(hsecret + i * 2, "%2hhx", &bsecret[i]);
188                 secret = bsecret;
189         }
190         ao = authfile(userid, password, update_nonce,
191                         secret, secret ? sizeof(bsecret) : 0,
192                         (unsigned char *)payload, payload ? strlen(payload) : 0,
193                         token_key);
194         memset(bsecret, 0, sizeof(bsecret));
195         if (ao.err) {
196                 fprintf(stderr, "%s\n", ao.err);
197                 exit(EXIT_FAILURE);
198         } else if (verbose) {
199                 printf("version: %s\n", VERSION);
200                 printf("userid : \"%.*s\"\n", ao.datasize, ao.data);
201                 printf("payload: \"%.*s\"\n", ao.paylsize, ao.payload);
202         }
203         if (ao.buffer) free(ao.buffer);
204         return 0;
205 }