root/source3/winbindd/winbindd_util.c

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

DEFINITIONS

This source file includes following definitions.
  1. domain_list
  2. free_domain_list
  3. is_internal_domain
  4. is_in_internal_domain
  5. add_trusted_domain
  6. add_trusted_domains
  7. trustdom_recv
  8. rescan_forest_root_trusts
  9. rescan_forest_trusts
  10. rescan_trusted_domains
  11. init_child_connection
  12. init_child_getdc_recv
  13. init_child_recv
  14. winbindd_dual_init_connection
  15. init_domain_list
  16. check_domain_trusted
  17. find_domain_from_name_noinit
  18. find_domain_from_name
  19. find_domain_from_sid_noinit
  20. find_domain_from_sid
  21. find_our_domain
  22. find_root_domain
  23. find_builtin_domain
  24. find_lookup_domain_from_sid
  25. find_lookup_domain_from_name
  26. winbindd_lookup_sid_by_name
  27. winbindd_lookup_name_by_sid
  28. free_getent_state
  29. assume_domain
  30. parse_domain_user
  31. parse_domain_user_talloc
  32. parse_add_domuser
  33. canonicalize_username
  34. fill_domain_username
  35. fill_domain_username_talloc
  36. get_winbind_pipe_dir
  37. get_winbind_priv_pipe_dir
  38. open_winbindd_socket
  39. open_winbindd_priv_socket
  40. winbindd_client_list
  41. winbindd_add_client
  42. winbindd_remove_client
  43. winbindd_kill_all_clients
  44. winbindd_num_clients
  45. lookup_usergroups_cached
  46. normalize_name_map
  47. normalize_name_unmap
  48. winbindd_can_contact_domain
  49. winbindd_internal_child
  50. winbindd_set_locator_kdc_env
  51. winbindd_set_locator_kdc_envs
  52. winbindd_unset_locator_kdc_env
  53. winbindd_set_locator_kdc_envs
  54. winbindd_unset_locator_kdc_env
  55. set_auth_errors

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Winbind daemon for ntdom nss module
   5 
   6    Copyright (C) Tim Potter 2000-2001
   7    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
   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 3 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, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "winbindd.h"
  25 
  26 #undef DBGC_CLASS
  27 #define DBGC_CLASS DBGC_WINBIND
  28 
  29 extern struct winbindd_methods cache_methods;
  30 extern struct winbindd_methods builtin_passdb_methods;
  31 extern struct winbindd_methods sam_passdb_methods;
  32 
  33 
  34 /**
  35  * @file winbindd_util.c
  36  *
  37  * Winbind daemon for NT domain authentication nss module.
  38  **/
  39 
  40 
  41 /* The list of trusted domains.  Note that the list can be deleted and
  42    recreated using the init_domain_list() function so pointers to
  43    individual winbindd_domain structures cannot be made.  Keep a copy of
  44    the domain name instead. */
  45 
  46 static struct winbindd_domain *_domain_list = NULL;
  47 
  48 /**
  49    When was the last scan of trusted domains done?
  50    
  51    0 == not ever
  52 */
  53 
  54 static time_t last_trustdom_scan;
  55 
  56 struct winbindd_domain *domain_list(void)
     /* [<][>][^][v][top][bottom][index][help] */
  57 {
  58         /* Initialise list */
  59 
  60         if ((!_domain_list) && (!init_domain_list())) {
  61                 smb_panic("Init_domain_list failed");
  62         }
  63 
  64         return _domain_list;
  65 }
  66 
  67 /* Free all entries in the trusted domain list */
  68 
  69 void free_domain_list(void)
     /* [<][>][^][v][top][bottom][index][help] */
  70 {
  71         struct winbindd_domain *domain = _domain_list;
  72 
  73         while(domain) {
  74                 struct winbindd_domain *next = domain->next;
  75                 
  76                 DLIST_REMOVE(_domain_list, domain);
  77                 SAFE_FREE(domain);
  78                 domain = next;
  79         }
  80 }
  81 
  82 static bool is_internal_domain(const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
  83 {
  84         if (sid == NULL)
  85                 return False;
  86 
  87         if ( IS_DC )
  88                 return sid_check_is_builtin(sid);
  89 
  90         return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
  91 }
  92 
  93 static bool is_in_internal_domain(const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
  94 {
  95         if (sid == NULL)
  96                 return False;
  97 
  98         if ( IS_DC )
  99                 return sid_check_is_in_builtin(sid);
 100 
 101         return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
 102 }
 103 
 104 
 105 /* Add a trusted domain to our list of domains */
 106 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
     /* [<][>][^][v][top][bottom][index][help] */
 107                                                   struct winbindd_methods *methods,
 108                                                   const DOM_SID *sid)
 109 {
 110         struct winbindd_domain *domain;
 111         const char *alternative_name = NULL;
 112         char *idmap_config_option;
 113         const char *param;
 114         const char **ignored_domains, **dom;
 115         
 116         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
 117         for (dom=ignored_domains; dom && *dom; dom++) {
 118                 if (gen_fnmatch(*dom, domain_name) == 0) {
 119                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
 120                         return NULL;
 121                 }
 122         }
 123 
 124         /* ignore alt_name if we are not in an AD domain */
 125         
 126         if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
 127                 alternative_name = alt_name;
 128         }
 129         
 130         /* We can't call domain_list() as this function is called from
 131            init_domain_list() and we'll get stuck in a loop. */
 132         for (domain = _domain_list; domain; domain = domain->next) {
 133                 if (strequal(domain_name, domain->name) ||
 134                     strequal(domain_name, domain->alt_name)) 
 135                 {
 136                         break;                  
 137                 }
 138 
 139                 if (alternative_name && *alternative_name) 
 140                 {
 141                         if (strequal(alternative_name, domain->name) ||
 142                             strequal(alternative_name, domain->alt_name)) 
 143                         {
 144                                 break;                          
 145                         }
 146                 }
 147 
 148                 if (sid) 
 149                 {
 150                         if (is_null_sid(sid)) {
 151                                 continue;                               
 152                         }
 153                                 
 154                         if (sid_equal(sid, &domain->sid)) {
 155                                 break;                          
 156                         }
 157                 }
 158         }
 159         
 160         /* See if we found a match.  Check if we need to update the
 161            SID. */
 162 
 163         if ( domain && sid) {
 164                 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
 165                         sid_copy( &domain->sid, sid );
 166 
 167                 return domain;          
 168         }       
 169         
 170         /* Create new domain entry */
 171 
 172         if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
 173                 return NULL;
 174 
 175         /* Fill in fields */
 176         
 177         ZERO_STRUCTP(domain);
 178 
 179         fstrcpy(domain->name, domain_name);
 180         if (alternative_name) {
 181                 fstrcpy(domain->alt_name, alternative_name);
 182         }
 183 
 184         domain->methods = methods;
 185         domain->backend = NULL;
 186         domain->internal = is_internal_domain(sid);
 187         domain->sequence_number = DOM_SEQUENCE_NONE;
 188         domain->last_seq_check = 0;
 189         domain->initialized = False;
 190         domain->online = is_internal_domain(sid);
 191         domain->check_online_timeout = 0;
 192         domain->dc_probe_pid = (pid_t)-1;
 193         if (sid) {
 194                 sid_copy(&domain->sid, sid);
 195         }
 196 
 197         /* Link to domain list */
 198         DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
 199         
 200         wcache_tdc_add_domain( domain );
 201         
 202         idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
 203                                               domain->name);
 204         if (idmap_config_option == NULL) {
 205                 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
 206                 goto done;
 207         }
 208 
 209         param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
 210 
 211         DEBUG(10, ("%s : range = %s\n", idmap_config_option,
 212                    param ? param : "not defined"));
 213 
 214         if (param != NULL) {
 215                 unsigned low_id, high_id;
 216                 if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
 217                         DEBUG(1, ("invalid range syntax in %s: %s\n",
 218                                   idmap_config_option, param));
 219                         goto done;
 220                 }
 221                 if (low_id > high_id) {
 222                         DEBUG(1, ("invalid range in %s: %s\n",
 223                                   idmap_config_option, param));
 224                         goto done;
 225                 }
 226                 domain->have_idmap_config = true;
 227                 domain->id_range_low = low_id;
 228                 domain->id_range_high = high_id;
 229         }
 230 
 231 done:
 232 
 233         DEBUG(2,("Added domain %s %s %s\n", 
 234                  domain->name, domain->alt_name,
 235                  &domain->sid?sid_string_dbg(&domain->sid):""));
 236         
 237         return domain;
 238 }
 239 
 240 /********************************************************************
 241   rescan our domains looking for new trusted domains
 242 ********************************************************************/
 243 
 244 struct trustdom_state {
 245         TALLOC_CTX *mem_ctx;
 246         bool primary;   
 247         bool forest_root;       
 248         struct winbindd_response *response;
 249 };
 250 
 251 static void trustdom_recv(void *private_data, bool success);
 252 static void rescan_forest_root_trusts( void );
 253 static void rescan_forest_trusts( void );
 254 
 255 static void add_trusted_domains( struct winbindd_domain *domain )
     /* [<][>][^][v][top][bottom][index][help] */
 256 {
 257         TALLOC_CTX *mem_ctx;
 258         struct winbindd_request *request;
 259         struct winbindd_response *response;
 260         uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
 261 
 262         struct trustdom_state *state;
 263 
 264         mem_ctx = talloc_init("add_trusted_domains");
 265         if (mem_ctx == NULL) {
 266                 DEBUG(0, ("talloc_init failed\n"));
 267                 return;
 268         }
 269 
 270         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
 271         response = TALLOC_P(mem_ctx, struct winbindd_response);
 272         state = TALLOC_P(mem_ctx, struct trustdom_state);
 273 
 274         if ((request == NULL) || (response == NULL) || (state == NULL)) {
 275                 DEBUG(0, ("talloc failed\n"));
 276                 talloc_destroy(mem_ctx);
 277                 return;
 278         }
 279 
 280         state->mem_ctx = mem_ctx;
 281         state->response = response;
 282 
 283         /* Flags used to know how to continue the forest trust search */
 284 
 285         state->primary = domain->primary;
 286         state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
 287 
 288         request->length = sizeof(*request);
 289         request->cmd = WINBINDD_LIST_TRUSTDOM;
 290 
 291         async_domain_request(mem_ctx, domain, request, response,
 292                              trustdom_recv, state);
 293 }
 294 
 295 static void trustdom_recv(void *private_data, bool success)
     /* [<][>][^][v][top][bottom][index][help] */
 296 {
 297         struct trustdom_state *state =
 298                 talloc_get_type_abort(private_data, struct trustdom_state);
 299         struct winbindd_response *response = state->response;
 300         char *p;
 301 
 302         if ((!success) || (response->result != WINBINDD_OK)) {
 303                 DEBUG(1, ("Could not receive trustdoms\n"));
 304                 talloc_destroy(state->mem_ctx);
 305                 return;
 306         }
 307 
 308         p = (char *)response->extra_data.data;
 309 
 310         while ((p != NULL) && (*p != '\0')) {
 311                 char *q, *sidstr, *alt_name;
 312                 DOM_SID sid;
 313                 struct winbindd_domain *domain;
 314                 char *alternate_name = NULL;
 315 
 316                 alt_name = strchr(p, '\\');
 317                 if (alt_name == NULL) {
 318                         DEBUG(0, ("Got invalid trustdom response\n"));
 319                         break;
 320                 }
 321 
 322                 *alt_name = '\0';
 323                 alt_name += 1;
 324 
 325                 sidstr = strchr(alt_name, '\\');
 326                 if (sidstr == NULL) {
 327                         DEBUG(0, ("Got invalid trustdom response\n"));
 328                         break;
 329                 }
 330 
 331                 *sidstr = '\0';
 332                 sidstr += 1;
 333 
 334                 q = strchr(sidstr, '\n');
 335                 if (q != NULL)
 336                         *q = '\0';
 337 
 338                 if (!string_to_sid(&sid, sidstr)) {
 339                         /* Allow NULL sid for sibling domains */
 340                         if ( strcmp(sidstr,"S-0-0") == 0) {
 341                                 sid_copy( &sid, &global_sid_NULL);                              
 342                         } else {                                
 343                                 DEBUG(0, ("Got invalid trustdom response\n"));
 344                                 break;
 345                         }                       
 346                 }
 347 
 348                 /* use the real alt_name if we have one, else pass in NULL */
 349 
 350                 if ( !strequal( alt_name, "(null)" ) )
 351                         alternate_name = alt_name;
 352 
 353                 /* If we have an existing domain structure, calling
 354                    add_trusted_domain() will update the SID if
 355                    necessary.  This is important because we need the
 356                    SID for sibling domains */
 357 
 358                 if ( find_domain_from_name_noinit(p) != NULL ) {
 359                         domain = add_trusted_domain(p, alternate_name,
 360                                                     &cache_methods,
 361                                                     &sid);
 362                 } else {
 363                         domain = add_trusted_domain(p, alternate_name,
 364                                                     &cache_methods,
 365                                                     &sid);
 366                         if (domain) {
 367                                 setup_domain_child(domain,
 368                                                    &domain->child);
 369                         }
 370                 }
 371                 p=q;
 372                 if (p != NULL)
 373                         p += 1;
 374         }
 375 
 376         SAFE_FREE(response->extra_data.data);
 377 
 378         /* 
 379            Cases to consider when scanning trusts:
 380            (a) we are calling from a child domain (primary && !forest_root)
 381            (b) we are calling from the root of the forest (primary && forest_root)
 382            (c) we are calling from a trusted forest domain (!primary
 383                && !forest_root)
 384         */
 385 
 386         if ( state->primary ) {
 387                 /* If this is our primary domain and we are not in the
 388                    forest root, we have to scan the root trusts first */
 389 
 390                 if ( !state->forest_root )
 391                         rescan_forest_root_trusts();
 392                 else
 393                         rescan_forest_trusts();
 394 
 395         } else if ( state->forest_root ) {
 396                 /* Once we have done root forest trust search, we can
 397                    go on to search the trusted forests */
 398 
 399                 rescan_forest_trusts();
 400         }
 401         
 402         talloc_destroy(state->mem_ctx);
 403         
 404         return;
 405 }
 406 
 407 /********************************************************************
 408  Scan the trusts of our forest root
 409 ********************************************************************/
 410 
 411 static void rescan_forest_root_trusts( void )
     /* [<][>][^][v][top][bottom][index][help] */
 412 {
 413         struct winbindd_tdc_domain *dom_list = NULL;
 414         size_t num_trusts = 0;
 415         int i;  
 416 
 417         /* The only transitive trusts supported by Windows 2003 AD are
 418            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
 419            first two are handled in forest and listed by
 420            DsEnumerateDomainTrusts().  Forest trusts are not so we
 421            have to do that ourselves. */
 422 
 423         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
 424                 return;
 425 
 426         for ( i=0; i<num_trusts; i++ ) {
 427                 struct winbindd_domain *d = NULL;
 428 
 429                 /* Find the forest root.  Don't necessarily trust 
 430                    the domain_list() as our primary domain may not 
 431                    have been initialized. */
 432 
 433                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
 434                         continue;
 435                 }
 436         
 437                 /* Here's the forest root */
 438 
 439                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
 440 
 441                 if ( !d ) {
 442                         d = add_trusted_domain( dom_list[i].domain_name,
 443                                                 dom_list[i].dns_name,
 444                                                 &cache_methods,
 445                                                 &dom_list[i].sid );
 446                 }
 447 
 448                 if (d == NULL) {
 449                         continue;
 450                 }
 451 
 452                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
 453                           "for domain tree root %s (%s)\n",
 454                           d->name, d->alt_name ));
 455 
 456                 d->domain_flags = dom_list[i].trust_flags;
 457                 d->domain_type  = dom_list[i].trust_type;               
 458                 d->domain_trust_attribs = dom_list[i].trust_attribs;            
 459                 
 460                 add_trusted_domains( d );
 461 
 462                 break;          
 463         }
 464 
 465         TALLOC_FREE( dom_list );
 466 
 467         return;
 468 }
 469 
 470 /********************************************************************
 471  scan the transitive forest trusts (not our own)
 472 ********************************************************************/
 473 
 474 
 475 static void rescan_forest_trusts( void )
     /* [<][>][^][v][top][bottom][index][help] */
 476 {
 477         struct winbindd_domain *d = NULL;
 478         struct winbindd_tdc_domain *dom_list = NULL;
 479         size_t num_trusts = 0;
 480         int i;  
 481 
 482         /* The only transitive trusts supported by Windows 2003 AD are
 483            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
 484            first two are handled in forest and listed by
 485            DsEnumerateDomainTrusts().  Forest trusts are not so we
 486            have to do that ourselves. */
 487 
 488         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
 489                 return;
 490 
 491         for ( i=0; i<num_trusts; i++ ) {
 492                 uint32 flags   = dom_list[i].trust_flags;
 493                 uint32 type    = dom_list[i].trust_type;
 494                 uint32 attribs = dom_list[i].trust_attribs;
 495                 
 496                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
 497 
 498                 /* ignore our primary and internal domains */
 499 
 500                 if ( d && (d->internal || d->primary ) )
 501                         continue;               
 502 
 503                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
 504                      (type == NETR_TRUST_TYPE_UPLEVEL) &&
 505                      (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
 506                 {
 507                         /* add the trusted domain if we don't know
 508                            about it */
 509 
 510                         if ( !d ) {
 511                                 d = add_trusted_domain( dom_list[i].domain_name,
 512                                                         dom_list[i].dns_name,
 513                                                         &cache_methods,
 514                                                         &dom_list[i].sid );
 515                         }
 516 
 517                         if (d == NULL) {
 518                                 continue;
 519                         }
 520                         
 521                         DEBUG(10,("Following trust path for domain %s (%s)\n",
 522                                   d->name, d->alt_name ));
 523                         add_trusted_domains( d );
 524                 }
 525         }
 526 
 527         TALLOC_FREE( dom_list );
 528 
 529         return; 
 530 }
 531 
 532 /*********************************************************************
 533  The process of updating the trusted domain list is a three step
 534  async process:
 535  (a) ask our domain
 536  (b) ask the root domain in our forest
 537  (c) ask the a DC in any Win2003 trusted forests
 538 *********************************************************************/
 539 
 540 void rescan_trusted_domains( void )
     /* [<][>][^][v][top][bottom][index][help] */
 541 {
 542         time_t now = time(NULL);
 543 
 544         /* Check that we allow trusted domains at all */
 545         if (!lp_allow_trusted_domains())
 546                 return;
 547 
 548         /* see if the time has come... */
 549         
 550         if ((now >= last_trustdom_scan) &&
 551             ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
 552                 return;
 553                 
 554         /* I use to clear the cache here and start over but that
 555            caused problems in child processes that needed the
 556            trust dom list early on.  Removing it means we
 557            could have some trusted domains listed that have been
 558            removed from our primary domain's DC until a full
 559            restart.  This should be ok since I think this is what
 560            Windows does as well. */
 561 
 562         /* this will only add new domains we didn't already know about
 563            in the domain_list()*/
 564         
 565         add_trusted_domains( find_our_domain() );
 566 
 567         last_trustdom_scan = now;
 568         
 569         return; 
 570 }
 571 
 572 struct init_child_state {
 573         TALLOC_CTX *mem_ctx;
 574         struct winbindd_domain *domain;
 575         struct winbindd_request *request;
 576         struct winbindd_response *response;
 577         void (*continuation)(void *private_data, bool success);
 578         void *private_data;
 579 };
 580 
 581 static void init_child_recv(void *private_data, bool success);
 582 static void init_child_getdc_recv(void *private_data, bool success);
 583 
 584 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 585                                            void (*continuation)(void *private_data,
 586                                                                 bool success),
 587                                            void *private_data)
 588 {
 589         TALLOC_CTX *mem_ctx;
 590         struct winbindd_request *request;
 591         struct winbindd_response *response;
 592         struct init_child_state *state;
 593         struct winbindd_domain *request_domain;
 594 
 595         mem_ctx = talloc_init("init_child_connection");
 596         if (mem_ctx == NULL) {
 597                 DEBUG(0, ("talloc_init failed\n"));
 598                 return WINBINDD_ERROR;
 599         }
 600 
 601         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
 602         response = TALLOC_P(mem_ctx, struct winbindd_response);
 603         state = TALLOC_P(mem_ctx, struct init_child_state);
 604 
 605         if ((request == NULL) || (response == NULL) || (state == NULL)) {
 606                 DEBUG(0, ("talloc failed\n"));
 607                 TALLOC_FREE(mem_ctx);
 608                 continuation(private_data, False);
 609                 return WINBINDD_ERROR;
 610         }
 611 
 612         request->length = sizeof(*request);
 613 
 614         state->mem_ctx = mem_ctx;
 615         state->domain = domain;
 616         state->request = request;
 617         state->response = response;
 618         state->continuation = continuation;
 619         state->private_data = private_data;
 620 
 621         if (IS_DC || domain->primary || domain->internal ) {
 622                 /* The primary domain has to find the DC name itself */
 623                 request->cmd = WINBINDD_INIT_CONNECTION;
 624                 fstrcpy(request->domain_name, domain->name);
 625                 request->data.init_conn.is_primary = domain->primary ? true : false;
 626                 fstrcpy(request->data.init_conn.dcname, "");
 627                 async_request(mem_ctx, &domain->child, request, response,
 628                               init_child_recv, state);
 629                 return WINBINDD_PENDING;
 630         }
 631 
 632         /* This is *not* the primary domain, let's ask our DC about a DC
 633          * name */
 634 
 635         request->cmd = WINBINDD_GETDCNAME;
 636         fstrcpy(request->domain_name, domain->name);
 637 
 638         request_domain = find_our_domain();
 639         async_domain_request(mem_ctx, request_domain, request, response,
 640                              init_child_getdc_recv, state);
 641         return WINBINDD_PENDING;
 642 }
 643 
 644 static void init_child_getdc_recv(void *private_data, bool success)
     /* [<][>][^][v][top][bottom][index][help] */
 645 {
 646         struct init_child_state *state =
 647                 talloc_get_type_abort(private_data, struct init_child_state);
 648         const char *dcname = "";
 649 
 650         DEBUG(10, ("Received getdcname response\n"));
 651 
 652         if (success && (state->response->result == WINBINDD_OK)) {
 653                 dcname = state->response->data.dc_name;
 654         }
 655 
 656         state->request->cmd = WINBINDD_INIT_CONNECTION;
 657         fstrcpy(state->request->domain_name, state->domain->name);
 658         state->request->data.init_conn.is_primary = False;
 659         fstrcpy(state->request->data.init_conn.dcname, dcname);
 660 
 661         async_request(state->mem_ctx, &state->domain->child,
 662                       state->request, state->response,
 663                       init_child_recv, state);
 664 }
 665 
 666 static void init_child_recv(void *private_data, bool success)
     /* [<][>][^][v][top][bottom][index][help] */
 667 {
 668         struct init_child_state *state =
 669                 talloc_get_type_abort(private_data, struct init_child_state);
 670 
 671         DEBUG(5, ("Received child initialization response for domain %s\n",
 672                   state->domain->name));
 673 
 674         if ((!success) || (state->response->result != WINBINDD_OK)) {
 675                 DEBUG(3, ("Could not init child\n"));
 676                 state->continuation(state->private_data, False);
 677                 talloc_destroy(state->mem_ctx);
 678                 return;
 679         }
 680 
 681         fstrcpy(state->domain->name,
 682                 state->response->data.domain_info.name);
 683         fstrcpy(state->domain->alt_name,
 684                 state->response->data.domain_info.alt_name);
 685         if (!string_to_sid(&state->domain->sid,
 686                       state->response->data.domain_info.sid)) {
 687                 DEBUG(1,("init_child_recv: Could not convert sid %s "
 688                         "from string\n",
 689                         state->response->data.domain_info.sid));
 690                 state->continuation(state->private_data, False);
 691                 talloc_destroy(state->mem_ctx);
 692                 return;
 693         }
 694 
 695         state->domain->native_mode =
 696                 state->response->data.domain_info.native_mode;
 697         state->domain->active_directory =
 698                 state->response->data.domain_info.active_directory;
 699 
 700         init_dc_connection(state->domain);
 701 
 702         if (state->continuation != NULL)
 703                 state->continuation(state->private_data, True);
 704         talloc_destroy(state->mem_ctx);
 705 }
 706 
 707 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 708                                                    struct winbindd_cli_state *state)
 709 {
 710         /* Ensure null termination */
 711         state->request.domain_name
 712                 [sizeof(state->request.domain_name)-1]='\0';
 713         state->request.data.init_conn.dcname
 714                 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
 715 
 716         if (strlen(state->request.data.init_conn.dcname) > 0) {
 717                 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
 718         }
 719 
 720         init_dc_connection(domain);
 721 
 722         if (!domain->initialized) {
 723                 /* If we return error here we can't do any cached authentication,
 724                    but we may be in disconnected mode and can't initialize correctly.
 725                    Do what the previous code did and just return without initialization,
 726                    once we go online we'll re-initialize.
 727                 */
 728                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
 729                         "online = %d\n", domain->name, (int)domain->online ));
 730         }
 731 
 732         fstrcpy(state->response.data.domain_info.name, domain->name);
 733         fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
 734         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
 735         
 736         state->response.data.domain_info.native_mode
 737                 = domain->native_mode;
 738         state->response.data.domain_info.active_directory
 739                 = domain->active_directory;
 740         state->response.data.domain_info.primary
 741                 = domain->primary;
 742 
 743         return WINBINDD_OK;
 744 }
 745 
 746 /* Look up global info for the winbind daemon */
 747 bool init_domain_list(void)
     /* [<][>][^][v][top][bottom][index][help] */
 748 {
 749         struct winbindd_domain *domain;
 750         int role = lp_server_role();
 751 
 752         /* Free existing list */
 753         free_domain_list();
 754 
 755         /* BUILTIN domain */
 756 
 757         domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
 758                                     &global_sid_Builtin);
 759         if (domain) {
 760                 setup_domain_child(domain,
 761                                    &domain->child);
 762         }
 763 
 764         /* Local SAM */
 765 
 766         domain = add_trusted_domain(get_global_sam_name(), NULL,
 767                                     &sam_passdb_methods, get_global_sam_sid());
 768         if (domain) {
 769                 if ( role != ROLE_DOMAIN_MEMBER ) {
 770                         domain->primary = True;
 771                 }
 772                 setup_domain_child(domain,
 773                                    &domain->child);
 774         }
 775 
 776         /* Add ourselves as the first entry. */
 777 
 778         if ( role == ROLE_DOMAIN_MEMBER ) {
 779                 DOM_SID our_sid;
 780 
 781                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
 782                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
 783                         return False;
 784                 }
 785         
 786                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
 787                                              &cache_methods, &our_sid);
 788                 if (domain) {
 789                         domain->primary = True;
 790                         setup_domain_child(domain,
 791                                            &domain->child);
 792 
 793                         /* Even in the parent winbindd we'll need to
 794                            talk to the DC, so try and see if we can
 795                            contact it. Theoretically this isn't neccessary
 796                            as the init_dc_connection() in init_child_recv()
 797                            will do this, but we can start detecting the DC
 798                            early here. */
 799                         set_domain_online_request(domain);
 800                 }
 801         }
 802 
 803         return True;
 804 }
 805 
 806 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
     /* [<][>][^][v][top][bottom][index][help] */
 807 {
 808         struct winbindd_domain *domain; 
 809         DOM_SID dom_sid;
 810         uint32 rid;
 811 
 812         /* Check if we even care */
 813 
 814         if (!lp_allow_trusted_domains())
 815                 return;
 816 
 817         domain = find_domain_from_name_noinit( name );
 818         if ( domain )
 819                 return; 
 820         
 821         sid_copy( &dom_sid, user_sid );         
 822         if ( !sid_split_rid( &dom_sid, &rid ) )
 823                 return;
 824         
 825         /* add the newly discovered trusted domain */
 826 
 827         domain = add_trusted_domain( name, NULL, &cache_methods, 
 828                                      &dom_sid);
 829 
 830         if ( !domain )
 831                 return;
 832 
 833         /* assume this is a trust from a one-way transitive 
 834            forest trust */
 835 
 836         domain->active_directory = True;
 837         domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
 838         domain->domain_type  = NETR_TRUST_TYPE_UPLEVEL;
 839         domain->internal = False;
 840         domain->online = True;  
 841 
 842         setup_domain_child(domain,
 843                            &domain->child);
 844 
 845         wcache_tdc_add_domain( domain );
 846 
 847         return; 
 848 }
 849 
 850 /** 
 851  * Given a domain name, return the struct winbindd domain info for it 
 852  *
 853  * @note Do *not* pass lp_workgroup() to this function.  domain_list
 854  *       may modify it's value, and free that pointer.  Instead, our local
 855  *       domain may be found by calling find_our_domain().
 856  *       directly.
 857  *
 858  *
 859  * @return The domain structure for the named domain, if it is working.
 860  */
 861 
 862 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
     /* [<][>][^][v][top][bottom][index][help] */
 863 {
 864         struct winbindd_domain *domain;
 865 
 866         /* Search through list */
 867 
 868         for (domain = domain_list(); domain != NULL; domain = domain->next) {
 869                 if (strequal(domain_name, domain->name) ||
 870                     (domain->alt_name[0] &&
 871                      strequal(domain_name, domain->alt_name))) {
 872                         return domain;
 873                 }
 874         }
 875 
 876         /* Not found */
 877 
 878         return NULL;
 879 }
 880 
 881 struct winbindd_domain *find_domain_from_name(const char *domain_name)
     /* [<][>][^][v][top][bottom][index][help] */
 882 {
 883         struct winbindd_domain *domain;
 884 
 885         domain = find_domain_from_name_noinit(domain_name);
 886 
 887         if (domain == NULL)
 888                 return NULL;
 889 
 890         if (!domain->initialized)
 891                 init_dc_connection(domain);
 892 
 893         return domain;
 894 }
 895 
 896 /* Given a domain sid, return the struct winbindd domain info for it */
 897 
 898 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
 899 {
 900         struct winbindd_domain *domain;
 901 
 902         /* Search through list */
 903 
 904         for (domain = domain_list(); domain != NULL; domain = domain->next) {
 905                 if (sid_compare_domain(sid, &domain->sid) == 0)
 906                         return domain;
 907         }
 908 
 909         /* Not found */
 910 
 911         return NULL;
 912 }
 913 
 914 /* Given a domain sid, return the struct winbindd domain info for it */
 915 
 916 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
 917 {
 918         struct winbindd_domain *domain;
 919 
 920         domain = find_domain_from_sid_noinit(sid);
 921 
 922         if (domain == NULL)
 923                 return NULL;
 924 
 925         if (!domain->initialized)
 926                 init_dc_connection(domain);
 927 
 928         return domain;
 929 }
 930 
 931 struct winbindd_domain *find_our_domain(void)
     /* [<][>][^][v][top][bottom][index][help] */
 932 {
 933         struct winbindd_domain *domain;
 934 
 935         /* Search through list */
 936 
 937         for (domain = domain_list(); domain != NULL; domain = domain->next) {
 938                 if (domain->primary)
 939                         return domain;
 940         }
 941 
 942         smb_panic("Could not find our domain");
 943         return NULL;
 944 }
 945 
 946 struct winbindd_domain *find_root_domain(void)
     /* [<][>][^][v][top][bottom][index][help] */
 947 {
 948         struct winbindd_domain *ours = find_our_domain();       
 949         
 950         if ( !ours )
 951                 return NULL;
 952         
 953         if ( strlen(ours->forest_name) == 0 )
 954                 return NULL;
 955         
 956         return find_domain_from_name( ours->forest_name );
 957 }
 958 
 959 struct winbindd_domain *find_builtin_domain(void)
     /* [<][>][^][v][top][bottom][index][help] */
 960 {
 961         DOM_SID sid;
 962         struct winbindd_domain *domain;
 963 
 964         string_to_sid(&sid, "S-1-5-32");
 965         domain = find_domain_from_sid(&sid);
 966 
 967         if (domain == NULL) {
 968                 smb_panic("Could not find BUILTIN domain");
 969         }
 970 
 971         return domain;
 972 }
 973 
 974 /* Find the appropriate domain to lookup a name or SID */
 975 
 976 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
 977 {
 978         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
 979 
 980         if ( sid_check_is_in_unix_groups(sid) || 
 981              sid_check_is_unix_groups(sid) ||
 982              sid_check_is_in_unix_users(sid) ||
 983              sid_check_is_unix_users(sid) )
 984         {
 985                 return find_domain_from_sid(get_global_sam_sid());
 986         }
 987 
 988         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
 989          * one to contact the external DC's. On member servers the internal
 990          * domains are different: These are part of the local SAM. */
 991 
 992         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
 993 
 994         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
 995                 DEBUG(10, ("calling find_domain_from_sid\n"));
 996                 return find_domain_from_sid(sid);
 997         }       
 998 
 999         /* On a member server a query for SID or name can always go to our
1000          * primary DC. */
1001 
1002         DEBUG(10, ("calling find_our_domain\n"));
1003         return find_our_domain();
1004 }
1005 
1006 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
     /* [<][>][^][v][top][bottom][index][help] */
