Print this page
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-2667 Wrong error when join domain with wrong password
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
NEX-2225 Unable to join NexentaStor to 2008 AD
NEX-1638 Updated DC Locator
 Includes work by: matt.barden@nexenta.com, kevin.crowe@nexenta.com
re #12435 rb3958 r10 is added 2 times to panic info
re #12393 rb3935 Kerberos and smbd disagree about who is our AD server


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 #include <syslog.h>
  28 #include <synch.h>
  29 #include <pthread.h>
  30 #include <unistd.h>
  31 #include <string.h>
  32 #include <strings.h>
  33 #include <sys/errno.h>
  34 #include <sys/types.h>
  35 #include <netinet/in.h>
  36 #include <arpa/nameser.h>
  37 #include <resolv.h>
  38 #include <netdb.h>
  39 #include <assert.h>
  40 
  41 #include <smbsrv/libsmb.h>
  42 #include <smbsrv/libsmbns.h>
  43 #include <smbsrv/libmlsvc.h>
  44 


  73 static void smb_domainex_free(smb_domainex_t *);
  74 static void smb_set_krb5_realm(char *);
  75 
  76 /*
  77  * ===================================================================
  78  * API to initialize DC locator thread, trigger DC discovery, and
  79  * get the discovered DC and/or domain information.
  80  * ===================================================================
  81  */
  82 
  83 /*
  84  * Initialization of the DC locator thread.
  85  * Returns 0 on success, an error number if thread creation fails.
  86  */
  87 int
  88 smb_dclocator_init(void)
  89 {
  90         pthread_attr_t tattr;
  91         int rc;
  92 








  93         (void) pthread_attr_init(&tattr);
  94         (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
  95         rc = pthread_create(&smb_dclocator_thr, &tattr,
  96             smb_ddiscover_service, &smb_dclocator);
  97         (void) pthread_attr_destroy(&tattr);
  98         return (rc);
  99 }
 100 
 101 /*
 102  * This is the entry point for discovering a domain controller for the
 103  * specified domain.  Called during join domain, and then periodically
 104  * by smbd_dc_update (the "DC monitor" thread).
 105  *
 106  * The actual work of discovering a DC is handled by DC locator thread.
 107  * All we do here is signal the request and wait for a DC or a timeout.
 108  *
 109  * Input parameters:
 110  *  domain - domain to be discovered (can either be NetBIOS or DNS domain)
 111  *
 112  * Output parameter:


 224 
 225         if (strcmp(smb_dclocator.sdl_dci.dc_name, bad_dc)) {
 226                 /*
 227                  * The "bad" DC is no longer the current one.
 228                  * Probably a late "bad DC" report.
 229                  */
 230                 goto out;
 231         }
 232         if (smb_dclocator.sdl_bad_dc) {
 233                 /* Someone already marked the current DC as "bad". */
 234                 syslog(LOG_DEBUG, "smb_ddiscover_bad_dc repeat");
 235                 goto out;
 236         }
 237 
 238         /*
 239          * Mark the current DC as "bad" and let the DC Locator
 240          * run again if it's not already.
 241          */
 242         syslog(LOG_INFO, "smb_ddiscover, bad DC: %s", bad_dc);
 243         smb_dclocator.sdl_bad_dc = B_TRUE;

 244 
 245         /* In-line smb_ddiscover_kick */
 246         if (!smb_dclocator.sdl_locate) {
 247                 smb_dclocator.sdl_locate = B_TRUE;
 248                 (void) cond_broadcast(&smb_dclocator.sdl_cv);
 249         }
 250 
 251 out:
 252         (void) mutex_unlock(&smb_dclocator.sdl_mtx);
 253 }
 254 
 255 /*
 256  * If domain discovery is running, wait for it to finish.
 257  */
 258 int
 259 smb_ddiscover_wait(void)
 260 {
 261         timestruc_t to;
 262         int rc = 0;
 263 
 264         (void) mutex_lock(&smb_dclocator.sdl_mtx);
 265 
 266         if (smb_dclocator.sdl_locate) {
 267                 to.tv_sec = SMB_DCLOCATOR_TIMEOUT;
 268                 to.tv_nsec = 0;
 269                 rc = cond_reltimedwait(&smb_dclocator.sdl_cv,
 270                     &smb_dclocator.sdl_mtx, &to);
 271         }
 272 
 273         (void) mutex_unlock(&smb_dclocator.sdl_mtx);
 274 
 275         return (rc);
 276 }
 277 
 278 
 279 /*
 280  * ==========================================================
 281  * DC discovery functions
 282  * ==========================================================
 283  */
 284 
 285 /*
 286  * This is the domain and DC discovery service: it gets woken up whenever
 287  * there is need to locate a domain controller.
 288  *
 289  * Upon success, the SMB domain cache will be populated with the discovered
 290  * DC and domain info.
 291  */
 292 /*ARGSUSED*/
 293 static void *
 294 smb_ddiscover_service(void *arg)
 295 {
 296         smb_domainex_t dxi;
 297         smb_dclocator_t *sdl = arg;
 298         uint32_t status;


 337                 sdl->sdl_cfg_chg = B_FALSE;
 338 
 339                 (void) mutex_unlock(&sdl->sdl_mtx);
 340 
 341                 syslog(LOG_DEBUG, "smb_ddiscover_service running "
 342                     "cfg_chg=%d bad_dc=%d", (int)cfg_chg, (int)bad_dc);
 343 
 344                 /*
 345                  * Clear the cached DC now so that we'll ask idmap again.
 346                  * If our current DC gave us errors, force rediscovery.
 347                  */
 348                 smb_ads_refresh(bad_dc);
 349 
 350                 /*
 351                  * Search for the DC, save the result.
 352                  */
 353                 bzero(&dxi, sizeof (dxi));
 354                 status = smb_ddiscover_main(sdl->sdl_domain, &dxi);
 355                 if (status == 0)
 356                         smb_domain_save();

 357                 (void) mutex_lock(&sdl->sdl_mtx);

 358                 sdl->sdl_status = status;
 359                 if (status == 0)
 360                         sdl->sdl_dci = dxi.d_dci;







 361 
 362                 /*
 363                  * Run again if either of cfg_chg or bad_dc
 364                  * was turned on during smb_ddiscover_main().
 365                  * Note: mutex held here.
 366                  */
 367                 if (sdl->sdl_bad_dc) {
 368                         syslog(LOG_DEBUG, "smb_ddiscover_service "
 369                             "restart because bad_dc was set");
 370                         goto find_again;
 371                 }
 372                 if (sdl->sdl_cfg_chg) {
 373                         syslog(LOG_DEBUG, "smb_ddiscover_service "
 374                             "restart because cfg_chg was set");
 375                         goto find_again;
 376                 }
 377 
 378         wait_again:
 379                 sdl->sdl_locate = B_FALSE;
 380                 sdl->sdl_bad_dc = B_FALSE;


 388 }
 389 
 390 /*
 391  * Discovers a domain controller for the specified domain via DNS.
 392  * After the domain controller is discovered successfully primary and
 393  * trusted domain infromation will be queried using RPC queries.
 394  *
 395  * Caller should zero out *dxi before calling, and after a
 396  * successful return should call:  smb_domain_save()
 397  */
 398 uint32_t
 399 smb_ddiscover_main(char *domain, smb_domainex_t *dxi)
 400 {
 401         uint32_t status;
 402 
 403         if (domain[0] == '\0') {
 404                 syslog(LOG_DEBUG, "smb_ddiscover_main NULL domain");
 405                 return (NT_STATUS_INTERNAL_ERROR);
 406         }
 407 
 408         if (smb_domain_start_update() != SMB_DOMAIN_SUCCESS) {
 409                 syslog(LOG_DEBUG, "smb_ddiscover_main can't get lock");
 410                 return (NT_STATUS_INTERNAL_ERROR);
 411         }
 412 
 413         status = smb_ads_lookup_msdcs(domain, &dxi->d_dci);
 414         if (status != 0) {
 415                 syslog(LOG_DEBUG, "smb_ddiscover_main can't find DC (%s)",
 416                     xlate_nt_status(status));
 417                 goto out;
 418         }
 419 
 420         status = smb_ddiscover_qinfo(domain, dxi->d_dci.dc_name, dxi);
 421         if (status != 0) {
 422                 syslog(LOG_DEBUG,
 423                     "smb_ddiscover_main can't get domain info (%s)",
 424                     xlate_nt_status(status));
 425                 goto out;
 426         }
 427 




 428         smb_domain_update(dxi);
 429 
 430 out:
 431         smb_domain_end_update();

 432 

 433         /* Don't need the trusted domain list anymore. */
 434         smb_domainex_free(dxi);
 435 
 436         return (status);
 437 }
 438 
 439 /*
 440  * Obtain primary and trusted domain information using LSA queries.
 441  *
 442  * domain - either NetBIOS or fully-qualified domain name
 443  */
 444 static uint32_t
 445 smb_ddiscover_qinfo(char *domain, char *server, smb_domainex_t *dxi)
 446 {
 447         uint32_t ret, tmp;
 448 
 449         /* If we must return failure, use this first one. */
 450         ret = lsa_query_dns_domain_info(server, domain, &dxi->d_primary);
 451         if (ret == NT_STATUS_SUCCESS)
 452                 goto success;




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 #include <syslog.h>
  28 #include <synch.h>
  29 #include <pthread.h>
  30 #include <unistd.h>
  31 #include <string.h>
  32 #include <strings.h>
  33 #include <sys/errno.h>
  34 #include <sys/types.h>
  35 #include <netinet/in.h>
  36 #include <arpa/nameser.h>
  37 #include <resolv.h>
  38 #include <netdb.h>
  39 #include <assert.h>
  40 
  41 #include <smbsrv/libsmb.h>
  42 #include <smbsrv/libsmbns.h>
  43 #include <smbsrv/libmlsvc.h>
  44 


  73 static void smb_domainex_free(smb_domainex_t *);
  74 static void smb_set_krb5_realm(char *);
  75 
  76 /*
  77  * ===================================================================
  78  * API to initialize DC locator thread, trigger DC discovery, and
  79  * get the discovered DC and/or domain information.
  80  * ===================================================================
  81  */
  82 
  83 /*
  84  * Initialization of the DC locator thread.
  85  * Returns 0 on success, an error number if thread creation fails.
  86  */
  87 int
  88 smb_dclocator_init(void)
  89 {
  90         pthread_attr_t tattr;
  91         int rc;
  92 
  93         /*
  94          * We need the smb_ddiscover_service to run on startup,
  95          * so it will enter smb_ddiscover_main() and put the
  96          * SMB "domain cache" into "updating" state so clients
  97          * trying to logon will wait while we're finding a DC.
  98          */
  99         smb_dclocator.sdl_locate = B_TRUE;
 100 
 101         (void) pthread_attr_init(&tattr);
 102         (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
 103         rc = pthread_create(&smb_dclocator_thr, &tattr,
 104             smb_ddiscover_service, &smb_dclocator);
 105         (void) pthread_attr_destroy(&tattr);
 106         return (rc);
 107 }
 108 
 109 /*
 110  * This is the entry point for discovering a domain controller for the
 111  * specified domain.  Called during join domain, and then periodically
 112  * by smbd_dc_update (the "DC monitor" thread).
 113  *
 114  * The actual work of discovering a DC is handled by DC locator thread.
 115  * All we do here is signal the request and wait for a DC or a timeout.
 116  *
 117  * Input parameters:
 118  *  domain - domain to be discovered (can either be NetBIOS or DNS domain)
 119  *
 120  * Output parameter:


 232 
 233         if (strcmp(smb_dclocator.sdl_dci.dc_name, bad_dc)) {
 234                 /*
 235                  * The "bad" DC is no longer the current one.
 236                  * Probably a late "bad DC" report.
 237                  */
 238                 goto out;
 239         }
 240         if (smb_dclocator.sdl_bad_dc) {
 241                 /* Someone already marked the current DC as "bad". */
 242                 syslog(LOG_DEBUG, "smb_ddiscover_bad_dc repeat");
 243                 goto out;
 244         }
 245 
 246         /*
 247          * Mark the current DC as "bad" and let the DC Locator
 248          * run again if it's not already.
 249          */
 250         syslog(LOG_INFO, "smb_ddiscover, bad DC: %s", bad_dc);
 251         smb_dclocator.sdl_bad_dc = B_TRUE;
 252         smb_domain_bad_dc();
 253 
 254         /* In-line smb_ddiscover_kick */
 255         if (!smb_dclocator.sdl_locate) {
 256                 smb_dclocator.sdl_locate = B_TRUE;
 257                 (void) cond_broadcast(&smb_dclocator.sdl_cv);
 258         }
 259 
 260 out:
 261         (void) mutex_unlock(&smb_dclocator.sdl_mtx);
 262 }
 263 








 264 















 265 /*
 266  * ==========================================================
 267  * DC discovery functions
 268  * ==========================================================
 269  */
 270 
 271 /*
 272  * This is the domain and DC discovery service: it gets woken up whenever
 273  * there is need to locate a domain controller.
 274  *
 275  * Upon success, the SMB domain cache will be populated with the discovered
 276  * DC and domain info.
 277  */
 278 /*ARGSUSED*/
 279 static void *
 280 smb_ddiscover_service(void *arg)
 281 {
 282         smb_domainex_t dxi;
 283         smb_dclocator_t *sdl = arg;
 284         uint32_t status;


 323                 sdl->sdl_cfg_chg = B_FALSE;
 324 
 325                 (void) mutex_unlock(&sdl->sdl_mtx);
 326 
 327                 syslog(LOG_DEBUG, "smb_ddiscover_service running "
 328                     "cfg_chg=%d bad_dc=%d", (int)cfg_chg, (int)bad_dc);
 329 
 330                 /*
 331                  * Clear the cached DC now so that we'll ask idmap again.
 332                  * If our current DC gave us errors, force rediscovery.
 333                  */
 334                 smb_ads_refresh(bad_dc);
 335 
 336                 /*
 337                  * Search for the DC, save the result.
 338                  */
 339                 bzero(&dxi, sizeof (dxi));
 340                 status = smb_ddiscover_main(sdl->sdl_domain, &dxi);
 341                 if (status == 0)
 342                         smb_domain_save();
 343 
 344                 (void) mutex_lock(&sdl->sdl_mtx);
 345 
 346                 sdl->sdl_status = status;
 347                 if (status == 0) {
 348                         sdl->sdl_dci = dxi.d_dci;
 349                 } else {
 350                         syslog(LOG_DEBUG, "smb_ddiscover_service "
 351                             "retry after STATUS_%s",
 352                             xlate_nt_status(status));
 353                         (void) sleep(5);
 354                         goto find_again;
 355                 }
 356 
 357                 /*
 358                  * Run again if either of cfg_chg or bad_dc
 359                  * was turned on during smb_ddiscover_main().
 360                  * Note: mutex held here.
 361                  */
 362                 if (sdl->sdl_bad_dc) {
 363                         syslog(LOG_DEBUG, "smb_ddiscover_service "
 364                             "restart because bad_dc was set");
 365                         goto find_again;
 366                 }
 367                 if (sdl->sdl_cfg_chg) {
 368                         syslog(LOG_DEBUG, "smb_ddiscover_service "
 369                             "restart because cfg_chg was set");
 370                         goto find_again;
 371                 }
 372 
 373         wait_again:
 374                 sdl->sdl_locate = B_FALSE;
 375                 sdl->sdl_bad_dc = B_FALSE;


 383 }
 384 
 385 /*
 386  * Discovers a domain controller for the specified domain via DNS.
 387  * After the domain controller is discovered successfully primary and
 388  * trusted domain infromation will be queried using RPC queries.
 389  *
 390  * Caller should zero out *dxi before calling, and after a
 391  * successful return should call:  smb_domain_save()
 392  */
 393 uint32_t
 394 smb_ddiscover_main(char *domain, smb_domainex_t *dxi)
 395 {
 396         uint32_t status;
 397 
 398         if (domain[0] == '\0') {
 399                 syslog(LOG_DEBUG, "smb_ddiscover_main NULL domain");
 400                 return (NT_STATUS_INTERNAL_ERROR);
 401         }
 402 





 403         status = smb_ads_lookup_msdcs(domain, &dxi->d_dci);
 404         if (status != 0) {
 405                 syslog(LOG_DEBUG, "smb_ddiscover_main can't find DC (%s)",
 406                     xlate_nt_status(status));
 407                 goto out;
 408         }
 409 
 410         status = smb_ddiscover_qinfo(domain, dxi->d_dci.dc_name, dxi);
 411         if (status != 0) {
 412                 syslog(LOG_DEBUG,
 413                     "smb_ddiscover_main can't get domain info (%s)",
 414                     xlate_nt_status(status));
 415                 goto out;
 416         }
 417 
 418         if (smb_domain_start_update() != SMB_DOMAIN_SUCCESS) {
 419                 syslog(LOG_DEBUG, "smb_ddiscover_main can't get lock");
 420                 status = NT_STATUS_INTERNAL_ERROR;
 421         } else {
 422                 smb_domain_update(dxi);


 423                 smb_domain_end_update();
 424         }
 425 
 426 out:
 427         /* Don't need the trusted domain list anymore. */
 428         smb_domainex_free(dxi);
 429 
 430         return (status);
 431 }
 432 
 433 /*
 434  * Obtain primary and trusted domain information using LSA queries.
 435  *
 436  * domain - either NetBIOS or fully-qualified domain name
 437  */
 438 static uint32_t
 439 smb_ddiscover_qinfo(char *domain, char *server, smb_domainex_t *dxi)
 440 {
 441         uint32_t ret, tmp;
 442 
 443         /* If we must return failure, use this first one. */
 444         ret = lsa_query_dns_domain_info(server, domain, &dxi->d_primary);
 445         if (ret == NT_STATUS_SUCCESS)
 446                 goto success;