Пример #1
0
/* Group and User RID username mapping function */
BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid)
{
    struct passwd *pw = Get_Pwnam(user_name, False);

	if (u_rid == NULL || g_rid == NULL || user_name == NULL)
	{
		return False;
	}

    if (!pw)
	{
      DEBUG(1,("Username %s is invalid on this system\n", user_name));
      return False;
    }

	if (user_in_list(user_name, lp_domain_guest_users()))
	{
		*u_rid = DOMAIN_USER_RID_GUEST;
	}
	else if (user_in_list(user_name, lp_domain_admin_users()))
	{
		*u_rid = DOMAIN_USER_RID_ADMIN;
	}
	else
	{
		/* turn the unix UID into a Domain RID.  this is what the posix
		   sub-system does (adds 1000 to the uid) */
		*u_rid = (uint32)(pw->pw_uid + 1000);
	}

	/* absolutely no idea what to do about the unix GID to Domain RID mapping */
	*g_rid = (uint32)(pw->pw_gid + 1000);

	return True;
}
Пример #2
0
static bool user_ok(const char *user, int snum)
{
	char **valid, **invalid;
	bool ret;

	valid = invalid = NULL;
	ret = True;

	if (lp_invalid_users(snum)) {
		invalid = str_list_copy(talloc_tos(), lp_invalid_users(snum));
		if (invalid &&
		    str_list_substitute(invalid, "%S", lp_servicename(snum))) {

			/* This is used in sec=share only, so no current user
			 * around to pass to str_list_sub_basic() */

			if ( invalid && str_list_sub_basic(invalid, "", "") ) {
				ret = !user_in_list(user,
						    (const char **)invalid);
			}
		}
	}
	TALLOC_FREE(invalid);

	if (ret && lp_valid_users(snum)) {
		valid = str_list_copy(talloc_tos(), lp_valid_users(snum));
		if ( valid &&
		     str_list_substitute(valid, "%S", lp_servicename(snum)) ) {

			/* This is used in sec=share only, so no current user
			 * around to pass to str_list_sub_basic() */

			if ( valid && str_list_sub_basic(valid, "", "") ) {
				ret = user_in_list(user, (const char **)valid);
			}
		}
	}
	TALLOC_FREE(valid);

	if (ret && lp_onlyuser(snum)) {
		char **user_list = str_list_make_v3(
			talloc_tos(), lp_username(snum), NULL);
		if (user_list &&
		    str_list_substitute(user_list, "%S",
					lp_servicename(snum))) {
			ret = user_in_list(user, (const char **)user_list);
		}
		TALLOC_FREE(user_list);
	}

	return(ret);
}
Пример #3
0
static BOOL user_ok(const char *user, int snum)
{
	char **valid, **invalid;
	BOOL ret;

	valid = invalid = NULL;
	ret = True;

	if (lp_invalid_users(snum)) {
		str_list_copy(&invalid, lp_invalid_users(snum));
		if (invalid &&
		    str_list_substitute(invalid, "%S", lp_servicename(snum))) {
			if ( invalid &&
			     str_list_sub_basic(invalid,
						current_user_info.smb_name) ) {
				ret = !user_in_list(user,
						    (const char **)invalid);
			}
		}
	}
	if (invalid)
		str_list_free (&invalid);

	if (ret && lp_valid_users(snum)) {
		str_list_copy(&valid, lp_valid_users(snum));
		if ( valid &&
		     str_list_substitute(valid, "%S", lp_servicename(snum)) ) {
			if ( valid &&
			     str_list_sub_basic(valid,
						current_user_info.smb_name) ) {
				ret = user_in_list(user, (const char **)valid);
			}
		}
	}
	if (valid)
		str_list_free (&valid);

	if (ret && lp_onlyuser(snum)) {
		char **user_list = str_list_make (lp_username(snum), NULL);
		if (user_list &&
		    str_list_substitute(user_list, "%S",
					lp_servicename(snum))) {
			ret = user_in_list(user, (const char **)user_list);
		}
		if (user_list) str_list_free (&user_list);
	}

	return(ret);
}
Пример #4
0
static BOOL is_share_read_only_for_user(connection_struct *conn, user_struct *vuser)
{
	char **list;
	const char *service = lp_servicename(conn->service);
	BOOL read_only_ret = lp_readonly(conn->service);

	if (!service)
		return read_only_ret;

	str_list_copy(&list, lp_readlist(conn->service));
	if (list) {
		if (!str_list_sub_basic(list, vuser->user.smb_name) ) {
			DEBUG(0, ("is_share_read_only_for_user: ERROR: read list substitution failed\n"));
		}
		if (!str_list_substitute(list, "%S", service)) {
			DEBUG(0, ("is_share_read_only_for_user: ERROR: read list service substitution failed\n"));
		}
		if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) {
			read_only_ret = True;
		}
		str_list_free(&list);
	}

	str_list_copy(&list, lp_writelist(conn->service));
	if (list) {
		if (!str_list_sub_basic(list, vuser->user.smb_name) ) {
			DEBUG(0, ("is_share_read_only_for_user: ERROR: write list substitution failed\n"));
		}
		if (!str_list_substitute(list, "%S", service)) {
			DEBUG(0, ("is_share_read_only_for_user: ERROR: write list service substitution failed\n"));
		}
		if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) {
			read_only_ret = False;
		}
		str_list_free(&list);
	}

	DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user %s\n",
		service, read_only_ret ? "read-only" : "read-write", vuser->user.unix_name ));

	return read_only_ret;
}
Пример #5
0
static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
{
	unsigned int i;
	struct vuid_cache_entry *ent = NULL;
	BOOL readonly_share;

	for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
		if (conn->vuid_cache.array[i].vuid == vuser->vuid) {
			ent = &conn->vuid_cache.array[i];
			conn->read_only = ent->read_only;
			conn->admin_user = ent->admin_user;
			return(True);
		}
	}

	if (!user_ok(vuser->user.unix_name,snum, vuser->groups, vuser->n_groups))
		return(False);

	readonly_share = is_share_read_only_for_user(conn, vuser);

	if (!readonly_share &&
	    !share_access_check(conn, snum, vuser, FILE_WRITE_DATA)) {
		/* smb.conf allows r/w, but the security descriptor denies
		 * write. Fall back to looking at readonly. */
		readonly_share = True;
	}

	if (!share_access_check(conn, snum, vuser, readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) {
		return False;
	}

	i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
	if (conn->vuid_cache.entries < VUID_CACHE_SIZE)
		conn->vuid_cache.entries++;

	ent = &conn->vuid_cache.array[i];
	ent->vuid = vuser->vuid;
	ent->read_only = readonly_share;

	if (user_in_list(vuser->user.unix_name ,lp_admin_users(conn->service), vuser->groups, vuser->n_groups)) {
		ent->admin_user = True;
	} else {
		ent->admin_user = False;
	}

	conn->read_only = ent->read_only;
	conn->admin_user = ent->admin_user;

	return(True);
}
Пример #6
0
/****************************************************************************
check if a username is valid
****************************************************************************/
BOOL user_ok(char *user,int snum)
{
  pstring valid, invalid;
  BOOL ret;

  StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
  StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));

  string_sub(valid,"%S",lp_servicename(snum));
  string_sub(invalid,"%S",lp_servicename(snum));

  ret = !user_in_list(user,invalid);

  if (ret && valid && *valid)
    ret = user_in_list(user,valid);

  if (ret && lp_onlyuser(snum)) {
    char *user_list = lp_username(snum);
    string_sub(user_list,"%S",lp_servicename(snum));
    ret = user_in_list(user,user_list);
  }

  return(ret);
}
Пример #7
0
BOOL map_username(char *user)
{
  static BOOL initialised=False;
  static fstring last_from,last_to;
  FILE *f;
  char *mapfile = lp_username_map();
  char *s;
  pstring buf;
  BOOL mapped_user = False;

  if (!*user)
    return False;

  if (!*mapfile)
    return False;

  if (!initialised) {
    *last_from = *last_to = 0;
    initialised = True;
  }

  if (strequal(user,last_to))
    return False;

  if (strequal(user,last_from)) {
    DEBUG(3,("Mapped user %s to %s\n",user,last_to));
    fstrcpy(user,last_to);
    return True;
  }
  
  f = sys_fopen(mapfile,"r");
  if (!f) {
    DEBUG(0,("can't open username map %s\n",mapfile));
    return False;
  }

  DEBUG(4,("Scanning username map %s\n",mapfile));

  while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
    char *unixname = s;
    char *dosname = strchr(unixname,'=');
    BOOL return_if_mapped = False;

    if (!dosname)
      continue;

    *dosname++ = 0;

    while (isspace(*unixname))
      unixname++;
    if ('!' == *unixname) {
      return_if_mapped = True;
      unixname++;
      while (*unixname && isspace(*unixname))
        unixname++;
    }
    
    if (!*unixname || strchr("#;",*unixname))
      continue;

    {
      int l = strlen(unixname);
      while (l && isspace(unixname[l-1])) {
        unixname[l-1] = 0;
        l--;
      }
    }

    if (strchr(dosname,'*') || user_in_list(user,dosname)) {
      DEBUG(3,("Mapped user %s to %s\n",user,unixname));
      mapped_user = True;
      fstrcpy(last_from,user);
      sscanf(unixname,"%s",user);
      fstrcpy(last_to,user);
      if(return_if_mapped) { 
        fclose(f);
        return True;
      }
    }
  }

  fclose(f);

  /*
   * Setup the last_from and last_to as an optimization so 
   * that we don't scan the file again for the same user.
   */
  fstrcpy(last_from,user);
  fstrcpy(last_to,user);

  return mapped_user;
}
Пример #8
0
/****************************************************************************
  make a connection to a service
****************************************************************************/
connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode)
{
	int snum;
	struct passwd *pass = NULL;
	BOOL guest = False;
	BOOL force = False;
	extern int Client;
	connection_struct *conn;
	int ret;

	strlower(service);

	snum = find_service(service);
	if (snum < 0) {
		extern int Client;
		if (strequal(service,"IPC$")) {
			DEBUG(3,("refusing IPC connection\n"));
			*ecode = ERRnoipc;
			return NULL;
		}

		DEBUG(0,("%s (%s) couldn't find service %s\n",
			 remote_machine, client_addr(Client), service));
		*ecode = ERRinvnetname;
		return NULL;
	}

	if (strequal(service,HOMES_NAME)) {
		if (*user && Get_Pwnam(user,True)) {
			fstring dos_username;
			fstrcpy(dos_username, user);
			unix_to_dos(dos_username, True);
			return(make_connection(dos_username,user,password,
					       pwlen,dev,vuid,ecode));
		}

		if(lp_security() != SEC_SHARE) {
			if (validated_username(vuid)) {
				fstring dos_username;
				fstrcpy(user,validated_username(vuid));
				fstrcpy(dos_username, user);
				unix_to_dos(dos_username, True);
				return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
			}
		} else {
			/* Security = share. Try with sesssetup_user
			 * as the username.  */
			if(*sesssetup_user) {
				fstring dos_username;
				fstrcpy(user,sesssetup_user);
				fstrcpy(dos_username, user);
				unix_to_dos(dos_username, True);
				return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
			}
		}
	}

	if (!lp_snum_ok(snum) || 
	    !check_access(Client, 
			  lp_hostsallow(snum), lp_hostsdeny(snum))) {    
		*ecode = ERRaccess;
		return NULL;
	}

	/* you can only connect to the IPC$ service as an ipc device */
	if (strequal(service,"IPC$"))
		pstrcpy(dev,"IPC");
	
	if (*dev == '?' || !*dev) {
		if (lp_print_ok(snum)) {
			pstrcpy(dev,"LPT1:");
		} else {
			pstrcpy(dev,"A:");
		}
	}

	/* if the request is as a printer and you can't print then refuse */
	strupper(dev);
	if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
		DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
		*ecode = ERRinvdevice;
		return NULL;
	}

	/* lowercase the user name */
	strlower(user);

	/* add it as a possible user name */
	add_session_user(service);

	/* shall we let them in? */
	if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) {
		DEBUG( 2, ( "Invalid username/password for %s\n", service ) );
		*ecode = ERRbadpw;
		return NULL;
	}
  
	conn = conn_new();
	if (!conn) {
		DEBUG(0,("Couldn't find free connection.\n"));
		*ecode = ERRnoresource;
		conn_free(conn);
		return NULL;
	}

	/* find out some info about the user */
	pass = Get_Pwnam(user,True);

	if (pass == NULL) {
		DEBUG(0,( "Couldn't find account %s\n",user));
		*ecode = ERRbaduid;
		conn_free(conn);
		return NULL;
	}

	conn->read_only = lp_readonly(snum);

	{
		pstring list;
		StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
		pstring_sub(list,"%S",service);

		if (user_in_list(user,list))
			conn->read_only = True;
		
		StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
		pstring_sub(list,"%S",service);
		
		if (user_in_list(user,list))
			conn->read_only = False;    
	}

	/* admin user check */
	
	/* JRA - original code denied admin user if the share was
	   marked read_only. Changed as I don't think this is needed,
	   but old code left in case there is a problem here.
	*/
	if (user_in_list(user,lp_admin_users(snum)) 
#if 0
	    && !conn->read_only
#endif
	    ) {
		conn->admin_user = True;
		DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
	} else {
		conn->admin_user = False;
	}
    
	conn->force_user = force;
	conn->vuid = vuid;
	conn->uid = pass->pw_uid;
	conn->gid = pass->pw_gid;
	safe_strcpy(conn->client_address, client_addr(Client), sizeof(conn->client_address)-1);
	conn->num_files_open = 0;
	conn->lastused = time(NULL);
	conn->service = snum;
	conn->used = True;
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = (strncmp(dev,"IPC",3) == 0);
	conn->dirptr = NULL;
	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	string_set(&conn->dirpath,"");
	string_set(&conn->user,user);
	
	/*
	 * If force user is true, then store the
	 * given userid and also the primary groupid
	 * of the user we're forcing.
	 */
	
	if (*lp_force_user(snum)) {
		struct passwd *pass2;
		pstring fuser;
		pstrcpy(fuser,lp_force_user(snum));

		/* Allow %S to be used by force user. */
		pstring_sub(fuser,"%S",service);

		pass2 = (struct passwd *)Get_Pwnam(fuser,True);
		if (pass2) {
			conn->uid = pass2->pw_uid;
			conn->gid = pass2->pw_gid;
			string_set(&conn->user,fuser);
			fstrcpy(user,fuser);
			conn->force_user = True;
			DEBUG(3,("Forced user %s\n",fuser));	  
		} else {
			DEBUG(1,("Couldn't find user %s\n",fuser));
		}
	}