1007 {
1008         if ( strequal(domain_name, unix_users_domain_name() ) ||
1009              strequal(domain_name, unix_groups_domain_name() ) )
1010         {
1011                 return find_domain_from_name_noinit( get_global_sam_name() );
1012         }
1013 
1014         if (IS_DC || strequal(domain_name, "BUILTIN") ||
1015             strequal(domain_name, get_global_sam_name()))
1016                 return find_domain_from_name_noinit(domain_name);
1017 
1018         /* The "Unix User" and "Unix Group" domain our handled by passdb */
1019 
1020         return find_our_domain();
1021 }
1022 
1023 /* Lookup a sid in a domain from a name */
1024 
1025 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1026                                  enum winbindd_cmd orig_cmd,
1027                                  struct winbindd_domain *domain, 
1028                                  const char *domain_name,
1029                                  const char *name, DOM_SID *sid, 
1030                                  enum lsa_SidType *type)
1031 {
1032         NTSTATUS result;
1033 
1034         /* Lookup name */
1035         result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
1036                                               domain_name, name, sid, type);
1037 
1038         /* Return sid and type if lookup successful */
1039         if (!NT_STATUS_IS_OK(result)) {
1040                 *type = SID_NAME_UNKNOWN;
1041         }
1042 
1043         return NT_STATUS_IS_OK(result);
1044 }
1045 
1046 /**
1047  * @brief Lookup a name in a domain from a sid.
1048  *
1049  * @param sid Security ID you want to look up.
1050  * @param name On success, set to the name corresponding to @p sid.
1051  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
1052  * @param type On success, contains the type of name: alias, group or
1053  * user.
1054  * @retval True if the name exists, in which case @p name and @p type
1055  * are set, otherwise False.
1056  **/
1057 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1058                                  struct winbindd_domain *domain,
1059                                  DOM_SID *sid,
1060                                  char **dom_name,
1061                                  char **name,
1062                                  enum lsa_SidType *type)
1063 {
1064         NTSTATUS result;
1065 
1066         *dom_name = NULL;
1067         *name = NULL;
1068 
1069         /* Lookup name */
1070 
1071         result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1072 
1073         /* Return name and type if successful */
1074         
1075         if (NT_STATUS_IS_OK(result)) {
1076                 return True;
1077         }
1078 
1079         *type = SID_NAME_UNKNOWN;
1080         
1081         return False;
1082 }
1083 
1084 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1085 
1086 void free_getent_state(struct getent_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1087 {
1088         struct getent_state *temp;
1089 
1090         /* Iterate over state list */
1091 
1092         temp = state;
1093 
1094         while(temp != NULL) {
1095                 struct getent_state *next = temp->next;
1096 
1097                 /* Free sam entries then list entry */
1098 
1099                 SAFE_FREE(state->sam_entries);
1100                 DLIST_REMOVE(state, state);
1101 
1102                 SAFE_FREE(temp);
1103                 temp = next;
1104         }
1105 }
1106 
1107 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1108 
1109 static bool assume_domain(const char *domain)
     /* [<][>][^][v][top][bottom][index][help] */
1110 {
1111         /* never assume the domain on a standalone server */
1112 
1113         if ( lp_server_role() == ROLE_STANDALONE )
1114                 return False;
1115 
1116         /* domain member servers may possibly assume for the domain name */
1117 
1118         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1119                 if ( !strequal(lp_workgroup(), domain) )
1120                         return False;
1121 
1122                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1123                         return True;
1124         } 
1125 
1126         /* only left with a domain controller */
1127 
1128         if ( strequal(get_global_sam_name(), domain) )  {
1129                 return True;
1130         }
1131         
1132         return False;
1133 }
1134 
1135 /* Parse a string of the form DOMAIN\user into a domain and a user */
1136 
1137 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
     /* [<][>][^][v][top][bottom][index][help] */
