/********************************************************************/
/**         Microsoft LAN Manager              **/
/**       Copyright(c) Microsoft Corp., 1987-1990      **/
/********************************************************************/

/*  accounts.c - functions to display & modify the user modals
 *
 *  history:
 *  when    who what
 *  02/19/89 erichn initial code
 *  03/16/89 erichn uses local buf instead of BigBuf, misc cleaning
 *  06/08/89 erichn canonicalization sweep
 *  06/23/89 erichn auto-remoting to domain controller
 *  07/05/89 thomaspa /maxpwage:unlimited
 *  02/19/90 thomaspa fix /forcelogoff to check for overflow
 *  04/27/90 thomaspa fix /uniquepw to check for >DEF_MAX_PWHIST
 *            and /minpwlen >MAX_PASSWD_LEN
 *  01/28/91 robdu, added /lockout switch (includes setting and display)
 *  02/19/91 danhi, converted to 16/32 portability layer
 *  04/01/91 danhi, ifdef'ed out lockout feature
 */

#define INCL_NOCOMMON
#define INCL_DOSFILEMGR
#define INCL_ERRORS
#include <os2.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <netcons.h>
#include <wksta.h>
#include "netlib0.h"
#include <lui.h>
#include <neterr.h>
#include <access.h>
#include <apperr.h>
#include <apperr2.h>
#include "port1632.h"
#include "netcmds.h"
#include "nettext.h"

#define SECS_PER_DAY    ((ULONG) 3600 * 24)
#define SECS_PER_MIN    ((ULONG) 60 )
#define NOT_SET     (0xFFFF)
#define CALL_LEVEL_0    (0x0001)
#define CALL_LEVEL_1    (0x0002)
#define CALL_LEVEL_2    (0x0004)
#define CALL_LEVEL_3    (0x0008)
#define LOCKOUT_NEVER 0

/* local function prototype */

VOID CheckAndSetSwitches(struct user_modals_info_0 FAR *,
    			 struct user_modals_info_1 FAR *,
                         struct user_modals_info_3 FAR *,
			 USHORT *,
			 BOOL *);



/*
 *  accounts_change(): used to set the user modals when switches
 *  are detected on the command line.
 */
VOID accounts_change(VOID)
{
    USHORT       err;        /* API return status */
    USHORT       APIMask = 0;    /* maks for API that we call */
    TCHAR         controller[UNCLEN+1];   /* name of domain controller */
    BOOL         fPasswordAgeChanged ;   /* has the min/max ages been set? */

    struct user_modals_info_0 FAR * modals_0;
    char modals_0_buffer[sizeof(struct user_modals_info_0)];
    struct user_modals_info_1 FAR * modals_1;
    char modals_1_buffer[sizeof(struct user_modals_info_1) + CNLEN];
    struct user_modals_info_3 FAR * modals_3;
    char modals_3_buffer[sizeof(struct user_modals_info_3)];


    // since these are not used for anything on the first pass, make them
    // the same & pointing to some dummy buffer that is not used.
    modals_0 = (struct user_modals_info_0 FAR *)  modals_0_buffer ;
    modals_1 = (struct user_modals_info_1 FAR *)  modals_1_buffer ;
    modals_3 = (struct user_modals_info_3 FAR *)  modals_3_buffer ;

    /* check switches first before doing anything */
    CheckAndSetSwitches(modals_0, modals_1, modals_3, &APIMask, &fPasswordAgeChanged);

    /* if we need to call level 0, try to get DC name to remote to. */
    if (APIMask & (CALL_LEVEL_0 | CALL_LEVEL_3))
    {
        if (err = GetSAMLocation(controller, DIMENSION(controller),
                                 NULL, 0, TRUE))
            ErrorExit(err);
    }

    if ( APIMask & CALL_LEVEL_0 )
    {
        err = MNetUserModalsGet(controller, 0, (LPBYTE*)&modals_0);

        switch (err) {
            case NERR_Success:
                break;
            case ERROR_BAD_NETPATH:
                ErrorExitInsTxt(APE_DCNotFound, controller);
            default:
                ErrorExit(err);
        }
    }   /* APIMask & CALL_LEVEL_0 */

    if ( APIMask & CALL_LEVEL_3 )
    {
        err = MNetUserModalsGet(controller, 3, (LPBYTE*)&modals_3);

        switch (err) {
            case NERR_Success:
                break;
            case ERROR_BAD_NETPATH:
                ErrorExitInsTxt(APE_DCNotFound, controller);
            default:
                ErrorExit(err);
        }
    }   /* APIMask & CALL_LEVEL_3 */

    /* Now set switches before doing actual calls */
    CheckAndSetSwitches(modals_0, modals_1, modals_3, &APIMask, &fPasswordAgeChanged);

    /* call remote function first */
    if (APIMask & CALL_LEVEL_0)
    {
	/* check to make sure we dont set Min to be greater than Max */
        if (fPasswordAgeChanged &&
	    modals_0->usrmod0_max_passwd_age < modals_0->usrmod0_min_passwd_age)
        {
	    ErrorExit(APE_MinGreaterThanMaxAge) ;
        }

	/* call the API to do its thing */
        err = MNetUserModalsSet(controller, 0, (LPBYTE)modals_0,
		    sizeof(struct user_modals_info_0), MODAL0_PARMNUM_ALL);

        switch (err)
        {
            case NERR_Success:
                break;
            case ERROR_BAD_NETPATH:
                ErrorExitInsTxt(APE_DCNotFound, controller);
            default:
                ErrorExit(err);
        }
        NetApiBufferFree((TCHAR FAR *) modals_0);
    }

    if (APIMask & CALL_LEVEL_3)
    {
	/* call the API to do its thing */
        err = MNetUserModalsSet(controller, 3, (LPBYTE)modals_3,
		    sizeof(struct user_modals_info_3), 0);

        switch (err)
        {
            case NERR_Success:
                break;
            case ERROR_BAD_NETPATH:
                ErrorExitInsTxt(APE_DCNotFound, controller);
            default:
                ErrorExit(err);
        }
        NetApiBufferFree((TCHAR FAR *) modals_3);
    }


    InfoSuccess();
}

