nwrap: catch NULL list in nwrap_add_hname_add_to_existing
[kai/samba-autobuild/.git] / nsswitch / libwbclient / wbc_idmap.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client API
5
6    Copyright (C) Gerald (Jerry) Carter 2007
7
8    This library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public
10    License as published by the Free Software Foundation; either
11    version 3 of the License, or (at your option) any later version.
12
13    This library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Library General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /* Required Headers */
23
24 #include "replace.h"
25 #include "libwbclient.h"
26 #include "../winbind_client.h"
27
28 /* Convert a Windows SID to a Unix uid, allocating an uid if needed */
29 wbcErr wbcCtxSidToUid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
30                       uid_t *puid)
31 {
32         struct winbindd_request request;
33         struct winbindd_response response;
34         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
35
36         if (!sid || !puid) {
37                 wbc_status = WBC_ERR_INVALID_PARAM;
38                 BAIL_ON_WBC_ERROR(wbc_status);
39         }
40
41         /* Initialize request */
42
43         ZERO_STRUCT(request);
44         ZERO_STRUCT(response);
45
46         wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
47
48         /* Make request */
49
50         wbc_status = wbcRequestResponse(ctx, WINBINDD_SID_TO_UID,
51                                         &request,
52                                         &response);
53         BAIL_ON_WBC_ERROR(wbc_status);
54
55         *puid = response.data.uid;
56
57         wbc_status = WBC_ERR_SUCCESS;
58
59  done:
60         return wbc_status;
61 }
62
63 wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid)
64 {
65         return wbcCtxSidToUid(NULL, sid, puid);
66 }
67
68 /* Convert a Windows SID to a Unix uid if there already is a mapping */
69 wbcErr wbcQuerySidToUid(const struct wbcDomainSid *sid,
70                         uid_t *puid)
71 {
72         return WBC_ERR_NOT_IMPLEMENTED;
73 }
74
75 /* Convert a Unix uid to a Windows SID, allocating a SID if needed */
76 wbcErr wbcCtxUidToSid(struct wbcContext *ctx, uid_t uid,
77                       struct wbcDomainSid *sid)
78 {
79         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
80         struct winbindd_request request;
81         struct winbindd_response response;
82
83         if (!sid) {
84                 wbc_status = WBC_ERR_INVALID_PARAM;
85                 BAIL_ON_WBC_ERROR(wbc_status);
86         }
87
88         /* Initialize request */
89
90         ZERO_STRUCT(request);
91         ZERO_STRUCT(response);
92
93         request.data.uid = uid;
94
95         /* Make request */
96
97         wbc_status = wbcRequestResponse(ctx, WINBINDD_UID_TO_SID,
98                                         &request,
99                                         &response);
100         BAIL_ON_WBC_ERROR(wbc_status);
101
102         wbc_status = wbcStringToSid(response.data.sid.sid, sid);
103         BAIL_ON_WBC_ERROR(wbc_status);
104
105 done:
106         return wbc_status;
107 }
108
109 wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid)
110 {
111         return wbcCtxUidToSid(NULL, uid, sid);
112 }
113
114 /* Convert a Unix uid to a Windows SID if there already is a mapping */
115 wbcErr wbcQueryUidToSid(uid_t uid,
116                         struct wbcDomainSid *sid)
117 {
118         return WBC_ERR_NOT_IMPLEMENTED;
119 }
120
121 /** @brief Convert a Windows SID to a Unix gid, allocating a gid if needed
122  *
123  * @param *sid        Pointer to the domain SID to be resolved
124  * @param *pgid       Pointer to the resolved gid_t value
125  *
126  * @return #wbcErr
127  *
128  **/
129
130 wbcErr wbcCtxSidToGid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
131                       gid_t *pgid)
132 {
133         struct winbindd_request request;
134         struct winbindd_response response;
135         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
136
137         if (!sid || !pgid) {
138                 wbc_status = WBC_ERR_INVALID_PARAM;
139                 BAIL_ON_WBC_ERROR(wbc_status);
140         }
141
142         /* Initialize request */
143
144         ZERO_STRUCT(request);
145         ZERO_STRUCT(response);
146
147         wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
148
149         /* Make request */
150
151         wbc_status = wbcRequestResponse(ctx, WINBINDD_SID_TO_GID,
152                                         &request,
153                                         &response);
154         BAIL_ON_WBC_ERROR(wbc_status);
155
156         *pgid = response.data.gid;
157
158         wbc_status = WBC_ERR_SUCCESS;
159
160  done:
161         return wbc_status;
162 }
163
164 wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid)
165 {
166         return wbcCtxSidToGid(NULL, sid, pgid);
167 }
168
169 /* Convert a Windows SID to a Unix gid if there already is a mapping */
170
171 wbcErr wbcQuerySidToGid(const struct wbcDomainSid *sid,
172                         gid_t *pgid)
173 {
174         return WBC_ERR_NOT_IMPLEMENTED;
175 }
176
177
178 /* Convert a Unix gid to a Windows SID, allocating a SID if needed */
179 wbcErr wbcCtxGidToSid(struct wbcContext *ctx, gid_t gid,
180                       struct wbcDomainSid *sid)
181 {
182         struct winbindd_request request;
183         struct winbindd_response response;
184         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
185
186         if (!sid) {
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         request.data.gid = gid;
197
198         /* Make request */
199
200         wbc_status = wbcRequestResponse(ctx, WINBINDD_GID_TO_SID,
201                                         &request,
202                                         &response);
203         BAIL_ON_WBC_ERROR(wbc_status);
204
205         wbc_status = wbcStringToSid(response.data.sid.sid, sid);
206         BAIL_ON_WBC_ERROR(wbc_status);
207
208 done:
209         return wbc_status;
210 }
211
212 wbcErr wbcGidToSid(gid_t gid, struct wbcDomainSid *sid)
213 {
214         return wbcCtxGidToSid(NULL, gid, sid);
215 }
216
217 /* Convert a Unix gid to a Windows SID if there already is a mapping */
218 wbcErr wbcQueryGidToSid(gid_t gid,
219                         struct wbcDomainSid *sid)
220 {
221         return WBC_ERR_NOT_IMPLEMENTED;
222 }
223
224 /* Obtain a new uid from Winbind */
225 wbcErr wbcCtxAllocateUid(struct wbcContext *ctx, uid_t *puid)
226 {
227         struct winbindd_request request;
228         struct winbindd_response response;
229         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
230
231         if (!puid)
232                 return WBC_ERR_INVALID_PARAM;
233
234         /* Initialise request */
235
236         ZERO_STRUCT(request);
237         ZERO_STRUCT(response);
238
239         /* Make request */
240
241         wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_ALLOCATE_UID,
242                                             &request, &response);
243         BAIL_ON_WBC_ERROR(wbc_status);
244
245         /* Copy out result */
246         *puid = response.data.uid;
247
248         wbc_status = WBC_ERR_SUCCESS;
249
250  done:
251         return wbc_status;
252 }
253
254 wbcErr wbcAllocateUid(uid_t *puid)
255 {
256         return wbcCtxAllocateUid(NULL, puid);
257 }
258
259 /* Obtain a new gid from Winbind */
260 wbcErr wbcCtxAllocateGid(struct wbcContext *ctx, gid_t *pgid)
261 {
262         struct winbindd_request request;
263         struct winbindd_response response;
264         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
265
266         if (!pgid)
267                 return WBC_ERR_INVALID_PARAM;
268
269         /* Initialise request */
270
271         ZERO_STRUCT(request);
272         ZERO_STRUCT(response);
273
274         /* Make request */
275
276         wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_ALLOCATE_GID,
277                                             &request, &response);
278         BAIL_ON_WBC_ERROR(wbc_status);
279
280         /* Copy out result */
281         *pgid = response.data.gid;
282
283         wbc_status = WBC_ERR_SUCCESS;
284
285  done:
286         return wbc_status;
287 }
288
289 wbcErr wbcAllocateGid(gid_t *pgid)
290 {
291         return wbcCtxAllocateGid(NULL, pgid);
292 }
293
294 /* we can't include smb.h here... */
295 #define _ID_TYPE_UID 1
296 #define _ID_TYPE_GID 2
297
298 /* Set an user id mapping - not implemented any more */
299 wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid)
300 {
301         return WBC_ERR_NOT_IMPLEMENTED;
302 }
303
304 /* Set a group id mapping - not implemented any more */
305 wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid)
306 {
307         return WBC_ERR_NOT_IMPLEMENTED;
308 }
309
310 /* Remove a user id mapping - not implemented any more */
311 wbcErr wbcRemoveUidMapping(uid_t uid, const struct wbcDomainSid *sid)
312 {
313         return WBC_ERR_NOT_IMPLEMENTED;
314 }
315
316 /* Remove a group id mapping - not implemented any more */
317 wbcErr wbcRemoveGidMapping(gid_t gid, const struct wbcDomainSid *sid)
318 {
319         return WBC_ERR_NOT_IMPLEMENTED;
320 }
321
322 /* Set the highwater mark for allocated uids - not implemented any more */
323 wbcErr wbcSetUidHwm(uid_t uid_hwm)
324 {
325         return WBC_ERR_NOT_IMPLEMENTED;
326 }
327
328 /* Set the highwater mark for allocated gids - not implemented any more */
329 wbcErr wbcSetGidHwm(gid_t gid_hwm)
330 {
331         return WBC_ERR_NOT_IMPLEMENTED;
332 }
333
334 /* Convert a list of SIDs */
335 wbcErr wbcCtxSidsToUnixIds(struct wbcContext *ctx,
336                            const struct wbcDomainSid *sids,
337                            uint32_t num_sids, struct wbcUnixId *ids)
338 {
339         struct winbindd_request request;
340         struct winbindd_response response;
341         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
342         int buflen, extra_len;
343         uint32_t i;
344         char *sidlist, *p, *extra_data;
345
346         buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
347
348         sidlist = (char *)malloc(buflen);
349         if (sidlist == NULL) {
350                 return WBC_ERR_NO_MEMORY;
351         }
352
353         p = sidlist;
354
355         for (i=0; i<num_sids; i++) {
356                 int remaining;
357                 int len;
358
359                 remaining = buflen - (p - sidlist);
360
361                 len = wbcSidToStringBuf(&sids[i], p, remaining);
362                 if (len > remaining) {
363                         free(sidlist);
364                         return WBC_ERR_UNKNOWN_FAILURE;
365                 }
366
367                 p += len;
368                 *p++ = '\n';
369         }
370         *p++ = '\0';
371
372         ZERO_STRUCT(request);
373         ZERO_STRUCT(response);
374
375         request.extra_data.data = sidlist;
376         request.extra_len = p - sidlist;
377
378         wbc_status = wbcRequestResponse(ctx, WINBINDD_SIDS_TO_XIDS,
379                                         &request, &response);
380         free(sidlist);
381         if (!WBC_ERROR_IS_OK(wbc_status)) {
382                 return wbc_status;
383         }
384
385         extra_len = response.length - sizeof(struct winbindd_response);
386         extra_data = (char *)response.extra_data.data;
387
388         if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) {
389                 goto wbc_err_invalid;
390         }
391
392         p = extra_data;
393
394         for (i=0; i<num_sids; i++) {
395                 struct wbcUnixId *id = &ids[i];
396                 char *q;
397
398                 switch (p[0]) {
399                 case 'U':
400                         id->type = WBC_ID_TYPE_UID;
401                         id->id.uid = strtoul(p+1, &q, 10);
402                         break;
403                 case 'G':
404                         id->type = WBC_ID_TYPE_GID;
405                         id->id.gid = strtoul(p+1, &q, 10);
406                         break;
407                 case 'B':
408                         id->type = WBC_ID_TYPE_BOTH;
409                         id->id.uid = strtoul(p+1, &q, 10);
410                         break;
411                 default:
412                         id->type = WBC_ID_TYPE_NOT_SPECIFIED;
413                         q = strchr(p, '\n');
414                         break;
415                 };
416                 if (q == NULL || q[0] != '\n') {
417                         goto wbc_err_invalid;
418                 }
419                 p = q+1;
420         }
421         wbc_status = WBC_ERR_SUCCESS;
422         goto done;
423
424 wbc_err_invalid:
425         wbc_status = WBC_ERR_INVALID_RESPONSE;
426 done:
427         winbindd_free_response(&response);
428         return wbc_status;
429 }
430
431 wbcErr wbcSidsToUnixIds(const struct wbcDomainSid *sids, uint32_t num_sids,
432                         struct wbcUnixId *ids)
433 {
434         return wbcCtxSidsToUnixIds(NULL, sids, num_sids, ids);
435 }