Пример #1
0
static NTSTATUS row_to_sam_account ( PGresult *r, long row, SAM_ACCOUNT *u )
{
  pstring temp ;
  DOM_SID sid ;
  
  if ( row >= PQntuples( r ) ) return NT_STATUS_INVALID_PARAMETER ;

  pdb_set_logon_time           ( u, PQgetlong ( r, row,  0 ), PDB_SET ) ;
  pdb_set_logoff_time          ( u, PQgetlong ( r, row,  1 ), PDB_SET ) ;
  pdb_set_kickoff_time         ( u, PQgetlong ( r, row,  2 ), PDB_SET ) ;
  pdb_set_pass_last_set_time   ( u, PQgetlong ( r, row,  3 ), PDB_SET ) ;
  pdb_set_pass_can_change_time ( u, PQgetlong ( r, row,  4 ), PDB_SET ) ;
  pdb_set_pass_must_change_time( u, PQgetlong ( r, row,  5 ), PDB_SET ) ;
  pdb_set_username             ( u, PQgetvalue( r, row,  6 ), PDB_SET ) ;
  pdb_set_domain               ( u, PQgetvalue( r, row,  7 ), PDB_SET ) ;
  pdb_set_nt_username          ( u, PQgetvalue( r, row,  8 ), PDB_SET ) ;
  pdb_set_fullname             ( u, PQgetvalue( r, row,  9 ), PDB_SET ) ;
  pdb_set_homedir              ( u, PQgetvalue( r, row, 10 ), PDB_SET ) ;
  pdb_set_dir_drive            ( u, PQgetvalue( r, row, 11 ), PDB_SET ) ;
  pdb_set_logon_script         ( u, PQgetvalue( r, row, 12 ), PDB_SET ) ;
  pdb_set_profile_path         ( u, PQgetvalue( r, row, 13 ), PDB_SET ) ;
  pdb_set_acct_desc            ( u, PQgetvalue( r, row, 14 ), PDB_SET ) ;
  pdb_set_workstations         ( u, PQgetvalue( r, row, 15 ), PDB_SET ) ;
  pdb_set_unknown_str          ( u, PQgetvalue( r, row, 16 ), PDB_SET ) ;
  pdb_set_munged_dial          ( u, PQgetvalue( r, row, 17 ), PDB_SET ) ;
  
  pdb_set_acct_ctrl            ( u, PQgetlong ( r, row, 23 ), PDB_SET ) ;
  pdb_set_logon_divs           ( u, PQgetlong ( r, row, 24 ), PDB_SET ) ;
  pdb_set_hours_len            ( u, PQgetlong ( r, row, 25 ), PDB_SET ) ;
  pdb_set_bad_password_count	( u, PQgetlong (r, row, 26 ), PDB_SET ) ;
  pdb_set_logon_count            ( u, PQgetlong ( r, row, 27 ), PDB_SET ) ;
  pdb_set_unknown_6            ( u, PQgetlong ( r, row, 28 ), PDB_SET ) ;
  
  if ( !PQgetisnull( r, row, 18 ) ) {
    string_to_sid( &sid, PQgetvalue( r, row, 18 ) ) ;
    pdb_set_user_sid ( u, &sid, PDB_SET ) ;
  }

  if ( !PQgetisnull( r, row, 19 ) ) {
    string_to_sid( &sid, PQgetvalue( r, row, 19 ) ) ;
    pdb_set_group_sid( u, &sid, PDB_SET ) ;
  }
  
  if ( pdb_gethexpwd( PQgetvalue( r, row, 20 ), temp ), PDB_SET ) pdb_set_lanman_passwd( u, temp, PDB_SET ) ;
  if ( pdb_gethexpwd( PQgetvalue( r, row, 21 ), temp ), PDB_SET ) pdb_set_nt_passwd    ( u, temp, PDB_SET ) ;
  
  /* Only use plaintext password storage when lanman and nt are NOT used */
  if ( PQgetisnull( r, row, 20 ) || PQgetisnull( r, row, 21 ) ) pdb_set_plaintext_passwd( u, PQgetvalue( r, row, 22 ) ) ;
  
  return NT_STATUS_OK ;
}
Пример #2
0
static int set_user_info(const char *username, const char *fullname,
			 const char *homedir, const char *acct_desc,
			 const char *drive, const char *script,
			 const char *profile, const char *account_control,
			 const char *user_sid, const char *user_domain,
			 const bool badpw, const bool hours,
			 const char *kickoff_time)
{
	bool updated_autolock = False, updated_badpw = False;
	struct samu *sam_pwent;
	uint8_t hours_array[MAX_HOURS_LEN];
	uint32_t hours_len;
	uint32_t acb_flags;
	uint32_t not_settable;
	uint32_t new_flags;
	struct dom_sid u_sid;
	bool ret;

	sam_pwent = samu_new(NULL);
	if (!sam_pwent) {
		return 1;
	}

	ret = pdb_getsampwnam(sam_pwent, username);
	if (!ret) {
		fprintf (stderr, "Username not found!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}

	if (hours) {
		hours_len = pdb_get_hours_len(sam_pwent);
		memset(hours_array, 0xff, hours_len);

		pdb_set_hours(sam_pwent, hours_array, hours_len, PDB_CHANGED);
	}

	if (!pdb_update_autolock_flag(sam_pwent, &updated_autolock)) {
		DEBUG(2,("pdb_update_autolock_flag failed.\n"));
	}

	if (!pdb_update_bad_password_count(sam_pwent, &updated_badpw)) {
		DEBUG(2,("pdb_update_bad_password_count failed.\n"));
	}

	if (fullname)
		pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
	if (acct_desc)
		pdb_set_acct_desc(sam_pwent, acct_desc, PDB_CHANGED);
	if (homedir)
		pdb_set_homedir(sam_pwent, homedir, PDB_CHANGED);
	if (drive)
		pdb_set_dir_drive(sam_pwent,drive, PDB_CHANGED);
	if (script)
		pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
	if (profile)
		pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
	if (user_domain)
		pdb_set_domain(sam_pwent, user_domain, PDB_CHANGED);

	if (account_control) {
		not_settable = ~(ACB_DISABLED | ACB_HOMDIRREQ |
				 ACB_PWNOTREQ | ACB_PWNOEXP | ACB_AUTOLOCK);

		new_flags = pdb_decode_acct_ctrl(account_control);

		if (new_flags & not_settable) {
			fprintf(stderr, "Can only set [NDHLX] flags\n");
			TALLOC_FREE(sam_pwent);
			return -1;
		}

		acb_flags = pdb_get_acct_ctrl(sam_pwent);

		pdb_set_acct_ctrl(sam_pwent,
				  (acb_flags & not_settable) | new_flags,
				  PDB_CHANGED);
	}
	if (user_sid) {
		if (get_sid_from_cli_string(&u_sid, user_sid)) {
			fprintf(stderr, "Failed to parse SID\n");
			return -1;
		}
		pdb_set_user_sid(sam_pwent, &u_sid, PDB_CHANGED);
	}

	if (badpw) {
		pdb_set_bad_password_count(sam_pwent, 0, PDB_CHANGED);
		pdb_set_bad_password_time(sam_pwent, 0, PDB_CHANGED);
	}

	if (kickoff_time) {
		char *endptr;
		time_t value = get_time_t_max();

		if (strcmp(kickoff_time, "never") != 0) {
			uint32_t num = strtoul(kickoff_time, &endptr, 10);

			if ((endptr == kickoff_time) || (endptr[0] != '\0')) {
				fprintf(stderr, "Failed to parse kickoff time\n");
				return -1;
			}

			value = convert_uint32_t_to_time_t(num);
		}

		pdb_set_kickoff_time(sam_pwent, value, PDB_CHANGED);
	}

	if (NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) {
		print_user_info(username, True, False);
	} else {
		fprintf (stderr, "Unable to modify entry!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}
	TALLOC_FREE(sam_pwent);
	return 0;
}
Пример #3
0
/************************************************************************
 makes a struct sam_passwd from a NIS+ object.
 ************************************************************************/
static BOOL make_sam_from_nisp_object(SAM_ACCOUNT *pw_buf, nis_object *obj)
{
  char *ptr;
  pstring full_name;    /* this must be translated to dos code page */
  pstring acct_desc;    /* this must be translated to dos code page */
  pstring home_dir;     /* set default value from smb.conf for user */
  pstring home_drive;   /* set default value from smb.conf for user */
  pstring logon_script; /* set default value from smb.conf for user */
  pstring profile_path; /* set default value from smb.conf for user */
  pstring hours;
  int hours_len;
  unsigned char smbpwd[16];
  unsigned char smbntpwd[16];
  

  /*
   * time values. note: this code assumes 32bit time_t!
   */

  pdb_set_logon_time(pw_buf, (time_t)0);
  ptr = ENTRY_VAL(obj, NPF_LOGON_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "LNT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_logon_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }

  pdb_set_logoff_time(pw_buf, get_time_t_max());
  ptr = ENTRY_VAL(obj, NPF_LOGOFF_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "LOT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_logoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }

  pdb_set_kickoff_time(pw_buf, get_time_t_max());
  ptr = ENTRY_VAL(obj, NPF_KICK_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "KOT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_kickoff_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }

  pdb_set_pass_last_set_time(pw_buf, (time_t)0);
  ptr = ENTRY_VAL(obj, NPF_PWDLSET_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "LCT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_pass_last_set_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }
  
  pdb_set_pass_can_change_time(pw_buf, (time_t)0);
  ptr = ENTRY_VAL(obj, NPF_PWDCCHG_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "CCT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_pass_can_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }
  
  pdb_set_pass_must_change_time(pw_buf, get_time_t_max()); /* Password never expires. */
  ptr = ENTRY_VAL(obj, NPF_PWDMCHG_T);
  if(ptr && *ptr && (StrnCaseCmp(ptr, "MCT-", 4)==0)) {
    int i;
    ptr += 4;
    for(i = 0; i < 8; i++) {
      if(ptr[i] == '\0' || !isxdigit(ptr[i]))
	break;
    }
    if(i == 8) {
      pdb_set_pass_must_change_time(pw_buf, (time_t)strtol(ptr, NULL, 16));
    }
  }

  /* string values */
  pdb_set_username(pw_buf, ENTRY_VAL(obj, NPF_NAME));
  pdb_set_domain(pw_buf, lp_workgroup());
  /* pdb_set_nt_username() -- cant set it here... */

  get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
  unix_to_dos(full_name);
  pdb_set_fullname(pw_buf, full_name);

  pdb_set_acct_ctrl(pw_buf, pdb_decode_acct_ctrl(ENTRY_VAL(obj,
							   NPF_ACB)));

  get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
  unix_to_dos(acct_desc);
  pdb_set_acct_desc(pw_buf, acct_desc);

  pdb_set_workstations(pw_buf, ENTRY_VAL(obj, NPF_WORKSTATIONS));
  pdb_set_munged_dial(pw_buf, NULL);

/* Might want to consult sys_getpwnam for the following two.
  for now, use same default as pdb_fill-default_sam */

  ptr = ENTRY_VAL(obj, NPF_UID);
  pdb_set_uid(pw_buf, ptr ? atoi(ptr) : -1);

  ptr = ENTRY_VAL(obj, NPF_SMB_GRPID);
  pdb_set_gid(pw_buf, ptr ? atoi(ptr) : -1);


  ptr = ENTRY_VAL(obj, NPF_USER_RID); 
  pdb_set_user_rid(pw_buf, ptr ? atoi(ptr) : 
	pdb_uid_to_user_rid(pdb_get_uid(pw_buf)));

  ptr = ENTRY_VAL(obj, NPF_GROUP_RID);
  pdb_set_group_rid(pw_buf, ptr ? atoi(ptr) :
	pdb_gid_to_group_rid(pdb_get_gid(pw_buf)));


  /* values, must exist for user */
  if( !(pdb_get_acct_ctrl(pw_buf) & ACB_WSTRUST) ) {
    /* FIXME!!  This doesn't belong here. 
       Should be set in net_sam_logon() 
       --jerry */
    pstrcpy(samlogon_user, pdb_get_username(pw_buf));
    
    get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
    if( !(home_dir && *home_dir) ) {
      pstrcpy(home_dir, lp_logon_home());
      pdb_set_homedir(pw_buf, home_dir, False);
    }
    else
      pdb_set_homedir(pw_buf, home_dir, True);

    get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
    if( !(home_drive && *home_drive) ) {
      pstrcpy(home_drive, lp_logon_drive());
      pdb_set_dir_drive(pw_buf, home_drive, False);
    }
    else
      pdb_set_dir_drive(pw_buf, home_drive, True);

    get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script,
			 sizeof(pstring));
    if( !(logon_script && *logon_script) ) {
      pstrcpy(logon_script, lp_logon_script());
      pdb_set_logon_script(pw_buf, logon_script, False);
    }
    else
      pdb_set_logon_script(pw_buf, logon_script, True);

    get_single_attribute(obj, NPF_PROFILE_PATH, profile_path, sizeof(pstring));
    if( !(profile_path && *profile_path) ) {
      pstrcpy(profile_path, lp_logon_path());
      pdb_set_profile_path(pw_buf, profile_path, False);
    }
    else
      pdb_set_profile_path(pw_buf, profile_path, True);

  } 
  else 
  {
    /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
    pdb_set_group_rid (pw_buf, DOMAIN_GROUP_RID_USERS); 
  }

  /* Check the lanman password column. */
  ptr = ENTRY_VAL(obj, NPF_LMPWD);
  if (!pdb_set_lanman_passwd(pw_buf, NULL))
	return False;

  if (!strncasecmp(ptr, "NO PASSWORD", 11)) {
    pdb_set_acct_ctrl(pw_buf, pdb_get_acct_ctrl(pw_buf) | ACB_PWNOTREQ);
  } else {
    if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbpwd)) {
      DEBUG(0, ("malformed LM pwd entry: %s.\n",
		pdb_get_username(pw_buf)));
      return False;
    } 
    if (!pdb_set_lanman_passwd(pw_buf, smbpwd))
		return False;
  }
  
  /* Check the NT password column. */
  ptr = ENTRY_VAL(obj, NPF_NTPWD);
  if (!pdb_set_nt_passwd(pw_buf, NULL))
	return False;
  
  if (!(pdb_get_acct_ctrl(pw_buf) & ACB_PWNOTREQ) &&
      strncasecmp(ptr, "NO PASSWORD", 11)) {
    if (strlen(ptr) != 32 || !pdb_gethexpwd(ptr, smbntpwd)) {
      DEBUG(0, ("malformed NT pwd entry:\
 uid = %d.\n",
		pdb_get_uid(pw_buf)));
      return False;
    }
    if (!pdb_set_nt_passwd(pw_buf, smbntpwd))
		return False;
  }
Пример #4
0
static int set_user_info (struct pdb_methods *in, const char *username, 
			  const char *fullname, const char *homedir, 
			  const char *acct_desc, 
			  const char *drive, const char *script, 
			  const char *profile, const char *account_control,
			  const char *user_sid, const char *user_domain,
			  const BOOL badpw, const BOOL hours)
{
	BOOL updated_autolock = False, updated_badpw = False;
	struct samu *sam_pwent=NULL;
	BOOL ret;
	
	if ( (sam_pwent = samu_new( NULL )) == NULL ) {
		return 1;
	}
	
	ret = NT_STATUS_IS_OK(in->getsampwnam (in, sam_pwent, username));
	if (ret==False) {
		fprintf (stderr, "Username not found!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}

	if (hours) {
		uint8 hours_array[MAX_HOURS_LEN];
		uint32 hours_len;
		
		hours_len = pdb_get_hours_len(sam_pwent);
		memset(hours_array, 0xff, hours_len);
		
		pdb_set_hours(sam_pwent, hours_array, PDB_CHANGED);
	}

	if (!pdb_update_autolock_flag(sam_pwent, &updated_autolock)) {
		DEBUG(2,("pdb_update_autolock_flag failed.\n"));
	}

	if (!pdb_update_bad_password_count(sam_pwent, &updated_badpw)) {
		DEBUG(2,("pdb_update_bad_password_count failed.\n"));
	}

	if (fullname)
		pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
	if (acct_desc)
		pdb_set_acct_desc(sam_pwent, acct_desc, PDB_CHANGED);
	if (homedir)
		pdb_set_homedir(sam_pwent, homedir, PDB_CHANGED);
	if (drive)
		pdb_set_dir_drive(sam_pwent,drive, PDB_CHANGED);
	if (script)
		pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
	if (profile)
		pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
	if (user_domain)
		pdb_set_domain(sam_pwent, user_domain, PDB_CHANGED);

	if (account_control) {
		uint32 not_settable = ~(ACB_DISABLED|ACB_HOMDIRREQ|ACB_PWNOTREQ|
					ACB_PWNOEXP|ACB_AUTOLOCK);

		uint32 newflag = pdb_decode_acct_ctrl(account_control);

		if (newflag & not_settable) {
			fprintf(stderr, "Can only set [NDHLX] flags\n");
			TALLOC_FREE(sam_pwent);
			return -1;
		}

		pdb_set_acct_ctrl(sam_pwent,
				  (pdb_get_acct_ctrl(sam_pwent) & not_settable) | newflag,
				  PDB_CHANGED);
	}
	if (user_sid) {
		DOM_SID u_sid;
		if (!string_to_sid(&u_sid, user_sid)) {
			/* not a complete sid, may be a RID, try building a SID */
			int u_rid;
			
			if (sscanf(user_sid, "%d", &u_rid) != 1) {
				fprintf(stderr, "Error passed string is not a complete user SID or RID!\n");
				return -1;
			}
			sid_copy(&u_sid, get_global_sam_sid());
			sid_append_rid(&u_sid, u_rid);
		}
		pdb_set_user_sid (sam_pwent, &u_sid, PDB_CHANGED);
	}

	if (badpw) {
		pdb_set_bad_password_count(sam_pwent, 0, PDB_CHANGED);
		pdb_set_bad_password_time(sam_pwent, 0, PDB_CHANGED);
	}

	if (NT_STATUS_IS_OK(in->update_sam_account (in, sam_pwent)))
		print_user_info (in, username, True, False);
	else {
		fprintf (stderr, "Unable to modify entry!\n");
		TALLOC_FREE(sam_pwent);
		return -1;
	}
	TALLOC_FREE(sam_pwent);
	return 0;
}
Пример #5
0
static int reply_spnego_kerberos(connection_struct *conn, 
				 char *inbuf, char *outbuf,
				 int length, int bufsize,
				 DATA_BLOB *secblob,
				 BOOL *p_invalidate_vuid)
{
	TALLOC_CTX *mem_ctx;
	DATA_BLOB ticket;
	char *client, *p, *domain;
	fstring netbios_domain_name;
	struct passwd *pw;
	fstring user;
	int sess_vuid;
	NTSTATUS ret;
	PAC_DATA *pac_data;
	DATA_BLOB ap_rep, ap_rep_wrapped, response;
	auth_serversupplied_info *server_info = NULL;
	DATA_BLOB session_key = data_blob(NULL, 0);
	uint8 tok_id[2];
	DATA_BLOB nullblob = data_blob(NULL, 0);
	fstring real_username;
	BOOL map_domainuser_to_guest = False;
	BOOL username_was_mapped;
	PAC_LOGON_INFO *logon_info = NULL;

	ZERO_STRUCT(ticket);
	ZERO_STRUCT(pac_data);
	ZERO_STRUCT(ap_rep);
	ZERO_STRUCT(ap_rep_wrapped);
	ZERO_STRUCT(response);

	/* Normally we will always invalidate the intermediate vuid. */
	*p_invalidate_vuid = True;

	mem_ctx = talloc_init("reply_spnego_kerberos");
	if (mem_ctx == NULL) {
		return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
	}

	if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
		talloc_destroy(mem_ctx);
		return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
	}

	ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);

	data_blob_free(&ticket);

	if (!NT_STATUS_IS_OK(ret)) {
#if 0
		/* Experiment that failed. See "only happens with a KDC" comment below. */

		if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {

			/*
			 * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED
			 * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded
			 * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its
			 * clock and continues rather than giving an error. JRA.
			 * -- Looks like this only happens with a KDC. JRA.
			 */

			BOOL ok = make_krb5_skew_error(&ap_rep);
			if (!ok) {
				talloc_destroy(mem_ctx);
				return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
			}
			ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR);
			response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
			reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED);

			/*
			 * In this one case we don't invalidate the intermediate vuid.
			 * as we're expecting the client to re-use it for the next
			 * sessionsetupX packet. JRA.
			 */

			*p_invalidate_vuid = False;

			data_blob_free(&ap_rep);
			data_blob_free(&ap_rep_wrapped);
			data_blob_free(&response);
			talloc_destroy(mem_ctx);
			return -1; /* already replied */
		}
#else
		if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
			ret = NT_STATUS_LOGON_FAILURE;
		}
#endif
		DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret)));	
		talloc_destroy(mem_ctx);
		return ERROR_NT(nt_status_squash(ret));
	}

	DEBUG(3,("Ticket name is [%s]\n", client));

	p = strchr_m(client, '@');
	if (!p) {
		DEBUG(3,("Doesn't look like a valid principal\n"));
		data_blob_free(&ap_rep);
		data_blob_free(&session_key);
		SAFE_FREE(client);
		talloc_destroy(mem_ctx);
		return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
	}

	*p = 0;

	/* save the PAC data if we have it */

	if (pac_data) {
		logon_info = get_logon_info_from_pac(pac_data);
		if (logon_info) {
			netsamlogon_cache_store( client, &logon_info->info3 );
		}
	}

	if (!strequal(p+1, lp_realm())) {
		DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
		if (!lp_allow_trusted_domains()) {
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			SAFE_FREE(client);
			talloc_destroy(mem_ctx);
			return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
		}
	}

	/* this gives a fully qualified user name (ie. with full realm).
	   that leads to very long usernames, but what else can we do? */

	domain = p+1;

	if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {

		unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
		domain = netbios_domain_name;
		DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));

	} else {

		/* If we have winbind running, we can (and must) shorten the
		   username by using the short netbios name. Otherwise we will
		   have inconsistent user names. With Kerberos, we get the
		   fully qualified realm, with ntlmssp we get the short
		   name. And even w2k3 does use ntlmssp if you for example
		   connect to an ip address. */

		struct winbindd_request wb_request;
		struct winbindd_response wb_response;
		NSS_STATUS wb_result;

		ZERO_STRUCT(wb_request);
		ZERO_STRUCT(wb_response);

		DEBUG(10, ("Mapping [%s] to short name\n", domain));

		fstrcpy(wb_request.domain_name, domain);

		wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
					     &wb_request, &wb_response);

		if (wb_result == NSS_STATUS_SUCCESS) {

			fstrcpy(netbios_domain_name,
				wb_response.data.domain_info.name);
			domain = netbios_domain_name;

			DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
		} else {
			DEBUG(3, ("Could not find short name -- winbind "
				  "not running?\n"));
		}
	}

	fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
	
	/* lookup the passwd struct, create a new user if necessary */

	username_was_mapped = map_username( user );

	pw = smb_getpwnam( mem_ctx, user, real_username, True );

	if (pw) {
		/* if a real user check pam account restrictions */
		/* only really perfomed if "obey pam restriction" is true */
		/* do this before an eventual mappign to guest occurs */
		ret = smb_pam_accountcheck(pw->pw_name);
		if (  !NT_STATUS_IS_OK(ret)) {
			DEBUG(1, ("PAM account restriction prevents user login\n"));
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE(mem_ctx);
			return ERROR_NT(nt_status_squash(ret));
		}
	}

	if (!pw) {

		/* this was originally the behavior of Samba 2.2, if a user
		   did not have a local uid but has been authenticated, then 
		   map them to a guest account */

		if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
			map_domainuser_to_guest = True;
			fstrcpy(user,lp_guestaccount());
			pw = smb_getpwnam( mem_ctx, user, real_username, True );
		} 

		/* extra sanity check that the guest account is valid */

		if ( !pw ) {
			DEBUG(1,("Username %s is invalid on this system\n", user));
			SAFE_FREE(client);
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE(mem_ctx);
			return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
		}
	}

	/* setup the string used by %U */
	
	sub_set_smb_name( real_username );
	reload_services(True);

	if ( map_domainuser_to_guest ) {
		make_server_info_guest(&server_info);
	} else if (logon_info) {
		/* pass the unmapped username here since map_username() 
		   will be called again from inside make_server_info_info3() */
		
		ret = make_server_info_info3(mem_ctx, client, domain, 
					     &server_info, &logon_info->info3);
		if ( !NT_STATUS_IS_OK(ret) ) {
			DEBUG(1,("make_server_info_info3 failed: %s!\n",
				 nt_errstr(ret)));
			SAFE_FREE(client);
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE(mem_ctx);
			return ERROR_NT(nt_status_squash(ret));
		}

	} else {
		ret = make_server_info_pw(&server_info, real_username, pw);

		if ( !NT_STATUS_IS_OK(ret) ) {
			DEBUG(1,("make_server_info_pw failed: %s!\n",
				 nt_errstr(ret)));
			SAFE_FREE(client);
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE(mem_ctx);
			return ERROR_NT(nt_status_squash(ret));
		}

	        /* make_server_info_pw does not set the domain. Without this
		 * we end up with the local netbios name in substitutions for
		 * %D. */

		if (server_info->sam_account != NULL) {
			pdb_set_domain(server_info->sam_account, domain, PDB_SET);
		}
	}

	server_info->was_mapped |= username_was_mapped;
	
	/* we need to build the token for the user. make_server_info_guest()
	   already does this */
	
	if ( !server_info->ptok ) {
		ret = create_local_token( server_info );
		if ( !NT_STATUS_IS_OK(ret) ) {
			SAFE_FREE(client);
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE( mem_ctx );
			TALLOC_FREE( server_info );
			return ERROR_NT(nt_status_squash(ret));
		}
	}

	/* register_vuid keeps the server info */
	/* register_vuid takes ownership of session_key, no need to free after this.
 	   A better interface would copy it.... */
	sess_vuid = register_vuid(server_info, session_key, nullblob, client);

	SAFE_FREE(client);

	if (sess_vuid == UID_FIELD_INVALID ) {
		ret = NT_STATUS_LOGON_FAILURE;
	} else {
		/* current_user_info is changed on new vuid */
		reload_services( True );

		set_message(outbuf,4,0,True);
		SSVAL(outbuf, smb_vwv3, 0);
			
		if (server_info->guest) {
			SSVAL(outbuf,smb_vwv2,1);
		}
		
		SSVAL(outbuf, smb_uid, sess_vuid);

		sessionsetup_start_signing_engine(server_info, inbuf);
	}

        /* wrap that up in a nice GSS-API wrapping */
	if (NT_STATUS_IS_OK(ret)) {
		ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
	} else {
		ap_rep_wrapped = data_blob(NULL, 0);
	}
	response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
	reply_sesssetup_blob(conn, outbuf, response, ret);

	data_blob_free(&ap_rep);
	data_blob_free(&ap_rep_wrapped);
	data_blob_free(&response);
	TALLOC_FREE(mem_ctx);

	return -1; /* already replied */
}
Пример #6
0
/****************************************************************************
reply to a session setup spnego negotiate packet for kerberos
****************************************************************************/
static int reply_spnego_kerberos(connection_struct *conn, 
				 char *inbuf, char *outbuf,
				 int length, int bufsize,
				 DATA_BLOB *secblob)
{
	DATA_BLOB ticket;
	char *client, *p, *domain;
	fstring netbios_domain_name;
	struct passwd *pw;
	char *user;
	int sess_vuid;
	NTSTATUS ret;
	DATA_BLOB auth_data;
	DATA_BLOB ap_rep, ap_rep_wrapped, response;
	auth_serversupplied_info *server_info = NULL;
	DATA_BLOB session_key = data_blob(NULL, 0);
	uint8 tok_id[2];
	DATA_BLOB nullblob = data_blob(NULL, 0);
	fstring real_username;

	ZERO_STRUCT(ticket);
	ZERO_STRUCT(auth_data);
	ZERO_STRUCT(ap_rep);
	ZERO_STRUCT(ap_rep_wrapped);
	ZERO_STRUCT(response);

	if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
	}

	ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key);

	data_blob_free(&ticket);

	if (!NT_STATUS_IS_OK(ret)) {
		DEBUG(1,("Failed to verify incoming ticket!\n"));	
		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
	}

	data_blob_free(&auth_data);

	DEBUG(3,("Ticket name is [%s]\n", client));

	p = strchr_m(client, '@');
	if (!p) {
		DEBUG(3,("Doesn't look like a valid principal\n"));
		data_blob_free(&ap_rep);
		data_blob_free(&session_key);
		SAFE_FREE(client);
		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
	}

	*p = 0;
	if (!strequal(p+1, lp_realm())) {
		DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
		if (!lp_allow_trusted_domains()) {
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			SAFE_FREE(client);
			return ERROR_NT(NT_STATUS_LOGON_FAILURE);
		}
	}

	/* this gives a fully qualified user name (ie. with full realm).
	   that leads to very long usernames, but what else can we do? */

	domain = p+1;

	{
		/* If we have winbind running, we can (and must) shorten the
		   username by using the short netbios name. Otherwise we will
		   have inconsistent user names. With Kerberos, we get the
		   fully qualified realm, with ntlmssp we get the short
		   name. And even w2k3 does use ntlmssp if you for example
		   connect to an ip address. */

		struct winbindd_request wb_request;
		struct winbindd_response wb_response;
		NSS_STATUS wb_result;

		ZERO_STRUCT(wb_request);
		ZERO_STRUCT(wb_response);

		DEBUG(10, ("Mapping [%s] to short name\n", domain));

		fstrcpy(wb_request.domain_name, domain);

		wb_result = winbindd_request(WINBINDD_DOMAIN_INFO,
					     &wb_request, &wb_response);

		if (wb_result == NSS_STATUS_SUCCESS) {

			fstrcpy(netbios_domain_name,
				wb_response.data.domain_info.name);
			domain = netbios_domain_name;

			DEBUG(10, ("Mapped to [%s]\n", domain));
		} else {
			DEBUG(3, ("Could not find short name -- winbind "
				  "not running?\n"));
		}
	}

	asprintf(&user, "%s%c%s", domain, *lp_winbind_separator(), client);
	
	/* lookup the passwd struct, create a new user if necessary */

	map_username( user );

	pw = smb_getpwnam( user, real_username, True );
	
	if (!pw) {
		DEBUG(1,("Username %s is invalid on this system\n",user));
		SAFE_FREE(user);
		SAFE_FREE(client);
		data_blob_free(&ap_rep);
		data_blob_free(&session_key);
		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
	}

	/* setup the string used by %U */
	
	sub_set_smb_name( real_username );
	reload_services(True);
	
	if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw))) 
	{
		DEBUG(1,("make_server_info_from_pw failed!\n"));
		SAFE_FREE(user);
		SAFE_FREE(client);
		data_blob_free(&ap_rep);
		data_blob_free(&session_key);
		return ERROR_NT(ret);
	}

        /* make_server_info_pw does not set the domain. Without this we end up
	 * with the local netbios name in substitutions for %D. */

        if (server_info->sam_account != NULL) {
                pdb_set_domain(server_info->sam_account, domain, PDB_SET);
        }

	/* register_vuid keeps the server info */
	/* register_vuid takes ownership of session_key, no need to free after this.
 	   A better interface would copy it.... */
	sess_vuid = register_vuid(server_info, session_key, nullblob, client);

	SAFE_FREE(user);
	SAFE_FREE(client);

	if (sess_vuid == -1) {
		ret = NT_STATUS_LOGON_FAILURE;
	} else {
		/* current_user_info is changed on new vuid */
		reload_services( True );

		set_message(outbuf,4,0,True);
		SSVAL(outbuf, smb_vwv3, 0);
			
		if (server_info->guest) {
			SSVAL(outbuf,smb_vwv2,1);
		}
		
		SSVAL(outbuf, smb_uid, sess_vuid);

		if (!server_info->guest && !srv_signing_started()) {
			/* We need to start the signing engine
			 * here but a W2K client sends the old
			 * "BSRSPYL " signature instead of the
			 * correct one. Subsequent packets will
			 * be correct.
			 */
		       	srv_check_sign_mac(inbuf, False);
		}
	}

        /* wrap that up in a nice GSS-API wrapping */
	if (NT_STATUS_IS_OK(ret)) {
		ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
	} else {
		ap_rep_wrapped = data_blob(NULL, 0);
	}
	response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
	reply_sesssetup_blob(conn, outbuf, response, ret);

	data_blob_free(&ap_rep);
	data_blob_free(&ap_rep_wrapped);
	data_blob_free(&response);

	return -1; /* already replied */
}