[PATCH] validate -n parameter value
Update the service_name global to an SBuf and use Tokenizer to validate the -n argument is a pure alphanumeric. Amos === modified file 'src/WinSvc.cc' --- src/WinSvc.cc 2014-01-24 01:57:15 + +++ src/WinSvc.cc 2014-06-14 14:20:56 + @@ -493,41 +493,41 @@ #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */ newHandler = Squid_Win32InvalidParameterHandler; oldHandler = _set_invalid_parameter_handler(newHandler); _CrtSetReportMode(_CRT_ASSERT, 0); #endif #if USE_WIN32_SERVICE if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { char path[512]; HKEY hndKey; if (signal(SIGABRT, WIN32_Abort) == SIG_ERR) return 1; /* Register the service Handler function */ -svcHandle = RegisterServiceCtrlHandler(service_name, WIN32_svcHandler); +svcHandle = RegisterServiceCtrlHandler(service_name.c_str(), WIN32_svcHandler); if (svcHandle == 0) return 1; /* Set Process work dir to directory cointaining squid.exe */ GetModuleFileName(NULL, path, 512); WIN32_module_name=xstrdup(path); path[strlen(path) - 10] = '\0'; if (SetCurrentDirectory(path) == 0) return 1; safe_free(ConfigFile); /* get config file from Windows Registry */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) { DWORD Type = 0; DWORD Size = 0; @@ -654,192 +654,195 @@ status = GetLastError(); debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status); } debugs(1, DBG_IMPORTANT, "Leaving Squid service"); break; default: debugs(1, DBG_IMPORTANT, "Unrecognized opcode " << Opcode); } return; } void WIN32_RemoveService() { SC_HANDLE schService; SC_HANDLE schSCManager; -if (!service_name) -service_name = xstrdup(APP_SHORTNAME); +if (service_name.isEmpty()) +service_name = SBuf(APP_SHORTNAME); -strcat(REGKEY, service_name); +const char *service = service_name.c_str(); +strcat(REGKEY, service); -keys[4] = service_name; +keys[4] = service; schSCManager = OpenSCManager(NULL, /* machine (NULL == local)*/ NULL, /* database (NULL == default) */ SC_MANAGER_ALL_ACCESS /* access required */ ); if (!schSCManager) fprintf(stderr, "OpenSCManager failed\n"); else { -schService = OpenService(schSCManager, service_name, SERVICE_ALL_ACCESS); +schService = OpenService(schSCManager, service, SERVICE_ALL_ACCESS); if (schService == NULL) fprintf(stderr, "OpenService failed\n"); /* Could not open the service */ else { /* try to stop the service */ if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP, &svcStatus)) { sleep(1); while (QueryServiceStatus(schService, &svcStatus)) { if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) sleep(1); else break; } } /* now remove the service */ if (DeleteService(schService) == 0) fprintf(stderr, "DeleteService failed.\n"); else -printf("Service %s deleted successfully.\n", service_name); +printf("Service " SQUIDSBUFPH " deleted successfully.\n", SQUIDSBUFPRINT(service_name)); CloseServiceHandle(schService); } CloseServiceHandle(schSCManager); } } void WIN32_SetServiceCommandLine() { -if (!service_name) -service_name = xstrdup(APP_SHORTNAME); +if (service_name.isEmpty()) +service_name = SBuf(APP_SHORTNAME); -strcat(REGKEY, service_name); +const char *service = servie_name.c_str(); +strcat(REGKEY, service); -keys[4] = service_name; +keys[4] = service; /* Now store the Service Command Line in the registry */ WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1); } void WIN32_InstallService() { SC_HANDLE schService; SC_HANDLE schSCManager; char ServicePath[512]; char szPath[512]; int lenpath; -if (!service_name) -service_name = xstrdup(APP_SHORTNAME); +if (service_name.isEmpty()) +service_name = SBuf(APP_SHORTNAME); -strcat(REGKEY, service_name); +const char *service = service_name.c_str(); +strcat(REGKEY, service); -keys[4] = service_name; +keys[4] = service; if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
Re: [PATCH] validate -n parameter value
LGTM, only: Are the first two columns really necessary in the statement ::Parser::Tokenizer tok ? On Sun, Jun 15, 2014 at 8:05 AM, Amos Jeffries wrote: > Update the service_name global to an SBuf and use Tokenizer to validate > the -n argument is a pure alphanumeric. > > Amos -- Francesco
Re: [PATCH] validate -n parameter value
On 16/06/2014 9:32 p.m., Kinkie wrote: > LGTM, only: > Are the first two columns really necessary in the statement > ::Parser::Tokenizer tok > ? > Maybe not in this location. But its required in this "global" namespace location other namespaces I've been using it there was clashes with component-secific Parser classes. So I've been keeping consistency. Amos
Re: [PATCH] validate -n parameter value
On 06/15/2014 12:05 AM, Amos Jeffries wrote: > +if (optarg) { > +SBuf t(optarg); > +::Parser::Tokenizer tok(t); Pleaser remove "t" as used-once and lacking a descriptive name. If you insist on keeping it, please make it "const" and try to give it a more descriptive name such as rawName or serviceName. > +const CharacterSet chr = > CharacterSet::ALPHA+CharacterSet::DIGIT; Is there a document stating that only those characters are valid? My quick search resulted in [1] that seems to imply many other characters are accepted. However, [2] lists more prohibited characters. Both seem to allow "-" and "_" though. It would be good to provide a reference in the code or commit message to explain why we are restricting its value. Do you want to validate the total service name length? [1] says the limit is 256 characters. None of the above applies to -n used on Unix. Do we need to validate the service name (whatever that is) there? > +if (!tok.prefix(service_name, chr) || !tok.atEnd()) Please note that the above also rejects empty service names (-n ""). That may be good, but the error messages do not reflect that restriction. > +fatal("Need to provide alphanumeric service name when > using -n option"); > +opt_signal_service = true; > +} else { > +fatal("Need to provide alphanumeric service name when using > -n option"); > +} I recommend adjusting the fatal() messages to distinguish the two errors and avoid a possible misunderstanding that the service name was provided but was not alphanumeric in the second case: * Expected alphanumeric service name for the -n option but got: ... * A service name is required for the -n option. I continue to dislike the undefined -n option meaning on non-Windows boxes, but I have no objection to this patch and believe the above changes can be done without a new review cycle. Cheers, Alex. [1] http://msdn.microsoft.com/en-us/library/ms682450%28VS.85%29.aspx [2] http://www.anzio.com/resources/cannot-install-or-start-windows-service
Re: [PATCH] validate -n parameter value
On 17/06/2014 4:06 a.m., Alex Rousskov wrote: > On 06/15/2014 12:05 AM, Amos Jeffries wrote: >> +if (optarg) { >> +SBuf t(optarg); >> +::Parser::Tokenizer tok(t); > > Pleaser remove "t" as used-once and lacking a descriptive name. If you > insist on keeping it, please make it "const" and try to give it a more > descriptive name such as rawName or serviceName. > >> +const CharacterSet chr = >> CharacterSet::ALPHA+CharacterSet::DIGIT; > > Is there a document stating that only those characters are valid? My > quick search resulted in [1] that seems to imply many other characters > are accepted. However, [2] lists more prohibited characters. Both seem > to allow "-" and "_" though. It would be good to provide a reference in > the code or commit message to explain why we are restricting its value. > Arbitrary design choice for guaranteed portability. Other characters can be added if necessary, but most lack cross-platform usability for all the situations the service name string is being used. > Do you want to validate the total service name length? [1] says the > limit is 256 characters. > > None of the above applies to -n used on Unix. Do we need to validate the > service name (whatever that is) there? IMO portable consistency is better for this type of thing than being pedantically accepting for the OS-specific character sets. Yes, length needs to be checked. Thank you. Does an arbitrary 32 bytes seem acceptible since this is a prefix on the UDS sockets and paths which the final total still needs to fit within the 256 or so for some OS? > >> +if (!tok.prefix(service_name, chr) || !tok.atEnd()) > > Please note that the above also rejects empty service names (-n ""). > That may be good, but the error messages do not reflect that restriction. > > >> +fatal("Need to provide alphanumeric service name when >> using -n option"); >> +opt_signal_service = true; >> +} else { >> +fatal("Need to provide alphanumeric service name when using >> -n option"); >> +} > > I recommend adjusting the fatal() messages to distinguish the two errors > and avoid a possible misunderstanding that the service name was provided > but was not alphanumeric in the second case: > > * Expected alphanumeric service name for the -n option but got: ... > * A service name is required for the -n option. > "" is not an alphanumeric string. But okay. > > I continue to dislike the undefined -n option meaning on non-Windows > boxes, but I have no objection to this patch and believe the above > changes can be done without a new review cycle. > > > Cheers, > > Alex. > [1] http://msdn.microsoft.com/en-us/library/ms682450%28VS.85%29.aspx > [2] http://www.anzio.com/resources/cannot-install-or-start-windows-service >
Re: [PATCH] validate -n parameter value
On 23/06/2014 12:35 a.m., Amos Jeffries wrote: > On 17/06/2014 4:06 a.m., Alex Rousskov wrote: >> On 06/15/2014 12:05 AM, Amos Jeffries wrote: >>> +if (optarg) { >>> +SBuf t(optarg); >>> +::Parser::Tokenizer tok(t); >> >> Pleaser remove "t" as used-once and lacking a descriptive name. If you >> insist on keeping it, please make it "const" and try to give it a more >> descriptive name such as rawName or serviceName. > No can do on removal. Without it we get: error: request for member 'prefix' in 'tok', which is of non-class type 'Parser::Tokenizer(SBuf)' if (!tok.prefix(service_name, chr) || !tok.atEnd()) ^ error: request for member 'atEnd' in 'tok', which is of non-class type 'Parser::Tokenizer(SBuf)' if (!tok.prefix(service_name, chr) || !tok.atEnd()) ^ const seems to be fine though. >> >>> +const CharacterSet chr = >>> CharacterSet::ALPHA+CharacterSet::DIGIT; >> >> Is there a document stating that only those characters are valid? My >> quick search resulted in [1] that seems to imply many other characters >> are accepted. However, [2] lists more prohibited characters. Both seem >> to allow "-" and "_" though. It would be good to provide a reference in >> the code or commit message to explain why we are restricting its value. >> > > Arbitrary design choice for guaranteed portability. Other characters can > be added if necessary, but most lack cross-platform usability for all > the situations the service name string is being used. > > >> Do you want to validate the total service name length? [1] says the >> limit is 256 characters. >> >> None of the above applies to -n used on Unix. Do we need to validate the >> service name (whatever that is) there? > > IMO portable consistency is better for this type of thing than being > pedantically accepting for the OS-specific character sets. > > Yes, length needs to be checked. Thank you. > > Does an arbitrary 32 bytes seem acceptible since this is a prefix on the > UDS sockets and paths which the final total still needs to fit within > the 256 or so for some OS? Taking absence of a response as a yes. Fixed. >> >>> +if (!tok.prefix(service_name, chr) || !tok.atEnd()) >> >> Please note that the above also rejects empty service names (-n ""). >> That may be good, but the error messages do not reflect that restriction. >> Moved this to an explicit check on *optarg content so it is obviously intentional and gets the right "missing service name" error. >> >>> +fatal("Need to provide alphanumeric service name when >>> using -n option"); >>> +opt_signal_service = true; >>> +} else { >>> +fatal("Need to provide alphanumeric service name when >>> using -n option"); >>> +} >> >> I recommend adjusting the fatal() messages to distinguish the two errors >> and avoid a possible misunderstanding that the service name was provided >> but was not alphanumeric in the second case: >> >> * Expected alphanumeric service name for the -n option but got: ... >> * A service name is required for the -n option. >> > > "" is not an alphanumeric string. But okay. > >> >> I continue to dislike the undefined -n option meaning on non-Windows >> boxes, but I have no objection to this patch and believe the above >> changes can be done without a new review cycle. -n means the same on all boxes. Windows default is "squid" just like the rest. Updates made and applied to trunk. Amos
Re: [PATCH] validate -n parameter value
On 07/14/2014 07:02 AM, Amos Jeffries wrote: > Alex Rousskov wrote: >> I continue to dislike the undefined -n option meaning on non-Windows > -n means the same on all boxes. I am guessing that Windows have a standard concept of a "service" and there is an interface for setting and getting the service name (and possibly for other "service operations"). On Unix, a lot of things may be called services, and "service" term use in interfaces such as ICAP and System V init scripts is standard, but I cannot think of any formal Unix interface that matches what Squid is doing with -n on Unix. We define -n as "service name to use for service operations", but I do not know what those "service operations" are in a Unix context. If most admins know what that means, there is no problem. Hope this clarifies, Alex.
Re: [PATCH] validate -n parameter value
On 07/14/2014 07:02 AM, Amos Jeffries wrote: > On 23/06/2014 12:35 a.m., Amos Jeffries wrote: >> On 17/06/2014 4:06 a.m., Alex Rousskov wrote: >>> On 06/15/2014 12:05 AM, Amos Jeffries wrote: +if (optarg) { +SBuf t(optarg); +::Parser::Tokenizer tok(t); >>> >>> Pleaser remove "t" as used-once and lacking a descriptive name. If you >>> insist on keeping it, please make it "const" and try to give it a more >>> descriptive name such as rawName or serviceName. > No can do on removal. Without it we get: > error: request for member 'prefix' in 'tok', which is of non-class type > 'Parser::Tokenizer(SBuf)' Yeah, we appear to hit some hairy C++ concept here that I cannot fully reconstruct. I could not find an explanation by quick googling (all results point to trivial cases of declaring a function instead of calling the default constructor). The following works for me: ::Parser::Tokenizer tok(SBuf(optarg, SBuf::npos)); However, at this point, it is not clear whether the extra "t" temporary is actually worse than the extra SBuf argument! If you keep "t", a more descriptive name for t would be nice but obviously not required. +if (!tok.prefix(service_name, chr) || !tok.atEnd()) >>> >>> Please note that the above also rejects empty service names (-n ""). >>> That may be good, but the error messages do not reflect that restriction. >>> > > Moved this to an explicit check on *optarg content so it is obviously > intentional and gets the right "missing service name" error. The adjusted if condition in the committed code appears to dereference a nil pointer when the service name is missing: > if (optarg || *optarg == '\0') { The code actually does not get that far because getopt() does not allow a missing service name (at least in my tests), but the condition should be fixed. HTH, Alex.
Re: [PATCH] validate -n parameter value
On 16/07/2014 10:53 a.m., Alex Rousskov wrote: > On 07/14/2014 07:02 AM, Amos Jeffries wrote: >> On 23/06/2014 12:35 a.m., Amos Jeffries wrote: >>> On 17/06/2014 4:06 a.m., Alex Rousskov wrote: On 06/15/2014 12:05 AM, Amos Jeffries wrote: > +if (optarg) { > +SBuf t(optarg); > +::Parser::Tokenizer tok(t); Pleaser remove "t" as used-once and lacking a descriptive name. If you insist on keeping it, please make it "const" and try to give it a more descriptive name such as rawName or serviceName. > > >> No can do on removal. Without it we get: >> error: request for member 'prefix' in 'tok', which is of non-class type >> 'Parser::Tokenizer(SBuf)' > > > Yeah, we appear to hit some hairy C++ concept here that I cannot fully > reconstruct. I could not find an explanation by quick googling (all > results point to trivial cases of declaring a function instead of > calling the default constructor). > > The following works for me: > > ::Parser::Tokenizer tok(SBuf(optarg, SBuf::npos)); > > However, at this point, it is not clear whether the extra "t" temporary > is actually worse than the extra SBuf argument! If you keep "t", a more > descriptive name for t would be nice but obviously not required. > > > +if (!tok.prefix(service_name, chr) || !tok.atEnd()) Please note that the above also rejects empty service names (-n ""). That may be good, but the error messages do not reflect that restriction. >> >> Moved this to an explicit check on *optarg content so it is obviously >> intentional and gets the right "missing service name" error. > > The adjusted if condition in the committed code appears to dereference a > nil pointer when the service name is missing: > >> if (optarg || *optarg == '\0') { > > The code actually does not get that far because getopt() does not allow > a missing service name (at least in my tests), but the condition should > be fixed. Ouch. Fixed now. Amos