/*
 *  CheckAndSetSwitches - validates the contents of switches passed to
 *  NET ACCOUNTS, and sets the appropriate modal structure.  This function
 *  is called twice.  The first is to check the user input for mistakes,
 *  before we do any API calls that might fail (like NetGetDCName).  The
 *  second time is to actually set the structures from what was passed on
 *  the command line.  This function could arguably be two seperate functions,
 *  but it was thought that having all the switch handling code in one place
 *  would be more maintainable.  Also, keeping track of which switches were
 *  given, using flags or whatnot, would be ugly and require adding new
 *  flags with new switches.  So, we just call the thing twice.
 *
 *  When adding new switches, be careful not to break the loop flow
 *  (by adding continue statements, for example), as after each switch
 *  is processed, the colon that is replaced by a NULL in FindColon() is
 *  restored back to a colon for the next call.
 *
 *  Entry   modals_0 - pointer to a user_modals_0 struct.
 *      modals_1 - pointer to a user_modals_1 struct.
 *      modals_3 - pointer to a user_modals_3 struct.
 *
 *  Exit    modals_0 - appropriate fields are set according to switches
 *  modals_1 - appropriate fields are set according to switches
 *  modals_3 - appropriate fields are set according to switches
 *  APIMask - the appropriate bit is set to mark wether an API
 *      should be called.  Currently for modal levels 0 & 1.
 *
 *  Other   Exits on bad arguments in switches.
 */
