]> err.no Git - yubikey-personalization.old/blob - ykpersonalize.c
Merge tag 'v1.6.4'
[yubikey-personalization.old] / ykpersonalize.c
1 /* -*- mode:C; c-file-style: "bsd" -*- */
2 /*
3  * Copyright (c) 2008-2012 Yubico AB
4  * Copyright (c) 2010 Tollef Fog Heen <tfheen@err.no>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *
14  *     * Redistributions in binary form must reproduce the above
15  *       copyright notice, this list of conditions and the following
16  *       disclaimer in the documentation and/or other materials provided
17  *       with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <stddef.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <errno.h>
38
39 #include <ykpers.h>
40 #include <ykdef.h>
41
42 #include "ykpers-args.h"
43
44 static int reader(char *buf, size_t count, void *stream)
45 {
46         return (int)fread(buf, 1, count, (FILE *)stream);
47 }
48 static int writer(const char *buf, size_t count, void *stream)
49 {
50         return (int)fwrite(buf, 1, count, (FILE *)stream);
51 }
52
53 int main(int argc, char **argv)
54 {
55         FILE *inf = NULL; const char *infname = NULL;
56         FILE *outf = NULL; const char *outfname = NULL;
57         bool verbose = false;
58         bool aesviahash = false;
59         bool use_access_code = false;
60         unsigned char access_code[256];
61         YK_KEY *yk = 0;
62         YKP_CONFIG *cfg = ykp_create_config();
63         YK_STATUS *st = ykds_alloc();
64         bool autocommit = false;
65
66         /* Options */
67         char *salt = NULL;
68
69         bool error = false;
70         int exit_code = 0;
71
72         ykp_errno = 0;
73         yk_errno = 0;
74
75         /* Assume the worst */
76         error = true;
77
78         if (!yk_init()) {
79                 exit_code = 1;
80                 goto err;
81         }
82
83         if (argc == 2 && strcmp (argv[1], "-h") == 0) {
84                 fputs(usage, stderr);
85                 goto err;
86         }
87
88         if (!(yk = yk_open_first_key())) {
89                 exit_code = 1;
90                 goto err;
91         }
92
93         if (!yk_get_status(yk, st)) {
94                 exit_code = 1;
95                 goto err;
96         }
97
98         printf("Firmware version %d.%d.%d Touch level %d ",
99                ykds_version_major(st),
100                ykds_version_minor(st),
101                ykds_version_build(st),
102                ykds_touch_level(st));
103         if (ykds_pgm_seq(st))
104                 printf("Program sequence %d\n",
105                        ykds_pgm_seq(st));
106         else
107                 printf("Unconfigured\n");
108
109         if (!(yk_check_firmware_version(yk))) {
110                 if (yk_errno == YK_EFIRMWARE) {
111                         printf("Unsupported firmware revision - some "
112                                "features may not be available\n"
113                                "Please see \n"
114                                "http://code.google.com/p/yubikey-personalization/wiki/Compatibility\n"
115                                "for more information.\n");
116                 } else {
117                         goto err;
118                 }
119         }
120
121         if (!ykp_configure_for(cfg, 1, st))
122                 goto err;
123
124         /* Parse all arguments in a testable way */
125         if (! args_to_config(argc, argv, cfg, yk,
126                              &infname, &outfname,
127                              &autocommit, salt,
128                              st, &verbose,
129                              access_code, &use_access_code,
130                              &aesviahash,
131                              &exit_code)) {
132                 goto err;
133         }
134
135         if (verbose && (ykds_version_major(st) > 2 ||
136                         (ykds_version_major(st) == 2 &&
137                          ykds_version_minor(st) >= 2))) {
138                 unsigned int serial;
139                 if (! yk_get_serial(yk, 0, 0, &serial)) {
140                         printf ("Failed to read serial number (serial-api-visible disabled?).\n");
141
142                 } else {
143                         printf ("Serial number : %i\n", serial);
144                 }
145         }
146
147         printf ("\n");
148
149         if (infname) {
150                 if (strcmp(infname, "-") == 0)
151                         inf = stdin;
152                 else
153                         inf = fopen(infname, "r");
154                 if (inf == NULL) {
155                         fprintf(stderr,
156                                 "Couldn't open %s for reading: %s\n",
157                                 infname,
158                                 strerror(errno));
159                         exit_code = 1;
160                         goto err;
161                 }
162         }
163
164         if (outfname) {
165                 if (strcmp(outfname, "-") == 0)
166                         outf = stdout;
167                 else
168                         outf = fopen(outfname, "w");
169                 if (outf == NULL) {
170                         fprintf(stderr,
171                                 "Couldn't open %s for writing: %s\n",
172                                 outfname,
173                                 strerror(errno));
174                         exit(1);
175                 }
176         }
177
178         if (inf) {
179                 if (!ykp_read_config(cfg, reader, inf))
180                         goto err;
181         } else if (! aesviahash) {
182                 char passphrasebuf[256]; size_t passphraselen;
183                 fprintf(stderr, "Passphrase to create AES key: ");
184                 fflush(stderr);
185                 fgets(passphrasebuf, sizeof(passphrasebuf), stdin);
186                 passphraselen = strlen(passphrasebuf);
187                 if (passphrasebuf[passphraselen - 1] == '\n')
188                         passphrasebuf[passphraselen - 1] = '\0';
189                 if (!ykp_AES_key_from_passphrase(cfg,
190                                                  passphrasebuf, salt))
191                         goto err;
192         }
193
194         if (outf) {
195                 if (!ykp_write_config(cfg, writer, outf))
196                         goto err;
197         } else {
198                 char commitbuf[256]; size_t commitlen;
199
200                 fprintf(stderr, "Configuration data to be written to key configuration %d:\n\n", ykp_config_num(cfg));
201                 ykp_write_config(cfg, writer, stderr);
202                 fprintf(stderr, "\nCommit? (y/n) [n]: ");
203                 if (autocommit) {
204                         strcpy(commitbuf, "yes");
205                         puts(commitbuf);
206                 } else {
207                         fgets(commitbuf, sizeof(commitbuf), stdin);
208                 }
209                 commitlen = strlen(commitbuf);
210                 if (commitbuf[commitlen - 1] == '\n')
211                         commitbuf[commitlen - 1] = '\0';
212                 if (strcmp(commitbuf, "y") == 0
213                     || strcmp(commitbuf, "yes") == 0) {
214                         exit_code = 2;
215
216                         if (verbose)
217                                 printf("Attempting to write configuration to the yubikey...");
218                         if (!yk_write_config(yk,
219                                              ykp_core_config(cfg), ykp_config_num(cfg),
220                                              use_access_code ? access_code : NULL)) {
221                                 if (verbose)
222                                         printf(" failure\n");
223                                 goto err;
224                         }
225
226                         if (verbose)
227                                 printf(" success\n");
228                 }
229         }
230
231         exit_code = 0;
232         error = false;
233
234 err:
235         if (error) {
236                 report_yk_error();
237         }
238
239         if (salt)
240                 free(salt);
241         if (st)
242                 free(st);
243         if (inf)
244                 fclose(inf);
245         if (outf)
246                 fclose(outf);
247
248         if (yk && !yk_close_key(yk)) {
249                 report_yk_error();
250                 exit_code = 2;
251         }
252
253         if (!yk_release()) {
254                 report_yk_error();
255                 exit_code = 2;
256         }
257
258         if (cfg)
259                 ykp_free_config(cfg);
260
261         exit(exit_code);
262 }