#ifdef HAVE_GETGRNAM 
	/*
	 * If force group is true, then override
	 * any groupid stored for the connecting user.
	 */
	
	if (*lp_force_group(snum)) {
		struct group *gptr;
		pstring gname;
		pstring tmp_gname;
		BOOL user_must_be_member = False;
		
		StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);

		if (tmp_gname[0] == '+') {
			user_must_be_member = True;
			StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
		} else {
			StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
		}
		/* default service may be a group name 		*/
		pstring_sub(gname,"%S",service);
		gptr = (struct group *)getgrnam(gname);
		
		if (gptr) {
			/*
			 * If the user has been forced and the forced group starts
			 * with a '+', then we only set the group to be the forced
			 * group if the forced user is a member of that group.
			 * Otherwise, the meaning of the '+' would be ignored.
			 */
			if (conn->force_user && user_must_be_member) {
				int i;
				for (i = 0; gptr->gr_mem[i] != NULL; i++) {
					if (strcmp(user,gptr->gr_mem[i]) == 0) {
						conn->gid = gptr->gr_gid;
						DEBUG(3,("Forced group %s for member %s\n",gname,user));
						break;
					}
				}
			} else {
				conn->gid = gptr->gr_gid;
				DEBUG(3,("Forced group %s\n",gname));
			}
		} else {
			DEBUG(1,("Couldn't find group %s\n",gname));
		}
	}
#endif /* HAVE_GETGRNAM */

	{
		pstring s;
		pstrcpy(s,lp_pathname(snum));
		standard_sub(conn,s);
		string_set(&conn->connectpath,s);
		DEBUG(3,("Connect path is %s\n",s));
	}

	/* groups stuff added by ih */
	conn->ngroups = 0;
	conn->groups = NULL;
	
	if (!IS_IPC(conn)) {
		/* Find all the groups this uid is in and
		   store them. Used by become_user() */
		setup_groups(conn->user,conn->uid,conn->gid,
			     &conn->ngroups,&conn->groups);
		
		/* check number of connections */
		if (!claim_connection(conn,
				      lp_servicename(SNUM(conn)),
				      lp_max_connections(SNUM(conn)),
				      False)) {
			DEBUG(1,("too many connections - rejected\n"));
			*ecode = ERRnoresource;
			conn_free(conn);
			return NULL;
		}  
		
		if (lp_status(SNUM(conn)))
			claim_connection(conn,"STATUS.",
					 MAXSTATUS,False);
	} /* IS_IPC */
	
	/* execute any "root preexec = " line */
	if (*lp_rootpreexec(SNUM(conn))) {
		pstring cmd;
		pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
		standard_sub(conn,cmd);
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL,False);
		if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
			DEBUG(1,("preexec gave %d - failing connection\n", ret));
			conn_free(conn);
			*ecode = ERRsrverror;
			return NULL;
		}
	}
	
	if (!become_user(conn, conn->vuid)) {
		DEBUG(0,("Can't become connected user!\n"));
		if (!IS_IPC(conn)) {
			yield_connection(conn,
					 lp_servicename(SNUM(conn)),
					 lp_max_connections(SNUM(conn)));
			if (lp_status(SNUM(conn))) {
				yield_connection(conn,"STATUS.",MAXSTATUS);
			}
		}
		conn_free(conn);
		*ecode = ERRbadpw;
		return NULL;
	}
	
	if (dos_ChDir(conn->connectpath) != 0) {
		DEBUG(0,("Can't change directory to %s (%s)\n",
			 conn->connectpath,strerror(errno)));
		unbecome_user();
		if (!IS_IPC(conn)) {
			yield_connection(conn,
					 lp_servicename(SNUM(conn)),
					 lp_max_connections(SNUM(conn)));
			if (lp_status(SNUM(conn))) 
				yield_connection(conn,"STATUS.",MAXSTATUS);
		}
		conn_free(conn);
		*ecode = ERRinvnetname;
		return NULL;
	}
	
	string_set(&conn->origpath,conn->connectpath);
	
