Skip to content

Instantly share code, notes, and snippets.

@stefanschneider
Created October 8, 2015 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefanschneider/2719032b8e58e6433ab8 to your computer and use it in GitHub Desktop.
Save stefanschneider/2719032b8e58e6433ab8 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace credsTest
{
// https://github.com/dblock/waffle/blob/ddbeb7f99e2676183e71c188c15d577328695f0f/Source/WindowsAuthProvider/Netapi32.cs#L110
/// <summary>
/// Netapi32.dll PInvoke.
/// </summary>
public class Netapi32
{
/// <summary>
/// The NetGetJoinInformation function retrieves join status information for the specified computer.
/// </summary>
/// <param name="server">String that specifies the DNS or NetBIOS name of the computer on which to call the function.</param>
/// <param name="domain">Receives the NetBIOS name of the domain or workgroup to which the computer is joined.</param>
/// <param name="status">Receives the join status of the specified computer.</param>
/// <returns></returns>
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int NetGetJoinInformation(
string server,
out IntPtr domain,
out NetJoinStatus status);
/// <summary>
/// The NetApiBufferFree function frees the memory that the NetApiBufferAllocate function allocates.
/// Applications should also call NetApiBufferFree to free the memory that other network management
/// functions use internally to return information.
/// </summary>
/// <param name="Buffer">A buffer returned previously by another network management function or memory allocated by calling the NetApiBufferAllocate function.</param>
/// <returns>If the function succeeds, the return value is NERR_Success.</returns>
[DllImport("Netapi32.dll")]
public static extern int NetApiBufferFree(IntPtr Buffer);
/// <summary>
/// Win32 Result Code Constant.
/// </summary>
public const int NERR_Success = 0;
/// <summary>
/// Buffer is too small.
/// </summary>
public const int NERR_BufTooSmall = 2123;
/// <summary>
/// Computer spcified is invalid.
/// </summary>
public const int NERR_InvalidComputer = 2351;
/// <summary>
/// NetGetJoinInformation() Enumeration
/// </summary>
public enum NetJoinStatus
{
/// <summary>
/// Unknown membership status.
/// </summary>
NetSetupUnknownStatus = 0,
/// <summary>
/// Computer not joined to a domain.
/// </summary>
NetSetupUnjoined,
/// <summary>
/// Computer joined to a workgroup.
/// </summary>
NetSetupWorkgroupName,
/// <summary>
/// Computer joined to a domain.
/// </summary>
NetSetupDomainName
} // NETSETUP_JOIN_STATUS
/// <summary>
/// The NetLocalGroupEnum function returns information about each local group account on the specified server.
/// </summary>
/// <param name="servername">String that specifies the DNS or NetBIOS name of the remote server on which the function is to execute.</param>
/// <param name="level">The information level of the data.</param>
/// <param name="bufptr">Pointer to the address of the buffer that receives the information structure.</param>
/// <param name="prefmaxlen">Specifies the preferred maximum length of returned data, in bytes.</param>
/// <param name="entriesread">Pointer to a value that receives the count of elements actually enumerated.</param>
/// <param name="totalentries">Pointer to a value that receives the approximate total number of entries that could have been enumerated from the current resume position.</param>
/// <param name="resume_handle">Pointer to a value that contains a resume handle that is used to continue an existing local group search.</param>
/// <returns>If the function succeeds, the return value is NERR_Success.</returns>
[DllImport("Netapi32.dll")]
public extern static int NetLocalGroupEnum(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
int level,
out IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
ref int resume_handle);
/// <summary>
/// LOCALGROUP_INFO_0
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LOCALGROUP_USERS_INFO_0
{
/// <summary>
/// Group name.
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string name;
}
/// <summary>
/// The USER_INFO_1 structure contains information about a user account, including account name,
/// password data, privilege level, and the path to the user's home directory.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct USER_INFO_1
{
/// <summary>
/// A Unicode string that specifies the name of the user account.
/// </summary>
public string usri1_name;
/// <summary>
/// a Unicode string that specifies the password of the user indicated by the usri1_name member.
/// The length cannot exceed PWLEN bytes. By convention, the length of passwords is limited
/// to LM20_PWLEN characters.
/// </summary>
public string usri1_password;
/// <summary>
/// The number of seconds that have elapsed since the usri1_password member was last changed.
/// </summary>
public int usri1_password_age;
/// <summary>
/// The level of privilege assigned to the usri1_name member.
/// </summary>
public int usri1_priv;
/// <summary>
/// A Unicode string specifying the path of the home directory for the user specified in the
/// usri1_name member. The string can be null.
/// </summary>
public string usri1_home_dir;
/// <summary>
/// A Unicode string that contains a comment to associate with the user account. This string can
/// be a null string, or it can have any number of characters before the terminating null character.
/// </summary>
public string comment;
/// <summary>
/// User flags, one of UF_ values.
/// </summary>
public int usri1_flags;
/// <summary>
/// A Unicode string specifying the path for the user's logon script file.
/// The script file can be a .CMD file, an .EXE file, or a .BAT file. The string can also be null.
/// </summary>
public string usri1_script_path;
}
/// <summary>
/// The NetUserAdd function adds a user account and assigns a password and privilege level.
/// </summary>
/// <param name="servername"></param>
/// <param name="level"></param>
/// <param name="buf"></param>
/// <param name="parm_err"></param>
/// <returns></returns>
[DllImport("Netapi32.dll")]
public extern static int NetUserAdd(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
int level,
ref USER_INFO_1 buf,
int parm_err);
/// <summary>
/// The NetUserDel function deletes a user account from a server.
/// </summary>
/// <param name="servername"></param>
/// <param name="username"></param>
/// <returns></returns>
[DllImport("Netapi32.dll")]
public extern static int NetUserDel(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username);
}
class Program
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct USER_INFO_2
{
public string name;
public string password;
public int password_age;
public int priv;
public string home_dir;
public string comment;
public int flags;
public string script_path;
public int auth_flags;
public string full_name;
public string usr_comment;
public string parms;
public string workstations;
public int last_logon;
public int last_logoff;
public ulong acct_expires;
public int max_storage;
public int units_per_week;
public IntPtr logon_hours; // This is a PBYTE
public int bad_pw_count;
public int num_logons;
public string logon_server;
public int country_code;
public int code_page;
}
[DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int NetUserAdd(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
UInt32 level,
ref USER_INFO_2 userinfo,
out UInt32 parm_err);
private static uint CreateUser(string computer, string userName,
string psswrd, string fullname)
{
const int UF_DONT_EXPIRE_PASSWD = 0x10000;
const int UF_ACCOUNTDISABLE = 0x000002;
const int USER_PRIV_GUEST = 0; // lmaccess.h:656
const int USER_PRIV_USER = 1; // lmaccess.h:657
const int USER_PRIV_ADMIN = 2; // lmaccess.h:658
USER_INFO_2 userInfo2 = new USER_INFO_2()
{
acct_expires = long.MaxValue,
auth_flags = 0, // Must be 0 for NetUserAddCalls
bad_pw_count = -1, //ignored for NetUserAdd calls
//code_page = ?,
comment = "ScanTrack Account",
//country_code = ?,
flags = UF_DONT_EXPIRE_PASSWD,// & UF_ACCOUNTDISABLE,
full_name = fullname,
home_dir = "c:\\users\\testtt",
last_logoff = 0,
last_logon = 0,
logon_hours = IntPtr.Zero, // User is given no logon time.
logon_server = "", //ignored for NetUserAdd calls
max_storage = 0,
name = userName,
num_logons = -1, //ignored for NetUserAdd calls
parms = "",
password = psswrd,
password_age = -1,
priv = USER_PRIV_GUEST,
script_path = "",
units_per_week = -1, //ignored for NetUserAdd calls
usr_comment = "",
workstations = ""
};
uint output;
var res = NetUserAdd(computer, 2, ref userInfo2, out output);
Console.WriteLine(res);
return output;
}
private void button1_Click(object sender, EventArgs e)
{
}
static void Main(string[] args)
{
var userName = "test";
var _testUser = new Netapi32.USER_INFO_1();
_testUser.usri1_name = userName;
_testUser.usri1_password = Guid.NewGuid().ToString();
_testUser.usri1_priv = 1;
_testUser.usri1_home_dir = null;
_testUser.comment = "Waffle test user.";
_testUser.usri1_script_path = null;
var x = new Stopwatch();
x.Start();
for (int i = 1; i < 100; i++)
{
int rc = Netapi32.NetUserAdd(null, 1, ref _testUser, 0);
Netapi32.NetUserDel(null, userName);
}
Console.WriteLine(x.Elapsed);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment