]> arthur.barton.de Git - netatalk.git/blob - libatalk/acl/uuid.c
ldap_uuid_string
[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
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
37 char *uuidtype[] = {"", "USER", "GROUP", "LOCAL"};
38
39 /********************************************************
40  * Public helper function
41  ********************************************************/
42
43 static unsigned char local_group_uuid[] = {0xab, 0xcd, 0xef,
44                                            0xab, 0xcd, 0xef,
45                                            0xab, 0xcd, 0xef,
46                                            0xab, 0xcd, 0xef};
47
48 static unsigned char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd,
49                                           0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa};
50
51 void 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  */
75 void 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  */
109 const 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     if (ldap_uuid_string)
116         uuidmask = ldap_uuid_string;
117     else
118         uuidmask = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
119
120     LOG(log_debug, logtype_afpd, "uuid_bin2string{uuid}: mask: %s", uuidmask);
121                 
122     while (i < strlen(uuidmask)) {
123         c = *uuid;
124         uuid++;
125         sprintf(uuidstring + i, "%02X", c);
126         i += 2;
127         if (uuidmask[i] == '-')
128             uuidstring[i++] = '-';
129     }
130     uuidstring[i] = 0;
131     return uuidstring;
132 }
133
134 /********************************************************
135  * Interface
136  ********************************************************/
137
138 /*
139  *   name: give me his name
140  *   type: and type (UUID_USER or UUID_GROUP)
141  *   uuid: pointer to uuid_t storage that the caller must provide
142  * returns 0 on success !=0 on errror
143  */
144 int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid) {
145     int ret = 0;
146     uuidtype_t mytype = type;
147     char nulluuid[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
148 #ifdef HAVE_LDAP
149     char *uuid_string = NULL;
150 #endif
151
152     ret = search_cachebyname(name, &mytype, uuid);
153
154     if (ret == 0) {
155         /* found in cache */
156         LOG(log_debug, logtype_afpd,
157             "getuuidfromname{cache}: name: %s, type%s: %s -> UUID: %s",
158             name,
159             (mytype & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
160             uuidtype[type & UUIDTYPESTR_MASK],
161             uuid_bin2string(uuid));
162         if ((mytype & UUID_ENOENT) == UUID_ENOENT)
163             return -1;
164     } else  {
165         /* if not found in cache */
166 #ifdef HAVE_LDAP
167         if ((ret = ldap_getuuidfromname( name, type, &uuid_string)) == 0) {
168             uuid_string2bin( uuid_string, uuid);
169             LOG(log_debug, logtype_afpd, "getuuidfromname{LDAP}: name: %s, type: %s -> UUID: %s",
170                 name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
171         } else {
172             LOG(log_debug, logtype_afpd, "getuuidfromname(\"%s\",t:%u): no result from ldap search",
173                 name, type);
174         }
175 #endif
176         if (ret != 0) {
177             /* Build a local UUID */
178             if (type == UUID_USER) {
179                 struct passwd *pwd;
180                 if ((pwd = getpwnam(name)) == NULL) {
181                     LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
182                         name, uuidtype[type & UUIDTYPESTR_MASK]);
183                     mytype |= UUID_ENOENT;
184                     memcpy(uuid, nulluuid, 16);
185                 } else {
186                     localuuid_from_id(uuid, UUID_USER, pwd->pw_uid);
187                     ret = 0;
188                     LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
189                         name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
190                 }
191             } else {
192                 struct group *grp;
193                 if ((grp = getgrnam(name)) == NULL) {
194                     LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
195                         name, uuidtype[type & UUIDTYPESTR_MASK]);
196                     mytype |= UUID_ENOENT;
197                     memcpy(uuid, nulluuid, 16);
198                 } else {
199                     localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid);
200                     ret = 0;
201                     LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
202                         name, uuidtype[type & UUIDTYPESTR_MASK], uuid_bin2string(uuid));
203                 }
204             }
205         }
206         add_cachebyname(name, uuid, mytype, 0);
207     }
208
209 cleanup:
210 #ifdef HAVE_LDAP
211     if (uuid_string) free(uuid_string);
212 #endif
213     return ret;
214 }
215
216
217 /*
218  * uuidp: pointer to a uuid
219  * name: returns allocated buffer from ldap_getnamefromuuid
220  * type: returns USER, GROUP or LOCAL
221  * return 0 on success !=0 on errror
222  *
223  * Caller must free name appropiately.
224  */
225 int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) {
226     int ret;
227     uid_t uid;
228     gid_t gid;
229     struct passwd *pwd;
230     struct group *grp;
231
232     if (search_cachebyuuid(uuidp, name, type) == 0) {
233         /* found in cache */
234         LOG(log_debug, logtype_afpd,
235             "getnamefromuuid{cache}: UUID: %s -> name: %s, type%s: %s",
236             uuid_bin2string(uuidp),
237             *name,
238             (*type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
239             uuidtype[(*type) & UUIDTYPESTR_MASK]);
240         if ((*type & UUID_ENOENT) == UUID_ENOENT)
241             return -1;
242         return 0;
243     }
244
245     /* not found in cache */
246
247     /* Check if UUID is a client local one */
248     if (memcmp(uuidp, local_user_uuid, 12) == 0) {
249         *type = UUID_USER;
250         uid = ntohl(*(uint32_t *)(uuidp + 12));
251         if ((pwd = getpwuid(uid)) == NULL) {
252             /* not found, add negative entry to cache */
253             add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
254             ret = -1;
255         } else {
256             *name = strdup(pwd->pw_name);
257             add_cachebyuuid(uuidp, *name, *type, 0);
258             ret = 0;
259         }
260         LOG(log_debug, logtype_afpd,
261             "getnamefromuuid{local}: UUID: %s -> name: %s, type:%s",
262             uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]);
263         return ret;
264     } else if (memcmp(uuidp, local_group_uuid, 12) == 0) {
265         *type = UUID_GROUP;
266         gid = ntohl(*(uint32_t *)(uuidp + 12));
267         if ((grp = getgrgid(gid)) == NULL) {
268             /* not found, add negative entry to cache */
269             add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
270             ret = -1;
271         } else {
272             *name = strdup(grp->gr_name);
273             add_cachebyuuid(uuidp, *name, *type, 0);
274             ret = 0;
275         }
276         return ret;
277     }
278
279 #ifdef HAVE_LDAP
280     ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type);
281 #else
282     ret = -1;
283 #endif
284
285     if (ret != 0) {
286         LOG(log_debug, logtype_afpd, "getnamefromuuid(%s): not found",
287             uuid_bin2string(uuidp));
288         add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0);
289         return -1;
290     }
291
292     add_cachebyuuid(uuidp, *name, *type, 0);
293
294     LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s",
295         uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]);
296
297     return 0;
298 }