root/source3/auth/auth_sam.c

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

DEFINITIONS

This source file includes following definitions.
  1. sam_password_ok
  2. logon_hours_ok
  3. sam_account_ok
  4. check_sam_security
  5. auth_init_sam_ignoredomain
  6. check_samstrict_security
  7. auth_init_sam
  8. auth_sam_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Password and authentication handling
   4    Copyright (C) Andrew Tridgell              1992-2000
   5    Copyright (C) Luke Kenneth Casson Leighton 1996-2000
   6    Copyright (C) Andrew Bartlett              2001-2003
   7    Copyright (C) Gerald Carter                2003
   8 
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 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 
  25 #undef DBGC_CLASS
  26 #define DBGC_CLASS DBGC_AUTH
  27 
  28 /****************************************************************************
  29  Do a specific test for an smb password being correct, given a smb_password and
  30  the lanman and NT responses.
  31 ****************************************************************************/
  32 
  33 static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
     /* [<][>][^][v][top][bottom][index][help] */
  34                                 TALLOC_CTX *mem_ctx,
  35                                 struct samu *sampass, 
  36                                 const auth_usersupplied_info *user_info, 
  37                                 DATA_BLOB *user_sess_key, 
  38                                 DATA_BLOB *lm_sess_key)
  39 {
  40         uint32 acct_ctrl;
  41         const uint8 *lm_pw, *nt_pw;
  42         const char *username = pdb_get_username(sampass);
  43 
  44         acct_ctrl = pdb_get_acct_ctrl(sampass);
  45         if (acct_ctrl & ACB_PWNOTREQ) {
  46                 if (lp_null_passwords()) {
  47                         DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", username));
  48                         return NT_STATUS_OK;
  49                 } else {
  50                         DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", username));
  51                         return NT_STATUS_LOGON_FAILURE;
  52                 }               
  53         }
  54 
  55         lm_pw = pdb_get_lanman_passwd(sampass);
  56         nt_pw = pdb_get_nt_passwd(sampass);
  57 
  58         return ntlm_password_check(mem_ctx, &auth_context->challenge, 
  59                                    &user_info->lm_resp, &user_info->nt_resp, 
  60                                    &user_info->lm_interactive_pwd, &user_info->nt_interactive_pwd,
  61                                    username, 
  62                                    user_info->smb_name,
  63                                    user_info->client_domain,
  64                                    lm_pw, nt_pw, user_sess_key, lm_sess_key);
  65 }
  66 
  67 /****************************************************************************
  68  Check if a user is allowed to logon at this time. Note this is the
  69  servers local time, as logon hours are just specified as a weekly
  70  bitmask.
  71 ****************************************************************************/
  72 
  73 static bool logon_hours_ok(struct samu *sampass)
     /* [<][>][^][v][top][bottom][index][help] */
  74 {
  75         /* In logon hours first bit is Sunday from 12AM to 1AM */
  76         const uint8 *hours;
  77         struct tm *utctime;
  78         time_t lasttime;
  79         const char *asct;
  80         uint8 bitmask, bitpos;
  81 
  82         hours = pdb_get_hours(sampass);
  83         if (!hours) {
  84                 DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n",pdb_get_username(sampass)));
  85                 return True;
  86         }
  87 
  88         lasttime = time(NULL);
  89         utctime = gmtime(&lasttime);
  90         if (!utctime) {
  91                 DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
  92                         pdb_get_username(sampass) ));
  93                 return False;
  94         }
  95 
  96         /* find the corresponding byte and bit */
  97         bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
  98         bitmask = 1 << (bitpos % 8);
  99 
 100         if (! (hours[bitpos/8] & bitmask)) {
 101                 struct tm *t = localtime(&lasttime);
 102                 if (!t) {
 103                         asct = "INVALID TIME";
 104                 } else {
 105                         asct = asctime(t);
 106                         if (!asct) {
 107                                 asct = "INVALID TIME";
 108                         }
 109                 }
 110 
 111                 DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
 112                           "logon at this time (%s).\n",
 113                           pdb_get_username(sampass), asct ));
 114                 return False;
 115         }
 116 
 117         asct = asctime(utctime);
 118         DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
 119                 pdb_get_username(sampass), asct ? asct : "UNKNOWN TIME" ));
 120 
 121         return True;
 122 }
 123 
 124 /****************************************************************************
 125  Do a specific test for a struct samu being valid for this connection
 126  (ie not disabled, expired and the like).
 127 ****************************************************************************/
 128 
 129 static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 130                                struct samu *sampass, 
 131                                const auth_usersupplied_info *user_info)
 132 {
 133         uint32  acct_ctrl = pdb_get_acct_ctrl(sampass);
 134         char *workstation_list;
 135         time_t kickoff_time;
 136 
 137         DEBUG(4,("sam_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));
 138 
 139         /* Quit if the account was disabled. */
 140         if (acct_ctrl & ACB_DISABLED) {
 141                 DEBUG(1,("sam_account_ok: Account for user '%s' was disabled.\n", pdb_get_username(sampass)));
 142                 return NT_STATUS_ACCOUNT_DISABLED;
 143         }
 144 
 145         /* Quit if the account was locked out. */
 146         if (acct_ctrl & ACB_AUTOLOCK) {
 147                 DEBUG(1,("sam_account_ok: Account for user %s was locked out.\n", pdb_get_username(sampass)));
 148                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
 149         }
 150 
 151         /* Quit if the account is not allowed to logon at this time. */
 152         if (! logon_hours_ok(sampass)) {
 153                 return NT_STATUS_INVALID_LOGON_HOURS;
 154         }
 155 
 156         /* Test account expire time */
 157 
 158         kickoff_time = pdb_get_kickoff_time(sampass);
 159         if (kickoff_time != 0 && time(NULL) > kickoff_time) {
 160                 DEBUG(1,("sam_account_ok: Account for user '%s' has expired.\n", pdb_get_username(sampass)));
 161                 DEBUG(3,("sam_account_ok: Account expired at '%ld' unix time.\n", (long)kickoff_time));
 162                 return NT_STATUS_ACCOUNT_EXPIRED;
 163         }
 164 
 165         if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP) && !(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) {
 166                 time_t must_change_time = pdb_get_pass_must_change_time(sampass);
 167                 time_t last_set_time = pdb_get_pass_last_set_time(sampass);
 168 
 169                 /* check for immediate expiry "must change at next logon" 
 170                  * for a user account. */
 171                 if (((acct_ctrl & (ACB_WSTRUST|ACB_SVRTRUST)) == 0) && (last_set_time == 0)) {
 172                         DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
 173                         return NT_STATUS_PASSWORD_MUST_CHANGE;
 174                 }
 175 
 176                 /* check for expired password */
 177                 if (must_change_time < time(NULL) && must_change_time != 0) {
 178                         DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
 179                         DEBUG(1,("sam_account_ok: Password expired at '%s' (%ld) unix time.\n", http_timestring(talloc_tos(), must_change_time), (long)must_change_time));
 180                         return NT_STATUS_PASSWORD_EXPIRED;
 181                 }
 182         }
 183 
 184         /* Test workstation. Workstation list is comma separated. */
 185 
 186         workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
 187         if (!workstation_list)
 188                 return NT_STATUS_NO_MEMORY;
 189 
 190         if (*workstation_list) {
 191                 bool invalid_ws = True;
 192                 char *tok;
 193                 const char *s = workstation_list;
 194 
 195                 const char *machine_name = talloc_asprintf(mem_ctx, "%s$", user_info->wksta_name);
 196                 if (machine_name == NULL)
 197                         return NT_STATUS_NO_MEMORY;
 198 
 199                 while (next_token_talloc(mem_ctx, &s, &tok, ",")) {
 200                         DEBUG(10,("sam_account_ok: checking for workstation match %s and %s\n",
 201                                   tok, user_info->wksta_name));
 202                         if(strequal(tok, user_info->wksta_name)) {
 203                                 invalid_ws = False;
 204                                 break;
 205                         }
 206                         if (tok[0] == '+') {
 207                                 DEBUG(10,("sam_account_ok: checking for workstation %s in group: %s\n", 
 208                                         machine_name, tok + 1));
 209                                 if (user_in_group(machine_name, tok + 1)) {
 210                                         invalid_ws = False;
 211                                         break;
 212                                 }
 213                         }
 214                         TALLOC_FREE(tok);
 215                 }
 216                 TALLOC_FREE(tok);
 217 
 218                 if (invalid_ws)
 219                         return NT_STATUS_INVALID_WORKSTATION;
 220         }
 221 
 222         if (acct_ctrl & ACB_DOMTRUST) {
 223                 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", pdb_get_username(sampass)));
 224                 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
 225         }
 226 
 227         if (acct_ctrl & ACB_SVRTRUST) {
 228                 if (!(user_info->logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
 229                         DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", pdb_get_username(sampass)));
 230                         return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
 231                 }
 232         }
 233 
 234         if (acct_ctrl & ACB_WSTRUST) {
 235                 if (!(user_info->logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
 236                         DEBUG(2,("sam_account_ok: Wksta trust account %s denied by server\n", pdb_get_username(sampass)));
 237                         return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
 238                 }
 239         }
 240         return NT_STATUS_OK;
 241 }
 242 
 243 /****************************************************************************
 244 check if a username/password is OK assuming the password is a 24 byte
 245 SMB hash supplied in the user_info structure
 246 return an NT_STATUS constant.
 247 ****************************************************************************/
 248 
 249 static NTSTATUS check_sam_security(const struct auth_context *auth_context,
     /* [<][>][^][v][top][bottom][index][help] */
 250                                    void *my_private_data, 
 251                                    TALLOC_CTX *mem_ctx,
 252                                    const auth_usersupplied_info *user_info, 
 253                                    auth_serversupplied_info **server_info)
 254 {
 255         struct samu *sampass=NULL;
 256         bool ret;
 257         NTSTATUS nt_status;
 258         NTSTATUS update_login_attempts_status;
 259         DATA_BLOB user_sess_key = data_blob_null;
 260         DATA_BLOB lm_sess_key = data_blob_null;
 261         bool updated_autolock = False, updated_badpw = False;
 262 
 263         if (!user_info || !auth_context) {
 264                 return NT_STATUS_UNSUCCESSFUL;
 265         }
 266 
 267         /* the returned struct gets kept on the server_info, by means
 268            of a steal further down */
 269 
 270         if ( !(sampass = samu_new( mem_ctx )) ) {
 271                 return NT_STATUS_NO_MEMORY;
 272         }
 273 
 274         /* get the account information */
 275 
 276         become_root();
 277         ret = pdb_getsampwnam(sampass, user_info->internal_username);
 278         unbecome_root();
 279 
 280         if (ret == False) {
 281                 DEBUG(3,("check_sam_security: Couldn't find user '%s' in "
 282                          "passdb.\n", user_info->internal_username));
 283                 TALLOC_FREE(sampass);
 284                 return NT_STATUS_NO_SUCH_USER;
 285         }
 286 
 287         /* see if autolock flag needs to be updated */
 288         if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL)
 289                 pdb_update_autolock_flag(sampass, &updated_autolock);
 290         /* Quit if the account was locked out. */
 291         if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) {
 292                 DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", pdb_get_username(sampass)));
 293                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
 294         }
 295 
 296         nt_status = sam_password_ok(auth_context, mem_ctx, sampass, 
 297                                     user_info, &user_sess_key, &lm_sess_key);
 298 
 299         /* Notify passdb backend of login success/failure. If not 
 300            NT_STATUS_OK the backend doesn't like the login */
 301 
 302         update_login_attempts_status = pdb_update_login_attempts(sampass, NT_STATUS_IS_OK(nt_status));
 303 
 304         if (!NT_STATUS_IS_OK(nt_status)) {
 305                 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_WRONG_PASSWORD) && 
 306                     pdb_get_acct_ctrl(sampass) &ACB_NORMAL &&
 307                     NT_STATUS_IS_OK(update_login_attempts_status)) 
 308                 {  
 309                         pdb_increment_bad_password_count(sampass);
 310                         updated_badpw = True;
 311                 } else {
 312                         pdb_update_bad_password_count(sampass, 
 313                                                       &updated_badpw);
 314                 }
 315                 if (updated_autolock || updated_badpw){
 316                         become_root();
 317                         if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass)))
 318                                 DEBUG(1, ("Failed to modify entry.\n"));
 319                         unbecome_root();
 320                 }
 321                 data_blob_free(&user_sess_key);
 322                 data_blob_free(&lm_sess_key);
 323                 TALLOC_FREE(sampass);
 324                 return nt_status;
 325         }
 326 
 327         if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) && 
 328             (pdb_get_bad_password_count(sampass) > 0)){
 329                 pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
 330                 pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
 331                 updated_badpw = True;
 332         }
 333 
 334         if (updated_autolock || updated_badpw){
 335                 become_root();
 336                 if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass)))
 337                         DEBUG(1, ("Failed to modify entry.\n"));
 338                 unbecome_root();
 339         }
 340 
 341         nt_status = sam_account_ok(mem_ctx, sampass, user_info);
 342 
 343         if (!NT_STATUS_IS_OK(nt_status)) {
 344                 TALLOC_FREE(sampass);
 345                 data_blob_free(&user_sess_key);
 346                 data_blob_free(&lm_sess_key);
 347                 return nt_status;
 348         }
 349 
 350         become_root();
 351         nt_status = make_server_info_sam(server_info, sampass);
 352         unbecome_root();
 353 
 354         if (!NT_STATUS_IS_OK(nt_status)) {
 355                 DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status)));
 356                 data_blob_free(&user_sess_key);
 357                 data_blob_free(&lm_sess_key);
 358                 return nt_status;
 359         }
 360 
 361         (*server_info)->user_session_key =
 362                 data_blob_talloc(*server_info, user_sess_key.data,
 363                                  user_sess_key.length);
 364         data_blob_free(&user_sess_key);
 365 
 366         (*server_info)->lm_session_key =
 367                 data_blob_talloc(*server_info, lm_sess_key.data,
 368                                  lm_sess_key.length);
 369         data_blob_free(&lm_sess_key);
 370 
 371         (*server_info)->nss_token |= user_info->was_mapped;
 372 
 373         return nt_status;
 374 }
 375 
 376 /* module initialisation */
 377 static NTSTATUS auth_init_sam_ignoredomain(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
     /* [<][>][^][v][top][bottom][index][help] */
 378 {
 379         if (!make_auth_methods(auth_context, auth_method)) {
 380                 return NT_STATUS_NO_MEMORY;
 381         }
 382 
 383         (*auth_method)->auth = check_sam_security;      
 384         (*auth_method)->name = "sam_ignoredomain";
 385         return NT_STATUS_OK;
 386 }
 387 
 388 
 389 /****************************************************************************
 390 Check SAM security (above) but with a few extra checks.
 391 ****************************************************************************/
 392 
 393 static NTSTATUS check_samstrict_security(const struct auth_context *auth_context,
     /* [<][>][^][v][top][bottom][index][help] */
 394                                          void *my_private_data, 
 395                                          TALLOC_CTX *mem_ctx,
 396                                          const auth_usersupplied_info *user_info, 
 397                                          auth_serversupplied_info **server_info)
 398 {
 399         bool is_local_name, is_my_domain;
 400 
 401         if (!user_info || !auth_context) {
 402                 return NT_STATUS_LOGON_FAILURE;
 403         }
 404 
 405         is_local_name = is_myname(user_info->domain);
 406         is_my_domain  = strequal(user_info->domain, lp_workgroup());
 407 
 408         /* check whether or not we service this domain/workgroup name */
 409 
 410         switch ( lp_server_role() ) {
 411                 case ROLE_STANDALONE:
 412                 case ROLE_DOMAIN_MEMBER:
 413                         if ( !is_local_name ) {
 414                                 DEBUG(6,("check_samstrict_security: %s is not one of my local names (%s)\n",
 415                                         user_info->domain, (lp_server_role() == ROLE_DOMAIN_MEMBER 
 416                                         ? "ROLE_DOMAIN_MEMBER" : "ROLE_STANDALONE") ));
 417                                 return NT_STATUS_NOT_IMPLEMENTED;
 418                         }
 419                 case ROLE_DOMAIN_PDC:
 420                 case ROLE_DOMAIN_BDC:
 421                         if ( !is_local_name && !is_my_domain ) {
 422                                 DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n",
 423                                         user_info->domain));
 424                                 return NT_STATUS_NOT_IMPLEMENTED;
 425                         }
 426                 default: /* name is ok */
 427                         break;
 428         }
 429 
 430         return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
 431 }
 432 
 433 /* module initialisation */
 434 static NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
     /* [<][>][^][v][top][bottom][index][help] */
 435 {
 436         if (!make_auth_methods(auth_context, auth_method)) {
 437                 return NT_STATUS_NO_MEMORY;
 438         }
 439 
 440         (*auth_method)->auth = check_samstrict_security;
 441         (*auth_method)->name = "sam";
 442         return NT_STATUS_OK;
 443 }
 444 
 445 NTSTATUS auth_sam_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 446 {
 447         smb_register_auth(AUTH_INTERFACE_VERSION, "sam", auth_init_sam);
 448         smb_register_auth(AUTH_INTERFACE_VERSION, "sam_ignoredomain", auth_init_sam_ignoredomain);
 449         return NT_STATUS_OK;
 450 }

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