1/* 2 Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com> 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13*/ 14 15#ifdef HAVE_CONFIG_H 16#include "config.h" 17#endif /* HAVE_CONFIG_H */ 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22#include <errno.h> 23#include <inttypes.h> 24#include <sys/types.h> 25#include <pwd.h> 26#include <grp.h> 27 28#include <atalk/logger.h> 29#include <atalk/afp.h> 30#include <atalk/uuid.h> 31#include <atalk/util.h> 32 33#include "aclldap.h" 34#include "cache.h" 35 36char *uuidtype[] = {"USER", "GROUP", "LOCAL"}; 37 38/******************************************************** 39 * Public helper function 40 ********************************************************/ 41 42static unsigned char local_group_uuid[] = {0xab, 0xcd, 0xef, 43 0xab, 0xcd, 0xef, 44 0xab, 0xcd, 0xef, 45 0xab, 0xcd, 0xef}; 46 47static unsigned char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 48 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa}; 49 50void localuuid_from_id(unsigned char *buf, uuidtype_t type, unsigned int id) 51{ 52 uint32_t tmp; 53 54 switch (type) { 55 case UUID_GROUP: 56 memcpy(buf, local_group_uuid, 12); 57 break; 58 case UUID_USER: 59 default: 60 memcpy(buf, local_user_uuid, 12); 61 break; 62 } 63 64 tmp = htonl(id); 65 memcpy(buf + 12, &tmp, 4); 66 67 return; 68} 69 70/* 71 * convert ascii string that can include dashes to binary uuid. 72 * caller must provide a buffer. 73 */ 74void uuid_string2bin( const char *uuidstring, uuidp_t uuid) { 75 int nibble = 1; 76 int i = 0; 77 unsigned char c, val = 0; 78 79 while (*uuidstring) { 80 c = *uuidstring; 81 if (c == '-') { 82 uuidstring++; 83 continue; 84 } 85 else if (c <= '9') /* 0-9 */ 86 c -= '0'; 87 else if (c <= 'F') /* A-F */ 88 c -= 'A' - 10; 89 else if (c <= 'f') /* a-f */ 90 c-= 'a' - 10; 91 92 if (nibble) 93 val = c * 16; 94 else 95 uuid[i++] = val + c; 96 97 nibble ^= 1; 98 uuidstring++; 99 } 100 101} 102 103/*! 104 * Convert 16 byte binary uuid to neat ascii represantation including dashes. 105 * 106 * Returns pointer to static buffer. 107 */ 108const char *uuid_bin2string(unsigned char *uuid) { 109 static char uuidstring[UUID_STRINGSIZE + 1]; 110 111 int i = 0; 112 unsigned char c; 113 114 while (i < UUID_STRINGSIZE) { 115 c = *uuid; 116 uuid++; 117 sprintf(uuidstring + i, "%02X", c); 118 i += 2; 119 if (i==8 || i==13 || i==18 || i==23) 120 uuidstring[i++] = '-'; 121 } 122 uuidstring[i] = 0; 123 return uuidstring; 124} 125 126/******************************************************** 127 * Interface 128 ********************************************************/ 129 130/* 131 * name: give me his name 132 * type: and type (UUID_USER or UUID_GROUP) 133 * uuid: pointer to uuid_t storage that the caller must provide 134 * returns 0 on success !=0 on errror 135 */ 136int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid) { 137 int ret = 0; 138 uuidtype_t mytype = type; 139 char nulluuid[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; 140#ifdef HAVE_LDAP 141 char *uuid_string = NULL; 142#endif 143 144 ret = search_cachebyname(name, &mytype, uuid); 145 146 if (ret == 0) { 147 /* found in cache */ 148 LOG(log_debug, logtype_afpd, 149 "getuuidfromname{cache}: name: %s, type%s: %s -> UUID: %s", 150 name, 151 (mytype & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "", 152 uuidtype[type & UUIDTYPESTR_MASK], 153 uuid_bin2string(uuid)); 154 if ((mytype & UUID_ENOENT) == UUID_ENOENT) 155 return -1; 156 } else { 157 /* if not found in cache */ 158#ifdef HAVE_LDAP 159 if ((ret = ldap_getuuidfromname( name, type, &uuid_string)) == 0) { 160 uuid_string2bin( uuid_string, uuid); 161 LOG(log_debug, logtype_afpd, "getuuidfromname{LDAP}: name: %s, type: %s -> UUID: %s", 162 name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid)); 163 } else { 164 LOG(log_debug, logtype_afpd, "getuuidfromname(\"%s\",t:%u): no result from ldap search", 165 name, type); 166 } 167#endif 168 if (ret != 0) { 169 /* Build a local UUID */ 170 if (type == UUID_USER) { 171 struct passwd *pwd; 172 if ((pwd = getpwnam(name)) == NULL) { 173 LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user", 174 name, uuidtype[type & UUIDTYPESTR_MASK]); 175 mytype |= UUID_ENOENT; 176 memcpy(uuid, nulluuid, 16); 177 } else { 178 localuuid_from_id(uuid, UUID_USER, pwd->pw_uid); 179 ret = 0; 180 LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s", 181 name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid)); 182 } 183 } else { 184 struct group *grp; 185 if ((grp = getgrnam(name)) == NULL) { 186 LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user", 187 name, uuidtype[type & UUIDTYPESTR_MASK]); 188 mytype |= UUID_ENOENT; 189 memcpy(uuid, nulluuid, 16); 190 } else { 191 localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid); 192 ret = 0; 193 LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s", 194 name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid)); 195 } 196 } 197 } 198 add_cachebyname(name, uuid, mytype, 0); 199 } 200 201cleanup: 202#ifdef HAVE_LDAP 203 if (uuid_string) free(uuid_string); 204#endif 205 return ret; 206} 207 208 209/* 210 * uuidp: pointer to a uuid 211 * name: returns allocated buffer from ldap_getnamefromuuid 212 * type: returns USER, GROUP or LOCAL 213 * return 0 on success !=0 on errror 214 * 215 * Caller must free name appropiately. 216 */ 217int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) { 218 int ret = 0; 219 uid_t uid; 220 gid_t gid; 221 struct passwd *pwd; 222 struct group *grp; 223 224 if (search_cachebyuuid(uuidp, name, type) == 0) { 225 /* found in cache */ 226 LOG(log_debug, logtype_afpd, 227 "getnamefromuuid{cache}: UUID: %s -> name: %s, type%s: %s", 228 uuid_bin2string(uuidp), 229 *name, 230 (*type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "", 231 uuidtype[(*type) & UUIDTYPESTR_MASK]); 232 if ((*type & UUID_ENOENT) == UUID_ENOENT) 233 return -1; 234 return 0; 235 } 236 237 /* not found in cache */ 238 239 /* Check if UUID is a client local one */ 240 if (memcmp(uuidp, local_user_uuid, 12) == 0) { 241 *type = UUID_USER; 242 uid = ntohl(*(uint32_t *)(uuidp + 12)); 243 if ((pwd = getpwuid(uid)) == NULL) { 244 /* not found, add negative entry to cache */ 245 add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0); 246 ret = -1; 247 } else { 248 *name = strdup(pwd->pw_name); 249 add_cachebyuuid(uuidp, *name, *type, 0); 250 ret = 0; 251 } 252 LOG(log_debug, logtype_afpd, 253 "getnamefromuuid{local}: UUID: %s -> name: %s, type:%s", 254 uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]); 255 return ret; 256 } else if (memcmp(uuidp, local_group_uuid, 12) == 0) { 257 *type = UUID_GROUP; 258 gid = ntohl(*(uint32_t *)(uuidp + 12)); 259 if ((grp = getgrgid(gid)) == NULL) { 260 /* not found, add negative entry to cache */ 261 add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0); 262 ret = -1; 263 } else { 264 *name = strdup(grp->gr_name); 265 add_cachebyuuid(uuidp, *name, *type, 0); 266 ret = 0; 267 } 268 return ret; 269 } 270 271#ifdef HAVE_LDAP 272 ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type); 273 if (ret != 0) { 274 LOG(log_warning, logtype_afpd, "getnamefromuuid(%s): no result from ldap_getnamefromuuid", 275 uuid_bin2string(uuidp)); 276 add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0); 277 return -1; 278 } 279#endif 280 281 add_cachebyuuid(uuidp, *name, *type, 0); 282 283 LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s", 284 uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]); 285 286 return 0; 287} 288