4 Copyright (C) Simo Sorce 2006
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.
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.
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/>.
22 struct _ldb_nss_context *_ldb_nss_ctx = NULL;
24 NSS_STATUS _ldb_nss_init(void)
28 pid_t mypid = getpid();
30 if (_ldb_nss_ctx != NULL) {
31 if (_ldb_nss_ctx->pid == mypid) {
32 /* already initialized */
33 return NSS_STATUS_SUCCESS;
35 /* we are in a forked child now, reinitialize */
36 talloc_free(_ldb_nss_ctx);
41 _ldb_nss_ctx = talloc_named(NULL, 0, "_ldb_nss_ctx(%u)", mypid);
42 if (_ldb_nss_ctx == NULL) {
43 return NSS_STATUS_UNAVAIL;
46 _ldb_nss_ctx->pid = mypid;
48 _ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx, NULL);
49 if (_ldb_nss_ctx->ldb == NULL) {
53 ret = ldb_connect(_ldb_nss_ctx->ldb, _LDB_NSS_URL, LDB_FLG_RDONLY, NULL);
54 if (ret != LDB_SUCCESS) {
58 _ldb_nss_ctx->base = ldb_dn_new(_ldb_nss_ctx, _ldb_nss_ctx->ldb, _LDB_NSS_BASEDN);
59 if ( ! ldb_dn_validate(_ldb_nss_ctx->base)) {
63 _ldb_nss_ctx->pw_cur = 0;
64 _ldb_nss_ctx->pw_res = NULL;
65 _ldb_nss_ctx->gr_cur = 0;
66 _ldb_nss_ctx->gr_res = NULL;
68 return NSS_STATUS_SUCCESS;
71 /* talloc_free(_ldb_nss_ctx); */
73 return NSS_STATUS_UNAVAIL;
76 NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result,
80 struct ldb_message *msg)
89 tmp = ldb_msg_find_attr_as_string(msg, "uid", NULL);
91 /* this is a fatal error */
92 *errnop = errno = ENOENT;
93 return NSS_STATUS_UNAVAIL;
96 if (bufpos + len > buflen) {
97 /* buffer too small */
98 *errnop = errno = EAGAIN;
99 return NSS_STATUS_TRYAGAIN;
101 memcpy(&buffer[bufpos], tmp, len);
102 result->pw_name = &buffer[bufpos];
105 /* get userPassword */
106 tmp = ldb_msg_find_attr_as_string(msg, "userPassword", NULL);
111 if (bufpos + len > buflen) {
112 /* buffer too small */
113 *errnop = errno = EAGAIN;
114 return NSS_STATUS_TRYAGAIN;
116 memcpy(&buffer[bufpos], tmp, len);
117 result->pw_passwd = &buffer[bufpos];
120 /* this backend never serves an uid 0 user */
121 result->pw_uid = ldb_msg_find_attr_as_int(msg, "uidNumber", 0);
122 if (result->pw_uid == 0) {
123 /* this is a fatal error */
124 *errnop = errno = ENOENT;
125 return NSS_STATUS_UNAVAIL;
128 result->pw_gid = ldb_msg_find_attr_as_int(msg, "gidNumber", 0);
129 if (result->pw_gid == 0) {
130 /* this is a fatal error */
131 *errnop = errno = ENOENT;
132 return NSS_STATUS_UNAVAIL;
136 tmp = ldb_msg_find_attr_as_string(msg, "gecos", NULL);
141 if (bufpos + len > buflen) {
142 /* buffer too small */
143 *errnop = errno = EAGAIN;
144 return NSS_STATUS_TRYAGAIN;
146 memcpy(&buffer[bufpos], tmp, len);
147 result->pw_gecos = &buffer[bufpos];
150 /* get homeDirectory */
151 tmp = ldb_msg_find_attr_as_string(msg, "homeDirectory", NULL);
156 if (bufpos + len > buflen) {
157 /* buffer too small */
158 *errnop = errno = EAGAIN;
159 return NSS_STATUS_TRYAGAIN;
161 memcpy(&buffer[bufpos], tmp, len);
162 result->pw_dir = &buffer[bufpos];
166 tmp = ldb_msg_find_attr_as_string(msg, "loginShell", NULL);
171 if (bufpos + len > buflen) {
172 /* buffer too small */
173 *errnop = errno = EAGAIN;
174 return NSS_STATUS_TRYAGAIN;
176 memcpy(&buffer[bufpos], tmp, len);
177 result->pw_shell = &buffer[bufpos];
180 return NSS_STATUS_SUCCESS;
183 NSS_STATUS _ldb_nss_fill_group(struct group *result,
187 struct ldb_message *group,
188 struct ldb_result *members)
199 tmp = ldb_msg_find_attr_as_string(group, "cn", NULL);
201 /* this is a fatal error */
202 *errnop = errno = ENOENT;
203 return NSS_STATUS_UNAVAIL;
206 if (bufpos + len > buflen) {
207 /* buffer too small */
208 *errnop = errno = EAGAIN;
209 return NSS_STATUS_TRYAGAIN;
211 memcpy(&buffer[bufpos], tmp, len);
212 result->gr_name = &buffer[bufpos];
215 /* get userPassword */
216 tmp = ldb_msg_find_attr_as_string(group, "userPassword", NULL);
221 if (bufpos + len > buflen) {
222 /* buffer too small */
223 *errnop = errno = EAGAIN;
224 return NSS_STATUS_TRYAGAIN;
226 memcpy(&buffer[bufpos], tmp, len);
227 result->gr_passwd = &buffer[bufpos];
230 result->gr_gid = ldb_msg_find_attr_as_int(group, "gidNumber", 0);
231 if (result->gr_gid == 0) {
232 /* this is a fatal error */
233 *errnop = errno = ENOENT;
234 return NSS_STATUS_UNAVAIL;
237 /* check if there is enough memory for the list of pointers */
238 lsize = (members->count + 1) * sizeof(char *);
240 /* align buffer on pointer boundary */
241 bufpos += (sizeof(char*) - ((unsigned long)(buffer) % sizeof(char*)));
242 if ((buflen - bufpos) < lsize) {
243 /* buffer too small */
244 *errnop = errno = EAGAIN;
245 return NSS_STATUS_TRYAGAIN;
248 result->gr_mem = (char **)&buffer[bufpos];
251 for (i = 0; i < members->count; i++) {
252 tmp = ldb_msg_find_attr_as_string(members->msgs[i], "uid", NULL);
254 /* this is a fatal error */
255 *errnop = errno = ENOENT;
256 return NSS_STATUS_UNAVAIL;
259 if (bufpos + len > buflen) {
260 /* buffer too small */
261 *errnop = errno = EAGAIN;
262 return NSS_STATUS_TRYAGAIN;
264 memcpy(&buffer[bufpos], tmp, len);
265 result->gr_mem[i] = &buffer[bufpos];
269 result->gr_mem[i] = NULL;
271 return NSS_STATUS_SUCCESS;
274 NSS_STATUS _ldb_nss_fill_initgr(gid_t group,
280 struct ldb_result *grlist)
285 for (i = 0; i < grlist->count; i++) {
287 if (limit && (*start > limit)) {
288 /* TODO: warn no all groups were reported */
290 ret = NSS_STATUS_SUCCESS;
294 if (*start == *size) {
295 /* buffer full, enlarge it */
300 if (limit && (gs > limit)) {
304 gm = (gid_t *)realloc((*groups), gs * sizeof(gid_t));
307 ret = NSS_STATUS_UNAVAIL;
315 (*groups)[*start] = ldb_msg_find_attr_as_int(grlist->msgs[i], "gidNumber", 0);
316 if ((*groups)[*start] == 0 || (*groups)[*start] == group) {
317 /* skip root group or primary group */
325 ret = NSS_STATUS_SUCCESS;
330 #define _LDB_NSS_ALLOC_CHECK(mem) do { if (!mem) { errno = ENOMEM; return NSS_STATUS_UNAVAIL; } } while(0)
332 NSS_STATUS _ldb_nss_group_request(struct ldb_result **_res,
333 struct ldb_dn *group_dn,
334 const char * const *attrs,
337 struct ldb_control **ctrls;
338 struct ldb_control *ctrl;
339 struct ldb_asq_control *asqc;
340 struct ldb_request *req;
342 struct ldb_result *res = *_res;
344 ctrls = talloc_array(res, struct ldb_control *, 2);
345 _LDB_NSS_ALLOC_CHECK(ctrls);
347 ctrl = talloc(ctrls, struct ldb_control);
348 _LDB_NSS_ALLOC_CHECK(ctrl);
350 asqc = talloc(ctrl, struct ldb_asq_control);
351 _LDB_NSS_ALLOC_CHECK(asqc);
353 asqc->source_attribute = talloc_strdup(asqc, mattr);
354 _LDB_NSS_ALLOC_CHECK(asqc->source_attribute);
357 asqc->src_attr_len = strlen(asqc->source_attribute);
358 ctrl->oid = LDB_CONTROL_ASQ_OID;
364 ret = ldb_build_search_req(
374 ldb_search_default_callback);
376 if (ret != LDB_SUCCESS) {
378 return NSS_STATUS_UNAVAIL;
381 ldb_set_timeout(_ldb_nss_ctx->ldb, req, 0);
383 ret = ldb_request(_ldb_nss_ctx->ldb, req);
385 if (ret == LDB_SUCCESS) {
386 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
389 return NSS_STATUS_UNAVAIL;
393 return NSS_STATUS_SUCCESS;