Branch data Line data Source code
1 : : /* zxpasswd.c - Password creation and user management tool
2 : : * Copyright (c) 2009-2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 : : * This is confidential unpublished proprietary source code of the author.
4 : : * NO WARRANTY, not even implied warranties. Contains trade secrets.
5 : : * Distribution prohibited unless authorized in writing.
6 : : * Licensed under Apache License 2.0, see file COPYING.
7 : : * $Id: zxpasswd.c,v 1.6 2010-01-08 02:10:09 sampo Exp $
8 : : *
9 : : * 18.10.2009, created --Sampo
10 : : * 14.11.2009, added yubikey support --Sampo
11 : : * 16.9.2010, added support for traditional Unix crypt(3) hashed passwords --Sampo
12 : : *
13 : : * See also: http://www.users.zetnet.co.uk/hopwood/crypto/scan/ph.html
14 : : * http://www.usenix.org/events/usenix99/provos/provos_html/index.html
15 : : * http://www.koders.com/c/fid18C2933FE8729E3DBC6E9B1DEB65D282560D4B14.aspx?s=md5
16 : : * zxid_pw_authn() in zxiduser.c
17 : : * phd/sampo-idp-disco-encfs-kbdtok-2009.pd
18 : : */
19 : :
20 : : #include "platform.h" /* for dirent.h */
21 : :
22 : : #include <string.h>
23 : : #include <stdio.h>
24 : : #include <stdlib.h>
25 : : #include <errno.h>
26 : : #include <sys/types.h>
27 : : #include <signal.h>
28 : : #include <fcntl.h>
29 : : #ifndef MINGW
30 : : #include <sys/stat.h>
31 : : #endif
32 : :
33 : : #ifdef USE_OPENSSL
34 : : #include <openssl/des.h>
35 : : #endif
36 : :
37 : : #include "errmac.h"
38 : : #include "zx.h"
39 : : #include "zxid.h"
40 : : #include "zxidutil.h"
41 : : #include "zxidconf.h"
42 : : #include "c/zxidvers.h"
43 : : #include "c/zx-ns.h"
44 : : #include "yubikey.h"
45 : :
46 : : #define UDIR "/var/zxid/idpuid"
47 : :
48 : : char* help =
49 : : "zxpasswd - Password creation and user management tool R" ZXID_REL "\n\
50 : : Copyright (c) 2009-2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.\n\
51 : : NO WARRANTY, not even implied warranties. Licensed under Apache License v2.0\n\
52 : : See http://www.apache.org/licenses/LICENSE-2.0\n\
53 : : Send well researched bug reports to the author. Home: zxid.org\n\
54 : : \n\
55 : : Usage: zxpasswd [options] user [udir] <passwd # Set user's password\n\
56 : : zxpasswd [options] -c user [udir] <passwd # Create user and set password\n\
57 : : zxpasswd [options] -a user [udir] <passwd # Authenticate as user using pw\n\
58 : : zxpasswd [options] -l [user [udir]] # List information about user\n\
59 : : [udir] Specify zxididp user directory. Default " UDIR "\n\
60 : : -c Create user\n\
61 : : -at 'attr: val' Append attribute(s) to .bs/.at\n\
62 : : -s exist_uid Symlink user to an existing user (e.g. yubikey alias)\n\
63 : : -a Authenticate as user. exit(2) value 0 means success\n\
64 : : -l List user info. If no user is specified, lists all users.\n\
65 : : -t N Choose password hash type: 0=plain, 1=MD5 (default), y=yubikey\n\
66 : : -v Verbose messages.\n\
67 : : -q Be extra quiet.\n\
68 : : -d Turn on debugging.\n\
69 : : -h This help message\n\
70 : : -- End of options\n\
71 : : \n\
72 : : For Yubikey (yubico.com) authentication (-a), supply the yubikey ticket\n\
73 : : as user and omit the password. For creating account or changing password,\n\
74 : : use -t y to indicate that you pass yubikey AES128 shared key in hex as password.\n";
75 : :
76 : : int verbose = 1;
77 : : int create = 0;
78 : : int an = 0;
79 : : int list = 0;
80 : : char* hash_type = "1";
81 : : char* udir = "/var/zxid/idpuid/";
82 : : char* user = 0;
83 : : char* symlink_user = 0;
84 : : char* at = 0;
85 : : char pw[1024];
86 : : char userdir[4096];
87 : : char buf[4096];
88 : : struct zx_ctx ctx;
89 : :
90 : : /* Called by: main x8, zxcall_main, zxcot_main, zxdecode_main */
91 : : static void opt(int* argc, char*** argv, char*** env)
92 : 15 : {
93 [ + + ]: 15 : if (*argc <= 1) {
94 : 1 : fprintf(stderr, "Too few arguments (%d). Must specify at least user name.\n", *argc);
95 : 1 : goto help;
96 : : }
97 : :
98 : : while (1) {
99 : 38 : ++(*argv); --(*argc);
100 : :
101 [ + + + + ]: 38 : if (!(*argc) || ((*argv)[0][0] != '-')) break; /* normal exit from options loop */
102 : :
103 [ + + + + : 26 : switch ((*argv)[0][1]) {
+ + + + +
+ ]
104 [ + - ]: 1 : case '-': if ((*argv)[0][2]) break;
105 : 1 : ++(*argv); --(*argc);
106 : : DD("End of options by --");
107 : 1 : goto last; /* -- ends the options */
108 : :
109 : : case 'c':
110 [ + - ]: 4 : switch ((*argv)[0][2]) {
111 : : case '\0':
112 : 4 : ++create;
113 : 4 : continue;
114 : : }
115 : 0 : break;
116 : :
117 : : case 'a':
118 [ + + - ]: 3 : switch ((*argv)[0][2]) {
119 : : case '\0':
120 : 2 : ++an;
121 : 2 : continue;
122 : : case 't':
123 : 1 : ++(*argv); --(*argc);
124 [ + - ]: 1 : if ((*argc) < 1) break;
125 : 1 : at = (*argv)[0];
126 : 1 : continue;
127 : : }
128 : 0 : break;
129 : :
130 : : case 'l':
131 [ + - ]: 4 : switch ((*argv)[0][2]) {
132 : : case '\0':
133 : 4 : ++list;
134 : 4 : continue;
135 : : #if 0
136 : : case 'i':
137 : : if (!strcmp((*argv)[0],"-license")) {
138 : : extern char* license;
139 : : fprintf(stderr, license);
140 : : exit(0);
141 : : }
142 : : break;
143 : : #endif
144 : : }
145 : 0 : break;
146 : :
147 : : case 't':
148 [ + - ]: 5 : switch ((*argv)[0][2]) {
149 : : case '\0':
150 : 5 : ++(*argv); --(*argc);
151 [ + - ]: 5 : if ((*argc) < 1) break;
152 : 5 : hash_type = (*argv)[0];
153 : 5 : continue;
154 : : }
155 : 0 : break;
156 : :
157 : : case 's':
158 [ + - ]: 1 : switch ((*argv)[0][2]) {
159 : : case '\0':
160 : 1 : ++(*argv); --(*argc);
161 [ + - ]: 1 : if ((*argc) < 1) break;
162 : 1 : symlink_user = (*argv)[0];
163 : 1 : continue;
164 : : }
165 : 0 : break;
166 : :
167 : : case 'd':
168 [ + - ]: 2 : switch ((*argv)[0][2]) {
169 : : case '\0':
170 : 2 : ++zx_debug;
171 : 2 : continue;
172 : : }
173 : 0 : break;
174 : :
175 : : case 'q':
176 [ + - ]: 1 : switch ((*argv)[0][2]) {
177 : : case '\0':
178 : 1 : verbose = 0;
179 : 1 : continue;
180 : : }
181 : 0 : break;
182 : :
183 : : case 'v':
184 [ + - ]: 4 : switch ((*argv)[0][2]) {
185 : : case '\0':
186 : 4 : ++verbose;
187 : 4 : continue;
188 : : }
189 : : break;
190 : :
191 : : }
192 : : /* fall thru means unrecognized flag */
193 [ + - ]: 1 : if (*argc)
194 : 1 : fprintf(stderr, "Unrecognized flag `%s'\n", (*argv)[0]);
195 : 4 : help:
196 [ + + ]: 4 : if (verbose>1) {
197 : 1 : printf(help);
198 : 1 : exit(0);
199 : : }
200 : 3 : fprintf(stderr, help);
201 : : /*fprintf(stderr, "version=0x%06x rel(%s)\n", zxid_version(), zxid_version_str());*/
202 : 3 : exit(3);
203 : 24 : }
204 : 13 : last:
205 [ + + + + ]: 13 : if (!list && !*argc) {
206 : 2 : fprintf(stderr, "Too few arguments (%d). Must specify at least user name.\n", *argc);
207 : 2 : goto help;
208 : : }
209 : 11 : }
210 : :
211 : : /* Called by: main */
212 : : static int list_user(char* userdir, char* udir)
213 : 3 : {
214 : : int got;
215 : : char* at;
216 : : struct dirent* de;
217 : : DIR* dir;
218 : 3 : dir = opendir(userdir);
219 [ + + ]: 3 : if (!dir) {
220 : 1 : perror("opendir for /var/zxid/idpuid/USER userdir (or other if configured)");
221 [ + - - + ]: 1 : D("failed path(%s)", userdir);
222 : 1 : return 4;
223 : : }
224 : 2 : printf("User dir: %s\n", userdir);
225 : 2 : got = read_all(sizeof(buf), buf, "pw", 0, "%s/%s/.pw", udir, user);
226 : 2 : printf("Password hash: %s\n", buf);
227 : 2 : at = read_all_alloc(&ctx, "at", 0, 0, "%s/%s/.bs/.at", udir, user);
228 [ + - ]: 2 : if (at) printf("User attributes: %s\n", at);
229 : 2 : at = read_all_alloc(&ctx, "all at", 0, 0, "%s/.all/.bs/.at", udir, 0);
230 [ + - ]: 2 : if (at) printf("Common (.all) user attributes: %s\n", buf);
231 : :
232 : 2 : printf("User's Federated SPs\n");
233 : :
234 [ + + ]: 28 : while (de = readdir(dir))
235 [ + + + - ]: 24 : if (de->d_name[0] != '.' && de->d_name[strlen(de->d_name)-1] != '~') {
236 : 11 : got = read_all(sizeof(buf), buf, "sp at", 0, "%s/%s/.mni", userdir, de->d_name);
237 : 11 : printf("SP specific NameID: %s (%s)\n", buf, de->d_name);
238 : 11 : at = read_all_alloc(&ctx, "sp at", 0, 0, "%s/%s/.at", userdir, de->d_name);
239 [ - + ]: 11 : if (at) printf("SP specific attrib: %s (%s)\n", buf, de->d_name);
240 : : }
241 : :
242 : : /* *** TODO: .all SPs, bootstraps, discovery regs */
243 : :
244 : : DD("HERE %p", cf);
245 : 2 : closedir(dir);
246 : :
247 : 2 : return 0;
248 : : }
249 : :
250 : : /* Called by: main */
251 : : static int list_users(char* udir)
252 : 1 : {
253 : : int got;
254 : : char* at;
255 : : struct dirent* de;
256 : : DIR* dir;
257 : :
258 : 1 : dir = opendir(udir);
259 [ - + ]: 1 : if (!dir) {
260 : 0 : perror("opendir for /var/zxid/idpuid (or other if configured)");
261 [ # # # # ]: 0 : D("failed path(%s)", udir);
262 : 0 : return 1;
263 : : }
264 [ + + ]: 25 : while (de = readdir(dir))
265 [ + + + - ]: 23 : if (de->d_name[0] != '.' && de->d_name[strlen(de->d_name)-1] != '~') {
266 : 20 : got = read_all(sizeof(buf), buf, "sp at", 0, "%s/%s/.mni", userdir, de->d_name);
267 : 20 : printf("SP specific NameID: %s (%s)\n", buf, de->d_name);
268 : 20 : at = read_all_alloc(&ctx, "sp at", 0, 0, "%s/%s/.bs/.at", userdir, de->d_name);
269 [ - + ]: 20 : if (at) printf("SP specific attrib: %s (%s)\n", buf, de->d_name);
270 : : }
271 : :
272 : 1 : closedir(dir);
273 : 1 : return 0;
274 : : }
275 : :
276 : : extern char pw_basis_64[64];
277 : :
278 : : /* Called by: */
279 : : int main(int argc, char** argv, char** env)
280 : 15 : {
281 : 15 : int isyk = 0;
282 : : int got, pwgot;
283 : : char* p;
284 : : unsigned char salt[16];
285 : : unsigned char pw_hash[120];
286 : : unsigned char ch;
287 : : yubikey_token_st yktok;
288 : :
289 : 15 : strcpy(zx_instance, "\tzxpw");
290 : 15 : zx_reset_ctx(&ctx);
291 : 15 : opt(&argc, &argv, &env);
292 [ + + ]: 11 : if (argc)
293 : 10 : user = argv[0];
294 [ - + ]: 1 : else if (!list) {
295 : 0 : fprintf(stderr, "Too few arguments (%d). Specify at least user name.\n", argc);
296 : 0 : fprintf(stderr, help);
297 : : /*fprintf(stderr, "version=0x%06x rel(%s)\n", zxid_version(), zxid_version_str());*/
298 : 0 : exit(3);
299 : : }
300 : :
301 [ + + ]: 11 : if (user) {
302 [ + + ]: 10 : udir = argc>1?argv[1]:UDIR;
303 : 10 : snprintf(userdir, sizeof(userdir)-1, "%s/%s", udir, user);
304 : 10 : userdir[sizeof(userdir)-1] = 0;
305 : : }
306 [ + + ]: 11 : if (list) {
307 [ + + + - ]: 4 : if (user && user[0]) /* passing empty user results full listing */
308 : 3 : return list_user(userdir, udir);
309 : : else
310 : 1 : return list_users(udir);
311 : : }
312 : :
313 : 7 : got = strlen(user);
314 [ - + ]: 7 : if (got > 32) { /* Very long user is actually yubikey ticket */
315 : 0 : strcpy(pw, user + got - 32);
316 : 0 : user[got - 32] = 0;
317 : 0 : pwgot = 32;
318 [ # # # # ]: 0 : D("yubikey user(%s) ticket(%s)", user, pw);
319 : 0 : isyk = 1;
320 : : } else {
321 : 7 : read_all_fd(0, pw, sizeof(pw)-1, &pwgot); /* Password from stdin */
322 : : }
323 [ + - ]: 7 : if (pwgot) {
324 [ + + ]: 7 : if (pw[pwgot-1] == '\012') --pwgot;
325 [ - + ]: 7 : if (pw[pwgot-1] == '\015') --pwgot;
326 : : }
327 : 7 : pw[pwgot] = 0;
328 [ - + # # ]: 7 : D("pw(%s) len=%d", pw, pwgot);
329 : :
330 [ + + ]: 7 : if (an) {
331 : : /* See also: zxid_pw_authn() in zxiduser.c */
332 : :
333 [ - + ]: 2 : if (isyk) {
334 : 0 : snprintf(userdir, sizeof(userdir)-1, "%s/%s", udir, user);
335 : 0 : userdir[sizeof(userdir)-1] = 0;
336 : 0 : got = read_all(sizeof(buf), buf, "ykspent", 1, "%s/.ykspent/%s", userdir, pw);
337 [ # # ]: 0 : if (got) {
338 : 0 : ERR("The One Time Password has already been spent. ticket(%s%s) buf(%.*s)", user, pw, got, buf);
339 : 0 : return 5;
340 : : }
341 [ # # ]: 0 : if (!write_all_path_fmt("ykspent", sizeof(buf), buf, "%s/.ykspent/%s", userdir, pw, "1"))
342 : 0 : return 1;
343 : :
344 : 0 : got = read_all(sizeof(buf), buf, "ykaes", 1, "%s/%s/.yk", udir, user);
345 [ # # # # ]: 0 : D("buf (%s) got=%d", buf, got);
346 [ # # ]: 0 : if (got < 32) {
347 : 0 : ERR("User's %s/.yk file must contain aes128 key as 32 hexadecimal characters. Too few characters %d ticket(%s)", user, got, pw);
348 : 0 : return 6;
349 : : }
350 [ # # ]: 0 : if (got > 32) {
351 : 0 : INFO("User's %s/.yk file must contain aes128 key as 32 hexadecimal characters. Too many characters %d ticket(%s). Truncating.", user, got, pw);
352 : 0 : got = 32;
353 : 0 : buf[got] = 0;
354 : : }
355 : 0 : zx_hexdec(buf, buf, got, hex_trans);
356 : 0 : ZERO(&yktok, sizeof(yktok));
357 : 0 : zx_hexdec((void *)&yktok, pw, pwgot, ykmodhex_trans);
358 : 0 : yubikey_aes_decrypt((void *)&yktok, (unsigned char*)buf);
359 [ # # # # ]: 0 : D("internal uid %02x %02x %02x %02x %02x %02x counter=%d 0x%x timestamp=%d (hi=%x lo=%x) use=%d 0x%x rnd=0x%x crc=0x%x", yktok.uid[0], yktok.uid[1], yktok.uid[2], yktok.uid[3], yktok.uid[4], yktok.uid[5], yktok.ctr, yktok.ctr, (yktok.tstph << 16) | yktok.tstpl, yktok.tstph, yktok.tstpl, yktok.use, yktok.use, yktok.rnd, yktok.crc);
360 : :
361 [ # # ]: 0 : if (yubikey_crc_ok_p((unsigned char*)&yktok)) {
362 [ # # # # ]: 0 : D("yubikey ticket validates ok %d", 0);
363 [ # # ]: 0 : if (verbose) printf("yubikey ticket validates ok\n");
364 : 0 : return 0;
365 : : }
366 [ # # # # ]: 0 : D("yubikey ticket validation failure %d", 0);
367 [ # # ]: 0 : if (verbose) printf("yubikey ticket validation failure\n");
368 : 0 : return 7;
369 : : }
370 : 2 : got = read_all(sizeof(buf), buf, "pw", 1, "%s/%s/.pw", udir, user);
371 [ + - ]: 2 : if (got>0) {
372 [ - + ]: 2 : if (buf[got-1] == '\012') --got;
373 [ - + ]: 2 : if (buf[got-1] == '\015') --got;
374 : : }
375 : 2 : buf[got] = 0;
376 [ - + # # ]: 2 : D("buf (%s) got=%d", buf, got);
377 [ + - ]: 2 : if (!memcmp(buf, "$1$", sizeof("$1$")-1)) {
378 : 2 : zx_md5_crypt(pw, buf, (char*)pw_hash);
379 [ - + # # ]: 2 : D("pw_hash(%s)", pw_hash);
380 [ + + ]: 2 : got = strcmp(buf, (char*)pw_hash)?7:0;
381 [ + - + + ]: 2 : if (verbose) printf("md5_crypt hash ($1$) validate: %s\n", got?"fail":"ok");
382 : 2 : return got;
383 : : }
384 : : #ifdef USE_OPENSSL
385 [ # # ]: 0 : if (!memcmp(buf, "$c$", sizeof("$c$")-1)) {
386 : 0 : DES_fcrypt(pw, buf+3, (char*)pw_hash);
387 [ # # # # ]: 0 : D("pw_hash(%s)", pw_hash);
388 [ # # ]: 0 : got = strcmp(buf+3, (char*)pw_hash)?7:0;
389 [ # # # # ]: 0 : if (verbose) printf("Unix DES_crypt hash ($c$) validate: %s\n", got?"fail":"ok");
390 : 0 : return got;
391 : : }
392 : : #endif
393 [ # # # # ]: 0 : if (ONE_OF_2(buf[0], '$', '_')) {
394 : 0 : fprintf(stderr, "Unsupported password hash algorithm (%s).\n", buf);
395 : 0 : return 8;
396 : : }
397 [ # # # # ]: 0 : D("Assume plain text password %d", 0);
398 [ # # ]: 0 : got = strcmp(buf, pw)?7:0;
399 [ # # # # ]: 0 : if (verbose) printf("plaintext password validate: %s\n", got?"fail":"ok");
400 : 0 : return got;
401 : : }
402 : :
403 : : /* Create and other user management functions */
404 : :
405 [ + + ]: 5 : if (create) {
406 [ + + ]: 4 : if (MKDIR(userdir, 0770) == -1) {
407 : 1 : ERR("User already exists %s", userdir);
408 : 1 : return 3;
409 : : }
410 : 3 : snprintf(buf, sizeof(buf)-1, "%s/.bs", userdir);
411 : 3 : buf[sizeof(buf)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
412 : 3 : MKDIR(buf, 0770);
413 : 3 : snprintf(buf, sizeof(buf)-1, "%s/.ps", userdir);
414 : 3 : buf[sizeof(buf)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
415 : 3 : MKDIR(buf, 0770);
416 : 3 : snprintf(buf, sizeof(buf)-1, "%s/.ykspent", userdir);
417 : 3 : buf[sizeof(buf)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
418 : 3 : MKDIR(buf, 0770);
419 : : }
420 [ - + ]: 4 : if (symlink_user) {
421 : 0 : snprintf(buf, sizeof(buf), "%s/%s", udir, symlink_user);
422 : 0 : buf[sizeof(buf)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
423 : : #ifdef MINGW
424 : : ERR("Symlink not implemented on Win32. from(%s) (-s %s) path(%s)", buf, symlink_user, userdir);
425 : : #else
426 [ # # # # ]: 0 : D("Symlink from(%s) (-s %s) path(%s)", buf, symlink_user, userdir);
427 [ # # ]: 0 : if (symlink(buf, userdir) == -1) {
428 : 0 : perror("symlink user alias");
429 : 0 : return 2;
430 : : }
431 : : #endif
432 : : }
433 : :
434 [ + + ]: 4 : if (at) {
435 [ + + ]: 30 : for (p = at; *p; ++p)
436 [ + + ]: 29 : if (*p == '$') *p = '\n';
437 : 1 : snprintf(buf, sizeof(buf)-1, "%s/.bs/.at", userdir);
438 [ - + # # ]: 1 : D("Appending to(%s) attributes(%s)", buf, at);
439 : 1 : buf[sizeof(buf)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
440 : 1 : write2_or_append_lock_c_path(buf, strlen(at), at, 0, 0, "append .bs/.at", SEEK_END, O_APPEND);
441 : : }
442 : :
443 : : /* $1$$6C2jXXYmjnyAkfWXmnCSf0 */
444 : : /* $y$$6012cab434c66ab87d43d4babe463331 */
445 : :
446 [ - + ]: 4 : if (!strcmp(hash_type, "0")) {
447 : 0 : strcpy((char*)pw_hash, pw);
448 [ # # # # ]: 0 : D("pw0(%s) len=%d", pw, strlen(pw));
449 : : #ifdef USE_OPENSSL
450 [ - + ]: 4 : } else if (!strcmp(hash_type, "c")) { /* Unix crypt(3) hash */
451 : 0 : zx_rand((char*)salt, 2);
452 : 0 : salt[0] = pw_basis_64[salt[0] & 0x3f];
453 : 0 : salt[1] = pw_basis_64[salt[1] & 0x3f];
454 : 0 : strcpy((char*)pw_hash, "$c$"); /* Our custom magic to identify Unix crypt(3) hash */
455 : 0 : DES_fcrypt(pw, (char*)salt, (char*)pw_hash+3);
456 : : #endif
457 [ - + ]: 4 : } else if (!strcmp(hash_type, "1")) { /* MD5 hash */
458 [ # # ]: 0 : for (got = 0; got < 8; ++got) {
459 : 0 : zx_rand((char*)&ch, 1);
460 : 0 : salt[got] = pw_basis_64[ch & 0x3f];
461 : : }
462 : 0 : salt[8] = 0;
463 [ # # # # ]: 0 : D("salt(%s)", salt);
464 : 0 : zx_md5_crypt(pw, (char*)salt, (char*)pw_hash);
465 [ # # # # ]: 0 : D("pw_hash(%s)", pw_hash);
466 [ + + ]: 4 : } else if (!strcmp(hash_type, "y")) {
467 [ - + # # ]: 3 : D("Provisioning yubikey aes(%s) in %s/%s/.yk", pw, udir, user);
468 [ - + ]: 3 : if (!write_all_path_fmt("set yk", sizeof(buf), buf, "%s/%s/.yk", udir, user, "%s", pw))
469 : 0 : return 1;
470 : 3 : snprintf(userdir, sizeof(userdir)-1, "%s/%s/.ykspent", udir, user);
471 : 3 : userdir[sizeof(userdir)-1] = 0;
472 : 3 : MKDIR(userdir, 0770);
473 : 3 : return 0;
474 : : } else {
475 : 1 : fprintf(stderr, "Unsupported password hash algorithm (%s).\n", hash_type);
476 : : }
477 : :
478 : : DD("pw_hash(%s) len=%d", pw_hash, strlen(pw_hash));
479 [ - + ]: 1 : if (!write_all_path_fmt("set pw", sizeof(buf), buf, "%s/%s/.pw", udir, user, "%s", pw_hash))
480 : 0 : return 1;
481 : 1 : return 0;
482 : : }
483 : :
484 : : /* EOF -- zxdecode.c */
485 : :
486 : : #if 0
487 : :
488 : : We choose $c$sshhhhhhhhhh representation for plain Unix crypt(3) hashed passwords.
489 : :
490 : : man crypt
491 : :
492 : : If salt is a character string starting with the characters "$id$" followed
493 : : by a string terminated by "$":
494 : :
495 : : $id$salt$encrypted
496 : :
497 : : then instead of using the DES machine, id identifies the encryption
498 : : method used and this then determines how the rest of the password string
499 : : is interpreted. The following values of id are supported:
500 : :
501 : : ID | Method
502 : : ---------------------------------------------------------
503 : : 1 | MD5
504 : : 2a | Blowfish (not in mainline glibc; added in some
505 : : | Linux distributions)
506 : : 5 | SHA-256 (since glibc 2.7)
507 : : 6 | SHA-512 (since glibc 2.7)
508 : :
509 : : So $5$salt$encrypted is an SHA-256 encoded password and $6$salt$encrypted
510 : : is an SHA-512 encoded one.
511 : :
512 : : "salt" stands for the up to 16 characters following "$id$" in the salt.
513 : : The encrypted part of the password string is the actual computed
514 : : password. The size of this string is fixed:
515 : :
516 : : MD5 | 22 characters
517 : : SHA-256 | 43 characters
518 : : SHA-512 | 86 characters
519 : :
520 : : The characters in "salt" and "encrypted" are drawn from the
521 : : set [a-zA-Z0-9./]. In the SHA implementation the entire key is significant
522 : : (instead of only the first 8 bytes in MD5).
523 : :
524 : :
525 : : See also man DES_fcrypt
526 : :
527 : : Personalizing yubikeys 2009: get and compile libyubikey-1.5 and ykpers-1.0
528 : :
529 : : ykpersonalize -y -v -ofixed=refucenikj -a6012cad434c66ab87d43d4babe463231
530 : : ykdebug 6012cad434c66ab87d43d4babe463231 refucenikjdbrgulutnjhurchlkcckdkergfitcebf
531 : :
532 : : Here -ofixed specifies the "username" for purposes of /var/zxid/idpuid and
533 : : -a specifies the AES128 key that will be put in .pw file as follows:
534 : :
535 : : y5e0w.RTowQpk
536 : : ldapinlisboa
537 : :
538 : : /var/lib/trac/conf/trac.htpasswd
539 : : sampo:y5e0w.RTowQpk
540 : :
541 : : #endif
|