UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include <openssl/sha.h> 34 #if defined(__sun) && defined(__SunOS_5_10) 35 #include <sha2.h> 36 #define SHA256_Init SHA256Init 37 #define SHA256_Update SHA256Update 38 #define SHA256_Final SHA256Final 39 #endif 40 41 #include "../util/atomic.h" 42 #include "../util/util.h" 43 44 #include <cx/hash_map.h> 45 46 #include "keyfile_auth.h" 47 48 Keyfile* keyfile_new(CxAllocator *a) { 49 Keyfile *keyfile = cxCalloc(a, 1, sizeof(Keyfile)); 50 if(!keyfile) { 51 return NULL; 52 } 53 keyfile->authdb.get_user = keyfile_get_user; 54 keyfile->authdb.use_cache = 0; 55 keyfile->users = cxHashMapCreate(a, CX_STORE_POINTERS, 16); 56 return keyfile; 57 } 58 59 int keyfile_add_user( 60 Keyfile *keyfile, 61 cxmutstr name, 62 enum KeyfileHashType hash_type, 63 cxmutstr hash, 64 cxmutstr *groups, 65 size_t ngroups) 66 { 67 const CxAllocator *a = keyfile->users->allocator; 68 69 if(hash.length < 12) { 70 // hash too short 71 // TODO: log 72 return -1; 73 } 74 75 KeyfileUser *user = cxMalloc(a, sizeof(KeyfileUser)); 76 user->user.name = cx_strdup_a(a, cx_strcast(name)).ptr; 77 user->user.uid = -1; 78 user->user.gid = -1; 79 user->user.verify_password = keyfile_user_verify_password; 80 user->user.check_group = keyfile_user_check_group; 81 user->user.free = keyfile_user_free; 82 83 user->hash_type = hash_type; 84 user->hash = cxMalloc(a, hash.length + 1); 85 86 if(!user->user.name || !user->hash) { 87 return -1; 88 } 89 90 user->hashlen = util_base64decode(hash.ptr, hash.length, user->hash); 91 92 if(ngroups > 0) { 93 user->groups = cxCalloc(a, ngroups, sizeof(cxmutstr)); 94 if(!user->groups) { 95 return -1; 96 } 97 for(int i=0;i<ngroups;i++) { 98 user->groups[i] = cx_strdup_a(a, cx_strcast(groups[i])); 99 } 100 101 } else { 102 user->groups = NULL; 103 } 104 105 // add to keyfile 106 return cxMapPut(keyfile->users, cx_hash_key(name.ptr, name.length), user); 107 } 108 109 // authdb functions 110 111 User* keyfile_get_user(AuthDB *db, Session *sn, Request *rq, const char *user) { 112 Keyfile *keyfile = (Keyfile*)db; 113 return cxMapGet(keyfile->users, cx_hash_key_str(user)); 114 } 115 116 int keyfile_user_verify_password(User *user, const char *password) { 117 KeyfileUser *usr = (KeyfileUser*)user; 118 return ssha_verify(usr, password); 119 } 120 121 int keyfile_user_check_group(User *user, const char *group) { 122 KeyfileUser *usr = (KeyfileUser*)user; 123 cxstring grp = cx_str(group); 124 for(int i=0;i<usr->numgroups;i++) { 125 if(!cx_strcmp(cx_strcast(usr->groups[i]), grp)) { 126 return 1; 127 } 128 } 129 return 0; 130 } 131 132 void keyfile_user_free(User *user) { 133 // don't free, it will be freed by keyfile_unref 134 } 135 136 137 int ssha_verify(KeyfileUser *user, const char *password) { 138 /* 139 * SSHA: SHA(pw + salt) + salt 140 * user->hash is already base64 decoded 141 */ 142 143 size_t hlen; 144 switch(user->hash_type) { 145 case KEYFILE_SSHA: hlen = 20; break; 146 case KEYFILE_SSHA256: hlen = 32; break; 147 case KEYFILE_SSHA512: hlen = 64; break; 148 } 149 150 char *salt = user->hash + hlen; 151 size_t saltlen = user->hashlen - hlen; 152 153 size_t pwlen = strlen(password); 154 155 unsigned char pwhash[64]; 156 switch(user->hash_type) { 157 case KEYFILE_SSHA: { 158 SHA_CTX ctx; 159 SHA1_Init(&ctx); 160 SHA1_Update(&ctx, password, pwlen); 161 SHA1_Update(&ctx, salt, saltlen); 162 SHA1_Final(pwhash, &ctx); 163 break; 164 } 165 case KEYFILE_SSHA256: { 166 SHA256_CTX ctx; 167 SHA256_Init(&ctx); 168 SHA256_Update(&ctx, password, pwlen); 169 SHA256_Update(&ctx, salt, saltlen); 170 SHA256_Final(pwhash, &ctx); 171 break; 172 } 173 case KEYFILE_SSHA512: { 174 SHA512_CTX ctx; 175 SHA512_Init(&ctx); 176 SHA512_Update(&ctx, password, pwlen); 177 SHA512_Update(&ctx, salt, saltlen); 178 SHA512_Final(pwhash, &ctx); 179 break; 180 } 181 } 182 183 if(!memcmp(user->hash, pwhash, hlen)) { 184 return 1; 185 } else { 186 return 0; 187 } 188 } 189 190