Beispiel #1
0
NTSTATUS make_server_info_sam(struct auth_serversupplied_info **server_info,
			      struct samu *sampass)
{
	struct passwd *pwd;
	struct auth_serversupplied_info *result;
	const char *username = pdb_get_username(sampass);
	NTSTATUS status;

	if ( !(result = make_server_info(NULL)) ) {
		return NT_STATUS_NO_MEMORY;
	}

	if ( !(pwd = Get_Pwnam_alloc(result, username)) ) {
		DEBUG(1, ("User %s in passdb, but getpwnam() fails!\n",
			  pdb_get_username(sampass)));
		TALLOC_FREE(result);
		return NT_STATUS_NO_SUCH_USER;
	}

	status = samu_to_SamInfo3(result, sampass, lp_netbios_name(),
				  &result->info3, &result->extra);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(result);
		return status;
	}

	result->unix_name = pwd->pw_name;
	/* Ensure that we keep pwd->pw_name, because we will free pwd below */
	talloc_steal(result, pwd->pw_name);
	result->utok.gid = pwd->pw_gid;
	result->utok.uid = pwd->pw_uid;

	TALLOC_FREE(pwd);

	if (IS_DC && is_our_machine_account(username)) {
		/*
		 * This is a hack of monstrous proportions.
		 * If we know it's winbindd talking to us,
		 * we know we must never recurse into it,
		 * so turn off contacting winbindd for this
		 * entire process. This will get fixed when
		 * winbindd doesn't need to talk to smbd on
		 * a PDC. JRA.
		 */

		(void)winbind_off();

		DEBUG(10, ("make_server_info_sam: our machine account %s "
			   "turning off winbindd requests.\n", username));
	}

	DEBUG(5,("make_server_info_sam: made server info for user %s -> %s\n",
		 pdb_get_username(sampass), result->unix_name));

	*server_info = result;

	return NT_STATUS_OK;
}
Beispiel #2
0
static BOOL logon_hours_ok(struct samu *sampass)
{
	/* In logon hours first bit is Sunday from 12AM to 1AM */
	const uint8 *hours;
	struct tm *utctime;
	time_t lasttime;
	const char *asct;
	uint8 bitmask, bitpos;

	hours = pdb_get_hours(sampass);
	if (!hours) {
		DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n",pdb_get_username(sampass)));
		return True;
	}

	lasttime = time(NULL);
	utctime = gmtime(&lasttime);
	if (!utctime) {
		DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
			pdb_get_username(sampass) ));
		return False;
	}

	/* find the corresponding byte and bit */
	bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
	bitmask = 1 << (bitpos % 8);

	if (! (hours[bitpos/8] & bitmask)) {
		struct tm *t = localtime(&lasttime);
		if (!t) {
			asct = "INVALID TIME";
		} else {
			asct = asctime(t);
			if (!asct) {
				asct = "INVALID TIME";
			}
		}
		
		DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
			  "logon at this time (%s).\n",
			  pdb_get_username(sampass), asct ));
		return False;
	}

	asct = asctime(utctime);
	DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
		pdb_get_username(sampass), asct ? asct : "UNKNOWN TIME" ));

	return True;
}
Beispiel #3
0
static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
				TALLOC_CTX *mem_ctx,
				struct samu *sampass, 
				const auth_usersupplied_info *user_info, 
				DATA_BLOB *user_sess_key, 
				DATA_BLOB *lm_sess_key)
{
	uint32 acct_ctrl;
	const uint8 *lm_pw, *nt_pw;
	const char *username = pdb_get_username(sampass);

	acct_ctrl = pdb_get_acct_ctrl(sampass);
	if (acct_ctrl & ACB_PWNOTREQ) {
		if (lp_null_passwords()) {
			DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", username));
			return NT_STATUS_OK;
		} else {
			DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", username));
			return NT_STATUS_LOGON_FAILURE;
		}		
	}

	lm_pw = pdb_get_lanman_passwd(sampass);
	nt_pw = pdb_get_nt_passwd(sampass);

	return ntlm_password_check(mem_ctx, &auth_context->challenge, 
				   &user_info->lm_resp, &user_info->nt_resp, 
				   &user_info->lm_interactive_pwd, &user_info->nt_interactive_pwd,
				   username, 
				   user_info->smb_name,
				   user_info->client_domain,
				   lm_pw, nt_pw, user_sess_key, lm_sess_key);
}
Beispiel #4
0
static bool tdb_delete_samacct_only( struct samu *sam_pass )
{
	fstring 	keystr;
	fstring		name;
	NTSTATUS status;

	fstrcpy(name, pdb_get_username(sam_pass));
	if (!strlower_m(name)) {
		return false;
	}

  	/* set the search key */

	fstr_sprintf(keystr, "%s%s", USERPREFIX, name);

	/* it's outaa here!  8^) */
	if ( !tdbsam_open( tdbsam_filename ) ) {
		DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
			 tdbsam_filename));
		return false;
	}

	status = dbwrap_delete_bystring(db_sam, keystr);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(5, ("Error deleting entry from tdb passwd "
			  "database: %s!\n", nt_errstr(status)));
		return false;
	}

	return true;
}
Beispiel #5
0
/***************************************************************************
 Update the TDB SAM RID record only
 Assumes that the tdbsam is already open
****************************************************************************/
static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
{
	TDB_DATA 	data;
	fstring 	keystr;
	fstring		name;
	NTSTATUS status;

	fstrcpy(name, pdb_get_username(newpwd));
	if (!strlower_m(name)) {
		return false;
	}

	/* setup RID data */
	data = string_term_tdb_data(name);

	/* setup the RID index key */
	fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));

	/* add the reference */
	status = dbwrap_store_bystring(db_sam, keystr, data, flag);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
			  nt_errstr(status)));
		return false;
	}

	return true;

}
Beispiel #6
0
/*********************************************************
 Fix a list of Users for uninitialised passwords
**********************************************************/
static int fix_users_list(void)
{
	struct pdb_search *u_search;
	struct samr_displayentry userentry;
	struct samu *sam_pwent;
	TALLOC_CTX *tosctx;
	struct dom_sid user_sid;
	NTSTATUS status;
	bool bret;
	int ret;

	tosctx = talloc_tos();
	if (!tosctx) {
		fprintf(stderr, "Out of memory!\n");
		return 1;
	}

	u_search = pdb_search_users(tosctx, 0);
	if (!u_search) {
		fprintf(stderr, "User Search failed!\n");
		ret = 1;
		goto done;
	}

	while (u_search->next_entry(u_search, &userentry)) {

		sam_pwent = samu_new(tosctx);
		if (sam_pwent == NULL) {
			fprintf(stderr, "Out of memory!\n");
			ret = 1;
			goto done;
		}

		sid_compose(&user_sid, get_global_sam_sid(), userentry.rid);

		bret = pdb_getsampwsid(sam_pwent, &user_sid);
		if (!bret) {
			DEBUG(2, ("getsampwsid failed\n"));
			TALLOC_FREE(sam_pwent);
			continue;
		}

		status = pdb_update_sam_account(sam_pwent);
		if (!NT_STATUS_IS_OK(status)) {
			printf("Update of user %s failed!\n",
			       pdb_get_username(sam_pwent));
		}
		TALLOC_FREE(sam_pwent);
	}

	ret = 0;

done:
	TALLOC_FREE(tosctx);
	return ret;
}
Beispiel #7
0
static NTSTATUS pgsqlsam_delete_sam_account( struct pdb_methods *methods, SAM_ACCOUNT *sam_pass )
{
  struct pdb_pgsql_data *data ;
  
  const char *sname = pdb_get_username( sam_pass ) ;
  char *esc ;
  char *query ;
  
  PGresult *result ;
  NTSTATUS retval ;
  
  SET_DATA(data, methods);
  
  if ( !sname )
  {
    DEBUG( 0, ("invalid name specified\n") ) ;
    return NT_STATUS_INVALID_PARAMETER ;
  }
  
  /* Escape sname */
  esc = malloc(strlen(sname) * 2 + 1);
  if ( !esc )
  {
    DEBUG(0, ("Can't allocate memory to store escaped name\n"));
    return NT_STATUS_NO_MEMORY;
  }
  
  PQescapeString( esc, sname, strlen(sname) ) ;
  
  query = sql_account_query_delete(data->location, esc);
  
  /* Do it */
  result = PQexec( data->handle, query ) ;
  
  if ( result == NULL )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( data->handle ) ) ) ;
    retval = NT_STATUS_UNSUCCESSFUL ;
  }
  else if ( PQresultStatus( result ) != PGRES_COMMAND_OK )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
    retval = NT_STATUS_UNSUCCESSFUL ;
  }
  else
  {
    DEBUG( 5, ("User '%s' deleted\n", sname) ) ;
    retval = NT_STATUS_OK ;
  }
  
  SAFE_FREE( esc ) ;
  SAFE_FREE( query ) ;
  
  return retval ;
}
Beispiel #8
0
static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_pass)
{
	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
	TDB_CONTEXT 	*pwd_tdb;
	TDB_DATA 	key;
	fstring 	keystr;
	uint32		rid;
	fstring		name;
	
	fstrcpy(name, pdb_get_username(sam_pass));
	strlower_m(name);
	
	/* open the TDB */
	if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR, 0600))) {
		DEBUG(0, ("Unable to open TDB passwd!"));
		return nt_status;
	}
  
  	/* set the search key */
	slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
	key.dptr = keystr;
	key.dsize = strlen (keystr) + 1;
	
	rid = pdb_get_user_rid(sam_pass);

	/* it's outaa here!  8^) */
	if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
		DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
		DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
		tdb_close(pwd_tdb); 
		return nt_status;
	}	

	/* delete also the RID key */

  	/* set the search key */
	slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
	key.dptr = keystr;
	key.dsize = strlen (keystr) + 1;

	/* it's outaa here!  8^) */
	if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
		DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
		DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
		tdb_close(pwd_tdb); 
		return nt_status;
	}
	
	tdb_close(pwd_tdb);
	
	return NT_STATUS_OK;
}
Beispiel #9
0
/*********************************************************
 Fix a list of Users for uninitialised passwords
**********************************************************/
static int fix_users_list (struct pdb_methods *in)
{
	struct samu *sam_pwent=NULL;
	BOOL check;
	
	check = NT_STATUS_IS_OK(in->setsampwent(in, False, 0));
	if (!check) {
		return 1;
	}

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

	while (check && NT_STATUS_IS_OK(in->getsampwent (in, sam_pwent))) {
		printf("Updating record for user %s\n", pdb_get_username(sam_pwent));
	
		if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) {
			printf("Update of user %s failed!\n", pdb_get_username(sam_pwent));
		}
		TALLOC_FREE(sam_pwent);
		if ( (sam_pwent = samu_new( NULL )) == NULL ) {
			check = False;
		}
		if (!check) {
			fprintf(stderr, "Failed to initialise new struct samu structure (out of memory?)\n");
		}
			
	}
	if (check) 
		TALLOC_FREE(sam_pwent);
	
	in->endsampwent(in);
	return 0;
}
Beispiel #10
0
/***************************************************************************
 Update the TDB SAM account record only
 Assumes that the tdbsam is already open 
****************************************************************************/
static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
{
	TDB_DATA 	data;
	uint8_t		*buf = NULL;
	fstring 	keystr;
	fstring		name;
	bool		ret = false;
	NTSTATUS status;

	/* copy the struct samu struct into a BYTE buffer for storage */

	if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
		DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
		goto done;
	}
	data.dptr = buf;

	fstrcpy(name, pdb_get_username(newpwd));
	if (!strlower_m(name)) {
		goto done;
	}

	DEBUG(5, ("Storing %saccount %s with RID %d\n",
		  flag == TDB_INSERT ? "(new) " : "", name,
		  pdb_get_user_rid(newpwd)));

  	/* setup the USER index key */
	fstr_sprintf(keystr, "%s%s", USERPREFIX, name);

	/* add the account */

	status = dbwrap_store_bystring(db_sam, keystr, data, flag);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("Unable to modify passwd TDB: %s!",
			  nt_errstr(status)));
		goto done;
	}

	ret = true;

done:
	/* cleanup */
	SAFE_FREE(buf);
	return ret;
}
Beispiel #11
0
/*******************************************************************
 Look up a local user rid and return a name and type.
 ********************************************************************/
NTSTATUS local_lookup_user_name(uint32 rid, char *user_name, uint32 *type)
{
	SAM_ACCOUNT *sampwd=NULL;
	int i = 0;
	BOOL ret;
	
	(*type) = SID_NAME_USER;

	DEBUG(5,("lookup_user_name: rid: %d", rid));

	/* look up the well-known domain user rids first */
	while (domain_user_rids[i].rid != rid && domain_user_rids[i].rid != 0)
	{
		i++;
	}

	if (domain_user_rids[i].rid != 0) {
		fstrcpy(user_name, domain_user_rids[i].name);
		DEBUG(5,(" = %s\n", user_name));
		return NT_STATUS_OK;
	}

	pdb_init_sam(&sampwd);

	/* ok, it's a user.  find the user account */
	become_root();
	ret = pdb_getsampwrid(sampwd, rid);
	unbecome_root();

	if (ret == True) {
		fstrcpy(user_name, pdb_get_username(sampwd) );
		DEBUG(5,(" = %s\n", user_name));
		pdb_free_sam(&sampwd);
		return NT_STATUS_OK;
	}

	DEBUG(5,(" none mapped\n"));
	pdb_free_sam(&sampwd);
	return NT_STATUS_NONE_MAPPED;
}
Beispiel #12
0
int main(int argc, char **argv)
{
	TALLOC_CTX *ctx;
	struct samu *out = NULL;
	struct samu *in = NULL;
	NTSTATUS rv;
	int i;
	struct timeval tv;
	BOOL error = False;
	struct passwd *pwd;
	uint8 *buf;
	uint32 expire, min_age, history;
	struct pdb_methods *pdb;
	poptContext pc;
	static const char *backend = NULL;
	static const char *unix_user = "******";
	struct poptOption long_options[] = {
		{"username", 'u', POPT_ARG_STRING, &unix_user, 0, "Unix user to use for testing", "USERNAME" },
		{"backend", 'b', POPT_ARG_STRING, &backend, 0, "Backend to use if not default", "BACKEND[:SETTINGS]" },
		POPT_AUTOHELP
		POPT_COMMON_SAMBA
		POPT_TABLEEND
	};

	load_case_tables();

	pc = poptGetContext("vfstest", argc, (const char **) argv,
			    long_options, 0);

	poptSetOtherOptionHelp(pc, "backend[:settings] username");
	
	while(poptGetNextOpt(pc) != -1);

	poptFreeContext(pc);

	/* Load configuration */
	lp_load(dyn_CONFIGFILE, False, False, True, True);
	setup_logging("pdbtest", True);

	if (backend == NULL) {
		backend = lp_passdb_backend();
	}

	rv = make_pdb_method_name(&pdb, backend);
	if (NT_STATUS_IS_ERR(rv)) {
		fprintf(stderr, "Error initializing '%s': %s\n", backend, get_friendly_nt_error_msg(rv));
		exit(1);
	}
	
	ctx = talloc_init("PDBTEST");
	
	if (!(out = samu_new(ctx))) {
		fprintf(stderr, "Can't create samu structure.\n");
		exit(1);
	}
	
	if ((pwd = getpwnam_alloc(ctx, unix_user)) == NULL) {
		fprintf(stderr, "Error getting user information for %s\n", unix_user);
		exit(1);
	}
	
	samu_set_unix(out, pwd);

	pdb_set_profile_path(out, "\\\\torture\\profile", PDB_SET);
	pdb_set_homedir(out, "\\\\torture\\home", PDB_SET);
	pdb_set_logon_script(out, "torture_script.cmd", PDB_SET);

	pdb_get_account_policy(AP_PASSWORD_HISTORY, &history);
	if (history * PW_HISTORY_ENTRY_LEN < NT_HASH_LEN) {
		buf = (uint8 *)TALLOC(ctx, NT_HASH_LEN);
	} else {
		buf = (uint8 *)TALLOC(ctx, history * PW_HISTORY_ENTRY_LEN);
	}

	/* Generate some random hashes */
	GetTimeOfDay(&tv);
	srand(tv.tv_usec);
	for (i = 0; i < NT_HASH_LEN; i++) {
		buf[i] = (uint8) rand();
	}
	pdb_set_nt_passwd(out, buf, PDB_SET);
	for (i = 0; i < LM_HASH_LEN; i++) {
		buf[i] = (uint8) rand();
	}
	pdb_set_lanman_passwd(out, buf, PDB_SET);
	for (i = 0; i < history * PW_HISTORY_ENTRY_LEN; i++) {
		buf[i] = (uint8) rand();
	}
	pdb_set_pw_history(out, buf, history, PDB_SET);

	pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &expire);
	pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &min_age);
	pdb_set_pass_last_set_time(out, time(NULL), PDB_SET);
	
	if (expire == 0 || expire == (uint32)-1) {
		pdb_set_pass_must_change_time(out, get_time_t_max(), PDB_SET);
	} else {
		pdb_set_pass_must_change_time(out, time(NULL)+expire, PDB_SET);
	}

	if (min_age == (uint32)-1) {
		pdb_set_pass_can_change_time(out, 0, PDB_SET);
	} else {
		pdb_set_pass_can_change_time(out, time(NULL)+min_age, PDB_SET);
	}
	
	/* Create account */
	if (!NT_STATUS_IS_OK(rv = pdb->add_sam_account(pdb, out))) {
		fprintf(stderr, "Error in add_sam_account: %s\n", 
				get_friendly_nt_error_msg(rv));
		exit(1);
	}

	if (!(in = samu_new(ctx))) {
		fprintf(stderr, "Can't create samu structure.\n");
		exit(1);
	}
	
	/* Get account information through getsampwnam() */
	if (NT_STATUS_IS_ERR(pdb->getsampwnam(pdb, in, out->username))) {
		fprintf(stderr, "Error getting sampw of added user %s.\n",
				out->username);
		if (!NT_STATUS_IS_OK(rv = pdb->delete_sam_account(pdb, out))) {
			fprintf(stderr, "Error in delete_sam_account %s\n", 
					get_friendly_nt_error_msg(rv));
		}
		TALLOC_FREE(ctx);
	}
	
	/* Verify integrity */
	if (samu_correct(out, in)) {
		printf("User info written correctly\n");
	} else {
		printf("User info NOT written correctly\n");
		error = True;
	}
	
	/* Delete account */
	if (!NT_STATUS_IS_OK(rv = pdb->delete_sam_account(pdb, out))) {
		fprintf(stderr, "Error in delete_sam_account %s\n", 
					get_friendly_nt_error_msg(rv));
	}

	pdb->setsampwent(pdb, False, 0);
	while (NT_STATUS_IS_OK(pdb->getsampwent(pdb, out))) {
		if (pdb_get_username(out) == NULL) {
			fprintf(stderr, "Got bad username through getsampwent()\n");
			error = True;
			break;
		}
		if (NT_STATUS_IS_ERR(pdb->getsampwnam(pdb, in, pdb_get_username(out)))) {
			fprintf(stderr, "Error getting samu through getsampwnam() of an account we got through getsampwent!\n");
			error = True;
			continue;
		}
		if (!samu_correct(out, in)) {
			printf("Record gotten through getsampwnam() differs from same record through getsampwent()\n");
		}
	}
	pdb->endsampwent(pdb);
	
	TALLOC_FREE(ctx);

	if (error) {
		return 1;
	}
	return 0;
}
Beispiel #13
0
static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
					  struct samu *sam_pass)
{
	NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
	fstring 	keystr;
	uint32_t	rid;
	fstring		name;

	/* open the database */

	if ( !tdbsam_open( tdbsam_filename ) ) {
		DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
			 tdbsam_filename));
		return NT_STATUS_ACCESS_DENIED;
	}

	fstrcpy(name, pdb_get_username(sam_pass));
	if (!strlower_m(name)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

  	/* set the search key */

	fstr_sprintf(keystr, "%s%s", USERPREFIX, name);

	rid = pdb_get_user_rid(sam_pass);

	/* it's outaa here!  8^) */

	if (dbwrap_transaction_start(db_sam) != 0) {
		DEBUG(0, ("Could not start transaction\n"));
		return NT_STATUS_UNSUCCESSFUL;
	}

	nt_status = dbwrap_delete_bystring(db_sam, keystr);
	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(5, ("Error deleting entry from tdb passwd "
			  "database: %s!\n", nt_errstr(nt_status)));
		goto cancel;
	}

  	/* set the search key */

	fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);

	/* it's outaa here!  8^) */

	nt_status = dbwrap_delete_bystring(db_sam, keystr);
	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(5, ("Error deleting entry from tdb rid "
			  "database: %s!\n", nt_errstr(nt_status)));
		goto cancel;
	}

	if (dbwrap_transaction_commit(db_sam) != 0) {
		DEBUG(0, ("Could not commit transaction\n"));
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	return NT_STATUS_OK;

 cancel:
	if (dbwrap_transaction_cancel(db_sam) != 0) {
		smb_panic("transaction_cancel failed");
	}

	return nt_status;
}
Beispiel #14
0
static BOOL samu_correct(struct samu *s1, struct samu *s2)
{
	BOOL ret = True;
	uint32 s1_len, s2_len;
	const char *s1_buf, *s2_buf;
	const uint8 *d1_buf, *d2_buf;
		
	/* Check Unix username */
	s1_buf = pdb_get_username(s1);
	s2_buf = pdb_get_username(s2);
	if (s2_buf == NULL && s1_buf != NULL) {
		DEBUG(0, ("Username is not set\n"));
		ret = False;
	} else if (s1_buf == NULL) {
		/* Do nothing */
	} else if (strcmp(s1_buf,s2_buf)) {
		DEBUG(0, ("Username not written correctly, want %s, got \"%s\"\n",
					pdb_get_username(s1),
					pdb_get_username(s2)));
		ret = False;
	}

	/* Check NT username */
	s1_buf = pdb_get_nt_username(s1);
	s2_buf = pdb_get_nt_username(s2);
	if (s2_buf == NULL && s1_buf != NULL) {
		DEBUG(0, ("NT Username is not set\n"));
		ret = False;
	} else if (s1_buf == NULL) {
		/* Do nothing */
	} else if (strcmp(s1_buf, s2_buf)) {
		DEBUG(0, ("NT Username not written correctly, want \"%s\", got \"%s\"\n",
					pdb_get_nt_username(s1),
					pdb_get_nt_username(s2)));
		ret = False;
	}

	/* Check acct ctrl */
	if (pdb_get_acct_ctrl(s1) != pdb_get_acct_ctrl(s2)) {
		DEBUG(0, ("Acct ctrl field not written correctly, want %d (0x%X), got %d (0x%X)\n",
					pdb_get_acct_ctrl(s1),
					pdb_get_acct_ctrl(s1),
					pdb_get_acct_ctrl(s2),
					pdb_get_acct_ctrl(s2)));
		ret = False;
	}

	/* Check NT password */
	d1_buf = pdb_get_nt_passwd(s1);
	d2_buf = pdb_get_nt_passwd(s2);
	if (d2_buf == NULL && d1_buf != NULL) {
		DEBUG(0, ("NT password is not set\n"));
		ret = False;
	} else if (d1_buf == NULL) {
		/* Do nothing */
	} else if (memcmp(d1_buf, d2_buf, NT_HASH_LEN)) {
		DEBUG(0, ("NT password not written correctly\n"));
		ret = False;
	}

	/* Check lanman password */
	d1_buf = pdb_get_lanman_passwd(s1);
	d2_buf = pdb_get_lanman_passwd(s2);
	if (d2_buf == NULL && d1_buf != NULL) {
		DEBUG(0, ("Lanman password is not set\n"));
	} else if (d1_buf == NULL) {
		/* Do nothing */
	} else if (memcmp(d1_buf, d2_buf, NT_HASH_LEN)) {
		DEBUG(0, ("Lanman password not written correctly\n"));
		ret = False;
	}

	/* Check password history */
	d1_buf = pdb_get_pw_history(s1, &s1_len);
	d2_buf = pdb_get_pw_history(s2, &s2_len);
	if (d2_buf == NULL && d1_buf != NULL) {
		DEBUG(0, ("Password history is not set\n"));
	} else if (d1_buf == NULL) {
		/* Do nothing */
	} else if (s1_len != s1_len) {
		DEBUG(0, ("Password history not written correctly, lengths differ, want %d, got %d\n",
					s1_len, s2_len));
		ret = False;
	} else if (strncmp(s1_buf, s2_buf, s1_len)) {
		DEBUG(0, ("Password history not written correctly\n"));
		ret = False;
	}

	/* Check logon time */
	if (pdb_get_logon_time(s1) != pdb_get_logon_time(s2)) {
		DEBUG(0, ("Logon time is not written correctly\n"));
		ret = False;
	}

	/* Check logoff time */
	if (pdb_get_logoff_time(s1) != pdb_get_logoff_time(s2)) {
		DEBUG(0, ("Logoff time is not written correctly\n"));
		ret = False;
	}
	
	/* Check kickoff time */
	if (pdb_get_kickoff_time(s1) != pdb_get_logoff_time(s2)) {
		DEBUG(0, ("Kickoff time is not written correctly\n"));
		ret = False;
	}
	
	/* Check bad password time */
	if (pdb_get_bad_password_time(s1) != pdb_get_bad_password_time(s2)) {
		DEBUG(0, ("Bad password time is not written correctly\n"));
		ret = False;
	}
	
	/* Check password last set time */
	if (pdb_get_pass_last_set_time(s1) != pdb_get_pass_last_set_time(s2)) {
		DEBUG(0, ("Password last set time is not written correctly\n"));
		ret = False;
	}
	
	/* Check password can change time */
	if (pdb_get_pass_can_change_time(s1) != pdb_get_pass_can_change_time(s2)) {
		DEBUG(0, ("Password can change time is not written correctly\n"));
		ret = False;
	}
	
	/* Check password must change time */
	if (pdb_get_pass_must_change_time(s1) != pdb_get_pass_must_change_time(s2)) {
		DEBUG(0, ("Password must change time is not written correctly\n"));
		ret = False;
	}
	
	/* Check logon divs */
	if (pdb_get_logon_divs(s1) != pdb_get_logon_divs(s2)) {
		DEBUG(0, ("Logon divs not written correctly\n"));
		ret = False;
	}
	
	/* Check logon hours */
	if (pdb_get_hours_len(s1) != pdb_get_hours_len(s2)) {
		DEBUG(0, ("Logon hours length not written correctly\n"));
		ret = False;
	} else if (pdb_get_hours_len(s1) != 0) {
		d1_buf = pdb_get_hours(s1);
		d2_buf = pdb_get_hours(s2);
		if (d2_buf == NULL && d2_buf != NULL) {
			DEBUG(0, ("Logon hours is not set\n"));
			ret = False;
		} else if (d1_buf == NULL) {
			/* Do nothing */
		} else if (memcmp(d1_buf, d2_buf, MAX_HOURS_LEN)) {
			DEBUG(0, ("Logon hours is not written correctly\n"));
			ret = False;
		}
	}
	
	/* Check profile path */
	s1_buf = pdb_get_profile_path(s1);
	s2_buf = pdb_get_profile_path(s2);
	if (s2_buf == NULL && s1_buf != NULL) {
		DEBUG(0, ("Profile path is not set\n"));
		ret = False;
	} else if (s1_buf == NULL) {
		/* Do nothing */
	} else if (strcmp(s1_buf, s2_buf)) {
		DEBUG(0, ("Profile path is not written correctly\n"));
		ret = False;
	}

	/* Check home dir */
	s1_buf = pdb_get_homedir(s1);
	s2_buf = pdb_get_homedir(s2);
	if (s2_buf == NULL && s1_buf != NULL) {
		DEBUG(0, ("Home dir is not set\n"));
		ret = False;
	} else if (s1_buf == NULL) {
		/* Do nothing */
	} else if (strcmp(s1_buf, s2_buf)) {
		DEBUG(0, ("Home dir is not written correctly\n"));
		ret = False;
	}
	
	/* Check logon script */
	s1_buf = pdb_get_logon_script(s1);
	s2_buf = pdb_get_logon_script(s2);
	if (s2_buf == NULL && s1_buf != NULL) {
		DEBUG(0, ("Logon script not set\n"));
		ret = False;
	} else if (s1_buf == NULL) {
		/* Do nothing */
	} else if (strcmp(s1_buf, s2_buf)) {
		DEBUG(0, ("Logon script is not written correctly\n"));
		ret = False;
	}
	
	/* TODO Check user and group sids */
		
	return ret;	
}
Beispiel #15
0
void copy_id21_to_sam_passwd(const char *log_prefix,
			     struct samu *to,
			     struct samr_UserInfo21 *from)
{
	time_t unix_time, stored_time;
	const char *old_string, *new_string;
	const char *l;

