]> arthur.barton.de Git - netatalk.git/blob - libatalk/acl/uuid.c
Merge master
[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/util.h>
33
34 #include "aclldap.h"
35 #include "cache.h"
36
37 char *uuidtype[] = {"NULL","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, unsigned char *uuid) {
76     int nibble = 1;
77     int i = 0;
78     unsigned char c, val = 0;
79
80     while (*uuidstring) {
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  * 
107  * Returns pointer to static buffer.
108  */
109 const char *uuid_bin2string(const unsigned char *uuid) {
110     static char uuidstring[UUID_STRINGSIZE + 1];
111
112     int i = 0;
113     unsigned char c;
114
115     while (i < UUID_STRINGSIZE) {
116         c = *uuid;
117         uuid++;
118         sprintf(uuidstring + i, "%02X", c);
119         i += 2;
120         if (i==8 || i==13 || i==18 || i==23)
121             uuidstring[i++] = '-';
122     }
123     uuidstring[i] = 0;
124     return uuidstring;
125 }
126
127 /********************************************************
128  * Interface
129  ********************************************************/
130
131 /*
132  *   name: give me his name
133  *   type: and type (UUID_USER or UUID_GROUP)
134  *   uuid: pointer to uuid_t storage that the caller must provide
135  * returns 0 on success !=0 on errror
136  */  
137 int getuuidfromname( const char *name, uuidtype_t type, unsigned char *uuid) {
138     int ret = 0;
139 #ifdef HAVE_LDAP
140     char *uuid_string = NULL;
141 #endif
142     ret = search_cachebyname( name, type, uuid);
143     if (ret == 0) {
144         /* found in cache */
145         LOG(log_debug, logtype_afpd, "getuuidfromname{cache}: name: %s, type: %s -> UUID: %s",
146             name, uuidtype[type], uuid_bin2string(uuid));
147     } else  {
148         /* if not found in cache */
149 #ifdef HAVE_LDAP
150         if ((ret = ldap_getuuidfromname( name, type, &uuid_string)) == 0) {
151             uuid_string2bin( uuid_string, uuid);
152             LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
153                 name, uuidtype[type], uuid_bin2string(uuid));
154         } else {
155             LOG(log_debug, logtype_afpd, "getuuidfromname(\"%s\",t:%u): no result from ldap search",
156                 name, type);
157         }
158 #endif
159         if (ret != 0) {
160             /* Build a local UUID */
161             if (type == UUID_USER) {
162                 struct passwd *pwd;
163                 if ((pwd = getpwnam(name)) == NULL) {
164                     LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
165                         name, uuidtype[type]);
166                     goto cleanup;
167                 }
168                 localuuid_from_id(uuid, UUID_USER, pwd->pw_uid);
169             } else {
170                 struct group *grp;
171                 if ((grp = getgrnam(name)) == NULL) {
172                     LOG(log_error, logtype_afpd, "getuuidfromname(\"%s\",t:%u): unknown user",
173                         name, uuidtype[type]);
174                     goto cleanup;
175                 }
176                 localuuid_from_id(uuid, UUID_GROUP, grp->gr_gid);
177             }
178             LOG(log_debug, logtype_afpd, "getuuidfromname{local}: name: %s, type: %s -> UUID: %s",
179                 name, uuidtype[type], uuid_bin2string(uuid));
180         }
181         ret = 0;
182         add_cachebyname( name, uuid, type, 0);
183     }
184
185 cleanup:
186 #ifdef HAVE_LDAP
187     if (uuid_string) free(uuid_string);
188 #endif
189     return ret;
190 }
191
192
193 /*
194  * uuidp: pointer to a uuid
195  * name: returns allocated buffer from ldap_getnamefromuuid
196  * type: returns USER, GROUP or LOCAL
197  * return 0 on success !=0 on errror
198  *
199  * Caller must free name appropiately.
200  */
201 int getnamefromuuid(uuidp_t uuidp, char **name, uuidtype_t *type) {
202     int ret;
203
204     ret = search_cachebyuuid( uuidp, name, type);
205     if (ret == 0) {
206         /* found in cache */
207         LOG(log_debug9, logtype_afpd, "getnamefromuuid{cache}: UUID: %s -> name: %s, type:%s",
208             uuid_bin2string(uuidp), *name, uuidtype[*type]);
209     } else {
210         /* not found in cache */
211
212         /* Check if UUID is a client local one */
213         if (memcmp(uuidp, local_user_uuid, 12) == 0
214             || memcmp(uuidp, local_group_uuid, 12) == 0) {
215             LOG(log_debug, logtype_afpd, "getnamefromuuid: local UUID: %" PRIu32 "",
216                 ntohl(*(uint32_t *)(uuidp + 12)));
217             *type = UUID_LOCAL;
218             *name = strdup("UUID_LOCAL");
219             return 0;
220         }
221
222 #ifdef HAVE_LDAP
223         ret = ldap_getnamefromuuid(uuid_bin2string(uuidp), name, type);
224         if (ret != 0) {
225             LOG(log_warning, logtype_afpd, "getnamefromuuid(%s): no result from ldap_getnamefromuuid",
226                 uuid_bin2string(uuidp));
227             goto cleanup;
228         }
229         add_cachebyuuid( uuidp, *name, *type, 0);
230         LOG(log_debug, logtype_afpd, "getnamefromuuid{LDAP}: UUID: %s -> name: %s, type:%s",
231             uuid_bin2string(uuidp), *name, uuidtype[*type]);
232 #endif
233     }
234
235 cleanup:
236     return ret;
237 }