From: Harald Radi Date: Wed, 10 Jul 2002 20:27:17 +0000 (+0000) Subject: merging parts of the old com extension to the new rpc extension X-Git-Tag: dev~370 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=77f1d265be2cf2b594721c1d129f2c36e1f2dbd8;p=php merging parts of the old com extension to the new rpc extension --- diff --git a/ext/rpc/com/com.c b/ext/rpc/com/com.c index 0b51925ed7..c597e7a869 100644 --- a/ext/rpc/com/com.c +++ b/ext/rpc/com/com.c @@ -1,8 +1,18 @@ +#define _WIN32_DCOM + +#include "../handler.h" +#include "../php_rpc.h" + #include "com.h" +#include "com_wrapper.h" +#include "conversion.h" + +#include + /* protos */ -static int com_hash(rpc_string, rpc_string *, int, char *, int); -static int com_name(rpc_string, rpc_string *, int); +static int com_hash(rpc_string, rpc_string *, void *, int, char *, int); +static int com_name(rpc_string, rpc_string *, void *, int); static int com_ctor(rpc_string, void **, int , zval ***); static int com_dtor(void **); static int com_call(rpc_string, void **, zval **, int, zval ***); @@ -13,6 +23,12 @@ static int com_has_property(rpc_string, void **); static int com_unset_property(rpc_string, void **); static int com_get_properties(HashTable **, void **); +static PHP_INI_MH(OnTypelibFileChange); + + +/* globals */ +static IBindCtx *pBindCtx; + /* register rpc callback function */ RPC_REGISTER_HANDLERS_START(com) @@ -37,6 +53,7 @@ PHP_INI_ENTRY_EX("com.allow_dcom", "0", PHP_INI_SYSTEM, NULL, php_ini_boolean_di PHP_INI_ENTRY_EX("com.autoregister_typelib", "0", PHP_INI_SYSTEM, NULL, php_ini_boolean_displayer_cb) PHP_INI_ENTRY_EX("com.autoregister_verbose", "0", PHP_INI_SYSTEM, NULL, php_ini_boolean_displayer_cb) PHP_INI_ENTRY_EX("com.autoregister_casesensitive", "1", PHP_INI_SYSTEM, NULL, php_ini_boolean_displayer_cb) +PHP_INI_ENTRY("com.typelib_file", "", PHP_INI_SYSTEM, OnTypelibFileChange) RPC_INI_END() /* register userspace functions */ @@ -52,33 +69,351 @@ RPC_METHOD_ENTRY_START(com) ZEND_FALIAS(release, com_release, NULL) RPC_METHOD_ENTRY_END() + /* init function that is called before the class is registered * so you can do any tricky stuff in here */ RPC_INIT_FUNCTION(com) { + CreateBindCtx(0, &pBindCtx); +} + +RPC_SHUTDOWN_FUNCTION(com) +{ + pBindCtx->lpVtbl->Release(pBindCtx); } /* rpc handler functions */ -static int com_hash(rpc_string name, rpc_string *hash, int num_args, char *arg_types, int type) +static int com_hash(rpc_string name, rpc_string *hash, void *data, int num_args, char *arg_types, int type) { - hash->str = strdup(name.str); - hash->len = name.len; + OLECHAR *olestr = php_char_to_OLECHAR(name.str, name.len, CP_ACP, FALSE); - return SUCCESS; + switch (type) { + case CLASS: + { + CLSID *clsid = malloc(sizeof(CLSID)); + + if (FAILED(CLSIDFromString(olestr, clsid))) { + /* Perhaps this is a Moniker? */ + free(clsid); + + hash->str = strdup(name.str); + hash->len = name.len; + } else { + hash->str = (char *) clsid; + /* str is actually not a string but a CLSID struct, thus set len to 0. + * nevertheless clsid is freed by the rpc_string_dtor + */ + hash->len = 0; + } + + efree(olestr); + + return SUCCESS; + } + + case METHOD: + case PROPERTY: + { + DISPID *dispid = malloc(sizeof(DISPID)); + + if(SUCCEEDED(php_COM_get_ids_of_names((comval *) data, olestr, dispid))) { + hash->str = (char *) dispid; + /* str is actually not a string but a DISPID struct, thus set len to 0. + * nevertheless dispid is freed by the rpc_string_dtor + */ + hash->len = 0; + + efree(olestr); + + return SUCCESS; + } else { + free(dispid); + efree(olestr); + + return FAILURE; + } + } + } + + efree(olestr); + + return FAILURE; } -static int com_name(rpc_string hash, rpc_string *name, int type) +static int com_name(rpc_string hash, rpc_string *name, void *data, int type) { - name->str = strdup(hash.str); - name->len = hash.len; + if (hash.len != 0) { + /* not a GUID, perhaps a Moniker */ + name->str = strdup(hash.str); + name->len = hash.len; - return SUCCESS; + return SUCCESS; + } else { + switch (type) { + case CLASS: + { + OLECHAR *olestr; + + StringFromCLSID((CLSID *) hash.str, &olestr); + name->str = php_OLECHAR_to_char(olestr, &(name->len), CP_ACP, TRUE); + CoTaskMemFree(olestr); + + return SUCCESS; + } + + case METHOD: + case PROPERTY: + /* not used yet */ + break; + } + } + + return FAILURE; } static int com_ctor(rpc_string class_name, void **data, int num_args, zval **args[]) { + zval **server_name = NULL; + zval **code_page = NULL; + zval **typelib = NULL; + zval **user_name=NULL; + zval **password=NULL; + zval **domain=NULL; + int mode = 0; + comval *obj; + HRESULT hr; + CLSCTX flags = CLSCTX_SERVER; + + switch (num_args) { + case 3: + typelib = args[2]; + convert_to_string_ex(typelib); + /* break missing intentionally */ + case 2: + code_page = args[1]; + convert_to_long_ex(code_page); + /* break missing intentionally */ + case 1: + server_name = args[0]; + /* break missing intentionally */ + break; + + case 0: + /* nothing to do */ + break; + + default: + /* exception */ + return FAILURE; + } + + if (server_name != NULL) { + /* What is server name? A String or an array? */ + if (Z_TYPE_PP(server_name) == IS_NULL) { + server_name = NULL; + } else if (Z_TYPE_PP(server_name) == IS_ARRAY) { + zval **tmp; + /* Aha - we have a number of possible arguments. + * They are in the hash By name: Server, Domain, Username, Password + * Flags. + * This has been crafted to maintian maximum backward compatability. + * If the server name is specified as a string, then the function + * should behave as before by defaulting username and password and + * using the (I believe) incorrect CLSCTX_SERVER instantiation + * paramter. However if server is specified in this array then we + * use either CLSCTX_REMOTE_SERVER or whatever flags are specified + * in the array + */ + HashTable *ht = Z_ARRVAL_PP(server_name); + if (FAILURE == zend_hash_find(ht, "Server", 7, (void **) &tmp)) { + server_name = NULL; + } else { + server_name = tmp; + convert_to_string_ex(server_name); + /* CLSCTX_SERVER includes INPROC and LOCAL SERVER. This means + * that any local server will be instantiated BEFORE even + * looking on a remote server. Thus if we have a server name, + * probably we want to access a remote machine or we would not + * have bothered specifying it. So it would be wrong to to + * connect locally. Futher, unless the name passed is a GUID, + * there has to be something to map the Prog.Id to GUID and + * unless that has been modified to remove the information + * about local instantiation CLSCTX_SERVER would force a local + * instantiation This setting can be overridden below if the + * user specifies a flags element */ + flags = CLSCTX_REMOTE_SERVER; + } + if (FAILURE == zend_hash_find(ht, "username", 9, (void **) &tmp)) { + user_name = NULL; + } else { + user_name = tmp; + convert_to_string_ex(user_name); + } + if (FAILURE == zend_hash_find(ht, "domain", 7, (void **) &tmp)) { + domain = NULL; + } else { + domain = tmp; + convert_to_string_ex(domain); + } + if (FAILURE == zend_hash_find(ht, "password", 9, (void **) &tmp)) { + password=NULL; + } else { + password = tmp; + convert_to_string_ex(password); + } + if (SUCCESS == zend_hash_find(ht, "flags", 6, (void **) &tmp)) { + convert_to_long_ex(tmp); + flags = (CLSCTX) Z_LVAL_PP(tmp); + } + } + + if (server_name != NULL) { + if (!INI_INT("com.allow_dcom")) { + rpc_error(E_WARNING, "DCOM is disabled"); + return FAILURE; + } else { + flags = CLSCTX_REMOTE_SERVER; + convert_to_string_ex(server_name); + } + } + } + + ALLOC_COM(obj); + *data = obj; + + if (code_page != NULL) { + C_CODEPAGE(obj) = Z_LVAL_PP(code_page); + } + + if (class_name.len) { + /* Perhaps this is a Moniker? */ + IMoniker *pMoniker; + ULONG ulEaten; + + if (server_name) { + hr = MK_E_SYNTAX; + } else { + OLECHAR *olestr = php_char_to_OLECHAR(class_name.str, class_name.len, obj->codepage, FALSE); + + if (SUCCEEDED(hr = MkParseDisplayNameEx(pBindCtx, olestr, &ulEaten, &pMoniker))) { + hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL, &IID_IDispatch, (LPVOID *) &C_DISPATCH(obj)); + pMoniker->lpVtbl->Release(pMoniker); + } + + efree(olestr); + } + + if (FAILED(hr)) { + char *error_message; + + php_COM_destruct(obj); + error_message = php_COM_error_message(hr); + rpc_error(E_WARNING,"Invalid ProgID, GUID string, or Moniker: %s", error_message); + LocalFree(error_message); + + return FAILURE; + } + } else { + /* obtain IDispatch */ + if (!server_name) { + hr = CoCreateInstance((CLSID *) class_name.str, NULL, flags, &IID_IDispatch, (LPVOID *) &C_DISPATCH(obj)); + } else { + COSERVERINFO server_info; + MULTI_QI pResults; + COAUTHIDENTITY authid; + COAUTHINFO authinfo = {RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, &authid, EOAC_NONE}; + + server_info.dwReserved1=0; + server_info.dwReserved2=0; + server_info.pwszName = php_char_to_OLECHAR(Z_STRVAL_PP(server_name), Z_STRLEN_PP(server_name), obj->codepage, FALSE); + if (user_name) { + /* Parse Username into domain\username */ + authid.User = (WCHAR *) Z_STRVAL_PP(user_name); + authid.UserLength = Z_STRLEN_PP(user_name); + if (password) { + authid.Password = (USHORT *) Z_STRVAL_PP(password); + authid.PasswordLength = Z_STRLEN_PP(password); + } else { + authid.Password = (USHORT *) ""; + authid.PasswordLength = 0; + } + if (domain) { + authid.Domain = (USHORT *) Z_STRVAL_PP(domain); + authid.DomainLength = Z_STRLEN_PP(domain); + } else { + authid.Domain = (USHORT *) ""; + authid.DomainLength = 0; + } + authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + + server_info.pAuthInfo=&authinfo; + } else { + server_info.pAuthInfo=NULL; + } + + pResults.pIID = &IID_IDispatch; + pResults.pItf = NULL; + pResults.hr = S_OK; + hr=CoCreateInstanceEx((CLSID *) class_name.str, NULL, flags, &server_info, 1, &pResults); + if (SUCCEEDED(hr)) { + hr = pResults.hr; + C_DISPATCH(obj) = (IDispatch *) pResults.pItf; + } + efree(server_info.pwszName); + } + + if (FAILED(hr)) { + char *error_message, *clsid; + + php_COM_destruct(obj); + error_message = php_COM_error_message(hr); + clsid = php_COM_string_from_CLSID((CLSID *)class_name.str); + rpc_error(E_WARNING,"Unable to obtain IDispatch interface for CLSID %s: %s", clsid, error_message); + LocalFree(error_message); + efree(clsid); + + return FAILURE; + } + } + + php_COM_set(obj, &C_DISPATCH(obj), TRUE); + + if (INI_INT("com.autoregister_casesensitive")) { + mode |= CONST_CS; + } + + if (C_HASTLIB(obj)) { + if (INI_INT("com.autoregister_typelib")) { + ITypeLib *pTL; + unsigned int idx; + + /* @todo check if typlib isn't already loaded */ + if (C_TYPEINFO_VT(obj)->GetContainingTypeLib(C_TYPEINFO(obj), &pTL, &idx) == S_OK) { + php_COM_load_typelib(pTL, mode); + pTL->lpVtbl->Release(pTL); + } + } + } else { + if (typelib != NULL) { + ITypeLib *pTL; + + if ((pTL = php_COM_find_typelib(Z_STRVAL_PP(typelib), mode)) != NULL) { + C_HASTLIB(obj) = SUCCEEDED(pTL->lpVtbl->GetTypeInfo(pTL, 0, &C_TYPEINFO(obj))); + /* idx 0 should deliver the ITypeInfo for the IDispatch Interface */ + if (INI_INT("com.autoregister_typelib")) { + php_COM_load_typelib(pTL, mode); + } + pTL->lpVtbl->Release(pTL); + } + } + } + +#if 0 + RETURN_RESOURCE(zend_list_insert(obj, IS_COM)); +#endif + return SUCCESS; } @@ -129,4 +464,75 @@ ZEND_FUNCTION(com_addref) ZEND_FUNCTION(com_release) { -} \ No newline at end of file +} + +/* ini callbacks */ +static PHP_INI_MH(OnTypelibFileChange) +{ + FILE *typelib_file; + char *typelib_name_buffer; + char *strtok_buf = NULL; + int interactive; + interactive = CG(interactive); + + if (!new_value || (typelib_file = VCWD_FOPEN(new_value, "r"))==NULL) { + return FAILURE; + } + + if (interactive) { + printf("Loading type libraries..."); + fflush(stdout); + } + + typelib_name_buffer = (char *) emalloc(sizeof(char)*1024); + + while (fgets(typelib_name_buffer, 1024, typelib_file)) { + ITypeLib *pTL; + char *typelib_name; + char *modifier, *ptr; + int mode = CONST_CS | CONST_PERSISTENT; /* CONST_PERSISTENT is ok here */ + + if (typelib_name_buffer[0]==';') { + continue; + } + typelib_name = php_strtok_r(typelib_name_buffer, "\r\n", &strtok_buf); /* get rid of newlines */ + if (typelib_name == NULL) { + continue; + } + typelib_name = php_strtok_r(typelib_name, "#", &strtok_buf); + modifier = php_strtok_r(NULL, "#", &strtok_buf); + if (modifier != NULL) { + if (!strcmp(modifier, "cis") || !strcmp(modifier, "case_insensitive")) { + mode &= ~CONST_CS; + } + } + + /* Remove leading/training white spaces on search_string */ + while (isspace(*typelib_name)) {/* Ends on '\0' in worst case */ + typelib_name ++; + } + ptr = typelib_name + strlen(typelib_name) - 1; + while ((ptr != typelib_name) && isspace(*ptr)) { + *ptr = '\0'; + ptr--; + } + + if (interactive) { + printf("\rLoading %-60s\r", typelib_name); + } + + if ((pTL = php_COM_find_typelib(typelib_name, mode)) != NULL) { + php_COM_load_typelib(pTL, mode); + pTL->lpVtbl->Release(pTL); + } + } + + efree(typelib_name_buffer); + fclose(typelib_file); + + if (interactive) { + printf("\r%70s\r", ""); + } + + return SUCCESS; +}