1138 {
1139         char *p = strchr(domuser,*lp_winbind_separator());
1140 
1141         if ( !p ) {
1142                 fstrcpy(user, domuser);
1143 
1144                 if ( assume_domain(lp_workgroup())) {
1145                         fstrcpy(domain, lp_workgroup());
1146                 } else if ((p = strchr(domuser, '@')) != NULL) {
1147                         fstrcpy(domain, p + 1);
1148                         user[PTR_DIFF(p, domuser)] = 0;
1149                 } else {
1150                         return False;
1151                 }
1152         } else {
1153                 fstrcpy(user, p+1);
1154                 fstrcpy(domain, domuser);
1155                 domain[PTR_DIFF(p, domuser)] = 0;
1156         }
1157         
1158         strupper_m(domain);
1159         
1160         return True;
1161 }
1162 
1163 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
     /* [<][>][^][v][top][bottom][index][help] */
1164                               char **domain, char **user)
1165 {
1166         fstring fstr_domain, fstr_user;
1167         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1168                 return False;
1169         }
1170         *domain = talloc_strdup(mem_ctx, fstr_domain);
1171         *user = talloc_strdup(mem_ctx, fstr_user);
1172         return ((*domain != NULL) && (*user != NULL));
1173 }
1174 
1175 /* add a domain user name to a buffer */
1176 void parse_add_domuser(void *buf, char *domuser, int *len)
     /* [<][>][^][v][top][bottom][index][help] */