VOID CheckAndSetSwitches(struct  user_modals_info_0 FAR * modals_0,
    			 struct  user_modals_info_1 FAR * modals_1,
    			 struct  user_modals_info_3 FAR * modals_3,
			 USHORT *APIMask,
			 BOOL   *pfPasswordAgeChanged)
{
    USHORT  i;      			   /* generic index loop */
    USHORT  err;    			   /* API return code */
    TCHAR *  ptr;    			   /* pointer to start of arg,
					      set by FindColon */
    static TCHAR nlsNo[20] = { 0 } ;	   /* buffer to hold NLS no string */

    /* set to FALSE initially */
    *pfPasswordAgeChanged = FALSE ;

    /* get NLS no string for comparison */
    if (nlsNo[0] == NULLC)   /* if not allocated yet */
    if (err = LUI_GetMsg(nlsNo, DIMENSION(nlsNo), APE2_GEN_NO))
        ErrorExit(err);

    /* for each switch in switchlist */
    for (i = 0; SwitchList[i]; i++)
    {
    /* Skip the DOMAIN switch */
    if (! _tcscmp(SwitchList[i], swtxt_SW_DOMAIN))
        continue;

    /* all switches currently require arguments, hence colons */
    if ((ptr = FindColon(SwitchList[i])) == NULL)
        ErrorExit(APE_InvalidSwitchArg);

    if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_FORCELOGOFF)))
    {
        (*APIMask) |= CALL_LEVEL_0;
        if (!stricmpf(ptr, nlsNo))
            modals_0->usrmod0_force_logoff = TIMEQ_FOREVER;
        else
        {
            modals_0->usrmod0_force_logoff = do_atoul(ptr,APE_CmdArgIllegal,
                        swtxt_SW_ACCOUNTS_FORCELOGOFF);
            if (modals_0->usrmod0_force_logoff > 0xffffffff / SECS_PER_MIN)
            {
                ErrorExitInsTxt(APE_CmdArgIllegal,
                        swtxt_SW_ACCOUNTS_FORCELOGOFF);
            }
            modals_0->usrmod0_force_logoff *= SECS_PER_MIN;
        }
    }
    else if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_UNIQUEPW)))
    {
        (*APIMask) |= CALL_LEVEL_0;
        modals_0->usrmod0_password_hist_len =
            do_atou(ptr,APE_CmdArgIllegal,swtxt_SW_ACCOUNTS_UNIQUEPW);
        if (modals_0->usrmod0_password_hist_len > 24) // also in User Manager
        {
            ErrorExitInsTxt(APE_CmdArgIllegal, swtxt_SW_ACCOUNTS_UNIQUEPW);
        }
    }
    else if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_MINPWLEN)))
    {
        (*APIMask) |= CALL_LEVEL_0;
        modals_0->usrmod0_min_passwd_len =
            do_atou(ptr,APE_CmdArgIllegal,swtxt_SW_ACCOUNTS_MINPWLEN);
        if (modals_0->usrmod0_min_passwd_len > MAX_PASSWD_LEN)
        {
            ErrorExitInsTxt(APE_CmdArgIllegal, swtxt_SW_ACCOUNTS_MINPWLEN);
        }
        if (modals_0->usrmod0_min_passwd_len > LM20_PWLEN)
        {
            ErrorExit(APE_NotUASCompatible) ;
        }
    }
    else if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_MINPWAGE)))
    {
        (*APIMask) |= CALL_LEVEL_0;
	*pfPasswordAgeChanged = TRUE ;
        modals_0->usrmod0_min_passwd_age =
            do_atoul(ptr,APE_CmdArgIllegal,swtxt_SW_ACCOUNTS_MINPWAGE);
        if (modals_0->usrmod0_min_passwd_age > 0xffffffff / SECS_PER_DAY)
        {
            ErrorExitInsTxt(APE_CmdArgIllegal, swtxt_SW_ACCOUNTS_MINPWAGE);
        }
        modals_0->usrmod0_min_passwd_age *= SECS_PER_DAY;
    }
    else if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_MAXPWAGE)))
    {
        (*APIMask) |= CALL_LEVEL_0;
	*pfPasswordAgeChanged = TRUE ;
        /* NOTE: we use the same global as "UNLIMITED" for the Net
           User /MAXSTORAGE:unlimited here.  If these diverge then
           a new global will need to be added to nettext.c and .h
         */
        if( !stricmpf( ptr, USER_MAXSTOR_UNLIMITED ) )
        {
            modals_0->usrmod0_max_passwd_age = 0xffffffff;
        }
        else
        {
            modals_0->usrmod0_max_passwd_age=
                do_atoul(ptr,APE_CmdArgIllegal,swtxt_SW_ACCOUNTS_MAXPWAGE);
            if (modals_0->usrmod0_max_passwd_age > 0xffffffff/SECS_PER_DAY)
            {
                ErrorExitInsTxt(APE_CmdArgIllegal,
                        swtxt_SW_ACCOUNTS_MAXPWAGE);
            }
            modals_0->usrmod0_max_passwd_age *= SECS_PER_DAY;
        }
    }
    else if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_LOCKOUT_DURATION)))
    {
        (*APIMask) |= CALL_LEVEL_3;
        if (!stricmpf(ptr, nlsNo))
            modals_3->usrmod3_lockout_duration = TIMEQ_FOREVER;
        else
        {
            modals_3->usrmod3_lockout_duration = do_atoul(ptr,APE_CmdArgIllegal,
                        swtxt_SW_ACCOUNTS_LOCKOUT_DURATION);
            if (modals_3->usrmod3_lockout_duration > 0xffffffff / SECS_PER_MIN)
            {
                ErrorExitInsTxt(APE_CmdArgIllegal,
                        swtxt_SW_ACCOUNTS_LOCKOUT_DURATION);
            }
            modals_3->usrmod3_lockout_duration *= SECS_PER_MIN;
        }
    }
    else if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_LOCKOUT_WINDOW)))
    {
        (*APIMask) |= CALL_LEVEL_3;
        if (!stricmpf(ptr, nlsNo))
            modals_3->usrmod3_lockout_observation_window = TIMEQ_FOREVER;
        else
        {
            modals_3->usrmod3_lockout_observation_window = do_atoul(ptr,APE_CmdArgIllegal,
                        swtxt_SW_ACCOUNTS_LOCKOUT_WINDOW);
            if (modals_3->usrmod3_lockout_observation_window > 0xffffffff / SECS_PER_MIN)
            {
                ErrorExitInsTxt(APE_CmdArgIllegal,
                        swtxt_SW_ACCOUNTS_LOCKOUT_WINDOW);
            }
            modals_3->usrmod3_lockout_observation_window *= SECS_PER_MIN;
        }
    }
    else if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_LOCKOUT_THRESHOLD)))
    {
        (*APIMask) |= CALL_LEVEL_3;
        if (!stricmpf(ptr, nlsNo))
        modals_3->usrmod3_lockout_threshold = LOCKOUT_NEVER;
        else
        modals_3->usrmod3_lockout_threshold =
            do_atou(ptr, APE_CmdArgIllegal, swtxt_SW_ACCOUNTS_LOCKOUT_THRESHOLD);

    }