	if (from == NULL || to == NULL) {
		return;
	}

	if (log_prefix) {
		l = log_prefix;
	} else {
		l = "INFO_21";
	}

	if (from->fields_present & SAMR_FIELD_LAST_LOGON) {
		unix_time = nt_time_to_unix(from->last_logon);
		stored_time = pdb_get_logon_time(to);
		DEBUG(10,("%s SAMR_FIELD_LAST_LOGON: %lu -> %lu\n", l,
			(long unsigned int)stored_time,
			(long unsigned int)unix_time));
		if (stored_time != unix_time) {
			pdb_set_logon_time(to, unix_time, PDB_CHANGED);
		}
	}

	if (from->fields_present & SAMR_FIELD_LAST_LOGOFF) {
		unix_time = nt_time_to_unix(from->last_logoff);
		stored_time = pdb_get_logoff_time(to);
		DEBUG(10,("%s SAMR_FIELD_LAST_LOGOFF: %lu -> %lu\n", l,
			(long unsigned int)stored_time,
			(long unsigned int)unix_time));
		if (stored_time != unix_time) {
			pdb_set_logoff_time(to, unix_time, PDB_CHANGED);
		}
	}

	if (from->fields_present & SAMR_FIELD_ACCT_EXPIRY) {
		unix_time = nt_time_to_unix(from->acct_expiry);
		stored_time = pdb_get_kickoff_time(to);
		DEBUG(10,("%s SAMR_FIELD_ACCT_EXPIRY: %lu -> %lu\n", l,
			(long unsigned int)stored_time,
			(long unsigned int)unix_time));
		if (stored_time != unix_time) {
			pdb_set_kickoff_time(to, unix_time , PDB_CHANGED);
		}
	}

	if (from->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) {
		unix_time = nt_time_to_unix(from->last_password_change);
		stored_time = pdb_get_pass_last_set_time(to);
		DEBUG(10,("%s SAMR_FIELD_LAST_PWD_CHANGE: %lu -> %lu\n", l,
			(long unsigned int)stored_time,
			(long unsigned int)unix_time));
		if (stored_time != unix_time) {
			pdb_set_pass_last_set_time(to, unix_time, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_ACCOUNT_NAME) &&
	    (from->account_name.string)) {
		old_string = pdb_get_username(to);
		new_string = from->account_name.string;
		DEBUG(10,("%s SAMR_FIELD_ACCOUNT_NAME: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_username(to, new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_FULL_NAME) &&
	    (from->full_name.string)) {
		old_string = pdb_get_fullname(to);
		new_string = from->full_name.string;
		DEBUG(10,("%s SAMR_FIELD_FULL_NAME: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_fullname(to, new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_HOME_DIRECTORY) &&
	    (from->home_directory.string)) {
		old_string = pdb_get_homedir(to);
		new_string = from->home_directory.string;
		DEBUG(10,("%s SAMR_FIELD_HOME_DIRECTORY: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_homedir(to, new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_HOME_DRIVE) &&
	    (from->home_drive.string)) {
		old_string = pdb_get_dir_drive(to);
		new_string = from->home_drive.string;
		DEBUG(10,("%s SAMR_FIELD_HOME_DRIVE: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_dir_drive(to, new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_LOGON_SCRIPT) &&
	    (from->logon_script.string)) {
		old_string = pdb_get_logon_script(to);
		new_string = from->logon_script.string;
		DEBUG(10,("%s SAMR_FIELD_LOGON_SCRIPT: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_logon_script(to  , new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_PROFILE_PATH) &&
	    (from->profile_path.string)) {
		old_string = pdb_get_profile_path(to);
		new_string = from->profile_path.string;
		DEBUG(10,("%s SAMR_FIELD_PROFILE_PATH: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_profile_path(to  , new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_DESCRIPTION) &&
	    (from->description.string)) {
		old_string = pdb_get_acct_desc(to);
		new_string = from->description.string;
		DEBUG(10,("%s SAMR_FIELD_DESCRIPTION: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_acct_desc(to, new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_WORKSTATIONS) &&
	    (from->workstations.string)) {
		old_string = pdb_get_workstations(to);
		new_string = from->workstations.string;
		DEBUG(10,("%s SAMR_FIELD_WORKSTATIONS: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_workstations(to  , new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_COMMENT) &&
	    (from->comment.string)) {
		old_string = pdb_get_comment(to);
		new_string = from->comment.string;
		DEBUG(10,("%s SAMR_FIELD_COMMENT: %s -> %s\n", l,
			old_string, new_string));
		if (STRING_CHANGED) {
			pdb_set_comment(to, new_string, PDB_CHANGED);
		}
	}

	if ((from->fields_present & SAMR_FIELD_PARAMETERS) &&
	    (from->parameters.array)) {
		char *newstr;
		DATA_BLOB mung;
		old_string = pdb_get_munged_dial(to);

		mung = data_blob_const(from->parameters.array,
				       from->parameters.length);
		newstr = (mung.length == 0) ?
			NULL : base64_encode_data_blob(talloc_tos(), mung);
		DEBUG(10,("%s SAMR_FIELD_PARAMETERS: %s -> %s\n", l,
			old_string, newstr));
		if (STRING_CHANGED_NC(old_string,newstr)) {
			pdb_set_munged_dial(to, newstr, PDB_CHANGED);
		}

		TALLOC_FREE(newstr);
	}

	if (from->fields_present & SAMR_FIELD_RID) {
		if (from->rid == 0) {
			DEBUG(10,("%s: Asked to set User RID to 0 !? Skipping change!\n", l));
		} else if (from->rid != pdb_get_user_rid(to)) {
			DEBUG(10,("%s SAMR_FIELD_RID: %u -> %u NOT UPDATED!\n", l,
				pdb_get_user_rid(to), from->rid));
		}
	}

	if (from->fields_present & SAMR_FIELD_PRIMARY_GID) {
		if (from->primary_gid == 0) {
			DEBUG(10,("%s: Asked to set Group RID to 0 !? Skipping change!\n", l));
		} else if (from->primary_gid != pdb_get_group_rid(to)) {
			DEBUG(10,("%s SAMR_FIELD_PRIMARY_GID: %u -> %u\n", l,
				pdb_get_group_rid(to), from->primary_gid));
			pdb_set_group_sid_from_rid(to,
				from->primary_gid, PDB_CHANGED);
		}
	}

	if (from->fields_present & SAMR_FIELD_ACCT_FLAGS) {
		DEBUG(10,("%s SAMR_FIELD_ACCT_FLAGS: %08X -> %08X\n", l,
			pdb_get_acct_ctrl(to), from->acct_flags));
		if (from->acct_flags != pdb_get_acct_ctrl(to)) {

			/* You cannot autolock an unlocked account via
			 * setuserinfo calls, so make sure to remove the
			 * ACB_AUTOLOCK bit here - gd */

			if ((from->acct_flags & ACB_AUTOLOCK) &&
			    !(pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) {
				from->acct_flags &= ~ACB_AUTOLOCK;
			}

			if (!(from->acct_flags & ACB_AUTOLOCK) &&
			     (pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) {
				/* We're unlocking a previously locked user. Reset bad password counts.
				   Patch from Jianliang Lu. <*****@*****.**> */
				pdb_set_bad_password_count(to, 0, PDB_CHANGED);
				pdb_set_bad_password_time(to, 0, PDB_CHANGED);
			}
			pdb_set_acct_ctrl(to, from->acct_flags, PDB_CHANGED);
		}
	}

	if (from->fields_present & SAMR_FIELD_LOGON_HOURS) {
		char oldstr[44]; /* hours strings are 42 bytes. */
		char newstr[44];
		DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week): %08X -> %08X\n", l,
			pdb_get_logon_divs(to), from->logon_hours.units_per_week));
		if (from->logon_hours.units_per_week != pdb_get_logon_divs(to)) {
			pdb_set_logon_divs(to,
				from->logon_hours.units_per_week, PDB_CHANGED);
		}

		DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week/8): %08X -> %08X\n", l,
			pdb_get_hours_len(to),
			from->logon_hours.units_per_week/8));
		if (from->logon_hours.units_per_week/8 != pdb_get_hours_len(to)) {
			pdb_set_hours_len(to,
				from->logon_hours.units_per_week/8, PDB_CHANGED);
		}

		DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (bits): %s -> %s\n", l,
			pdb_get_hours(to), from->logon_hours.bits));
		pdb_sethexhours(oldstr, pdb_get_hours(to));
		pdb_sethexhours(newstr, from->logon_hours.bits);
		if (!strequal(oldstr, newstr)) {
			pdb_set_hours(to, from->logon_hours.bits,
				      from->logon_hours.units_per_week/8,
				      PDB_CHANGED);
		}
	}

	if (from->fields_present & SAMR_FIELD_BAD_PWD_COUNT) {
		DEBUG(10,("%s SAMR_FIELD_BAD_PWD_COUNT: %08X -> %08X\n", l,
			pdb_get_bad_password_count(to), from->bad_password_count));
		if (from->bad_password_count != pdb_get_bad_password_count(to)) {
			pdb_set_bad_password_count(to,
				from->bad_password_count, PDB_CHANGED);
		}
	}

	if (from->fields_present & SAMR_FIELD_NUM_LOGONS) {
		DEBUG(10,("%s SAMR_FIELD_NUM_LOGONS: %08X -> %08X\n", l,
			pdb_get_logon_count(to), from->logon_count));
		if (from->logon_count != pdb_get_logon_count(to)) {
			pdb_set_logon_count(to, from->logon_count, PDB_CHANGED);
		}
	}

	/* If the must change flag is set, the last set time goes to zero.
	   the must change and can change fields also do, but they are
	   calculated from policy, not set from the wire */

	if (from->fields_present & SAMR_FIELD_EXPIRED_FLAG) {
		DEBUG(10,("%s SAMR_FIELD_EXPIRED_FLAG: %02X\n", l,
			from->password_expired));
		if (from->password_expired != 0) {
			/* Only allow the set_time to zero (which means
			   "User Must Change Password on Next Login"
			   if the user object allows password change. */
			if (pdb_get_pass_can_change(to)) {
				pdb_set_pass_last_set_time(to, 0, PDB_CHANGED);
			} else {
				DEBUG(10,("%s Disallowing set of 'User Must "
					"Change Password on Next Login' as "
					"user object disallows this.\n", l));
			}
		} else {
			/* A subtlety here: some windows commands will
			   clear the expired flag even though it's not
			   set, and we don't want to reset the time
			   in these caess.  "net user /dom <user> /active:y"
			   for example, to clear an autolocked acct.
			   We must check to see if it's expired first. jmcd */

			uint32_t pwd_max_age = 0;
			time_t now = time(NULL);

			pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &pwd_max_age);

			if (pwd_max_age == (uint32_t)-1 || pwd_max_age == 0) {
				pwd_max_age = get_time_t_max();
			}

			stored_time = pdb_get_pass_last_set_time(to);

			/* we will only *set* a pwdlastset date when
			   a) the last pwdlastset time was 0 (user was forced to
			      change password).
			   b) the users password has not expired. gd. */

			if ((stored_time == 0) ||
			    ((now - stored_time) > pwd_max_age)) {
				pdb_set_pass_last_set_time(to, now, PDB_CHANGED);
			}
		}
	}

	if (from->fields_present & SAMR_FIELD_COUNTRY_CODE) {
		DEBUG(10,("%s SAMR_FIELD_COUNTRY_CODE: %08X -> %08X\n", l,
			pdb_get_country_code(to), from->country_code));
		if (from->country_code != pdb_get_country_code(to)) {
			pdb_set_country_code(to,
				from->country_code, PDB_CHANGED);
		}
	}

	if (from->fields_present & SAMR_FIELD_CODE_PAGE) {
		DEBUG(10,("%s SAMR_FIELD_CODE_PAGE: %08X -> %08X\n", l,
			pdb_get_code_page(to), from->code_page));
		if (from->code_page != pdb_get_code_page(to)) {
			pdb_set_code_page(to,
				from->code_page, PDB_CHANGED);
		}
	}
}
Beispiel #16
0
static NTSTATUS check_sam_security(const struct auth_context *auth_context,
				   void *my_private_data, 
				   TALLOC_CTX *mem_ctx,
				   const auth_usersupplied_info *user_info, 
				   auth_serversupplied_info **server_info)
{
	struct samu *sampass=NULL;
	BOOL ret;
	NTSTATUS nt_status;
	NTSTATUS update_login_attempts_status;
	DATA_BLOB user_sess_key = data_blob(NULL, 0);
	DATA_BLOB lm_sess_key = data_blob(NULL, 0);
	BOOL updated_autolock = False, updated_badpw = False;

	if (!user_info || !auth_context) {
		return NT_STATUS_UNSUCCESSFUL;
	}

	/* Can't use the talloc version here, because the returned struct gets
	   kept on the server_info */

	if ( !(sampass = samu_new( NULL )) ) {
		return NT_STATUS_NO_MEMORY;
	}

	/* get the account information */

	become_root();
	ret = pdb_getsampwnam(sampass, user_info->internal_username);
	unbecome_root();

	if (ret == False) {
		DEBUG(3,("check_sam_security: Couldn't find user '%s' in "
			 "passdb.\n", user_info->internal_username));
		TALLOC_FREE(sampass);
		return NT_STATUS_NO_SUCH_USER;
	}

	/* see if autolock flag needs to be updated */
	if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL)
		pdb_update_autolock_flag(sampass, &updated_autolock);
	/* Quit if the account was locked out. */
	if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) {
		DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", pdb_get_username(sampass)));
		return NT_STATUS_ACCOUNT_LOCKED_OUT;
	}

	nt_status = sam_password_ok(auth_context, mem_ctx, sampass, 
				    user_info, &user_sess_key, &lm_sess_key);

	/* Notify passdb backend of login success/failure. If not NT_STATUS_OK the backend doesn't like the login */
	update_login_attempts_status = pdb_update_login_attempts(sampass, NT_STATUS_IS_OK(nt_status));
	if (!NT_STATUS_IS_OK(update_login_attempts_status))
		nt_status = update_login_attempts_status;

	if (!NT_STATUS_IS_OK(nt_status)) {
		if (NT_STATUS_EQUAL(nt_status,NT_STATUS_WRONG_PASSWORD) && 
		    pdb_get_acct_ctrl(sampass) &ACB_NORMAL) {  
			pdb_increment_bad_password_count(sampass);
			updated_badpw = True;
		} else {
			pdb_update_bad_password_count(sampass, 
						      &updated_badpw);
		}
		if (updated_autolock || updated_badpw){
			become_root();
			if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass)))
				DEBUG(1, ("Failed to modify entry.\n"));
			unbecome_root();
		}
		data_blob_free(&user_sess_key);
		data_blob_free(&lm_sess_key);
		TALLOC_FREE(sampass);
		return nt_status;
	}

	if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) && 
	    (pdb_get_bad_password_count(sampass) > 0)){
		pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
		pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
		updated_badpw = True;
	}

	if (updated_autolock || updated_badpw){
		become_root();
		if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass)))
			DEBUG(1, ("Failed to modify entry.\n"));
		unbecome_root();
 	}