1177 {
1178         fstring domain;
1179         char *p, *user;
1180 
1181         user = domuser;
1182         p = strchr(domuser, *lp_winbind_separator());
1183 
1184         if (p) {
1185 
1186                 fstrcpy(domain, domuser);
1187                 domain[PTR_DIFF(p, domuser)] = 0;
1188                 p++;
1189 
1190                 if (assume_domain(domain)) {
1191 
1192                         user = p;
1193                         *len -= (PTR_DIFF(p, domuser));
1194                 }
1195         }
1196 
1197         safe_strcpy((char *)buf, user, *len);
1198 }
1199 
1200 /* Ensure an incoming username from NSS is fully qualified. Replace the
1201    incoming fstring with DOMAIN <separator> user. Returns the same
1202    values as parse_domain_user() but also replaces the incoming username.
1203    Used to ensure all names are fully qualified within winbindd.
1204    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1205    The protocol definitions of auth_crap, chng_pswd_auth_crap
1206    really should be changed to use this instead of doing things
1207    by hand. JRA. */
1208 
1209 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
     /* [<][>][^][v][top][bottom][index][help] */
1210 {
1211         if (!parse_domain_user(username_inout, domain, user)) {
1212                 return False;
1213         }
1214         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1215                  domain, *lp_winbind_separator(),
1216                  user);
1217         return True;
1218 }
1219 
1220 /*
1221     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1222     'winbind separator' options.
1223     This means:
1224         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1225         lp_workgroup()
1226 
1227     If we are a PDC or BDC, and this is for our domain, do likewise.
1228 
1229     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the 
1230     username is then unqualified in unix
1231 
1232     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1233 */
1234 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
     /* [<][>][^][v][top][bottom][index][help] */