#if !defined(NTENV)
    else if (!(_tcscmp(SwitchList[i], swtxt_SW_ACCOUNTS_LOCKOUT)))
    {
        (*APIMask) |= CALL_LEVEL_0;
        if (!stricmpf(ptr, nlsNo))
        modals_0->usrmod0_lockout_count = LOCKOUT_NEVER;
        else
        modals_0->usrmod0_lockout_count =
            do_atou(ptr, APE_CmdArgIllegal, swtxt_SW_ACCOUNTS_LOCKOUT);

    }
#endif /* !NTENV */
    *--ptr = ':';       /* restore pointer for next call */
    }
}

#define FORCE_LOGOFF    0
#define MIN_PW_AGE  (FORCE_LOGOFF + 1)
#define MAX_PW_AGE  (MIN_PW_AGE + 1)
#define MIN_PW_LEN  (MAX_PW_AGE + 1)
#define PW_HIST_LEN (MIN_PW_LEN + 1)
#define ROLE        (PW_HIST_LEN + 1)
#define CONTROLLER  (ROLE + 1)
#define MSG_UNLIMITED   (CONTROLLER + 1)
#define MSG_NEVER   (MSG_UNLIMITED + 1)
#define MSG_NONE    (MSG_NEVER + 1)
#define MSG_UNKNOWN (MSG_NONE + 1)
#define LOCKOUT_CNT (MSG_UNKNOWN + 1)
#define TYPE_PRIMARY (LOCKOUT_CNT + 1)
#define TYPE_BACKUP (TYPE_PRIMARY + 1)
#define TYPE_WORKSTATION (TYPE_BACKUP + 1)
#define TYPE_STANDARD_SERVER (TYPE_WORKSTATION + 1)
#define LOCKOUT_THRESHOLD (TYPE_STANDARD_SERVER + 1)
#define LOCKOUT_DURATION (LOCKOUT_THRESHOLD + 1)
#define LOCKOUT_WINDOW (LOCKOUT_DURATION + 1)

static MESSAGE accMsgList[] = {
    { APE2_ACCOUNTS_FORCELOGOFF,    NULL },
    { APE2_ACCOUNTS_MINPWAGE,       NULL },
    { APE2_ACCOUNTS_MAXPWAGE,       NULL },
    { APE2_ACCOUNTS_MINPWLEN,       NULL },
    { APE2_ACCOUNTS_UNIQUEPW,       NULL },
    { APE2_ACCOUNTS_ROLE,       NULL },
    { APE2_ACCOUNTS_CONTROLLER,     NULL },
    { APE2_GEN_UNLIMITED,       NULL },
    { APE2_GEN_NEVER,           NULL },
    { APE2_GEN_NONE,            NULL },
    { APE2_GEN_UNKNOWN,         NULL },
    { APE2_ACCOUNTS_LOCKOUT_COUNT,  NULL },
    { APE2_PRIMARY,  NULL },
    { APE2_BACKUP,  NULL },
    { APE2_WORKSTATION,  NULL },
    { APE2_STANDARD_SERVER, NULL },
    { APE2_ACCOUNTS_LOCKOUT_THRESHOLD },
    { APE2_ACCOUNTS_LOCKOUT_DURATION },
    { APE2_ACCOUNTS_LOCKOUT_WINDOW }
};

