]> arthur.barton.de Git - netatalk.git/blob - libatalk/acl/uuid.c
Ensure TCP_NODELAY is set on the AFP session socket
[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 #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  */
146 int 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
211 cleanup:
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     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 }