2014年5月17日星期六

以另一个用户启动一个进程

#include "stdafx.h"

/*
runas是一个常用的命令,你会用吗?
我不会,但我要探究它的进一步的原理。
其实很简单,参见:http://msdn.microsoft.com/en-us/library/windows/desktop/ms682431(v=vs.85).aspx
注意事项:见注释。

不过要在不同的会话中运行,那就麻烦了。
普通的程序需要提权。
而进程的权限是继承自用户的,所以还要给用户分派权限。
具体的设置可以参考本地安全策略:http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/08bc7712-548c-4308-a49c-d551a4b5e245.mspx?mfr=true。
注意:这些设置还要重启后生效。
所以常用的办法是用服务,服务默认是具有这些权限的。再次郑重说明:不用服务也是可以的。
正好这有解决了服务在Vista及以后系统的编程交互(如:弹出对话框)的问题。

提示:命令行输入空的参数,可以使用双引号,也就是这两个引号之间没有内容,包括空格。

made by correy
made at 2014.05.17
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#include <windows.h>
#include <stdio.h>
#include <userenv.h>

#pragma comment(lib, "userenv.lib")

void DisplayError(LPWSTR pszAPI)
{
    LPVOID lpvMessageBuffer;

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpvMessageBuffer, 0, NULL);

    //... now display this string
    wprintf(L"ERROR: API        = %s.\n", pszAPI);
    wprintf(L"       error code = %d.\n", GetLastError());
    wprintf(L"       message    = %s.\n", (LPWSTR)lpvMessageBuffer);
        
    LocalFree(lpvMessageBuffer);// Free the buffer allocated by the system
    ExitProcess(GetLastError());
}

void wmain(int argc, WCHAR *argv[])
{    
    if (argc != 4)
    {
        wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
        wprintf(L"\n\n");
        return;
    }

    // TO DO: change NULL to '.' to use local account database
    HANDLE    hToken;
    if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken)) { //必须有密码,不然失败。
        DisplayError(L"LogonUser");
    }

    //得到的内容其实就是:The environment block is an array of null-terminated Unicode strings. The list ends with two nulls (\0\0).
    LPVOID    lpvEnv;
    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) {
        DisplayError(L"CreateEnvironmentBlock");
    }

    //获取用户的文件夹。
    WCHAR               szUserProfile[256] = L""; 
    DWORD dwSize = sizeof(szUserProfile)/sizeof(WCHAR);
    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize)) {//用户必须登录运行过一次,不必此时这个用户运行着。
        DisplayError(L"GetUserProfileDirectory");
    }

    // TO DO: change NULL to '.' to use local account database
    STARTUPINFO         si = {0};
    si.cb = sizeof(STARTUPINFO);
    PROCESS_INFORMATION pi = {0};
    if (!CreateProcessWithLogonW(argv[1], NULL, argv[2], LOGON_WITH_PROFILE, NULL, argv[3], CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile, &si, &pi)) {
        DisplayError(L"CreateProcessWithLogonW");
    }

    if (!DestroyEnvironmentBlock(lpvEnv)) {
        DisplayError(L"DestroyEnvironmentBlock");
    }

    CloseHandle(hToken);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

没有评论:

发表评论