#if SOFTLINK_OPTIMISATION
	/* resolve any soft links early */
	{
		pstring s;
		pstrcpy(s,conn->connectpath);
		dos_GetWd(s);
		string_set(&conn->connectpath,s);
		dos_ChDir(conn->connectpath);
	}
#endif
	
	add_session_user(user);
		
	/* execute any "preexec = " line */
	if (*lp_preexec(SNUM(conn))) {
		pstring cmd;
		pstrcpy(cmd,lp_preexec(SNUM(conn)));
		standard_sub(conn,cmd);
		ret = smbrun(cmd,NULL,False);
		if (ret != 0 && lp_preexec_close(SNUM(conn))) {
			DEBUG(1,("preexec gave %d - failing connection\n", ret));
			conn_free(conn);
			*ecode = ERRsrverror;
			return NULL;
		}
	}

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using.
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
		dbgtext( "%s (%s) ", remote_machine, conn->client_address );
		dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
		dbgtext( "as user %s ", user );
		dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
		dbgtext( "(pid %d)\n", (int)getpid() );
	}
	
	/* we've finished with the sensitive stuff */
	unbecome_user();
	
	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
		set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
		set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
	}
	
	return(conn);
}
Пример #9
0
bool map_username(TALLOC_CTX *ctx, const char *user_in, char **p_user_out)
{
	XFILE *f;
	char *mapfile = lp_username_map(talloc_tos());
	char *s;
	char buf[512];
	bool mapped_user = False;
	char *cmd = lp_username_map_script(talloc_tos());

	*p_user_out = NULL;

	if (!user_in)
		return false;

	/* Initially make a copy of the incoming name. */
	*p_user_out = talloc_strdup(ctx, user_in);
	if (!*p_user_out) {
		return false;
	}

	if (strequal(user_in,get_last_to()))
		return false;

	if (strequal(user_in,get_last_from())) {
		DEBUG(3,("Mapped user %s to %s\n",user_in,get_last_to()));
		TALLOC_FREE(*p_user_out);
		*p_user_out = talloc_strdup(ctx, get_last_to());
		return true;
	}

	if (fetch_map_from_gencache(ctx, user_in, p_user_out)) {
		return true;
	}

	/* first try the username map script */

	if ( *cmd ) {
		char **qlines;
		char *command = NULL;
		int numlines, ret, fd;

		command = talloc_asprintf(ctx,
					"%s \"%s\"",
					cmd,
					user_in);
		if (!command) {
			return false;
		}

		DEBUG(10,("Running [%s]\n", command));
		ret = smbrun(command, &fd);
		DEBUGADD(10,("returned [%d]\n", ret));

		TALLOC_FREE(command);

		if ( ret != 0 ) {
			if (fd != -1)
				close(fd);
			return False;
		}

		numlines = 0;
		qlines = fd_lines_load(fd, &numlines, 0, ctx);
		DEBUGADD(10,("Lines returned = [%d]\n", numlines));
		close(fd);

		/* should be either no lines or a single line with the mapped username */

		if (numlines && qlines) {
			DEBUG(3,("Mapped user %s to %s\n", user_in, qlines[0] ));
			set_last_from_to(user_in, qlines[0]);
			store_map_in_gencache(ctx, user_in, qlines[0]);
			TALLOC_FREE(*p_user_out);
			*p_user_out = talloc_strdup(ctx, qlines[0]);
			if (!*p_user_out) {
				return false;
			}
		}

		TALLOC_FREE(qlines);

		return numlines != 0;
	}

	/* ok.  let's try the mapfile */
	if (!*mapfile)
		return False;

	f = x_fopen(mapfile,O_RDONLY, 0);
	if (!f) {
		DEBUG(0,("can't open username map %s. Error %s\n",mapfile, strerror(errno) ));
		return False;
	}

	DEBUG(4,("Scanning username map %s\n",mapfile));

	while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
		char *unixname = s;
		char *dosname = strchr_m(unixname,'=');
		char **dosuserlist;
		bool return_if_mapped = False;

		if (!dosname)
			continue;

		*dosname++ = 0;

		unixname = skip_space(unixname);

		if ('!' == *unixname) {
			return_if_mapped = True;
			unixname = skip_space(unixname+1);
		}

		if (!*unixname || strchr_m("#;",*unixname))
			continue;

		{
			int l = strlen(unixname);
			while (l && isspace((int)unixname[l-1])) {
				unixname[l-1] = 0;
				l--;
			}
		}

		/* skip lines like 'user = '******'*') ||
		    user_in_list(ctx, user_in, (const char **)dosuserlist)) {
			DEBUG(3,("Mapped user %s to %s\n",user_in,unixname));
			mapped_user = True;

			set_last_from_to(user_in, unixname);
			store_map_in_gencache(ctx, user_in, unixname);
			TALLOC_FREE(*p_user_out);
			*p_user_out = talloc_strdup(ctx, unixname);
			if (!*p_user_out) {
				TALLOC_FREE(dosuserlist);
				x_fclose(f);
				return false;
			}

			if ( return_if_mapped ) {
				TALLOC_FREE(dosuserlist);
				x_fclose(f);
				return True;
			}
		}

		TALLOC_FREE(dosuserlist);
	}

	x_fclose(f);

	/*
	 * If we didn't successfully map a user in the loop above,
	 * setup the last_from and last_to as an optimization so
	 * that we don't scan the file again for the same user.
	 */
	if (!mapped_user) {
		DEBUG(8, ("The user '%s' has no mapping. "
			  "Skip it next time.\n", user_in));
		set_last_from_to(user_in, user_in);
		store_map_in_gencache(ctx, user_in, user_in);
	}

	return mapped_user;
}