	nt_status = sam_account_ok(mem_ctx, sampass, user_info);

	if (!NT_STATUS_IS_OK(nt_status)) {
		TALLOC_FREE(sampass);
		data_blob_free(&user_sess_key);
		data_blob_free(&lm_sess_key);
		return nt_status;
	}

	become_root();
	nt_status = make_server_info_sam(server_info, sampass);
	unbecome_root();

	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status)));
		TALLOC_FREE(sampass);
		data_blob_free(&user_sess_key);
		data_blob_free(&lm_sess_key);
		return nt_status;
	}

	(*server_info)->user_session_key =
		data_blob_talloc(*server_info, user_sess_key.data,
				 user_sess_key.length);
	data_blob_free(&user_sess_key);

	(*server_info)->lm_session_key =
		data_blob_talloc(*server_info, lm_sess_key.data,
				 lm_sess_key.length);
	data_blob_free(&lm_sess_key);

	(*server_info)->was_mapped |= user_info->was_mapped;

	return nt_status;
}
Beispiel #17
0
/**
 * Check whether the given password is one of the last two
 * password history entries. If so, the bad pwcount should
 * not be incremented even thought the actual password check
 * failed.
 */
static bool need_to_increment_bad_pw_count(
	const DATA_BLOB *challenge,
	struct samu* sampass,
	const struct auth_usersupplied_info *user_info)
{
	uint8_t i;
	const uint8_t *pwhistory;
	uint32_t pwhistory_len;
	uint32_t policy_pwhistory_len;
	uint32_t acct_ctrl;
	const char *username;
	TALLOC_CTX *mem_ctx = talloc_stackframe();
	bool result = true;

	pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY,
			       &policy_pwhistory_len);
	if (policy_pwhistory_len == 0) {
		goto done;
	}

	pwhistory = pdb_get_pw_history(sampass, &pwhistory_len);
	if (!pwhistory || pwhistory_len == 0) {
		goto done;
	}

	acct_ctrl = pdb_get_acct_ctrl(sampass);
	username = pdb_get_username(sampass);

	for (i=1; i < MIN(MIN(3, policy_pwhistory_len), pwhistory_len); i++) {
		static const uint8_t zero16[SALTED_MD5_HASH_LEN];
		const uint8_t *salt;
		const uint8_t *nt_pw;
		NTSTATUS status;
		DATA_BLOB user_sess_key = data_blob_null;
		DATA_BLOB lm_sess_key = data_blob_null;

		salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
		nt_pw = salt + PW_HISTORY_SALT_LEN;

		if (memcmp(zero16, nt_pw, NT_HASH_LEN) == 0) {
			/* skip zero password hash */
			continue;
		}

		if (memcmp(zero16, salt, PW_HISTORY_SALT_LEN) != 0) {
			/* skip nonzero salt (old format entry) */
			continue;
		}

		status = sam_password_ok(mem_ctx,
					 username, acct_ctrl,
					 challenge,
					 NULL, nt_pw,
					 user_info, &user_sess_key, &lm_sess_key);
		if (NT_STATUS_IS_OK(status)) {
			result = false;
			break;
		}
	}

done:
	TALLOC_FREE(mem_ctx);
	return result;
}
Beispiel #18
0
static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, int flag)
{
	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
	TDB_CONTEXT 	*pwd_tdb = NULL;
	TDB_DATA 	key, data;
	uint8		*buf = NULL;
	fstring 	keystr;
	fstring		name;
	BOOL		ret = True;
	uint32		user_rid;

	/* invalidate the existing TDB iterator if it is open */
	
	if (tdb_state->passwd_tdb) {
		tdb_close(tdb_state->passwd_tdb);
		tdb_state->passwd_tdb = NULL;
	}

 	/* open the account TDB passwd*/
	
	pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
	
  	if (!pwd_tdb) {
		DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", 
			tdb_state->tdbsam_location));
		return False;
	}

	if (!pdb_get_group_rid(newpwd)) {
		DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",
			pdb_get_username(newpwd)));
		ret = False;
		goto done;
	}

	if ( !(user_rid = pdb_get_user_rid(newpwd)) ) {
		DEBUG(0,("tdb_update_sam: SAM_ACCOUNT (%s) with no RID!\n", pdb_get_username(newpwd)));
		ret = False;
		goto done;
	}

	/* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
	if ((data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1) {
		DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
		ret = False;
		goto done;
	}
	data.dptr = (char *)buf;

	fstrcpy(name, pdb_get_username(newpwd));
	strlower_m(name);
	
	DEBUG(5, ("Storing %saccount %s with RID %d\n", flag == TDB_INSERT ? "(new) " : "", name, user_rid));

  	/* setup the USER index key */
	slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
	key.dptr = keystr;
	key.dsize = strlen(keystr) + 1;

	/* add the account */
	if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
		DEBUG(0, ("Unable to modify passwd TDB!"));
		DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb)));
		DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr));
		ret = False;
		goto done;
	}
	
	/* setup RID data */
	data.dsize = strlen(name) + 1;
	data.dptr = name;

	/* setup the RID index key */
	slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, user_rid);
	key.dptr = keystr;
	key.dsize = strlen (keystr) + 1;
	
	/* add the reference */
	if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
		DEBUG(0, ("Unable to modify TDB passwd !"));
		DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
		DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
		ret = False;
		goto done;
	}

done:	
	/* cleanup */
	tdb_close (pwd_tdb);
	SAFE_FREE(buf);
	
	return (ret);	
}
Beispiel #19
0
NTSTATUS check_sam_security(const DATA_BLOB *challenge,
			    TALLOC_CTX *mem_ctx,
			    const struct auth_usersupplied_info *user_info,
			    struct auth_serversupplied_info **server_info)
{
	struct samu *sampass=NULL;
	bool ret;
	NTSTATUS nt_status;
	NTSTATUS update_login_attempts_status;
	DATA_BLOB user_sess_key = data_blob_null;
	DATA_BLOB lm_sess_key = data_blob_null;
	bool updated_badpw = False;
	const char *username;
	const uint8_t *nt_pw;
	const uint8_t *lm_pw;
	uint32_t acct_ctrl;

	/* the returned struct gets kept on the server_info, by means
	   of a steal further down */

	sampass = samu_new(mem_ctx);
	if (sampass == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	/* get the account information */

	become_root();
	ret = pdb_getsampwnam(sampass, user_info->mapped.account_name);
	unbecome_root();

	if (ret == False) {
		DEBUG(3,("check_sam_security: Couldn't find user '%s' in "
			 "passdb.\n", user_info->mapped.account_name));
		TALLOC_FREE(sampass);
		return NT_STATUS_NO_SUCH_USER;
	}

	acct_ctrl = pdb_get_acct_ctrl(sampass);
	username = pdb_get_username(sampass);
	nt_pw = pdb_get_nt_passwd(sampass);
	lm_pw = pdb_get_lanman_passwd(sampass);

	/* Quit if the account was locked out. */
	if (acct_ctrl & ACB_AUTOLOCK) {
		DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", username));
		TALLOC_FREE(sampass);
		return NT_STATUS_ACCOUNT_LOCKED_OUT;
	}

	nt_status = sam_password_ok(mem_ctx,
				    username, acct_ctrl,
				    challenge, lm_pw, nt_pw,
				    user_info, &user_sess_key, &lm_sess_key);

	/* Notify passdb backend of login success/failure. If not
	   NT_STATUS_OK the backend doesn't like the login */

	update_login_attempts_status = pdb_update_login_attempts(sampass, NT_STATUS_IS_OK(nt_status));

	if (!NT_STATUS_IS_OK(nt_status)) {
		bool increment_bad_pw_count = false;

		if (NT_STATUS_EQUAL(nt_status,NT_STATUS_WRONG_PASSWORD) &&
		    (acct_ctrl & ACB_NORMAL) &&
		    NT_STATUS_IS_OK(update_login_attempts_status))
		{
			increment_bad_pw_count =
				need_to_increment_bad_pw_count(
					challenge, sampass, user_info);
		}

		if (increment_bad_pw_count) {
			pdb_increment_bad_password_count(sampass);
			updated_badpw = True;
		} else {
			pdb_update_bad_password_count(sampass,
						      &updated_badpw);
		}
		if (updated_badpw){
			NTSTATUS status;

			become_root();
			status = pdb_update_sam_account(sampass);
			unbecome_root();

			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(1, ("Failed to modify entry: %s\n",
					  nt_errstr(status)));
			}
		}
		goto done;
	}

	/*
	 * We must only reset the bad password count if the login was
	 * successful, including checking account policies
	 */
	nt_status = sam_account_ok(mem_ctx, sampass, user_info);
	if (!NT_STATUS_IS_OK(nt_status)) {
		goto done;
	}

	if ((acct_ctrl & ACB_NORMAL) &&
	    (pdb_get_bad_password_count(sampass) > 0)){
		NTSTATUS status;

		pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
		pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);

		become_root();
		status = pdb_update_sam_account(sampass);
		unbecome_root();

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to modify entry: %s\n",
				  nt_errstr(status)));
		}
	}

	become_root();
	nt_status = make_server_info_sam(mem_ctx, sampass, server_info);
	unbecome_root();

	TALLOC_FREE(sampass);

	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status)));
		goto done;
	}

	(*server_info)->session_key =
		data_blob_talloc(*server_info, user_sess_key.data,
				 user_sess_key.length);
	data_blob_free(&user_sess_key);

	(*server_info)->lm_session_key =
		data_blob_talloc(*server_info, lm_sess_key.data,
				 lm_sess_key.length);
	data_blob_free(&lm_sess_key);

	(*server_info)->nss_token |= user_info->was_mapped;

done:
	TALLOC_FREE(sampass);
	data_blob_free(&user_sess_key);
	data_blob_free(&lm_sess_key);
	return nt_status;
}
Beispiel #20
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;
  }
Beispiel #21
0
static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
			   int flag)
{
	uint32_t oldrid;
	uint32_t newrid;

	if (!(newrid = pdb_get_user_rid(newpwd))) {
		DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
			 pdb_get_username(newpwd)));
		return False;
	}

	oldrid = newrid;

	/* open the database */

	if ( !tdbsam_open( tdbsam_filename ) ) {
		DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
		return False;
	}

	if (dbwrap_transaction_start(db_sam) != 0) {
		DEBUG(0, ("Could not start transaction\n"));
		return false;
	}

	/* If we are updating, we may be changing this users RID. Retrieve the old RID
	   so we can check. */

	if (flag == TDB_MODIFY) {
		struct samu *account = samu_new(talloc_tos());
		if (account == NULL) {
			DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
			goto cancel;
		}
		if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
			DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
				pdb_get_username(newpwd)));
			TALLOC_FREE(account);
			goto cancel;
		}
		if (!(oldrid = pdb_get_user_rid(account))) {
			DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
			TALLOC_FREE(account);
			goto cancel;
		}
		TALLOC_FREE(account);
	}

	/* Update the new samu entry. */
	if (!tdb_update_samacct_only(newpwd, flag)) {
		goto cancel;
	}

	/* Now take care of the case where the RID changed. We need
	 * to delete the old RID key and add the new. */

	if (flag == TDB_MODIFY && newrid != oldrid) { 
		fstring keystr;

		/* Delete old RID key */
		DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
		fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, oldrid);
		if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
			DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
			goto cancel;
		}
		/* Insert new RID key */
		DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
		if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
			goto cancel;
		}
	} else {
		DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
			flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
		if (!tdb_update_ridrec_only(newpwd, flag)) {
			goto cancel;
		}
	}

	if (dbwrap_transaction_commit(db_sam) != 0) {
		DEBUG(0, ("Could not commit transaction\n"));
		return false;
	}

	return true;

 cancel:
	if (dbwrap_transaction_cancel(db_sam) != 0) {
		smb_panic("transaction_cancel failed");
	}
	return false;
}
Beispiel #22
0
/*******************************************************************
 gets a domain user's groups
 ********************************************************************/
BOOL get_domain_user_groups(TALLOC_CTX *ctx, int *numgroups, DOM_GID **pgids, SAM_ACCOUNT *sam_pass)
{
	GROUP_MAP *map=NULL;
	int i, num, num_entries, cur_gid=0;
	struct group *grp;
	DOM_GID *gids;
	fstring user_name;
	uint32 grid;
	uint32 tmp_rid;
	BOOL ret;

	*numgroups= 0;

	fstrcpy(user_name, pdb_get_username(sam_pass));
	grid=pdb_get_group_rid(sam_pass);

	DEBUG(10,("get_domain_user_groups: searching domain groups [%s] is a member of\n", user_name));

	/* we must wrap this is become/unbecome root for ldap backends */
	
	become_root();
	/* first get the list of the domain groups */
	ret = pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, &num_entries, ENUM_ONLY_MAPPED);
	
	unbecome_root();

	/* end wrapper for group enumeration */

	
	if ( !ret )
		return False;
		
	DEBUG(10,("get_domain_user_groups: there are %d mapped groups\n", num_entries));


	/* 
	 * alloc memory. In the worse case, we alloc memory for nothing.
	 * but I prefer to alloc for nothing
	 * than reallocing everytime.
	 */
	gids = (DOM_GID *)talloc(ctx, sizeof(DOM_GID) *  num_entries);	

	/* for each group, check if the user is a member of.  Only include groups 
	   from this domain */
	
	for(i=0; i<num_entries; i++) {
	
		if ( !sid_check_is_in_our_domain(&map[i].sid) ) {
			DEBUG(10,("get_domain_user_groups: skipping check of %s since it is not in our domain\n",
				map[i].nt_name));
			continue;
		}
			
		if ((grp=sys_getgrgid(map[i].gid)) == NULL) {
			/* very weird !!! */
			DEBUG(5,("get_domain_user_groups: gid %d doesn't exist anymore !\n", (int)map[i].gid));
			continue;
		}

		for(num=0; grp->gr_mem[num]!=NULL; num++) {
			if(strcmp(grp->gr_mem[num], user_name)==0) {
				/* we found the user, add the group to the list */
				sid_peek_rid(&map[i].sid, &(gids[cur_gid].g_rid));
				gids[cur_gid].attr=7;
				DEBUG(10,("get_domain_user_groups: user found in group %s\n", map[i].nt_name));
				cur_gid++;
				break;
			}
		}
	}

	/* we have checked the groups */
	/* we must now check the gid of the user or the primary group rid, that's the same */
	for (i=0; i<cur_gid && grid!=gids[i].g_rid; i++)
		;
	
	/* the user's gid is already there */
	if (i!=cur_gid) {
		/* 
		 * the primary group of the user but be the first one in the list
		 * don't ask ! JFM.
		 */
		gids[i].g_rid=gids[0].g_rid;
		gids[0].g_rid=grid;
		goto done;
	}

	for(i=0; i<num_entries; i++) {
		sid_peek_rid(&map[i].sid, &tmp_rid);
		if (tmp_rid==grid) {
			/* 
			 * the primary group of the user but be the first one in the list
			 * don't ask ! JFM.
			 */
			gids[cur_gid].g_rid=gids[0].g_rid;
			gids[0].g_rid=tmp_rid;
			gids[cur_gid].attr=7;
			DEBUG(10,("get_domain_user_groups: primary gid of user found in group %s\n", map[i].nt_name));
			cur_gid++;
			goto done; /* leave the loop early */
		}
	}

	DEBUG(0,("get_domain_user_groups: primary gid of user [%s] is not a Domain group !\n", user_name));
	DEBUGADD(0,("get_domain_user_groups: You should fix it, NT doesn't like that\n"));


 done:
	*pgids=gids;
	*numgroups=cur_gid;
	SAFE_FREE(map);

	return True;
}
Beispiel #23
0
int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
                     int argc, const char **argv)
{
    unsigned int ctrl;
    int retval;

    extern BOOL in_client;

    SAM_ACCOUNT *sampass = NULL;
    void (*oldsig_handler)(int);
    const char *user;
    char *pass_old;
    char *pass_new;

    NTSTATUS nt_status;

    /* Samba initialization. */
    setup_logging( "pam_smbpass", False );
    in_client = True;

    ctrl = set_ctrl(flags, argc, argv);

    /*
     * First get the name of a user.  No need to do anything if we can't
     * determine this.
     */

    retval = pam_get_user( pamh, &user, "Username: "******"password: could not identify user" );
        }
        return retval;
    }
    if (on( SMB_DEBUG, ctrl )) {
        _log_err( LOG_DEBUG, "username [%s] obtained", user );
    }

    /* Getting into places that might use LDAP -- protect the app
       from a SIGPIPE it's not expecting */
    oldsig_handler = CatchSignal(SIGPIPE, SIGNAL_CAST SIG_IGN);

    if (!initialize_password_db(True)) {
        _log_err( LOG_ALERT, "Cannot access samba password database" );
        CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
        return PAM_AUTHINFO_UNAVAIL;
    }

    /* obtain user record */
    if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(&sampass))) {
        CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
        return nt_status_to_pam(nt_status);
    }

    if (!pdb_getsampwnam(sampass,user)) {
        _log_err( LOG_ALERT, "Failed to find entry for user %s.", user );
        CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
        return PAM_USER_UNKNOWN;
    }

    if (flags & PAM_PRELIM_CHECK) {
        /*
         * obtain and verify the current password (OLDAUTHTOK) for
         * the user.
         */

        char *Announce;

        if (_smb_blankpasswd( ctrl, sampass )) {

            pdb_free_sam(&sampass);
            CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
            return PAM_SUCCESS;
        }

	/* Password change by root, or for an expired token, doesn't
           require authentication.  Is this a good choice? */
        if (getuid() != 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {

            /* tell user what is happening */
#define greeting "Changing password for "
            Announce = (char *) malloc(sizeof(greeting)+strlen(user));
            if (Announce == NULL) {
                _log_err(LOG_CRIT, "password: out of memory");
                pdb_free_sam(&sampass);
                CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
                return PAM_BUF_ERR;
            }
            strncpy( Announce, greeting, sizeof(greeting) );
            strncpy( Announce+sizeof(greeting)-1, user, strlen(user)+1 );
#undef greeting

            set( SMB__OLD_PASSWD, ctrl );
            retval = _smb_read_password( pamh, ctrl, Announce, "Current SMB password: "******"password - (old) token not obtained" );
                pdb_free_sam(&sampass);
                CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
                return retval;
            }

            /* verify that this is the password for this user */

            retval = _smb_verify_password( pamh, sampass, pass_old, ctrl );

        } else {
	    pass_old = NULL;
            retval = PAM_SUCCESS;           /* root doesn't have to */
        }

        pass_old = NULL;
        pdb_free_sam(&sampass);
        CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
        return retval;

    } else if (flags & PAM_UPDATE_AUTHTOK) {

        /*
         * obtain the proposed password
         */

        /*
         * get the old token back. NULL was ok only if root [at this
         * point we assume that this has already been enforced on a
         * previous call to this function].
         */

        if (off( SMB_NOT_SET_PASS, ctrl )) {
            retval = pam_get_item( pamh, PAM_OLDAUTHTOK,
                                   (const void **)&pass_old );
        } else {
            retval = pam_get_data( pamh, _SMB_OLD_AUTHTOK,
                                   (const void **)&pass_old );
            if (retval == PAM_NO_MODULE_DATA) {
		pass_old = NULL;
                retval = PAM_SUCCESS;
            }
        }

        if (retval != PAM_SUCCESS) {
            _log_err( LOG_NOTICE, "password: user not authenticated" );
            pdb_free_sam(&sampass);
            CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
            return retval;
        }

        /*
         * use_authtok is to force the use of a previously entered
         * password -- needed for pluggable password strength checking
	 * or other module stacking
         */

        if (on( SMB_USE_AUTHTOK, ctrl )) {
            set( SMB_USE_FIRST_PASS, ctrl );
        }

        retval = _smb_read_password( pamh, ctrl
                                      , NULL
                                      , "Enter new SMB password: "******"Retype new SMB password: "******"password: new password not obtained" );
            }
            pass_old = NULL;                               /* tidy up */
            pdb_free_sam(&sampass);
            CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
            return retval;
        }

        /*
         * At this point we know who the user is and what they
         * propose as their new password. Verify that the new
         * password is acceptable.
         */ 

        if (pass_new[0] == '\0') {     /* "\0" password = NULL */
            pass_new = NULL;
        }

        retval = _pam_smb_approve_pass(pamh, ctrl, pass_old, pass_new);

        if (retval != PAM_SUCCESS) {
            _log_err(LOG_NOTICE, "new password not acceptable");
            pass_new = pass_old = NULL;               /* tidy up */
            pdb_free_sam(&sampass);
            CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
            return retval;
        }

        /*
         * By reaching here we have approved the passwords and must now
         * rebuild the smb password file.
         */

        /* update the password database */

        retval = smb_update_db(pamh, ctrl, user, pass_new);
        if (retval == PAM_SUCCESS) {
	    uid_t uid;
	    
            /* password updated */
		if (!NT_STATUS_IS_OK(sid_to_uid(pdb_get_user_sid(sampass), &uid))) {
			_log_err( LOG_NOTICE, "Unable to get uid for user %s",
				pdb_get_username(sampass));
			_log_err( LOG_NOTICE, "password for (%s) changed by (%s/%d)",
				user, uidtoname(getuid()), getuid());
		} else {
			_log_err( LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)",
				user, uid, uidtoname(getuid()), getuid());
		}
	} else {
		_log_err( LOG_ERR, "password change failed for user %s", user);
	}

        pass_old = pass_new = NULL;
	if (sampass) {
		pdb_free_sam(&sampass);
		sampass = NULL;
	}

    } else {            /* something has broken with the library */

        _log_err( LOG_ALERT, "password received unknown request" );
        retval = PAM_ABORT;

    }
    
    if (sampass) {
    	pdb_free_sam(&sampass);
	sampass = NULL;
    }

    pdb_free_sam(&sampass);
    CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
    return retval;
}
NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info,
				uint8_t pipe_session_key[16],
				struct netr_SamInfo3 *sam3)
{
	struct samu *sampw;
	DOM_GID *gids = NULL;
	const DOM_SID *user_sid = NULL;
	const DOM_SID *group_sid = NULL;
	DOM_SID domain_sid;
	uint32 user_rid, group_rid;
	NTSTATUS status;

