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
;