#define NUM_ACC_MSGS (sizeof(accMsgList)/sizeof(accMsgList[0]))

/*
 *  accounts_display(): displays the current user modals
 */
VOID accounts_display(VOID)
{
    struct user_modals_info_0 FAR * modals_0;
    struct user_modals_info_1 FAR * modals_1;
    struct user_modals_info_3 FAR * modals_3;

    ULONG       maxPasswdAge;     /* max password age in days */
    ULONG       minPasswdAge;     /* min password age in days */
    ULONG       forceLogoff;      /* force logoff time in minutes */
    USHORT      len;              /* max message string size */
    USHORT      err;              /* API return status */
    TCHAR *      rolePtr;          /* points to text for role */
    TCHAR        controller[UNCLEN+1]; /* name of domain controller */
    TCHAR *      pBuffer = NULL ;

    /* determine where to call the API. FALSE => no need PDC */
    if (err = GetSAMLocation(controller, DIMENSION(controller),
                             NULL, 0, FALSE))
         ErrorExit(err);

    /* get `da modals */
    if (err = MNetUserModalsGet(controller, 0, (LPBYTE*)&modals_0))
        ErrorExit(err);

    if (err = MNetUserModalsGet(controller, 1, (LPBYTE*)&modals_1))
        ErrorExit(err);

    if (err = MNetUserModalsGet(controller, 3, (LPBYTE*)&modals_3))
        ErrorExit(err);


    /*
     * we call GetDCName rather than use the info in the modals
     * structure which may be out of date.
     */
    err = MNetGetDCName(NULL, NULL, (LPBYTE*)&pBuffer);
    if (err != NERR_Success)
    {
        pBuffer = TEXT("") ;     // later this will indicate to us we didnt get one
    }

    /* convert internal representation to days or minutes as approp. */
    if( modals_0->usrmod0_max_passwd_age != 0xffffffff )
    {
        maxPasswdAge = modals_0->usrmod0_max_passwd_age / SECS_PER_DAY;
    }
    minPasswdAge = modals_0->usrmod0_min_passwd_age / SECS_PER_DAY;
    forceLogoff = modals_0->usrmod0_force_logoff / SECS_PER_MIN;

    GetMessageList(NUM_ACC_MSGS, accMsgList, &len);
    len += 5; /* text should be 5 further to right than largest str */

    if (modals_0->usrmod0_force_logoff == TIMEQ_FOREVER)
	    WriteToCon(fmtNPSZ, len, len, accMsgList[FORCE_LOGOFF].msg_text,
	        accMsgList[MSG_NEVER].msg_text);
    else
	    WriteToCon(fmtULONG, len, len, accMsgList[FORCE_LOGOFF].msg_text,
	        forceLogoff);

#if !defined(NTENV)
    if (modals_0->usrmod0_lockout_count == LOCKOUT_NEVER)
	    WriteToCon(fmtNPSZ, len, len, accMsgList[LOCKOUT_CNT].msg_text,
	        accMsgList[MSG_NEVER].msg_text);
    else
	    WriteToCon(fmtUSHORT, len, len, accMsgList[LOCKOUT_CNT].msg_text,
	        modals_0->usrmod0_lockout_count);
#endif /* !NTENV */

    WriteToCon(fmtULONG, len, len, accMsgList[MIN_PW_AGE].msg_text,
    minPasswdAge);
    if (modals_0->usrmod0_max_passwd_age == 0xffffffff )
    {
        WriteToCon(fmtNPSZ, len, len, accMsgList[MAX_PW_AGE].msg_text,
            accMsgList[MSG_UNLIMITED].msg_text );
    }
    else
    {
        WriteToCon(fmtULONG, len, len, accMsgList[MAX_PW_AGE].msg_text,
            maxPasswdAge);
    }
    WriteToCon(fmtUSHORT, len, len, accMsgList[MIN_PW_LEN].msg_text,
    modals_0->usrmod0_min_passwd_len);

    if (modals_0->usrmod0_password_hist_len == 0)
        WriteToCon(fmtNPSZ, len, len, accMsgList[PW_HIST_LEN].msg_text,
            accMsgList[MSG_NONE].msg_text);
    else
        WriteToCon(fmtUSHORT, len, len, accMsgList[PW_HIST_LEN].msg_text,
            modals_0->usrmod0_password_hist_len);

    if (modals_3->usrmod3_lockout_threshold == LOCKOUT_NEVER)
        WriteToCon(fmtNPSZ, len, len, accMsgList[LOCKOUT_THRESHOLD].msg_text,
            accMsgList[MSG_NEVER].msg_text);
    else
        WriteToCon(fmtUSHORT, len, len, accMsgList[LOCKOUT_THRESHOLD].msg_text,
            modals_3->usrmod3_lockout_threshold);

    if ( modals_3->usrmod3_lockout_duration ==  TIMEQ_FOREVER )
        WriteToCon(fmtNPSZ, len, len, accMsgList[LOCKOUT_DURATION].msg_text,
            accMsgList[MSG_NEVER].msg_text); // BUGBUG
    else
        WriteToCon(fmtULONG, len, len, accMsgList[LOCKOUT_DURATION].msg_text,
            modals_3->usrmod3_lockout_duration / SECS_PER_MIN);

    WriteToCon(fmtULONG, len, len, accMsgList[LOCKOUT_WINDOW].msg_text,
            modals_3->usrmod3_lockout_observation_window / SECS_PER_MIN);



    switch (modals_1->usrmod1_role) {
        case UAS_ROLE_PRIMARY:
            if (IsLocalMachineWinNT())
		/* this is OK since accounts_display is always local */
                if (IsLocalMachineStandard())
                    rolePtr = accMsgList[TYPE_STANDARD_SERVER].msg_text ;
                else
                    rolePtr = accMsgList[TYPE_WORKSTATION].msg_text ;
	    else
                rolePtr = accMsgList[TYPE_PRIMARY].msg_text ;
            break;
        case UAS_ROLE_BACKUP:
            rolePtr = accMsgList[TYPE_BACKUP].msg_text ;
            break;

        /* this should no happen for NT */
        case UAS_ROLE_STANDALONE:
        case UAS_ROLE_MEMBER:
            rolePtr = accMsgList[MSG_UNKNOWN].msg_text ;
            break;
    }

    WriteToCon(fmtNPSZ, len, len, accMsgList[ROLE].msg_text, rolePtr);

    /* if MEMBER or BACKUP, display the domain controller */
    if ((modals_1->usrmod1_role == UAS_ROLE_MEMBER) ||
        (modals_1->usrmod1_role == UAS_ROLE_BACKUP))
    {
         if (*pBuffer)
         {
             /* got a DC back */
             WriteToCon(fmtNPSZ, len, len, accMsgList[CONTROLLER].msg_text,
                    pBuffer);
             NetApiBufferFree(pBuffer);
         }
         else
         {
            /* Unknown domain */
            WriteToCon(fmtNPSZ, len, len, accMsgList[CONTROLLER].msg_text,
                accMsgList[MSG_UNKNOWN].msg_text);
         }
    }

    NetApiBufferFree((TCHAR FAR *) modals_0);
    NetApiBufferFree((TCHAR FAR *) modals_1);
    InfoSuccess();
}

