Make sure that wbcLookupSid() and wbcLookupRids() use talloc()'d memory.
[ira/wip.git] / source3 / nsswitch / libwbclient / wbc_sid.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client API
5
6    Copyright (C) Gerald (Jerry) Carter 2007
7
8
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Lesser General Public
11    License as published by the Free Software Foundation; either
12    version 3 of the License, or (at your option) any later version.
13
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18
19    You should have received a copy of the GNU Lesser General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /* Required Headers */
24
25 #include "libwbclient.h"
26
27
28 /** @brief Convert a binary SID to a character string
29  *
30  * @param sid           Binary Security Identifier
31  * @param **sid_string  Resulting character string
32  *
33  * @return #wbcErr
34  **/
35
36 wbcErr wbcSidToString(const struct wbcDomainSid *sid,
37                       char **sid_string)
38 {
39         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
40         uint32_t id_auth;
41         int i;
42         char *tmp = NULL;
43         TALLOC_CTX *ctx = NULL;
44
45         if (!sid) {
46                 wbc_status = WBC_ERR_INVALID_SID;
47                 BAIL_ON_WBC_ERROR(wbc_status);
48         }
49
50         ctx = talloc_init("wbcSidToString");
51         BAIL_ON_PTR_ERROR(ctx, wbc_status);
52
53         id_auth = sid->id_auth[5] +
54                 (sid->id_auth[4] << 8) +
55                 (sid->id_auth[3] << 16) +
56                 (sid->id_auth[2] << 24);
57
58         tmp = talloc_asprintf(ctx, "S-%d-%d", sid->sid_rev_num, id_auth);
59         BAIL_ON_PTR_ERROR(tmp, wbc_status);
60
61         for (i=0; i<sid->num_auths; i++) {
62                 char *tmp2 =
63                 tmp2 = talloc_asprintf_append(tmp, "-%u", sid->sub_auths[i]);
64                 BAIL_ON_PTR_ERROR(tmp2, wbc_status);
65
66                 tmp = tmp2;
67         }
68
69         *sid_string=talloc_strdup(NULL, tmp);
70         BAIL_ON_PTR_ERROR((*sid_string), wbc_status);
71
72         wbc_status = WBC_ERR_SUCCESS;
73
74 done:
75         talloc_free(ctx);
76
77         return wbc_status;
78 }
79
80 /** @brief Convert a character string to a binary SID
81  *
82  * @param *str          Character string in the form of S-...
83  * @param sid           Resulting binary SID
84  *
85  * @return #wbcErr
86  **/
87
88 wbcErr wbcStringToSid(const char *str,
89                       struct wbcDomainSid *sid)
90 {
91         const char *p;
92         char *q;
93         uint32_t x;
94         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
95
96         if (!sid) {
97                 wbc_status = WBC_ERR_INVALID_PARAM;
98                 BAIL_ON_WBC_ERROR(wbc_status);
99         }
100
101         /* Sanity check for either "S-" or "s-" */
102
103         if (!str
104             || (str[0]!='S' && str[0]!='s')
105             || (str[1]!='-')
106             || (strlen(str)<2))
107         {
108                 wbc_status = WBC_ERR_INVALID_PARAM;
109                 BAIL_ON_WBC_ERROR(wbc_status);
110         }
111
112         /* Get the SID revision number */
113
114         p = str+2;
115         x = (uint32_t)strtol(p, &q, 10);
116         if (x==0 || !q || *q!='-') {
117                 wbc_status = WBC_ERR_INVALID_SID;
118                 BAIL_ON_WBC_ERROR(wbc_status);
119         }
120         sid->sid_rev_num = (uint8_t)x;
121
122         /* Next the Identifier Authority.  This is stored in big-endian
123            in a 6 byte array. */
124
125         p = q+1;
126         x = (uint32_t)strtol(p, &q, 10);
127         if (x==0 || !q || *q!='-') {
128                 wbc_status = WBC_ERR_INVALID_SID;
129                 BAIL_ON_WBC_ERROR(wbc_status);
130         }
131         sid->id_auth[5] = (x & 0x000000ff);
132         sid->id_auth[4] = (x & 0x0000ff00) >> 8;
133         sid->id_auth[3] = (x & 0x00ff0000) >> 16;
134         sid->id_auth[2] = (x & 0xff000000) >> 24;
135         sid->id_auth[1] = 0;
136         sid->id_auth[0] = 0;
137
138         /* now read the the subauthorities */
139
140         p = q +1;
141         sid->num_auths = 0;
142         while (sid->num_auths < MAXSUBAUTHS) {
143                 if ((x=(uint32_t)strtoul(p, &q, 10)) == 0)
144                         break;
145                 sid->sub_auths[sid->num_auths++] = x;
146
147                 if (q && ((*q!='-') || (*q=='\0')))
148                         break;
149                 p = q + 1;
150         }
151
152         /* IF we ended early, then the SID could not be converted */
153
154         if (q && *q!='\0') {
155                 wbc_status = WBC_ERR_INVALID_SID;
156                 BAIL_ON_WBC_ERROR(wbc_status);
157         }
158
159         wbc_status = WBC_ERR_SUCCESS;
160
161 done:
162         return wbc_status;
163
164 }
165
166 /** @brief Convert a domain and name to SID
167  *
168  * @param domain      Domain name (possibly "")
169  * @param name        User or group name
170  * @param *sid        Pointer to the resolved domain SID
171  * @param *name_type  Pointet to the SID type
172  *
173  * @return #wbcErr
174  *
175  **/
176
177 wbcErr wbcLookupName(const char *domain,
178                      const char *name,
179                      struct wbcDomainSid *sid,
180                      enum wbcSidType *name_type)
181 {
182         struct winbindd_request request;
183         struct winbindd_response response;
184         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
185
186         if (!sid || !name_type) {
187                 wbc_status = WBC_ERR_INVALID_PARAM;
188                 BAIL_ON_WBC_ERROR(wbc_status);
189         }
190
191         /* Initialize request */
192
193         ZERO_STRUCT(request);
194         ZERO_STRUCT(response);
195
196         /* dst is already null terminated from the memset above */
197
198         strncpy(request.data.name.dom_name, domain,
199                 sizeof(request.data.name.dom_name)-1);
200         strncpy(request.data.name.name, name,
201                 sizeof(request.data.name.name)-1);
202
203         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPNAME,
204                                         &request,
205                                         &response);
206         BAIL_ON_WBC_ERROR(wbc_status);
207
208         wbc_status = wbcStringToSid(response.data.sid.sid, sid);
209         BAIL_ON_WBC_ERROR(wbc_status);
210
211         *name_type = (enum wbcSidType)response.data.sid.type;
212
213         wbc_status = WBC_ERR_SUCCESS;
214
215  done:
216         return wbc_status;
217 }
218
219 /** @brief Convert a SID to a domain and name
220  *
221  * @param *sid        Pointer to the domain SID to be resolved
222  * @param domain      Resolved Domain name (possibly "")
223  * @param name        Resolved User or group name
224  * @param *name_type  Pointet to the resolved SID type
225  *
226  * @return #wbcErr
227  *
228  **/
229
230 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
231                     char **domain,
232                     char **name,
233                     enum wbcSidType *name_type)
234 {
235         struct winbindd_request request;
236         struct winbindd_response response;
237         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
238         char *sid_string = NULL;
239
240         if (!sid) {
241                 wbc_status = WBC_ERR_INVALID_PARAM;
242                 BAIL_ON_WBC_ERROR(wbc_status);
243         }
244
245         /* Initialize request */
246
247         ZERO_STRUCT(request);
248         ZERO_STRUCT(response);
249
250         /* dst is already null terminated from the memset above */
251
252         wbc_status = wbcSidToString(sid, &sid_string);
253         BAIL_ON_WBC_ERROR(wbc_status);
254
255         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
256         wbcFreeMemory(sid_string);
257
258         /* Make request */
259
260         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID,
261                                            &request,
262                                            &response);
263         BAIL_ON_WBC_ERROR(wbc_status);
264
265         /* Copy out result */
266
267         if (domain != NULL) {
268                 *domain = talloc_strdup(NULL, response.data.name.dom_name);
269                 BAIL_ON_PTR_ERROR((*domain), wbc_status);
270         }
271
272         if (name != NULL) {
273                 *name = talloc_strdup(NULL, response.data.name.name);
274                 BAIL_ON_PTR_ERROR((*name), wbc_status);
275         }
276
277         if (name_type) {
278                 *name_type = (enum wbcSidType)response.data.name.type;
279         }
280
281         wbc_status = WBC_ERR_SUCCESS;
282
283  done:
284         if (!WBC_ERROR_IS_OK(wbc_status)) {
285                 if (*domain)
286                         talloc_free(*domain);
287                 if (*name)
288                         talloc_free(*name);
289         }
290
291         return wbc_status;
292 }
293
294 /** @brief Translate a collection of RIDs within a domain to names
295  *
296  **/
297
298 wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
299                      int num_rids,
300                      uint32_t *rids,
301                      const char **pp_domain_name,
302                      const char ***names,
303                      enum wbcSidType **types)
304 {
305         size_t i, len, ridbuf_size;
306         char *ridlist;
307         char *p;
308         struct winbindd_request request;
309         struct winbindd_response response;
310         char *sid_string = NULL;
311         char *domain_name = NULL;
312         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
313
314         if (!dom_sid || (num_rids == 0)) {
315                 wbc_status = WBC_ERR_INVALID_PARAM;
316                 BAIL_ON_WBC_ERROR(wbc_status);
317         }
318
319         /* Initialise request */
320
321         ZERO_STRUCT(request);
322         ZERO_STRUCT(response);
323
324         wbc_status = wbcSidToString(dom_sid, &sid_string);
325         BAIL_ON_WBC_ERROR(wbc_status);
326
327         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
328         wbcFreeMemory(sid_string);
329
330         /* Even if all the Rids were of maximum 32bit values,
331            we would only have 11 bytes per rid in the final array
332            ("4294967296" + \n).  Add one more byte for the
333            terminating '\0' */
334
335         ridbuf_size = (sizeof(char)*11) * num_rids + 1;
336
337         ridlist = talloc_zero_array(NULL, char, ridbuf_size);
338         BAIL_ON_PTR_ERROR(ridlist, wbc_status);
339
340         len = 0;
341         for (i=0; i<num_rids && (len-1)>0; i++) {
342                 char ridstr[12];
343
344                 len = strlen(ridlist);
345                 p = ridlist + len;
346
347                 snprintf( ridstr, sizeof(ridstr)-1, "%u\n", rids[i]);
348                 strncat(p, ridstr, ridbuf_size-len-1);
349         }
350
351         request.extra_data.data = ridlist;
352         request.extra_len = strlen(ridlist)+1;
353
354         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
355                                         &request,
356                                         &response);
357         talloc_free(ridlist);
358
359         domain_name = talloc_strdup(NULL, response.data.domain_name);
360         BAIL_ON_PTR_ERROR(domain_name, wbc_status);
361
362         *names = talloc_array(NULL, const char*, num_rids);
363         BAIL_ON_PTR_ERROR((*names), wbc_status);
364
365         *types = talloc_array(NULL, enum wbcSidType, num_rids);
366         BAIL_ON_PTR_ERROR((*types), wbc_status);
367
368         p = (char *)response.extra_data.data;
369
370         for (i=0; i<num_rids; i++) {
371                 char *q;
372
373                 if (*p == '\0') {
374                         wbc_status = WBC_INVALID_RESPONSE;
375                         BAIL_ON_WBC_ERROR(wbc_status);
376                 }
377
378                 (*types)[i] = (enum wbcSidType)strtoul(p, &q, 10);
379
380                 if (*q != ' ') {
381                         wbc_status = WBC_INVALID_RESPONSE;
382                         BAIL_ON_WBC_ERROR(wbc_status);
383                 }
384
385                 p = q+1;
386
387                 if ((q = strchr(p, '\n')) == NULL) {
388                         wbc_status = WBC_INVALID_RESPONSE;
389                         BAIL_ON_WBC_ERROR(wbc_status);
390                 }
391
392                 *q = '\0';
393
394                 (*names)[i] = talloc_strdup((*names), p);
395                 BAIL_ON_PTR_ERROR(((*names)[i]), wbc_status);           
396
397                 p = q+1;
398         }
399
400         if (*p != '\0') {
401                 wbc_status = WBC_INVALID_RESPONSE;
402                 BAIL_ON_WBC_ERROR(wbc_status);
403         }
404
405         wbc_status = WBC_ERR_SUCCESS;
406
407  done:
408         if (response.extra_data.data) {         
409                 free(response.extra_data.data);
410         }       
411                 
412         if (!WBC_ERROR_IS_OK(wbc_status)) {
413                 if (domain_name)
414                         talloc_free(domain_name);
415                 if (*names)
416                         talloc_free(*names);
417                 if (*types)
418                         talloc_free(*types);
419         } else {
420                 *pp_domain_name = domain_name;
421         }
422
423         return wbc_status;
424