/* Configuration Manager for RPC cm_env.c ** ============================= ** ** This module provides address translation facilities for an RPC system, ** using the process environment (on VMS: logical name tables) as the ** database. ** ** Authors: ** ** Tim Berners-Lee CERN/DD (TBL) ** Roberto Bagnara CERN, Univ. Pisa (RB) ** Abramo Bagnara (AB) ** ** History: ** ** 27 Sep 89 Adapted from part of ts.c (TBL) ** 16 Nov 89 Cleaned up code by RB and AB incorporated ** 23 Nov 89 Standard header files and declarations added */ #ifdef OSK #include /* For strcpy(), strncpy(), strlen()... */ #else #include /* For strcpy(), strncpy(), strlen()... */ #endif #include /* For file handling for trace file */ #include "syspec.h" /* Local variations */ #include "rpcrts.h" /* Public RPC macros */ #include "rpc_code.h" /* Macros for internal use by RPC code */ /* External routines: */ #ifdef __STDC__ extern char *getenv(const char * name); /* Get shell environment variable */ extern char *malloc(int size); /* Allocate memory */ extern void *free(void *block); /* Deallocate memory */ #else extern char *getenv(); /* Get shell environment variable */ extern char *malloc(); /* Allocate memory */ extern void free(); /* Deallocate memory */ #endif /* Translate a logical name cm_translate() ** ------------------------ ** ** Given the logical name, this function translates it according to the ** local process environment, or equivalent. ** ** On entry, ** ** initial The address of the logical name (zero terminated). ** ** buffer The address of a buffer for the result. ** ** buffer_size The number of bytes available at *buffer. ** ** On exit, ** ** returns A status indicating success (GOOD) or failure (BAD). ** Inability to translate it counts as BAD. ** Buffer overflow counts as bad, in that there is nothing ** one can do with a truncated address. ** *buffer If status is GOOD, the physical address (zero terminated). ** If status is BAD, undefined. */ #ifdef __STDC__ PUBLIC rpc_status cm_translate( char *initial, /* IN Initial string to be translated */ char *buffer, /* OUT Buffer for returned string */ int buffer_size) /* IN Maximum length of returned string */ #else PUBLIC rpc_status cm_translate(initial, buffer, buffer_size) char *initial; char *buffer; int buffer_size; #endif { if (getenv(initial)) { if (strlen(getenv(initial)) > buffer_size) { CTRACE(tfp, "RPC/CM: Buffer overflow translating `%s' to `%s'\n", initial,getenv(initial)); return RPC_S_BUFFER_OVERFLOW; } CTRACE(tfp, "RPC/CM: Translated `%s' to `%s'\n", initial, getenv(initial)); strncpy(buffer, getenv(initial), buffer_size); return RPC_S_NORMAL; } else { CTRACE(tfp, "RPC/CM: No translation for `%s'.\n",initial); return RPC_S_NO_TRANSLATION; } /*NOTREACHED*/ } /* Capitalise a character. uppercase() ** ----------------------- ** ** ** char uppercase(char c) ** ** Parameters: c character to be upper-cased. ** ** Return: upper-cased character. ** ** History: ** ** 14 Aug 89 Cleaned up. (RB) ** */ #ifdef UPPERCASE_LOGICALS #ifdef __STDC__ char uppercase(char c) #else char uppercase(c) char c; #endif { return ((c >= 'a') && (c <= 'z')) ? (c - 'a' + 'A') : c; } /* Capitalise a string. capital() ** -------------------- ** ** ** void capital(char *string) ** ** Parameters: string pointer to string to be capitalised. ** ** Return: none ** ** On entry: string[] null terminated string. ** ** On exit: string[] same as above but capitalised. ** ** Description: ** ** Self explanatory. ** ** History: ** ** 14 Aug 89 Cleaned up. (RB) ** */ #ifdef __STDC__ void capital(char *string) #else void capital(string) char *string; #endif { register char *p; for (p = string; *p; p++) *p = uppercase(*p); } #endif /* Recursively translates logical names. translated() ** ------------------------------------- ** ** ** BOOLEAN translated(char *buffer, int buflen, int curlevel, ** int maxlevel, char *previous[]) ** ** Parameters: buffer pointer to string containing the name to ** be translated on entry, its translation ** on exit; ** ** buflen maximum length of the translation; ** ** curlevel current recursion level; ** ** maxlevel maximum recursion level; ** ** previous array of pointers to previous translation ** strings. ** ** Return: FALSE if a translation loop was detected, ** TRUE otherwise. ** ** On entry: buffer[] null terminated string containing the name to ** translate; ** ** previous[] contains in positions 0 to curlevel-1 ** pointers to the previous translation strings. ** ** On exit: buffer[] null terminated translation string. ** ** Description: ** ** Recursively gets the translation of the string contained in 'buffer' ** from the environment. Recursion stops when either the maximum ** recursion level 'maxlevel' is reached, or there is no translation, ** or a translation loop is detected (in this case FALSE is returned). ** ** History: ** ** 14 Aug 89 Rewritten. (RB) ** */ #ifdef __STDC__ BOOLEAN translated(char *buffer, int buflen, int curlevel, int maxlevel, char *previous[]) #else BOOLEAN translated(buffer, buflen, curlevel, maxlevel, previous) char *buffer; int buflen; int curlevel; int maxlevel; char *previous[]; #endif { int status; if (curlevel < maxlevel) { extern char *getenv(); char *translation; char *aux_buf; /* Copy the input string into our private buffer. */ aux_buf = (char *)malloc(buflen); (void) strcpy(aux_buf, buffer); #ifdef UPPERCASE_LOGICALS capital(aux_buf); /* Convert to uppercase before look-up */ #endif /* Save pointer to name we are trying to translate. */ previous[curlevel] = aux_buf; /* Try translating. */ if ((translation = getenv(aux_buf)) != NULL) { int k; /* Translation worked: save and retry. */ (void) strncpy(buffer, translation, buflen); buffer[buflen] = '\0'; CTRACE(tfp, "RPC/CM: Translated `%s' to `%s'\n", aux_buf, buffer); /* Check for translation loop. */ for (k = 0; k <= curlevel; k++) if (strcmp(previous[k], buffer) == 0) { UTRACE(tfp, "RPC/CM: Translation loop detected, fail.\n"); free(aux_buf); return FALSE; } status = translated(buffer, buflen, curlevel+1, maxlevel, previous); } else { /* Translation didn't work, say it's good anyway. */ CTRACE(tfp, "RPC/CM: No translation for `%s'.\n", aux_buf); status = TRUE; } free(aux_buf); } else /* Maximum translation level reached, return ok. */ status = TRUE; return status; } /* Satisfy requests for configuration items. cm_request() ** ----------------------------------------- ** ** ** rpc_status cm_request(const char *name, char *expansion, int explen) ** ** Parameters: name pointer to string containing the name to be ** looked up; ** ** expansion pointer to string where the expansion for ** 'name' will be stored; ** ** explen maximum length of the expansion for 'name', ** ** Return: status RPC_S_NORMAL if translation succeeded, ** RPC_S_NOTRANS if a translation loop has been ** detected. ** ** On entry: name[] Null terminated string containing the name to ** looked up. ** ** On exit: expansion[] Null terminated string containing the expansion ** for name, possibly truncated to explen-1 ** characters. ** ** Description: ** ** Initialises for calling the 'translated' recursive function ** that will do the real job. ** ** History: ** ** 14 Aug 89 Rewritten. (RB) ** */ /*ARGSUSED*/ #ifdef __STDC__ rpc_status cm_request( const char *name, int version, int compatibility, char *expansion, int explen) #else rpc_status cm_request(name, version, compatibility, expansion, explen) char *name; int version; int compatibility; char *expansion; int explen; #endif { #define MAXLEVEL 3 /* This array is used to detect translation loops. */ char *previous[MAXLEVEL]; /* Copy name to expansion, possibly truncated. */ (void) strncpy(expansion, name, RPC_NAME_LENGTH); /* Make sure it is null terminated. */ expansion[RPC_NAME_LENGTH] = '\0'; /* Do the actual translation. */ return translated(expansion, explen, 0, MAXLEVEL, previous) ? RPC_S_NORMAL : RPC_S_NO_TRANSLATION; } /* Register a service cm_register() ** ------------------ ** ** This routine records the provision of a particular version of a ** service at a given RPC address. ** ** On entry, ** ** service points to the zero-terminated package name of the service ** ** version is the actual version of the service ** ** compatibility is the lowest previous version of client which is ** also supported by this version of the server. ** ** address points to the zero-terminated rpc address at which the ** service is provided. ** ** On exit, ** ** returns a status indicating GOOD or BAD completion. ** If good, the service has been registered and should ** eventually be unregistered. ** If bad, the service has not been registered. */ #ifdef __STDC__ rpc_status cm_register( char * service, int version, int compatibility, char * address) #else rpc_status cm_register(service, version, compatibility, address) char * service; int version; int compatibility; char * address; #endif { CTRACE(tfp, "CM: Registering %s version %d (compat:%d) at %s", service, version, compatibility, address); return RPC_S_NOT_IMPLEMENTED; } /* Remove a registration cm_unregister() ** --------------------- ** ** This routine removes the record of the provision of a service at a ** particular given RPC address. ** ** On entry, ** ** service points to the zero-reminated package name of the service ** ** version is the actual version of the service ** ** address points to the zero-terminated rpc address ** ** On exit, ** ** returns a status indicating GOOD or BAD completion. ** If good, the registration has been removed. ** If bad, it has not -- because the registrationwas not ** found or for another reason. */ #ifdef __STDC__ rpc_status cm_unregister( char * service, int version, char * address) #else rpc_status cm_unregister(service, version, address) char * service; int version; char * address; #endif { CTRACE(tfp, "CM: Unregistering of %s version %d at %s", service, version, address); return RPC_S_NOT_IMPLEMENTED; } /* Initialse This Module cm_init() ** --------------------- ** ** On entry, ** No prerequisites. ** ** On exit, ** CM may be used. ** */ #ifdef __STDC__ rpc_status cm_init(void) #else rpc_status cm_init() #endif { return RPC_S_NORMAL; }