/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 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. 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 * . * * 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 (SetLastError(rv), rv); ap_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; ap_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); } ap_status_t ap_registry_delete_key(const char *key) { ap_status_t rv; HKEY hKey; int nSize = 0; char tempkey[MAX_PATH + 1]; char *parsekey; ap_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_FILE_NOT_FOUND) return APR_ENODIR; 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_ENOPATH, APR_NOTFOUND, or the OS error */ ap_status_t ap_registry_get_value(ap_pool_t *p, const char *key, const char *name, char **ppValue) { ap_status_t rv; HKEY hKey; int nSize = 0; rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey); if (rv == ERROR_FILE_NOT_FOUND) return APR_ENODIR; 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 = ap_palloc(p, nSize); rv = RegQueryValueEx(hKey, name, /* key name */ NULL, /* reserved */ NULL, /* type */ *ppValue, /* for value */ &nSize); /* for size of "value" */ if (rv == ERROR_FILE_NOT_FOUND) rv = APR_NOTFOUND; RegCloseKey(hKey); return_error(rv); } ap_status_t ap_registry_get_array(ap_pool_t *p, const char *key, const char *name, ap_array_header_t **parray) { char *pValue; char *tmp; char **newelem; ap_status_t rv; HKEY hKey; int nSize = 0; rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey); if (rv == ERROR_FILE_NOT_FOUND) return APR_ENODIR; 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_FILE_NOT_FOUND) { rv = APR_NOTFOUND; } else if (rv != ERROR_SUCCESS) { return_error(rv); } else { pValue = ap_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 = ap_make_array(p, nSize, sizeof(char *)); tmp = pValue; newelem = (char **) ap_push_array(*parray); *newelem = tmp; while (tmp[0] || tmp[1]) { if (!tmp[0]) { newelem = (char **) ap_push_array(*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(). */ ap_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_FILE_NOT_FOUND) return APR_ENODIR; } 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); } ap_status_t ap_registry_store_array(ap_pool_t *p, const char *key, const char *name, int nelts, char const* 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_FILE_NOT_FOUND) return APR_ENODIR; } 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 = ap_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. */ ap_status_t ap_registry_delete_value(const char *key, const char *name) { ap_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. */ ap_status_t ap_registry_get_server_root(ap_pool_t *p, char **buf) { ap_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(). */ ap_status_t ap_registry_set_server_root(char *dir) { return ap_registry_store_value(REGKEY, "ServerRoot", dir); }