/*
 *  accounts_synch(): synch-es the current user modals to the one on PDC
 */
VOID accounts_synch(VOID)
{
    USHORT				err;	     /* API return status */
    struct user_modals_info_1 FAR *	modals;
    LPBYTE 				pBuffer = NULL ;

    /* retrieve modals to find role */
    err = MNetUserModalsGet(NULL, 1, (LPBYTE *) &modals);
    switch (err)
    {
    case NERR_Success:
	break;

    default:
	ErrorExit(err);
    }

    if (modals->usrmod1_role == UAS_ROLE_BACKUP)
    {
	err = I_MNetLogonControl(NULL,
			         NETLOGON_CONTROL_SYNCHRONIZE,
				 1,
				 &pBuffer) ;
	if (err != NERR_Success)
	    ErrorExit(err) ;
    }
    else if (modals->usrmod1_role == UAS_ROLE_PRIMARY)
    {
	err = I_MNetLogonControl(NULL,
			         NETLOGON_CONTROL_PDC_REPLICATE,
				 1,
				 &pBuffer) ;
	if (err != NERR_Success)
	    ErrorExit(err) ;
    }

    NetApiBufferFree((TCHAR FAR *) modals);
    if (pBuffer) NetApiBufferFree((TCHAR FAR *) pBuffer);
    InfoSuccess() ;
}
