| /* ==================================================================== |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2000-2001 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. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Apache" 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 name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``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. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| * |
| * Portions of this software are based upon public domain software |
| * originally written at the National Center for Supercomputing Applications, |
| * University of Illinois, Urbana-Champaign. |
| */ |
| |
| /* |
| * 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. |
| */ |
| |
| #include "httpd.h" |
| #include "http_log.h" |
| #include "mpm_winnt.h" |
| #include "apr_strings.h" |
| |
| /* bet you are looking to change revisions to roll the tarball... |
| * Guess what, you already did. Revised May '00 to save you from |
| * searching all over creation for every revision tag. |
| */ |
| |
| #define VENDOR AP_SERVER_BASEVENDOR |
| #define SOFTWARE AP_SERVER_BASEPRODUCT |
| #define VERSION AP_SERVER_BASEREVISION |
| |
| #define REGKEY "SOFTWARE\\" VENDOR "\\" SOFTWARE "\\" VERSION |
| |
| /* |
| * 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 return_error(rv) return (apr_set_os_error(APR_FROM_OS_ERROR(rv)),\ |
| APR_FROM_OS_ERROR(rv)); |
| |
| apr_status_t ap_registry_create_key(const char *key) |
| { |
| HKEY hKey = HKEY_LOCAL_MACHINE; |
| HKEY hKeyNext; |
| char keystr[MAX_PATH + 1]; |
| char *parsekey = keystr; |
| char *nextkey = keystr; |
| DWORD result; |
| int rv; |
| |
| apr_cpystrn(keystr, key, sizeof(keystr) - 1); |
| |
| /* Walk the tree, creating at each stage if necessary */ |
| while (parsekey) { |
| if (nextkey = strchr(parsekey, '\\')) |
| *(nextkey++) = '\0'; |
| |
| rv = RegCreateKeyEx(hKey, |
| parsekey, /* subkey */ |
| 0, /* reserved */ |
| NULL, /* class */ |
| REG_OPTION_NON_VOLATILE, |
| KEY_WRITE, |
| NULL, |
| &hKeyNext, |
| &result); |
| |
| /* Close the old key */ |
| if (hKey != HKEY_LOCAL_MACHINE) |
| RegCloseKey(hKey); |
| hKey = hKeyNext; |
| |
| if (rv != ERROR_SUCCESS) |
| break; |
| |
| parsekey = nextkey; |
| } |
| |
| if (hKey != HKEY_LOCAL_MACHINE) |
| RegCloseKey(hKey); |
| |
| return_error(rv); |
| } |
| |
| apr_status_t ap_registry_delete_key(const char *key) |
| { |
| apr_status_t rv; |
| HKEY hKey; |
| int nSize = 0; |
| char tempkey[MAX_PATH + 1]; |
| char *parsekey; |
| |
| apr_cpystrn(tempkey, key, sizeof(parsekey) - 1); |
| parsekey = strrchr(tempkey, '\\'); |
| |
| if (parsekey) { |
| *(parsekey++) = '\0'; |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| tempkey, |
| 0, |
| KEY_WRITE, |
| &hKey); |
| |
| if (rv != ERROR_SUCCESS) |
| return_error(rv); |
| } |
| else { |
| parsekey = tempkey; |
| hKey = HKEY_LOCAL_MACHINE; |
| } |
| |
| rv = RegDeleteKey(hKey, key); |
| |
| if (hKey != HKEY_LOCAL_MACHINE) |
| RegCloseKey(hKey); |
| |
| return_error(rv); |
| } |
| |
| /* Clean up a way over complicated process. |
| * |
| * The return value is APR_SUCCESS, APR_ENOENT, APR_NOTFOUND, or the OS error |
| */ |
| |
| apr_status_t ap_registry_get_value(apr_pool_t *p, const char *key, const char *name, char **ppValue) |
| { |
| apr_status_t rv; |
| HKEY hKey; |
| int nSize = 0; |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_READ, |
| &hKey); |
| |
| if (rv != ERROR_SUCCESS) |
| return_error(rv); |
| |
| /* 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) |
| return_error(rv); |
| |
| *ppValue = apr_palloc(p, nSize); |
| rv = RegQueryValueEx(hKey, |
| name, /* key name */ |
| NULL, /* reserved */ |
| NULL, /* type */ |
| *ppValue, /* for value */ |
| &nSize); /* for size of "value" */ |
| |
| RegCloseKey(hKey); |
| |
| return_error(rv); |
| } |
| |
| apr_status_t ap_registry_get_array(apr_pool_t *p, const char *key, const char *name, apr_array_header_t **parray) |
| { |
| char *pValue; |
| char *tmp; |
| char **newelem; |
| apr_status_t rv; |
| HKEY hKey; |
| int nSize = 0; |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_READ, |
| &hKey); |
| |
| if (rv != ERROR_SUCCESS) |
| return_error(rv); |
| |
| /* 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) { |
| return_error(rv); |
| } |
| else |
| { |
| pValue = apr_palloc(p, nSize); |
| rv = RegQueryValueEx(hKey, |
| name, /* key name */ |
| NULL, /* reserved */ |
| NULL, /* type */ |
| pValue, /* for value */ |
| &nSize); /* for size of "value" */ |
| |
| nSize = 1; /* Element Count */ |
| tmp = pValue; |
| while (tmp[0] || tmp[1]) |
| { |
| if (!tmp[0]) |
| ++nSize; |
| ++tmp; |
| } |
| |
| *parray = apr_array_make(p, nSize, sizeof(char *)); |
| tmp = pValue; |
| newelem = (char **) apr_array_push(*parray); |
| *newelem = tmp; |
| while (tmp[0] || tmp[1]) |
| { |
| if (!tmp[0]) { |
| newelem = (char **) apr_array_push(*parray); |
| *newelem = tmp + 1; |
| } |
| ++tmp; |
| } |
| } |
| |
| RegCloseKey(hKey); |
| |
| return_error(rv); |
| } |
| |
| /* |
| * ap_registry_store_key_value() 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_value()). |
| * If the return value is negative then the error will already have been |
| * logged via aplog_error(). |
| */ |
| |
| apr_status_t ap_registry_store_value(const char *key, const char *name, const char *value) |
| { |
| long rv; |
| HKEY hKey; |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_WRITE, |
| &hKey); |
| |
| if (rv == ERROR_FILE_NOT_FOUND) |
| { |
| rv = ap_registry_create_key(key); |
| |
| if (rv != APR_SUCCESS) |
| return_error(rv); |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_WRITE, |
| &hKey); |
| } |
| |
| if (rv != ERROR_SUCCESS) |
| return_error(rv); |
| |
| /* Now set the value and data */ |
| rv = RegSetValueEx(hKey, |
| name, /* value key name */ |
| 0, /* reserved */ |
| REG_SZ, /* type */ |
| value, /* value data */ |
| (DWORD) strlen(value) + 1); /* for size of "value" */ |
| |
| if (rv == ERROR_SUCCESS) { |
| ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,rv,NULL, |
| "Registry stored HKLM\\" REGKEY "\\%s value %s", key, value); |
| } |
| |
| /* Make sure we close the key even if there was an error storing |
| * the data |
| */ |
| RegCloseKey(hKey); |
| |
| return_error(rv); |
| } |
| |
| apr_status_t ap_registry_store_array(apr_pool_t *p, |
| const char *key, const char *name, |
| int nelts, const char * const * elts) |
| { |
| int bufsize, i; |
| char *buf, *tmp; |
| long rv; |
| HKEY hKey; |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_WRITE, |
| &hKey); |
| |
| if (rv == ERROR_FILE_NOT_FOUND) |
| { |
| rv = ap_registry_create_key(key); |
| |
| if (rv != APR_SUCCESS) |
| return_error(rv); |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_WRITE, |
| &hKey); |
| } |
| |
| if (rv != ERROR_SUCCESS) |
| return_error(rv); |
| |
| bufsize = 1; /* For trailing second null */ |
| for (i = 0; i < nelts; ++i) |
| { |
| bufsize += strlen(elts[i]) + 1; |
| } |
| if (!nelts) |
| ++bufsize; |
| |
| buf = apr_palloc(p, bufsize); |
| tmp = buf; |
| for (i = 0; i < nelts; ++i) |
| { |
| strcpy(tmp, elts[i]); |
| tmp += strlen(elts[i]) + 1; |
| } |
| if (!nelts) |
| (*tmp++) = '\0'; |
| *tmp = '\0'; /* Trailing second null */ |
| |
| /* Now set the value and data */ |
| rv = RegSetValueEx(hKey, |
| name, /* value key name */ |
| 0, /* reserved */ |
| REG_MULTI_SZ, /* type */ |
| buf, /* value data */ |
| (DWORD) bufsize); /* for size of "value" */ |
| |
| if (rv == ERROR_SUCCESS) { |
| ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,rv,NULL, |
| "Registry stored HKLM\\" REGKEY "\\%s", key); |
| } |
| |
| /* Make sure we close the key even if there was an error storing |
| * the data |
| */ |
| RegCloseKey(hKey); |
| |
| return_error(rv); |
| } |
| |
| /* A key or value that does not exist is _not_ an error while deleting. */ |
| |
| apr_status_t ap_registry_delete_value(const char *key, const char *name) |
| { |
| apr_status_t rv; |
| HKEY hKey; |
| |
| rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, |
| key, |
| 0, |
| KEY_WRITE, |
| &hKey); |
| |
| if (rv == ERROR_FILE_NOT_FOUND) |
| return APR_SUCCESS; |
| |
| if (rv != ERROR_SUCCESS) |
| return_error(rv); |
| |
| rv = RegDeleteValue(hKey, name); |
| |
| if (rv == ERROR_FILE_NOT_FOUND) |
| rv = APR_SUCCESS; |
| |
| RegCloseKey(hKey); |
| return_error(rv); |
| } |
| |
| /* |
| * 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. |
| */ |
| apr_status_t ap_registry_get_server_root(apr_pool_t *p, char **buf) |
| { |
| apr_status_t rv; |
| |
| rv = ap_registry_get_value(p, REGKEY, "ServerRoot", buf); |
| if (rv) |
| *buf = NULL; |
| |
| return rv; |
| } |
| |
| |
| /* |
| * 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(). |
| */ |
| |
| apr_status_t ap_registry_set_server_root(char *dir) |
| { |
| return ap_registry_store_value(REGKEY, "ServerRoot", dir); |
| } |