1235 {
1236         fstring tmp_user;
1237 
1238         fstrcpy(tmp_user, user);
1239         strlower_m(tmp_user);
1240 
1241         if (can_assume && assume_domain(domain)) {
1242                 strlcpy(name, tmp_user, sizeof(fstring));
1243         } else {
1244                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1245                          domain, *lp_winbind_separator(),
1246                          tmp_user);
1247         }
1248 }
1249 
1250 /**
1251  * talloc version of fill_domain_username()
1252  * return NULL on talloc failure.
1253  */
1254 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1255                                   const char *domain,
1256                                   const char *user,
1257                                   bool can_assume)
1258 {
1259         char *tmp_user, *name;
1260 
1261         tmp_user = talloc_strdup(mem_ctx, user);
1262         strlower_m(tmp_user);
1263 
1264         if (can_assume && assume_domain(domain)) {
1265                 name = tmp_user;
1266         } else {
1267                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1268                                        domain,
1269                                        *lp_winbind_separator(),
1270                                        tmp_user);
1271                 TALLOC_FREE(tmp_user);
1272         }
1273 
1274         return name;
1275 }
1276 
1277 /*
1278  * Winbindd socket accessor functions
1279  */
1280 
1281 const char *get_winbind_pipe_dir(void) 
     /* [<][>][^][v][top][bottom][index][help] */
