2 Unix SMB/CIFS implementation.
6 Copyright (C) Simo Sorce 2006
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program 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
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/passwd.h"
25 #include "nsswitch/winbind_client.h"
27 #include "lib/winbind_util.h"
28 #include "libcli/security/dom_sid.h"
29 #include "lib/global_contexts.h"
33 #define DBGC_CLASS DBGC_IDMAP
35 struct idmap_nss_context
{
36 struct idmap_domain
*dom
;
40 static int idmap_nss_context_destructor(struct idmap_nss_context
*ctx
)
42 if ((ctx
->dom
!= NULL
) && (ctx
->dom
->private_data
== ctx
)) {
43 ctx
->dom
->private_data
= NULL
;
48 static NTSTATUS
idmap_nss_context_create(TALLOC_CTX
*mem_ctx
,
49 struct idmap_domain
*dom
,
50 struct idmap_nss_context
**pctx
)
52 struct idmap_nss_context
*ctx
= NULL
;
54 ctx
= talloc_zero(mem_ctx
, struct idmap_nss_context
);
56 return NT_STATUS_NO_MEMORY
;
60 talloc_set_destructor(ctx
, idmap_nss_context_destructor
);
62 ctx
->use_upn
= idmap_config_bool(dom
->name
, "use_upn", false);
68 static NTSTATUS
idmap_nss_get_context(struct idmap_domain
*dom
,
69 struct idmap_nss_context
**pctx
)
71 struct idmap_nss_context
*ctx
= NULL
;
74 if (dom
->private_data
!= NULL
) {
75 *pctx
= talloc_get_type_abort(dom
->private_data
,
76 struct idmap_nss_context
);
80 status
= idmap_nss_context_create(dom
, dom
, &ctx
);
81 if (!NT_STATUS_IS_OK(status
)) {
82 DBG_WARNING("idmap_nss_context_create failed: %s\n",
87 dom
->private_data
= ctx
;
92 static bool idmap_nss_msg_filter(struct messaging_rec
*rec
, void *private_data
)
94 struct idmap_domain
*dom
= talloc_get_type_abort(private_data
,
96 struct idmap_nss_context
*ctx
= NULL
;
100 if (rec
->msg_type
== MSG_SMB_CONF_UPDATED
) {
101 ret
= lp_load_global(get_dyn_CONFIGFILE());
103 DBG_WARNING("Failed to reload configuration\n");
107 status
= idmap_nss_get_context(dom
, &ctx
);
108 if (NT_STATUS_IS_ERR(status
)) {
109 DBG_WARNING("Failed to get idmap nss context: %s\n",
114 ctx
->use_upn
= idmap_config_bool(dom
->name
, "use_upn", false);
120 /*****************************
121 Initialise idmap database.
122 *****************************/
124 static NTSTATUS
idmap_nss_int_init(struct idmap_domain
*dom
)
126 struct idmap_nss_context
*ctx
= NULL
;
128 struct messaging_context
*msg_ctx
= global_messaging_context();
129 struct tevent_req
*req
= NULL
;
131 status
= idmap_nss_context_create(dom
, dom
, &ctx
);
132 if (NT_STATUS_IS_ERR(status
)) {
136 dom
->private_data
= ctx
;
138 req
= messaging_filtered_read_send(
140 messaging_tevent_context(msg_ctx
),
142 idmap_nss_msg_filter
,
145 DBG_WARNING("messaging_filtered_read_send failed\n");
146 return NT_STATUS_UNSUCCESSFUL
;
152 static NTSTATUS
idmap_nss_lookup_name(const char *namespace,
153 const char *username
,
155 enum lsa_SidType
*type
)
160 * By default calls to winbindd are disabled
161 * the following call will not recurse so this is safe
164 ret
= winbind_lookup_name(namespace, username
, sid
, type
);
168 DBG_NOTICE("Failed to lookup name [%s] in namespace [%s]\n",
169 username
, namespace);
170 return NT_STATUS_NOT_FOUND
;
176 /**********************************
177 lookup a set of unix ids.
178 **********************************/
180 static NTSTATUS
idmap_nss_unixids_to_sids(struct idmap_domain
*dom
, struct id_map
**ids
)
182 struct idmap_nss_context
*ctx
= NULL
;
186 status
= idmap_nss_get_context(dom
, &ctx
);
187 if (NT_STATUS_IS_ERR(status
)) {
188 DBG_WARNING("Failed to get idmap nss context: %s\n",
193 /* initialize the status to avoid surprise */
194 for (i
= 0; ids
[i
]; i
++) {
195 ids
[i
]->status
= ID_UNKNOWN
;
198 for (i
= 0; ids
[i
]; i
++) {
203 enum lsa_SidType type
;
205 switch (ids
[i
]->xid
.type
) {
208 pw
= getpwuid((uid_t
)ids
[i
]->xid
.id
);
210 DBG_DEBUG("getpwuid(%lu) failed: %s\n",
211 (unsigned long)ids
[i
]->xid
.id
,
215 ids
[i
]->status
= ID_UNMAPPED
;
222 gr
= getgrgid((gid_t
)ids
[i
]->xid
.id
);
224 DBG_DEBUG("getgrgid(%lu) failed: %s\n",
225 (unsigned long)ids
[i
]->xid
.id
,
229 ids
[i
]->status
= ID_UNMAPPED
;
235 DBG_WARNING("Unexpected xid type %d\n",
237 ids
[i
]->status
= ID_UNKNOWN
;
241 /* Lookup name from PDC using lsa_lookup_names() */
244 const char *namespace = NULL
;
245 const char *domname
= NULL
;
246 const char *domuser
= NULL
;
248 p
= strstr(name
, lp_winbind_separator());
255 p
= strchr(name
, '@');
262 namespace = dom
->name
;
267 DBG_DEBUG("Using namespace [%s] from UPN instead "
268 "of [%s] to lookup the name [%s]\n",
269 namespace, dom
->name
, domuser
);
271 status
= idmap_nss_lookup_name(namespace,
276 status
= idmap_nss_lookup_name(dom
->name
,
282 if (NT_STATUS_IS_ERR(status
)) {
284 * TODO: how do we know if the name is really
285 * not mapped, or something just failed ?
287 ids
[i
]->status
= ID_UNMAPPED
;
293 if (ids
[i
]->xid
.type
== ID_TYPE_UID
) {
294 sid_copy(ids
[i
]->sid
, &sid
);
295 ids
[i
]->status
= ID_MAPPED
;
299 case SID_NAME_DOM_GRP
:
301 case SID_NAME_WKN_GRP
:
302 if (ids
[i
]->xid
.type
== ID_TYPE_GID
) {
303 sid_copy(ids
[i
]->sid
, &sid
);
304 ids
[i
]->status
= ID_MAPPED
;
309 ids
[i
]->status
= ID_UNKNOWN
;
316 /**********************************
317 lookup a set of sids.
318 **********************************/
320 static NTSTATUS
idmap_nss_sids_to_unixids(struct idmap_domain
*dom
, struct id_map
**ids
)
322 struct idmap_nss_context
*ctx
= NULL
;
326 status
= idmap_nss_get_context(dom
, &ctx
);
327 if (NT_STATUS_IS_ERR(status
)) {
328 DBG_WARNING("Failed to get idmap nss context: %s\n",
333 /* initialize the status to avoid surprise */
334 for (i
= 0; ids
[i
]; i
++) {
335 ids
[i
]->status
= ID_UNKNOWN
;
338 for (i
= 0; ids
[i
]; i
++) {
340 enum lsa_SidType type
;
341 const char *_domain
= NULL
;
342 const char *_name
= NULL
;
349 /* by default calls to winbindd are disabled
350 the following call will not recurse so this is safe */
352 ret
= winbind_lookup_sid(talloc_tos(),
359 /* TODO: how do we know if the name is really not mapped,
360 * or something just failed ? */
361 ids
[i
]->status
= ID_UNMAPPED
;
365 domain
= discard_const_p(char, _domain
);
366 name
= discard_const_p(char, _name
);
368 if (!strequal(domain
, dom
->name
)) {
369 struct dom_sid_buf buf
;
370 DBG_ERR("DOMAIN[%s] ignoring SID[%s] belongs to %s [%s\\%s]\n",
371 dom
->name
, dom_sid_str_buf(ids
[i
]->sid
, &buf
),
372 sid_type_lookup(type
), domain
, name
);
373 ids
[i
]->status
= ID_UNMAPPED
;
378 fqdn
= talloc_asprintf(talloc_tos(),
381 lp_winbind_separator(),
384 DBG_ERR("No memory\n");
385 ids
[i
]->status
= ID_UNMAPPED
;
388 DBG_DEBUG("Using UPN [%s] instead of plain name [%s]\n",
396 case SID_NAME_USER
: {
399 /* this will find also all lower case name and use username level */
400 pw
= Get_Pwnam_alloc(talloc_tos(), sname
);
402 ids
[i
]->xid
.id
= pw
->pw_uid
;
403 ids
[i
]->xid
.type
= ID_TYPE_UID
;
404 ids
[i
]->status
= ID_MAPPED
;
410 case SID_NAME_DOM_GRP
:
412 case SID_NAME_WKN_GRP
:
414 gr
= getgrnam(sname
);
416 ids
[i
]->xid
.id
= gr
->gr_gid
;
417 ids
[i
]->xid
.type
= ID_TYPE_GID
;
418 ids
[i
]->status
= ID_MAPPED
;
423 ids
[i
]->status
= ID_UNKNOWN
;
433 /**********************************
434 Close the idmap tdb instance
435 **********************************/
437 static const struct idmap_methods nss_methods
= {
438 .init
= idmap_nss_int_init
,
439 .unixids_to_sids
= idmap_nss_unixids_to_sids
,
440 .sids_to_unixids
= idmap_nss_sids_to_unixids
,
443 NTSTATUS
idmap_nss_init(TALLOC_CTX
*mem_ctx
)
445 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "nss", &nss_methods
);