Thread: Piping problems

    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Whyalla, Australia
    Posts
    20
    Rep Power
    0

    Piping problems


    Hey everyone.

    Im current;y working on a web server (swebs.sourceforge.net). I have the following function that is part of my CONNECTION class:

    PHP Code:
    int CONNECTION::SendCGI()
    {
        
    RealFile "C:\\SWS\\Webroot\\samplephp.php";

        
    char psBuffer[128];
        
    FILE hPipe;
        
    string CGIInterpreter "\"";                                // Put quotes around the name of the interpreter    
        
    CGIInterpreter += "C:\\PHP\\php.exe";    // Interpreter
        
    CGIInterpreter += "\" ";    // End quote
        
    CGIInterpreter += RealFile;    // Add the file to be interpreted

        
    if ((hPipe _popen(CGIInterpreter.c_str(), "r")) == NULL)            
        {                                                            
    // Open a pipe
            
    Beep(80,1000);
        }
        else 
        {
        while (!
    feofhPipe ))                                        // Loop until output finishes
        
    {
            if( 
    fgetspsBuffer128hPipe) )                        // Get part of the output
            
    {    
                
    cout << psBuffer;    // Send it
            
    }
        }
        
    fclose(hPipe);                            // Close pipe    
        
    }                                                    // Return true for now
        
    return true;

    The code runs as part of an NT service and is supposed to send a file to a CGI interpreter and pipe its output to be sent back to the browser.

    When that code is run from the server all I get is the beep. But if I copy everything from the function and run it inside 'main()' as part of a stand alone application it runs fine and gives the expected output.

    I don't use any of the variables externally (for now, I will when its working) yet it wont work when run as a service.

    Theres nothing wrong with the service code or anything because I can do everything else, just not this. Does anyone have any idea why I might be having these problems?
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Oct 2000
    Location
    Back in the real world.
    Posts
    5,966
    Rep Power
    191
    Two things:
    You need double-backslashes, but I guess you know that and one was lost in the cut-n-paste process.

    Probably itīs this:
    The folder and program needs read(?) and execute(!) permissions for services or you have to run your service with user permissions.
  4. #3
  5. pogremar
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    At Work
    Posts
    958
    Rep Power
    13
    I know that Services cannot interact with the desktop. I don't know if they can interact with console windows (your cout <<). You should check on the msdn site.
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Whyalla, Australia
    Posts
    20
    Rep Power
    0
    Yeh I know they can't interact with the desktop or console windows, the cout << was there from the int main. I've tested by using send() to send it over the network, but that doesn't matter anyway since I get a beep (because there was a null handle returned).

    Heres a thought though. Services run under the system account (I think). Since I've been doing all this testing as administrator, maybe the system account can't access the files like M.Hirsch said. But my partitions are all FAT32, so I don't think I have any control over read/execute permisions.

    I did, however, change the service to run as Administrator, but that didn't make a difference :(

    Oh and btw yeh the backslashes were lost in the cut and paste when (probably to do with the way the PHP works on this site).

    Thanks for your help guys, any more suggestions?
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Oct 2000
    Location
    Back in the real world.
    Posts
    5,966
    Rep Power
    191
    My local win32 reference says that _popen() does not work for windows. Either it is outdated or you have a wrapper library for _popen().
    You need to find out the error code and what it means. Look in the msdn reference or the documentation of your C++ compiler how to get it for _popen().

    I never wrote a services application, but in "normal" win32 programs you usually get the error code like this: (sorry, sloppy syntax... parameters are probably not right and / or mixed up.)
    Code:
    if ((hPipe = _popen(CGIInterpreter.c_str(), "r")) == NULL)            
        {  
            int err=GetLastError();
            char s[1000];
            FormatMessage(FORMAT_FROM_SYSTEM, &s[0], 1000, ??? see yourself what else);
            MessageBox(0, "Error", &s[0], MB_OK);
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Whyalla, Australia
    Posts
    20
    Rep Power
    0
    Thanks very much M.Hirsch. I had read that _popen() can freeze on Win32 Apps on MSDN, but bieng a service it is compiled as a console application, so I figured there wouldn't be a problem with it.

    I tried what you suggested, and this is what it gave me:
    "The operation completed successfully." which makes no sense! Heres the code:
    PHP Code:
    hrPipe _popen(CGIInterpreter.c_str(), "r");
        if (
    hrPipe == NULL)            
        {
            
    int Err GetLastError();
            
    char Error[1000];
            
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                          
    NULL,
                          
    Err,
                          
    0,
                          &
    Error[0],
                          
    1000,
                          
    NULL);
            
            
    LogText(Error);
            
    //Status = 500;
            
    return false;
        } 
    LogText() simply writes the string passed to it to a file.

    Which brings me to an article I read about problems with services under NT (at http://www.microsoft.com/msj/0398/service2.aspx)
    "The System account is a special account known only locally to your machine. This means that this account cannot be used to access network resources relying on NT LAN Manager (NTLM) authentication. These resources include file shares, named pipes, the registry, and access to a remote computer's eventlog or Service Control Manager."

    So from that I gather it means that I cannot use Pipes with the localsystem account?

    Ok then, if thats the case I figured I'll have the service run using the Administrator username/password, but that didn't help either.

    So it seems to me that the code is right, but the handle returns null because services can't use named pipes as the system account. But there must be hundreds of windows services out there that use pipes!! Does anyone know how to enable them?
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Oct 2000
    Location
    Back in the real world.
    Posts
    5,966
    Rep Power
    191
    I had read that _popen() can freeze on Win32 Apps on MSDN, but bieng a service it is compiled as a console application, so I figured there wouldn't be a problem with it
    [...]
    The operation completed successfully
    Console apps are win32 apps too.
    And it seems like _popen() does not set LastError. :(

    So from that I gather it means that I cannot use Pipes with the localsystem account?
    No, it says you canīt use named pipes, they are a special kind of pipes. But then - I am not sure (anymore) if windows does support anonymous pipes at all...
    AFAIK: No. This would be the popen() command. But you have it, I donīt. If they emulate popen() with using named pipes here, it can of course not work either. :confused:

    Anyway, this info applies to the system account, you said you started it with administrator privileges now.

    I have an assumption:
    I think you have to adjust the process privileges. I donīt know why this step is necessary though. But for rebooting a NT machine eg., I had to adjust them like this:
    Code:
      if Win32Platform = VER_PLATFORM_WIN32_NT then
      begin
        hProcess := OpenProcess(PROCESS_ALL_ACCESS, True, GetCurrentProcessID);
        try
          if not OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,
            hToken) then Exit;
        finally
          CloseHandle(hProcess);
        end;
        try
          if not LookupPrivilegeValue('', 'SeShutdownPrivilege',
            tp.Privileges[0].Luid) then Exit;
          tp.PrivilegeCount := 1;
          tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
          if not AdjustTokenPrivileges(hToken, False, tp, SizeOf(prev_tp),
            prev_tp, Len) then Exit;
        finally
          CloseHandle(hToken);
        end;
      end;
      CanShutdown := True;
      if FForce then Flags := EWX_FORCE else Flags := 0;
      SetSystemPowerState(True, FForce);
      Close();
    This is delphi code... HTH
  14. #8
  15. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Whyalla, Australia
    Posts
    20
    Rep Power
    0
    Alright, thanks very much M.Hirsch, I'm going to search for OpenProcess() and adjusting the process priveliges right now. You've been a very big help thanks so much!
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Whyalla, Australia
    Posts
    20
    Rep Power
    0
    Sorry to bother you again M.Hirsch, but I'm having another problem. This is what I've gotten so far (mostly taken from your code)
    PHP Code:
    #include <iostream>
    #include <windows.h>

    using namespace std;


    int main()
    {

        
    HANDLE hProcess;
        
    PHANDLE hToken;
        
    hProcess OpenProcess(PROCESS_ALL_ACCESStrueGetCurrentProcessId());

        if (
    hProcess == NULL)
        {
            
    cout << "Process opened!\n";
            return 
    1;
        }

        if (!
    OpenProcessToken(hProcessTOKEN_ALL_ACCESShToken))
        {
            
    cout << "OpenProcessToken failed\n";
            
    int Err GetLastError();
            
    char Error[1000];
            
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                          
    NULL,
                          
    Err,
                          
    0,
                          &
    Error[0],
                          
    1000,
                          
    NULL);
            
    cout << "Error: " << Error << "\n";
            return 
    1;
        }


        return 
    0;

    It always says:
    Code:
    OpenProcessToken failed
    Error: Invalid access to memory location.
    What have I done wrong? I am compiling this with MSVC++6.0 as a console app, could that be the problem?

IMN logo majestic logo threadwatch logo seochat tools logo