1282 {
1283         return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1284 }
1285 
1286 char *get_winbind_priv_pipe_dir(void) 
     /* [<][>][^][v][top][bottom][index][help] */
1287 {
1288         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1289 }
1290 
1291 /* Open the winbindd socket */
1292 
1293 static int _winbindd_socket = -1;
1294 static int _winbindd_priv_socket = -1;
1295 
1296 int open_winbindd_socket(void)
     /* [<][>][^][v][top][bottom][index][help] */
1297 {
1298         if (_winbindd_socket == -1) {
1299                 _winbindd_socket = create_pipe_sock(
1300                         get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1301                 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1302                            _winbindd_socket));
1303         }
1304 
1305         return _winbindd_socket;
1306 }
1307 
1308 int open_winbindd_priv_socket(void)
     /* [<][>][^][v][top][bottom][index][help] */
1309 {
1310         if (_winbindd_priv_socket == -1) {
1311                 _winbindd_priv_socket = create_pipe_sock(
1312                         get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1313                 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1314                            _winbindd_priv_socket));
1315         }
1316 
1317         return _winbindd_priv_socket;
1318 }
1319 
1320 /*
1321  * Client list accessor functions
1322  */
1323 
1324 static struct winbindd_cli_state *_client_list;
1325 static int _num_clients;
1326 
1327 /* Return list of all connected clients */
1328 
1329 struct winbindd_cli_state *winbindd_client_list(void)
     /* [<][>][^][v][top][bottom][index][help] */