	int num_gids = 0;
	const char *my_name;

	struct netr_UserSessionKey user_session_key;
	struct netr_LMSessionKey lm_session_key;

	NTTIME last_logon, last_logoff, acct_expiry, last_password_change;
	NTTIME allow_password_change, force_password_change;
	struct samr_RidWithAttributeArray groups;
	int i;
	struct dom_sid2 *sid = NULL;

	ZERO_STRUCT(user_session_key);
	ZERO_STRUCT(lm_session_key);

	sampw = server_info->sam_account;

	user_sid = pdb_get_user_sid(sampw);
	group_sid = pdb_get_group_sid(sampw);

	if ((user_sid == NULL) || (group_sid == NULL)) {
		DEBUG(1, ("_netr_LogonSamLogon: User without group or user SID\n"));
		return NT_STATUS_UNSUCCESSFUL;
	}

	sid_copy(&domain_sid, user_sid);
	sid_split_rid(&domain_sid, &user_rid);

	sid = sid_dup_talloc(sam3, &domain_sid);
	if (!sid) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) {
		DEBUG(1, ("_netr_LogonSamLogon: user %s\\%s has user sid "
			  "%s\n but group sid %s.\n"
			  "The conflicting domain portions are not "
			  "supported for NETLOGON calls\n",
			  pdb_get_domain(sampw),
			  pdb_get_username(sampw),
			  sid_string_dbg(user_sid),
			  sid_string_dbg(group_sid)));
		return NT_STATUS_UNSUCCESSFUL;
	}

	if(server_info->login_server) {
		my_name = server_info->login_server;
	} else {
		my_name = global_myname();
	}

	status = nt_token_to_group_list(sam3, &domain_sid,
					server_info->num_sids,
					server_info->sids,
					&num_gids, &gids);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (server_info->user_session_key.length) {
		memcpy(user_session_key.key,
		       server_info->user_session_key.data,
		       MIN(sizeof(user_session_key.key),
			   server_info->user_session_key.length));
		SamOEMhash(user_session_key.key, pipe_session_key, 16);
	}
	if (server_info->lm_session_key.length) {
		memcpy(lm_session_key.key,
		       server_info->lm_session_key.data,
		       MIN(sizeof(lm_session_key.key),
			   server_info->lm_session_key.length));
		SamOEMhash(lm_session_key.key, pipe_session_key, 8);
	}

	groups.count = num_gids;
	groups.rids = TALLOC_ARRAY(sam3, struct samr_RidWithAttribute, groups.count);
	if (!groups.rids) {
		return NT_STATUS_NO_MEMORY;
	}

	for (i=0; i < groups.count; i++) {
		groups.rids[i].rid = gids[i].g_rid;
		groups.rids[i].attributes = gids[i].attr;
	}

	unix_to_nt_time(&last_logon, pdb_get_logon_time(sampw));
	unix_to_nt_time(&last_logoff, get_time_t_max());
	unix_to_nt_time(&acct_expiry, get_time_t_max());
	unix_to_nt_time(&last_password_change, pdb_get_pass_last_set_time(sampw));
	unix_to_nt_time(&allow_password_change, pdb_get_pass_can_change_time(sampw));
	unix_to_nt_time(&force_password_change, pdb_get_pass_must_change_time(sampw));

	init_netr_SamInfo3(sam3,
			   last_logon,
			   last_logoff,
			   acct_expiry,
			   last_password_change,
			   allow_password_change,
			   force_password_change,
			   talloc_strdup(sam3, pdb_get_username(sampw)),
			   talloc_strdup(sam3, pdb_get_fullname(sampw)),
			   talloc_strdup(sam3, pdb_get_logon_script(sampw)),
			   talloc_strdup(sam3, pdb_get_profile_path(sampw)),
			   talloc_strdup(sam3, pdb_get_homedir(sampw)),
			   talloc_strdup(sam3, pdb_get_dir_drive(sampw)),
			   0, /* logon_count */
			   0, /* bad_password_count */
			   user_rid,
			   group_rid,
			   groups,
			   NETLOGON_EXTRA_SIDS,
			   user_session_key,
			   my_name,
			   talloc_strdup(sam3, pdb_get_domain(sampw)),
			   sid,
			   lm_session_key,
			   pdb_get_acct_ctrl(sampw),
			   0, /* sidcount */
			   NULL); /* struct netr_SidAttr *sids */
	ZERO_STRUCT(user_session_key);
	ZERO_STRUCT(lm_session_key);

	return NT_STATUS_OK;
}
Beispiel #25
0
/***************************************************************************
 Renames a struct samu
 - check for the posix user/rename user script
 - Add and lock the new user record
 - rename the posix user
 - rewrite the rid->username record
 - delete the old user
 - unlock the new user record
***************************************************************************/
static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
					  struct samu *old_acct,
					  const char *newname)
{
	struct samu      *new_acct = NULL;
	char *rename_script = NULL;
	int              rename_ret;
	fstring          oldname_lower;
	fstring          newname_lower;

	/* can't do anything without an external script */

	if ( !(new_acct = samu_new( talloc_tos() )) ) {
		return NT_STATUS_NO_MEMORY;
	}

	rename_script = lp_rename_user_script(new_acct);
	if (!rename_script) {
		TALLOC_FREE(new_acct);
		return NT_STATUS_NO_MEMORY;
	}
	if (!*rename_script) {
		TALLOC_FREE(new_acct);
		return NT_STATUS_ACCESS_DENIED;
	}

	if ( !pdb_copy_sam_account(new_acct, old_acct)
		|| !pdb_set_username(new_acct, newname, PDB_CHANGED))
	{
		TALLOC_FREE(new_acct);
		return NT_STATUS_NO_MEMORY;
	}

	/* open the database */
	if ( !tdbsam_open( tdbsam_filename ) ) {
		DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
			  tdbsam_filename));
		TALLOC_FREE(new_acct);
		return NT_STATUS_ACCESS_DENIED;
	}

	if (dbwrap_transaction_start(db_sam) != 0) {
		DEBUG(0, ("Could not start transaction\n"));
		TALLOC_FREE(new_acct);
		return NT_STATUS_ACCESS_DENIED;

	}

	/* add the new account and lock it */
	if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
		goto cancel;
	}

	/* Rename the posix user.  Follow the semantics of _samr_create_user()
	   so that we lower case the posix name but preserve the case in passdb */

	fstrcpy( oldname_lower, pdb_get_username(old_acct) );
	if (!strlower_m( oldname_lower )) {
		goto cancel;
	}

	fstrcpy( newname_lower, newname );
	if (!strlower_m( newname_lower )) {
		goto cancel;
	}

	rename_script = talloc_string_sub2(new_acct,
				rename_script,
				"%unew",
				newname_lower,
				true,
				false,
				true);
	if (!rename_script) {
		goto cancel;
	}
	rename_script = talloc_string_sub2(new_acct,
				rename_script,
				"%uold",
				oldname_lower,
				true,
				false,
				true);
	if (!rename_script) {
		goto cancel;
	}
	rename_ret = smbrun(rename_script, NULL, NULL);

	DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
				rename_script, rename_ret));

	if (rename_ret != 0) {
		goto cancel;
	}

	smb_nscd_flush_user_cache();

	/* rewrite the rid->username record */

	if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
		goto cancel;
	}

	tdb_delete_samacct_only( old_acct );

	if (dbwrap_transaction_commit(db_sam) != 0) {
		/*
		 * Ok, we're screwed. We've changed the posix account, but
		 * could not adapt passdb.tdb. Shall we change the posix
		 * account back?
		 */
		DEBUG(0, ("transaction_commit failed\n"));
		TALLOC_FREE(new_acct);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;	
	}

	TALLOC_FREE(new_acct );
	return NT_STATUS_OK;

 cancel:
	if (dbwrap_transaction_cancel(db_sam) != 0) {
		smb_panic("transaction_cancel failed");
	}

	TALLOC_FREE(new_acct);

	return NT_STATUS_ACCESS_DENIED;	
}
Beispiel #26
0
/*******************************************************************
 gets a domain user's groups
 ********************************************************************/
NTSTATUS get_alias_user_groups(TALLOC_CTX *ctx, DOM_SID *sid, int *numgroups, uint32 **prids, DOM_SID *q_sid)
{
	SAM_ACCOUNT *sam_pass=NULL;
	int i, cur_rid=0;
	gid_t gid;
	gid_t *groups = NULL;
	int num_groups;
	GROUP_MAP map;
	DOM_SID tmp_sid;
	fstring user_name;
	fstring str_domsid, str_qsid;
	uint32 rid,grid;
	uint32 *rids=NULL, *new_rids=NULL;
	gid_t winbind_gid_low, winbind_gid_high;
	BOOL ret;
	BOOL winbind_groups_exist;

	/*
	 * this code is far from perfect.
	 * first it enumerates the full /etc/group and that can be slow.
	 * second, it works only with users' SIDs
	 * whereas the day we support nested groups, it will have to
	 * support both users's SIDs and domain groups' SIDs
	 *
	 * having our own ldap backend would be so much faster !
	 * we're far from that, but hope one day ;-) JFM.
	 */

	*prids=NULL;
	*numgroups=0;

	winbind_groups_exist = lp_idmap_gid(&winbind_gid_low, &winbind_gid_high);


	DEBUG(10,("get_alias_user_groups: looking if SID %s is a member of groups in the SID domain %s\n", 
	          sid_to_string(str_qsid, q_sid), sid_to_string(str_domsid, sid)));

	pdb_init_sam(&sam_pass);
	become_root();
	ret = pdb_getsampwsid(sam_pass, q_sid);
	unbecome_root();
	if (ret == False) {
		pdb_free_sam(&sam_pass);
		return NT_STATUS_NO_SUCH_USER;
	}

	fstrcpy(user_name, pdb_get_username(sam_pass));
	grid=pdb_get_group_rid(sam_pass);
	if (!NT_STATUS_IS_OK(sid_to_gid(pdb_get_group_sid(sam_pass), &gid))) {
		/* this should never happen */
		DEBUG(2,("get_alias_user_groups: sid_to_gid failed!\n"));
		pdb_free_sam(&sam_pass);
		return NT_STATUS_UNSUCCESSFUL;
	}

	become_root();
	/* on some systems this must run as root */
	num_groups = getgroups_user(user_name, &groups);	
	unbecome_root();
	if (num_groups == -1) {
		/* this should never happen */
		DEBUG(2,("get_alias_user_groups: getgroups_user failed\n"));
		pdb_free_sam(&sam_pass);
		return NT_STATUS_UNSUCCESSFUL;
	}

	for (i=0;i<num_groups;i++) {

		if (!get_group_from_gid(groups[i], &map)) {
			DEBUG(10,("get_alias_user_groups: gid %d. not found\n", (int)groups[i]));
			continue;
		}
		
		/* if it's not an alias, continue */
		if (map.sid_name_use != SID_NAME_ALIAS) {
			DEBUG(10,("get_alias_user_groups: not returing %s, not an ALIAS group.\n", map.nt_name));
			continue;
		}

		sid_copy(&tmp_sid, &map.sid);
		sid_split_rid(&tmp_sid, &rid);
		
		/* if the sid is not in the correct domain, continue */
		if (!sid_equal(&tmp_sid, sid)) {
			DEBUG(10,("get_alias_user_groups: not returing %s, not in the domain SID.\n", map.nt_name));
			continue;
		}

		/* Don't return winbind groups as they are not local! */
		if (winbind_groups_exist && (groups[i] >= winbind_gid_low) && (groups[i] <= winbind_gid_high)) {
			DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name));
			continue;
		}

		/* Don't return user private groups... */
		if (Get_Pwnam(map.nt_name) != 0) {
			DEBUG(10,("get_alias_user_groups: not returing %s, clashes with user.\n", map.nt_name));
			continue;			
		}
		
		new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
		if (new_rids==NULL) {
			DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
			pdb_free_sam(&sam_pass);
			free(groups);
			return NT_STATUS_NO_MEMORY;
		}
		rids=new_rids;
		
		sid_peek_rid(&map.sid, &(rids[cur_rid]));
		cur_rid++;
		break;
	}

	if(num_groups) 
		free(groups);

	/* now check for the user's gid (the primary group rid) */
	for (i=0; i<cur_rid && grid!=rids[i]; i++)
		;

	/* the user's gid is already there */
	if (i!=cur_rid) {
		DEBUG(10,("get_alias_user_groups: user is already in the list. good.\n"));
		goto done;
	}

	DEBUG(10,("get_alias_user_groups: looking for gid %d of user %s\n", (int)gid, user_name));

	if(!get_group_from_gid(gid, &map)) {
		DEBUG(0,("get_alias_user_groups: gid of user %s doesn't exist. Check your "
		"/etc/passwd and /etc/group files\n", user_name));
		goto done;
	}	

	/* the primary group isn't an alias */
	if (map.sid_name_use!=SID_NAME_ALIAS) {
		DEBUG(10,("get_alias_user_groups: not returing %s, not an ALIAS group.\n", map.nt_name));
		goto done;
	}

	sid_copy(&tmp_sid, &map.sid);
	sid_split_rid(&tmp_sid, &rid);

	/* if the sid is not in the correct domain, continue */
	if (!sid_equal(&tmp_sid, sid)) {
		DEBUG(10,("get_alias_user_groups: not returing %s, not in the domain SID.\n", map.nt_name));
		goto done;
	}

	/* Don't return winbind groups as they are not local! */
	if (winbind_groups_exist && (gid >= winbind_gid_low) && (gid <= winbind_gid_high)) {
		DEBUG(10,("get_alias_user_groups: not returing %s, not local.\n", map.nt_name ));
		goto done;
	}

	/* Don't return user private groups... */
	if (Get_Pwnam(map.nt_name) != 0) {
		DEBUG(10,("get_alias_user_groups: not returing %s, clashes with user.\n", map.nt_name ));
		goto done;			
	}

	new_rids=(uint32 *)Realloc(rids, sizeof(uint32)*(cur_rid+1));
	if (new_rids==NULL) {
		DEBUG(10,("get_alias_user_groups: could not realloc memory\n"));
		pdb_free_sam(&sam_pass);
		return NT_STATUS_NO_MEMORY;
	}
	rids=new_rids;

 	sid_peek_rid(&map.sid, &(rids[cur_rid]));
	cur_rid++;

