| /* ==================================================================== |
| * Copyright (c) 1995-2000 The Apache Software Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. All advertising materials mentioning features or use of this |
| * software must display the following acknowledgment: |
| * "This product includes software developed by the Apache Software Foundation |
| * for use in the Apache HTTP server project (http://www.apache.org/)." |
| * |
| * 4. The names "Apache Server" and "Apache Software Foundation" must not be used to |
| * endorse or promote products derived from this software without |
| * prior written permission. For written permission, please contact |
| * apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * 6. Redistributions of any form whatsoever must retain the following |
| * acknowledgment: |
| * "This product includes software developed by the Apache Software Foundation |
| * for use in the Apache HTTP server project (http://www.apache.org/)." |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE Apache Software Foundation ``AS IS'' AND ANY |
| * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE Apache Software Foundation OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| * OF THE POSSIBILITY OF SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was originally based |
| * on public domain software written at the National Center for |
| * Supercomputing Applications, University of Illinois, Urbana-Champaign. |
| * For more information on the Apache Software Foundation and the Apache HTTP server |
| * project, please see <http://www.apache.org/>. |
| * |
| */ |
| |
| /* |
| * Functions to handle interacting with the Win32 registry |
| */ |
| |
| /* |
| * Apache registry key structure |
| * |
| * Apache's registry information is stored in the HKEY_LOCAL_MACHINE |
| * key, under |
| * |
| * HKLM\SOFTWARE\Apache Software Foundation\Apache\version |
| * |
| * These keys are defined in this file. The definition of the "version" part |
| * will need updating each time Apache moves from beta to non-beta or from a |
| * release to a development or beta version. |
| */ |
| |
| /* To allow for multiple services, store the configuration file's full path |
| * under each service entry: |
| * |
| * HKLM\System\CurrentControlSet\Services\[service name]\Parameters\ConfPath |
| * |
| * The default configuration path (for console apache) is still stored: |
| * |
| * HKLM\Software\[Vendor]\[Software]\[Version]\ServerRoot |
| */ |
| #include "os.h" |
| //#include <windows.h> |
| //#include <stdio.h> |
| |
| #include "httpd.h" |
| #include "http_log.h" |
| |
| /* Define where the Apache values are stored in the registry. In general |
| * VERSION will be the same across all beta releases for a particular |
| * major release, but will change when the final release is made. |
| */ |
| |
| #define VENDOR "Apache Software Foundation" |
| #define SOFTWARE "Apache" |
| #define VERSION "2.0" |
| |
| #define REGKEY "SOFTWARE\\" VENDOR "\\" SOFTWARE "\\" VERSION |
| |
| #define SERVICEKEYPRE "System\\CurrentControlSet\\Services\\" |
| #define SERVICEKEYPOST "\\Parameters" |
| |
| /* |
| * The Windows API registry key functions don't set the last error |
| * value (the windows equivalent of errno). So we need to set it |
| * with SetLastError() before calling the aplog_error() function. |
| * Because this is common, let's have a macro. |
| */ |
| #define do_error(rv,fmt,arg) do { \ |
| ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, fmt, arg); \ |
| } while (0); |
| |
| /* |
| * Get the data for registry key value. This is a generic function that |
| * can either get a value into a caller-supplied buffer, or it can |
| * allocate space for the value from the pass in pool. It will normally |
| * be used by other functions within this file to get specific key values |
| * (e.g. registry_get_server_root()). This function returns a number of |
| * different error statuses, allowing the caller to differentiate |
| * between a key or value not existing and other kinds of errors. Depending |
| * on the type of data being obtained the caller can then either ignore |
| * the key-not-existing error, or treat it as a real error. |
| * |
| * If ppValue is NULL, allocate space for the value and return it in |
| * *pValue. The return value is the number of bytes in the value. |
| * The first argument is the ap_context_t to use to allocate space for the value. |
| * |
| * If pValue is not NULL, assume it is a buffer of nSizeValue bytes, |
| * and write the value into the buffer. The return value is the number |
| * of bytes in the value (so if the return value is greater than |
| * the supplied nSizeValue, the caller knows that *pValue is truncated). |
| * The ap_context_t argument is ignored. |
| * |
| * The return value is the number of bytes in the successfully retreived |
| * key if everything worked, or: |
| * |
| * -1 the key does not exists |
| * -2 if out of memory during the function |
| * -3 if the buffer specified by *pValue/nSizeValue was not large enough |
| * for the value. |
| * -4 if an error occurred |
| * |
| * If the return value is negative a message will be logged to the error |
| * log (aplog_error) function. If the return value is -2, -3 or -4 the message |
| * will be logged at priority "error", while if the return value is -1 the |
| * message will be logged at priority "warning". |
| */ |
| |
| static int ap_registry_get_key_int(ap_context_t *p, char *key, char *name, char *pBuffer, int nSizeBuffer, char **ppValue) |
| { |
| long rv; |
| HKEY hKey; |
| char *pValue; |
| int nSize; |
| int retval; |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_READ, |
| &hKey); |
| |
| if (rv == ERROR_FILE_NOT_FOUND) { |
| ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,rv,NULL, |
| "Registry does not contain key %s",key); |
| return -1; |
| } |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegOpenKeyEx HKLM\\%s",key); |
| return -4; |
| } |
| |
| if (pBuffer == NULL) { |
| /* Find the size required for the data by passing NULL as the buffer |
| * pointer. On return nSize will contain the size required for the |
| * buffer if the return value is ERROR_SUCCESS. |
| */ |
| rv = RegQueryValueEx(hKey, |
| name, /* key name */ |
| NULL, /* reserved */ |
| NULL, /* type */ |
| NULL, /* for value */ |
| &nSize); /* for size of "value" */ |
| |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegQueryValueEx(key %s)", key); |
| return -1; |
| } |
| |
| pValue = ap_palloc(p, nSize); |
| *ppValue = pValue; |
| if (!pValue) { |
| /* Eek, out of memory, probably not worth trying to carry on, |
| * but let's give it a go |
| */ |
| ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,APR_ENOMEM,NULL, |
| "Error getting registry key: out of memory"); |
| return -2; |
| } |
| } |
| else { |
| /* Get the value into the existing buffer of length nSizeBuffer */ |
| pValue = pBuffer; |
| nSize = nSizeBuffer; |
| } |
| |
| rv = RegQueryValueEx(hKey, |
| name, /* key name */ |
| NULL, /* reserved */ |
| NULL, /* type */ |
| pValue, /* for value */ |
| &nSize); /* for size of "value" */ |
| |
| retval = 0; /* Return value */ |
| |
| if (rv == ERROR_FILE_NOT_FOUND) { |
| ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,rv,NULL, |
| "Registry does not contain value %s\\%s", key, name); |
| retval = -1; |
| } |
| else if (rv == ERROR_MORE_DATA) { |
| /* This should only happen if we got passed a pre-existing buffer |
| * (pBuffer, nSizeBuffer). But I suppose it could also happen if we |
| * allocate a buffer if another process changed the length of the |
| * value since we found out its length above. Umm. |
| */ |
| ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,rv,NULL, |
| "Error getting registry value %s: buffer not big enough", key); |
| retval = -3; |
| } |
| else if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegQueryValueEx(key %s)", key); |
| retval = -4; |
| } |
| |
| rv = RegCloseKey(hKey); |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegCloseKey HKLM\\%s", key); |
| if (retval == 0) { |
| /* Keep error status from RegQueryValueEx, if any */ |
| retval = -4; |
| } |
| } |
| |
| return retval < 0 ? retval : nSize; |
| } |
| |
| /* |
| * Get the server root from the registry into 'dir' which is |
| * size bytes long. Returns 0 if the server root was found |
| * or if the serverroot key does not exist (in which case |
| * dir will contain an empty string), or -1 if there was |
| * an error getting the key. |
| */ |
| #if 0 |
| int ap_registry_get_server_root(ap_context_t *p, char *dir, int size) |
| { |
| int rv; |
| |
| rv = ap_registry_get_key_int(p, REGKEY, "ServerRoot", dir, size, NULL); |
| if (rv < 0) { |
| dir[0] = '\0'; |
| } |
| |
| return (rv < -1) ? -1 : 0; |
| } |
| #else |
| int ap_registry_get_server_root(ap_context_t *p, char **buf) |
| { |
| int rv; |
| |
| rv = ap_registry_get_key_int(p, REGKEY, "ServerRoot", NULL, 0, buf); |
| if (rv < 0) { |
| *buf = NULL; |
| } |
| |
| return (rv < -1) ? -1 : 0; |
| } |
| #endif |
| char *ap_get_service_key(char *service_name) |
| { |
| char *key = malloc(strlen(SERVICEKEYPRE) + |
| strlen(service_name) + |
| strlen(SERVICEKEYPOST) + 1); |
| |
| sprintf(key,"%s%s%s", SERVICEKEYPRE, service_name, SERVICEKEYPOST); |
| |
| return(key); |
| } |
| #if 0 |
| int ap_registry_get_service_conf(ap_context_t *p, char *dir, int size, char *service_name) |
| { |
| int rv; |
| char *key = ap_get_service_key(service_name); |
| |
| rv = ap_registry_get_key_int(p, key, "ConfPath", dir, size, NULL); |
| if (rv < 0) { |
| dir[0] = '\0'; |
| } |
| |
| free(key); |
| return (rv < -1) ? -1 : 0; |
| } |
| #else |
| int ap_registry_get_service_conf(ap_context_t *p, char **buf, char *service_name) |
| { |
| int rv; |
| char *key = ap_get_service_key(service_name); |
| |
| rv = ap_registry_get_key_int(p, key, "ConfPath", NULL, 0, buf); |
| if (rv < 0) { |
| *buf = NULL; |
| } |
| |
| free(key); |
| return (rv < -1) ? -1 : 0; |
| } |
| #endif |
| |
| /********************************************************************** |
| * The rest of this file deals with storing keys or values in the registry |
| */ |
| |
| char *ap_registry_parse_key(int index, char *key) |
| { |
| char *head = key, *skey; |
| int i; |
| |
| if(!key) |
| return(NULL); |
| |
| for(i = 0; i <= index; i++) |
| { |
| if(key && key[0] == '\\') |
| key++; |
| if (!key) |
| return(NULL); |
| head = key; |
| key = strchr(head, '\\'); |
| } |
| |
| if(!key) |
| return(strdup(head)); |
| *key = '\0'; |
| skey = strdup(head); |
| *key = '\\'; |
| return(skey); |
| } |
| |
| /* |
| * ap_registry_create_apache_key() creates the Apache registry key |
| * (HLKM\SOFTWARE\Apache Software Foundation\Apache\version, as defined at the start |
| * of this file), if it does not already exist. It will be called by |
| * ap_registry_store_key_int() if it cannot open this key. This |
| * function is intended to be called by ap_registry_store_key_int() if |
| * the Apache key does not exist when it comes to store a data item. |
| * |
| * Returns 0 on success or -1 on error. If -1 is returned, the error will |
| * already have been logged. |
| */ |
| |
| static int ap_registry_create_key(char *longkey) |
| { |
| int index; |
| HKEY hKey; |
| HKEY hKeyNext; |
| int retval; |
| int rv; |
| char *key; |
| |
| hKey = HKEY_LOCAL_MACHINE; |
| index = 0; |
| retval = 0; |
| |
| /* Walk the tree, creating at each stage if necessary */ |
| while (key=ap_registry_parse_key(index,longkey)) { |
| int result; |
| |
| rv = RegCreateKeyEx(hKey, |
| key, /* subkey */ |
| 0, /* reserved */ |
| NULL, /* class */ |
| REG_OPTION_NON_VOLATILE, |
| KEY_WRITE, |
| NULL, |
| &hKeyNext, |
| &result); |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegCreateKeyEx(%s)", longkey); |
| retval = -4; |
| } |
| |
| /* Close the old key */ |
| rv = RegCloseKey(hKey); |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegCloseKey", NULL); |
| if (retval == 0) { |
| /* Keep error status from RegCreateKeyEx, if any */ |
| retval = -4; |
| } |
| } |
| |
| if (retval) { |
| break; |
| } |
| |
| free(key); |
| hKey = hKeyNext; |
| index++; |
| } |
| |
| if (!key) { |
| /* Close the final key we opened, if we walked the entire |
| * tree |
| */ |
| rv = RegCloseKey(hKey); |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegCloseKey", NULL); |
| if (retval == 0) { |
| /* Keep error status from RegCreateKeyEx, if any */ |
| retval = -4; |
| } |
| } |
| } |
| else |
| free(key); |
| |
| return retval; |
| } |
| |
| /* |
| * ap_registry_store_key_int() stores a value name and value under the |
| * Apache registry key. If the Apache key does not exist it is created |
| * first. This function is intended to be called from a wrapper function |
| * in this file to set particular data values, such as |
| * ap_registry_set_server_root() below. |
| * |
| * Returns 0 if the value name and data was stored successfully, or |
| * returns -1 if the Apache key does not exist (since we try to create |
| * this key, this should never happen), or -4 if any other error occurred |
| * (these values are consistent with ap_registry_get_key_int()). |
| * If the return value is negative then the error will already have been |
| * logged via aplog_error(). |
| */ |
| |
| static int ap_registry_store_key_int(char *key, char *name, DWORD type, void *value, int value_size) |
| { |
| long rv; |
| HKEY hKey; |
| int retval; |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_WRITE, |
| &hKey); |
| |
| if (rv == ERROR_FILE_NOT_FOUND) { |
| /* Key could not be opened -- try to create it |
| */ |
| if (ap_registry_create_key(key) < 0) { |
| /* Creation failed (error already reported) */ |
| return -4; |
| } |
| |
| /* Now it has been created we should be able to open it |
| */ |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_WRITE, |
| &hKey); |
| |
| if (rv == ERROR_FILE_NOT_FOUND) { |
| ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,rv,NULL, |
| "Registry does not contain key %s after creation",key); |
| return -1; |
| } |
| } |
| |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegOpenKeyEx HKLM\\%s", key); |
| return -4; |
| } |
| |
| /* Now set the value and data */ |
| rv = RegSetValueEx(hKey, |
| name, /* value key name */ |
| 0, /* reserved */ |
| type, /* type */ |
| value, /* value data */ |
| (DWORD)value_size); /* for size of "value" */ |
| |
| retval = 0; /* Return value */ |
| |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegQueryValueEx(key %s)", key); |
| retval = -4; |
| } |
| else { |
| ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,rv,NULL, |
| "Registry stored HKLM\\" REGKEY "\\%s value %s", key, |
| type == REG_SZ ? value : "(not displayable)"); |
| } |
| |
| /* Make sure we close the key even if there was an error storing |
| * the data |
| */ |
| rv = RegCloseKey(hKey); |
| if (rv != ERROR_SUCCESS) { |
| do_error(rv, "RegCloseKey HKLM\\%s", key); |
| if (retval == 0) { |
| /* Keep error status from RegQueryValueEx, if any */ |
| retval = -4; |
| } |
| } |
| |
| return retval; |
| } |
| |
| /* |
| * Sets the service confpath value within the registry. Returns 0 on success |
| * or -1 on error. If -1 is return the error will already have been |
| * logged via aplog_error(). |
| */ |
| |
| int ap_registry_set_service_conf(char *conf, char *service_name) |
| { |
| int rv; |
| char *key = ap_get_service_key(service_name); |
| |
| rv = ap_registry_store_key_int(key, "ConfPath", REG_SZ, conf, strlen(conf)+1); |
| free(key); |
| |
| return rv < 0 ? -1: 0; |
| } |
| |
| /* |
| * Sets the serverroot value within the registry. Returns 0 on success |
| * or -1 on error. If -1 is return the error will already have been |
| * logged via aplog_error(). |
| */ |
| |
| int ap_registry_set_server_root(char *dir) |
| { |
| int rv; |
| |
| rv = ap_registry_store_key_int(REGKEY, "ServerRoot", REG_SZ, dir, strlen(dir)+1); |
| |
| return rv < 0 ? -1 : 0; |
| } |
| |