AccountInfo.cpp revision 84b0ad095922000fcc017f18cd294691c126d0c4
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence/*
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 2001 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Permission to use, copy, modify, and distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * copyright notice and this permission notice appear in all copies.
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence *
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
6b7257f756eb0530cdf54df9a7fab8d51a5001c3David Lawrence * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
6b7257f756eb0530cdf54df9a7fab8d51a5001c3David Lawrence */
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence/* $Id: AccountInfo.cpp,v 1.2 2001/09/29 00:01:43 gson Exp $ */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
ce2be9b7211ab5bacaa10fe74ef35def3a3f6089David Lawrence#ifndef UNICODE
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence#define UNICODE
73a691c373488e4f70387a62462cd8ce0d991705David Lawrence#endif /* UNICODE */
8f66dad9393ae0724f758c4a51e06ff55c2d1219Brian Wellington
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews#include "stdafx.h"
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence
3759f10fc543747668b1ca4b4671f35b0dea8445Francis Dupont#include <windows.h>
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews#include <lm.h>
f96b41064bcd427d8125a096fd646c1f068d8ed7David Lawrence#include <ntsecapi.h>
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence#include <isc/ntgroups.h>
f96b41064bcd427d8125a096fd646c1f068d8ed7David Lawrence#include "AccountInfo.h"
e19501436a92cd48eba2ff47d90fa49c661ec8d8Brian Wellington
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence#define MAX_NAME_LENGTH 256
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence
c40906dfad6dd6e3a3e3c94b8c8847bc9bc064e5Mark AndrewsNTSTATUS
c40906dfad6dd6e3a3e3c94b8c8847bc9bc064e5Mark AndrewsOpenPolicy(
669e9657c731176df235832367f61435f7b83ddfAndreas Gustafsson LPWSTR ServerName, /* machine to open policy on (Unicode) */
3db78e0855a8dfc162180880cd70d9c1a03d9301David Lawrence DWORD DesiredAccess, /* desired access to policy */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington PLSA_HANDLE PolicyHandle /* resultant policy handle */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington );
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian WellingtonBOOL
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian WellingtonGetAccountSid(
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington LPTSTR SystemName, /* where to lookup account */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington LPTSTR AccountName, /* account of interest */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington PSID *Sid /* resultant buffer containing SID */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington );
d32b13e0be7f01020365c83a0bd36483ace4d7c3Mark Andrews
d32b13e0be7f01020365c83a0bd36483ace4d7c3Mark AndrewsNTSTATUS
b493dfe8bce94b05efc0f161238d32f1234c5670Brian WellingtonSetPrivilegeOnAccount(
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington LSA_HANDLE PolicyHandle, /* open policy handle */
b493dfe8bce94b05efc0f161238d32f1234c5670Brian Wellington PSID AccountSid, /* SID to grant privilege to */
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence LPWSTR PrivilegeName, /* privilege to grant (Unicode) */
3f96cf3e4f96b36cc1ad2ec7edc5b8e285fced8fBrian Wellington BOOL bEnable /* enable or disable */
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington );
7318a964ece83f748bc7e9814d8c3a61c2b4d946Mark Andrews
4cd765650776027d05fe7fca248478918e02e63bDavid LawrenceNTSTATUS
4cd765650776027d05fe7fca248478918e02e63bDavid LawrenceGetPrivilegesOnAccount(
80b67b3a4f2d9fc7fdd32a50edc67ff189894da2Danny Mayer LSA_HANDLE PolicyHandle, /* open policy handle */
326bcfa0e2a6b924cb829a0bcc3bf9590ce21ad6Mark Andrews PSID AccountSid, /* SID to grant privilege to */
87983da955bf63128de85d180359bdc418516c3cDavid Lawrence wchar_t **PrivList, /* Ptr to List of Privileges found */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington unsigned int *PrivCount /* total number of Privileges in list */
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington );
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark AndrewsNTSTATUS
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian WellingtonAddPrivilegeToAcccount(
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington LPTSTR AccountName, /* Name of the account */
326bcfa0e2a6b924cb829a0bcc3bf9590ce21ad6Mark Andrews LPWSTR PrivilegeName /* Privilege to Add */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington );
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellingtonvoid
4eb998928b9aef0ceda42d7529980d658138698aEvan HuntInitLsaString(
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington PLSA_UNICODE_STRING LsaString, /* destination */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington LPWSTR String /* source (Unicode) */
4144efb39046963989ad002cf88a0c195401100aJeremy Reed );
11463c0ac24692e229ec87f307f5e7df3c0a7e10Evan Hunt
71ca6e64b4d208a090d255eb64c24f945e615ea0Brian Wellingtonvoid
73a691c373488e4f70387a62462cd8ce0d991705David LawrenceDisplayNtStatus(
73a691c373488e4f70387a62462cd8ce0d991705David Lawrence LPSTR szAPI, /* pointer to function name (ANSI) */
bfafdac0616107ff32389532e7040567cd84b8aaBrian Wellington NTSTATUS Status /* NTSTATUS error value */
2ba574f329c14376d26d7c0f22c89d7a978a2625Mark Andrews );
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
e7c0d42b11358f08e04316d31c67c23261dcdf36Evan Huntvoid
9e804040a29b9c3066c8471b43835f30707039b7Evan HuntDisplayWinError(
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence LPSTR szAPI, /* pointer to function name (ANSI) */
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington DWORD WinError /* DWORD WinError */
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington );
debd489a44363870f96f75818e89ec27d3cab736Francis Dupont
debd489a44363870f96f75818e89ec27d3cab736Francis Dupont#ifndef STATUS_SUCCESS
debd489a44363870f96f75818e89ec27d3cab736Francis Dupont#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence#endif
73a691c373488e4f70387a62462cd8ce0d991705David Lawrence
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence/*
5b79d154014f87b6c54b1ec2d3912c35b02042a1Mark Andrews * Note that this code only retrieves the list of privileges of the
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt * requested account or group. However, all accounts belong to the
94b166ffa58ef0ff263563c0550d0b30eb9f7772David Lawrence * Everyone group even though that group is not returned by the
f7c21e46c4b5fdae516b91374c24a87671f83ea3Andreas Gustafsson * calls to get the groups to which that account belongs.
94b166ffa58ef0ff263563c0550d0b30eb9f7772David Lawrence * The Everyone group has two privileges associated with it:
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews * SeChangeNotifyPrivilege and SeNetworkLogonRight
fc39b6a96109b78154ec148d20eaf29e8abc14b6Mukund Sivaraman * It is not advisable to disable or remove these privileges
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews * from the group nor can the account be removed from the Everyone
fc39b6a96109b78154ec148d20eaf29e8abc14b6Mukund Sivaraman * group
d6a0e00dc3e047f8470b938878926957070def77Mark Andrews * The None group has no privileges associated with it and is the group
d6a0e00dc3e047f8470b938878926957070def77Mark Andrews * to which an account belongs if it is associated with no group.
d6a0e00dc3e047f8470b938878926957070def77Mark Andrews */
d6a0e00dc3e047f8470b938878926957070def77Mark Andrews
1479200aa05414b2acf33607dbd1682c16f58c51Evan Huntint
b326d7e3a3a50eb65dd06db007d2fddc62606bbfMark AndrewsGetAccountPrivileges(char *name, wchar_t **PrivList, unsigned int *PrivCount,
5455f30a7532738d750252c00e649890c694ee30Brian Wellington char **Accounts, unsigned int *totalAccounts,
5455f30a7532738d750252c00e649890c694ee30Brian Wellington int maxAccounts)
60213f2815a7e6584a2285546d05633fa7b6f5b4Mark Andrews{
c30d291128e099a284fa6272b91b2bd64519a209Mark Andrews LSA_HANDLE PolicyHandle;
6150d3cb666a58d5e3a15275562c9fc5c5b6b2d8Evan Hunt TCHAR AccountName[256]; /* static account name buffer */
6150d3cb666a58d5e3a15275562c9fc5c5b6b2d8Evan Hunt PSID pSid;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews unsigned int i;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews NTSTATUS Status;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews int iRetVal=RTN_ERROR; /* assume error from main */
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews /*
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews * Open the policy on the target machine.
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews */
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews if ((Status = OpenPolicy(NULL,
ecaed3593cd14f2491d1bd81fc98cb940e12f8bbMark Andrews POLICY_LOOKUP_NAMES,
ecaed3593cd14f2491d1bd81fc98cb940e12f8bbMark Andrews &PolicyHandle)) != STATUS_SUCCESS)
ecaed3593cd14f2491d1bd81fc98cb940e12f8bbMark Andrews return (RTN_ERROR);
ecaed3593cd14f2491d1bd81fc98cb940e12f8bbMark Andrews
ecaed3593cd14f2491d1bd81fc98cb940e12f8bbMark Andrews /*
ecaed3593cd14f2491d1bd81fc98cb940e12f8bbMark Andrews * Let's see if the account exists. Return if not
fc39b6a96109b78154ec148d20eaf29e8abc14b6Mukund Sivaraman */
fc39b6a96109b78154ec148d20eaf29e8abc14b6Mukund Sivaraman wsprintf(AccountName, TEXT("%hS"), name);
fc39b6a96109b78154ec148d20eaf29e8abc14b6Mukund Sivaraman if (!GetAccountSid(NULL, AccountName, &pSid))
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews return (RTN_NOACCOUNT);
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews /*
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews * Find out what groups the account belongs to
323bb31d7c54078aa62146b3aa946b755cbfd52bMark Andrews */
323bb31d7c54078aa62146b3aa946b755cbfd52bMark Andrews Status = isc_ntsecurity_getaccountgroups(name, Accounts, maxAccounts,
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt totalAccounts);
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt Accounts[*totalAccounts] = name; /* Add the account to the list */
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt (*totalAccounts)++;
629a0159401a6c0d991a78a6d0b90ee84e83668cEvan Hunt
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt /*
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt * Loop through each Account to get the list of privileges
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt */
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt for (i = 0; i < *totalAccounts; i++) {
547411428e467f2a2848886eaac0a8b3e136a9abEvan Hunt wsprintf(AccountName, TEXT("%hS"), Accounts[i]);
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews /* Obtain the SID of the user/group. */
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews if (!GetAccountSid(NULL, AccountName, &pSid))
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews continue; /* Try the next one */
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews /* Get the Privileges allocated to this SID */
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews if ((Status = GetPrivilegesOnAccount(PolicyHandle, pSid,
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews PrivList, PrivCount)) == STATUS_SUCCESS)
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews {
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews iRetVal=RTN_OK;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews if (pSid != NULL)
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews HeapFree(GetProcessHeap(), 0, pSid);
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews } else {
62ec9fd1681ffae7d6b0d54618599ecf650e3100Mark Andrews if (pSid != NULL)
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews HeapFree(GetProcessHeap(), 0, pSid);
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews continue; /* Try the next one */
fc39b6a96109b78154ec148d20eaf29e8abc14b6Mukund Sivaraman }
fc39b6a96109b78154ec148d20eaf29e8abc14b6Mukund Sivaraman }
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews /*
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews * Close the policy handle.
9c03f13e18c1b0c32f62391a17300378605bbc7bEvan Hunt */
9c03f13e18c1b0c32f62391a17300378605bbc7bEvan Hunt LsaClose(PolicyHandle);
9c03f13e18c1b0c32f62391a17300378605bbc7bEvan Hunt
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews (*totalAccounts)--; /* Correct for the number of groups */
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews return iRetVal;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews}
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark AndrewsBOOL
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark AndrewsCreateServiceAccount(char *name, char *password) {
9bd876a683709be588f6fac6781a76fdd57b2f08Mark Andrews NTSTATUS retstat;
9bd876a683709be588f6fac6781a76fdd57b2f08Mark Andrews USER_INFO_1 ui;
9bd876a683709be588f6fac6781a76fdd57b2f08Mark Andrews DWORD dwLevel = 1;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews DWORD dwError = 0;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews NET_API_STATUS nStatus;
fdcfc6bae754ee8f0b43dfd872284a294a8f2fd2Mark Andrews
fdcfc6bae754ee8f0b43dfd872284a294a8f2fd2Mark Andrews unsigned int namelen = strlen(name);
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews unsigned int passwdlen = strlen(password);
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews wchar_t *AccountName = (wchar_t *)malloc((namelen + 1)*
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews sizeof(wchar_t));
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews wchar_t *AccountPassword = (wchar_t *)malloc((passwdlen + 1)*
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews sizeof(wchar_t));
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews mbstowcs(AccountName, name, namelen + 1);
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews mbstowcs(AccountPassword, password, passwdlen + 1);
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews /*
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews * Set up the USER_INFO_1 structure.
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews * USER_PRIV_USER: name is required here when creating an account
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews * rather than an administrator or a guest.
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews */
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews ui.usri1_name = AccountName;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews ui.usri1_password = AccountPassword;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews ui.usri1_priv = USER_PRIV_USER;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews ui.usri1_home_dir = NULL;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews ui.usri1_comment = L"ISC BIND Service Account";
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews ui.usri1_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews ui.usri1_script_path = NULL;
d96f74a3cb6212ac9e4a7a0fa8924f850348eae9Mark Andrews /*
94b166ffa58ef0ff263563c0550d0b30eb9f7772David Lawrence * Call the NetUserAdd function, specifying level 1.
87983da955bf63128de85d180359bdc418516c3cDavid Lawrence */
87983da955bf63128de85d180359bdc418516c3cDavid Lawrence nStatus = NetUserAdd(NULL, dwLevel, (LPBYTE)&ui, &dwError);
73a691c373488e4f70387a62462cd8ce0d991705David Lawrence
73a691c373488e4f70387a62462cd8ce0d991705David Lawrence free(AccountPassword);
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence free(AccountName);
20bd7b4bbf2437ef2f9109edca168ab0ce8445b3David Lawrence if (nStatus != NERR_Success)
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington return (FALSE);
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington
b493dfe8bce94b05efc0f161238d32f1234c5670Brian Wellington retstat = AddPrivilegeToAcccount(name, SE_SERVICE_LOGON_PRIV);
7389e8330d62a059b8923fb8ca6f933caeb559d9Mark Andrews return (TRUE);
b493dfe8bce94b05efc0f161238d32f1234c5670Brian Wellington}
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark AndrewsNTSTATUS
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark AndrewsAddPrivilegeToAcccount(LPTSTR name, LPWSTR PrivilegeName) {
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews LSA_HANDLE PolicyHandle;
1d16cf8bb8596c3e4dc1123a5bdf360bf24a272bAutomatic Updater TCHAR AccountName[256]; /* static account name buffer */
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews PSID pSid;
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews NTSTATUS Status;
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews unsigned long err;
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews /*
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews * Open the policy on the target machine.
4423c99613db1399dbb5c51e86ef0d351a1418c2Mark Andrews */
b493dfe8bce94b05efc0f161238d32f1234c5670Brian Wellington if ((Status = OpenPolicy(NULL, POLICY_ALL_ACCESS, &PolicyHandle))
b493dfe8bce94b05efc0f161238d32f1234c5670Brian Wellington != STATUS_SUCCESS)
b493dfe8bce94b05efc0f161238d32f1234c5670Brian Wellington return (RTN_ERROR);
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington /*
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington * Let's see if the account exists. Return if not
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington wsprintf(AccountName, TEXT("%hS"), name);
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington if (!GetAccountSid(NULL, AccountName, &pSid))
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington return (RTN_NOACCOUNT);
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington err = LsaNtStatusToWinError(SetPrivilegeOnAccount(PolicyHandle,
71ca6e64b4d208a090d255eb64c24f945e615ea0Brian Wellington pSid, PrivilegeName, TRUE));
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington LsaClose(PolicyHandle);
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington if (err == ERROR_SUCCESS)
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews return (RTN_OK);
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews else
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews return (err);
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews}
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellingtonvoid
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian WellingtonInitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String){
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington DWORD StringLength;
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington if (String == NULL) {
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington LsaString->Buffer = NULL;
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington LsaString->Length = 0;
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington LsaString->MaximumLength = 0;
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington return;
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington }
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
71ca6e64b4d208a090d255eb64c24f945e615ea0Brian Wellington StringLength = wcslen(String);
71ca6e64b4d208a090d255eb64c24f945e615ea0Brian Wellington LsaString->Buffer = String;
73a691c373488e4f70387a62462cd8ce0d991705David Lawrence LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
e1d05d323526e7e65df13a6d3dfbec30f6ddb500Brian Wellington LsaString->MaximumLength = (USHORT)(StringLength+1) * sizeof(WCHAR);
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews}
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark AndrewsNTSTATUS
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark AndrewsOpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle){
287910778c57d4836a52b03b697c2ef342d0eaa9Francis Dupont LSA_OBJECT_ATTRIBUTES ObjectAttributes;
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews LSA_UNICODE_STRING ServerString;
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington PLSA_UNICODE_STRING Server = NULL;
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington /*
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington * Always initialize the object attributes to all zeroes.
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
73a691c373488e4f70387a62462cd8ce0d991705David Lawrence
4eb998928b9aef0ceda42d7529980d658138698aEvan Hunt if (ServerName != NULL) {
4eb998928b9aef0ceda42d7529980d658138698aEvan Hunt /*
73a691c373488e4f70387a62462cd8ce0d991705David Lawrence * Make a LSA_UNICODE_STRING out of the LPWSTR passed in
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington */
a2b15b3305acd52179e6f3dc7d073b07fbc40b8eMark Andrews InitLsaString(&ServerString, ServerName);
a2b15b3305acd52179e6f3dc7d073b07fbc40b8eMark Andrews Server = &ServerString;
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington }
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington /*
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington * Attempt to open the policy.
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington return (LsaOpenPolicy(Server, &ObjectAttributes, DesiredAccess,
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington PolicyHandle));
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington}
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian WellingtonBOOL
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian WellingtonGetAccountSid(LPTSTR SystemName, LPTSTR AccountName, PSID *Sid) {
927e4c9fecf448bf3894c68fcaf9dc2f89557f3aEvan Hunt LPTSTR ReferencedDomain = NULL;
e7c0d42b11358f08e04316d31c67c23261dcdf36Evan Hunt DWORD cbSid = 128; /* initial allocation attempt */
e7c0d42b11358f08e04316d31c67c23261dcdf36Evan Hunt DWORD cbReferencedDomain = 16; /* initial allocation size */
927e4c9fecf448bf3894c68fcaf9dc2f89557f3aEvan Hunt SID_NAME_USE peUse;
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington BOOL bSuccess = FALSE; /* assume this function will fail */
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington
e4cd5a1e5d0358abeee7618b02b4592c055d957fBrian Wellington __try {
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt /*
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt * initial memory allocations
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt */
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt if ((*Sid = HeapAlloc(GetProcessHeap(), 0, cbSid)) == NULL)
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt __leave;
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt if ((ReferencedDomain = (LPTSTR) HeapAlloc(GetProcessHeap(), 0,
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt cbReferencedDomain)) == NULL) __leave;
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt
9e804040a29b9c3066c8471b43835f30707039b7Evan Hunt /*
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington * Obtain the SID of the specified account on the specified system.
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington */
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews while (!LookupAccountName(SystemName, AccountName, *Sid, &cbSid,
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews ReferencedDomain, &cbReferencedDomain,
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews &peUse))
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews {
f07fe5a1ac9d1345eb7a36a0bc38716a03e25f61Mark Andrews if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington /* reallocate memory */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington if ((*Sid = HeapReAlloc(GetProcessHeap(), 0,
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews *Sid, cbSid)) == NULL) __leave;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews if ((ReferencedDomain= (LPTSTR) HeapReAlloc(
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews GetProcessHeap(), 0, ReferencedDomain,
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews cbReferencedDomain)) == NULL)
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews __leave;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews }
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews else
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews __leave;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews }
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews bSuccess = TRUE;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews } /* finally */
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews __finally {
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews /* Cleanup and indicate failure, if appropriate. */
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews HeapFree(GetProcessHeap(), 0, ReferencedDomain);
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews if (!bSuccess) {
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews if (*Sid != NULL) {
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews HeapFree(GetProcessHeap(), 0, *Sid);
4eb998928b9aef0ceda42d7529980d658138698aEvan Hunt *Sid = NULL;
bcae9a15c1e9c50a6e6433168d5225b1de89d6b9Evan Hunt }
c4f9e613e12f03795bee18cf2ca8e6a9d39d6468Mark Andrews }
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews }
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews return (bSuccess);
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews}
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark AndrewsNTSTATUS
4eb998928b9aef0ceda42d7529980d658138698aEvan HuntSetPrivilegeOnAccount(LSA_HANDLE PolicyHandle, PSID AccountSid,
4eb998928b9aef0ceda42d7529980d658138698aEvan Hunt LPWSTR PrivilegeName, BOOL bEnable)
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews{
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews LSA_UNICODE_STRING PrivilegeString;
a2b15b3305acd52179e6f3dc7d073b07fbc40b8eMark Andrews
a2b15b3305acd52179e6f3dc7d073b07fbc40b8eMark Andrews /* Create a LSA_UNICODE_STRING for the privilege name. */
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews InitLsaString(&PrivilegeString, PrivilegeName);
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews /* grant or revoke the privilege, accordingly */
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews if (bEnable)
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews return (LsaAddAccountRights(PolicyHandle, AccountSid,
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews &PrivilegeString, 1));
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews else
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews return (LsaRemoveAccountRights(PolicyHandle, AccountSid,
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews FALSE, &PrivilegeString, 1));
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews}
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark AndrewsNTSTATUS
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark AndrewsGetPrivilegesOnAccount(LSA_HANDLE PolicyHandle, PSID AccountSid,
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews wchar_t **PrivList, unsigned int *PrivCount)
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews{
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews NTSTATUS Status;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews LSA_UNICODE_STRING *UserRights;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews ULONG CountOfRights;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews unsigned int retlen = 0;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews DWORD i, j;
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt int found;
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt Status = LsaEnumerateAccountRights(PolicyHandle, AccountSid,
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt &UserRights, &CountOfRights);
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt /* Only continue if there is something */
4eb998928b9aef0ceda42d7529980d658138698aEvan Hunt if (UserRights == NULL || Status != STATUS_SUCCESS)
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt return (Status);
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt for (i = 0; i < CountOfRights; i++) {
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt found = -1;
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt retlen = UserRights[i].Length/sizeof(wchar_t);
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt for (j = 0; j < *PrivCount; j++) {
e32d354f754a5d7847a0862bcd6302827ea225bfEvan Hunt found = wcsncmp(PrivList[j], UserRights[i].Buffer,
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews retlen);
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews if (found == 0)
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews break;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews }
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews if (found != 0) {
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews PrivList[*PrivCount] =
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews (wchar_t *)malloc(UserRights[i].MaximumLength);
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews wcsncpy(PrivList[*PrivCount], UserRights[i].Buffer,
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews retlen);
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews PrivList[*PrivCount][retlen] = L'\0';
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews (*PrivCount)++;
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews }
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews
72ddc4cef9c6a6de53aae530dea1ddbb90631131Mark Andrews }
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington return (Status);
bcdf37e0ff7d73310b7bf247d755194a5718ba38Mark Andrews}
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellingtonvoid
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian WellingtonDisplayNtStatus(LPSTR szAPI, NTSTATUS Status) {
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington /* Convert the NTSTATUS to Winerror. Then call DisplayWinError(). */
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington DisplayWinError(szAPI, LsaNtStatusToWinError(Status));
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington}
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellingtonvoid
71ca6e64b4d208a090d255eb64c24f945e615ea0Brian WellingtonDisplayWinError(LPSTR szAPI, DWORD WinError) {
71ca6e64b4d208a090d255eb64c24f945e615ea0Brian Wellington LPSTR MessageBuffer;
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington DWORD dwBufferLength;
bcdf37e0ff7d73310b7bf247d755194a5718ba38Mark Andrews
bcdf37e0ff7d73310b7bf247d755194a5718ba38Mark Andrews if (dwBufferLength=FormatMessageA(
420e5e1022ff5ca4697ed5286462eeaf03614e53Brian Wellington FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
bcdf37e0ff7d73310b7bf247d755194a5718ba38Mark Andrews NULL, WinError, GetUserDefaultLangID(),
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington (LPSTR) &MessageBuffer, 0, NULL)){
bcdf37e0ff7d73310b7bf247d755194a5718ba38Mark Andrews DWORD dwBytesWritten; /* unused */
420e5e1022ff5ca4697ed5286462eeaf03614e53Brian Wellington
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington /* Output message string on stderr. */
420e5e1022ff5ca4697ed5286462eeaf03614e53Brian Wellington WriteFile(GetStdHandle(STD_ERROR_HANDLE), MessageBuffer,
bcdf37e0ff7d73310b7bf247d755194a5718ba38Mark Andrews dwBufferLength, &dwBytesWritten, NULL);
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington /* Free the buffer allocated by the system. */
bcdf37e0ff7d73310b7bf247d755194a5718ba38Mark Andrews LocalFree(MessageBuffer);
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington }
b6b9d8b8434e4eaab74b69cd14fcacf448055ca5Brian Wellington}
1d92d8a2456b23842a649b6104c60a9d6ea25333Brian Wellington