done:
 	*prids=rids;
	*numgroups=cur_rid;
	pdb_free_sam(&sam_pass);

	return NT_STATUS_OK;
}
Beispiel #27
0
static int print_sam_info (struct samu *sam_pwent, bool verbosity, bool smbpwdstyle)
{
	uid_t uid;
	time_t tmp;

	/* TODO: check if entry is a user or a workstation */
	if (!sam_pwent) return -1;

	if (verbosity) {
		char temp[44];
		const uint8_t *hours;

		printf ("Unix username:        %s\n", pdb_get_username(sam_pwent));
		printf ("NT username:          %s\n", pdb_get_nt_username(sam_pwent));
		printf ("Account Flags:        %s\n", pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent), NEW_PW_FORMAT_SPACE_PADDED_LEN));
		printf ("User SID:             %s\n",
			sid_string_tos(pdb_get_user_sid(sam_pwent)));
		printf ("Primary Group SID:    %s\n",
			sid_string_tos(pdb_get_group_sid(sam_pwent)));
		printf ("Full Name:            %s\n", pdb_get_fullname(sam_pwent));
		printf ("Home Directory:       %s\n", pdb_get_homedir(sam_pwent));
		printf ("HomeDir Drive:        %s\n", pdb_get_dir_drive(sam_pwent));
		printf ("Logon Script:         %s\n", pdb_get_logon_script(sam_pwent));
		printf ("Profile Path:         %s\n", pdb_get_profile_path(sam_pwent));
		printf ("Domain:               %s\n", pdb_get_domain(sam_pwent));
		printf ("Account desc:         %s\n", pdb_get_acct_desc(sam_pwent));
		printf ("Workstations:         %s\n", pdb_get_workstations(sam_pwent));
		printf ("Munged dial:          %s\n", pdb_get_munged_dial(sam_pwent));

		tmp = pdb_get_logon_time(sam_pwent);
		printf ("Logon time:           %s\n",
				tmp ? http_timestring(talloc_tos(), tmp) : "0");

		tmp = pdb_get_logoff_time(sam_pwent);
		printf ("Logoff time:          %s\n",
				tmp ? http_timestring(talloc_tos(), tmp) : "0");

		tmp = pdb_get_kickoff_time(sam_pwent);
		printf ("Kickoff time:         %s\n",
				tmp ? http_timestring(talloc_tos(), tmp) : "0");

		tmp = pdb_get_pass_last_set_time(sam_pwent);
		printf ("Password last set:    %s\n",
				tmp ? http_timestring(talloc_tos(), tmp) : "0");

		tmp = pdb_get_pass_can_change_time(sam_pwent);
		printf ("Password can change:  %s\n",
				tmp ? http_timestring(talloc_tos(), tmp) : "0");

		tmp = pdb_get_pass_must_change_time(sam_pwent);
		printf ("Password must change: %s\n",
				tmp ? http_timestring(talloc_tos(), tmp) : "0");

		tmp = pdb_get_bad_password_time(sam_pwent);
		printf ("Last bad password   : %s\n",
				tmp ? http_timestring(talloc_tos(), tmp) : "0");
		printf ("Bad password count  : %d\n",
			pdb_get_bad_password_count(sam_pwent));

		hours = pdb_get_hours(sam_pwent);
		pdb_sethexhours(temp, hours);
		printf ("Logon hours         : %s\n", temp);

	} else if (smbpwdstyle) {
		char lm_passwd[33];
		char nt_passwd[33];

		uid = nametouid(pdb_get_username(sam_pwent));
		pdb_sethexpwd(lm_passwd, pdb_get_lanman_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
		pdb_sethexpwd(nt_passwd, pdb_get_nt_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));

		printf("%s:%lu:%s:%s:%s:LCT-%08X:\n",
		       pdb_get_username(sam_pwent),
		       (unsigned long)uid,
		       lm_passwd,
		       nt_passwd,
		       pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent),NEW_PW_FORMAT_SPACE_PADDED_LEN),
		       (uint32_t)convert_time_t_to_uint32_t(pdb_get_pass_last_set_time(sam_pwent)));
	} else {
		uid = nametouid(pdb_get_username(sam_pwent));
		printf ("%s:%lu:%s\n", pdb_get_username(sam_pwent), (unsigned long)uid,
			pdb_get_fullname(sam_pwent));
	}

	return 0;
}
Beispiel #28
0
NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
{
	NTSTATUS status = NT_STATUS_OK;
	NET_USER_INFO_3 *usr_info = NULL;
	NET_ID_INFO_CTR *ctr = q_u->sam_id.ctr;
	DOM_CRED srv_cred;
	UNISTR2 *uni_samlogon_user = NULL;
	UNISTR2 *uni_samlogon_domain = NULL;
	UNISTR2 *uni_samlogon_workstation = NULL;
	fstring nt_username, nt_domain, nt_workstation;
	auth_usersupplied_info *user_info = NULL;
	auth_serversupplied_info *server_info = NULL;
	extern userdom_struct current_user_info;
	SAM_ACCOUNT *sampw;
	struct auth_context *auth_context = NULL;
	        
	usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
	if (!usr_info)
		return NT_STATUS_NO_MEMORY;

	ZERO_STRUCTP(usr_info);

 	/* store the user information, if there is any. */
	r_u->user = usr_info;
	r_u->switch_value = 0; /* indicates no info */
	r_u->auth_resp = 1; /* authoritative response */
	r_u->switch_value = 3; /* indicates type of validation user info */
 
	if (!get_valid_user_struct(p->vuid))
		return NT_STATUS_NO_SUCH_USER;


	if ( (lp_server_schannel() == True) && (!p->netsec_auth_validated) ) {
		/* 'server schannel = yes' should enforce use of
		   schannel, the client did offer it in auth2, but
		   obviously did not use it. */
		return NT_STATUS_ACCESS_DENIED;
	}

	/* checks and updates credentials.  creates reply credentials */
	if (!(p->dc.authenticated && deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred)))
		return NT_STATUS_INVALID_HANDLE;

	memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
    
	r_u->buffer_creds = 1; /* yes, we have valid server credentials */
	memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));

	/* find the username */
    
	switch (q_u->sam_id.logon_level) {
	case INTERACTIVE_LOGON_TYPE:
		uni_samlogon_user = &ctr->auth.id1.uni_user_name;
 		uni_samlogon_domain = &ctr->auth.id1.uni_domain_name;

                uni_samlogon_workstation = &ctr->auth.id1.uni_wksta_name;
            
		DEBUG(3,("SAM Logon (Interactive). Domain:[%s].  ", lp_workgroup()));
		break;
	case NET_LOGON_TYPE:
		uni_samlogon_user = &ctr->auth.id2.uni_user_name;
		uni_samlogon_domain = &ctr->auth.id2.uni_domain_name;
		uni_samlogon_workstation = &ctr->auth.id2.uni_wksta_name;
            
		DEBUG(3,("SAM Logon (Network). Domain:[%s].  ", lp_workgroup()));
		break;
	default:
		DEBUG(2,("SAM Logon: unsupported switch value\n"));
		return NT_STATUS_INVALID_INFO_CLASS;
	} /* end switch */

	rpcstr_pull(nt_username,uni_samlogon_user->buffer,sizeof(nt_username),uni_samlogon_user->uni_str_len*2,0);
	rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0);
	rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0);

	DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, 
                 nt_workstation, nt_domain));
   	
	fstrcpy(current_user_info.smb_name, nt_username);
	sub_set_smb_name(nt_username);
     
	DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", q_u->sam_id.ctr->switch_value, nt_username));

	status = NT_STATUS_OK;
	
	switch (ctr->switch_value) {
	case NET_LOGON_TYPE:
	{
		const char *wksname = nt_workstation;
		
		if (!NT_STATUS_IS_OK(status = make_auth_context_fixed(&auth_context, ctr->auth.id2.lm_chal))) {
			return status;
		}

		/* For a network logon, the workstation name comes in with two
		 * backslashes in the front. Strip them if they are there. */

		if (*wksname == '\\') wksname++;
		if (*wksname == '\\') wksname++;

		/* Standard challenge/response authenticaion */
		if (!make_user_info_netlogon_network(&user_info, 
						     nt_username, nt_domain, 
						     wksname,
						     ctr->auth.id2.lm_chal_resp.buffer,
						     ctr->auth.id2.lm_chal_resp.str_str_len,
						     ctr->auth.id2.nt_chal_resp.buffer,
						     ctr->auth.id2.nt_chal_resp.str_str_len)) {
			status = NT_STATUS_NO_MEMORY;
		}	
		break;
	}
	case INTERACTIVE_LOGON_TYPE:
		/* 'Interactive' autheticaion, supplies the password in its
		   MD4 form, encrypted with the session key.  We will
		   convert this to chellange/responce for the auth
		   subsystem to chew on */
	{
		const uint8 *chal;
		
		if (!NT_STATUS_IS_OK(status = make_auth_context_subsystem(&auth_context))) {
			return status;
		}
		
		chal = auth_context->get_ntlm_challenge(auth_context);

		if (!make_user_info_netlogon_interactive(&user_info, 
							 nt_username, nt_domain, 
							 nt_workstation, chal,
							 ctr->auth.id1.lm_owf.data, 
							 ctr->auth.id1.nt_owf.data, 
							 p->dc.sess_key)) {
			status = NT_STATUS_NO_MEMORY;
		}
		break;
	}
	default:
		DEBUG(2,("SAM Logon: unsupported switch value\n"));
		return NT_STATUS_INVALID_INFO_CLASS;
	} /* end switch */
	
	if ( NT_STATUS_IS_OK(status) ) {
		status = auth_context->check_ntlm_password(auth_context, 
			user_info, &server_info);
	}

	(auth_context->free)(&auth_context);	
	free_user_info(&user_info);
	
	DEBUG(5, ("_net_sam_logon: check_password returned status %s\n", 
		  nt_errstr(status)));

	/* Check account and password */
    
	if (!NT_STATUS_IS_OK(status)) {
		free_server_info(&server_info);
		return status;
	}

	if (server_info->guest) {
		/* We don't like guest domain logons... */
		DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST denied.\n"));
		free_server_info(&server_info);
		return NT_STATUS_LOGON_FAILURE;
	}

	/* This is the point at which, if the login was successful, that
           the SAM Local Security Authority should record that the user is
           logged in to the domain.  */
    
	{
		DOM_GID *gids = NULL;
		const DOM_SID *user_sid = NULL;
		const DOM_SID *group_sid = NULL;
		DOM_SID domain_sid;
		uint32 user_rid, group_rid; 

		int num_gids = 0;
		pstring my_name;
		fstring user_sid_string;
		fstring group_sid_string;
		uchar user_session_key[16];
		uchar lm_session_key[16];
		uchar netlogon_sess_key[16];

		sampw = server_info->sam_account;

		/* set up pointer indicating user/password failed to be found */
		usr_info->ptr_user_info = 0;

		user_sid = pdb_get_user_sid(sampw);
		group_sid = pdb_get_group_sid(sampw);

		sid_copy(&domain_sid, user_sid);
		sid_split_rid(&domain_sid, &user_rid);

		if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) {
			DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid %s\n but group sid %s.\nThe conflicting domain portions are not supported for NETLOGON calls\n", 	    
				  pdb_get_domain(sampw), pdb_get_username(sampw),
				  sid_to_string(user_sid_string, user_sid),
				  sid_to_string(group_sid_string, group_sid)));
			return NT_STATUS_UNSUCCESSFUL;
		}
		
		pstrcpy(my_name, global_myname());

		if (!NT_STATUS_IS_OK(status 
				     = nt_token_to_group_list(p->mem_ctx, 
							      &domain_sid, 
							      server_info->ptok, 
							      &num_gids, 
							      &gids))) {
			return status;
		}

		ZERO_STRUCT(netlogon_sess_key);
		memcpy(netlogon_sess_key, p->dc.sess_key, 8);
		if (server_info->user_session_key.length) {
			memcpy(user_session_key, server_info->user_session_key.data, 
			       MIN(sizeof(user_session_key), server_info->user_session_key.length));
			SamOEMhash(user_session_key, netlogon_sess_key, 16);
		}
		if (server_info->lm_session_key.length) {
			memcpy(lm_session_key, server_info->lm_session_key.data, 
			       MIN(sizeof(lm_session_key), server_info->lm_session_key.length));
			SamOEMhash(lm_session_key, netlogon_sess_key, 16);
		}
		ZERO_STRUCT(netlogon_sess_key);
		
		init_net_user_info3(p->mem_ctx, usr_info, 
				    user_rid,
				    group_rid,   
				    pdb_get_username(sampw),
				    pdb_get_fullname(sampw),
				    pdb_get_homedir(sampw),
				    pdb_get_dir_drive(sampw),
				    pdb_get_logon_script(sampw),
				    pdb_get_profile_path(sampw),
				    pdb_get_logon_time(sampw),
				    get_time_t_max(),
				    get_time_t_max(),
				    pdb_get_pass_last_set_time(sampw),
				    pdb_get_pass_can_change_time(sampw),
				    pdb_get_pass_must_change_time(sampw),
				    
				    0, /* logon_count */
				    0, /* bad_pw_count */
				    num_gids,    /* uint32 num_groups */
				    gids    , /* DOM_GID *gids */
				    0x20    , /* uint32 user_flgs (?) */
				    server_info->user_session_key.length ? user_session_key : NULL,
				    server_info->lm_session_key.length ? lm_session_key : NULL,
				    my_name     , /* char *logon_srv */
				    pdb_get_domain(sampw),
				    &domain_sid,     /* DOM_SID *dom_sid */  
				    /* Should be users domain sid, not servers - for trusted domains */
				  
				    NULL); /* char *other_sids */
		ZERO_STRUCT(user_session_key);
		ZERO_STRUCT(lm_session_key);
	}
	free_server_info(&server_info);
	return status;
}
Beispiel #29
0
NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
			  struct samu *samu,
			  const char *login_server,
			  struct netr_SamInfo3 **_info3,
			  struct extra_auth_info *extra)
{
	struct netr_SamInfo3 *info3;
	const struct dom_sid *user_sid;
	const struct dom_sid *group_sid;
	struct dom_sid domain_sid;
	struct dom_sid *group_sids;
	uint32_t num_group_sids = 0;
	const char *tmp;
	gid_t *gids;
	NTSTATUS status;
	bool ok;

	user_sid = pdb_get_user_sid(samu);
	group_sid = pdb_get_group_sid(samu);

	if (!user_sid || !group_sid) {
		DEBUG(1, ("Sam account is missing sids!\n"));
		return NT_STATUS_UNSUCCESSFUL;
	}

	info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
	if (!info3) {
		return NT_STATUS_NO_MEMORY;
	}

	ZERO_STRUCT(domain_sid);

	/* check if this is a "Unix Users" domain user,
	 * we need to handle it in a special way if that's the case */
	if (sid_check_is_in_unix_users(user_sid)) {
		/* in info3 you can only set rids for the user and the
		 * primary group, and the domain sid must be that of
		 * the sam domain.
		 *
		 * Store a completely bogus value here.
		 * The real SID is stored in the extra sids.
		 * Other code will know to look there if (-1) is found
		 */
		info3->base.rid = (uint32_t)(-1);
		sid_copy(&extra->user_sid, user_sid);

		DEBUG(10, ("Unix User found in struct samu. Rid marked as "
			   "special and sid (%s) saved as extra sid\n",
			   sid_string_dbg(user_sid)));
	} else {
		sid_copy(&domain_sid, user_sid);
		sid_split_rid(&domain_sid, &info3->base.rid);
	}

	if (is_null_sid(&domain_sid)) {
		sid_copy(&domain_sid, get_global_sam_sid());
	}

	/* check if this is a "Unix Groups" domain group,
	 * if so we need special handling */
	if (sid_check_is_in_unix_groups(group_sid)) {
		/* in info3 you can only set rids for the user and the
		 * primary group, and the domain sid must be that of
		 * the sam domain.
		 *
		 * Store a completely bogus value here.
		 * The real SID is stored in the extra sids.
		 * Other code will know to look there if (-1) is found
		 */
		info3->base.primary_gid = (uint32_t)(-1);
		sid_copy(&extra->pgid_sid, group_sid);

		DEBUG(10, ("Unix Group found in struct samu. Rid marked as "
			   "special and sid (%s) saved as extra sid\n",
			   sid_string_dbg(group_sid)));

	} else {
		ok = sid_peek_check_rid(&domain_sid, group_sid,
					&info3->base.primary_gid);
		if (!ok) {
			DEBUG(1, ("The primary group domain sid(%s) does not "
				  "match the domain sid(%s) for %s(%s)\n",
				  sid_string_dbg(group_sid),
				  sid_string_dbg(&domain_sid),
				  pdb_get_username(samu),
				  sid_string_dbg(user_sid)));
			TALLOC_FREE(info3);
			return NT_STATUS_UNSUCCESSFUL;
		}
	}

	unix_to_nt_time(&info3->base.last_logon, pdb_get_logon_time(samu));
	unix_to_nt_time(&info3->base.last_logoff, get_time_t_max());
	unix_to_nt_time(&info3->base.acct_expiry, get_time_t_max());
	unix_to_nt_time(&info3->base.last_password_change,
			pdb_get_pass_last_set_time(samu));
	unix_to_nt_time(&info3->base.allow_password_change,
			pdb_get_pass_can_change_time(samu));
	unix_to_nt_time(&info3->base.force_password_change,
			pdb_get_pass_must_change_time(samu));

	tmp = pdb_get_username(samu);
	if (tmp) {
		info3->base.account_name.string	= talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.account_name.string);
	}
	tmp = pdb_get_fullname(samu);
	if (tmp) {
		info3->base.full_name.string = talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.full_name.string);
	}
	tmp = pdb_get_logon_script(samu);
	if (tmp) {
		info3->base.logon_script.string = talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.logon_script.string);
	}
	tmp = pdb_get_profile_path(samu);
	if (tmp) {
		info3->base.profile_path.string	= talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.profile_path.string);
	}
	tmp = pdb_get_homedir(samu);
	if (tmp) {
		info3->base.home_directory.string = talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.home_directory.string);
	}
	tmp = pdb_get_dir_drive(samu);
	if (tmp) {
		info3->base.home_drive.string = talloc_strdup(info3, tmp);
		RET_NOMEM(info3->base.home_drive.string);
	}

	info3->base.logon_count	= pdb_get_logon_count(samu);
	info3->base.bad_password_count = pdb_get_bad_password_count(samu);

	info3->base.domain.string = talloc_strdup(info3,
						  pdb_get_domain(samu));
	RET_NOMEM(info3->base.domain.string);

	info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
	RET_NOMEM(info3->base.domain_sid);

	status = pdb_enum_group_memberships(mem_ctx, samu,
					    &group_sids, &gids,
					    &num_group_sids);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to get groups from sam account.\n"));
		TALLOC_FREE(info3);
		return status;
	}

	if (num_group_sids) {
		status = group_sids_to_info3(info3, group_sids, num_group_sids);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(info3);
			return status;
		}
	}

	/* We don't need sids and gids after the conversion */
	TALLOC_FREE(group_sids);
	TALLOC_FREE(gids);
	num_group_sids = 0;

	/* FIXME: should we add other flags ? */
	info3->base.user_flags = NETLOGON_EXTRA_SIDS;

	if (login_server) {
		info3->base.logon_server.string = talloc_strdup(info3, login_server);
		RET_NOMEM(info3->base.logon_server.string);
	}

	info3->base.acct_flags = pdb_get_acct_ctrl(samu);

	*_info3 = info3;
	return NT_STATUS_OK;
}
Beispiel #30
0
static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx,
			       struct samu *sampass, 
			       const auth_usersupplied_info *user_info)
{
	uint32	acct_ctrl = pdb_get_acct_ctrl(sampass);
	char *workstation_list;
	time_t kickoff_time;
	
	DEBUG(4,("sam_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));

	/* Quit if the account was disabled. */
	if (acct_ctrl & ACB_DISABLED) {
		DEBUG(1,("sam_account_ok: Account for user '%s' was disabled.\n", pdb_get_username(sampass)));
		return NT_STATUS_ACCOUNT_DISABLED;
	}

	/* Quit if the account was locked out. */
	if (acct_ctrl & ACB_AUTOLOCK) {
		DEBUG(1,("sam_account_ok: Account for user %s was locked out.\n", pdb_get_username(sampass)));
		return NT_STATUS_ACCOUNT_LOCKED_OUT;
	}

	/* Quit if the account is not allowed to logon at this time. */
	if (! logon_hours_ok(sampass)) {
		return NT_STATUS_INVALID_LOGON_HOURS;
	}

	/* Test account expire time */
	
	kickoff_time = pdb_get_kickoff_time(sampass);
	if (kickoff_time != 0 && time(NULL) > kickoff_time) {
		DEBUG(1,("sam_account_ok: Account for user '%s' has expired.\n", pdb_get_username(sampass)));
		DEBUG(3,("sam_account_ok: Account expired at '%ld' unix time.\n", (long)kickoff_time));
		return NT_STATUS_ACCOUNT_EXPIRED;
	}

	if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP) && !(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) {
		time_t must_change_time = pdb_get_pass_must_change_time(sampass);
		time_t last_set_time = pdb_get_pass_last_set_time(sampass);

		/* check for immediate expiry "must change at next logon" 
		 * for a user account. */
		if (((acct_ctrl & (ACB_WSTRUST|ACB_SVRTRUST)) == 0) && (last_set_time == 0)) {
			DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
			return NT_STATUS_PASSWORD_MUST_CHANGE;
		}

		/* check for expired password */
		if (must_change_time < time(NULL) && must_change_time != 0) {
			DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
			DEBUG(1,("sam_account_ok: Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time));
			return NT_STATUS_PASSWORD_EXPIRED;
		}
	}

	/* Test workstation. Workstation list is comma separated. */

	workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
	if (!workstation_list)
		return NT_STATUS_NO_MEMORY;

	if (*workstation_list) {
		BOOL invalid_ws = True;
		fstring tok;
		const char *s = workstation_list;

		const char *machine_name = talloc_asprintf(mem_ctx, "%s$", user_info->wksta_name);
		if (machine_name == NULL)
			return NT_STATUS_NO_MEMORY;
			
			
		while (next_token(&s, tok, ",", sizeof(tok))) {
			DEBUG(10,("sam_account_ok: checking for workstation match %s and %s\n",
				  tok, user_info->wksta_name));
			if(strequal(tok, user_info->wksta_name)) {
				invalid_ws = False;
				break;
			}
			if (tok[0] == '+') {
				DEBUG(10,("sam_account_ok: checking for workstation %s in group: %s\n", 
					machine_name, tok + 1));
				if (user_in_group(machine_name, tok + 1)) {
					invalid_ws = False;
					break;
				}
			}
		}
		
		if (invalid_ws) 
			return NT_STATUS_INVALID_WORKSTATION;
	}

	if (acct_ctrl & ACB_DOMTRUST) {
		DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", pdb_get_username(sampass)));
		return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
	}
	
	if (acct_ctrl & ACB_SVRTRUST) {
		if (!(user_info->logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
			DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", pdb_get_username(sampass)));
			return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
		}
	}

	if (acct_ctrl & ACB_WSTRUST) {
		if (!(user_info->logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
			DEBUG(2,("sam_account_ok: Wksta trust account %s denied by server\n", pdb_get_username(sampass)));
			return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
		}
	}
	return NT_STATUS_OK;
}