1330 {
1331         return _client_list;
1332 }
1333 
1334 /* Add a connection to the list */
1335 
1336 void winbindd_add_client(struct winbindd_cli_state *cli)
     /* [<][>][^][v][top][bottom][index][help] */
1337 {
1338         DLIST_ADD(_client_list, cli);
1339         _num_clients++;
1340 }
1341 
1342 /* Remove a client from the list */
1343 
1344 void winbindd_remove_client(struct winbindd_cli_state *cli)
     /* [<][>][^][v][top][bottom][index][help] */
1345 {
1346         DLIST_REMOVE(_client_list, cli);
1347         _num_clients--;
1348 }
1349 
1350 /* Close all open clients */
1351 
1352 void winbindd_kill_all_clients(void)
     /* [<][>][^][v][top][bottom][index][help] */
1353 {
1354         struct winbindd_cli_state *cl = winbindd_client_list();
1355 
1356         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1357 
1358         while (cl) {
1359                 struct winbindd_cli_state *next;
1360                 
1361                 next = cl->next;
1362                 winbindd_remove_client(cl);
1363                 cl = next;
1364         }
1365 }
1366 
1367 /* Return number of open clients */
1368 
1369 int winbindd_num_clients(void)
     /* [<][>][^][v][top][bottom][index][help] */
1370 {
1371         return _num_clients;
1372 }
1373 
1374 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1375                                   TALLOC_CTX *mem_ctx,
1376                                   const DOM_SID *user_sid,
1377                                   uint32 *p_num_groups, DOM_SID **user_sids)
1378 {
1379         struct netr_SamInfo3 *info3 = NULL;
1380         NTSTATUS status = NT_STATUS_NO_MEMORY;
1381         size_t num_groups = 0;
1382 
1383         DEBUG(3,(": lookup_usergroups_cached\n"));
1384 
1385         *user_sids = NULL;
1386         *p_num_groups = 0;
1387 
1388         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1389 
1390         if (info3 == NULL) {
1391                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1392         }
1393 
1394         if (info3->base.groups.count == 0) {
1395                 TALLOC_FREE(info3);
1396                 return NT_STATUS_UNSUCCESSFUL;
1397         }
1398 
1399         /* Skip Domain local groups outside our domain.
1400            We'll get these from the getsidaliases() RPC call. */
1401         status = sid_array_from_info3(mem_ctx, info3,
1402                                       user_sids,
1403                                       &num_groups,
1404                                       false, true);
1405 
1406         if (!NT_STATUS_IS_OK(status)) {
1407                 TALLOC_FREE(info3);
1408                 return status;
1409         }
1410 
1411         TALLOC_FREE(info3);
1412         *p_num_groups = num_groups;
1413         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1414         
1415         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1416 
1417         return status;
1418 }
1419 
1420 /*********************************************************************
1421  We use this to remove spaces from user and group names
1422 ********************************************************************/
1423 
1424 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1425                              struct winbindd_domain *domain,
1426                              char *name,
1427                              char **normalized)
1428 {
1429         NTSTATUS nt_status;
1430 
1431         if (!name || !normalized) {
1432                 return NT_STATUS_INVALID_PARAMETER;
1433         }
1434 
1435         if (!lp_winbind_normalize_names()) {
1436                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1437         }
1438 
1439         /* Alias support and whitespace replacement are mutually
1440            exclusive */
1441 
1442         nt_status = resolve_username_to_alias(mem_ctx, domain,
1443                                               name, normalized );
1444         if (NT_STATUS_IS_OK(nt_status)) {
1445                 /* special return code to let the caller know we
1446                    mapped to an alias */
1447                 return NT_STATUS_FILE_RENAMED;
1448         }
1449 
1450         /* check for an unreachable domain */
1451 
1452         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1453                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1454                          domain->name));
1455                 set_domain_offline(domain);
1456                 return nt_status;
1457         }
1458 
1459         /* deal with whitespace */
1460 
1461         *normalized = talloc_strdup(mem_ctx, name);
1462         if (!(*normalized)) {
1463                 return NT_STATUS_NO_MEMORY;
1464         }
1465 
1466         all_string_sub( *normalized, " ", "_", 0 );
1467 
1468         return NT_STATUS_OK;
1469 }
1470 
1471 /*********************************************************************
1472  We use this to do the inverse of normalize_name_map()
1473 ********************************************************************/
1474 
1475 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1476                               char *name,
1477                               char **normalized)
1478 {
1479         NTSTATUS nt_status;
1480         struct winbindd_domain *domain = find_our_domain();
1481 
1482         if (!name || !normalized) {
1483                 return NT_STATUS_INVALID_PARAMETER;
1484         }
1485         
1486         if (!lp_winbind_normalize_names()) {
1487                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1488         }
1489 
1490         /* Alias support and whitespace replacement are mutally
1491            exclusive */
1492 
1493         /* When mapping from an alias to a username, we don't know the
1494            domain.  But we only need a domain structure to cache
1495            a successful lookup , so just our own domain structure for
1496            the seqnum. */
1497 
1498         nt_status = resolve_alias_to_username(mem_ctx, domain,
1499                                               name, normalized);
1500         if (NT_STATUS_IS_OK(nt_status)) {
1501                 /* Special return code to let the caller know we mapped
1502                    from an alias */
1503                 return NT_STATUS_FILE_RENAMED;
1504         }
1505 
1506         /* check for an unreachable domain */
1507 
1508         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1509                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1510                          domain->name));
1511                 set_domain_offline(domain);
1512                 return nt_status;
1513         }
1514 
1515         /* deal with whitespace */
1516 
1517         *normalized = talloc_strdup(mem_ctx, name);
1518         if (!(*normalized)) {
1519                 return NT_STATUS_NO_MEMORY;
1520         }
1521 
1522         all_string_sub(*normalized, "_", " ", 0);
1523 
1524         return NT_STATUS_OK;
1525 }
1526 
1527 /*********************************************************************
1528  ********************************************************************/
1529 
1530 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
     /* [<][>][^][v][top][bottom][index][help] */
1531 {
1532         struct winbindd_tdc_domain *tdc = NULL;
1533         TALLOC_CTX *frame = talloc_stackframe();
1534         bool ret = false;
1535 
1536         /* We can contact the domain if it is our primary domain */
1537 
1538         if (domain->primary) {
1539                 return true;
1540         }
1541 
1542         /* Trust the TDC cache and not the winbindd_domain flags */
1543 
1544         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1545                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1546                           domain->name));
1547                 return false;
1548         }
1549 
1550         /* Can always contact a domain that is in out forest */
1551 
1552         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1553                 ret = true;
1554                 goto done;
1555         }
1556         
1557         /*
1558          * On a _member_ server, we cannot contact the domain if it
1559          * is running AD and we have no inbound trust.
1560          */
1561 
1562         if (!IS_DC && 
1563              domain->active_directory &&
1564             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1565         {
1566                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1567                            "and we have no inbound trust.\n", domain->name));
1568                 goto done;
1569         }
1570 
1571         /* Assume everything else is ok (probably not true but what
1572            can you do?) */
1573 
1574         ret = true;     
1575 
1576 done:   
1577         talloc_destroy(frame);
1578         
1579         return ret;     
1580 }
1581 
1582 /*********************************************************************
1583  ********************************************************************/
1584 
1585 bool winbindd_internal_child(struct winbindd_child *child)
     /* [<][>][^][v][top][bottom][index][help] */
1586 {
1587         if ((child == idmap_child()) || (child == locator_child())) {
1588                 return True;
1589         }
1590 
1591         return False;
1592 }
1593 
1594 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1595 
1596 /*********************************************************************
1597  ********************************************************************/
1598 
1599 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
     /* [<][>][^][v][top][bottom][index][help] */
1600 {
1601         char *var = NULL;
1602         char addr[INET6_ADDRSTRLEN];
1603         const char *kdc = NULL;
1604         int lvl = 11;
1605 
1606         if (!domain || !domain->alt_name || !*domain->alt_name) {
1607                 return;
1608         }
1609 
1610         if (domain->initialized && !domain->active_directory) {
1611                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1612                         domain->alt_name));
1613                 return;
1614         }
1615 
1616         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1617         kdc = addr;
1618         if (!*kdc) {
1619                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1620                         domain->alt_name));
1621                 kdc = domain->dcname;
1622         }
1623 
1624         if (!kdc || !*kdc) {
1625                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1626                         domain->alt_name));
1627                 return;
1628         }
1629 
1630         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1631                                 domain->alt_name) == -1) {
1632                 return;
1633         }
1634 
1635         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1636                 var, kdc));
1637 
1638         setenv(var, kdc, 1);
1639         free(var);
1640 }
1641 
1642 /*********************************************************************
1643  ********************************************************************/
1644 
1645 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
     /* [<][>][^][v][top][bottom][index][help] */
1646 {
1647         struct winbindd_domain *our_dom = find_our_domain();
1648 
1649         winbindd_set_locator_kdc_env(domain);
1650 
1651         if (domain != our_dom) {
1652                 winbindd_set_locator_kdc_env(our_dom);
1653         }
1654 }
1655 
1656 /*********************************************************************
1657  ********************************************************************/
1658 
1659 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
     /* [<][>][^][v][top][bottom][index][help] */
1660 {
1661         char *var = NULL;
1662 
1663         if (!domain || !domain->alt_name || !*domain->alt_name) {
1664                 return;
1665         }
1666 
1667         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1668                                 domain->alt_name) == -1) {
1669                 return;
1670         }
1671 
1672         unsetenv(var);
1673         free(var);
1674 }
1675 #else
1676 
1677 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
     /* [<][>][^][v][top][bottom][index][help] */
1678 {
1679         return;
1680 }
1681 
1682 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
     /* [<][>][^][v][top][bottom][index][help] */
1683 {
1684         return;
1685 }
1686 
1687 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1688 
1689 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
     /* [<][>][^][v][top][bottom][index][help] */
1690 {
1691         resp->data.auth.nt_status = NT_STATUS_V(result);
1692         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1693 
1694         /* we might have given a more useful error above */
1695         if (*resp->data.auth.error_string == '\0')
1696                 fstrcpy(resp->data.auth.error_string,
1697                         get_friendly_nt_error_msg(result));
1698         resp->data.auth.pam_error = nt_status_to_pam(result);
1699 }

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