1/* 2 Unix SMB/CIFS implementation. 3 ID Mapping 4 Copyright (C) Tim Potter 2000 5 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 6 Copyright (C) Simo Sorce 2003 7 Copyright (C) Jeremy Allison 2003. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/ 22 23#include "includes.h" 24 25#undef DBGC_CLASS 26#define DBGC_CLASS DBGC_IDMAP 27 28struct idmap_function_entry { 29 const char *name; 30 struct idmap_methods *methods; 31 struct idmap_function_entry *prev,*next; 32}; 33 34static struct idmap_function_entry *backends = NULL; 35 36static struct idmap_methods *cache_map; 37static struct idmap_methods *remote_map; 38 39static BOOL proxyonly = False; 40 41/********************************************************************** 42 Get idmap methods. Don't allow tdb to be a remote method. 43**********************************************************************/ 44 45static struct idmap_methods *get_methods(const char *name, BOOL cache_method) 46{ 47 struct idmap_function_entry *entry = backends; 48 49 for(entry = backends; entry; entry = entry->next) { 50 if (!cache_method && strequal(entry->name, "tdb")) 51 continue; /* tdb is only cache method. */ 52 if (strequal(entry->name, name)) 53 return entry->methods; 54 } 55 56 return NULL; 57} 58 59/********************************************************************** 60 Allow a module to register itself as a method. 61**********************************************************************/ 62 63NTSTATUS smb_register_idmap(int version, const char *name, struct idmap_methods *methods) 64{ 65 struct idmap_function_entry *entry; 66 67 if ((version != SMB_IDMAP_INTERFACE_VERSION)) { 68 DEBUG(0, ("smb_register_idmap: Failed to register idmap module.\n" 69 "The module was compiled against SMB_IDMAP_INTERFACE_VERSION %d,\n" 70 "current SMB_IDMAP_INTERFACE_VERSION is %d.\n" 71 "Please recompile against the current version of samba!\n", 72 version, SMB_IDMAP_INTERFACE_VERSION)); 73 return NT_STATUS_OBJECT_TYPE_MISMATCH; 74 } 75 76 if (!name || !name[0] || !methods) { 77 DEBUG(0,("smb_register_idmap: called with NULL pointer or empty name!\n")); 78 return NT_STATUS_INVALID_PARAMETER; 79 } 80 81 if (get_methods(name, False)) { 82 DEBUG(0,("smb_register_idmap: idmap module %s already registered!\n", name)); 83 return NT_STATUS_OBJECT_NAME_COLLISION; 84 } 85 86 entry = SMB_XMALLOC_P(struct idmap_function_entry); 87 entry->name = smb_xstrdup(name); 88 entry->methods = methods; 89 90 DLIST_ADD(backends, entry); 91 DEBUG(5, ("smb_register_idmap: Successfully added idmap backend '%s'\n", name)); 92 return NT_STATUS_OK; 93} 94 95/********************************************************************** 96 Initialise idmap cache and a remote backend (if configured). 97**********************************************************************/ 98 99BOOL idmap_init(const char **remote_backend) 100{ 101 if (!backends) 102 static_init_idmap; 103 104 if (!cache_map) { 105 cache_map = get_methods("tdb", True); 106 107 if (!cache_map) { 108 DEBUG(0, ("idmap_init: could not find tdb cache backend!\n")); 109 return False; 110 } 111 112 if (!NT_STATUS_IS_OK(cache_map->init( NULL ))) { 113 DEBUG(0, ("idmap_init: could not initialise tdb cache backend!\n")); 114 return False; 115 } 116 } 117 118 if ((remote_map == NULL) && (remote_backend != NULL) && 119 (*remote_backend != NULL) && (**remote_backend != '\0')) { 120 char *rem_backend = smb_xstrdup(*remote_backend); 121 fstring params = ""; 122 char *pparams; 123 124 /* get any mode parameters passed in */ 125 126 if ( (pparams = strchr( rem_backend, ':' )) != NULL ) { 127 *pparams = '\0'; 128 pparams++; 129 fstrcpy( params, pparams ); 130 } 131 132 DEBUG(3, ("idmap_init: using '%s' as remote backend\n", rem_backend)); 133 134 if((remote_map = get_methods(rem_backend, False)) || 135 (NT_STATUS_IS_OK(smb_probe_module("idmap", rem_backend)) && 136 (remote_map = get_methods(rem_backend, False)))) { 137 if (!NT_STATUS_IS_OK(remote_map->init(params))) { 138 DEBUG(0, ("idmap_init: failed to initialize remote backend!\n")); 139 return False; 140 } 141 } else { 142 DEBUG(0, ("idmap_init: could not load remote backend '%s'\n", rem_backend)); 143 SAFE_FREE(rem_backend); 144 return False; 145 } 146 SAFE_FREE(rem_backend); 147 } 148 149 return True; 150} 151 152/************************************************************************** 153 Don't do id mapping. This is used to make winbind a netlogon proxy only. 154**************************************************************************/ 155 156void idmap_proxyonly(void) 157{ 158 proxyonly = True; 159} 160 161/************************************************************************** 162 This is a rare operation, designed to allow an explicit mapping to be 163 set up for a sid to a POSIX id. 164**************************************************************************/ 165 166NTSTATUS idmap_set_mapping(const DOM_SID *sid, unid_t id, int id_type) 167{ 168 struct idmap_methods *map = remote_map; 169 DOM_SID tmp_sid; 170 171 if (proxyonly) 172 return NT_STATUS_UNSUCCESSFUL; 173 174 DEBUG(10, ("idmap_set_mapping: Set %s to %s %lu\n", 175 sid_string_static(sid), 176 ((id_type & ID_TYPEMASK) == ID_USERID) ? "UID" : "GID", 177 ((id_type & ID_TYPEMASK) == ID_USERID) ? (unsigned long)id.uid : 178 (unsigned long)id.gid)); 179 180 if ( (NT_STATUS_IS_OK(cache_map-> 181 get_sid_from_id(&tmp_sid, id, 182 id_type | ID_QUERY_ONLY))) && 183 sid_equal(sid, &tmp_sid) ) { 184 /* Nothing to do, we already have that mapping */ 185 DEBUG(10, ("idmap_set_mapping: Mapping already there\n")); 186 return NT_STATUS_OK; 187 } 188 189 if (map == NULL) { 190 /* Ok, we don't have a authoritative remote 191 mapping. So update our local cache only. */ 192 map = cache_map; 193 } 194 195 return map->set_mapping(sid, id, id_type); 196} 197 198/************************************************************************** 199 Get ID from SID. This can create a mapping for a SID to a POSIX id. 200**************************************************************************/ 201 202NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid) 203{ 204 NTSTATUS ret; 205 int loc_type; 206 unid_t loc_id; 207 208 if (proxyonly) 209 return NT_STATUS_UNSUCCESSFUL; 210 211 loc_type = *id_type; 212 213 if (remote_map) { 214 /* We have a central remote idmap so only look in 215 cache, don't allocate */ 216 loc_type |= ID_QUERY_ONLY; 217 } 218 219 ret = cache_map->get_id_from_sid(id, &loc_type, sid); 220 221 if (NT_STATUS_IS_OK(ret)) { 222 *id_type = loc_type & ID_TYPEMASK; 223 return NT_STATUS_OK; 224 } 225 226 if (remote_map == NULL) { 227 return ret; 228 } 229 230 /* Before forking out to the possibly slow remote map, lets see if we 231 * already have the sid as uid when asking for a gid or vice versa. */ 232 233 loc_type = *id_type & ID_TYPEMASK; 234 235 switch (loc_type) { 236 case ID_USERID: 237 loc_type = ID_GROUPID; 238 break; 239 case ID_GROUPID: 240 loc_type = ID_USERID; 241 break; 242 default: 243 loc_type = ID_EMPTY; 244 } 245 246 loc_type |= ID_QUERY_ONLY; 247 248 ret = cache_map->get_id_from_sid(&loc_id, &loc_type, sid); 249 250 if (NT_STATUS_IS_OK(ret)) { 251 /* Ok, we have the uid as gid or vice versa. The remote map 252 * would not know anything different, so return here. */ 253 return NT_STATUS_UNSUCCESSFUL; 254 } 255 256 /* Ok, the mapping was not in the cache, give the remote map a 257 second try. */ 258 259 ret = remote_map->get_id_from_sid(id, id_type, sid); 260 261 if (NT_STATUS_IS_OK(ret)) { 262 /* The remote backend gave us a valid mapping, cache it. */ 263 ret = cache_map->set_mapping(sid, *id, *id_type); 264 } 265 266 return ret; 267} 268 269/************************************************************************** 270 Get SID from ID. This must have been created before. 271**************************************************************************/ 272 273NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type) 274{ 275 NTSTATUS ret; 276 int loc_type; 277 278 if (proxyonly) 279 return NT_STATUS_UNSUCCESSFUL; 280 281 loc_type = id_type; 282 if (remote_map) { 283 loc_type = id_type | ID_QUERY_ONLY; 284 } 285 286 ret = cache_map->get_sid_from_id(sid, id, loc_type); 287 288 if (NT_STATUS_IS_OK(ret)) 289 return ret; 290 291 if (remote_map == NULL) 292 return ret; 293 294 /* We have a second chance, ask our authoritative backend */ 295 296 ret = remote_map->get_sid_from_id(sid, id, id_type); 297 298 if (NT_STATUS_IS_OK(ret)) { 299 /* The remote backend gave us a valid mapping, cache it. */ 300 ret = cache_map->set_mapping(sid, id, id_type); 301 } 302 303 return ret; 304} 305 306/************************************************************************** 307 Alloocate a new UNIX uid/gid 308**************************************************************************/ 309 310NTSTATUS idmap_allocate_id(unid_t *id, int id_type) 311{ 312 /* we have to allocate from the authoritative backend */ 313 314 if (proxyonly) 315 return NT_STATUS_UNSUCCESSFUL; 316 317 if ( remote_map ) 318 return remote_map->allocate_id( id, id_type ); 319 320 return cache_map->allocate_id( id, id_type ); 321} 322 323/************************************************************************** 324 Alloocate a new RID 325**************************************************************************/ 326 327NTSTATUS idmap_allocate_rid(uint32 *rid, int type) 328{ 329 /* we have to allocate from the authoritative backend */ 330 331 if (proxyonly) 332 return NT_STATUS_UNSUCCESSFUL; 333 334 if ( remote_map ) 335 return remote_map->allocate_rid( rid, type ); 336 337 return cache_map->allocate_rid( rid, type ); 338} 339 340/************************************************************************** 341 Shutdown maps. 342**************************************************************************/ 343 344NTSTATUS idmap_close(void) 345{ 346 NTSTATUS ret; 347 348 if (proxyonly) 349 return NT_STATUS_OK; 350 351 ret = cache_map->close(); 352 if (!NT_STATUS_IS_OK(ret)) { 353 DEBUG(3, ("idmap_close: failed to close local tdb cache!\n")); 354 } 355 cache_map = NULL; 356 357 if (remote_map) { 358 ret = remote_map->close(); 359 if (!NT_STATUS_IS_OK(ret)) { 360 DEBUG(3, ("idmap_close: failed to close remote idmap repository!\n")); 361 } 362 remote_map = NULL; 363 } 364 365 return ret; 366} 367 368/************************************************************************** 369 Dump backend status. 370**************************************************************************/ 371 372void idmap_status(void) 373{ 374 cache_map->status(); 375 if (remote_map) 376 remote_map->status(); 377} 378