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