LCOV - code coverage report
Current view: top level - zxid - zxpasswd.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 161 243 66.3 %
Date: 2010-12-19 Functions: 4 4 100.0 %
Branches: 107 245 43.7 %

           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

Generated by: LCOV version 1.9