root/source3/winbindd/idmap_hash/idmap_hash.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hash_domain_sid
  2. hash_rid
  3. combine_hashes
  4. separate_hashes
  5. be_init
  6. unixids_to_sids
  7. sids_to_unixids
  8. be_close
  9. nss_hash_init
  10. nss_hash_get_info
  11. nss_hash_map_to_alias
  12. nss_hash_map_from_alias
  13. nss_hash_close
  14. idmap_hash_init

   1 /*
   2  *  idmap_hash.c
   3  *
   4  * Copyright (C) Gerald Carter  <jerry@samba.org>      2007 - 2008
   5  *
   6  *  This program is free software; you can redistribute it and/or modify
   7  *  it under the terms of the GNU General Public License as published by
   8  *  the Free Software Foundation; either version 3 of the License, or
   9  *  (at your option) any later version.
  10  *
  11  *  This program 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
  14  *  GNU General Public License for more details.
  15  *
  16  *  You should have received a copy of the GNU General Public License
  17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  18  *
  19  */
  20 
  21 #include "includes.h"
  22 #include "winbindd/winbindd.h"
  23 #include "idmap_hash.h"
  24 
  25 #undef DBGC_CLASS
  26 #define DBGC_CLASS DBGC_IDMAP
  27 
  28 struct sid_hash_table {
  29         DOM_SID *sid;
  30 };
  31 
  32 struct sid_hash_table *hashed_domains = NULL;
  33 
  34 /*********************************************************************
  35  Hash a domain SID (S-1-5-12-aaa-bbb-ccc) to a 12bit number
  36  ********************************************************************/
  37 
  38 static uint32_t hash_domain_sid(const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
  39 {
  40         uint32_t hash;
  41 
  42         if (sid->num_auths != 4)
  43                 return 0;
  44 
  45         /* XOR the last three subauths */
  46 
  47         hash = ((sid->sub_auths[1] ^ sid->sub_auths[2]) ^ sid->sub_auths[3]);
  48 
  49         /* Take all 32-bits into account when generating the 12-bit
  50            hash value */
  51         hash = (((hash & 0xFFF00000) >> 20)
  52                 + ((hash & 0x000FFF00) >> 8)
  53                 + (hash & 0x000000FF)) & 0x0000FFF;
  54 
  55         /* return a 12-bit hash value */
  56 
  57         return hash;
  58 }
  59 
  60 /*********************************************************************
  61  Hash a Relative ID to a 20 bit number
  62  ********************************************************************/
  63 
  64 static uint32_t hash_rid(uint32_t rid)
     /* [<][>][^][v][top][bottom][index][help] */
  65 {
  66         /* 20 bits for the rid which allows us to support
  67            the first 100K users/groups in a domain */
  68 
  69         return (rid & 0x0007FFFF);
  70 }
  71 
  72 /*********************************************************************
  73  ********************************************************************/
  74 
  75 static uint32_t combine_hashes(uint32_t h_domain,
     /* [<][>][^][v][top][bottom][index][help] */
  76                                uint32_t h_rid)
  77 {
  78         uint32_t return_id = 0;
  79 
  80         /* shift the hash_domain 19 bits to the left and OR with the
  81            hash_rid */
  82 
  83         return_id = ((h_domain<<19) | h_rid);
  84 
  85         return return_id;
  86 }
  87 
  88 /*********************************************************************
  89  ********************************************************************/
  90 
  91 static void separate_hashes(uint32_t id,
     /* [<][>][^][v][top][bottom][index][help] */
  92                             uint32_t *h_domain,
  93                             uint32_t *h_rid)
  94 {
  95         *h_rid = id & 0x0007FFFF;
  96         *h_domain = (id & 0x7FF80000) >> 19;
  97 
  98         return;
  99 }
 100 
 101 
 102 /*********************************************************************
 103  ********************************************************************/
 104 
 105 static NTSTATUS be_init(struct idmap_domain *dom,
     /* [<][>][^][v][top][bottom][index][help] */
 106                         const char *params)
 107 {
 108         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 109         struct winbindd_tdc_domain *dom_list = NULL;
 110         size_t num_domains = 0;
 111         int i;
 112 
 113         /* If the domain SID hash talbe has been initialized, assume
 114            that we completed this function previously */
 115 
 116         if ( hashed_domains ) {
 117                 nt_status = NT_STATUS_OK;
 118                 goto done;
 119         }
 120 
 121         if (!wcache_tdc_fetch_list(&dom_list, &num_domains)) {
 122                 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
 123                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 124         }
 125 
 126         /* Create the hash table of domain SIDs */
 127 
 128         hashed_domains = TALLOC_ZERO_ARRAY(NULL, struct sid_hash_table, 4096);
 129         BAIL_ON_PTR_NT_ERROR(hashed_domains, nt_status);
 130 
 131         /* create the hash table of domain SIDs */
 132 
 133         for (i=0; i<num_domains; i++) {
 134                 uint32_t hash;
 135 
 136                 if (is_null_sid(&dom_list[i].sid))
 137                         continue;
 138                 if ((hash = hash_domain_sid(&dom_list[i].sid)) == 0)
 139                         continue;
 140 
 141                 DEBUG(5,("hash:be_init() Adding %s (%s) -> %d\n",
 142                          dom_list[i].domain_name,
 143                          sid_string_dbg(&dom_list[i].sid),
 144                          hash));
 145 
 146                 hashed_domains[hash].sid = talloc(hashed_domains, DOM_SID);
 147                 sid_copy(hashed_domains[hash].sid, &dom_list[i].sid);
 148         }
 149 
 150 done:
 151         return nt_status;
 152 }
 153 
 154 /*********************************************************************
 155  ********************************************************************/
 156 
 157 static NTSTATUS unixids_to_sids(struct idmap_domain *dom,
     /* [<][>][^][v][top][bottom][index][help] */
 158                                 struct id_map **ids)
 159 {
 160         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 161         int i;
 162 
 163         /* initialize the status to avoid suprise */
 164         for (i = 0; ids[i]; i++) {
 165                 ids[i]->status = ID_UNKNOWN;
 166         }
 167         
 168         nt_status = be_init(dom, NULL);
 169         BAIL_ON_NTSTATUS_ERROR(nt_status);
 170 
 171         if (!ids) {
 172                 nt_status = NT_STATUS_INVALID_PARAMETER;
 173                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 174         }
 175 
 176         for (i=0; ids[i]; i++) {
 177                 uint32_t h_domain, h_rid;
 178 
 179                 ids[i]->status = ID_UNMAPPED;
 180 
 181                 separate_hashes(ids[i]->xid.id, &h_domain, &h_rid);
 182 
 183                 /* Make sure the caller allocated memor for us */
 184 
 185                 if (!ids[i]->sid) {
 186                         nt_status = NT_STATUS_INVALID_PARAMETER;
 187                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 188                 }
 189 
 190                 /* If the domain hash doesn't find a SID in the table,
 191                    skip it */
 192 
 193                 if (!hashed_domains[h_domain].sid)
 194                         continue;
 195 
 196                 sid_copy(ids[i]->sid, hashed_domains[h_domain].sid);
 197                 sid_append_rid(ids[i]->sid, h_rid);
 198                 ids[i]->status = ID_MAPPED;
 199         }
 200 
 201 done:
 202         return nt_status;
 203 }
 204 
 205 /*********************************************************************
 206  ********************************************************************/
 207 
 208 static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
     /* [<][>][^][v][top][bottom][index][help] */
 209                                 struct id_map **ids)
 210 {
 211         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 212         int i;
 213 
 214         /* initialize the status to avoid suprise */
 215         for (i = 0; ids[i]; i++) {
 216                 ids[i]->status = ID_UNKNOWN;
 217         }
 218         
 219         nt_status = be_init(dom, NULL);
 220         BAIL_ON_NTSTATUS_ERROR(nt_status);
 221 
 222         if (!ids) {
 223                 nt_status = NT_STATUS_INVALID_PARAMETER;
 224                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 225         }
 226 
 227         for (i=0; ids[i]; i++) {
 228                 DOM_SID sid;
 229                 uint32_t rid;
 230                 uint32_t h_domain, h_rid;
 231 
 232                 ids[i]->status = ID_UNMAPPED;
 233 
 234                 sid_copy(&sid, ids[i]->sid);
 235                 sid_split_rid(&sid, &rid);
 236 
 237                 h_domain = hash_domain_sid(&sid);
 238                 h_rid = hash_rid(rid);
 239 
 240                 /* Check that both hashes are non-zero*/
 241 
 242                 if (h_domain && h_rid) {
 243                         ids[i]->xid.id = combine_hashes(h_domain, h_rid);
 244                         ids[i]->status = ID_MAPPED;
 245                 }
 246         }
 247 
 248 done:
 249         return nt_status;
 250 }
 251 
 252 /*********************************************************************
 253  ********************************************************************/
 254 
 255 static NTSTATUS be_close(struct idmap_domain *dom)
     /* [<][>][^][v][top][bottom][index][help] */
 256 {
 257         if (hashed_domains)
 258                 talloc_free(hashed_domains);
 259 
 260         return NT_STATUS_OK;
 261 }
 262 
 263 /*********************************************************************
 264  ********************************************************************/
 265 
 266 static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
     /* [<][>][^][v][top][bottom][index][help] */
 267 {
 268         return be_init(NULL, NULL);
 269 }
 270 
 271 /**********************************************************************
 272  *********************************************************************/
 273 
 274 static NTSTATUS nss_hash_get_info(struct nss_domain_entry *e,
     /* [<][>][^][v][top][bottom][index][help] */
 275                                     const DOM_SID *sid,
 276                                     TALLOC_CTX *ctx,
 277                                     ADS_STRUCT *ads,
 278                                     LDAPMessage *msg,
 279                                     char **homedir,
 280                                     char **shell,
 281                                     char **gecos,
 282                                     gid_t *p_gid )
 283 {
 284         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 285 
 286         nt_status = nss_hash_init(e);
 287         BAIL_ON_NTSTATUS_ERROR(nt_status);
 288 
 289         if (!homedir || !shell || !gecos) {
 290                 nt_status = NT_STATUS_INVALID_PARAMETER;
 291                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 292         }
 293 
 294         *homedir = talloc_strdup(ctx, lp_template_homedir());
 295         BAIL_ON_PTR_NT_ERROR(*homedir, nt_status);
 296 
 297         *shell   = talloc_strdup(ctx, lp_template_shell());
 298         BAIL_ON_PTR_NT_ERROR(*shell, nt_status);
 299 
 300         *gecos   = NULL;
 301 
 302         /* Initialize the gid so that the upper layer fills
 303            in the proper Windows primary group */
 304 
 305         if (*p_gid) {
 306                 *p_gid = (gid_t)-1;
 307         }
 308 
 309 done:
 310         return nt_status;
 311 }
 312 
 313 /**********************************************************************
 314  *********************************************************************/
 315 
 316 static NTSTATUS nss_hash_map_to_alias(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 317                                         struct nss_domain_entry *e,
 318                                         const char *name,
 319                                         char **alias)
 320 {
 321         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 322         const char *value;
 323 
 324         value = talloc_asprintf(mem_ctx, "%s\\%s", e->domain, name);
 325         BAIL_ON_PTR_NT_ERROR(value, nt_status);
 326 
 327         nt_status = mapfile_lookup_key(mem_ctx, value, alias);
 328         BAIL_ON_NTSTATUS_ERROR(nt_status);
 329 
 330 done:
 331         return nt_status;
 332 }
 333 
 334 /**********************************************************************
 335  *********************************************************************/
 336 
 337 static NTSTATUS nss_hash_map_from_alias(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 338                                           struct nss_domain_entry *e,
 339                                           const char *alias,
 340                                           char **name)
 341 {
 342         return mapfile_lookup_value(mem_ctx, alias, name);
 343 }
 344 
 345 /**********************************************************************
 346  *********************************************************************/
 347 
 348 static NTSTATUS nss_hash_close(void)
     /* [<][>][^][v][top][bottom][index][help] */
 349 {
 350         return NT_STATUS_OK;
 351 }
 352 
 353 /*********************************************************************
 354  Dispatch Tables for IDMap and NssInfo Methods
 355 ********************************************************************/
 356 
 357 static struct idmap_methods hash_idmap_methods = {
 358         .init            = be_init,
 359         .unixids_to_sids = unixids_to_sids,
 360         .sids_to_unixids = sids_to_unixids,
 361         .close_fn        = be_close
 362 };
 363 
 364 static struct nss_info_methods hash_nss_methods = {
 365         .init           = nss_hash_init,
 366         .get_nss_info   = nss_hash_get_info,
 367         .map_to_alias   = nss_hash_map_to_alias,
 368         .map_from_alias = nss_hash_map_from_alias,
 369         .close_fn       = nss_hash_close
 370 };
 371 
 372 /**********************************************************************
 373  Register with the idmap and idmap_nss subsystems. We have to protect
 374  against the idmap and nss_info interfaces being in a half-registered
 375  state.
 376  **********************************************************************/
 377 
 378 NTSTATUS idmap_hash_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 379 {
 380         static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
 381         static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;
 382 
 383         if ( !NT_STATUS_IS_OK(idmap_status) ) {
 384                 idmap_status =  smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
 385                                                    "hash", &hash_idmap_methods);
 386 
 387                 if ( !NT_STATUS_IS_OK(idmap_status) ) {
 388                         DEBUG(0,("Failed to register hash idmap plugin.\n"));
 389                         return idmap_status;
 390                 }
 391         }
 392 
 393         if ( !NT_STATUS_IS_OK(nss_status) ) {
 394                 nss_status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
 395                                                     "hash", &hash_nss_methods);
 396                 if ( !NT_STATUS_IS_OK(nss_status) ) {
 397                         DEBUG(0,("Failed to register hash idmap nss plugin.\n"));
 398                         return nss_status;
 399                 }
 400         }
 401 
 402         return NT_STATUS_OK;
 403 }

/* [<][>][^][v][top][bottom][index][help] */