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/ldapconfig.h> 32#include <atalk/util.h> 33 34#include "aclldap.h" 35#include "cache.h" 36 37char *uuidtype[] = {"", "USER", "GROUP", "LOCAL"}; 38 39/******************************************************** 40 * Public helper function 41 ********************************************************/ 42 43static unsigned char local_group_uuid[] = {0xab, 0xcd, 0xef, 44 0xab, 0xcd, 0xef, 45 0xab, 0xcd, 0xef, 46 0xab, 0xcd, 0xef}; 47 48static unsigned char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 49 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa}; 50 51void localuuid_from_id(unsigned char *buf, uuidtype_t type, unsigned int id) 52{ 53 uint32_t tmp; 54 55 switch (type) { 56 case UUID_GROUP: 57 memcpy(buf, local_group_uuid, 12); 58 break; 59 case UUID_USER: 60 default: 61 memcpy(buf, local_user_uuid, 12); 62 break; 63 } 64 65 tmp = htonl(id); 66 memcpy(buf + 12, &tmp, 4); 67 68 return; 69} 70 71/* 72 * convert ascii string that can include dashes to binary uuid. 73 * caller must provide a buffer. 74 */ 75void uuid_string2bin( const char *uuidstring, uuidp_t uuid) { 76 int nibble = 1; 77 int i = 0; 78 unsigned char c, val = 0; 79 80 while (*uuidstring && i < UUID_BINSIZE) { 81 c = *uuidstring; 82 if (c == '-') { 83 uuidstring++; 84 continue; 85 } 86 else if (c <= '9') /* 0-9 */ 87 c -= '0'; 88 else if (c <= 'F') /* A-F */ 89 c -= 'A' - 10; 90 else if (c <= 'f') /* a-f */ 91 c-= 'a' - 10; 92 93 if (nibble) 94 val = c * 16; 95 else 96 uuid[i++] = val + c; 97 98 nibble ^= 1; 99 uuidstring++; 100 } 101 102} 103 104/*! 105 * Convert 16 byte binary uuid to neat ascii represantation including dashes. 106 * Use defined or default ascii mask for dash placement 107 * Returns pointer to static buffer. 108 */ 109const char *uuid_bin2string(unsigned char *uuid) { 110 static char uuidstring[64]; 111 const char *uuidmask; 112 int i = 0; 113 unsigned char c; 114 115#ifdef HAVE_LDAP 116 if (ldap_uuid_string) 117 uuidmask = ldap_uuid_string; 118 else 119#endif 120 uuidmask = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; 121 122 LOG(log_debug, logtype_afpd, "uuid_bin2string{uuid}: mask: %s", uuidmask); 123 124 while (i < strlen(uuidmask)) { 125 c = *uuid; 126 uuid++; 127 sprintf(uuidstring + i, "%02X", c); 128 i += 2; 129 if (uuidmask[i] == '-') 130 uuidstring[i++] = '-'; 131 } 132 uuidstring[i] = 0; 133 return uuidstring; 134} 135 136/******************************************************** 137 * Interface 138 ********************************************************/ 139 140/* 141 * name: give me his name 142 * type: and type (UUID_USER or UUID_GROUP) 143 * uuid: pointer to uuid_t storage that the caller must provide 144 * returns 0 on success !=0 on errror 145 */ 146int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid) { 147 int ret = 0; 148 uuidtype_t mytype = type; 149 char nulluuid[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; 150#ifdef HAVE_LDAP 151 char *uuid_string = NULL; 152#endif 153 154 ret = search_cachebyname(name, &mytype, uuid); 155 156 if (ret == 0) { 157 /* found in cache */ 158 LOG(log_debug, logtype_afpd, 159 "getuuidfromname{cache}: name: %s, type%s: %s -> UUID: %s", 160 name, 161 (mytype & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "", 162 uuidtype[type & UUIDTYPESTR_MASK], 163 uuid_bin2string(uuid)); 164 if ((mytype & UUID_ENOENT) == UUID_ENOENT) 165 return -1; 166 } else { 167 /* if not found in cache */ 168#ifdef HAVE_LDAP 169 if ((ret = ldap_getuuidfromname( name, type, &uuid_string)) == 0) { 170 uuid_string2bin( uuid_string, uuid); 171 LOG(log_debug, logtype_afpd, "getuuidfromname{LDAP}: name: %s, type: %s -> UUID: %s", 172 name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid)); 173 } else { 174 LOG(log_debug, logtype_afpd, "getuuidfromname(\"%s\",t:%u): no result from ldap search", 175 name, type); 176 } 177#endif 178 if (ret != 0) { 179 /* Build a local UUID */ 180 if (type == UUID_USER) { 181 struct passwd *pwd; 182 if ((pwd = getpwnam(name)) == NULL) { 183 LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user", 184 name, uuidtype[type & UUIDTYPESTR_MASK]); 185 mytype |= UUID_ENOENT; 186 memcpy(uuid, nulluuid, 16); 187 } else { 188 localuuid_from_id(uuid, UUID_USER, pwd->pw_uid); 189 ret = 0; 190 LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s", 191 name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid)); 192 } 193 } else { 194 struct group *grp; 195 if ((grp = getgrnam(name)) == NULL) { 196 LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user", 197 name, uuidtype[type & UUIDTYPESTR_MASK]); 198 mytype |= UUID_ENOENT; 199 memcpy(uuid, nulluuid, 16); 200 } else { 201 localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid); 202 ret = 0; 203 LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s", 204 name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid)); 205 } 206 } 207 } 208 add_cachebyname(name, uuid, mytype, 0); 209 } 210 211cleanup: 212#ifdef HAVE_LDAP 213 if (uuid_string) free(uuid_string); 214#endif 215 return ret; 216} 217 218 219/* 220 * uuidp: pointer to a uuid 221 * name: returns allocated buffer from ldap_getnamefromuuid 222 * type: returns USER, GROUP or LOCAL 223 * return 0 on success !=0 on errror 224 * 225 * Caller must free name appropiately. 226 */ 227int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) { 228 int ret; 229 uid_t uid; 230 gid_t gid; 231 struct passwd *pwd; 232 struct group *grp; 233 234 if (search_cachebyuuid(uuidp, name, type) == 0) { 235 /* found in cache */ 236 LOG(log_debug, logtype_afpd, 237 "getnamefromuuid{cache}: UUID: %s -> name: %s, type%s: %s", 238 uuid_bin2string(uuidp), 239 *name, 240 (*type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "", 241 uuidtype[(*type) & UUIDTYPESTR_MASK]); 242 if ((*type & UUID_ENOENT) == UUID_ENOENT) 243 return -1; 244 return 0; 245 } 246 247 /* not found in cache */ 248 249 /* Check if UUID is a client local one */ 250 if (memcmp(uuidp, local_user_uuid, 12) == 0) { 251 *type = UUID_USER; 252 uid = ntohl(*(uint32_t *)(uuidp + 12)); 253 if ((pwd = getpwuid(uid)) == NULL) { 254 /* not found, add negative entry to cache */ 255 add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0); 256 ret = -1; 257 } else { 258 *name = strdup(pwd->pw_name); 259 add_cachebyuuid(uuidp, *name, *type, 0); 260 ret = 0; 261 } 262 LOG(log_debug, logtype_afpd, 263 "getnamefromuuid{local}: UUID: %s -> name: %s, type:%s", 264 uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]); 265 return ret; 266 } else if (memcmp(uuidp, local_group_uuid, 12) == 0) { 267 *type = UUID_GROUP; 268 gid = ntohl(*(uint32_t *)(uuidp + 12)); 269 if ((grp = getgrgid(gid)) == NULL) { 270 /* not found, add negative entry to cache */ 271 add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0); 272 ret = -1; 273 } else { 274 *name = strdup(grp->gr_name); 275 add_cachebyuuid(uuidp, *name, *type, 0); 276 ret = 0; 277 } 278 return ret; 279 } 280 281#ifdef HAVE_LDAP 282 ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type); 283#else 284 ret = -1; 285#endif 286 287 if (ret != 0) { 288 LOG(log_debug, logtype_afpd, "getnamefromuuid(%s): not found", 289 uuid_bin2string(uuidp)); 290 add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0); 291 return -1; 292 } 293 294 add_cachebyuuid(uuidp, *name, *type, 0); 295 296 LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s", 297 uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]); 298 299 return 0; 300} 301