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 #include "lib/util/util.h"
28 
29 /* Convert a Windows SID to a Unix uid, allocating an uid if needed */
wbcCtxSidToUid(struct wbcContext * ctx,const struct wbcDomainSid * sid,uid_t * puid)30 wbcErr wbcCtxSidToUid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
31 		      uid_t *puid)
32 {
33 	struct wbcUnixId xid;
34 	wbcErr wbc_status;
35 
36 	if (!sid || !puid) {
37 		wbc_status = WBC_ERR_INVALID_PARAM;
38 		BAIL_ON_WBC_ERROR(wbc_status);
39 	}
40 
41 	wbc_status = wbcCtxSidsToUnixIds(ctx, sid, 1, &xid);
42 	if (!WBC_ERROR_IS_OK(wbc_status)) {
43 		goto done;
44 	}
45 
46 	if ((xid.type == WBC_ID_TYPE_UID) || (xid.type == WBC_ID_TYPE_BOTH)) {
47 		*puid = xid.id.uid;
48 		wbc_status = WBC_ERR_SUCCESS;
49 	} else {
50 		wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
51 	}
52 
53  done:
54 	return wbc_status;
55 }
56 
wbcSidToUid(const struct wbcDomainSid * sid,uid_t * puid)57 wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid)
58 {
59 	return wbcCtxSidToUid(NULL, sid, puid);
60 }
61 
62 /* Convert a Windows SID to a Unix uid if there already is a mapping */
wbcQuerySidToUid(const struct wbcDomainSid * sid,uid_t * puid)63 wbcErr wbcQuerySidToUid(const struct wbcDomainSid *sid,
64 			uid_t *puid)
65 {
66 	return WBC_ERR_NOT_IMPLEMENTED;
67 }
68 
69 /* Convert a Unix uid to a Windows SID, allocating a SID if needed */
wbcCtxUidToSid(struct wbcContext * ctx,uid_t uid,struct wbcDomainSid * psid)70 wbcErr wbcCtxUidToSid(struct wbcContext *ctx, uid_t uid,
71 		      struct wbcDomainSid *psid)
72 {
73 	struct wbcUnixId xid;
74 	struct wbcDomainSid sid;
75 	struct wbcDomainSid null_sid = { 0 };
76 	wbcErr wbc_status;
77 
78 	if (!psid) {
79 		wbc_status = WBC_ERR_INVALID_PARAM;
80 		BAIL_ON_WBC_ERROR(wbc_status);
81 	}
82 
83 	xid = (struct wbcUnixId) { .type = WBC_ID_TYPE_UID, .id.uid = uid };
84 
85 	wbc_status = wbcCtxUnixIdsToSids(ctx, &xid, 1, &sid);
86 	if (!WBC_ERROR_IS_OK(wbc_status)) {
87 		goto done;
88 	}
89 
90 	if (memcmp(&sid, &null_sid, sizeof(sid)) != 0) {
91 		*psid = sid;
92 	} else {
93 		wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
94 	}
95 
96 done:
97 	return wbc_status;
98 }
99 
wbcUidToSid(uid_t uid,struct wbcDomainSid * sid)100 wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid)
101 {
102 	return wbcCtxUidToSid(NULL, uid, sid);
103 }
104 
105 /* Convert a Unix uid to a Windows SID if there already is a mapping */
wbcQueryUidToSid(uid_t uid,struct wbcDomainSid * sid)106 wbcErr wbcQueryUidToSid(uid_t uid,
107 			struct wbcDomainSid *sid)
108 {
109 	return WBC_ERR_NOT_IMPLEMENTED;
110 }
111 
112 /** @brief Convert a Windows SID to a Unix gid, allocating a gid if needed
113  *
114  * @param *sid        Pointer to the domain SID to be resolved
115  * @param *pgid       Pointer to the resolved gid_t value
116  *
117  * @return #wbcErr
118  *
119  **/
120 
wbcCtxSidToGid(struct wbcContext * ctx,const struct wbcDomainSid * sid,gid_t * pgid)121 wbcErr wbcCtxSidToGid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
122 		      gid_t *pgid)
123 {
124 	struct wbcUnixId xid;
125 	wbcErr wbc_status;
126 
127 	if (!sid || !pgid) {
128 		wbc_status = WBC_ERR_INVALID_PARAM;
129 		BAIL_ON_WBC_ERROR(wbc_status);
130 	}
131 
132 	wbc_status = wbcCtxSidsToUnixIds(ctx, sid, 1, &xid);
133 	if (!WBC_ERROR_IS_OK(wbc_status)) {
134 		goto done;
135 	}
136 
137 	if ((xid.type == WBC_ID_TYPE_GID) || (xid.type == WBC_ID_TYPE_BOTH)) {
138 		*pgid = xid.id.gid;
139 		wbc_status = WBC_ERR_SUCCESS;
140 	} else {
141 		wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
142 	}
143 
144  done:
145 	return wbc_status;
146 }
147 
wbcSidToGid(const struct wbcDomainSid * sid,gid_t * pgid)148 wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid)
149 {
150 	return wbcCtxSidToGid(NULL, sid, pgid);
151 }
152 
153 /* Convert a Windows SID to a Unix gid if there already is a mapping */
154 
wbcQuerySidToGid(const struct wbcDomainSid * sid,gid_t * pgid)155 wbcErr wbcQuerySidToGid(const struct wbcDomainSid *sid,
156 			gid_t *pgid)
157 {
158 	return WBC_ERR_NOT_IMPLEMENTED;
159 }
160 
161 
162 /* Convert a Unix gid to a Windows SID, allocating a SID if needed */
wbcCtxGidToSid(struct wbcContext * ctx,gid_t gid,struct wbcDomainSid * psid)163 wbcErr wbcCtxGidToSid(struct wbcContext *ctx, gid_t gid,
164 		      struct wbcDomainSid *psid)
165 {
166 	struct wbcUnixId xid;
167 	struct wbcDomainSid sid;
168 	struct wbcDomainSid null_sid = { 0 };
169 	wbcErr wbc_status;
170 
171 	if (!psid) {
172 		wbc_status = WBC_ERR_INVALID_PARAM;
173 		BAIL_ON_WBC_ERROR(wbc_status);
174 	}
175 
176 	xid = (struct wbcUnixId) { .type = WBC_ID_TYPE_GID, .id.gid = gid };
177 
178 	wbc_status = wbcCtxUnixIdsToSids(ctx, &xid, 1, &sid);
179 	if (!WBC_ERROR_IS_OK(wbc_status)) {
180 		goto done;
181 	}
182 
183 	if (memcmp(&sid, &null_sid, sizeof(sid)) != 0) {
184 		*psid = sid;
185 	} else {
186 		wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
187 	}
188 
189 done:
190 	return wbc_status;
191 }
192 
wbcGidToSid(gid_t gid,struct wbcDomainSid * sid)193 wbcErr wbcGidToSid(gid_t gid, struct wbcDomainSid *sid)
194 {
195 	return wbcCtxGidToSid(NULL, gid, sid);
196 }
197 
198 /* Convert a Unix gid to a Windows SID if there already is a mapping */
wbcQueryGidToSid(gid_t gid,struct wbcDomainSid * sid)199 wbcErr wbcQueryGidToSid(gid_t gid,
200 			struct wbcDomainSid *sid)
201 {
202 	return WBC_ERR_NOT_IMPLEMENTED;
203 }
204 
205 /* Obtain a new uid from Winbind */
wbcCtxAllocateUid(struct wbcContext * ctx,uid_t * puid)206 wbcErr wbcCtxAllocateUid(struct wbcContext *ctx, uid_t *puid)
207 {
208 	struct winbindd_request request;
209 	struct winbindd_response response;
210 	wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
211 
212 	if (!puid)
213 		return WBC_ERR_INVALID_PARAM;
214 
215 	/* Initialise request */
216 
217 	ZERO_STRUCT(request);
218 	ZERO_STRUCT(response);
219 
220 	/* Make request */
221 
222 	wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_ALLOCATE_UID,
223 					    &request, &response);
224 	BAIL_ON_WBC_ERROR(wbc_status);
225 
226 	/* Copy out result */
227 	*puid = response.data.uid;
228 
229 	wbc_status = WBC_ERR_SUCCESS;
230 
231  done:
232 	return wbc_status;
233 }
234 
wbcAllocateUid(uid_t * puid)235 wbcErr wbcAllocateUid(uid_t *puid)
236 {
237 	return wbcCtxAllocateUid(NULL, puid);
238 }
239 
240 /* Obtain a new gid from Winbind */
wbcCtxAllocateGid(struct wbcContext * ctx,gid_t * pgid)241 wbcErr wbcCtxAllocateGid(struct wbcContext *ctx, gid_t *pgid)
242 {
243 	struct winbindd_request request;
244 	struct winbindd_response response;
245 	wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
246 
247 	if (!pgid)
248 		return WBC_ERR_INVALID_PARAM;
249 
250 	/* Initialise request */
251 
252 	ZERO_STRUCT(request);
253 	ZERO_STRUCT(response);
254 
255 	/* Make request */
256 
257 	wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_ALLOCATE_GID,
258 					    &request, &response);
259 	BAIL_ON_WBC_ERROR(wbc_status);
260 
261 	/* Copy out result */
262 	*pgid = response.data.gid;
263 
264 	wbc_status = WBC_ERR_SUCCESS;
265 
266  done:
267 	return wbc_status;
268 }
269 
wbcAllocateGid(gid_t * pgid)270 wbcErr wbcAllocateGid(gid_t *pgid)
271 {
272 	return wbcCtxAllocateGid(NULL, pgid);
273 }
274 
275 /* we can't include smb.h here... */
276 #define _ID_TYPE_UID 1
277 #define _ID_TYPE_GID 2
278 
279 /* Set an user id mapping - not implemented any more */
wbcSetUidMapping(uid_t uid,const struct wbcDomainSid * sid)280 wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid)
281 {
282 	return WBC_ERR_NOT_IMPLEMENTED;
283 }
284 
285 /* Set a group id mapping - not implemented any more */
wbcSetGidMapping(gid_t gid,const struct wbcDomainSid * sid)286 wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid)
287 {
288 	return WBC_ERR_NOT_IMPLEMENTED;
289 }
290 
291 /* Remove a user id mapping - not implemented any more */
wbcRemoveUidMapping(uid_t uid,const struct wbcDomainSid * sid)292 wbcErr wbcRemoveUidMapping(uid_t uid, const struct wbcDomainSid *sid)
293 {
294 	return WBC_ERR_NOT_IMPLEMENTED;
295 }
296 
297 /* Remove a group id mapping - not implemented any more */
wbcRemoveGidMapping(gid_t gid,const struct wbcDomainSid * sid)298 wbcErr wbcRemoveGidMapping(gid_t gid, const struct wbcDomainSid *sid)
299 {
300 	return WBC_ERR_NOT_IMPLEMENTED;
301 }
302 
303 /* Set the highwater mark for allocated uids - not implemented any more */
wbcSetUidHwm(uid_t uid_hwm)304 wbcErr wbcSetUidHwm(uid_t uid_hwm)
305 {
306 	return WBC_ERR_NOT_IMPLEMENTED;
307 }
308 
309 /* Set the highwater mark for allocated gids - not implemented any more */
wbcSetGidHwm(gid_t gid_hwm)310 wbcErr wbcSetGidHwm(gid_t gid_hwm)
311 {
312 	return WBC_ERR_NOT_IMPLEMENTED;
313 }
314 
315 /* Convert a list of SIDs */
wbcCtxSidsToUnixIds(struct wbcContext * ctx,const struct wbcDomainSid * sids,uint32_t num_sids,struct wbcUnixId * ids)316 wbcErr wbcCtxSidsToUnixIds(struct wbcContext *ctx,
317 			   const struct wbcDomainSid *sids,
318 			   uint32_t num_sids, struct wbcUnixId *ids)
319 {
320 	struct winbindd_request request;
321 	struct winbindd_response response;
322 	wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
323 	int buflen, extra_len;
324 	uint32_t i;
325 	char *sidlist, *p, *extra_data;
326 
327 	buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
328 
329 	sidlist = (char *)malloc(buflen);
330 	if (sidlist == NULL) {
331 		return WBC_ERR_NO_MEMORY;
332 	}
333 
334 	p = sidlist;
335 
336 	for (i=0; i<num_sids; i++) {
337 		int remaining;
338 		int len;
339 
340 		remaining = buflen - (p - sidlist);
341 
342 		len = wbcSidToStringBuf(&sids[i], p, remaining);
343 		if (len > remaining) {
344 			free(sidlist);
345 			return WBC_ERR_UNKNOWN_FAILURE;
346 		}
347 
348 		p += len;
349 		*p++ = '\n';
350 	}
351 	*p++ = '\0';
352 
353 	ZERO_STRUCT(request);
354 	ZERO_STRUCT(response);
355 
356 	request.extra_data.data = sidlist;
357 	request.extra_len = p - sidlist;
358 
359 	wbc_status = wbcRequestResponse(ctx, WINBINDD_SIDS_TO_XIDS,
360 					&request, &response);
361 	free(sidlist);
362 	if (!WBC_ERROR_IS_OK(wbc_status)) {
363 		return wbc_status;
364 	}
365 
366 	extra_len = response.length - sizeof(struct winbindd_response);
367 	extra_data = (char *)response.extra_data.data;
368 
369 	if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) {
370 		goto wbc_err_invalid;
371 	}
372 
373 	p = extra_data;
374 
375 	for (i=0; i<num_sids; i++) {
376 		struct wbcUnixId *id = &ids[i];
377 		char *q;
378 		int error = 0;
379 
380 		switch (p[0]) {
381 		case 'U':
382 			id->type = WBC_ID_TYPE_UID;
383 			id->id.uid = smb_strtoul(p+1,
384 						 &q,
385 						 10,
386 						 &error,
387 						 SMB_STR_STANDARD);
388 			break;
389 		case 'G':
390 			id->type = WBC_ID_TYPE_GID;
391 			id->id.gid = smb_strtoul(p+1,
392 						 &q,
393 						 10,
394 						 &error,
395 						 SMB_STR_STANDARD);
396 			break;
397 		case 'B':
398 			id->type = WBC_ID_TYPE_BOTH;
399 			id->id.uid = smb_strtoul(p+1,
400 						 &q,
401 						 10,
402 						 &error,
403 						 SMB_STR_STANDARD);
404 			break;
405 		default:
406 			id->type = WBC_ID_TYPE_NOT_SPECIFIED;
407 			q = strchr(p, '\n');
408 			break;
409 		};
410 		if (q == NULL || q[0] != '\n' || error != 0) {
411 			goto wbc_err_invalid;
412 		}
413 		p = q+1;
414 	}
415 	wbc_status = WBC_ERR_SUCCESS;
416 	goto done;
417 
418 wbc_err_invalid:
419 	wbc_status = WBC_ERR_INVALID_RESPONSE;
420 done:
421 	winbindd_free_response(&response);
422 	return wbc_status;
423 }
424 
wbcSidsToUnixIds(const struct wbcDomainSid * sids,uint32_t num_sids,struct wbcUnixId * ids)425 wbcErr wbcSidsToUnixIds(const struct wbcDomainSid *sids, uint32_t num_sids,
426 			struct wbcUnixId *ids)
427 {
428 	return wbcCtxSidsToUnixIds(NULL, sids, num_sids, ids);
429 }
430 
wbcCtxUnixIdsToSids(struct wbcContext * ctx,const struct wbcUnixId * ids,uint32_t num_ids,struct wbcDomainSid * sids)431 wbcErr wbcCtxUnixIdsToSids(struct wbcContext *ctx,
432 			   const struct wbcUnixId *ids, uint32_t num_ids,
433 			   struct wbcDomainSid *sids)
434 {
435 	struct winbindd_request request;
436 	struct winbindd_response response;
437 	wbcErr wbc_status;
438 	char *buf;
439 	char *s;
440 	const size_t sidlen = (1 /* U/G */ + 10 /* 2^32 */ + 1 /* \n */);
441 	size_t ofs, buflen;
442 	uint32_t i;
443 
444 	if (num_ids > SIZE_MAX / sidlen) {
445 		return WBC_ERR_NO_MEMORY; /* overflow */
446 	}
447 	buflen = num_ids * sidlen;
448 
449 	buflen += 1;		/* trailing \0 */
450 	if (buflen < 1) {
451 		return WBC_ERR_NO_MEMORY; /* overflow */
452 	}
453 
454 	buf = malloc(buflen);
455 	if (buf == NULL) {
456 		return WBC_ERR_NO_MEMORY;
457 	}
458 
459 	ofs = 0;
460 
461 	for (i=0; i<num_ids; i++) {
462 		const struct wbcUnixId *id = &ids[i];
463 		int len;
464 
465 		switch (id->type) {
466 		case WBC_ID_TYPE_UID:
467 			len = snprintf(buf+ofs, buflen-ofs, "U%"PRIu32"\n",
468 				       (uint32_t)id->id.uid);
469 			break;
470 		case WBC_ID_TYPE_GID:
471 			len = snprintf(buf+ofs, buflen-ofs, "G%"PRIu32"\n",
472 				       (uint32_t)id->id.gid);
473 			break;
474 		default:
475 			free(buf);
476 			return WBC_ERR_INVALID_PARAM;
477 		}
478 
479 		if (len + ofs >= buflen) { /* >= for the terminating '\0' */
480 			free(buf);
481 			return WBC_ERR_UNKNOWN_FAILURE;
482 		}
483 		ofs += len;
484 	}
485 
486 	request = (struct winbindd_request) {
487 		.extra_data.data = buf, .extra_len = ofs+1
488 	};
489 	response = (struct winbindd_response) {0};
490 
491 	wbc_status = wbcRequestResponse(ctx, WINBINDD_XIDS_TO_SIDS,
492 					&request, &response);
493 	free(buf);
494 	if (!WBC_ERROR_IS_OK(wbc_status)) {
495 		return wbc_status;
496 	}
497 
498 	s = response.extra_data.data;
499 	for (i=0; i<num_ids; i++) {
500 		char *n = strchr(s, '\n');
501 
502 		if (n == NULL) {
503 			goto fail;
504 		}
505 		*n = '\0';
506 
507 		wbc_status = wbcStringToSid(s, &sids[i]);
508 		if (!WBC_ERROR_IS_OK(wbc_status)) {
509 			sids[i] = (struct wbcDomainSid) {0};
510 		}
511 		s = n+1;
512 	}
513 
514 	wbc_status = WBC_ERR_SUCCESS;
515 fail:
516 	winbindd_free_response(&response);
517 	return wbc_status;
518 }
519 
wbcUnixIdsToSids(const struct wbcUnixId * ids,uint32_t num_ids,struct wbcDomainSid * sids)520 wbcErr wbcUnixIdsToSids(const struct wbcUnixId *ids, uint32_t num_ids,
521 			struct wbcDomainSid *sids)
522 {
523 	return wbcCtxUnixIdsToSids(NULL, ids, num_ids, sids);
524 }
525