source: branches/samba-3.3.x/source/lib/ldb/nssldb/ldb-nss.c

Last change on this file was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

File size: 8.8 KB
Line 
1/*
2 LDB nsswitch module
3
4 Copyright (C) Simo Sorce 2006
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 3 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "ldb-nss.h"
21
22struct _ldb_nss_context *_ldb_nss_ctx = NULL;
23
24NSS_STATUS _ldb_nss_init(void)
25{
26 int ret;
27
28 pid_t mypid = getpid();
29
30 if (_ldb_nss_ctx != NULL) {
31 if (_ldb_nss_ctx->pid == mypid) {
32 /* already initialized */
33 return NSS_STATUS_SUCCESS;
34 } else {
35 /* we are in a forked child now, reinitialize */
36 talloc_free(_ldb_nss_ctx);
37 _ldb_nss_ctx = NULL;
38 }
39 }
40
41 _ldb_nss_ctx = talloc_named(NULL, 0, "_ldb_nss_ctx(%u)", mypid);
42 if (_ldb_nss_ctx == NULL) {
43 return NSS_STATUS_UNAVAIL;
44 }
45
46 _ldb_nss_ctx->pid = mypid;
47
48 ret = ldb_global_init();
49 if (ret != 0) {
50 goto failed;
51 }
52
53 _ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx);
54 if (_ldb_nss_ctx->ldb == NULL) {
55 goto failed;
56 }
57
58 ret = ldb_connect(_ldb_nss_ctx->ldb, _LDB_NSS_URL, LDB_FLG_RDONLY, NULL);
59 if (ret != LDB_SUCCESS) {
60 goto failed;
61 }
62
63 _ldb_nss_ctx->base = ldb_dn_explode(_ldb_nss_ctx, _LDB_NSS_BASEDN);
64 if (_ldb_nss_ctx->base == NULL) {
65 goto failed;
66 }
67
68 _ldb_nss_ctx->pw_cur = 0;
69 _ldb_nss_ctx->pw_res = NULL;
70 _ldb_nss_ctx->gr_cur = 0;
71 _ldb_nss_ctx->gr_res = NULL;
72
73 return NSS_STATUS_SUCCESS;
74
75failed:
76 /* talloc_free(_ldb_nss_ctx); */
77 _ldb_nss_ctx = NULL;
78 return NSS_STATUS_UNAVAIL;
79}
80
81NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result,
82 char *buffer,
83 int buflen,
84 int *errnop,
85 struct ldb_message *msg)
86{
87 int len;
88 int bufpos;
89 const char *tmp;
90
91 bufpos = 0;
92
93 /* get username */
94 tmp = ldb_msg_find_attr_as_string(msg, "uid", NULL);
95 if (tmp == NULL) {
96 /* this is a fatal error */
97 *errnop = errno = ENOENT;
98 return NSS_STATUS_UNAVAIL;
99 }
100 len = strlen(tmp)+1;
101 if (bufpos + len > buflen) {
102 /* buffer too small */
103 *errnop = errno = EAGAIN;
104 return NSS_STATUS_TRYAGAIN;
105 }
106 memcpy(&buffer[bufpos], tmp, len);
107 result->pw_name = &buffer[bufpos];
108 bufpos += len;
109
110 /* get userPassword */
111 tmp = ldb_msg_find_attr_as_string(msg, "userPassword", NULL);
112 if (tmp == NULL) {
113 tmp = "LDB";
114 }
115 len = strlen(tmp)+1;
116 if (bufpos + len > buflen) {
117 /* buffer too small */
118 *errnop = errno = EAGAIN;
119 return NSS_STATUS_TRYAGAIN;
120 }
121 memcpy(&buffer[bufpos], tmp, len);
122 result->pw_passwd = &buffer[bufpos];
123 bufpos += len;
124
125 /* this backend never serves an uid 0 user */
126 result->pw_uid = ldb_msg_find_attr_as_int(msg, "uidNumber", 0);
127 if (result->pw_uid == 0) {
128 /* this is a fatal error */
129 *errnop = errno = ENOENT;
130 return NSS_STATUS_UNAVAIL;
131 }
132
133 result->pw_gid = ldb_msg_find_attr_as_int(msg, "gidNumber", 0);
134 if (result->pw_gid == 0) {
135 /* this is a fatal error */
136 *errnop = errno = ENOENT;
137 return NSS_STATUS_UNAVAIL;
138 }
139
140 /* get gecos */
141 tmp = ldb_msg_find_attr_as_string(msg, "gecos", NULL);
142 if (tmp == NULL) {
143 tmp = "";
144 }
145 len = strlen(tmp)+1;
146 if (bufpos + len > buflen) {
147 /* buffer too small */
148 *errnop = errno = EAGAIN;
149 return NSS_STATUS_TRYAGAIN;
150 }
151 memcpy(&buffer[bufpos], tmp, len);
152 result->pw_gecos = &buffer[bufpos];
153 bufpos += len;
154
155 /* get homeDirectory */
156 tmp = ldb_msg_find_attr_as_string(msg, "homeDirectory", NULL);
157 if (tmp == NULL) {
158 tmp = "";
159 }
160 len = strlen(tmp)+1;
161 if (bufpos + len > buflen) {
162 /* buffer too small */
163 *errnop = errno = EAGAIN;
164 return NSS_STATUS_TRYAGAIN;
165 }
166 memcpy(&buffer[bufpos], tmp, len);
167 result->pw_dir = &buffer[bufpos];
168 bufpos += len;
169
170 /* get shell */
171 tmp = ldb_msg_find_attr_as_string(msg, "loginShell", NULL);
172 if (tmp == NULL) {
173 tmp = "";
174 }
175 len = strlen(tmp)+1;
176 if (bufpos + len > buflen) {
177 /* buffer too small */
178 *errnop = errno = EAGAIN;
179 return NSS_STATUS_TRYAGAIN;
180 }
181 memcpy(&buffer[bufpos], tmp, len);
182 result->pw_shell = &buffer[bufpos];
183 bufpos += len;
184
185 return NSS_STATUS_SUCCESS;
186}
187
188NSS_STATUS _ldb_nss_fill_group(struct group *result,
189 char *buffer,
190 int buflen,
191 int *errnop,
192 struct ldb_message *group,
193 struct ldb_result *members)
194{
195 const char *tmp;
196 size_t len;
197 size_t bufpos;
198 size_t lsize;
199 int i;
200
201 bufpos = 0;
202
203 /* get group name */
204 tmp = ldb_msg_find_attr_as_string(group, "cn", NULL);
205 if (tmp == NULL) {
206 /* this is a fatal error */
207 *errnop = errno = ENOENT;
208 return NSS_STATUS_UNAVAIL;
209 }
210 len = strlen(tmp)+1;
211 if (bufpos + len > buflen) {
212 /* buffer too small */
213 *errnop = errno = EAGAIN;
214 return NSS_STATUS_TRYAGAIN;
215 }
216 memcpy(&buffer[bufpos], tmp, len);
217 result->gr_name = &buffer[bufpos];
218 bufpos += len;
219
220 /* get userPassword */
221 tmp = ldb_msg_find_attr_as_string(group, "userPassword", NULL);
222 if (tmp == NULL) {
223 tmp = "LDB";
224 }
225 len = strlen(tmp)+1;
226 if (bufpos + len > buflen) {
227 /* buffer too small */
228 *errnop = errno = EAGAIN;
229 return NSS_STATUS_TRYAGAIN;
230 }
231 memcpy(&buffer[bufpos], tmp, len);
232 result->gr_passwd = &buffer[bufpos];
233 bufpos += len;
234
235 result->gr_gid = ldb_msg_find_attr_as_int(group, "gidNumber", 0);
236 if (result->gr_gid == 0) {
237 /* this is a fatal error */
238 *errnop = errno = ENOENT;
239 return NSS_STATUS_UNAVAIL;
240 }
241
242 /* check if there is enough memory for the list of pointers */
243 lsize = (members->count + 1) * sizeof(char *);
244
245 /* align buffer on pointer boundary */
246 bufpos += (sizeof(char*) - ((unsigned long)(buffer) % sizeof(char*)));
247 if ((buflen - bufpos) < lsize) {
248 /* buffer too small */
249 *errnop = errno = EAGAIN;
250 return NSS_STATUS_TRYAGAIN;
251 }
252
253 result->gr_mem = (char **)&buffer[bufpos];
254 bufpos += lsize;
255
256 for (i = 0; i < members->count; i++) {
257 tmp = ldb_msg_find_attr_as_string(members->msgs[i], "uid", NULL);
258 if (tmp == NULL) {
259 /* this is a fatal error */
260 *errnop = errno = ENOENT;
261 return NSS_STATUS_UNAVAIL;
262 }
263 len = strlen(tmp)+1;
264 if (bufpos + len > buflen) {
265 /* buffer too small */
266 *errnop = errno = EAGAIN;
267 return NSS_STATUS_TRYAGAIN;
268 }
269 memcpy(&buffer[bufpos], tmp, len);
270 result->gr_mem[i] = &buffer[bufpos];
271 bufpos += len;
272 }
273
274 result->gr_mem[i] = NULL;
275
276 return NSS_STATUS_SUCCESS;
277}
278
279NSS_STATUS _ldb_nss_fill_initgr(gid_t group,
280 long int limit,
281 long int *start,
282 long int *size,
283 gid_t **groups,
284 int *errnop,
285 struct ldb_result *grlist)
286{
287 NSS_STATUS ret;
288 int i;
289
290 for (i = 0; i < grlist->count; i++) {
291
292 if (limit && (*start > limit)) {
293 /* TODO: warn no all groups were reported */
294 *errnop = 0;
295 ret = NSS_STATUS_SUCCESS;
296 goto done;
297 }
298
299 if (*start == *size) {
300 /* buffer full, enlarge it */
301 long int gs;
302 gid_t *gm;
303
304 gs = (*size) + 32;
305 if (limit && (gs > limit)) {
306 gs = limit;
307 }
308
309 gm = (gid_t *)realloc((*groups), gs * sizeof(gid_t));
310 if ( ! gm) {
311 *errnop = ENOMEM;
312 ret = NSS_STATUS_UNAVAIL;
313 goto done;
314 }
315
316 *groups = gm;
317 *size = gs;
318 }
319
320 (*groups)[*start] = ldb_msg_find_attr_as_int(grlist->msgs[i], "gidNumber", 0);
321 if ((*groups)[*start] == 0 || (*groups)[*start] == group) {
322 /* skip root group or primary group */
323 continue;
324 }
325 (*start)++;
326
327 }
328
329 *errnop = 0;
330 ret = NSS_STATUS_SUCCESS;
331done:
332 return ret;
333}
334
335#define _LDB_NSS_ALLOC_CHECK(mem) do { if (!mem) { errno = ENOMEM; return NSS_STATUS_UNAVAIL; } } while(0)
336
337NSS_STATUS _ldb_nss_group_request(struct ldb_result **_res,
338 struct ldb_dn *group_dn,
339 const char * const *attrs,
340 const char *mattr)
341{
342 struct ldb_control **ctrls;
343 struct ldb_control *ctrl;
344 struct ldb_asq_control *asqc;
345 struct ldb_request *req;
346 int ret;
347 struct ldb_result *res = *_res;
348
349 ctrls = talloc_array(res, struct ldb_control *, 2);
350 _LDB_NSS_ALLOC_CHECK(ctrls);
351
352 ctrl = talloc(ctrls, struct ldb_control);
353 _LDB_NSS_ALLOC_CHECK(ctrl);
354
355 asqc = talloc(ctrl, struct ldb_asq_control);
356 _LDB_NSS_ALLOC_CHECK(asqc);
357
358 asqc->source_attribute = talloc_strdup(asqc, mattr);
359 _LDB_NSS_ALLOC_CHECK(asqc->source_attribute);
360
361 asqc->request = 1;
362 asqc->src_attr_len = strlen(asqc->source_attribute);
363 ctrl->oid = LDB_CONTROL_ASQ_OID;
364 ctrl->critical = 1;
365 ctrl->data = asqc;
366 ctrls[0] = ctrl;
367 ctrls[1] = NULL;
368
369 ret = ldb_build_search_req(
370 &req,
371 _ldb_nss_ctx->ldb,
372 res,
373 group_dn,
374 LDB_SCOPE_BASE,
375 "(objectClass=*)",
376 attrs,
377 ctrls,
378 res,
379 ldb_search_default_callback);
380
381 if (ret != LDB_SUCCESS) {
382 errno = ENOENT;
383 return NSS_STATUS_UNAVAIL;
384 }
385
386 ldb_set_timeout(_ldb_nss_ctx->ldb, req, 0);
387
388 ret = ldb_request(_ldb_nss_ctx->ldb, req);
389
390 if (ret == LDB_SUCCESS) {
391 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
392 } else {
393 talloc_free(req);
394 return NSS_STATUS_UNAVAIL;
395 }
396
397 talloc_free(req);
398 return NSS_STATUS_SUCCESS;
399}
400
Note: See TracBrowser for help on using the repository browser.