diff --git a/c/as.c b/c/as.c new file mode 100644 index 000000000..bc1585c25 --- /dev/null +++ b/c/as.c @@ -0,0 +1,431 @@ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifdef METTLE +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#include "zowetypes.h" +#include "alloc.h" + +#include "as.h" + +#ifndef __ZOWE_OS_ZOS +#error z/OS targets are supported only +#endif + +ZOWE_PRAGMA_PACK + +typedef struct ASCrossMemoryInfo_tag { + void * __ptr32 axlist; + void * __ptr32 tklist; + void * __ptr32 elxlist; +} ASCrossMemoryParms; + +ZOWE_PRAGMA_PACK_RESET + +typedef struct ASMacroParmList_tag { + + uint8_t version; +#define ASCRE_VERSION 1 + uint32_t attributes : 24; + + EightCharString * __ptr32 initRoutineName; + uint32_t initRoutineNameALET; + + ASParmString * __ptr32 startParmString; + uint32_t startParmStringALET; + + ASUserToken * __ptr32 utoken; + uint32_t utokenALET; + + ASParm * __ptr32 parm; + uint32_t parmALET; + + void * __ptr32 termRoutine; + + void * __ptr32 axlist; + uint32_t axlistALET; + void * __ptr32 tklist; + uint32_t tklistALET; + void * __ptr32 elxlist; + uint32_t elxlistALET; + + ASOutputData * __ptr32 oda; + uint32_t odaALET; + + char reserved[8]; + +} ASMacroParmList; + +#ifdef METTLE + +static Addr31 getTermExitWrapper(void) { + + Addr31 wrapper = NULL; + + __asm( + ASM_PREFIX + " LARL 1,L$TEW \n" + " ST 1,%[wrapper] \n" + " J L$TEWEX \n" + "L$TEW DS 0H \n" + + /* establish addressability */ + " PUSH USING \n" + " DROP \n" + " BAKR 14,0 \n" + " LARL 10,L$TEW \n" + " USING L$TEW,10 \n" + /* handle input parms */ + " LTR 2,1 UTOKEN provided? \n" + " BZ L$TEWRT no, leave \n" + " USING ASCREUTK,2 \n" + " LLGTR 2,2 make sure higher bits are clean \n" + " LLGT 15,TEWUFUNC load function provided \n" + " LTR 15,15 is it zero? \n" + " BZ L$TEWRT yes, leave \n" + /* handle stack */ + " STORAGE OBTAIN" + ",COND=YES,LENGTH=65536,CALLRKY=YES,SP=132,LOC=31,BNDRY=PAGE \n" + " LTR 15,15 check the RC \n" + " BNZ L$TEWRT bad RC, leave \n" + " LLGTR 13,1 load stack to R13 \n" + " USING TEWSA,13 \n" +#ifdef _LP64 + " MVC TEWSAEYE,=C'F1SA' stack eyecatcher \n" +#endif + " LA 5,TEWSANSA address of next save area \n" + " ST 5,TEWSANXT save next save area address \n" + " MVC TEWSAUP,TEWUPRM user data \n" + /* call user routine */ + " LLGT 15,TEWUFUNC user routine \n" + " LA 1,TEWSAPRM load pamlist address to R1 \n" +#ifdef _LP64 + " SAM64 go AMODE64 if needed \n" +#endif + " BASR 14,15 call user function \n" +#ifdef _LP64 + " SAM31 go back to AMODE31 \n" +#endif + /* return to caller */ + " LR 1,13 load save are to R1 for release \n" + " STORAGE RELEASE" + ",COND=YES,LENGTH=65536,CALLRKY=YES,SP=132,ADDR=(1) \n" + "L$TEWRT DS 0H \n" + " PR , return \n" + /* non executable code */ + " LTORG \n" + " POP USING \n" + + "L$TEWEX DS 0H \n" + : [wrapper]"=m"(wrapper) + : + : "r1" + ); + + return wrapper; +} + +#endif /* METTLE */ + +static int addressSpaceCreateInternal(const ASParmString *startParmString, + const ASParm *parm, + const EightCharString *initProgramName, + void * __ptr32 termRoutine, + ASUserToken *termRoutineUserToken, + uint16_t attributes, + ASCrossMemoryParms *xmemParms, + ASOutputData *result, + int *reasonCode) { + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + ASParmString startParmString; + ASParm parm; + EightCharString initProgramName; + ASUserToken utoken; + ASOutputData oda; + ASMacroParmList parmList; + ) + ); + + /* Init 31-bit data */ + if (startParmString) { + below2G->startParmString = *startParmString; + } + + if (parm) { + below2G->parm = *parm; + } + + if (initProgramName) { + below2G->initProgramName = *initProgramName; + } else { + EightCharString dummyInit = {"IEFBR14 "}; + below2G->initProgramName = dummyInit; + } + + if (termRoutine && termRoutineUserToken) { + below2G->utoken = *termRoutineUserToken; + } + + /* Init ASCRE parameter list */ + ASMacroParmList * __ptr32 parmList = &below2G->parmList; + parmList->version = ASCRE_VERSION; + parmList->attributes = attributes; + parmList->initRoutineName = &below2G->initProgramName; + parmList->startParmString = &below2G->startParmString; + parmList->utoken = termRoutine ? &below2G->utoken : NULL; + parmList->parm = &below2G->parm; + parmList->termRoutine = termRoutine; + if (xmemParms) { + parmList->axlist = xmemParms->axlist; + parmList->tklist = xmemParms->tklist; + parmList->elxlist = xmemParms->elxlist; + } + parmList->oda = &below2G->oda; + + int rc = 0, rsn = 0; + __asm( + ASM_PREFIX + "L@ASCRE DS 0H \n" + " PUSH USING \n" + " DROP \n" + " LARL 10,L@ASCRE \n" + " USING L@ASCRE,10 \n" + + " ASCRE MF=(E,%[parmList]) \n" + " ST 15,%[rc] \n" + " ST 0,%[rsn] \n" + + " POP USING \n" + : [rc]"=m"(rc), [rsn]"=m"(rsn) + : [parmList]"m"(below2G->parmList) + : "r0", "r1", "r10", "r14", "r15" + ); + + if (result) { + *result = below2G->oda; + } + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + below2G = NULL; + + if (reasonCode) { + *reasonCode = rsn; + } + return rc; +} + +int addressSpaceCreate(const ASParmString *startParmString, + const ASParm *parm, + uint32_t attributes, + ASOutputData *result, + int *reasonCode) { + + return addressSpaceCreateInternal(startParmString, parm, NULL, NULL, NULL, + attributes, NULL, result, reasonCode); + +} + +#ifdef METTLE + +int addressSpaceCreateWithTerm(const ASParmString *startParmString, + const ASParm *parm, + uint32_t attributes, + ASOutputData *result, + ASCRETermCallback *termCallback, + void * __ptr32 termCallbackParm, + int *reasonCode) { + + __packed union { + ASUserToken tokenValue; + __packed struct { + ASCRETermCallback * __ptr32 termCallback; + void * __ptr32 termCallbackParm; + }; + } utoken = { + .termCallback = termCallback, + .termCallbackParm = termCallbackParm, + }; + + return addressSpaceCreateInternal(startParmString, parm, NULL, + getTermExitWrapper(), &utoken.tokenValue, + attributes, NULL, result, reasonCode); + +} + +#endif /* METTLE */ + +int addressSpaceTerminate(uint64_t stoken, int *reasonCode) { + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + uint64_t stoken; + ) + ); + + below2G->stoken = stoken; + + int rc = 0, rsn = 0; + __asm( + ASM_PREFIX + "L@ASDES DS 0H \n" + " PUSH USING \n" + " DROP \n" + " LARL 10,L@ASDES \n" + " USING L@ASDES,10 \n" + + " ASDES STOKEN=(%[stoken]) \n" + " ST 15,%[rc] \n" + " ST 0,%[rsn] \n" + + " POP USING \n" + : [rc]"=m"(rc), [rsn]"=m"(rsn) + : [stoken]"r"(&below2G->stoken) + : "r0", "r1", "r10", "r14", "r15" + ); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + below2G = NULL; + + if (reasonCode) { + *reasonCode = rsn; + } + return rc; +} + +int addressSpaceExtractParm(ASParm **parm, int *reasonCode) { + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + uint64_t stoken; + ) + ); + + ASParm *__ptr32 result = NULL; + int rc = 0, rsn = 0; + __asm( + ASM_PREFIX + "L@ASEXT DS 0H \n" + " PUSH USING \n" + " DROP \n" + " LARL 10,L@ASEXT \n" + " USING L@ASEXT,10 \n" + + " ASEXT ASPARM \n" + " ST 1,%[parm] \n" + " ST 15,%[rc] \n" + " ST 0,%[rsn] \n" + + " POP USING \n" + : [parm]"=m"(result), [rc]"=m"(rc), [rsn]"=m"(rsn) + : + : "r0", "r1", "r10", "r14", "r15" + ); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + below2G = NULL; + + if (parm) { + *parm = result; + } + + if (reasonCode) { + *reasonCode = rsn; + } + return rc; +} + +#ifdef METTLE + +#define addressSpaceDESCTs ASCDSECT +void addressSpaceDESCTs(void) { + + __asm( +#ifndef _LP64 + "TEWSA DSECT , \n" + /* 31-bit save area */ + "TEWSARSV DS CL4 \n" + "TEWSAPRV DS A previous save area \n" + "TEWSANXT DS A next save area \n" + "TEWSAGPR DS 15F GPRs \n" + /* parameters on stack */ + "TEWSAPRM DS 0F parameter block for Metal C \n" + "TEWSAUP DS F user parms \n" + "TEWSALEN EQU *-TEWSA \n" + "TEWSANSA DS 0F top of next save area \n" + " EJECT , \n" +#else + "TEWSA DSECT , \n" + /* 64-bit save area */ + "TEWSARSV DS CL4 \n" + "TEWSAEYE DS CL4 eyecatcher F1SA \n" + "TEWSAGPR DS 15D GPRs \n" + "TEWSAPD1 DS F padding \n" + "TEWSAPRV DS A previous save area \n" + "TEWSAPD2 DS F padding \n" + "TEWSANXT DS A next save area \n" + /* parameters on stack */ + "TEWSAPRM DS 0F parameter block for Metal C \n" + "TEWSAPD3 DS F padding \n" + "TEWSAUP DS F user parms \n" + "TEWSALEN EQU *-TEWSA \n" + "TEWSANSA DS 0D top of next save area \n" + " EJECT , \n" +#endif + + "ASCREUTK DSECT , \n" + "TEWUFUNC DS A user function \n" + "TEWUPRM DS A user parm \n" + "RMPLLEN EQU *-ASCREUTK \n" + " EJECT , \n" + +#ifdef METTLE + " CSECT , \n" + " RMODE ANY \n" +#endif + ); + +} + +#endif /* METTLE */ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/c/collections.c b/c/collections.c index c65519cc6..b4df9b209 100644 --- a/c/collections.c +++ b/c/collections.c @@ -595,7 +595,24 @@ int stringCompare(void *key1, void *key2){ } void htDestroy(hashtable *ht){ - /* printf("htDestroy should apply all key and value reclaimers, if specified\n"); */ + + if (ht->keyReclaimer != NULL || ht->valueReclaimer != NULL) { + + for (int i = 0; i < ht->backboneSize; i++) { + hashentry *entry = ht->backbone[i]; + while (entry != NULL) { + if (ht->keyReclaimer != NULL) { + (ht->keyReclaimer)(entry->key); + } + if (ht->valueReclaimer != NULL) { + (ht->valueReclaimer)(entry->value); + } + entry = entry->next; + } + } + + } + fbMgrDestroy(ht->mgr); safeFree((char*)ht->backbone,sizeof(hashentry*)*ht->backboneSize); safeFree((char*)ht,sizeof(hashtable)); diff --git a/c/crossmemory.c b/c/crossmemory.c index fbafe02e3..f389e225a 100644 --- a/c/crossmemory.c +++ b/c/crossmemory.c @@ -4,9 +4,9 @@ This program and the accompanying materials are made available under the terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html - + SPDX-License-Identifier: EPL-2.0 - + Copyright Contributors to the Zowe Project. */ @@ -3110,7 +3110,7 @@ static void handleAsyncModifyCommand(CrossMemoryServer *server, (void *)command, commandLength); wtoPrintf2(consoleID, cart, CMS_LOG_CMD_TKNZ_FAILURE_MSG); } - + SLHFree(slh); } static int commandTaskHandler(RLETask *rleTask) { @@ -4267,8 +4267,8 @@ void crossmemoryServerDESCTs(){ This program and the accompanying materials are made available under the terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html - + SPDX-License-Identifier: EPL-2.0 - + Copyright Contributors to the Zowe Project. */ diff --git a/c/dataservice.c b/c/dataservice.c index 7293c92eb..8fbf4493d 100644 --- a/c/dataservice.c +++ b/c/dataservice.c @@ -141,7 +141,8 @@ static void *lookupDLLEntryPoint(char *libraryName, char *functionName){ return ep; } -static DataService *makeDataService(WebPlugin *plugin, JsonObject *serviceJsonObject, char *subURI, InternalAPIMap *namedAPIMap) { +static DataService *makeDataService(WebPlugin *plugin, JsonObject *serviceJsonObject, char *subURI, InternalAPIMap *namedAPIMap, + unsigned int *idMultiplier, int pluginLogLevel) { zowelog(NULL, LOG_COMP_DATASERVICE, ZOWE_LOG_INFO, "%s begin data service:\n", __FUNCTION__); DataService *service = (DataService*) safeMalloc(sizeof (DataService), "DataService"); memset(service, 0, sizeof (DataService)); @@ -166,6 +167,11 @@ static DataService *makeDataService(WebPlugin *plugin, JsonObject *serviceJsonOb } else { sprintf(service->identifier, "%s", plugin->identifier); } + + service->loggingIdentifier = LOG_PROD_PLUGINS + (0x10000 * (*idMultiplier)); + logConfigureComponent(NULL, service->loggingIdentifier, service->identifier, + LOG_DEST_PRINTF_STDOUT, pluginLogLevel); + zowelog(NULL, service->loggingIdentifier, ZOWE_LOG_WARNING, "added identifier for %s\n", service->identifier); char *initializerLookupMethod = jsonObjectGetString(serviceJsonObject, "initializerLookupMethod"); char *initializerName = jsonObjectGetString(serviceJsonObject, "initializerName"); @@ -252,7 +258,8 @@ static bool isValidServiceDef(JsonObject *serviceDef) { return true; } -WebPlugin *makeWebPlugin(char *pluginLocation, JsonObject *pluginDefintion, InternalAPIMap *internalAPIMap) { +WebPlugin *makeWebPlugin(char *pluginLocation, JsonObject *pluginDefintion, InternalAPIMap *internalAPIMap, + unsigned int *idMultiplier, int pluginLogLevel) { zowelog(NULL, LOG_COMP_DATASERVICE, ZOWE_LOG_INFO, "%s begin\n", __FUNCTION__); WebPlugin *plugin = (WebPlugin*)safeMalloc(sizeof(WebPlugin),"WebPlugin"); memset(plugin, 0, sizeof (WebPlugin)); @@ -298,13 +305,17 @@ WebPlugin *makeWebPlugin(char *pluginLocation, JsonObject *pluginDefintion, Inte char *type = jsonObjectGetString(serviceDef, "type"); if (!type || !strcmp(type, "service")) { - plugin->dataServices[k++] = makeDataService(plugin, jsonArrayGetObject(dataServices, i), NULL, internalAPIMap); + plugin->dataServices[k++] = makeDataService(plugin, jsonArrayGetObject(dataServices, i), NULL, internalAPIMap, + idMultiplier, pluginLogLevel); + (*idMultiplier++); } else if (!strcmp(type, "group")) { char *subURI = jsonObjectGetString(serviceDef, "name"); JsonArray* group = jsonObjectGetArray(serviceDef, "subservices"); if (group) { for (int j = 0; j < jsonArrayGetCount(group); j++) { - plugin->dataServices[k++] = makeDataService(plugin, jsonArrayGetObject(group, j), subURI, internalAPIMap); + plugin->dataServices[k++] = makeDataService(plugin, jsonArrayGetObject(group, j), subURI, internalAPIMap, + idMultiplier, pluginLogLevel); + (*idMultiplier++); } } } else { diff --git a/c/httpfileservice.c b/c/httpfileservice.c index 818141e38..96068412b 100644 --- a/c/httpfileservice.c +++ b/c/httpfileservice.c @@ -45,6 +45,9 @@ #define DEFAULT_UMASK 0022 #endif +/* A generic function to return a 200 OK to the caller. + * It takes a msg and prints it to JSON. + */ void response200WithMessage(HttpResponse *response, char *msg) { setResponseStatus(response,200,"OK"); setDefaultJSONRESTHeaders(response); @@ -57,11 +60,12 @@ void response200WithMessage(HttpResponse *response, char *msg) { finishResponse(response); } -int isDir(char *absolutePath) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; +/* Returns a boolean value for whether or not + * the specified file is a directory or not. + */ +bool isDir(char *absolutePath) { + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); if (status == -1) { @@ -71,55 +75,48 @@ int isDir(char *absolutePath) { return (fileInfoIsDirectory(&info)); } -int doesItExist(char *absolutePath) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; +/* Returns a boolean value for whether or not + * the specified file exists. + */ +bool doesFileExist(char *absolutePath) { + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); if (status == -1) { return FALSE; } - + return TRUE; } +/* Creates a new unix directory at the specified absolute + * path. It will only overwrite an existing directory if + * the forceCreate flag is on. + */ static int createUnixDirectory(char *absolutePath, int forceCreate) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; - int dirExists = FALSE; - + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; + status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); if (status == 0) { if (!forceCreate) { return -1; } - dirExists = TRUE; - status = tmpDirMake(absolutePath); - if (status == -1) { - return -1; - } } status = directoryMake(absolutePath, - 0, + 0700, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to create directory %s: (return = 0x%x, reason = 0x%x)\n", absolutePath, returnCode, reasonCode); -#endif - if (dirExists) { - tmpDirCleanup(absolutePath); - } + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to create directory %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + absolutePath, returnCode, reasonCode); return -1; } - tmpDirDelete(absolutePath); return 0; } @@ -132,22 +129,26 @@ void createUnixDirectoryAndRespond(HttpResponse *response, char *absolutePath, i } } +/* Deletes a unix directory at the specified absolute + * path. + */ static int deleteUnixDirectory(char *absolutePath) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; - + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; + status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); if (status == -1) { + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to stat directory %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + absolutePath, returnCode, reasonCode); return -1; } - status = directoryDeleteRecursive(absolutePath); + status = directoryDeleteRecursive(absolutePath, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to delete directory %s\n", absolutePath); -#endif + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to delete directory %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + absolutePath, returnCode, reasonCode); return -1; } @@ -163,22 +164,26 @@ void deleteUnixDirectoryAndRespond(HttpResponse *response, char *absolutePath) { } } +/* Deletes a unix file at the specified absolute + * path. + */ static int deleteUnixFile(char *absolutePath) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); if (status == -1) { + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to stat file %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + absolutePath, returnCode, reasonCode); return -1; } status = fileDelete(absolutePath, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to delete file %s: (return = 0x%x, reason = 0x%x)\n", absolutePath, returnCode, reasonCode); -#endif + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to delete file %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + absolutePath, returnCode, reasonCode); return -1; } @@ -194,14 +199,19 @@ void deleteUnixFileAndRespond(HttpResponse *response, char *absolutePath) { } } +/* Renames a unix directory at the specified absolute + * path. It will only overwrite an existing directory + * if the forceRename flag is on. + */ static int renameUnixDirectory(char *oldAbsolutePath, char *newAbsolutePath, int forceRename) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; status = fileInfo(oldAbsolutePath, &info, &returnCode, &reasonCode); if (status == -1) { + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to stat directory %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + oldAbsolutePath, returnCode, reasonCode); return -1; } @@ -212,9 +222,9 @@ static int renameUnixDirectory(char *oldAbsolutePath, char *newAbsolutePath, int status = directoryRename(oldAbsolutePath, newAbsolutePath, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to rename directory %s: (return = 0x%x, reason = 0x%x)\n", oldAbsolutePath, returnCode, reasonCode); -#endif + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to rename directory %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + oldAbsolutePath, returnCode, reasonCode); return -1; } @@ -230,14 +240,19 @@ void renameUnixDirectoryAndRespond(HttpResponse *response, char *oldAbsolutePath } } +/* Renames a unix file at the specified absolute + * path. It will only overwrite an existing file + * if the forceRename flag is on. + */ static int renameUnixFile(char *oldAbsolutePath, char *newAbsolutePath, int forceRename) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; status = fileInfo(oldAbsolutePath, &info, &returnCode, &reasonCode); if (status == -1) { + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to stat file %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + oldAbsolutePath, returnCode, reasonCode); return -1; } @@ -248,9 +263,9 @@ static int renameUnixFile(char *oldAbsolutePath, char *newAbsolutePath, int forc status = fileRename(oldAbsolutePath, newAbsolutePath, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to rename file %s: (return = 0x%x, reason = 0x%x)\n", oldAbsolutePath, returnCode, reasonCode); -#endif + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to rename file %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + oldAbsolutePath, returnCode, reasonCode); return -1; } @@ -266,22 +281,33 @@ void renameUnixFileAndRespond(HttpResponse *response, char *oldAbsolutePath, cha } } +/* Copies the contents of a unix directory to a new + * directory. It will only overwrite an existing directory + * if the forceCopy flag is on. At this time, copy will only + * copy the contents and nothing else. + */ static int copyUnixDirectory(char *oldAbsolutePath, char *newAbsolutePath, int forceCopy) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; status = fileInfo(oldAbsolutePath, &info, &returnCode, &reasonCode); if (status == -1) { + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to stat directory %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + oldAbsolutePath, returnCode, reasonCode); + return -1; + } + + status = fileInfo(newAbsolutePath, &info, &returnCode, &reasonCode); + if (status == 0 && !forceCopy) { return -1; } - status = directoryCopy(oldAbsolutePath, newAbsolutePath, forceCopy); + status = directoryCopy(oldAbsolutePath, newAbsolutePath, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to copy directory %s\n", oldAbsolutePath); -#endif + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to copy directory %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + oldAbsolutePath, returnCode, reasonCode); return -1; } @@ -297,22 +323,33 @@ void copyUnixDirectoryAndRespond(HttpResponse *response, char *oldAbsolutePath, } } +/* Copies the contents of a unix file to a new + * file. It will only overwrite an existing file + * if the forceCopy flag is on. At this time, copy will only + * copy the contents and nothing else. + */ static int copyUnixFile(char *oldAbsolutePath, char *newAbsolutePath, int forceCopy) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; status = fileInfo(oldAbsolutePath, &info, &returnCode, &reasonCode); if (status == -1) { + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to stat file %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + oldAbsolutePath, returnCode, reasonCode); + return -1; + } + + status = fileInfo(newAbsolutePath, &info, &returnCode, &reasonCode); + if (status == 0 && !forceCopy) { return -1; } - status = fileCopy(oldAbsolutePath, newAbsolutePath, forceCopy); + status = fileCopy(oldAbsolutePath, newAbsolutePath, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to copy file %s\n", oldAbsolutePath); -#endif + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to copy file %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + oldAbsolutePath, returnCode, reasonCode); return -1; } @@ -328,6 +365,98 @@ void copyUnixFileAndRespond(HttpResponse *response, char *oldAbsolutePath, char } } +/* Creates an empty unix file with no tag. This is + * done by mimicing the touch command. + */ +static int writeEmptyUnixFile(char *absolutePath, int forceWrite) { + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; + + status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); + if (status == 0 && !forceWrite) { + return -1; + } + + UnixFile *dest = fileOpen(absolutePath, + FILE_OPTION_CREATE | FILE_OPTION_TRUNCATE | FILE_OPTION_WRITE_ONLY, + 0700, + 0, + &returnCode, + &reasonCode); + + if (dest == NULL) { + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to open file %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + absolutePath, returnCode, reasonCode); + return -1; + } + + status = fileClose(dest, &returnCode, &reasonCode); + if (status == -1) { + zowelog(NULL, LOG_COMP_RESTFILE, ZOWE_LOG_WARNING, + "Failed to close file %s, (returnCode = 0x%x, reasonCode = 0x%x)\n", + absolutePath, returnCode, reasonCode); + return -1; + } + + return 0; +} + +void writeEmptyUnixFileAndRespond(HttpResponse *response, char *absolutePath, int forceWrite) { + if (!writeEmptyUnixFile(absolutePath, forceWrite)) { + response200WithMessage(response, "Successfully wrote a file"); + } + else { + respondWithJsonError(response, "Failed to write a file", 500, "Internal Server Error"); + } +} + +/* Gets the metadata of a unix file and returns it to the + * caller. + */ +void respondWithUnixFileMetadata(HttpResponse *response, char *absolutePath) { + FileInfo info; + int returnCode; + int reasonCode; + int status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); + + if (status == 0) { + jsonPrinter *out = respondWithJsonPrinter(response); + + setResponseStatus(response, 200, "OK"); + setDefaultJSONRESTHeaders(response); + writeHeader(response); + + int decimalMode = fileUnixMode(&info); + int octalMode = decimalToOctal(decimalMode); + + ISOTime timeStamp; + int unixTime = fileInfoUnixCreationTime(&info); + convertUnixToISO(unixTime, &timeStamp); + + jsonStart(out); + { + jsonAddString(out, "path", absolutePath); + jsonAddBoolean(out, "directory", fileInfoIsDirectory(&info)); + jsonAddInt64(out, "size", fileInfoSize(&info)); + jsonAddInt(out, "ccsid", fileInfoCCSID(&info)); + jsonAddString(out, "createdAt", timeStamp.data); + jsonAddInt(out, "mode", octalMode); + } + jsonEnd(out); + + finishResponse(response); + } + else { + respondWithUnixFileNotFound(response, TRUE); + } +} + +/* Writes binary data to a unix file by: + * + * 1. Decoding the data from base64. + * 2. Converting the data to EBCDIC. + */ int writeBinaryDataFromBase64(UnixFile *file, char *fileContents, int contentLength) { int status = 0; int returnCode = 0; @@ -391,6 +520,12 @@ int writeBinaryDataFromBase64(UnixFile *file, char *fileContents, int contentLen return 0; } +/* Writes text data to a unix file by: + * + * 1. Decoding the data from base64. + * 2. Converting the data to the specified encoding. + * 3. Disabling auto conversion. + */ int writeAsciiDataFromBase64(UnixFile *file, char *fileContents, int contentLength, int sourceEncoding, int targetEncoding) { int status = 0; int returnCode = 0; @@ -478,115 +613,6 @@ int writeAsciiDataFromBase64(UnixFile *file, char *fileContents, int contentLeng return 0; } -static int writeEmptyUnixFile(char *absolutePath, int forceWrite) { - int status = 0; - int returnCode = 0; - int reasonCode = 0; - FileInfo info; - int fileExists = FALSE; - - status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); - if (status == 0) { - if (!forceWrite) { -#ifdef DEBUG - printf("Writing has stopped because the file already exists and the force flag is off\n"); -#endif - return -1; - } - fileExists = TRUE; - status = tmpFileMake(absolutePath); - if (status == -1) { -#ifdef DEBUG - printf("Error occurred while creating tmp file: %s.tmp\n", absolutePath); -#endif - return -1; - } - } - - setUmask(DEFAULT_UMASK); - UnixFile *dest = fileOpen(absolutePath, - FILE_OPTION_CREATE | FILE_OPTION_TRUNCATE | FILE_OPTION_WRITE_ONLY, - 0, - 0, - &returnCode, - &reasonCode); - - if (dest == NULL) { -#ifdef DEBUG - printf("Failed to open file %s: (return = 0x%x, reason = 0x%x)\n", absolutePath, returnCode, reasonCode); -#endif - if (fileExists) { - tmpFileCleanup(absolutePath); - } - return -1; - } - - status = fileClose(dest, &returnCode, &reasonCode); - if (status == -1) { -#ifdef DEBUG - printf("Failed to close file %s: (return = 0x%x, reason = 0x%x)\n", absolutePath, returnCode, reasonCode); -#endif - if (fileExists) { - tmpFileCleanup(absolutePath); - } - else { - fileDelete(absolutePath, &returnCode, &reasonCode); - } - return -1; - } - - tmpFileDelete(absolutePath); - return 0; -} - -void writeEmptyUnixFileAndRespond(HttpResponse *response, char *absolutePath, int forceWrite) { - if (!writeEmptyUnixFile(absolutePath, forceWrite)) { - response200WithMessage(response, "Successfully wrote a file"); - } - else { - respondWithJsonError(response, "Failed to write a file", 500, "Internal Server Error"); - } -} - -void respondWithUnixFileMetadata(HttpResponse *response, char *absolutePath) { - FileInfo info; - int returnCode; - int reasonCode; - int status = fileInfo(absolutePath, &info, &returnCode, &reasonCode); - - if (status == 0) { - jsonPrinter *out = respondWithJsonPrinter(response); - - setResponseStatus(response, 200, "OK"); - setDefaultJSONRESTHeaders(response); - writeHeader(response); - - int decimalMode = fileUnixMode(&info); - int octalMode = decimalToOctal(decimalMode); - - ISOTime timeStamp; - int unixTime = fileInfoUnixCreationTime(&info); - convertUnixToISO(unixTime, &timeStamp); - - jsonStart(out); - { - jsonAddString(out, "path", absolutePath); - jsonAddBoolean(out, "directory", fileInfoIsDirectory(&info)); - jsonAddInt64(out, "size", fileInfoSize(&info)); - jsonAddInt(out, "ccsid", fileInfoCCSID(&info)); - jsonAddString(out, "createdAt", timeStamp.data); - jsonAddInt(out, "mode", octalMode); - } - jsonEnd(out); - - finishResponse(response); - } - else { - respondWithUnixFileNotFound(response, TRUE); - } -} - - /* This program and the accompanying materials are made available under the terms of the Eclipse Public License v2.0 which accompanies diff --git a/c/httpserver.c b/c/httpserver.c index e016c1db6..f64fd0510 100644 --- a/c/httpserver.c +++ b/c/httpserver.c @@ -67,6 +67,8 @@ #include "rs_ssl.h" #endif +#include "../jwt/jwt/jwt.h" + /* bool and time_t are not available for * METAL builds, but casting them to ints * is valid. @@ -92,6 +94,40 @@ typedef int time_t; #define TEMP_TRACE(...) 3 #endif +#define AUTH_TRACE(...) do { \ + if (traceAuth) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } \ +} while (0) + +#define AUTH_DUMPBUF($buf, $len) do { \ + if (traceAuth) { \ + dumpbuffer((void *)(uintptr_t)$buf, $len); \ + fflush(stdout); \ + } \ +} while (0) + +#ifdef DEBUG +# define DEBUG_TRACE do { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } while (0) +#else +# define DEBUG_TRACE(...) do {} while (0) +#endif + +/* A *very special* ifdef had been chosen so we never accidentally ship an + * executable that can be persuaded to print out passwords + */ +#ifdef ENABLE_DANGEROUS_AUTH_TRACING +# define DANGEROUS_TRACE AUTH_TRACE +# define DANGEROUS_DUMPBUF AUTH_DUMPBUF +#else +# define DANGEROUS_TRACE(...) do {} while (0) +# define DANGEROUS_DUMPBUF(...) do {} while (0) +#endif + /***** General Primitives ******************************/ @@ -1002,6 +1038,10 @@ static void traceHeader(const char*line, int len) } void writeHeader(HttpResponse *response){ + if (response->sessionCookie) { + addStringHeader(response, "Set-Cookie", response->sessionCookie); + } + Socket *socket = response->socket; int returnCode; int reasonCode; @@ -1460,6 +1500,7 @@ HttpServer *makeHttpServer2(STCBase *base, server->config->sessionTokenKeySize = sizeof (sessionTokenKey); memcpy(&server->config->sessionTokenKey[0], &sessionTokenKey, sizeof (sessionTokenKey)); + server->config->authTokenType = SERVICE_AUTH_TOKEN_TYPE_LEGACY; return server; } @@ -1524,7 +1565,7 @@ int httpServerSetSessionTokenKey(HttpServer *server, unsigned int size, } HttpServer *makeHttpServer(STCBase *base, int port, int *returnCode, int *reasonCode){ - return makeHttpServer2(base, NULL, 0, port, returnCode, reasonCode); + return makeHttpServer2(base, NULL, port, 0, returnCode, reasonCode); } int registerHttpService(HttpServer *server, HttpService *service){ @@ -2382,7 +2423,7 @@ static int safAuthenticate(HttpService *service, HttpRequest *request){ if (authDataFound) { ACEE *acee = NULL; strupcase(request->username); /* upfold username */ -#ifdef NEVER_DEFINE +#ifdef ENABLE_DANGEROUS_AUTH_TRACING #ifdef METTLE printf("SAF auth for user: '%s'\n", request->username); #else @@ -2524,28 +2565,21 @@ int extractBasicAuth(HttpRequest *request, HttpHeader *authHeader){ char *ebcdicHeader = authHeader->nativeValue; int headerLength = strlen(asciiHeader); if (traceAuth){ - printf("authHeader(A): \n"); - dumpbuffer(asciiHeader,strlen(asciiHeader)); - printf("authHeader(E): \n"); - dumpbuffer(ebcdicHeader,strlen(ebcdicHeader)); - fflush(stdout); + AUTH_TRACE("authHeader(A): \n"); + AUTH_DUMPBUF(asciiHeader,strlen(asciiHeader)); + AUTH_TRACE("authHeader(E): \n"); + AUTH_DUMPBUF(ebcdicHeader,strlen(ebcdicHeader)); } - if (!memcmp(ebcdicHeader+0,"Basic ",6)){ + if (!strncmp(ebcdicHeader+0,"Basic ",6)){ int authStart = 6; int authEnd = authStart; int authLen; int decodedLength; char *encodedAuthString = NULL; char *authString = NULL; - if (traceAuth){ - printf("start authEnd loop\n"); - fflush(stdout); - } + AUTH_TRACE("start authEnd loop\n"); while ((authEnd < headerLength) && (ebcdicHeader[authEnd] > 0x041)){ -#ifdef DEBUG - printf("authEnd=%d\n",authEnd); - fflush(stdout); -#endif + DEBUG_TRACE("authEnd=%d\n",authEnd); authEnd++; } authLen = authEnd-authStart; @@ -2553,31 +2587,17 @@ int extractBasicAuth(HttpRequest *request, HttpHeader *authHeader){ authString = SLHAlloc(slh,authLen+1); memcpy(encodedAuthString,ebcdicHeader+authStart,authLen); encodedAuthString[authLen] = 0; - /* choosing *very special* ifdef so we never accidentally ship an - * executable that can be persuaded to print out passwords - */ -#ifdef NEVER_DEFINE - if (traceAuth){ - printf("encoded auth string\n"); - dumpbuffer(encodedAuthString,authLen); - } -#endif + DANGEROUS_TRACE("encoded auth string\n"); decodedLength = decodeBase64(encodedAuthString,authString); authString[decodedLength] = 0; -#ifdef NEVER_DEFINE if (FALSE) { - printf("decoded base 64, no unascify %s, len=%d\n",authString,strlen(authString)); - dumpbuffer(authString,strlen(authString)); - fflush(stdout); + DANGEROUS_TRACE("decoded base 64, no unascify %s, len=%d\n", + authString, + strlen(authString)); + DANGEROUS_DUMPBUF(authString,strlen(authString)); } -#endif destructivelyUnasciify(authString); /* don't upfold case */ -#ifdef NEVER_DEFINE - if (traceAuth){ - printf("encoded auth '%s' decoded '%s'\n",encodedAuthString,authString); - fflush(stdout); - } -#endif + DANGEROUS_TRACE("encoded auth '%s' decoded '%s'\n",encodedAuthString,authString); char *password = SLHAlloc(slh,decodedLength); int colonPos = indexOf(authString,decodedLength,':',0); if (colonPos){ @@ -2587,38 +2607,66 @@ int extractBasicAuth(HttpRequest *request, HttpHeader *authHeader){ request->password = password; strupcase(request->username); /* upfold username */ if (isLowerCasePasswordAllowed() || isPassPhrase(request->password)) { -#ifdef DEBUG - printf("mixed-case system or a pass phrase, not upfolding password\n"); -#endif + DEBUG_TRACE("mixed-case system or a pass phrase, not upfolding password\n"); /* don't upfold password */ } else { -#ifdef DEBUG - printf("non-mixed-case system, not a pass phrase, upfolding password\n"); -#endif + DEBUG_TRACE("non-mixed-case system, not a pass phrase, upfolding password\n"); strupcase(request->password); /* upfold password */ } -#ifdef DEBUG - printf("returning TRUE from extractBasicAuth\n"); - fflush(stdout); -#endif + DEBUG_TRACE("returning TRUE from extractBasicAuth\n"); return TRUE; } else{ - if (traceAuth){ - printf("no colon seen in basic auth string, returning FALSE\n"); - fflush(stdout); - } + AUTH_TRACE("no colon seen in basic auth string, returning FALSE\n"); return FALSE; } } else{ - if (traceAuth){ - printf("Non-basic auth\n"); - fflush(stdout); - } + AUTH_TRACE("Non-basic auth\n"); return FALSE; } } +int extractBearerToken(HttpRequest *request, HttpHeader *authHeader) { + const char *const asciiHeader = authHeader->value; + const char *const ebcdicHeader = authHeader->nativeValue; + const int headerLength = strlen(asciiHeader); + + AUTH_TRACE("authHeader(A): \n"); + AUTH_DUMPBUF(asciiHeader, strlen(asciiHeader)); + AUTH_TRACE("authHeader(E): \n"); + AUTH_DUMPBUF(ebcdicHeader, strlen(ebcdicHeader)); + + if (strncmp(ebcdicHeader, "Bearer ", 7) != 0) { + AUTH_TRACE("Non-bearer auth\n"); + return FALSE; + } + + const int tokenStart = 7; + int tokenEnd = tokenStart; + AUTH_TRACE("start tokenEnd loop\n"); + while ((tokenEnd < headerLength) && (ebcdicHeader[tokenEnd] > 0x041)){ + tokenEnd++; + DEBUG_TRACE("tokenEnd=%d\n", tokenEnd); + } + const int tokenLen = tokenEnd - tokenStart; + AUTH_TRACE("bearer token length\n", tokenLen); + + char *const tokenString = SLHAlloc(request->slh, tokenLen + 1); + AUTH_TRACE("bearer token buffer at %p\n", tokenString); + if (tokenString == NULL) { + return FALSE; + } + memcpy(&tokenString[0], &ebcdicHeader[tokenStart], tokenLen); + tokenString[tokenLen] = 0; + + /* choosing *very special* ifdef so we never accidentally ship an + * executable that can be persuaded to print out passwords + */ + + request->authToken = tokenString; + return TRUE; +} + #ifdef __ZOWE_OS_ZOS #define ONE_SECOND (4096*1000000) /* one second in STCK */ @@ -2659,10 +2707,8 @@ static int sessionTokenStillValid(HttpService *service, HttpRequest *request, ch char *decodedData = SLHAlloc(slh,strlen(sessionTokenText)); int decodedDataLength = decodeBase64(sessionTokenText,decodedData); - if (traceAuth){ - printf("decoded session token data for text %s\n",sessionTokenText); - dumpbuffer(decodedData,decodedDataLength); - } + AUTH_TRACE("decoded session token data for text %s\n",sessionTokenText); + AUTH_DUMPBUF(decodedData,decodedDataLength); char *plaintextSessionToken = NULL; int decodeRC = decodeSessionToken(slh, server->config, @@ -2675,19 +2721,17 @@ static int sessionTokenStillValid(HttpService *service, HttpRequest *request, ch int colonPos = indexOf(plaintextSessionToken, decodedDataLength, ':', 0); if (traceAuth){ - printf("colon pos %d;decoded data token:\n",colonPos); - dumpbuffer(decodedData,decodedDataLength); - printf("EBCDIC session token:\n"); - dumpbuffer(plaintextSessionToken,decodedDataLength); + AUTH_TRACE("colon pos %d;decoded data token:\n",colonPos); + AUTH_DUMPBUF(decodedData,decodedDataLength); + AUTH_TRACE("EBCDIC session token:\n"); + AUTH_DUMPBUF(plaintextSessionToken,decodedDataLength); } if (colonPos == -1){ return FALSE; } int colonPos2 = indexOf(plaintextSessionToken, decodedDataLength, ':', colonPos+1); - if (traceAuth){ - printf("colon pos2 %d;\n",colonPos2); - } + AUTH_TRACE("colon pos2 %d;\n",colonPos2); if (colonPos2 == -1){ return FALSE; } @@ -2697,31 +2741,25 @@ static int sessionTokenStillValid(HttpService *service, HttpRequest *request, ch uint64 interval = ((uint64)SESSION_VALIDITY_IN_SECONDS)*ONE_SECOND; uint64 difference = now-decodedTimestamp; - if (traceAuth){ - printf("decodedTimestamp=%llx;now=%llx;difference=%llx;interval=%llx;tokenUID=%llx;serverUID=%llx\n", - decodedTimestamp,now,difference,interval, serverInstanceUID, service->serverInstanceUID); - } + AUTH_TRACE("decodedTimestamp=%llx;now=%llx;difference=%llx;interval=%llx;tokenUID=%llx;serverUID=%llx\n", + decodedTimestamp,now,difference,interval, serverInstanceUID, service->serverInstanceUID); if (difference > interval){ - if(traceAuth){ - printf("returning FALSE\n"); - } + AUTH_TRACE("returning FALSE\n"); return FALSE; } if (serverInstanceUID != service->serverInstanceUID){ - if(traceAuth){ - printf("token from other server, returning FALSE\n"); - } + AUTH_TRACE("token from other server, returning FALSE\n"); return FALSE; } request->username = SLHAlloc(slh, colonPos+1); memcpy(request->username, plaintextSessionToken, colonPos); request->username[colonPos] = 0; - if(traceAuth){ - printf("returning TRUE\n"); - } + strupcase(request->username); + + AUTH_TRACE("returning TRUE\n"); return TRUE; } @@ -2755,105 +2793,206 @@ static char *generateSessionTokenKeyValue(HttpService *service, HttpRequest *req } static int serviceAuthNativeWithSessionToken(HttpService *service, HttpRequest *request, HttpResponse *response, - int *clearSessionToken){ + int *clearSessionToken){ int authDataFound = FALSE; HttpHeader *authenticationHeader = getHeader(request,"Authorization"); char *tokenCookieText = getCookieValue(request,SESSION_TOKEN_COOKIE_NAME); - if (traceAuth){ - printf("serviceAuthNativeWithSessionToken: authenticationHeader 0x%p, extractFunction 0x%p\n", - authenticationHeader, service->authExtractionFunction); - } - - if (service->authExtractionFunction != NULL) { - if (service->authExtractionFunction(service, request) == 0) { + + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: authenticationHeader 0x%p, authenticationHeader(hex) = 0x%x\n", + "extractFunction 0x%p\n", + authenticationHeader, + authenticationHeader, + service->authExtractionFunction); + + if (authenticationHeader) { + if (extractBasicAuth(request,authenticationHeader)){ authDataFound = TRUE; } - } else if (authenticationHeader) { - HttpHeader *authenticationHeader = getHeader(request,"Authorization"); -#ifdef DEBUG - printf("safAuth: auth header = 0x%x\n",authenticationHeader); - fflush(stdout); -#endif - if (authenticationHeader){ - if (extractBasicAuth(request,authenticationHeader)){ -#ifdef DEBUG - printf("back inside safAuthenticate after call to extractBasicAuth\n"); - fflush(stdout); -#endif - authDataFound = TRUE; - } - } + } else { + if (service->authExtractionFunction != NULL){ + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: authExtractionFunction 0x%p\n", + service->authExtractionFunction); + + if (service->authExtractionFunction(service, request) == 0){ + authDataFound = TRUE; + } + } } - + + response->sessionCookie = NULL; - strupcase(request->username); /* upfold username */ - char *username = request->username; + AUTH_TRACE("AUTH: tokenCookieText: %s\n",(tokenCookieText ? tokenCookieText : "")); - if (traceAuth){ - printf("AUTH: tokenCookieText: %s\n",(tokenCookieText ? tokenCookieText : "")); - } if (tokenCookieText){ + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: tokenCookieText: %s\n", + (tokenCookieText ? tokenCookieText : "")); + if (sessionTokenStillValid(service,request,tokenCookieText)){ - if (traceAuth){ - printf("auth cookie still good, renewing cookie\n"); - } - char *sessionToken = generateSessionTokenKeyValue(service,request,request->username); - if (sessionToken == NULL) { + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: Cookie still good, renewing cookie\n"); + char *sessionToken = generateSessionTokenKeyValue(service, request,request->username); + if (sessionToken == NULL){ return FALSE; } - addStringHeader(response,"Set-Cookie",sessionToken); response->sessionCookie = sessionToken; return TRUE; } else if (authDataFound){ if (nativeAuth(service,request)){ - if (traceAuth){ - printf("AUTH: cookie not valid, auth is good\n"); - } - char *sessionToken = generateSessionTokenKeyValue(service,request,username); - addStringHeader(response,"Set-Cookie",sessionToken); + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: Cookie not valid, auth is good\n"); + char *sessionToken = generateSessionTokenKeyValue(service,request,request->username); response->sessionCookie = sessionToken; return TRUE; } else{ - if (traceAuth){ - printf("cookie not valid, auth is bad\n"); - } + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: Cookie not valid, auth is bad\n"); /* NOTES: CLEAR SESSION TOKEN */ - addStringHeader(response,"Set-Cookie","jedHTTPSession=non-token"); response->sessionCookie = "non-token"; return FALSE; } } else{ - if (traceAuth){ - printf("AUTH: cookie not valid, no auth provided\n"); - } + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: Cookie not valid, no auth provided\n"); /* NOTES: CLEAR SESSION TOKEN */ - addStringHeader(response,"Set-Cookie","jedHTTPSession=non-token"); response->sessionCookie = "non-token"; return FALSE; } } else if (authDataFound){ if (nativeAuth(service,request)){ - if (traceAuth){ - printf("AUTH: auth header provided and works, before generate session token req=0x%x, username=0x%x, response=0x%p\n",request,username,response); - } - char *sessionToken = generateSessionTokenKeyValue(service,request,username); - addStringHeader(response,"Set-Cookie",sessionToken); + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: auth header provided and works, " + "before generate session token req=0x%x, username=0x%x, response=0x%p\n", + request,request->username,response); + + char *sessionToken = generateSessionTokenKeyValue(service,request,request->username); response->sessionCookie = sessionToken; return TRUE; } else{ - if (traceAuth){ - printf("AUTH: no cookie, but auth header, which wasn't good\n"); - } + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: No cookie, but auth header, which wasn't good\n"); + return FALSE; } } else{ /* neither cookie */ - if (traceAuth){ - printf("AUTH: neither cookie nor auth header\n"); + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, + "serviceAuthNativeWithSessionToken: Neither cookie nor auth header\n"); + + return FALSE; + } +} + +static int serviceAuthWithJwt(HttpService *service, + HttpRequest *request, + HttpResponse *response) { + int authDataFound = FALSE; + HttpHeader *const authorizationHeader = getHeader(request, "Authorization"); + char *tokenCookieText = getCookieValue(request,SESSION_TOKEN_COOKIE_NAME); + + AUTH_TRACE("serviceAuthWithJwt: authenticationHeader 0x%p," + " extractFunction 0x%p\n", + authorizationHeader, + service->authExtractionFunction); + + /* + * The extractor should look at the request and get the raw JWT from anywhere + * in the request it thinks it can find it (Authorization: Bearer, cookie, URL, + * etc) and store it in request->authToken. + * + * Then we *replace* request->authToken with a parsed JWT structure, so that + * the service handler can find the JWT there if it needs it. + * + * TODO: consider changing the architecture: what fields do we want in the + * request structure? + */ + if (service->authExtractionFunction != NULL) { + if (service->authExtractionFunction(service, request) == 0) { + authDataFound = TRUE; + } + } else if (authorizationHeader) { + DEBUG_TRACE("serviceAuthWithJwt: auth header = 0x%x\n", authorizationHeader); + if (extractBearerToken(request, authorizationHeader)) { + DEBUG_TRACE("back inside serviceAuthWithJwt after call to extractBearerToken\n"); + authDataFound = TRUE; } + } + + AUTH_TRACE("serviceAuthWithJwt: request->authToken %p\n", request->authToken); + if (request->authToken == NULL) { + return FALSE; + } + + JwtContext *const jwtContext = service->server->config->jwtContext; + if (jwtContext == NULL) { + return FALSE; + } + + int jwtRc = 0; + const Jwt *const jwt = jwtVerifyAndParseToken( + jwtContext, + request->authToken, + true, + request->slh, + &jwtRc); + AUTH_TRACE("serviceAuthWithJwt: jwtContext %p\n", jwtContext); + if (jwtRc != RC_JWT_OK) { + return FALSE; + } + + if (!jwtAreBasicClaimsValid(jwt, NULL)) { + AUTH_TRACE("serviceAuthWithJwt: basic claims invalid\n"); return FALSE; } + + request->authToken = jwt; + + if (service->authValidateFunction != NULL) { + return service->authValidateFunction(service, request); + } else { + if (jwt->subject == NULL) { + return FALSE; + } + request->username = SLHAlloc(request->slh, 1 + strlen(jwt->subject)); + if (request->username == NULL) { + return FALSE; + } + strcpy(request->username, jwt->subject); + strupcase(request->username); + return TRUE; + } +} + +int httpServerInitJwtContext(HttpServer *self, + bool legacyFallback, + const char *pkcs11TokenName, + const char *keyName, + int keyType, + int *makeContextRc, int *p11Rc, int *p11Rsn) { + JwtContext *const context = makeJwtContextForKeyInToken( + pkcs11TokenName, + keyName, + keyType, + makeContextRc, + p11Rc, + p11Rsn); + + AUTH_TRACE("jwt context for %s:%s: rc %d, context at %p\n", + pkcs11TokenName, keyName, + *makeContextRc, context); + + if (*makeContextRc != RC_JWT_OK) { + return 1; + } + self->config->jwtContext = context; + self->config->authTokenType = legacyFallback? + SERVICE_AUTH_TOKEN_TYPE_JWT_WITH_LEGACY_FALLBACK + : SERVICE_AUTH_TOKEN_TYPE_JWT; + return 0; } + #ifdef __ZOWE_OS_ZOS typedef struct HTTPServiceABENDInfo_tag { @@ -3034,7 +3173,20 @@ static int handleHttpService(HttpServer *server, request->authenticated = FALSE; break; case SERVICE_AUTH_NATIVE_WITH_SESSION_TOKEN: - request->authenticated = serviceAuthNativeWithSessionToken(service,request,response,&clearSessionToken); + switch (server->config->authTokenType) { + case SERVICE_AUTH_TOKEN_TYPE_JWT: + case SERVICE_AUTH_TOKEN_TYPE_JWT_WITH_LEGACY_FALLBACK: + request->authenticated = serviceAuthWithJwt(service, request, response); + + if (request->authenticated || + service->server->config->authTokenType + != SERVICE_AUTH_TOKEN_TYPE_JWT_WITH_LEGACY_FALLBACK) { + break; + } /* else fall through */ + case SERVICE_AUTH_TOKEN_TYPE_LEGACY: + request->authenticated = serviceAuthNativeWithSessionToken(service,request,response,&clearSessionToken); + break; + } break; } #ifdef DEBUG @@ -3479,7 +3631,6 @@ static void respondWithUnixFileInternal(HttpResponse* response, char* absolutePa static void respondWithUnixDirectoryInternal(HttpResponse* response, char* absolutePath, int jsonMode, int secureFlag); static void respondWithUnixFile(HttpResponse* response, char* absolutePath, int jsonMode, bool asB64); -static void respondWithUnixFile2(HttpService* service, HttpResponse* response, char* absolutePath, int jsonMode, int autocvt, bool asB64); void respondWithUnixDirectory(HttpResponse *response, char* absolutePath, int jsonMode); void respondWithUnixFileSafer(HttpResponse* response, char* absolutePath, int jsonMode); void respondWithUnixDirectorySafer(HttpResponse* response, char* absolutePath, int jsonMode); diff --git a/c/isgenq.c b/c/isgenq.c index b031be95e..00bcc08f7 100644 --- a/c/isgenq.c +++ b/c/isgenq.c @@ -31,11 +31,11 @@ __asm("GLBENQPL ISGENQ MF=(L,GLBENQPL)" : "DS"(GLBENQPL)); #endif -int isgenqGetExclusiveLockOrFail(const QName *qname, - const RName *rname, - uint8_t scope, - ENQToken *token, - int *reasonCode) { +int isgenqTryExclusiveLock(const QName *qname, + const RName *rname, + uint8_t scope, + ENQToken *token, + int *reasonCode) { QName localQName = *qname; RName localRName = *rname; @@ -145,6 +145,120 @@ int isgenqGetExclusiveLock(const QName *qname, return rc; } +int isgenqTrySharedLock(const QName *qname, + const RName *rname, + uint8_t scope, + ENQToken *token, + int *reasonCode) { + + QName localQName = *qname; + RName localRName = *rname; + +#ifdef METTLE + __asm(" ISGENQ MF=L" : "DS"(isgenqParmList)); + isgenqParmList = GLBENQPL; +#else + char isgenqParmList[512]; +#endif + + int rc = 0, rsn = 0; + __asm( + ASM_PREFIX + " PUSH USING \n" + " DROP \n" + "ENQOBTS LARL 2,ENQOBTS \n" + " USING ENQOBTS,2 \n" + " ISGENQ REQUEST=OBTAIN" + ",TEST=NO" + ",CONTENTIONACT=FAIL" + ",USERDATA=NO_USERDATA" + ",RESLIST=NO" + ",QNAME=(%2)" + ",RNAME=(%3)" + ",RNAMELEN=(%4)" + ",CONTROL=SHARED" + ",RESERVEVOLUME=NO" + ",SCOPE=VALUE" + ",SCOPEVAL=(%5)" + ",RNL=YES" + ",ENQTOKEN=(%6)" + ",COND=YES" + ",RETCODE=%0" + ",RSNCODE=%1" + ",PLISTVER=IMPLIED_VERSION" + ",MF=(E,(%7),COMPLETE)" + " \n" + " DROP \n" + " POP USING \n" + : "=m"(rc), "=m"(rsn) + : "r"(&localQName.value), "r"(&localRName.value), "r"(&localRName.length), + "r"(&scope), "r"(token), "r"(&isgenqParmList) + : "r0", "r1", "r2", "r14", "r15" + ); + + if (reasonCode != NULL) { + *reasonCode = rsn; + } + return rc; +} + +int isgenqGetSharedLock(const QName *qname, + const RName *rname, + uint8_t scope, + ENQToken *token, + int *reasonCode) { + + QName localQName = *qname; + RName localRName = *rname; + +#ifdef METTLE + __asm(" ISGENQ MF=L" : "DS"(isgenqParmList)); + isgenqParmList = GLBENQPL; +#else + char isgenqParmList[512]; +#endif + + int rc = 0, rsn = 0; + __asm( + ASM_PREFIX + " PUSH USING \n" + " DROP \n" + "ENQOBTSW LARL 2,ENQOBTSW \n" + " USING ENQOBTSW,2 \n" + " ISGENQ REQUEST=OBTAIN" + ",TEST=NO" + ",CONTENTIONACT=WAIT" + ",USERDATA=NO_USERDATA" + ",RESLIST=NO" + ",QNAME=(%2)" + ",RNAME=(%3)" + ",RNAMELEN=(%4)" + ",CONTROL=SHARED" + ",RESERVEVOLUME=NO" + ",SCOPE=VALUE" + ",SCOPEVAL=(%5)" + ",RNL=YES" + ",ENQTOKEN=(%6)" + ",COND=YES" + ",RETCODE=%0" + ",RSNCODE=%1" + ",PLISTVER=IMPLIED_VERSION" + ",MF=(E,(%7),COMPLETE)" + " \n" + " DROP \n" + " POP USING \n" + : "=m"(rc), "=m"(rsn) + : "r"(&localQName.value), "r"(&localRName.value), "r"(&localRName.length), + "r"(&scope), "r"(token), "r"(&isgenqParmList) + : "r0", "r1", "r2", "r14", "r15" + ); + + if (reasonCode != NULL) { + *reasonCode = rsn; + } + return rc; +} + int isgenqTestLock(const QName *qname, const RName *rname, uint8_t scope, @@ -201,6 +315,71 @@ int isgenqTestLock(const QName *qname, return rc; } +int isgenqTestExclusiveLock(const QName *qname, + const RName *rname, + uint8_t scope, + int *reasonCode) { + + return isgenqTestLock(qname, rname, scope, reasonCode); + +} + +int isgenqTestSharedLock(const QName *qname, + const RName *rname, + uint8_t scope, + int *reasonCode) { + + QName localQName = *qname; + RName localRName = *rname; + +#ifdef METTLE + __asm(" ISGENQ MF=L" : "DS"(isgenqParmList)); + isgenqParmList = GLBENQPL; +#else + char isgenqParmList[512]; +#endif + + ENQToken localToken; + + int rc = 0, rsn = 0; + __asm( + ASM_PREFIX + " PUSH USING \n" + " DROP \n" + "ENQOBTST LARL 2,ENQOBTST \n" + " USING ENQOBTST,2 \n" + " ISGENQ REQUEST=OBTAIN" + ",TEST=YES" + ",RESLIST=NO" + ",QNAME=(%2)" + ",RNAME=(%3)" + ",RNAMELEN=(%4)" + ",CONTROL=SHARED" + ",RESERVEVOLUME=NO" + ",SCOPE=VALUE" + ",SCOPEVAL=(%5)" + ",RNL=YES" + ",ENQTOKEN=(%6)" + ",COND=YES" + ",RETCODE=%0" + ",RSNCODE=%1" + ",PLISTVER=IMPLIED_VERSION" + ",MF=(E,(%7),COMPLETE)" + " \n" + " DROP \n" + " POP USING \n" + : "=m"(rc), "=m"(rsn) + : "r"(&localQName.value), "r"(&localRName.value), "r"(&localRName.length), + "r"(&scope), "r"(&localToken), "r"(&isgenqParmList) + : "r0", "r1", "r2", "r14", "r15" + ); + + if (reasonCode != NULL) { + *reasonCode = rsn; + } + return rc; +} + int isgenqReleaseLock(ENQToken *token, int *reasonCode) { #ifdef METTLE diff --git a/c/json.c b/c/json.c index 30f2ccf0c..61da696db 100644 --- a/c/json.c +++ b/c/json.c @@ -85,6 +85,9 @@ int jsonIsError(Json *json) { return json->type == JSON_TYPE_ERROR; } +static void +writeToBuffer(struct jsonPrinter_tag *p, char *text, int len); + jsonPrinter *makeJsonPrinter(int fd) { jsonPrinter *p = (jsonPrinter*) safeMalloc(sizeof (jsonPrinter), "JSON Printer"); @@ -131,6 +134,10 @@ jsonPrinter *makeCustomUtf8JsonPrinter(void (*writeMethod)(jsonPrinter *, char * return p; } +jsonPrinter *makeBufferJsonPrinter(int inputCCSID, JsonBuffer *buf) { + return makeCustomUtf8JsonPrinter(&writeToBuffer, buf, inputCCSID); +} + void jsonEnablePrettyPrint(jsonPrinter *p) { p->prettyPrint = TRUE; } @@ -762,6 +769,55 @@ int jsonCheckIOErrorFlag(jsonPrinter *p) { return p->ioErrorFlag; } +#define JSON_BUF_DEFAULT_SIZE 1024 + +JsonBuffer *makeJsonBuffer(void) { + JsonBuffer *buf = (void *)safeMalloc(sizeof (*buf), "JSON buffer"); + buf->data = safeMalloc(JSON_BUF_DEFAULT_SIZE, "JSON buffer data"); + buf->size = JSON_BUF_DEFAULT_SIZE; + buf->len = 0; + return buf; +} + +void jsonBufferTerminateString(JsonBuffer *buf) { + buf->data[buf->len] = '\0'; + buf->len++; +} + +void freeJsonBuffer(JsonBuffer *buf) { + safeFree(buf->data, buf->size); + safeFree((void *)buf, sizeof (*buf)); +} + +void jsonBufferRewind(JsonBuffer *buf) { + buf->len = 0; + memset(buf->data, '0', buf->size); +} + +static void +writeToBuffer(struct jsonPrinter_tag *p, char *text, int len) { + JsonBuffer *buf = p->customObject; + int bytesRemaining; + + while ((bytesRemaining = buf->size - buf->len) < len) { + if (buf->size > INT32_MAX / 2) { + jsonSetIOErrorFlag(p); + return; + } + int newSize = 2 * buf->size; + void *newData = safeRealloc(buf->data, newSize, buf->size, + "JSON buffer data realloc"); + if (newData == NULL) { + jsonSetIOErrorFlag(p); + return; + } + buf->size = newSize; + buf->data = newData; + } + memmove(&buf->data[buf->len], text, len); + buf->len += len; +} + #ifndef JSON_TOKEN_BUFFER_SIZE #define JSON_TOKEN_BUFFER_SIZE 16384 #endif @@ -1869,6 +1925,40 @@ Json *jsonParseUnterminatedString(ShortLivedHeap *slh, char *jsonString, int len return json; } +/* + * Converts the string from UTF-8 to `outputCCSID` before parsing. + * + * This is a quick hack and doesn't actually handle UTF-8 properly: + * - non-ascii characters in strings are not handled correctly (even if the + * consumer of this API is capable of handling them) + * - Unicode escapes ('\u1234') are not supported by the parser + * - the source code defines the tokens in the source code encoding anyway, + * if `outputCCSID` is significantly different, nothing good will happen + * */ +Json *jsonParseUnterminatedUtf8String(ShortLivedHeap *slh, int outputCCSID, + char *jsonUtf8String, int len, + char* errorBufferOrNull, int errorBufferSize) { + int convRc, convRsn; + int convesionOutputLength = 2 * len; + char *buffer; + + buffer = SLHAlloc(slh, convesionOutputLength); + if (buffer == NULL) { + snprintf(errorBufferOrNull, errorBufferSize, "not enough memory"); + return NULL; + } + convRc = convertCharset(jsonUtf8String, len, CCSID_UTF_8, + CHARSET_OUTPUT_USE_BUFFER, &buffer, convesionOutputLength, outputCCSID, + NULL, &convesionOutputLength, &convRsn); + if (convRc != 0) { + snprintf(errorBufferOrNull, errorBufferSize, "could not convert from UTF8:" + " conversion rc %d, reason %d", convRc, convRsn); + return NULL; + } + return jsonParseUnterminatedString(slh, buffer, convesionOutputLength, + errorBufferOrNull, errorBufferSize); +} + Json *jsonParseFile(ShortLivedHeap *slh, const char *filename, char* errorBufferOrNull, int errorBufferSize) { Json *json = NULL; int returnCode = 0; @@ -1904,8 +1994,6 @@ Json *jsonParseString(ShortLivedHeap *slh, char *jsonString, char* errorBufferOr return jsonParseUnterminatedString(slh,jsonString,strlen(jsonString),errorBufferOrNull,errorBufferSize); } - - void jsonPrint(jsonPrinter *printer, Json *json) { jsonPrintInternal(printer, NULL, json); } diff --git a/c/pause-element.c b/c/pause-element.c new file mode 100644 index 000000000..24404b833 --- /dev/null +++ b/c/pause-element.c @@ -0,0 +1,248 @@ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifdef METTLE +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif + +#include "zowetypes.h" +#include "zos.h" + +#include "pause-element.h" + +#ifndef __ZOWE_OS_ZOS +#error z/OS targets are supported only +#endif + +#pragma linkage(IEAVAPE2,OS) +#pragma linkage(IEAVDPE2,OS) +#pragma linkage(IEAVPSE2,OS) +#pragma linkage(IEAVRLS2,OS) +#pragma linkage(IEAVRPI2,OS) +#pragma linkage(IEAVTPE,OS) +#pragma linkage(IEAVXFR2,OS) + +#pragma linkage(IEA4APE2,OS) +#pragma linkage(IEA4DPE2,OS) +#pragma linkage(IEA4PSE2,OS) +#pragma linkage(IEA4RLS2,OS) +#pragma linkage(IEA4RPI2,OS) +#pragma linkage(IEA4TPE,OS) +#pragma linkage(IEA4XFR2,OS) + +#ifdef _LP64 +#define IEAVAPE2 IEA4APE2 +#define IEAVDPE2 IEA4DPE2 +#define IEAVPSE2 IEA4PSE2 +#define IEAVRLS2 IEA4RLS2 +#define IEAVRPI2 IEA4RPI2 +#define IEAVTPE IEA4TPE +#define IEAVXFR2 IEA4XFR2 +#endif + +int peAlloc(PET *result, + const PEStoken *ownerStoken, + PEReleaseCode releaseCode, + PEAuth authLevel, + bool isBranchLinkage) { + + int32_t rc = 0; + PEStoken stoken = {0}; + if (ownerStoken) { + stoken = *ownerStoken; + } + int32_t linkage = isBranchLinkage ? PE_LINKAGE_BRANCH : PE_LINKAGE_SVC; + + int wasProblemState; + int key; + if (isBranchLinkage) { + wasProblemState = supervisorMode(TRUE); + key = setKey(0); + } + + IEAVAPE2(&rc, &authLevel, result, &stoken, &releaseCode, &linkage); + + if (isBranchLinkage) { + setKey(key); + if (wasProblemState) { + supervisorMode(FALSE); + } + } + + return rc; +} + +int peDealloc(PET *token, bool isBranchLinkage) { + + int32_t rc = 0; + int32_t linkage = isBranchLinkage ? PE_LINKAGE_BRANCH : PE_LINKAGE_SVC; + + int wasProblemState; + int key; + if (isBranchLinkage) { + wasProblemState = supervisorMode(TRUE); + key = setKey(0); + } + + IEAVDPE2(&rc, token, &linkage); + + if (isBranchLinkage) { + setKey(key); + if (wasProblemState) { + supervisorMode(FALSE); + } + } + + return rc; +} + +int pePause(const PET *token, PET *newToken, + PEReleaseCode *releaseCode, + bool isBranchLinkage) { + + int32_t rc = 0; + int32_t linkage = isBranchLinkage ? PE_LINKAGE_BRANCH : PE_LINKAGE_SVC; + + int wasProblemState; + int key; + if (isBranchLinkage) { + wasProblemState = supervisorMode(TRUE); + key = setKey(0); + } + + IEAVPSE2(&rc, token, newToken, releaseCode, &linkage); + + if (isBranchLinkage) { + setKey(key); + if (wasProblemState) { + supervisorMode(FALSE); + } + } + + return rc; +} + +int peRelease(const PET *token, + PEReleaseCode releaseCode, + bool isBranchLinkage) { + + int32_t rc = 0; + int32_t linkage = isBranchLinkage ? PE_LINKAGE_BRANCH : PE_LINKAGE_SVC; + + int wasProblemState; + int key; + if (isBranchLinkage) { + wasProblemState = supervisorMode(TRUE); + key = setKey(0); + } + + IEAVRLS2(&rc, token, releaseCode, &linkage); + + if (isBranchLinkage) { + setKey(key); + if (wasProblemState) { + supervisorMode(FALSE); + } + } + + return rc; +} + +int peRetrieveInfo(const PET *token, + PEInfo *info, + bool isBranchLinkage) { + + int32_t rc = 0; + int32_t linkage = isBranchLinkage ? PE_LINKAGE_BRANCH : PE_LINKAGE_SVC; + + int wasProblemState; + int key; + if (isBranchLinkage) { + wasProblemState = supervisorMode(TRUE); + key = setKey(0); + } + + IEAVRPI2(&rc, &info->authLevel, token, &linkage, + &info->ownerStoken, &info->currentStoken, + &info->state, &info->releaseCode); + + if (isBranchLinkage) { + setKey(key); + if (wasProblemState) { + supervisorMode(FALSE); + } + } + + return rc; +} + +int peTest(const PET *token, + PEState *state, + PEReleaseCode *releaseCode) { + + int32_t rc = 0; + IEAVTPE(&rc, token, state, releaseCode); + + return rc; +} + +int peTranfer(const PET *token, PET *newToken, + PEReleaseCode *releaseCode, + const PET *targetToken, + PEReleaseCode targetReleaseCode, + bool isBranchLinkage) { + + int32_t rc = 0; + int32_t linkage = isBranchLinkage ? PE_LINKAGE_BRANCH : PE_LINKAGE_SVC; + + int wasProblemState; + int key; + if (isBranchLinkage) { + wasProblemState = supervisorMode(TRUE); + key = setKey(0); + } + + IEAVXFR2(&rc, token, newToken, releaseCode, targetToken, &targetReleaseCode, + &linkage); + + if (isBranchLinkage) { + setKey(key); + if (wasProblemState) { + supervisorMode(FALSE); + } + } + + return rc; +} + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + diff --git a/c/pc.c b/c/pc.c new file mode 100644 index 000000000..e52bad289 --- /dev/null +++ b/c/pc.c @@ -0,0 +1,697 @@ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifdef METTLE +#include +#include +#include +#include +#include +#include +#else +#include "stdbool.h" +#include "stddef.h" +#include "stdint.h" +#include "stdlib.h" +#include "string.h" +#endif + +#include "zowetypes.h" +#include "alloc.h" +#include "pc.h" + + +int pcSetAllAddressSpaceAuthority(int *reasonCode) { + + int axsetRC = 0; + __asm( + ASM_PREFIX + + " SYSSTATE PUSH \n" + " SYSSTATE OSREL=ZOSV1R6 \n" +#ifdef _LP64 + " SAM31 \n" + " SYSSTATE AMODE64=NO \n" +#endif + + " LA 1,1 allow SSAR authority to all A/S \n" + " AXSET AX=(1) \n" + +#ifdef _LP64 + " SAM64 \n" + " SYSSTATE AMODE64=YES \n" +#endif + " SYSSTATE POP \n" + + " ST 15,%[rc] \n" + + : [rc]"=m"(axsetRC) + : + : "r0", "r1", "r14", "r15" + ); + + if (axsetRC != 0) { + *reasonCode = axsetRC; + return RC_PC_AXSET_FAILED; + } + + return RC_PC_OK; +} + + +ZOWE_PRAGMA_PACK + +typedef struct PCLinkageIndexList_tag { + int indexCount; + PCLinkageIndex entries[32]; +} PCLinkageIndexList; + +typedef struct PCEntryTableTokenList_tag { + int tokenCount; + PCEntryTableToken entries[32]; +} PCEntryTableTokenList; + +ZOWE_PRAGMA_PACK_RESET + + +static int reserveLinkageIndex(PCLinkageIndexList * __ptr32 indexList, + bool isSystem, bool isReusable, + PCLinkageIndexSize lxSize) { + + typedef struct LXRESParmList_tag { + uint8_t formatByte; +#define LXRES_FORMAT_BYTE 0x00 + uint8_t optionByte; +#define LXRES_OPT_SYSTEM 0x80 +#define LXRES_OPT_REUSE 0x40 +#define LXRES_OPT_SIZE_16 0x20 +#define LXRES_OPT_SIZE_23 0x10 +#define LXRES_OPT_SIZE_24 0x08 +#define LXRES_OPT_EXLIST 0x04 +#define LXRES_OPT_RESERVED1 0x02 +#define LXRES_OPT_RESERVED2 0x01 + char reserved[2]; + PCLinkageIndexList * __ptr32 elxList; + } LXRESParmList; + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + LXRESParmList parmList; + ) + ); + + below2G->parmList.formatByte = LXRES_FORMAT_BYTE; + + if (isSystem) { + below2G->parmList.optionByte |= LXRES_OPT_SYSTEM; + } + + if (isReusable) { + below2G->parmList.optionByte |= LXRES_OPT_REUSE; + } + + switch (lxSize) { + case LX_SIZE_12: + break; + case LX_SIZE_16: + below2G->parmList.optionByte |= LXRES_OPT_SIZE_16; + break; + case LX_SIZE_23: + below2G->parmList.optionByte |= LXRES_OPT_SIZE_23; + break; + case LX_SIZE_24: + below2G->parmList.optionByte |= LXRES_OPT_SIZE_24; + break; + default: + break; + } + + below2G->parmList.optionByte |= LXRES_OPT_EXLIST; + below2G->parmList.elxList = indexList; + + int lxresRC = 0; + __asm( + ASM_PREFIX + + " SYSSTATE PUSH \n" + " SYSSTATE OSREL=ZOSV1R6 \n" +#ifdef _LP64 + " SAM31 \n" + " SYSSTATE AMODE64=NO \n" +#endif + + " LXRES MF=(E,(%[parm])) \n" + +#ifdef _LP64 + " SAM64 \n" + " SYSSTATE AMODE64=YES \n" +#endif + " SYSSTATE POP \n" + + " ST 15,%[rc] \n" + + : [rc]"=m"(lxresRC) + : [parm]"r"(&below2G->parmList) + : "r0", "r1", "r14", "r15" + ); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + + return lxresRC; +} + + +static int freeLinkageIndex(PCLinkageIndexList * __ptr32 indexList, + bool forced) { + + typedef struct LXFREParmList_tag { + uint8_t formatByte; +#define LXFRE_FORMAT_BYTE 0x00 + uint8_t optionByte; +#define LXFRE_OPT_FORCE 0x80 +#define LXFRE_OPT_EXLIST 0x40 + char reserved[2]; + PCLinkageIndexList * __ptr32 elxList; + } LXFREParmList; + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + LXFREParmList parmList; + ) + ); + + below2G->parmList.formatByte = LXFRE_FORMAT_BYTE; + + if (forced) { + below2G->parmList.optionByte |= LXFRE_OPT_FORCE; + } + + below2G->parmList.optionByte |= LXFRE_OPT_EXLIST; + + below2G->parmList.elxList = indexList; + + int lxfreRC = 0; + __asm( + ASM_PREFIX + + " SYSSTATE PUSH \n" + " SYSSTATE OSREL=ZOSV1R6 \n" +#ifdef _LP64 + " SAM31 \n" + " SYSSTATE AMODE64=NO \n" +#endif + " LXFRE MF=(E,(%[parm])) \n" +#ifdef _LP64 + " SAM64 \n" + " SYSSTATE AMODE64=YES \n" +#endif + " SYSSTATE POP \n" + + " ST 15,%[rc] \n" + + : [rc]"=m"(lxfreRC) + : [parm]"r"(&below2G->parmList) + : "r0", "r1", "r14", "r15" + ); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + + return lxfreRC; +} + + +int pcReserveLinkageIndex(bool isSystem, bool isReusable, + PCLinkageIndexSize indexSize, + PCLinkageIndex *result, + int *reasonCode) { + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + PCLinkageIndexList indexList; + ) + ); + + below2G->indexList.indexCount = 1; + + int rc = reserveLinkageIndex(&below2G->indexList, isSystem, isReusable, indexSize); + if (rc == 0) { + *result = below2G->indexList.entries[0]; + } + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + + if (rc != 0) { + *reasonCode = rc; + return RC_PC_LXRES_FAILED; + } + + return RC_PC_OK; +} + + +int pcFreeLinkageIndex(PCLinkageIndex index, bool forced, int *reasonCode) { + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + PCLinkageIndexList indexList; + ) + ); + + below2G->indexList.indexCount = 1; + below2G->indexList.entries[0] = index; + + int rc = freeLinkageIndex(&below2G->indexList, forced); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + + if (rc != 0) { + *reasonCode = rc; + return RC_PC_LXFRE_FAILED; + } + + return RC_PC_OK; +} + +ZOWE_PRAGMA_PACK + +#define ETD_MAX_ENTRY_COUNT 256 + +typedef struct ETDELE_tag { + uint8_t index; + uint8_t flag; +#define ETDELE_FLAG_SUP 0x80 +#define ETDELE_FLAG_SSWITCH 0x40 + char reserved[2]; + union { + char pro[8]; + struct { + uint32_t zeros; + uint32_t address; + } routine; + }; + uint16_t akm; + char ekm[2]; + uint32_t par1; + uint8_t optb1; +#define ETDELE_OPTB1_STACKING_PC 0x80 +#define ETDELE_OPTB1_EXTENDED_AMODE 0x40 +#define ETDELE_OPTB1_REPLACE_PSW 0x10 +#define ETDELE_OPTB1_REPLACE_PKM 0x08 +#define ETDELE_OPTB1_REPLACE_EAX 0x04 +#define ETDELE_OPTB1_AR_MODE 0x02 +#define ETDELE_OPTB1_SASN_NEW 0x01 + uint8_t ek; + char eax[2]; + char arr[8]; + uint32_t par2; + char lpafl[4]; +} ETDELE; + +typedef struct ETD_tag { + char format; +#define ETD_FORMAT 0x01 + char hflag; + short entryNumber; + ETDELE entries[ETD_MAX_ENTRY_COUNT]; +} ETD; + + +ZOWE_PRAGMA_PACK_RESET + +typedef struct ETD_tag EntryTableDescriptor; + + +EntryTableDescriptor *pcMakeEntryTableDescriptor(void) { + + EntryTableDescriptor *descriptor = + (EntryTableDescriptor *)safeMalloc(sizeof(EntryTableDescriptor), "ETD"); + if (descriptor == NULL) { + return NULL; + } + + memset(descriptor, 0, sizeof(EntryTableDescriptor)); + + descriptor->format = ETD_FORMAT; + + return descriptor; +} + + +int pcAddToEntryTableDescriptor(EntryTableDescriptor *descriptor, + int (* __ptr32 routine)(void), + uint32_t routineParameter1, + uint32_t routineParameter2, + bool isSASNOld, + bool isAMODE64, + bool isSUP, + bool isSpaceSwitch, + int key) { + + if (descriptor->entryNumber == ETD_MAX_ENTRY_COUNT) { + return RC_PC_ETD_FULL; + } + + ETDELE *entry = &descriptor->entries[descriptor->entryNumber]; + memset(entry, 0, sizeof(ETDELE)); + + entry->index = descriptor->entryNumber; + + if (isSUP) { + entry->flag |= ETDELE_FLAG_SUP; + } + if (isSpaceSwitch) { + entry->flag |= ETDELE_FLAG_SSWITCH; + } + + entry->routine.address = (uint32_t)routine; + entry->akm = 0xFFFF; /* AKM 0:15 */ + entry->par1 = routineParameter1; + entry->par2 = routineParameter2; + + entry->optb1 |= ETDELE_OPTB1_STACKING_PC; + entry->optb1 |= ETDELE_OPTB1_REPLACE_PSW; + if (!isSASNOld) { + entry->optb1 |= ETDELE_OPTB1_SASN_NEW; + } + if (isAMODE64) { + entry->optb1 |= ETDELE_OPTB1_EXTENDED_AMODE; + } + + entry->ek = (key << 4); + + descriptor->entryNumber++; + + return RC_PC_OK; +} + + +void pcRemoveEntryTableDescriptor(EntryTableDescriptor *descriptor) { + safeFree((char *)descriptor, sizeof(EntryTableDescriptor)); +} + + +int pcCreateEntryTable(const EntryTableDescriptor *descriptor, + PCEntryTableToken *token, + int *reasonCode) { + + int etcreRC = 0; + __asm( + ASM_PREFIX + + " SYSSTATE PUSH \n" + " SYSSTATE OSREL=ZOSV1R6 \n" +#ifdef _LP64 + " SAM31 \n" + " SYSSTATE AMODE64=NO \n" +#endif + + " ETCRE ENTRIES=(%[descriptor]) \n" + +#ifdef _LP64 + " SAM64 \n" + " SYSSTATE AMODE64=YES \n" +#endif + " SYSSTATE POP \n" + + " ST 15,%[rc] \n" + " ST 0,0(%[token]) \n" + + : [rc]"=m"(etcreRC) + : [descriptor]"r"(descriptor), [token]"r"(token) + : "r0", "r1", "r14", "r15" + ); + + if (etcreRC != 0) { + *reasonCode = etcreRC; + return RC_PC_ETCRE_FAILED; + } + + return RC_PC_OK; +} + + +int pcDestroyEntryTable(PCEntryTableToken token, bool purge, int *reasonCode) { + + typedef struct ETDESParmList_tag { + uint8_t formatByte; +#define ETDES_FORMAT_BYTE 0x00 + uint8_t optionByte; + #define ETDES_OPT_PURGE 0x80 + char reserved[2]; + PCEntryTableToken * __ptr32 token; + } ETDESParmList; + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + ETDESParmList parmList; + PCEntryTableToken token; + ) + ); + + below2G->parmList.formatByte = ETDES_FORMAT_BYTE; + + if (purge) { + below2G->parmList.optionByte |= ETDES_OPT_PURGE; + } + + below2G->token = token; + below2G->parmList.token = &below2G->token; + + int etdesRC = 0; + __asm( + ASM_PREFIX + + " SYSSTATE PUSH \n" + " SYSSTATE OSREL=ZOSV1R6 \n" +#ifdef _LP64 + " SAM31 \n" + " SYSSTATE AMODE64=NO \n" +#endif + + " ETDES MF=(E,(%[parm])) \n" + +#ifdef _LP64 + " SAM64 \n" + " SYSSTATE AMODE64=YES \n" +#endif + " SYSSTATE POP \n" + + " ST 15,%[rc] \n" + + : [rc]"=m"(etdesRC) + : [parm]"r"(&below2G->parmList) + : "r0", "r1", "r14", "r15" + ); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + + if (etdesRC != 0) { + *reasonCode = etdesRC; + return RC_PC_ETDES_FAILED; + } + + return RC_PC_OK; +} + + +static int connectEntryTable(PCEntryTableTokenList * __ptr32 tokenList, + PCLinkageIndexList * __ptr32 elxList) { + + typedef struct ETCONParmList_tag { + uint8_t formatByte; +#define ETCON_FORMAT_BYTE 0x00 + uint8_t optionByte; +#define ETCON_OPT_EXLIST 0x80 + char reserved[2]; + PCEntryTableTokenList* __ptr32 tokenList; + PCLinkageIndexList * __ptr32 elxList; + } ETCONParmList; + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + ETCONParmList parmList; + ) + ); + + below2G->parmList.formatByte = ETCON_FORMAT_BYTE; + below2G->parmList.optionByte |= ETCON_OPT_EXLIST; + below2G->parmList.tokenList = tokenList; + below2G->parmList.elxList = elxList; + + int etconRC = 0; + __asm( + ASM_PREFIX + + " SYSSTATE PUSH \n" + " SYSSTATE OSREL=ZOSV1R6 \n" +#ifdef _LP64 + " SAM31 \n" + " SYSSTATE AMODE64=NO \n" +#endif + + " ETCON MF=(E,(%[parm])) \n" + +#ifdef _LP64 + " SAM64 \n" + " SYSSTATE AMODE64=YES \n" +#endif + " SYSSTATE POP \n" + + " ST 15,%[rc] \n" + + : [rc]"=m"(etconRC) + : [parm]"r"(&below2G->parmList) + : "r0", "r1", "r14", "r15" + ); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + + return etconRC; +} + + +static int disconnectEntryTable(PCEntryTableTokenList * __ptr32 tokenList) { + + int etdisRC = 0; + __asm( + ASM_PREFIX + + " SYSSTATE PUSH \n" + " SYSSTATE OSREL=ZOSV1R6 \n" +#ifdef _LP64 + " SAM31 \n" + " SYSSTATE AMODE64=NO \n" +#endif + + " ETDIS TKLIST=(%[tokens]) \n" + +#ifdef _LP64 + " SAM64 \n" + " SYSSTATE AMODE64=YES \n" +#endif + " SYSSTATE POP \n" + + " ST 15,%[rc] \n" + + : [rc]"=m"(etdisRC) + : [tokens]"r"(tokenList) + : "r0", "r1", "r14", "r15" + ); + + return etdisRC; +} + + +int pcConnectEntryTable(PCEntryTableToken token, PCLinkageIndex index, + int *reasonCode) { + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + PCEntryTableTokenList tokenList; + PCLinkageIndexList indexList; + ) + ); + + below2G->tokenList.tokenCount = 1; + below2G->tokenList.entries[0] = token; + + below2G->indexList.indexCount = 1; + below2G->indexList.entries[0] = index; + + int rc = connectEntryTable(&below2G->tokenList, &below2G->indexList); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + + if (rc != 0) { + *reasonCode = rc; + return RC_PC_ETCON_FAILED; + } + + return RC_PC_OK; +} + +int pcDisconnectEntryTable(PCEntryTableToken token, int *reasonCode) { + + ALLOC_STRUCT31( + STRUCT31_NAME(below2G), + STRUCT31_FIELDS( + PCEntryTableTokenList tokenList; + ) + ); + + below2G->tokenList.tokenCount = 1; + below2G->tokenList.entries[0] = token; + + int rc = disconnectEntryTable(&below2G->tokenList); + + FREE_STRUCT31( + STRUCT31_NAME(below2G) + ); + + if (rc != 0) { + *reasonCode = rc; + return RC_PC_ETDIS_FAILED; + } + + return RC_PC_OK; +} + +int pcCallRoutine(uint32_t pcNumber, uint32_t sequenceNumber, void *parmBlock) { + + int returnCode = 0; + __asm( + ASM_PREFIX + " LMH 15,15,%[sn] \n" + " L 14,%[pcn] \n" + " XGR 1,1 \n" + " LA 1,0(%[parm]) \n" + " PC 0(14) \n" + " ST 15,%[rc] \n" + : [rc]"=m"(returnCode) + : [pcn]"m"(pcNumber), [sn]"m"(sequenceNumber), [parm]"r"(parmBlock) + : "r1", "r14", "r15" + ); + + return returnCode; +} + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + diff --git a/c/shrmem64.c b/c/shrmem64.c new file mode 100644 index 000000000..e6b4f767f --- /dev/null +++ b/c/shrmem64.c @@ -0,0 +1,375 @@ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifdef METTLE +#include +#include +#include +#include +#else +#include "stdbool.h" +#include "stddef.h" +#include "stdint.h" +#endif + +#include "shrmem64.h" +#include "zos.h" + +#ifndef _LP64 +#error ILP32 is not supported +#endif + +typedef uint64_t MemObj; + +#define IARV64_V4PLIST_SIZE 160 + +static bool isIARV64OK(int iarv64RC) { + return iarv64RC < 8; +} + +static int makeRSN(int shrmem64RC, int iarv64RC, int iarv64RSN) { + + int rc = ((unsigned)shrmem64RC << 24) | + ((unsigned)iarv64RC << 16) | + ((iarv64RSN >> 8) & 0x0000FFFF); + + return rc; +} + +static MemObj getSharedMemObject(uint64_t segmentCount, + MemObjToken token, + uint32_t *iarv64RC, + uint32_t *iarv64RSN) { + + MemObj result = 0; + int localRC = 0; + int localRSN = 0; + char parmList[IARV64_V4PLIST_SIZE] = {0}; + + __asm( + ASM_PREFIX + " IARV64 REQUEST=GETSHARED" + ",USERTKN=(%[token])" + ",COND=YES" + ",SEGMENTS=(%[size])" + ",ORIGIN=(%[result])" + ",RETCODE=%[rc]" + ",RSNCODE=%[rsn]" + ",PLISTVER=4" + ",MF=(E,(%[parm]),COMPLETE) \n" + : [rc]"=m"(localRC), [rsn]"=m"(localRSN) + : [token]"r"(&token), [size]"r"(&segmentCount), [result]"r"(&result), + [parm]"r"(&parmList) + : "r0", "r1", "r14", "r15" + ); + + if (iarv64RC) { + *iarv64RC = localRC; + } + if (iarv64RSN) { + *iarv64RSN = localRSN; + } + + return result; +} + +static void shareMemObject(MemObj object, + MemObjToken token, + uint32_t *iarv64RC, + uint32_t *iarv64RSN) { + + int localRC = 0; + int localRSN = 0; + char parmList[IARV64_V4PLIST_SIZE] = {0}; + + struct { + MemObj vsa; + uint64_t reserved; + } rangeList = {object, 0}; + + uint64_t rangeListAddress = (uint64_t)&rangeList; + + __asm( + ASM_PREFIX + " IARV64 REQUEST=SHAREMEMOBJ" + ",USERTKN=(%[token])" + ",RANGLIST=(%[range])" + ",NUMRANGE=1" + ",COND=YES" + ",RETCODE=%[rc]" + ",RSNCODE=%[rsn]" + ",PLISTVER=4" + ",MF=(E,(%[parm]),COMPLETE) \n" + : [rc]"=m"(localRC), [rsn]"=m"(localRSN) + : [token]"r"(&token), [range]"r"(&rangeListAddress), [parm]"r"(&parmList) + : "r0", "r1", "r14", "r15" + ); + + if (iarv64RC) { + *iarv64RC = localRC; + } + if (iarv64RSN) { + *iarv64RSN = localRSN; + } + +} + +static void detachSingleSharedMemObject(MemObj object, + MemObjToken token, + uint32_t *iarv64RC, + uint32_t *iarv64RSN) { + + int localRC = 0; + int localRSN = 0; + char parmList[IARV64_V4PLIST_SIZE] = {0}; + + __asm( + ASM_PREFIX + " IARV64 REQUEST=DETACH" + ",MATCH=SINGLE" + ",MEMOBJSTART=(%[mobj])" + ",MOTKN=(%[token])" + ",MOTKNCREATOR=USER" + ",AFFINITY=LOCAL" + ",OWNER=YES" + ",COND=YES" + ",RETCODE=%[rc]" + ",RSNCODE=%[rsn]" + ",PLISTVER=4" + ",MF=(E,(%[parm]),COMPLETE) \n" + : [rc]"=m"(localRC), [rsn]"=m"(localRSN) + : [mobj]"r"(&object), [parm]"r"(&parmList), [token]"r"(&token) + : "r0", "r1", "r14", "r15" + ); + + if (iarv64RC) { + *iarv64RC = localRC; + } + if (iarv64RSN) { + *iarv64RSN = localRSN; + } + +} + +static void detachSharedMemObjects(MemObjToken token, + uint32_t *iarv64RC, + uint32_t *iarv64RSN) { + + int localRC = 0; + int localRSN = 0; + char parmList[IARV64_V4PLIST_SIZE] = {0}; + + __asm( + ASM_PREFIX + " IARV64 REQUEST=DETACH" + ",MATCH=MOTOKEN" + ",MOTKN=(%[token])" + ",MOTKNCREATOR=USER" + ",AFFINITY=LOCAL" + ",OWNER=YES" + ",COND=YES" + ",RETCODE=%[rc]" + ",RSNCODE=%[rsn]" + ",PLISTVER=4" + ",MF=(E,(%[parm]),COMPLETE) \n" + : [rc]"=m"(localRC), [rsn]"=m"(localRSN) + : [token]"r"(&token), [parm]"r"(&parmList) + : "r0", "r1", "r14", "r15" + ); + + if (iarv64RC) { + *iarv64RC = localRC; + } + if (iarv64RSN) { + *iarv64RSN = localRSN; + } + +} + + +static void removeSystemInterestForAllObjects(MemObjToken token, + uint32_t *iarv64RC, + uint32_t *iarv64RSN) { + + int localRC = 0; + int localRSN = 0; + char parmList[IARV64_V4PLIST_SIZE] = {0}; + + __asm( + ASM_PREFIX + " IARV64 REQUEST=DETACH" + ",MATCH=MOTOKEN" + ",MOTKN=(%[token])" + ",MOTKNCREATOR=USER" + ",AFFINITY=SYSTEM" + ",COND=YES" + ",RETCODE=%[rc]" + ",RSNCODE=%[rsn]" + ",PLISTVER=4" + ",MF=(E,(%[parm]),COMPLETE) \n" + : [rc]"=m"(localRC), [rsn]"=m"(localRSN) + : [token]"r"(&token), [parm]"r"(&parmList) + : "r0", "r1", "r14", "r15" + ); + + if (iarv64RC) { + *iarv64RC = localRC; + } + if (iarv64RSN) { + *iarv64RSN = localRSN; + } + +} + +static void removeSystemInterestForSingleObject(MemObj object, + MemObjToken token, + uint32_t *iarv64RC, + uint32_t *iarv64RSN) { + + int localRC = 0; + int localRSN = 0; + char parmList[IARV64_V4PLIST_SIZE] = {0}; + + __asm( + ASM_PREFIX + " IARV64 REQUEST=DETACH" + ",MATCH=SINGLE" + ",MEMOBJSTART=(%[mobj])" + ",MOTKN=(%[token])" + ",MOTKNCREATOR=USER" + ",AFFINITY=SYSTEM" + ",COND=YES" + ",RETCODE=%[rc]" + ",RSNCODE=%[rsn]" + ",PLISTVER=4" + ",MF=(E,(%[parm]),COMPLETE) \n" + : [rc]"=m"(localRC), [rsn]"=m"(localRSN) + : [mobj]"r"(&object), [token]"r"(&token), [parm]"r"(&parmList) + : "r0", "r1", "r14", "r15" + ); + + if (iarv64RC) { + *iarv64RC = localRC; + } + if (iarv64RSN) { + *iarv64RSN = localRSN; + } + +} + +MemObjToken shrmem64GetAddressSpaceToken(void) { + + union { + MemObj token; + struct { + ASCB * __ptr32 ascb; + uint32_t asid; + }; + } result = { .ascb = getASCB(), .asid = result.ascb->ascbasid }; + + return result.token; +} + +int shrmem64Alloc(MemObjToken userToken, size_t size, void **result, int *rsn) { + + uint32_t iarv64RC = 0, iarv64RSN = 0; + + /* + * Convert size in bytes into segments (megabytes), round up if necessary. + */ + uint64_t segmentCount = 0; + if ((size & 0xFFFFF) == 0) { + segmentCount = size >> 20; + } else{ + segmentCount = (size >> 20) + 1; + } + + MemObj mobj = getSharedMemObject(segmentCount, userToken, + &iarv64RC, &iarv64RSN); + if (!isIARV64OK(iarv64RC)) { + *rsn = makeRSN(RC_SHRMEM64_GETSHARED_FAILED, iarv64RC, iarv64RSN); + return RC_SHRMEM64_GETSHARED_FAILED; + } + + *result = (void *)mobj; + + return RC_SHRMEM64_OK; +} + +int shrmem64Release(MemObjToken userToken, void *target, int *rsn) { + + uint32_t iarv64RC = 0, iarv64RSN = 0; + + MemObj mobj = (MemObj)target; + + removeSystemInterestForSingleObject(mobj, userToken, &iarv64RC, &iarv64RSN); + if (!isIARV64OK(iarv64RC)) { + *rsn = makeRSN(RC_SHRMEM64_SINGLE_SYS_DETACH_FAILED, iarv64RC, iarv64RSN); + return RC_SHRMEM64_SINGLE_SYS_DETACH_FAILED; + } + + return RC_SHRMEM64_OK; +} + +int shrmem64ReleaseAll(MemObjToken userToken, int *rsn) { + + uint32_t iarv64RC = 0, iarv64RSN = 0; + + removeSystemInterestForAllObjects(userToken, &iarv64RC, &iarv64RSN); + if (!isIARV64OK(iarv64RC)) { + *rsn = makeRSN(RC_SHRMEM64_ALL_SYS_DETACH_FAILED, iarv64RC, iarv64RSN); + return RC_SHRMEM64_ALL_SYS_DETACH_FAILED; + } + + return RC_SHRMEM64_OK; +} + +int shrmem64GetAccess(MemObjToken userToken, void *target, int *rsn) { + + uint32_t iarv64RC = 0, iarv64RSN = 0; + + MemObj mobj = (MemObj)target; + + shareMemObject(mobj, userToken, &iarv64RC, &iarv64RSN); + if (!isIARV64OK(iarv64RC)) { + *rsn = makeRSN(RC_SHRMEM64_SHAREMEMOBJ_FAILED, iarv64RC, iarv64RSN); + return RC_SHRMEM64_SHAREMEMOBJ_FAILED; + } + + return RC_SHRMEM64_OK; +} + +int shrmem64RemoveAccess(MemObjToken userToken, void *target, int *rsn) { + + uint32_t iarv64RC = 0, iarv64RSN = 0; + + MemObj mobj = (MemObj)target; + + detachSingleSharedMemObject(mobj, userToken, &iarv64RC, &iarv64RSN); + if (!isIARV64OK(iarv64RC)) { + *rsn = makeRSN(RC_SHRMEM64_DETACH_FAILED, iarv64RC, iarv64RSN); + return RC_SHRMEM64_DETACH_FAILED; + } + + return RC_SHRMEM64_OK; +} + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/c/utils.c b/c/utils.c index 09bfec7af..283c98d16 100644 --- a/c/utils.c +++ b/c/utils.c @@ -160,6 +160,22 @@ int indexOfString(char *str, int len, char *searchString, int startPos){ return -1; } +int lastIndexOfString(char *str, int len, char *searchString) { + int searchLen = strlen(searchString); + int pos = len - searchLen; + + if (searchLen > len) { + return -1; + } + while (pos >= 0) { + if (!memcmp(str+pos,searchString,searchLen)) { + return pos; + } + pos--; + } + return -1; +} + #if defined(__ZOWE_OS_WINDOWS) || defined(__ZOWE_OS_LINUX) || defined(METTLE) || defined(__ZOWE_OS_AIX) static int cheesyInsensitiveMatch(char *str, int len, char *searchString, int searchLen){ @@ -1027,15 +1043,23 @@ static char binToEB64[] ={0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xd1,0xd2 0xa6,0xa7,0xa8,0xa9,0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0x4e,0x61}; -#define ENCODE64_SIZE(SZ) (2 + 4 * ((SZ + 2) / 3)) - -char *encodeBase64(ShortLivedHeap *slh, char *buf, int size, int *resultSize, int useEbcdic){ - char *data = (char*)buf; +char *encodeBase64(ShortLivedHeap *slh, const char buf[], int size, int *resultSize, int useEbcdic){ + int allocSize = BASE64_ENCODE_SIZE(size)+1; /* +1 for null term */ char *result = NULL; + if (result = (slh ? SLHAlloc(slh,allocSize) : safeMalloc31(allocSize,"BASE64"))) { + encodeBase64NoAlloc(buf, size, result, resultSize, useEbcdic); + return result; + } else{ + *resultSize = 0; + return NULL; + } +} + +void encodeBase64NoAlloc(const char buf[], int size, char result[], int *resultSize, + int useEbcdic){ + const char *data = (char*)buf; char equalsChar = (useEbcdic ? '=' : 0x3D); char *translation = (useEbcdic ? binToEB64 : binToB64); - int allocSize = ENCODE64_SIZE(size)+1; /* +1 for null term */ - if (result = (slh ? SLHAlloc(slh,allocSize) : safeMalloc31(allocSize,"BASE64"))) { int numFullGroups = size / 3; int numBytesInPartialGroup = size - 3 * numFullGroups; int inCursor = 0; @@ -1070,17 +1094,83 @@ char *encodeBase64(ShortLivedHeap *slh, char *buf, int size, int *resultSize, in } *resultSize = resPtr - result; result[*resultSize] = 0; - return result; - } else{ - *resultSize = 0; - return NULL; +} + +/* + * Assumes "EBCDIC base64" on EBCDIC platforms + */ +int base64ToBase64url(char *s) { + int i = 0; + unsigned int c; + + while ((c = s[i]) != '\0') { + switch (c) { + case '+': + s[i] = '-'; + break; + case '/': + s[i] = '_'; + break; + } + i++; + } + while ((i > 0) && s[i - 1] == '=') { + s[--i] = '\0'; + } + return i; +} + +/* + * Assumes "EBCDIC base64" on EBCDIC platforms + */ +int base64urlToBase64(char *s, int bufSize) { + int i = 0; + unsigned int c; + int rc = 0; + + while (((c = s[i]) != '\0') && (i < bufSize)) { + switch (c) { + case '-': + s[i] = '+'; + break; + case '_': + s[i] = '/'; + break; + } + i++; + } + switch (i % 4) { + case 2: + if (i >= bufSize - 2) { + rc = -2; + break; + } else { + s[i++] = '='; + rc++; + /* fall through */ + } + case 3: + if (i >= bufSize - 1) { + rc = -1; + break; + } else { + s[i++] = '='; + rc++; + /* fall through */ + } + case 0: + s[i++] = '\0'; + break; + default: + rc = -3; } + return rc; } char *destructivelyUnasciify(char *s){ - int i,len = strlen(s); - for (i=0; icvtrac, RACF_EYECATCHER, ESM_EYECATCHER_LENGTH)) { + return ZOS_ESM_RACF; + } + else if (!memcmp(cvt->cvtrac, RTSS_EYECATCHER, ESM_EYECATCHER_LENGTH)) { + return ZOS_ESM_RTSS; + } + else if (!memcmp(cvt->cvtrac, ACF2_EYECATCHER, ESM_EYECATCHER_LENGTH)) { + return ZOS_ESM_ACF2; + } + else { + return ZOS_ESM_NONE; + } +} + CVT *getCVT(void) { int * __ptr32 mem = (int * __ptr32) 0; int * __ptr32 theCVT = (int * __ptr32)(*(mem+(0x10/4))); diff --git a/c/zosfile.c b/c/zosfile.c index c42411178..21533453e 100644 --- a/c/zosfile.c +++ b/c/zosfile.c @@ -103,6 +103,9 @@ #define BPXLST BPX1LST #endif +#define MAX_ENTRY_BUFFER_SIZE 2550 +#define MAX_NUM_ENTRIES 1000 + static int fileTrace = FALSE; static const char* fileTypeString(char fileType) { @@ -134,178 +137,6 @@ static const char* fileTypeString(char fileType) { return result; } -int tmpFileMake(const char *fileName) { -#define TEMP_BUFFER_SIZE 1000 - - int returnCode = 0; - int reasonCode = 0; - int status = 0; - - char tempBuffer[TEMP_BUFFER_SIZE]; - strcpy(tempBuffer, fileName); - strcat(tempBuffer, ".tmp"); - - status = fileRename(fileName, tempBuffer, &returnCode, &reasonCode); - if (status == -1) { -#ifdef DEBUG - printf("Could not rename file %s: (return = 0x%x, reason = 0x%x)\n", tempBuffer, returnCode, reasonCode); -#endif - return -1; - } - - return 0; -} - -int tmpFileRecover(const char *fileName) { -#define TEMP_BUFFER_SIZE 1000 - - FileInfo info; - int returnCode = 0; - int reasonCode = 0; - int status = 0; - - char tempBuffer[TEMP_BUFFER_SIZE]; - strcpy(tempBuffer, fileName); - strcat(tempBuffer, ".tmp"); - - status = fileRename(tempBuffer, fileName, &returnCode, &reasonCode); - if (status == -1) { -#ifdef DEBUG - printf("Could not rename file %s: (return = 0x%x, reason = 0x%x)\n", tempBuffer, returnCode, reasonCode); -#endif - return -1; - } - - return 0; -} - -int tmpFileDelete(const char *fileName) { -#define TEMP_BUFFER_SIZE 1000 - - int status = 0; - int returnCode = 0; - int reasonCode = 0; - - char tempBuffer[TEMP_BUFFER_SIZE]; - strcpy(tempBuffer, fileName); - strcat(tempBuffer, ".tmp"); - - status = fileDelete(tempBuffer, &returnCode, &reasonCode); - if (status == -1) { -#ifdef DEBUG - printf("Could not delete file %s: (return = 0x%x, reason = 0x%x)\n", tempBuffer, returnCode, reasonCode); -#endif - } - - return 0; -} - -void tmpFileCleanup(const char *fileName) { - int status = 0; - - status = tmpFileRecover(fileName); - if (status == -1) { -#ifdef DEBUG - printf("Unable to recover file %s. Find it at %s.tmp\n", fileName, fileName); -#endif - return; - } - - status = tmpFileDelete(fileName); - if (status == -1) { -#ifdef DEBUG - printf("Unable to delete file %s. Find it at %s.tmp\n", fileName, fileName); -#endif - return; - } -} - -int tmpDirMake(const char *dirName) { - #define TEMP_BUFFER_SIZE 1000 - - int returnCode = 0; - int reasonCode = 0; - int status = 0; - - char tempBuffer[TEMP_BUFFER_SIZE]; - strcpy(tempBuffer, dirName); - strcat(tempBuffer, ".tmp"); - - status = directoryRename(dirName, tempBuffer, &returnCode, &reasonCode); - if (status == -1) { -#ifdef DEBUG - printf("Could not rename directory %s: (return = 0x%x, reason = 0x%x)\n", tempBuffer, returnCode, reasonCode); -#endif - return -1; - } - - return 0; -} - -int tmpDirRecover(const char *dirName) { - #define TEMP_BUFFER_SIZE 1000 - - FileInfo info; - int returnCode = 0; - int reasonCode = 0; - int status = 0; - - char tempBuffer[TEMP_BUFFER_SIZE]; - strcpy(tempBuffer, dirName); - strcat(tempBuffer, ".tmp"); - - status = directoryRename(tempBuffer, dirName, &returnCode, &reasonCode); - if (status == -1) { -#ifdef DEBUG - printf("Could not rename directory %s: (return = 0x%x, reason = 0x%x)\n", tempBuffer, returnCode, reasonCode); -#endif - return -1; - } - - return 0; -} - -int tmpDirDelete(const char *dirName) { - #define TEMP_BUFFER_SIZE 1000 - - int status = 0; - int returnCode = 0; - int reasonCode = 0; - - char tempBuffer[TEMP_BUFFER_SIZE]; - strcpy(tempBuffer, dirName); - strcat(tempBuffer, ".tmp"); - - status = directoryDeleteRecursive(tempBuffer); - if (status == -1) { -#ifdef DEBUG - printf("Could not delete directory %s\n", tempBuffer); -#endif - } - - return 0; -} - -void tmpDirCleanup(const char *dirName) { - int status = 0; - - status = tmpDirRecover(dirName); - if (status == -1) { -#ifdef DEBUG - printf("Unable to recover directory %s. Find it at %s.tmp\n", dirName, dirName); -#endif - return; - } - - status = tmpDirDelete(dirName); - if (status == -1) { -#ifdef DEBUG - printf("Unable to delete directory %s. Find it at %s.tmp\n", dirName, dirName); -#endif - return; - } -} - int setFileTrace(int toWhat) { int was = fileTrace; #ifndef METTLE @@ -668,162 +499,95 @@ int fileChangeTag(const char *fileName, int *returnCode, int *reasonCode, int cc return returnValue; } -int fileCopy(const char *existingFile, const char *newFile, int forceCopy){ -#define FILE_BUFFER_SIZE 4000 +int fileCopy(const char *existingFileName, const char *newFileName, int *retCode, int *resCode) { + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; - FileInfo info; - int returnCode = 0; - int reasonCode = 0; - int status = 0; - int bytesRead = 0; - int fileExists = 0; - char buffer[FILE_BUFFER_SIZE]; - - status = fileInfo(existingFile, &info, &returnCode, &reasonCode); + status = fileInfo(existingFileName, &info, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("File %s most likely does not exist, please check the provided file name: (return = 0x%x, reason = 0x%x)\n", existingFile, returnCode, reasonCode); -#endif + *retCode = returnCode; + *resCode = reasonCode; return -1; } - int ccsid = fileInfoCCSID(&info); - - status = fileInfo(newFile, &info, &returnCode, &reasonCode); - if (status == 0) { - if (!forceCopy) { -#ifdef DEBUG - printf("Copying has stopped because the file already exists and the force flag is off", newFile, returnCode, reasonCode); -#endif - return -1; - } - fileExists = 1; - } - - if (fileExists) { - status = tmpFileMake(newFile); - if (status == -1) { - return -1; - } - } - - UnixFile *fileCheckFrom = fileOpen(existingFile, FILE_OPTION_READ_ONLY, 0, 0, &returnCode, &reasonCode); - if (fileCheckFrom == NULL) { -#ifdef DEBUG - printf("Failed to open file %s: (return = 0x%x, reason = 0x%x)\n", existingFile, returnCode, reasonCode); -#endif - if (fileExists) { - tmpFileCleanup(newFile); - } + short ccsid = info.ccsid; + + UnixFile *existingFile = fileOpen(existingFileName, FILE_OPTION_READ_ONLY, 0, 0, &returnCode, &reasonCode); + if (existingFile == NULL) { + *retCode = returnCode; + *resCode = reasonCode; return -1; } - UnixFile *fileCheckTo = fileOpen(newFile, - FILE_OPTION_WRITE_ONLY | FILE_OPTION_CREATE, - 0700, - 0, - &returnCode, - &reasonCode); - - if (fileCheckTo == NULL) { -#ifdef DEBUG - printf("Failed to open file %s: (return = 0x%x, reason = 0x%x)\n", newFile, returnCode, reasonCode); -#endif - if (fileExists) { - tmpFileCleanup(newFile); - } + UnixFile *newFile = fileOpen(newFileName, + FILE_OPTION_WRITE_ONLY | FILE_OPTION_TRUNCATE | FILE_OPTION_CREATE, + 0700, + 0, + &returnCode, + &reasonCode); + if (newFile == NULL) { + *retCode = returnCode; + *resCode = reasonCode; return -1; } - /* If the file is not untagged. - */ - if (ccsid != 0) { - status = fileChangeTag(newFile, &returnCode, &reasonCode, ccsid); + if (ccsid != CCSID_UNTAGGED) { + status = fileChangeTag(newFileName, &returnCode, &reasonCode, ccsid); if (status == -1) { -#ifdef DEBUG - printf("Failed to change file tag for %s: (return = 0x%x, reason = 0x%x)\n", newFile, returnCode, reasonCode); -#endif - if (fileExists) { - tmpFileCleanup(newFile); - } - else { - fileDelete(newFile, &returnCode, &reasonCode); - } - return -1; + *retCode = returnCode; + *resCode = reasonCode; + return -1; } } - /* Disable automatic conversion to prevent any wacky - * problems that may arise from auto convert. - */ - status = fileDisableConversion(fileCheckTo, &returnCode, &reasonCode); + status = fileDisableConversion(existingFile, &returnCode, &reasonCode); if (status != 0) { - printf("Failed to disable automatic conversion. Unexpected results may occur.\n"); + *retCode = returnCode; + *resCode = reasonCode; + return -1; } - status = fileDisableConversion(fileCheckFrom, &returnCode, &reasonCode); + + status = fileDisableConversion(newFile, &returnCode, &reasonCode); if (status != 0) { - printf("Failed to disable automatic conversion. Unexpected results may occur.\n"); + *retCode = returnCode; + *resCode = reasonCode; + return -1; } - while (bytesRead = fileRead(fileCheckFrom, buffer, FILE_BUFFER_SIZE, &returnCode, &reasonCode)){ + int bytesRead = 0; + do { +#define FILE_BUFFER_SIZE 4000 + char fileBuffer[FILE_BUFFER_SIZE] = {0}; + + bytesRead = fileRead(existingFile, fileBuffer, sizeof(fileBuffer), &returnCode, &reasonCode); if (bytesRead == -1) { -#ifdef DEBUG - printf("Failed to read file %s: (return = 0x%x, reason = 0x%x)\n", existingFile, returnCode, reasonCode); -#endif - if (fileExists) { - tmpFileCleanup(newFile); - } - else { - fileDelete(newFile, &returnCode, &reasonCode); - } + *retCode = returnCode; + *resCode = reasonCode; return -1; } - status = fileWrite(fileCheckTo, buffer, bytesRead, &returnCode, &reasonCode); + + status = fileWrite(newFile, fileBuffer, bytesRead, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to write to file %s: (return = 0x%x, reason = 0x%x)\n", newFile, returnCode, reasonCode); -#endif - if (fileExists) { - tmpFileCleanup(newFile); - } - else { - fileDelete(newFile, &returnCode, &reasonCode); - } + *retCode = returnCode; + *resCode = reasonCode; return -1; - } - memset(buffer, 0, FILE_BUFFER_SIZE); - } + } + } while (bytesRead != 0); - status = fileClose(fileCheckTo, &returnCode, &reasonCode); + status = fileClose(existingFile, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to close file %s: (return = 0x%x, reason = 0x%x)\n", newFile, returnCode, reasonCode); -#endif - if (fileExists) { - fileClose(fileCheckFrom, &returnCode, &reasonCode); - tmpFileCleanup(newFile); - } - else { - fileDelete(newFile, &returnCode, &reasonCode); - } + *retCode = returnCode; + *resCode = reasonCode; return -1; } - status = fileClose(fileCheckFrom, &returnCode, &reasonCode); + status = fileClose(newFile, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to close file %s: (return = 0x%x, reason = 0x%x)\n", existingFile, returnCode, reasonCode); -#endif - if (fileExists) { - tmpFileCleanup(newFile); - } - else { - fileDelete(newFile, &returnCode, &reasonCode); - } + *retCode = returnCode; + *resCode = reasonCode; return -1; } - tmpFileDelete(newFile); return 0; } @@ -1006,7 +770,6 @@ int symbolicFileInfo(const char *filename, BPXYSTAT *stats, int *returnCode, int return returnValue; } - int fileInfoIsDirectory(const FileInfo *info) { return (info->fileType == BPXSTA_FILETYPE_DIRECTORY ? TRUE: FALSE); } @@ -1315,309 +1078,185 @@ int directoryDelete(const char *pathName, int *returnCode, int *reasonCode){ return returnValue; } -int directoryDeleteRecursive(const char *pathName){ -#define ENTRY_BUFFER_SIZE 1000 -#define PATH_BUFFER_SIZE 1000 - - /* Abort mission */ - if (!strcmp(pathName, "") || !strcmp(pathName, NULL)) { -#ifdef DEBUG - printf("pathName is null or empty\n"); -#endif - } - - FileInfo info; - int returnCode = 0; - int reasonCode = 0; - int status = 0; - int bytesRead = 0; - +static int getValidDirectoryEntries(int entries, char *entryBuffer, const char **entryArray) { + int entryOffset = 0; + int validEntries = 0; + for (int i = 0; i < entries; i++) { + const DirectoryEntry *de = (const DirectoryEntry *) (entryBuffer + entryOffset); + if (strcmp(".", de->name) && strcmp("..", de->name) && strcmp("", de->name)) { + entryArray[validEntries] = de->name; + validEntries++; + } + entryOffset += de->entryLength; + } + return validEntries; +} + +int directoryDeleteRecursive(const char *pathName, int *retCode, int *resCode){ + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; + status = fileInfo(pathName, &info, &returnCode, &reasonCode); if (status == -1){ + *retCode = returnCode; + *resCode = reasonCode; return -1; } UnixFile *dir = directoryOpen(pathName, &returnCode, &reasonCode); if (dir == NULL) { + *retCode = returnCode; + *resCode = reasonCode; return -1; } - char entryBuffer[ENTRY_BUFFER_SIZE]; - int entries = directoryRead(dir, entryBuffer, ENTRY_BUFFER_SIZE, &returnCode, &reasonCode); - if (entries < 0) { + char entryBuffer[MAX_ENTRY_BUFFER_SIZE] = {0}; + int entries = directoryRead(dir, entryBuffer, sizeof(entryBuffer), &returnCode, &reasonCode); + if (entries == -1) { + *retCode = returnCode; + *resCode = reasonCode; return -1; } - - /* directoryRead returns: - * "." - * ".." - * "NULL" - * - * To the entryBuffer. - * - * So, if it has three entries, - * we can be sure that the directory - * is empty. - */ - if (entries == 3) { -#ifdef DEBUG - printf("Deleting empty directory: %s\n", pathName); -#endif + + const char *entryArray[MAX_NUM_ENTRIES] = {0}; + int validEntries = getValidDirectoryEntries(entries, entryBuffer, entryArray); + if (validEntries < 1) { status = directoryDelete(pathName, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to delete directory: %s\n", pathName); -#endif + *retCode = returnCode; + *resCode = reasonCode; return -1; } return 0; } - /* The last entry is always a null. Disregard it to prevent issues. */ - int entryOffset = 0; - const char *entryArray[entries - 1]; - for (int i = 0; i < entries - 1; i++) { - const DirectoryEntry *de = (const DirectoryEntry*) (entryBuffer + entryOffset); - entryArray[i] = de->name; -#ifdef DEBUG - printf("%s in %s\n", entryArray[i], pathName); -#endif - entryOffset += de->entryLength; - } + for (int i = 0; i < validEntries; i++) { + char pathBuffer[USS_MAX_PATH_LENGTH + 1] = {0}; + snprintf(pathBuffer, sizeof(pathBuffer), "%s/%s", pathName, entryArray[i]); - /* The first two entries of directoryRead are the current directory - * and previous directory as stated above .*/ - char pathBuffer[PATH_BUFFER_SIZE]; - for (int i = 0; i < entries - 1; i++) { - if ((!strcmp(entryArray[i], ".")) || (!strcmp(entryArray[i], ".."))) { - continue; + status = fileInfo(pathBuffer, &info, &returnCode, &reasonCode); + if (status == -1){ + *retCode = returnCode; + *resCode = reasonCode; + return -1; } - else { - strcpy(pathBuffer, pathName); - strcat(pathBuffer, "/"); - strcat(pathBuffer, entryArray[i]); - status = fileInfo(pathBuffer, &info, &returnCode, &reasonCode); - if (status == -1){ + if (fileInfoIsDirectory(&info)) { + status = directoryDeleteRecursive(pathBuffer, retCode, resCode); + if (status == -1) { return -1; } - - if (fileInfoIsDirectory(&info)) { -#ifdef DEBUG - printf("Deleting directory: %s\n", pathBuffer); -#endif - directoryDeleteRecursive(pathBuffer); - } - else { -#ifdef DEBUG - printf("Deleting file: %s\n", pathBuffer); -#endif - status = fileDelete(pathBuffer, &returnCode, &reasonCode); - if (status == -1) { -#ifdef DEBUG - printf("Failed to delete file: %s\n", pathBuffer); -#endif - } + } + else { + status = fileDelete(pathBuffer, &returnCode, &reasonCode); + if (status == -1) { + *retCode = returnCode; + *resCode = reasonCode; + return -1; } - memset(pathBuffer, 0, PATH_BUFFER_SIZE); } } - /* Now we need to delete all the empty directories! */ - directoryDeleteRecursive(pathName); - - directoryClose(dir, &returnCode, &reasonCode); + directoryDeleteRecursive(pathName, retCode, resCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to close file %s: (return = 0x%x, reason = 0x%x)\n", pathName, returnCode, reasonCode); -#endif return -1; } return 0; } -int directoryCopy(const char *existingPathName, const char *newPathName, int forceCopy){ -#define ENTRY_BUFFER_SIZE 1000 -#define PATH_BUFFER_SIZE 1000 - - FileInfo info; - int returnCode = 0; - int reasonCode = 0; - int status = 0; - int bytesRead = 0; - int fileExists = 0; - char entryBuffer[ENTRY_BUFFER_SIZE]; +int directoryCopy(const char *existingPathName, const char *newPathName, int *retCode, int *resCode) { + int returnCode = 0, reasonCode = 0, status = 0; + FileInfo info = {0}; status = fileInfo(existingPathName, &info, &returnCode, &reasonCode); - if (status == -1){ -#ifdef DEBUG - printf("Directory %s most likely does not exist, please check the provided file name: (return = 0x%x, reason = 0x%x)\n", existingPathName, returnCode, reasonCode); -#endif + if (status == -1) { + *retCode = returnCode; + *resCode = reasonCode; return -1; } - status = fileInfo(newPathName, &info, &returnCode, &reasonCode); - if (status == 0){ - if (!forceCopy) { -#ifdef DEBUG - printf("Copying has stopped because the directory already exists and the force flag is off\n"); -#endif - return -1; - } - fileExists = 1; - } - - if (fileExists) { - status = tmpDirMake(newPathName); - if (status == -1) { - return -1; - } - } - - UnixFile *dirCheckFrom = directoryOpen(existingPathName, &returnCode, &reasonCode); - if (dirCheckFrom == NULL) { -#ifdef DEBUG - printf("Could not open directory %s: (return = 0x%x, reason = 0x%x)\n", existingPathName, returnCode, reasonCode); -#endif - if (fileExists) { - tmpDirCleanup(newPathName); - } + UnixFile *existingDirectory = directoryOpen(existingPathName, &returnCode, &reasonCode); + if (existingDirectory == NULL) { + *retCode = returnCode; + *resCode = reasonCode; return -1; } - int entries = directoryRead(dirCheckFrom, entryBuffer, ENTRY_BUFFER_SIZE, &returnCode, &reasonCode); - if (entries < 0) { -#ifdef DEBUG - printf("Could not read directory %s: (return = 0x%x, reason = 0x%x)\n", existingPathName, returnCode, reasonCode); -#endif - if (fileExists) { - tmpDirCleanup(newPathName); - } + char entryBuffer[MAX_ENTRY_BUFFER_SIZE] = {0}; + int entries = directoryRead(existingDirectory, entryBuffer, sizeof(entryBuffer), &returnCode, &reasonCode); + if (entries == -1) { + *retCode = returnCode; + *resCode = reasonCode; return -1; } - + + const char *entryArray[MAX_NUM_ENTRIES] = {0}; + int validEntries = getValidDirectoryEntries(entries, entryBuffer, entryArray); + if (validEntries < 1) { + + } + status = directoryMake(newPathName, - BPXOPN_MODE_USER_WRITE_PERMISSION | BPXOPN_MODE_USER_READ_PERMISSION | BPXOPN_MODE_USER_SEARCH_EXEC_PERMISSION, - &returnCode, - &reasonCode); + 0700, + &returnCode, + &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Could not make directory %s: (return = 0x%x, reason = 0x%x)\n", newPathName, returnCode, reasonCode); -#endif - if (fileExists) { - tmpDirCleanup(newPathName); - } + *retCode = returnCode; + *resCode = reasonCode; return -1; } - UnixFile *dirCheckTo = directoryOpen(newPathName, &returnCode, &reasonCode); - if (dirCheckTo == NULL) { -#ifdef DEBUG - printf("Could not open directory %s: (return = 0x%x, reason = 0x%x)\n", newPathName, returnCode, reasonCode); -#endif - if (fileExists) { - tmpDirCleanup(newPathName); - } + UnixFile *newDirectory = directoryOpen(newPathName, &returnCode, &reasonCode); + if (newDirectory == NULL) { + *retCode = returnCode; + *resCode = reasonCode; return -1; } - /* The last entry is always a null. Disregard it to prevent issues. */ - int entryOffset = 0; - const char *entryArray[entries - 1]; - for (int i = 0; i < entries - 1; i++) { - const DirectoryEntry *de = (const DirectoryEntry*) (entryBuffer + entryOffset); - entryArray[i] = de->name; -#ifdef DEBUG - printf("%s in %s\n", entryArray[i], existingPathName); -#endif - entryOffset += de->entryLength; - } + for (int i = 0; i < validEntries; i++) { + char existingPathBuffer[USS_MAX_PATH_LENGTH + 1] = {0}; + snprintf(existingPathBuffer, sizeof(existingPathBuffer), "%s/%s", existingPathName, entryArray[i]); + + char newPathBuffer[USS_MAX_PATH_LENGTH + 1] = {0}; + snprintf(newPathBuffer, sizeof(newPathBuffer), "%s/%s", newPathName, entryArray[i]); - /* The first two entries of directoryRead are the current directory and previous directory */ - char newPathBuffer[PATH_BUFFER_SIZE]; - char oldPathBuffer[PATH_BUFFER_SIZE]; - for (int i = 0; i < entries - 1; i++) { - if ((!strcmp(entryArray[i], ".")) || (!strcmp(entryArray[i], ".."))) { - continue; + status = fileInfo(existingPathBuffer, &info, &returnCode, &reasonCode); + if (status == -1) { + *retCode = returnCode; + *resCode = reasonCode; + return -1; } - else { - strcpy(oldPathBuffer, existingPathName); - strcat(oldPathBuffer, "/"); - strcat(oldPathBuffer, entryArray[i]); - strcpy(newPathBuffer, newPathName); - strcat(newPathBuffer, "/"); - strcat(newPathBuffer, entryArray[i]); - - status = fileInfo(oldPathBuffer, &info, &returnCode, &reasonCode); + + if (fileInfoIsDirectory(&info)) { + status = directoryCopy(existingPathBuffer, newPathBuffer, retCode, resCode); if (status == -1) { -#ifdef DEBUG - printf("Directory / File %s most likely does not exist, please check the provided file name: (return = 0x%x, reason = 0x%x)\n", oldPathBuffer, returnCode, reasonCode); -#endif - if (fileExists) { - tmpDirCleanup(newPathName); - } return -1; } - - if (fileInfoIsDirectory(&info)) { -#ifdef DEBUG - printf("Copying directory.\n"); - printf("from: %s\n", oldPathBuffer); - printf("to: %s\n", newPathBuffer); -#endif - status = directoryCopy(oldPathBuffer, newPathBuffer, forceCopy); - if (status == -1) { - if (fileExists) { - tmpDirCleanup(newPathName); - } - return -1; - } - } - else { -#ifdef DEBUG - printf("Copying file.\n"); - printf("from: %s\n", oldPathBuffer); - printf("to: %s\n", newPathBuffer); -#endif - status = fileCopy(oldPathBuffer, newPathBuffer, forceCopy); - if (status == -1) { - if (fileExists) { - tmpDirCleanup(newPathName); - } - return -1; - } + } + else { + status = fileCopy(existingPathBuffer, newPathBuffer, retCode, resCode); + if (status == -1) { + return -1; } - memset(newPathBuffer, 0, PATH_BUFFER_SIZE); - memset(oldPathBuffer, 0, PATH_BUFFER_SIZE); } } - status = directoryClose(dirCheckTo, &returnCode, &reasonCode); + status = directoryClose(existingDirectory, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to close file %s: (return = 0x%x, reason = 0x%x)\n", newPathName, returnCode, reasonCode); -#endif - if (fileExists) { - fileClose(dirCheckFrom, &returnCode, &reasonCode); - tmpFileCleanup(newPathName); - } + *retCode = returnCode; + *resCode = reasonCode; return -1; } - status = directoryClose(dirCheckFrom, &returnCode, &reasonCode); + status = directoryClose(newDirectory, &returnCode, &reasonCode); if (status == -1) { -#ifdef DEBUG - printf("Failed to close file %s: (return = 0x%x, reason = 0x%x)\n", existingPathName, returnCode, reasonCode); -#endif - if (fileExists) { - tmpDirCleanup(newPathName); - } + *retCode = returnCode; + *resCode = reasonCode; return -1; } - tmpDirDelete(newPathName); return 0; } diff --git a/h/as.h b/h/as.h new file mode 100644 index 000000000..3dbd8751e --- /dev/null +++ b/h/as.h @@ -0,0 +1,114 @@ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef SRC_AS_H_ +#define SRC_AS_H_ + +#ifdef METTLE +#include +#else +#include +#endif + +#include "zowetypes.h" +#include "zos.h" + +#ifndef __LONGNAME__ + +#define addressSpaceCreate ASCREATE +#define addressSpaceCreateWithTerm ASCREATT +#define addressSpaceTerminate ASTERMIN +#define addressSpaceExtractParm ASEXTRCT + +#endif + +ZOWE_PRAGMA_PACK + +typedef struct ASOutputData_tag { + uint64_t stoken; + ASCB * __ptr32 ascb; + void * __ptr32 commECBs; + char reserved[8]; +} ASOutputData; + +typedef struct ASUserToken { + char data[8]; +} ASUserToken; + +typedef struct ASParmString_tag { + uint16_t length; + char text[124]; +} ASParmString; + +typedef struct ASParm_tag { + uint16_t length; + char data[254]; +} ASParm; + +ZOWE_PRAGMA_PACK_RESET + +#define AS_ATTR_XMPT 0x00800000 +#define AS_ATTR_PXMT 0x00400000 +#define AS_ATTR_NOMT 0x00200000 +#define AS_ATTR_NOMD 0x00100000 +#define AS_ATTR_1LPU 0x00080000 +#define AS_ATTR_2LPU 0x00040000 +#define AS_ATTR_N2LP 0x00020000 +#define AS_ATTR_PRIV 0x00010000 +#define AS_ATTR_NOSWAP 0x00008000 +#define AS_ATTR_PERM 0x00004000 +#define AS_ATTR_CANCEL 0x00002000 +#define AS_ATTR_RESERVED 0x00001000 +#define AS_ATTR_HIPRI 0x00000800 +#define AS_ATTR_NONURG 0x00000400 +#define AS_ATTR_KEEPRGN 0x00000200 +#define AS_ATTR_REUSASID 0x00000100 +#define AS_ATTR_JOBSPACE 0x00000080 +#define AS_ATTR_ASCBV31 0x00000040 +#define AS_ATTR_MAXRGN 0x00000020 + +int addressSpaceCreate(const ASParmString *startParmString, + const ASParm *parm, + uint32_t attributes, + ASOutputData *result, + int *reasonCode); + +#ifdef METTLE + +typedef void ASCRETermCallback(void *userParm); + +int addressSpaceCreateWithTerm(const ASParmString *startParmString, + const ASParm *parm, + uint32_t attributes, + ASOutputData *result, + ASCRETermCallback *termCallback, + void * __ptr32 termCallbackParm, + int *reasonCode); + +#endif /* METTLE */ + +int addressSpaceTerminate(uint64_t stoken, int *reasonCode); + +int addressSpaceExtractParm(ASParm **parm, int *reasonCode); + +#endif /* SRC_AS_H_ */ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/h/charsets.h b/h/charsets.h index 3ee93bb65..424934f59 100644 --- a/h/charsets.h +++ b/h/charsets.h @@ -18,6 +18,7 @@ */ #include "zowetypes.h" +#include "utils.h" /* debugging switch */ @@ -44,8 +45,8 @@ #define CCSID_UTF_8 1208 /* The following two must be hex */ -#define CCSID_UNTAGGED 0x0000 -#define CCSID_BINARY 0xFFFF +#define CCSID_UNTAGGED (short)0x0000 +#define CCSID_BINARY (short)0xFFFF #elif defined(__ZOWE_OS_WINDOWS) /* WINDOWS CCSID's that are not common diff --git a/h/dataservice.h b/h/dataservice.h index 1054c738e..c673250a5 100644 --- a/h/dataservice.h +++ b/h/dataservice.h @@ -64,10 +64,12 @@ typedef struct DataService_tag { ExternalAPI *externalAPI; /* a function call to some lower level module to get data */ void *extension; /* another slot to stash things */ JsonObject *serviceDefinition; + uint64 loggingIdentifier; WebPlugin *plugin; } DataService; -WebPlugin *makeWebPlugin(char *baseDir, struct JsonObject_tag *pluginDefintion, InternalAPIMap *internalAPIMap); +WebPlugin *makeWebPlugin(char *baseDir, struct JsonObject_tag *pluginDefintion, InternalAPIMap *internalAPIMap, + unsigned int *idMultiplier, int pluginLogLevel); void initalizeWebPlugin(WebPlugin *plugin, HttpServer *server); /** diff --git a/h/http.h b/h/http.h index c5797568b..b09ae10b1 100644 --- a/h/http.h +++ b/h/http.h @@ -150,6 +150,7 @@ typedef struct HttpRequest_tag{ char *requestedSessionId; /* session id from client */ HttpRequestParam *processedParamList; struct HttpRequest_tag *next; + const void *authToken; /* a JWT or other */ } HttpRequest; /*************** WebSocket Stuff ********************/ diff --git a/h/httpfileservice.h b/h/httpfileservice.h index 93dfa75c0..5fc61f80b 100644 --- a/h/httpfileservice.h +++ b/h/httpfileservice.h @@ -16,26 +16,36 @@ #include "httpserver.h" void response200WithMessage(HttpResponse *response, char *msg); -int isDir(char *absolutePath); -int tagFile(char *absolutePath, char *targetEncoding, int isBinary); -int doesItExist(char *absolutePath); + +bool isDir(char *absolutePath); +bool doesFileExist(char *absolutePath); + static int createUnixDirectory(char *absolutePath, int forceCreate); void createUnixDirectoryAndRespond(HttpResponse *response, char *absolutePath, int forceCreate); + static int deleteUnixDirectory(char *absolutePath); void deleteUnixDirectoryAndRespond(HttpResponse *response, char *absolutePath); + static int deleteUnixFile(char *absolutePath); void deleteUnixFileAndRespond(HttpResponse *response, char *absolutePath); + static int renameUnixDirectory(char *oldAbsolutePath, char *newAbsolutePath, int forceRename); void renameUnixDirectoryAndRespond(HttpResponse *response, char *oldAbsolutePath, char *newAbsolutePath, int forceRename); + static int renameUnixFile(char *oldAbsolutePath, char *newAbsolutePath, int forceRename); void renameUnixFileAndRespond(HttpResponse *response, char *oldAbsolutePath, char *newAbsolutePath, int forceRename); + static int copyUnixDirectory(char *oldAbsolutePath, char *newAbsolutePath, int forceCopy); void copyUnixDirectoryAndRespond(HttpResponse *response, char *oldAbsolutePath, char *newAbsolutePath, int forceCopy); + static int copyUnixFile(char *oldAbsolutePath, char *newAbsolutePath, int forceCopy); void copyUnixFileAndRespond(HttpResponse *response, char *oldAbsolutePath, char *newAbsolutePath, int forceCopy); + void respondWithUnixFileMetadata(HttpResponse *response, char *absolutePath); + static int writeEmptyUnixFile(char *absolutePath, int forceWrite); void writeEmptyUnixFileAndRespond(HttpResponse *response, char *absolutePath, int forceWrite); + int writeBinaryDataFromBase64(UnixFile *file, char *fileContents, int contentLength); int writeAsciiDataFromBase64(UnixFile *file, char *fileContents, int contentLength, int sourceEncoding, int targetEncoding); diff --git a/h/httpserver.h b/h/httpserver.h index 9d7ebd4ab..d3cebe139 100644 --- a/h/httpserver.h +++ b/h/httpserver.h @@ -18,6 +18,7 @@ #include "json.h" #include "xml.h" #include "unixfile.h" +#include "../jwt/jwt/jwt.h" /** \file * \brief httpserver.h is the interface of an ultra-lightweight c-based web server. @@ -48,6 +49,10 @@ #define SERVICE_AUTH_CUSTOM 3 /* done by service */ #define SERVICE_AUTH_NATIVE_WITH_SESSION_TOKEN 4 +#define SERVICE_AUTH_TOKEN_TYPE_LEGACY 0 +#define SERVICE_AUTH_TOKEN_TYPE_JWT_WITH_LEGACY_FALLBACK 1 +#define SERVICE_AUTH_TOKEN_TYPE_JWT 2 + #define SERVICE_MATCH_WILD_RIGHT 1 #define HTTP_SERVICE_SUCCESS 0 @@ -137,6 +142,7 @@ struct HttpService_tag; typedef int HttpServiceInit(void); typedef int HttpServiceServe(struct HttpService_tag *service, HttpResponse *response); typedef int AuthExtract(struct HttpService_tag *service, HttpRequest *request); +typedef int AuthValidate(struct HttpService_tag *service, HttpRequest *request); typedef int HttpServiceInsertCustomHeaders(struct HttpService_tag *service, HttpResponse *response); /* @@ -194,6 +200,7 @@ typedef struct HttpService_tag{ void *sharedServiceMem; /* server-wide, address shared by all HttpServices */ const char *productURLPrefix; /* provided by the server */ int doImpersonation; + AuthValidate *authValidateFunction; } HttpService; typedef struct HTTPServerConfig_tag { @@ -202,6 +209,8 @@ typedef struct HTTPServerConfig_tag { HttpService *serviceOfLastResort; unsigned int sessionTokenKeySize; unsigned char sessionTokenKey[HTTP_SERVER_MAX_SESSION_TOKEN_KEY_SIZE]; + JwtContext *jwtContext; + int authTokenType; /* SERVICE_AUTH_TOKEN_TYPE_... */ } HttpServerConfig; typedef struct HttpServer_tag{ @@ -463,6 +472,7 @@ HttpService *makeWebSocketService(char *name, char *urlMask, WSEndpoint *endpoin jsonPrinter *initWSJsonPrinting(WSSession *session, int maxFrameSize); void flushWSJsonPrinting(WSSession *session); +void respondWithUnixFile2(HttpService* service, HttpResponse* response, char* absolutePath, int jsonMode, int autocvt, bool asB64); void respondWithUnixFileContents(HttpResponse* response, char *absolutePath, int jsonMode); void respondWithUnixFileContents2(HttpService* service, HttpResponse* response, char *absolutePath, int jsonMode); void respondWithUnixFileContentsWithAutocvtMode(HttpService* service, HttpResponse* response, char *absolutePath, int jsonMode, int convert); @@ -539,6 +549,12 @@ int setHttpCloseConversationTrace(int toWhat); int setHttpAuthTrace(int toWhat); #endif +int httpServerInitJwtContext(HttpServer *self, + bool legacyFallback, + const char *pkcs11TokenName, + const char *keyName, + int keyType, + int *makeContextRc, int *p11Rc, int *p11Rsn); /* diff --git a/h/isgenq.h b/h/isgenq.h index 67a203780..753f7ecbb 100644 --- a/h/isgenq.h +++ b/h/isgenq.h @@ -39,28 +39,151 @@ typedef struct ENQToken_tag { #define ISGENQ_SCOPE_SYSTEMS 3 #define ISGENQ_SCOPE_SYSPLEX 4 -#pragma map(isgenqGetExclusiveLockOrFail, "ENQGETXF") +#pragma map(isgenqTryExclusiveLock, "ENQTRYX") #pragma map(isgenqGetExclusiveLock, "ENQGETX") +#pragma map(isgenqTrySharedLock, "ENQTRYS") +#pragma map(isgenqGetSharedLock, "ENQGETS") +#pragma map(isgenqTestExclusiveLock, "ENQTSTX") +#pragma map(isgenqTestSharedLock, "ENQTSTS") #pragma map(isgenqTestLock, "ENQTEST") #pragma map(isgenqReleaseLock, "ENQREL") +/** + * @brief The function acquires an exclusive lock or fails if a lock is already + * being held for this QNAME and RNAME combination. See more details in the + * ISGENQ documentation. + * + * @param qname Enqueue major name + * @param rname Enqueue minor name + * @param scope Scope of the enqueue (use one of ISGENQ_SCOPE_xxxx) + * @param token Token used to release the enqueue + * @param reasonCode Reason code from ISGENQ + * @return Return code from ISGENQ + */ +int isgenqTryExclusiveLock(const QName *qname, + const RName *rname, + uint8_t scope, + ENQToken *token, + int *reasonCode); + +#define isgenqGetExclusiveLockOrFail isgenqTryExclusiveLock + +/** + * @brief Same as isgenqTryExclusiveLock + * @deprecated Use isgenqTryExclusiveLock + */ int isgenqGetExclusiveLockOrFail(const QName *qname, const RName *rname, uint8_t scope, ENQToken *token, int *reasonCode); - +/** + * @brief The function acquires an exclusive lock. If a lock is already being + * held for this QNAME and RNAME combination, the current task is suspended. + * See more details in the ISGENQ documentation. + * + * @param qname Enqueue major name + * @param rname Enqueue minor name + * @param scope Scope of the enqueue (use one of ISGENQ_SCOPE_xxxx) + * @param token Token used to release the enqueue + * @param reasonCode Reason code from ISGENQ + * @return Return code from ISGENQ + */ int isgenqGetExclusiveLock(const QName *qname, const RName *rname, uint8_t scope, ENQToken *token, int *reasonCode); - +/** + * @brief The function acquires a shared lock or fails if a lock is already + * being held for this QNAME and RNAME combination. See more details in the + * ISGENQ documentation. + * + * @param qname Enqueue major name + * @param rname Enqueue minor name + * @param scope Scope of the enqueue (use one of ISGENQ_SCOPE_xxxx) + * @param token Token used to release the enqueue + * @param reasonCode Reason code from ISGENQ + * @return Return code from ISGENQ + */ +int isgenqTrySharedLock(const QName *qname, + const RName *rname, + uint8_t scope, + ENQToken *token, + int *reasonCode); +/** + * @brief The function acquires a shared lock. If an exclusive lock is already + * being held for this QNAME and RNAME combination, the current task is + * suspended. See more details in the ISGENQ documentation. + * + * @param qname Enqueue major name + * @param rname Enqueue minor name + * @param scope Scope of the enqueue (use one of ISGENQ_SCOPE_xxxx) + * @param token Token used to release the enqueue + * @param reasonCode Reason code from ISGENQ + * @return Return code from ISGENQ + */ +int isgenqGetSharedLock(const QName *qname, + const RName *rname, + uint8_t scope, + ENQToken *token, + int *reasonCode); + +/** + * @brief The function does the same as isgenqTryExclusiveLock without + * acquiring the actual lock in case of success. See more details in the ISGENQ + * documentation. + * + * @param qname Enqueue major name + * @param rname Enqueue minor name + * @param scope Scope of the enqueue (use one of ISGENQ_SCOPE_xxxx) + * @param token Token used to release the enqueue + * @param reasonCode Reason code from ISGENQ + * @return Return code from ISGENQ + */ +int isgenqTestExclusiveLock(const QName *qname, + const RName *rname, + uint8_t scope, + int *reasonCode); +/** + * @brief The function does the same as isgenqTrySharedLock without + * acquiring the actual lock in case of success. See more details in the ISGENQ + * documentation. + * + * @param qname Enqueue major name + * @param rname Enqueue minor name + * @param scope Scope of the enqueue (use one of ISGENQ_SCOPE_xxxx) + * @param token Token used to release the enqueue + * @param reasonCode Reason code from ISGENQ + * @return Return code from ISGENQ + */ +int isgenqTestSharedLock(const QName *qname, + const RName *rname, + uint8_t scope, + int *reasonCode); + +/** + * @brief The function does the same as isgenqTestExclusiveLock. See more + * details in the ISGENQ documentation. + * + * @param qname Enqueue major name + * @param rname Enqueue minor name + * @param scope Scope of the enqueue (use one of ISGENQ_SCOPE_xxxx) + * @param reasonCode Reason code from ISGENQ + * @return Return code from ISGENQ + */ int isgenqTestLock(const QName *qname, const RName *rname, uint8_t scope, int *reasonCode); - +/** + * @brief The function releases a lock using the token obtain during the + * corresponding get call. See more details in the ISGENQ documentation. + * + * @param token Token used to acquire the lock + * @param reasonCode Reason code from ISGENQ + * @return Return code from ISGENQ + */ int isgenqReleaseLock(ENQToken *token, int *reasonCode); #define IS_ISGENQ_LOCK_OBTAINED($isgenqRC, $isgenqRSN) \ diff --git a/h/json.h b/h/json.h index 15a5cab08..e990501b6 100644 --- a/h/json.h +++ b/h/json.h @@ -59,6 +59,13 @@ typedef struct jsonPrinter_tag { int isInMultipartString; } jsonPrinter; +typedef struct jsonBuffer_tag { + char *data; + int size; + int len; +} JsonBuffer; + + /** \fn makeJsonPrinter() makeJsonPrinter is the principal means of creating a logical stream for generating JSON output to a lower level C stream. This calls the generate output in this printer must be done in the order of generation, i.e. @@ -74,6 +81,8 @@ jsonPrinter *makeCustomUtf8JsonPrinter( void (*writeMethod)(jsonPrinter *, char *, int), void *object, int inputCCSID); +jsonPrinter *makeBufferJsonPrinter(int inputCCSID, JsonBuffer *buf); + /** * \brief This will change the JSON printing to generate newlines and indentation to make the output human-friendly. * @@ -319,6 +328,11 @@ int jsonCheckIOErrorFlag(jsonPrinter *p); */ void jsonSetIOErrorFlag(jsonPrinter *p); +JsonBuffer *makeJsonBuffer(void); +void jsonBufferTerminateString(JsonBuffer *buffer); +void jsonBufferRewind(JsonBuffer *buffer); +void freeJsonBuffer(JsonBuffer *buffer); + typedef struct Json_tag Json; typedef struct JsonObject_tag JsonObject; typedef struct JsonArray_tag JsonArray; @@ -368,6 +382,9 @@ struct JsonError_tag { Json *jsonParseString(ShortLivedHeap *slh, char *jsonString, char* errorBufferOrNull, int errorBufferSize); Json *jsonParseUnterminatedString(ShortLivedHeap *slh, char *jsonString, int len, char* errorBufferOrNull, int errorBufferSize); Json *jsonParseFile(ShortLivedHeap *slh, const char *filename , char* errorBufferOrNull, int errorBufferSize); +Json *jsonParseUnterminatedUtf8String(ShortLivedHeap *slh, int outputCCSID, + char *jsonUtf8String, int len, + char *errorBufferOrNull, int errorBufferSize); void jsonPrint(jsonPrinter *printer, Json *json); void jsonPrintObject(jsonPrinter* printer, JsonObject *object); diff --git a/h/logging.h b/h/logging.h index 1d305dac6..69816a9f5 100644 --- a/h/logging.h +++ b/h/logging.h @@ -75,6 +75,7 @@ ZOWE_PRAGMA_PACK_RESET #define LOG_PROD_COMMON 0x008F000100000000LLU #define LOG_PROD_ZIS 0x008F000200000000LLU #define LOG_PROD_ZSS 0x008F000300000000LLU +#define LOG_PROD_PLUGINS 0x008F000400000000LLU #define LOG_COMP_ALLOC 0x008F000100010000LLU #define LOG_COMP_UTILS 0x008F000100020000LLU diff --git a/h/pause-element.h b/h/pause-element.h new file mode 100644 index 000000000..22e97b142 --- /dev/null +++ b/h/pause-element.h @@ -0,0 +1,227 @@ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef SRC_PAUSE_ELEMENT_H_ +#define SRC_PAUSE_ELEMENT_H_ + +#ifdef METTLE +#include +#include +#include +#else +#include +#include +#endif + +#pragma enum(4) + +typedef enum PEAuth_tag { + PE_AUTH_UNAUTHORIZED = 0, + PE_AUTH_AUTHORIZED = 1, + PE_AUTH_UNAUTH_CHECKPOINTOK = 2, + PE_AUTH_AUTH_CHECKPOINTOK = 3, +} PEAuth; + +typedef enum PELinkage_tag { + PE_LINKAGE_SVC = 0, + PE_LINKAGE_BRANCH = 1, + PE_LINKAGE_UNTRUSTED_PET = 2, +} PELinkage; + +typedef enum PEState_tag { + PE_STATUS_PRERELEASED = 1, + PE_STATUS_RESET = 2, + PE_STATUS_RELEASED = 64, + PE_STATUS_PAUSED = 128, +} PEState; + +#pragma enum(reset) + +ZOWE_PRAGMA_PACK + +typedef struct PET_tag { + union { + char value[16]; + struct { + uint64_t part1; + uint64_t part2; + }; + }; +} PET; + +typedef struct PEStoken_tag { + uint64_t value; +} PEStoken; + +typedef struct PEReleaseCode_tag { + int value : 24; +} PEReleaseCode; + +typedef struct PEInfo_tag { + PEStoken ownerStoken; + PEStoken currentStoken; + PEState state; + PEAuth authLevel; + PEReleaseCode releaseCode; +} PEInfo; + +ZOWE_PRAGMA_PACK_RESET + +#ifndef __LONGNAME__ + +#define peAlloc PETALLOC +#define peDealloc PETDEALC +#define pePause PETPAUSE +#define peRelease PETRLS +#define peRetrieveInfo PETINFO +#define peTest PETTEST +#define peTranfer PETTRNFR + +#endif + + +/** + * @brief Allocates a new pause element (see the IEAVAPE2 doc for details). + * + * @param result The pause element token associated with the pause element. + * @param ownerStoken specifies the STOKEN of the address space which is to be + * considered the owner of the new pause element. + * @param releaseCode The release code which will be returned to a paused DU + * if the system deallocates the pause element. + * @param authLevel The auth level of the pause element being allocated. + * @param isBranchLinkage The services routine will be invoked via a branch + * instruction. The caller must be in both key 0 and supervisor state. + * + * @return The IEAVAPE2 return code value. + */ +int peAlloc(PET *result, + const PEStoken *ownerStoken, + PEReleaseCode releaseCode, + PEAuth authLevel, + bool isBranchLinkage); + +/** + * @brief Deallocates a pause element (see the IEAVDPE2 doc for details). + * + * @param token The pause element token associated with the pause element. + * @param isBranchLinkage The services routine will be invoked via a branch + * instruction. The caller must be in both key 0 and supervisor state. + * + * @return The IEAVDPE2 return code value. + */ +int peDealloc(PET *token, bool isBranchLinkage); + +/** + * @brief Pauses the current task or SRB nondispatchable (see the IEAVPSE2 doc + * for details). + * + * @param token The pause element token associated with the pause element. + * @param newToken A new pause element token that identifies the pause element + * identified by the original token. + * @param releaseCode The release code specified by the issuer of the release + * call. + * @param isBranchLinkage The services routine will be invoked via a branch + * instruction. The caller must be in both key 0 and supervisor state. + * + * @return The IEAVPSE2 return code value. + */ +int pePause(const PET *token, PET *newToken, + PEReleaseCode *releaseCode, + bool isBranchLinkage); + +/** + * @brief Releases a task or SRB that has been paused, or keeps a task or + * SRB from being paused (see the IEAVRLS2 doc for details). + * + * @param token The pause element token associated with the pause element used + * to pause a task or SRB. + * @param releaseCode The release code to be returned to the paused task or SRB. + * @param isBranchLinkage The services routine will be invoked via a branch + * instruction. The caller must be in both key 0 and supervisor state. + * + * @return The IEAVRLS2 return code value. + */ +int peRelease(const PET *token, + PEReleaseCode releaseCode, + bool isBranchLinkage); + +/** + * @brief Gets information about a pause element (see the IEAVRPI2 doc for + * details). + * + * @param token The pause element token associated with the pause element. + * @param info The pause element information. + * @param isBranchLinkage The services routine will be invoked via a branch + * instruction. The caller must be in both key 0 and supervisor state. + * + * @return The IEAVRPI2 return code value. + */ +int peRetrieveInfo(const PET *token, + PEInfo *info, + bool isBranchLinkage); + +/** + * @brief Test a pause element and determines its state. The caller is + * responsible for providing any needed recovery. The call will ABEND if a bad + * pause element token is provided (see the IEAVTPE doc for details). + * + * @param token The pause element token associated with the pause element. + * @param state The pause element state. + * @param releaseCode The release code specified by the issuer of the release + * call. + * + * @return The IEAVTPE return code value. + */ +int peTest(const PET *token, + PEState *state, + PEReleaseCode *releaseCode); + +/** + * @brief Release a paused task or SRB, and, when possible, give the task or + * SRB immediate control. Optionally the function pauses the task or SRB under + * which makes the transfer request. If the caller does not request that its + * task or SRB to be paused, the task or SRB remain dispatchable (see the + * IEAVXFR2 doc for details). + * + * @param token The pause element token associated with the pause element used + * to pause a task or SRB. + * @param newToken A new pause element token that identifies the pause element + * identified by the original token. + * @param releaseCode The release code specified by the issuer of the release + * or transfer call. + * @param targetToken Specifies the pause element token that is associated with + * a pause element that is being used or will be used to pause a task or SRB. + * If the task or SRB is paused, it will be released. + * @targetReleaseCode The release code returned to a paused task or SRB. + * @param isBranchLinkage The services routine will be invoked via a branch + * instruction. The caller must be in both key 0 and supervisor state. + * + * @return The IEAVXFR2 return code value. + */ +int peTranfer(const PET *token, PET *newToken, + PEReleaseCode *releaseCode, + const PET *targetToken, + PEReleaseCode targetReleaseCode, + bool isBranchLinkage); + +#endif /* SRC_PAUSE_ELEMENT_H_ */ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/h/pc.h b/h/pc.h new file mode 100644 index 000000000..d97f4d46e --- /dev/null +++ b/h/pc.h @@ -0,0 +1,231 @@ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef SRC_PC_H_ +#define SRC_PC_H_ + +#ifdef METTLE +#include +#include +#include +#else +#include "stdbool.h" +#include "stdint.h" +#endif + +#include "zowetypes.h" + +ZOWE_PRAGMA_PACK + +typedef struct PCLatentParmList_tag { + void * __ptr32 parm1; + void * __ptr32 parm2; +} PCLatentParmList; + +typedef struct PCLinkageIndex { + uint32_t sequenceNumber; + uint32_t pcNumber; +} PCLinkageIndex; + +ZOWE_PRAGMA_PACK_RESET + +#ifndef __LONGNAME__ +#define pcSetAllAddressSpaceAuthority PCAXSET +#define pcReserveLinkageIndex PCLXRES +#define pcFreeLinkageIndex PCLXFRE +#define pcMakeEntryTableDescriptor PCETCRED +#define pcAddToEntryTableDescriptor PCETADD +#define pcRemoveEntryTableDescriptor PCETREMD +#define pcCreateEntryTable PCETCRE +#define pcDestroyEntryTable PCETDES +#define pcConnectEntryTable PCETCON +#define pcDisconnectEntryTable PCETDIS +#define pcCallRoutine PCCALLR +#endif + +typedef enum PCLinkageIndexSize_tag { + LX_SIZE_12, + LX_SIZE_16, + LX_SIZE_23, + LX_SIZE_24, +} PCLinkageIndexSize; + +typedef uint32_t PCEntryTableToken; + +typedef struct ETD_tag EntryTableDescriptor; + +/** + * @brief Sets the authorization index of the home address space to + * the value specified by the caller. + * + * @param reasonCode AXSET return code value. + * + * @return One of the RC_PC_xx return codes. + */ +int pcSetAllAddressSpaceAuthority(int *reasonCode); + +/** + * @brief Reserves a linkage index for the caller's use. + * + * @param isSystem Specifies whether or not the linkage index is reserved + * for system connections. + * @param isReusable Specifies whether or not the linkage index is reusable. + * @param indexSize The maximum size of the linkage index. + * @param result The result linkage index value. + * @param reasonCode LXRES return code value. + * + * @return One of the RC_PC_xx return codes. + */ +int pcReserveLinkageIndex(bool isSystem, bool isReusable, + PCLinkageIndexSize indexSize, + PCLinkageIndex *result, + int *reasonCode); + +/** + * @brief Frees a linkage index. + * + * @param index The linkage index to be freed. + * @param forced Free the linkage index even if entry tables are currently + * connected to it + * @param reasonCode LXFRE return code value. + * + * @return One of the RC_PC_xx return codes. + */ +int pcFreeLinkageIndex(PCLinkageIndex index, bool forced, int *reasonCode); + +/** + * @brief Allocates a table entry descriptor. + * + * @return The table entry descriptor address. + */ +EntryTableDescriptor *pcMakeEntryTableDescriptor(void); + +/** + * @brief Add a new entry to a table entry descriptor. + * + * @param descriptor The descriptor that will contain the new entry. + * @param routine The routine to be invoked in the corresponding PC. + * @param routineParameter1 The first parameter of the routine's latent + * parameter list. + * @param routineParameter2 The second parameter of the routine's latent + * parameter list. + * @param isSASNOld Specifies whether the PC routine will execute with SASN + * equal to the caller's PASN. + * @param isAMODE64 Specifies whether the PC routine is AMODE 64. + * @param isSUP Specifies whether the PC routine will run in SUP state. + * @param isSpaceSwitch Specifies whether the PC routine is a space switch + * routine. + * @param key The key in which the PC routine will be executed. + * + * @return One of the RC_PC_xx return codes. + */ +int pcAddToEntryTableDescriptor(EntryTableDescriptor *descriptor, + int (* __ptr32 routine)(void), + uint32_t routineParameter1, + uint32_t routineParameter2, + bool isSASNOld, + bool isAMODE64, + bool isSUP, + bool isSpaceSwitch, + int key); + +/** + * @brief Removes a table entry descriptor. + * + */ +void pcRemoveEntryTableDescriptor(EntryTableDescriptor *descriptor); + +/** + * @brief Builds a PC entry table using the descriptions of each entry. + * + * @param descriptor The descriptor containing the description of the entries. + * @param resultToken The token associated with the new entry table. + * @param reasonCode ETCRE return code value. + * + * @return One of the RC_PC_xx return codes. + */ +int pcCreateEntryTable(const EntryTableDescriptor *descriptor, + PCEntryTableToken *resultToken, + int *reasonCode); + +/** + * @brief Destroys a PC entry table. + * + * @param token The token associated with the entry table. + * @param purge Specifies whether the entry table is to be disconnected from + * all linkage tables and then destroyed. + * @param reasonCode ETDES return code value. + * + * @return One of the RC_PC_xx return codes. + */ +int pcDestroyEntryTable(PCEntryTableToken token, bool purge, int *reasonCode); + +/** + * @brief Connects a previously created entry table to the specified linkage + * index table in the current home address space. + * + * @param token The token associated with the entry table. + * @param index Specifies the linkage index to which the specified entry table + * is to be connected. + * @param reasonCode ETCON return code value. + * + * @return One of the RC_PC_xx return codes. + */ +int pcConnectEntryTable(PCEntryTableToken token, PCLinkageIndex index, + int *reasonCode); + +/** + * @brief Disconnects a previously connected entry table from the specified + * linkage index table in the current home address space. + * + * @param token The token associated with the entry table. + * @param reasonCode ETCDIS return code value. + * + * @return One of the RC_PC_xx return codes. + */ +int pcDisconnectEntryTable(PCEntryTableToken token, int *reasonCode); + +/** + * @brief Calls the PC routine associated with the specified PC and sequence + * numbers. + * + * @param pcNumber The PC number of the routine (found in PCLinkageIndex). + * @param sequenceNumber The sequence number of the routine + * (found in PCLinkageIndex). + * @param parmBlock The parameter block passed the routine via R1. + * + * @return The R15 value of the routine. + */ +int pcCallRoutine(uint32_t pcNumber, uint32_t sequenceNumber, void *parmBlock); + +#define RC_PC_OK 0 +#define RC_PC_AXSET_FAILED 8 +#define RC_PC_LXRES_FAILED 9 +#define RC_PC_LXFRE_FAILED 10 +#define RC_PC_ETD_FULL 11 +#define RC_PC_ETCRE_FAILED 12 +#define RC_PC_ETDES_FAILED 13 +#define RC_PC_ETCON_FAILED 14 +#define RC_PC_ETDIS_FAILED 15 + +#endif /* SRC_PC_H_ */ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/h/shrmem64.h b/h/shrmem64.h new file mode 100644 index 000000000..c2cd9f2e0 --- /dev/null +++ b/h/shrmem64.h @@ -0,0 +1,143 @@ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef SRC_SHRMEM64_H_ +#define SRC_SHRMEM64_H_ + +#ifdef METTLE +#include +#include +#include +#else +#include "stddef.h" +#include "stdint.h" +#endif + +#include "zowetypes.h" + +#ifndef _LP64 +#error ILP32 is not supported +#endif + +#ifndef __LONGNAME__ + +#define shrmem64GetAddressSpaceToken SHR64TKN + +#define shrmem64Alloc SHR64ALC +#define shrmem64Release SHR64REL +#define shrmem64ReleaseAll SHR64REA + +#define shrmem64GetAccess SHR64GAC +#define shrmem64GetAccess SHR64GRC + +#endif + +typedef uint64_t MemObjToken; + +/** + * @brief Returns a unique token for the current address space. + * + * @return 8-byte memory object token that can be used in shrmem64 functions. + */ +MemObjToken shrmem64GetAddressSpaceToken(void); + +/** + * @brief Allocates 64-bit shared storage. Use shrmem64GetAccess to establish + * addressability to this storage in your the current address space. See more + * details in the IARV64 doc (REQUEST=GETSHARED). + * + * @param userToken The token this storage will be associated with. This token + * must be used to free the storage. Read the full requirements in the IARV64 doc. + * @param size The size of the storage to be allocated. + * @param rsn The reason code returned in case of a failure. + * + * @return One of the RC_SHRMEM64_xx return codes. + */ +int shrmem64Alloc(MemObjToken userToken, size_t size, void **result, int *rsn); + +/** + * @brief Releases 64-bit shared storage. The storage will still be accessible + * in the address spaces that have issued shrmem64GetAccess. No new access can + * be obtained after this call. See more details in the IARV64 doc + * (REQUEST=DETACH,AFFINITY=SYSTEM,MATCH=SINGLE). + * + * @param userToken The token this storage was associated with during + * the corresponding shrmem64Alloc call. + * @param target The storage to be released. + * @param rsn The reason code returned in case of a failure. + * + * @return One of the RC_SHRMEM64_xx return codes. + */ +int shrmem64Release(MemObjToken userToken, void *target, int *rsn); + +/** + * @brief Releases all 64-bit shared storage associated with the specified token. + * The associated storage will still be accessible in the address spaces that + * have issued shrmem64GetAccess. No new access can be obtained after this call. + * See more details in the IARV64 doc + * (REQUEST=DETACH,AFFINITY=SYSTEM,MATCH=MOTOKEN). + * + * @param userToken The token all storage to be released is associated with. + * @param rsn The reason code returned in case of a failure. + * + * @return One of the RC_SHRMEM64_xx return codes. + */ +int shrmem64ReleaseAll(MemObjToken userToken, int *rsn); + +/** + * @brief Establishes addressability to the specified storage in the current + * address space. See more details in the IARV64 doc (REQUEST=SHAREMEMOBJ). + * + * @param userToken The token this storage will be associated with. It mist be + * used for the subsequent shrmem64RemoveAccess call. It does not have to be + * the same as the token used in shrmem64Alloc. Read the full requirements in + * the IARV64 doc. + * @param target The storage to be accessed. + * @param rsn The reason code returned in case of a failure. + * + * @return One of the RC_SHRMEM64_xx return codes. + */ +int shrmem64GetAccess(MemObjToken userToken, void *target, int *rsn); + +/** + * @brief Removes the addressability of the specified storage in the current + * address space. See more details in the IARV64 doc + * (REQUEST=DETACH,AFFINITY=LOCAL). + * + * @param userToken The token this storage was associated with during + * the corresponding shrmem64GetAccess call. + * @param target The storage to be detached. + * @param rsn The reason code returned in case of a failure. + * + * @return One of the RC_SHRMEM64_xx return codes. + */ +int shrmem64RemoveAccess(MemObjToken userToken, void *target, int *rsn); + +#define RC_SHRMEM64_OK 0 +#define RC_SHRMEM64_GETSHARED_FAILED 8 +#define RC_SHRMEM64_SHAREMEMOBJ_FAILED 9 +#define RC_SHRMEM64_ALL_SYS_DETACH_FAILED 10 +#define RC_SHRMEM64_SINGLE_SYS_DETACH_FAILED 11 +#define RC_SHRMEM64_DETACH_FAILED 12 + +#endif /* SRC_SHRMEM64_H_ */ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/h/unixfile.h b/h/unixfile.h index a6734e8d1..7ec134a31 100644 --- a/h/unixfile.h +++ b/h/unixfile.h @@ -401,7 +401,7 @@ int fileWrite(UnixFile *file, const char *buffer, int desiredBytes, int fileGetChar(UnixFile *file, int *returnCode, int *reasonCode); -int fileCopy(const char *existingFile, const char *newFile, int forceCopy); +int fileCopy(const char *existingFile, const char *newFile, int *retCode, int *resCode); int fileRename(const char *oldFileName, const char *newFileName, int *returnCode, int *reasonCode); @@ -467,6 +467,9 @@ int fileSetLock(UnixFile *file, int *returnCode, int *reasonCode); int fileGetLock(UnixFile *file, int *returnCode, int *reasonCode, int *isLocked); int fileUnlock(UnixFile *file, int *returnCode, int *reasonCode); +#define USS_MAX_PATH_LENGTH 1023 +#define USS_MAX_FILE_NAME 255 + #endif int fileInfoIsDirectory(const FileInfo *info); @@ -484,8 +487,8 @@ int fileClose(UnixFile *file, int *returnCode, int *reasonCode); int directoryMake(const char *pathName, int mode, int *returnCode, int *reasonCode); int directoryDelete(const char *pathName, int *returnCode, int *reasonCode); -int directoryDeleteRecursive(const char *pathName); -int directoryCopy(const char *existingPathName, const char *newPathName, int forceCopy); +int directoryDeleteRecursive(const char *pathName, int *retCode, int *resCode); +int directoryCopy(const char *existingPathName, const char *newPathName, int *retCode, int *resCode); int directoryRename(const char *oldDirName, const char *newDirName, int *returnCode, int *reasonCode); UnixFile *directoryOpen(const char *directoryName, int *returnCode, int *reasonCode); int directoryRead(UnixFile *directory, char *entryBuffer, int entryBufferLength, int *returnCode, int *reasonCode); @@ -494,20 +497,6 @@ int directoryClose(UnixFile *directory, int *returnCode, int *reasonCode); int setUmask(int mask); int getUmask(); -/* Utility functions that are used in zosfile.c - * and httpfileservice.c. Makes and deletes temporary - * files and directories. A ".tmp" is added to the - * absolutePath provided. - */ -int tmpFileMake(const char *fileName); -int tmpFileRecover(const char *fileName); -int tmpFileDelete(const char *fileName); -void tmpFileCleanup(const char *fileName); -int tmpDirMake(const char *dirName); -int tmpDirRecover(const char *dirName); -int tmpDirDelete(const char *dirName); -void tmpDirCleanup(const char *dirName); - #endif diff --git a/h/utils.h b/h/utils.h index 790d51ef6..34c02a796 100644 --- a/h/utils.h +++ b/h/utils.h @@ -31,6 +31,7 @@ extern "C" { #define strcopy_safe STRCPSAF #define indexOf INDEXOF #define indexOfString IDXSTR +#define lastIndexOfString LIDXSTR #define indexOfStringInsensitive IDXSTRNS #endif @@ -39,6 +40,7 @@ char * strcopy_safe(char * dest, const char * source, int dest_size); int indexOf(char *str, int len, char c, int startPos); int lastIndexOf(const char *str, int len, char c); int indexOfString(char *str, int len, char *searchString, int startPos); +int lastIndexOfString(char *str, int len, char *searchString); int indexOfStringInsensitive(char *str, int len, char *searchString, int startPos); /* max() is not a standard macro. Windows introduces this and they are wrong */ @@ -220,8 +222,23 @@ void SLHFree(ShortLivedHeap *slh); char *cleanURLParamValue(ShortLivedHeap *slh, char *value); int percentEncode(char *value, char *buffer, int len); +#define BASE64_ENCODE_SIZE(SZ) (2 + 4 * ((SZ + 2) / 3)) + int decodeBase64(char *s, char *result); -char *encodeBase64(ShortLivedHeap *slh, char *buf, int size, int *resultSize, int useEbcdic); +char *encodeBase64(ShortLivedHeap *slh, const char buf[], int size, int *resultSize, + int useEbcdic); +void encodeBase64NoAlloc(const char buf[], int size, char result[], int *resultSize, + int useEbcdic); +/* + * Assumes "EBCDIC base64" on EBCDIC platforms + */ +int base64ToBase64url(char *s); + +/* + * Assumes "EBCDIC base64" on EBCDIC platforms + */ +int base64urlToBase64(char *s, int bufSize); + char *destructivelyUnasciify(char *s); int base32Decode (int alphabet, diff --git a/h/zos.h b/h/zos.h index a6af15c8e..bffd3e5fc 100644 --- a/h/zos.h +++ b/h/zos.h @@ -49,6 +49,13 @@ int setKey(int key); int ddnameExists(char *ddname); int atomicIncrement(int *intPointer, int increment); +typedef enum ExternalSecurityManager_t { + ZOS_ESM_RTSS, + ZOS_ESM_RACF, + ZOS_ESM_ACF2, + ZOS_ESM_NONE +} ExternalSecurityManager; + ZOWE_PRAGMA_PACK typedef struct cvtfix_tag{ diff --git a/h/zvt.h b/h/zvt.h index fbe07d821..ba21de2cc 100644 --- a/h/zvt.h +++ b/h/zvt.h @@ -86,7 +86,7 @@ typedef struct ZVT_tag { struct { PAD_LONG(10, ZVTEntry *zis); - PAD_LONG(11, ZVTEntry *reservedSlot1); + PAD_LONG(11, ZVTEntry *zssp); PAD_LONG(12, ZVTEntry *reservedSlot2); PAD_LONG(13, ZVTEntry *reservedSlot3); PAD_LONG(14, ZVTEntry *reservedSlot4); diff --git a/jwt/Makefile b/jwt/Makefile new file mode 100644 index 000000000..49c9a7fad --- /dev/null +++ b/jwt/Makefile @@ -0,0 +1,38 @@ +-include cflags.mk + +CC := xlc +LIBRARY := lib/librsjwt.a + +MAINFRAME_C ?= .. + +MODULES := jwt rscrypto + +CFLAGS += $(patsubst %,-I%, $(MODULES)) +CFLAGS += -I. -I$(MAINFRAME_C)/h +CFLAGS += -D_XOPEN_SOURCE_EXTENDED -D_LARGE_TIME_API + +SRC := + +-include $(patsubst %,%/module.mk,$(MODULES)) + +OBJ := \ + $(patsubst %.c,%.o, $(filter %.c,$(SRC))) + +$(LIBRARY): $(OBJ) + mkdir -p lib + ar -r $(LIBRARY) $(OBJ) + +%.o : %.c + $(CC) -c $(CFLAGS) $< -o $@ > $@.listing + +compile.sh: + make -nsB > compile.sh + +include tests/test.mk + +.PHONY: clean +clean: + rm -f $(LIBRARY) $(OBJ) $(OBJ:.o=.u) $(OBJ:.o=.o.listing) $(TEST_OBJ) \ + $(TEST_OBJ:.o=.u) $(TEST_OBJ:.o=.o.listing) $(TEST_BINARIES) *.lst *.dbg + +-include $(OBJ:.o=.u) $(TEST_OBJ:.o=.u) diff --git a/jwt/cflags.mk b/jwt/cflags.mk new file mode 100644 index 000000000..0a8660df0 --- /dev/null +++ b/jwt/cflags.mk @@ -0,0 +1,58 @@ +TARGET := ZOSV2R1 +MACHINE := ZSERIES-6 +ARCH_6 := 6 +ARCH_10 := 10 + +#FIXME MNT0130 +INFO_FLAGS = INFO(ALL),CHECKOUT(ALL) #noals,cmp,gen,cns,eff,enu,par,por,pro,rea,ret,trd,use) +#CCN3196 Initialization between types "&1" and "&2" is not allowed +#CCN3224 Incorrect pragma ignored. +#CCN3280 Function argument assignment between types "&1" and "&2" is not allowed. +#CCN3304 No function prototype given for "&1". +#CCN3438 The variable "&1" might be used before it is set. +#CCN3449 Missing return expression. +#CCN3450 Obsolete non-prototype-style function declaration. +SEVERITY_E = CCN3196,CCN3224,CCN3280,CCN3304,CCN3438,CCN4332,CCN3449,CCN3450 +#CCN3419 Converting 3637953233 to type "int" does not preserve its value. +#CCN3420 An unsigned comparison is performed between an unsigned value and a negative constant. +#CCN3426 An assignment expression is used as a condition. An equality comparison ( := := ) may have been intended. +#CCN3434 The left-hand side of a bitwise right shift expression has a signed promoted type. +#CCN3451 The target integral type cannot hold all possible values of the source integral type. +SEVERITY_W = CCN3419,CCN3420,CCN3426,CCN3434,CCN3451,CCN3280 +#CN3997 Structure members cannot follow a flexible array member/zero extent array. +SEVERITY_I = CCN3997 +#CCN3409 The static variable "..." is defined but never referenced. +#CCN3413 A goto statement is used. -- We're using goto to free resources (and only for that!) +#CCN3415 The external function definition "..." is never referenced. -- Way too many of these, nothing we can do to fix +#CCN3425 The condition is always false. -- Lots of false positives on TRACE +#CCN3446 Array element(s) [1] ... [4] will be initialized with a default value of 0. -- So what??? +#CCN3447 The member(s) starting from "&1" will be initialized with a default value of 0. -- So what??? +#CCN3457 File /RZ202B/usr/include/stdint.h has already been included. -- Way too many of these, nothing we can do to fix +#CCN3493 The external variable "" is defined but never referenced. -- Way too many of these, nothing we can do to fix +#CCN3495 Pointer type conversion found -- typically followed by another message with the specifics +SUPPRESS = CCN3409,CCN3413,CCN3415,CCN3425,CCN3446,CCN3447,CCN3457,CCN3493,CCN3435,CCN3495 + + +ifeq ($(BUILD_TYPE),DEBUG) + ARCH := $(ARCH_10) + CFLAGS_RTCHECK := -Wc,RTCHECK + CFLAGS_DEBUG := -g -DJWT_DEBUG +else + ARCH := $(ARCH_6) + CFLAGS_RTCHECK := +endif + +CFLAGS_TARGET = -Wc,"TARGET($(TARGET)),ARCH($(ARCH))" +CFLAGS_INFO = -Wc,"$(INFO_FLAGS)" +CFLAGS_SEVERITY = -Wc,"SEVERITY(E($(SEVERITY_E)))" -Wc,"SEVERITY(W($(SEVERITY_W)))" \ + -Wc,"SEVERITY(I($(SEVERITY_I)))" -Wc,"SUPPRESS($(SUPPRESS))" +CFLAGS_LISTING := -Wc,list,aggregate,xref + +CFLAGS = -M -Wa,goff \ + -Wc,"LANGLVL(EXTC99),FLOAT(HEX),agg,exp,list,aggregate,xref,offset" \ + -Wc,"source,expmac,so(),goff" \ + -Wc,"gonum,roconst,ASM,ASMLIB('SYS1.MACLIB'),dll" \ + -Wc,"LANGLVL(EXTC99),FLOAT(HEX),agg,exp,list(),so(),goff,xref" \ + $(CFLAGS_INFO) $(CFLAGS_SEVERITY) \ + $(CFLAGS_RTCHECK) $(CFLAGS_TARGET) $(CFLAGS_LISTING) $(CFLAGS_DEBUG) + -Wl,ac=1 diff --git a/jwt/jwt/jwt.c b/jwt/jwt/jwt.c new file mode 100644 index 000000000..a97f3f1dd --- /dev/null +++ b/jwt/jwt/jwt.c @@ -0,0 +1,948 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef __IBM_METAL__ +#include +#include +#endif + +#include "zowetypes.h" +#include "charsets.h" +#include "json.h" +#include "utils.h" +#include "xlate.h" +#include "alloc.h" +#include "timeutls.h" + +/* rscrypto */ +#include "rs_icsfp11.h" +#include "rs_crypto_errors.h" + +#include "jwt.h" + +const char *RSJWT_ERROR_DESCRIPTIONS[] = { + [RC_JWT_OK] = "OK", + [RC_JWT_MEMORY_ERROR] = "memory error", + [RC_JWT_MISSING_PART] = "missing JWT part", + [RC_JWT_EXTRA_PART] = "extra JWT part", + [RC_JWT_INVALID_ENCODING] = "invalid encoding", + [RC_JWT_INVALID_JSON] = "invalid JSON", + [RC_JWT_UNKNOWN_ALGORITHM] = "unknown algorithm", + [RC_JWT_UNSUPPORTED_ALG] = "unsupported algorithm", + [RC_JWT_INVALID_SIGLEN] = "invalid signature length", + [RC_JWT_CRYPTO_ERROR] = "crypto error", + [RC_JWT_SIG_MISMATCH] = "signature mismatch", + [RC_JWT_CONTEXT_ALLOCATION_FAILED] = "context allocation failed", + [RC_JWT_CRYPTO_TOKEN_NOT_FOUND] = "crypto token not found", + [RC_JWT_KEY_NOT_FOUND] = "key not found in crypto token", + [RC_JWT_INSECURE] = "JWT is insecure" +}; + +#ifdef __ZOWE_EBCDIC +# define JSON_CCSID CCSID_IBM1047 +#else +# define JSON_CCSID CCSID_ISO_8859_1 +#endif + +#define MAX_NPARTS 3 +#define BASE64URL_EXTRA_BYTES 2 +#define BASE64URL_EXTRA_BYTES_TOTAL (BASE64URL_EXTRA_BYTES * MAX_NPARTS) + +#ifdef __ZOWE_EBCDIC +# define BASE64_IS_EBCDIC 1 +#else +# define BASE64_IS_EBCDIC 0 +#endif + +#ifdef JWT_DEBUG +#define DEBUG printf +#define DUMPBUF dumpbuffer +#else +#define DEBUG(...) (void)0 +#define DUMPBUF(...) (void)0 +#endif + +#define ASCII_PERIOD 0x2e + +/* + * buf should have extra space for base64url -> base64 conversion + */ +static int extractParts(char base64Buf[], int maxParts, + char *dparts[], int pLen[], char *decodedText) { + char *tokenizer; + unsigned int nParts, i = 0; + char *part; + + for (part = strtok_r(base64Buf, ".", &tokenizer); + (part != NULL) && (i < maxParts); + part = strtok_r(NULL, ".", &tokenizer), i++) { + dparts[i] = part; + pLen[i] = strlen(part) + 1; + DEBUG("found part %s, len %u\n", dparts[i], pLen[i]); + } + if ((part != NULL) && (i == maxParts)) { + DEBUG("error: too many token parts\n"); + return RC_JWT_EXTRA_PART; + } + nParts = i; + if (nParts > 0) { + pLen[nParts - 1] += BASE64URL_EXTRA_BYTES; + DEBUG("part %d is now %u bytes\n", nParts - 1, pLen[nParts - 1]); + } + for (i = nParts - 1; i > 0; i--) { + char *moved = dparts[i] + i * BASE64URL_EXTRA_BYTES; + DEBUG("adding extra space betwen parts: part %d %p -> %p\n", i, dparts[i], + moved); + memmove(moved, dparts[i], pLen[i]); + dparts[i] = moved; + pLen[i - 1] += BASE64URL_EXTRA_BYTES; + DEBUG("part %d is now %u bytes\n", i - 1, pLen[i - 1]); + } + for (i = 0; i < nParts; i++) { + int base64Rc = 0; + + DEBUG("decoding part %d: %s[%u]...\n", i, dparts[i], pLen[i]); + DEBUG("calling base64urlToBase64()...\n"); + if ((base64Rc = base64urlToBase64(dparts[i], pLen[i])) < 0) { + DEBUG("error: invalid base64url %d\n", base64Rc); + return RC_JWT_INVALID_ENCODING; + } + DEBUG("got base64: %s\n", dparts[i]); + DEBUG("calling decodeBase64()...\n"); + base64Rc = decodeBase64(dparts[i], decodedText); + if (base64Rc < 0) { + DEBUG("error: invalid base64\n"); + return RC_JWT_INVALID_ENCODING; + } + dparts[i] = decodedText; + pLen[i] = (unsigned int)base64Rc; + decodedText += (unsigned int)base64Rc; + decodedText[0] = '\0'; + decodedText++; + DEBUG("decoded part %d\n", i); + } + return nParts; +} + +static int readHeader(char *jsonText, int len, ShortLivedHeap *slh, Jwt *jwt) { + char errBuf[128]; + int status; + char *inputAlg; + + JwsHeader *head = &jwt->header; + DEBUG("readHeader: calling jsonParseUnterminatedUtf8String()...\n"); + Json *json = jsonParseUnterminatedUtf8String(slh, JSON_CCSID, jsonText, + len, errBuf, sizeof (errBuf)); + if (json == NULL) { + DEBUG("error: %.128s\n", errBuf); + return RC_JWT_INVALID_JSON; + } + JsonObject *obj = jsonAsObject(json); + if (obj == NULL) { + DEBUG("readHeader: jsonAsObject failed()\n"); + return RC_JWT_INVALID_JSON; + } + inputAlg = jsonStringProperty(obj, "alg", &status); + if (inputAlg == NULL) { + DEBUG("readHeader: no alg in the json\n"); + return RC_JWT_INVALID_JSON; + } +#define SET_ALG_IF_MATCHES($alg) \ + if (strcmp(#$alg, inputAlg) == 0) { \ + DEBUG("algorithm %s\n", #$alg); \ + head->algorithm = JWS_ALGORITHM_##$alg; \ + } else + + WITH_JWT_ALGORITHMS(SET_ALG_IF_MATCHES) { + /* if none matches */ + return RC_JWT_UNKNOWN_ALGORITHM; + } +#undef SET_ALG_IF_MATCHES + + head->keyId = jsonStringProperty(obj, "kid", &status); + if (status == JSON_PROPERTY_UNEXPECTED_TYPE) { + DEBUG("readHeader: header.kid type unexpected\n"); + return RC_JWT_INVALID_JSON; + } + return RC_JWT_OK; +} + +static int readClaims(char *jsonText, int len, ShortLivedHeap *slh, Jwt *jwt) { + char errBuf[128]; + Json *json; + JsonObject *obj; + JwtClaim **nextClaim = &jwt->firstCustomClaim; + + json = jsonParseUnterminatedUtf8String(slh, JSON_CCSID, jsonText, + len, errBuf, sizeof (errBuf)); + if (json == NULL) { + return RC_JWT_INVALID_JSON; + } + obj = jsonAsObject(json); + if (obj == NULL) { + return RC_JWT_INVALID_JSON; + } + for (JsonProperty *p = jsonObjectGetFirstProperty(obj); + p != NULL; + p = jsonObjectGetNextProperty(p)) { + bool standard = FALSE; + char *key = p->key; + + DEBUG("property %s, value at %p\n", p->key, p->value); +#define KEY_IS($val) (strncmp(key, $val, 4) == 0) + +#define SET_STANDARD_STRING($name) do {\ + DEBUG("standard string\n"); \ + standard = TRUE; \ + jwt->$name = jsonAsString(p->value); \ +} while (0) + +#define SET_STANDARD_NUMBER($name) do {\ + DEBUG("standard number\n"); \ + standard = TRUE; \ + jwt->$name = jsonAsNumber(p->value); \ +} while (0) + + if (KEY_IS("aud")) { + SET_STANDARD_STRING(audience); + } else if (KEY_IS("exp")) { + SET_STANDARD_NUMBER(expirationTime); + } else if (KEY_IS("iat")) { + SET_STANDARD_NUMBER(issuedAt); + } else if (KEY_IS("iss")) { + SET_STANDARD_STRING(issuer); + } else if (KEY_IS("jti")) { + SET_STANDARD_NUMBER(jwtId); + } else if (KEY_IS("nbf")) { + SET_STANDARD_NUMBER(notBefore); + } else if (KEY_IS("sub")) { + SET_STANDARD_STRING(subject); + } +#undef KEY_IS +#undef SET_STANDARD_STRING +#undef SET_STANDARD_NUMBER + + if ((slh != NULL) && !standard) { + DEBUG("making custom claim %s \n", p->key); + JwtClaim *c = (void *)SLHAlloc(slh, sizeof (*c)); + if (c == NULL) { + return RC_JWT_MEMORY_ERROR; + } + c->name = p->key; + c->value = p->value; + *nextClaim = c; + nextClaim = &c->next; + } + } + return 0; +} + +/* + * It is the responsibility of upstream code to acquire an ICSFP11_HANDLE_T* + * that is appropriate for the JWT signer and the algorithm used. + */ +static int checkSignature(JwsAlgorithm algorithm, + int sigLen, const uint8_t signature[], + int msgLen, const uint8_t message[], + ICSFP11_HANDLE_T *keyHandle) { + DEBUG("Going to verify the signature of this message: \n"); + DUMPBUF(message, msgLen); + DEBUG("signature: %p\n", signature); + if (signature != NULL) { + DUMPBUF(signature, sigLen); + } + DEBUG("keyHandle: %p\n", keyHandle); + if (keyHandle != NULL) { + DUMPBUF((void*)keyHandle, sizeof(ICSFP11_HANDLE_T)); + } + + int sts = RC_JWT_OK; + int p11rc=0, p11rsn=0; + + switch (algorithm) { + case JWS_ALGORITHM_none: { + if (sigLen == 0) { + sts = RC_JWT_INSECURE; + } else { + sts = RC_JWT_INVALID_SIGLEN; + } + break; + } + case JWS_ALGORITHM_RS256: { + DEBUG("checkSignature JWS_ALGORITHM_RS256\n"); + DEBUG("message:\n"); + DUMPBUF(message, msgLen); + DEBUG("signature:\n"); + DUMPBUF(signature, sigLen); + sts = rs_icsfp11_RS256_verify(keyHandle, + message, (int) msgLen, + signature, (int) sigLen, + &p11rc, &p11rsn); + if ((0 != sts) || (0 != p11rc)) { + DEBUG("checkSignature: error from rs_icsfp11_RS256_verify " + "(sts=%d, rc=%d, rsn=0x%x)\n", + sts, p11rc, p11rsn); + sts = RC_JWT_CRYPTO_ERROR; + break; + } + break; + } + + case JWS_ALGORITHM_HS256: { + if (sigLen != ICSFP11_SHA256_HASHLEN) { + DEBUG("saw HS256 sig alg with unexpected signature length\n"); + sts = RC_JWT_INVALID_SIGLEN; + break; + } + unsigned char hmacbuf[ICSFP11_SHA256_HASHLEN] = {0}; + int hmacbuflen = sizeof(hmacbuf); + sts = rs_icsfp11_hmacSHA256(keyHandle, + message, msgLen, + hmacbuf, &hmacbuflen, + &p11rc, &p11rsn); + + if ((0 != sts) || + (0 != p11rc) || (0 != p11rsn)) { + DEBUG("checkSignature: failed to produce comparison HMAC " + "(sts:%d, p11rc:%d, p11rsn:0x%x)\n", + sts, p11rc, p11rsn); + sts = RC_JWT_CRYPTO_ERROR; + break; + } + DEBUG("comparison HMAC value: \n"); + DUMPBUF(hmacbuf, sizeof(hmacbuf)); + if (0 != memcmp(signature, hmacbuf, ICSFP11_SHA256_HASHLEN)) { + DEBUG("signature verification failed\n"); + sts = RC_JWT_SIG_MISMATCH; + break; + } + DEBUG("signature verified successfully\n"); + break; + } + + case JWS_ALGORITHM_HS384: { + if (sigLen != ICSFP11_SHA384_HASHLEN) { + DEBUG("saw HS256 sig alg with unexpected signature length\n"); + sts = RC_JWT_INVALID_SIGLEN; + break; + } + unsigned char hmacbuf[ICSFP11_SHA384_HASHLEN] = {0}; + int hmacbuflen = sizeof(hmacbuf); + + sts = rs_icsfp11_hmacSHA384(keyHandle, + message, msgLen, + hmacbuf, &hmacbuflen, + &p11rc, &p11rsn); + + if ((0 != sts) || + (0 != p11rc) || (0 != p11rsn)) { + DEBUG("checkSignature: failed to produce comparison HMAC " + "(sts:%d, p11rc:%d, p11rsn:0x%x)\n", + sts, p11rc, p11rsn); + sts = RC_JWT_CRYPTO_ERROR; + break; + } + DEBUG("comparison HMAC value: \n"); + DUMPBUF(hmacbuf, sizeof(hmacbuf)); + if (0 != memcmp(signature, hmacbuf, ICSFP11_SHA384_HASHLEN)) { + DEBUG("signature verification failed\n"); + sts = RC_JWT_SIG_MISMATCH; + break; + } + DEBUG("signature verified successfully\n"); + break; + } + + case JWS_ALGORITHM_HS512: { + if (sigLen != ICSFP11_SHA512_HASHLEN) { + DEBUG("saw HS256 sig alg with unexpected signature length\n"); + sts = RC_JWT_INVALID_SIGLEN; + break; + } + unsigned char hmacbuf[ICSFP11_SHA512_HASHLEN] = {0}; + int hmacbuflen = sizeof(hmacbuf); + sts = rs_icsfp11_hmacSHA512(keyHandle, + message, msgLen, + hmacbuf, &hmacbuflen, + &p11rc, &p11rsn); + if ((0 != sts) || + (0 != p11rc) || (0 != p11rsn)) { + DEBUG("checkSignature: failed to produce comparison HMAC " + "(sts:%d, p11rc:%d, p11rsn:0x%x)\n", + sts, p11rc, p11rsn); + sts = RC_JWT_CRYPTO_ERROR; + break; + } + DEBUG("comparison HMAC value: \n"); + DUMPBUF(hmacbuf, sizeof(hmacbuf)); + if (0 != memcmp(signature, hmacbuf, ICSFP11_SHA512_HASHLEN)) { + DEBUG("signature verification failed\n"); + sts = RC_JWT_SIG_MISMATCH; + break; + } + DEBUG("signature verified successfully\n"); + break; + } + + default: { + sts = RC_JWT_UNSUPPORTED_ALG; + break; + } + } + + return sts; +} + + +int jwtParse(const char *base64Text, bool ebcdic, ICSFP11_HANDLE_T *keyHandle, + ShortLivedHeap *slh, Jwt **out) { + char *base64TextCopy, *decodedText; + char *decodedParts[MAX_NPARTS] = { NULL }; + int pLen[MAX_NPARTS] = { 0 }; + const int base64Len = strlen(base64Text); + const int bufSize = base64Len + BASE64URL_EXTRA_BYTES_TOTAL + 1; + int rc = RC_JWT_OK; + int nparts; + Jwt *j; + + if (slh == NULL) { + DEBUG("jwt slh missing\n"); + return RC_JWT_MEMORY_ERROR; + } + j = (void *)SLHAlloc(slh, sizeof (*j)); + if (j == NULL) { + return RC_JWT_MEMORY_ERROR; + } + if (!BASE64_IS_EBCDIC && ebcdic) { + DEBUG("error: ebcdic on an ascii platform not supported\n"); + return RC_JWT_INVALID_ENCODING; + } + base64TextCopy = safeMalloc(bufSize, "JWT text copy"); + strncpy(base64TextCopy, base64Text, base64Len); + decodedText = safeMalloc(bufSize, "decoded JWT text"); + + if (BASE64_IS_EBCDIC && !ebcdic) { + DEBUG("converting to ebcdic...\n"); + a2e(base64TextCopy, base64Len); + } + DEBUG("calling extractParts()...\n"); + nparts = extractParts(base64TextCopy, MAX_NPARTS, decodedParts, pLen, decodedText); + DEBUG("nparts %d\n", nparts); + if (nparts < 0) { + return nparts; + } + + if (nparts < 1) { + return RC_JWT_MISSING_PART; + } + DEBUG("calling readHeader()...\n"); + rc = readHeader(decodedParts[0], pLen[0], slh, j); + DEBUG("readHeader() rc %d...\n", rc); + if (rc != RC_JWT_OK) { + goto exit; + } + + if (nparts < 2) { + return RC_JWT_MISSING_PART; + } + DEBUG("calling readClaims()...\n"); + rc = readClaims(decodedParts[1], pLen[1], slh, j); + DEBUG("readClaims() rc %d...\n", rc); + if (rc != RC_JWT_OK) { + goto exit; + } + + const char *asciiBase64 = NULL; + int prefixLen = 0; + if (nparts == 3) { + int dotsNum = 0; + + if (!ebcdic) { + asciiBase64 = base64Text; + } else { + strncpy(base64TextCopy, base64Text, base64Len); + e2a(base64TextCopy, base64Len); + asciiBase64 = base64TextCopy; + } + while ((dotsNum < 2) && (prefixLen < base64Len)) { + if (asciiBase64[prefixLen++] == ASCII_PERIOD) { + dotsNum++; + } + } + } + /* + * note that the alg can be 'none' so we formally support the case when + * `nparts < 3`: we just won't verify the signature, so everything except the + * header will be ignored + */ + DEBUG("calling checkSignature()...\n"); + rc = checkSignature(j->header.algorithm, pLen[2], decodedParts[2], + prefixLen - 1, asciiBase64, keyHandle); + DEBUG("checkSignature() rc %d...\n", rc); + if (rc != RC_JWT_OK && rc != RC_JWT_INSECURE) { + goto exit; + } + + *out = j; + +exit: + safeFree(base64TextCopy, bufSize); + safeFree(decodedText, bufSize); + return rc; +} + +Json *jwtGetCustomClaim(const Jwt *jwt, const char *name) { + JwtClaim *claim; + + JWT_FOR_CLAIMS (jwt, claim) { + if (strcmp(claim->name, name) == 0) { + return claim->value; + } + } + return NULL; +} + +bool jwtAreBasicClaimsValid(const Jwt *jwt, const char *audience) { + if (jwt->expirationTime == 0) { + return false; + } + int64_t stck; getSTCK(&stck); + int64_t currentTime = stckToUnix(stck); + + DEBUG("Time now: %lld, valid after: %lld, expiration: %lld\n", + currentTime, jwt->notBefore, jwt->expirationTime); + if (!((jwt->notBefore <= currentTime) && (currentTime < jwt->expirationTime))) { + DEBUG("JWT expired or not yet active\n"); + return false; + } + + if (currentTime < jwt->issuedAt) { + DEBUG("JWT issued in the future???\n"); + return false; + } + + if (audience != NULL) { + if ((jwt->audience == NULL) || (strcmp(audience, jwt->audience) != 0)) { + DEBUG("JWT is not for %s\n", audience); + return false; + } + } + + return true; +} + +static int serializeHeader(const Jwt *j, JsonBuffer *jbuf) { + int rc = RC_JWT_OK; + const JwsHeader *h = &j->header; + jsonPrinter *p = makeBufferJsonPrinter(JSON_CCSID, jbuf); + if (p == NULL) { + rc = RC_JWT_MEMORY_ERROR; + goto json_printer_freed; + } + + jsonStart(p); + switch (h->algorithm) { + +#define ALG_TO_JSON($alg) \ + case JWS_ALGORITHM_##$alg: \ + jsonAddString(p, "alg", #$alg); \ + break; + + WITH_JWT_ALGORITHMS(ALG_TO_JSON) + +#undef ALG_TO_JSON + } + if (h->keyId != NULL) { + jsonAddString(p, "kid", h->keyId); + } + jsonEnd(p); + +exit: + freeJsonPrinter(p); +json_printer_freed: + return rc; +} + +static int serializeClaims(const Jwt *j, JsonBuffer *jbuf) { + int rc = RC_JWT_OK; + jsonPrinter *p = makeBufferJsonPrinter(JSON_CCSID, jbuf); + if (p == NULL) { + rc = RC_JWT_MEMORY_ERROR; + goto json_printer_freed; + } + + jsonStart(p); + + if (j->issuer != NULL) { + jsonAddString(p, "iss", j->issuer); + } + if (j->subject != NULL) { + jsonAddString(p, "sub", j->subject); + } + if (j->audience != NULL) { + jsonAddString(p, "aud", j->audience); + } + if (j->expirationTime != 0llu) { + jsonAddInt64(p, "exp", j->expirationTime); + } + if (j->notBefore != 0llu) { + jsonAddInt64(p, "nbf", j->notBefore); + } + if (j->issuedAt != 0llu) { + jsonAddInt64(p, "iat", j->issuedAt); + } + if (j->jwtId != 0llu) { + jsonAddInt64(p, "jti", j->jwtId); + } + + jsonEnd(p); + +exit: + freeJsonPrinter(p); +json_printer_freed: + return rc; +} + +/* + * It is the responsibility of upstream code to acquire an ICSFP11_HANDLE_T* + * that is appropriate for the JWT signer and the algorithm used. + */ +static int generateSignature(JwsAlgorithm algorithm, + int msgLen, const uint8_t message[], + int *sigLen, uint8_t signature[], + const ICSFP11_HANDLE_T *keyHandle) { + DEBUG("Going to generate the signature for this message: \n"); + DUMPBUF(message, msgLen); + DEBUG("keyHandle: %p\n", keyHandle); + if (keyHandle != NULL) { + DUMPBUF((void*)keyHandle, sizeof(ICSFP11_HANDLE_T)); + } + + int sts = RC_JWT_OK; + int p11rc=0, p11rsn=0; + + switch (algorithm) { + case JWS_ALGORITHM_none: { + *sigLen = 0; + break; + } + case JWS_ALGORITHM_RS256: { + DEBUG("generateSignature JWS_ALGORITHM_RS256\n"); + DEBUG("message:\n"); + DUMPBUF(message, msgLen); + sts = rs_icsfp11_RS256_sign(keyHandle, + message, msgLen, + signature, sigLen, + &p11rc, &p11rsn); + if ((0 != sts) || (0 != p11rc)) { + DEBUG("generateSignature: error from rs_icsfp11_RS256_verify " + "(sts=%d, rc=%d, rsn=0x%x)\n", + sts, p11rc, p11rsn); + sts = RC_JWT_CRYPTO_ERROR; + break; + } + DEBUG("signature:\n"); + DUMPBUF(signature, *sigLen); + break; + } + + case JWS_ALGORITHM_HS256: { + sts = rs_icsfp11_hmacSHA256(keyHandle, + message, msgLen, + signature, sigLen, + &p11rc, &p11rsn); + if ((0 != sts) || + (0 != p11rc) || (0 != p11rsn)) { + DEBUG("generateSignature: failed to produce comparison HMAC " + "(sts:%d, p11rc:%d, p11rsn:0x%x)\n", + sts, p11rc, p11rsn); + sts = RC_JWT_CRYPTO_ERROR; + break; + } + *sigLen = ICSFP11_SHA256_HASHLEN; + DEBUG("signature:\n"); + DUMPBUF(signature, *sigLen); + break; + } + + case JWS_ALGORITHM_HS384: { + sts = rs_icsfp11_hmacSHA384(keyHandle, + message, msgLen, + signature, sigLen, + &p11rc, &p11rsn); + if ((0 != sts) || + (0 != p11rc) || (0 != p11rsn)) { + DEBUG("checkSignature: failed to produce comparison HMAC " + "(sts:%d, p11rc:%d, p11rsn:0x%x)\n", + sts, p11rc, p11rsn); + sts = RC_JWT_CRYPTO_ERROR; + break; + } + *sigLen = ICSFP11_SHA384_HASHLEN; + DEBUG("signature:\n"); + DUMPBUF(signature, *sigLen); + break; + } + + case JWS_ALGORITHM_HS512: { + sts = rs_icsfp11_hmacSHA512(keyHandle, + message, msgLen, + signature, sigLen, + &p11rc, &p11rsn); + if ((0 != sts) || + (0 != p11rc) || (0 != p11rsn)) { + DEBUG("checkSignature: failed to produce comparison HMAC " + "(sts:%d, p11rc:%d, p11rsn:0x%x)\n", + sts, p11rc, p11rsn); + sts = RC_JWT_CRYPTO_ERROR; + break; + } + *sigLen = ICSFP11_SHA512_HASHLEN; + DEBUG("signature:\n"); + DUMPBUF(signature, *sigLen); + break; + } + + default: { + sts = RC_JWT_UNSUPPORTED_ALG; + break; + } + } + + return sts; +} + +int jwtEncode(const Jwt *jwt, bool ebcdic, + const ICSFP11_HANDLE_T *keyHandle, ShortLivedHeap *slh, + int *encodedSize, char **encoded) { + int rc = RC_JWT_OK; + + JsonBuffer *const jbufHead = makeJsonBuffer(); + if (jbufHead == NULL) { + rc = RC_JWT_MEMORY_ERROR; + goto json_buffer_head_freed; + } + DEBUG("Serializing the header...\n"); + rc = serializeHeader(jwt, jbufHead); + if (rc != RC_JWT_OK) { + DEBUG("fail, rc %d\n", rc); + goto exit; + } + + JsonBuffer *const jbufClaims = makeJsonBuffer(); + if (jbufClaims == NULL) { + rc = RC_JWT_MEMORY_ERROR; + goto json_buffer_claims_freed; + } + DUMPBUF(jbufHead->data, jbufHead->len); + DEBUG("Serializing the claims...\n"); + rc = serializeClaims(jwt, jbufClaims); + if (rc != RC_JWT_OK) { + DEBUG("fail, rc %d\n", rc); + goto exit; + } + DUMPBUF(jbufClaims->data, jbufClaims->len); + + const int resultSize = BASE64_ENCODE_SIZE(jbufHead->len) + 1 + + BASE64_ENCODE_SIZE(jbufClaims->len) + 1 + + BASE64_ENCODE_SIZE(JWT_MAX_SIGNATURE_SIZE) + 1; + char *const result = SLHAlloc(slh, resultSize); + if (result == NULL) { + rc = RC_JWT_MEMORY_ERROR; + goto exit; + } + memset(result, 0, resultSize); + + int partsLen; + int base64Size; + encodeBase64NoAlloc(jbufHead->data, jbufHead->len, result, &base64Size, + BASE64_IS_EBCDIC); + DEBUG("base64 header: %s[%u]\n", result, base64Size); + partsLen = base64ToBase64url(result); + DEBUG("base64url header: %s[%u]\n", result, partsLen); + result[partsLen++] = '.'; + encodeBase64NoAlloc(jbufClaims->data, jbufClaims->len, &result[partsLen], + &base64Size, BASE64_IS_EBCDIC); + DEBUG("base64 claims: %s[%u]\n", &result[partsLen], base64Size); + partsLen += base64ToBase64url(&result[partsLen]); + DEBUG("base64url header + claims: %.*s[%d]\n", partsLen, result, partsLen); + + if (jwt->header.algorithm != JWS_ALGORITHM_none) { + int signRc = 0; + uint8_t *const signatureBuf = (void *)safeMalloc(JWT_MAX_SIGNATURE_SIZE, + "JWT signature"); + if (signatureBuf == NULL) { + signRc = RC_JWT_MEMORY_ERROR; + goto signatureBuf_freed; + } + + int signatureLength = JWT_MAX_SIGNATURE_SIZE; + if (!ebcdic) { + signRc = generateSignature(jwt->header.algorithm, + partsLen, result, + &signatureLength, signatureBuf, + keyHandle); + } else { + char *asciiBase64 = (void *)safeMalloc(partsLen + 1, "JWT ASCII base64"); + if (asciiBase64 == NULL) { + signRc = RC_JWT_MEMORY_ERROR; + goto asciiBase64_freed; + } + strncpy(asciiBase64, result, partsLen + 1); + e2a(asciiBase64, partsLen); + signRc = generateSignature(jwt->header.algorithm, + partsLen, asciiBase64, + &signatureLength, signatureBuf, + keyHandle); + safeFree(asciiBase64, partsLen + 1); +asciiBase64_freed: + ; + } + + if (signRc == RC_JWT_OK) { + DEBUG("signatureLength %d\n", signatureLength); + result[partsLen++] = '.'; + encodeBase64NoAlloc(signatureBuf, signatureLength, &result[partsLen], + &base64Size, BASE64_IS_EBCDIC); + partsLen += base64ToBase64url(&result[partsLen]); + } + safeFree(signatureBuf, JWT_MAX_SIGNATURE_SIZE); +signatureBuf_freed: + ; + rc = signRc; + if (signRc != RC_JWT_OK) { + goto exit; + } + } + + *encodedSize = partsLen + 1; + *encoded = result; +exit: + freeJsonBuffer(jbufClaims); +json_buffer_claims_freed: + freeJsonBuffer(jbufHead); +json_buffer_head_freed: + return rc; +} + + +struct JwtContext_tag { + ICSFP11_HANDLE_T *tokenHandle; + ICSFP11_HANDLE_T *keyHandle; +}; + +JwtContext *makeJwtContextForKeyInToken(const char *in_tokenName, + const char *in_keyLabel, + int class, + int *out_rc, + int *out_p11rc, int *out_p11rsn) { + JwtContext *result = (void *)safeMalloc(sizeof (*result), "JwtContext"); + if (result == NULL) { + *out_rc = RC_JWT_CONTEXT_ALLOCATION_FAILED; + goto context_freed; + } + + DEBUG("attempting to address the token %s...\n", in_tokenName); + ICSFP11_HANDLE_T *tokenHandle = NULL; + const int findTokenRc = rs_icsfp11_findToken(in_tokenName, &tokenHandle, + out_p11rc, out_p11rsn); + DEBUG("findTokenRc %d, out_p11rc %d, out_p11rsn %d\n", findTokenRc, *out_p11rc, + *out_p11rsn); + if (!((0 == findTokenRc) && (0 == *out_p11rc) && (0 == *out_p11rsn))) { + *out_rc = RC_JWT_CRYPTO_TOKEN_NOT_FOUND; + goto token_freed; + } + DUMPBUF((void*)tokenHandle, sizeof (*tokenHandle)); + result->tokenHandle = tokenHandle; + + DEBUG("attempting to address the key record %s(%d)...\n", in_keyLabel, class); + ICSFP11_HANDLE_T *const keyHandle = (void *) safeMalloc(sizeof (*keyHandle), + "keyhandle"); + if (keyHandle == NULL) { + *out_rc = RC_JWT_CONTEXT_ALLOCATION_FAILED; + goto key_copy_freed; + } + + ICSFP11_HANDLE_T *foundHandles = NULL; + int numfound = 0; + const int findKeyRc = rs_icsfp11_findObjectsByLabelAndClass(tokenHandle, in_keyLabel, + class, + NULL, &foundHandles, &numfound, + out_p11rc, out_p11rsn); + DEBUG("findKeyRc %d, out_p11rc %d, out_p11rsn %d, numfound %d\n", + findKeyRc, *out_p11rc, *out_p11rsn, numfound); + if (!((0 == findKeyRc) && (0 == *out_p11rc) && (0 == *out_p11rsn) && (numfound > 0))) { + *out_rc = RC_JWT_KEY_NOT_FOUND; + goto key_not_found; + } + + DEBUG("key record found\n"); + DUMPBUF((void *)foundHandles, numfound * sizeof (foundHandles[0])); + + if (1 < numfound) { + DEBUG("Warning: More than one key record found for label: %s\n", in_keyLabel); + } + memcpy(keyHandle, &(foundHandles[0]), sizeof (foundHandles[0])); + safeFree((void *)foundHandles, numfound * sizeof (foundHandles[0])); + result->keyHandle = keyHandle; + *out_rc = RC_JWT_OK; + return result; + +key_not_found: + safeFree((void *)keyHandle, sizeof (*keyHandle)); +key_copy_freed: + safeFree((void *)tokenHandle, sizeof (*tokenHandle)); +token_freed: + safeFree((void *)result, sizeof (*result)); +context_freed: + return NULL; +} + +Jwt *jwtVerifyAndParseToken(const JwtContext *self, + const char *tokenText, + bool ebcdic, + ShortLivedHeap *slh, + int *rc) { + Jwt *out; + *rc = jwtParse(tokenText, ebcdic, self->keyHandle, slh, &out); + return out; +} + +char *jwtEncodeToken(const JwtContext *self, + const Jwt *jwt, + bool ebcdic, + ShortLivedHeap *slh, + int *encodedSize, + int *rc) { + char *out; + *rc = jwtEncode(jwt, ebcdic, self->keyHandle, slh, encodedSize, &out); + return out; +} + +void jwtContextDestroy(JwtContext *self) { + if (self->tokenHandle != NULL) { + safeFree((void *)self->tokenHandle, sizeof (*self->tokenHandle)); + } + if (self->keyHandle != NULL) { + safeFree((void *)self->keyHandle, sizeof (*self->keyHandle)); + } + safeFree((void *)self, sizeof (*self)); +} + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + diff --git a/jwt/jwt/jwt.h b/jwt/jwt/jwt.h new file mode 100644 index 000000000..1b9b63e42 --- /dev/null +++ b/jwt/jwt/jwt.h @@ -0,0 +1,154 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef H_JWT_H_ +#define H_JWT_H_ + +#include "zowetypes.h" +#include "json.h" +#include "utils.h" +#include "../rscrypto/rs_icsfp11.h" + +#define RC_JWT_OK 0 +#define RC_JWT_MEMORY_ERROR 1 +#define RC_JWT_MISSING_PART 2 +#define RC_JWT_EXTRA_PART 3 +#define RC_JWT_INVALID_ENCODING 4 +#define RC_JWT_INVALID_JSON 5 +#define RC_JWT_UNKNOWN_ALGORITHM 6 +#define RC_JWT_UNSUPPORTED_ALG 7 +#define RC_JWT_INVALID_SIGLEN 8 +#define RC_JWT_CRYPTO_ERROR 9 +#define RC_JWT_SIG_MISMATCH 10 +#define RC_JWT_CONTEXT_ALLOCATION_FAILED 11 +#define RC_JWT_CRYPTO_TOKEN_NOT_FOUND 12 +#define RC_JWT_KEY_NOT_FOUND 13 +/* + * RC_JWT_INSECURE is returned when a JWT is valid but has "alg": "none". + * This is a source of security issues, so a distinct RC is needed. + * If an app needs to accept insecure JWTs for some reason, it can do something + * like: +#ifdef DISABLE_SECURITY +# define IS_JWT_RC_OK($rc) (($rc) == RC_JWT_OK || ($rc) == RC_JWT_INSECURE) +#else +# define IS_JWT_RC_OK($rc) (($rc) == RC_JWT_OK) +#endif + */ +#define RC_JWT_INSECURE 14 + +#define MAX_JWT_RC RC_JWT_INSECURE + +extern const char *RSJWT_ERROR_DESCRIPTIONS[]; +#define JWT_ERROR_DESCRIPTION($rc) ((0 <= ($rc) && ($rc) <= MAX_JWT_RC)? \ + RSJWT_ERROR_DESCRIPTIONS[$rc] : NULL) + +#define WITH_JWT_ALGORITHMS($algHandler) \ + $algHandler(none) /* No digital signature or MAC performed Optional */ \ + $algHandler(HS256) /* HMAC using SHA-256 Required */ \ + $algHandler(HS384) /* HMAC using SHA-384 Optional */ \ + $algHandler(HS512) /* HMAC using SHA-512 Optional */ \ + $algHandler(RS256) /* RSASSA-PKCS1-v1_5 using SHA-256 Recommended */ \ + $algHandler(RS384) /* RSASSA-PKCS1-v1_5 using SHA-384 Optional */ \ + $algHandler(RS512) /* RSASSA-PKCS1-v1_5 using SHA-512 Optional */ \ + $algHandler(ES256) /* ECDSA using P-256 and SHA-256 Recommended+ */ \ + $algHandler(ES384) /* ECDSA using P-384 and SHA-384 Optional */ \ + $algHandler(ES512) /* ECDSA using P-521 and SHA-512 Optional */ \ + $algHandler(PS256) /* RSASSA-PSS using SHA-256 and MGF1 with SHA-256 Optional */ \ + $algHandler(PS384) /* RSASSA-PSS using SHA-384 and MGF1 with SHA-384 Optional */ \ + $algHandler(PS512) /* RSASSA-PSS using SHA-512 and MGF1 with SHA-512 Optional */ + +#define JWT_MAX_SIGNATURE_SIZE 2048 + +typedef enum JwsAlgorithm_tag { +#define JWT_ENUM_FIELD($alg) JWS_ALGORITHM_##$alg, + WITH_JWT_ALGORITHMS(JWT_ENUM_FIELD) +#undef JWT_ENUM_FIELD +} JwsAlgorithm; + + +typedef struct JwsHeader_tag { + JwsAlgorithm algorithm; + char *keyId; + /* optional stuff not implemented yet */ +} JwsHeader; + +typedef struct Jwt_tag { + JwsHeader header; + char *issuer; + char *subject; + char *audience; + int64 expirationTime; + int64 notBefore; + int64 issuedAt; + int64 jwtId; + struct JwtClaim_tag *firstCustomClaim; + char *signature; +} Jwt; + +typedef struct JwtClaim_tag { + char *name; + Json *value; + struct JwtClaim_tag *next; +} JwtClaim; + +typedef struct JwtContext_tag JwtContext; + +#define JWT_FOR_CLAIMS($jwt, $var) for ($var = ($jwt)->firstCustomClaim; \ + $var != NULL ;$var = ($var)->next) + +int jwtParse(const char *base64Text, + bool ebcdic, + const ICSFP11_HANDLE_T *keyHandle, + ShortLivedHeap *slh, + Jwt **out); + +int jwtEncode(const Jwt *jwt, + bool ebcdic, + const ICSFP11_HANDLE_T *keyHandle, + ShortLivedHeap *slh, + int *encodedSize, + char **encoded); + +Json *jwtGetCustomClaim(const Jwt *jwt, const char *name); + +bool jwtAreBasicClaimsValid(const Jwt *jwt, const char *audience); + +JwtContext *makeJwtContextForKeyInToken(const char *in_tokenName, + const char *in_keyLabel, + int class, + int *out_rc, + int *out_p11rc, int *out_p11rsn); + +Jwt *jwtVerifyAndParseToken(const JwtContext *self, + const char *tokenText, + bool ebcdic, + ShortLivedHeap *slh, + int *rc); + +char *jwtEncodeToken(const JwtContext *self, + const Jwt *jwt, + bool ebcdic, + ShortLivedHeap *slh, + int *encodedSize, + int *rc); + +void jwtContextDestroy(JwtContext *self); + +#endif /* H_JWT_H_ */ + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/jwt/jwt/module.mk b/jwt/jwt/module.mk new file mode 100644 index 000000000..1d6717beb --- /dev/null +++ b/jwt/jwt/module.mk @@ -0,0 +1,2 @@ +SRC += jwt/jwt.c + diff --git a/jwt/rscrypto/module.mk b/jwt/rscrypto/module.mk new file mode 100644 index 000000000..b8898477a --- /dev/null +++ b/jwt/rscrypto/module.mk @@ -0,0 +1,3 @@ +SRC += rscrypto/rs_rsclibc.c +SRC += rscrypto/rs_icsfp11.c + diff --git a/jwt/rscrypto/rs_crypto_errors.h b/jwt/rscrypto/rs_crypto_errors.h new file mode 100644 index 000000000..dc3817104 --- /dev/null +++ b/jwt/rscrypto/rs_crypto_errors.h @@ -0,0 +1,134 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef RSCRYPTO_ERRORS_H_ +#define RSCRYPTO_ERRORS_H_ + +//errors +#ifndef RS_SUCCESS +#define RS_SUCCESS 0 +#endif + +#define RSCRYPTO_BASE_ERROR 7770000 + +#define RSCRYPTO_INVALID_ARGUMENT (RSCRYPTO_BASE_ERROR + 1) +#define RSCRYPTO_INSUFFICIENT_OUTPUT_SPACE (RSCRYPTO_BASE_ERROR + 2) +#define RSCRYPTO_CALLABLE_SERVICE_ERROR (RSCRYPTO_BASE_ERROR + 3) +#define RSCRYPTO_UNSUPPORTED_KEY_TYPE (RSCRYPTO_BASE_ERROR + 4) +#define RSCRYPTO_UNSUPPORTED_ALGORITHM (RSCRYPTO_BASE_ERROR + 5) +#define RSCRYPTO_UNSUPPORTED_KEY_LENGTH (RSCRYPTO_BASE_ERROR + 6) +#define RSCRYPTO_INSUFFICIENT_IV_LENGTH (RSCRYPTO_BASE_ERROR + 7) +#define RSCRYPTO_INSUFFICIENT_CIPHERTEXT_LENGTH (RSCRYPTO_BASE_ERROR + 8) +#define RSCRYPTO_CONTEXT_VALIDATION_FAILED (RSCRYPTO_BASE_ERROR + 9) +#define RSCRYPTO_INSUFFICIENT_CLEARTEXT_LENGTH (RSCRYPTO_BASE_ERROR + 10) +#define RSCRYPTO_CIPHERTEXT_INPUT_LENGTH_WARNING (RSCRYPTO_BASE_ERROR + 11) +#define RSCRYPTO_PKCS_PADDING_MALFORMED_WARNING (RSCRYPTO_BASE_ERROR + 12) +#define RSCRYPTO_INSUFFICIENT_KEY_DATA_LENGTH (RSCRYPTO_BASE_ERROR + 13) +#define RSCRYPTO_ALLOC_FAILED (RSCRYPTO_BASE_ERROR + 14) +#define RSCRYPTO_KEYSRC_NO_PLUGIN (RSCRYPTO_BASE_ERROR + 15) +#define RSCRYPTO_UNSUPPORTED_KEYSRC_TYPE (RSCRYPTO_BASE_ERROR + 16) +#define RSCRYPTO_DIGEST_ALORITHM_MISMATCH (RSCRYPTO_BASE_ERROR + 17) +#define RSCRYPTO_INVALID_IDENTIFIER_LENGTH (RSCRYPTO_BASE_ERROR + 18) +#define RSCRYPTO_KEY_LABEL_NOTFOUND (RSCRYPTO_BASE_ERROR + 19) +#define RSCRYPTO_BASE64_DECODE_ERROR (RSCRYPTO_BASE_ERROR + 20) +#define RSCRYPTO_PEM_DECODE_ERROR (RSCRYPTO_BASE_ERROR + 21) +#define RSCRYPTO_KEY_LABEL_EXISTS (RSCRYPTO_BASE_ERROR + 22) +#define RSCRYPTO_KEY_COMPARISON_NOTEQUAL (RSCRYPTO_BASE_ERROR + 23) +#define RSCRYPTO_KEY_COMPARISON_EQUAL RS_SUCCESS + +#define RSCRYPTO_FILE_ERROR (RSCRYPTO_BASE_ERROR + 25) + +#define RSCRYPTO_PUBKEYINFO_NOT_FOUND (RSCRYPTO_BASE_ERROR + 30) +#define RSCRYPTO_ASN1_PARSE_ERROR (RSCRYPTO_BASE_ERROR + 31) +#define RSCRYPTO_PRIVKEYINFO_NOT_FOUND (RSCRYPTO_BASE_ERROR + 32) +#define RSCRYPTO_ATTRLIST_PARSE_ERROR (RSCRYPTO_BASE_ERROR + 33) +#define RSCRYPTO_APPATTR_NOT_FOUND (RSCRYPTO_BASE_ERROR + 34) + + +#define RSCRYPTO_OATH_INVALID_TIME (RSCRYPTO_BASE_ERROR + 40) + +#define RSCRYPTO_PLUGIN_LOAD_ERROR (RSCRYPTO_BASE_ERROR + 200) +#define RSCRYPTO_PLUGIN_SYMBOL_NOT_FOUND (RSCRYPTO_BASE_ERROR + 201) +#define RSCRYPTO_PLUGIN_CREATEINSTANCE_FAILED (RSCRYPTO_BASE_ERROR + 202) +#define RSCRYPTO_PLUGIN_LOOKUP_FAILED (RSCRYPTO_BASE_ERROR + 203) + +#define RSCRYPTO_ICSF_ERROR_BASE (RSCRYPTO_BASE_ERROR + 1000) + +#define RSCRYPTO_CKDS_LABEL_NOTFOUND (RSCRYPTO_ICSF_ERROR_BASE + 1) +#define RSCRYPTO_PKDS_LABEL_NOTFOUND (RSCRYPTO_ICSF_ERROR_BASE + 2) +#define RSCRYPTO_CKDS_RECORD_EXISTS (RSCRYPTO_ICSF_ERROR_BASE + 3) +#define RSCRYPTO_PKDS_RECORD_EXISTS (RSCRYPTO_ICSF_ERROR_BASE + 4) +#define RSCRYPTO_CKDS_CREATE_FAILED (RSCRYPTO_ICSF_ERROR_BASE + 5) +#define RSCRYPTO_PKDS_CREATE_FAILED (RSCRYPTO_ICSF_ERROR_BASE + 6) +#define RSCRYPTO_CKDS_READ_FAILED (RSCRYPTO_ICSF_ERROR_BASE + 7) +#define RSCRYPTO_PKDS_READ_FAILED (RSCRYPTO_ICSF_ERROR_BASE + 8) +#define RSCRYPTO_CKDS_WRITE_FAILED (RSCRYPTO_ICSF_ERROR_BASE + 9) +#define RSCRYPTO_PKDS_WRITE_FAILED (RSCRYPTO_ICSF_ERROR_BASE + 10) +#define RSCRYPTO_ICSF_TVV_EXCEPTION (RSCRYPTO_ICSF_ERROR_BASE + 11) +#define RSCRYPTO_ICSF_BAD_LABEL (RSCRYPTO_ICSF_ERROR_BASE + 12) +#define RSCRYPTO_ICSF_PRIVKEY_REQUIRED (RSCRYPTO_ICSF_ERROR_BASE + 13) +#define RSCRYPTO_ICSF_TASKMODE_ONLY (RSCRYPTO_ICSF_ERROR_BASE + 14) +#define RSCRYPTO_ICSF_CLEARKEY_ONLY (RSCRYPTO_ICSF_ERROR_BASE + 15) +#define RSCRYPTO_CKDS_RECORDFOUND_WRONGTYPE (RSCRYPTO_ICSF_ERROR_BASE + 16) +#define RSCRYPTO_ICSF_PROHIBIT_EXPORT (RSCRYPTO_ICSF_ERROR_BASE + 17) +#define RSCRYPTO_ICSF_PUBKEY_REQUIRED (RSCRYPTO_ICSF_ERROR_BASE + 18) +#define RSCRYPTO_ICSF_SERVICE_NOTAUTH (RSCRYPTO_ICSF_ERROR_BASE + 19) +#define RSCRYPTO_ICSF_LABEL_NOTAUTH (RSCRYPTO_ICSF_ERROR_BASE + 20) +#define RSCRYPTO_ICSF_BAD_TOKEN (RSCRYPTO_ICSF_ERROR_BASE + 21) +#define RSCRYPTO_ICSF_RETAINED_KEY_READONLY (RSCRYPTO_ICSF_ERROR_BASE + 22) +#define RSCRYPTO_ICSF_SIGVERIFY_THUMBS_DOWN (RSCRYPTO_ICSF_ERROR_BASE + 23) +#define RSCRYPTO_ICSF_CLEARKEY_REDACTED (RSCRYPTO_ICSF_ERROR_BASE + 24) +#define RSCRYPTO_ICSF_LENGTH_ERROR (RSCRYPTO_ICSF_ERROR_BASE + 25) + +#define RSCRYPTO_GETPROTECTEDKEY_FAILED (RSCRYPTO_ICSF_ERROR_BASE + 30) + +#define RSCRYPTO_ICSF_INTERNAL_ERROR (RSCRYPTO_ICSF_ERROR_BASE + 40) + +#define RSCRYPTO_ICSFERR_UNRECOGNIZED (RSCRYPTO_ICSF_ERROR_BASE + 50) + + +#define RSCRYPTO_OPENSSL_ERROR_BASE (RSCRYPTO_BASE_ERROR + 2000) + +#define RSCRYPTO_OPENSSL_EVP_CTXINIT (RSCRYPTO_OPENSSL_ERROR_BASE + 1) +#define RSCRYPTO_OPENSSL_EVP_UPDATE (RSCRYPTO_OPENSSL_ERROR_BASE + 2) +#define RSCRYPTO_OPENSSL_EVP_FINAL (RSCRYPTO_OPENSSL_ERROR_BASE + 3) +#define RSCRYPTO_OPENSSL_EVP_DIGESTINIT (RSCRYPTO_OPENSSL_ERROR_BASE + 4) +#define RSCRYPTO_OPENSSL_EVP_DIGESTUPDATE (RSCRYPTO_OPENSSL_ERROR_BASE + 5) +#define RSCRYPTO_OPENSSL_EVP_DIGESTFINAL (RSCRYPTO_OPENSSL_ERROR_BASE + 6) + + +#define RSCRYPTO_PKCS11_ERROR_BASE (RSCRYPTO_BASE_ERROR + 3000) + +#define RS_PKCS11_DLOPEN (RSCRYPTO_PKCS11_ERROR_BASE + 1) +#define RS_PKCS11_DLSYM (RSCRYPTO_PKCS11_ERROR_BASE + 2) +#define RS_PKCS11_TOKEN_NOTFOUND (RSCRYPTO_PKCS11_ERROR_BASE + 3) +#define RS_PKCS11_BAD_LABEL (RSCRYPTO_PKCS11_ERROR_BASE + 4) +#define RS_PKCS11_ENV_NOTINITIALIZED (RSCRYPTO_PKCS11_ERROR_BASE + 5) +#define RS_PKCS11_MAX_RANDOM_EXCEEDED (RSCRYPTO_PKCS11_ERROR_BASE + 6) +#define RS_PKCS11_OBJECT_NOTFOUND (RSCRYPTO_PKCS11_ERROR_BASE + 7) +#define RS_PKCS11_BAD_BITLENGTH (RSCRYPTO_PKCS11_ERROR_BASE + 8) +#define RS_PKCS11_ALREADY_OPEN (RSCRYPTO_PKCS11_ERROR_BASE + 9) +#define RS_PKCS11_ALREADY_CLOSED (RSCRYPTO_PKCS11_ERROR_BASE + 10) +#define RS_PKCS11_REQUIRES_READWRITE (RSCRYPTO_PKCS11_ERROR_BASE + 11) +#define RS_PKCS11_MAXLEN_EXCEEDED (RSCRYPTO_PKCS11_ERROR_BASE + 12) +#define RS_PKCS11_INVALID_SIGDIGEST_TYPE (RSCRYPTO_PKCS11_ERROR_BASE + 13) + + +#endif /* RSCRYPTO_ERRORS_H_ */ + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/jwt/rscrypto/rs_icsfp11.c b/jwt/rscrypto/rs_icsfp11.c new file mode 100644 index 000000000..cedd6e7f9 --- /dev/null +++ b/jwt/rscrypto/rs_icsfp11.c @@ -0,0 +1,1470 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ +#include "rs_rsclibc.h" + +#include "rs_icsfp11.h" +#include "rs_crypto_errors.h" + +#ifdef _LP64 +#pragma linkage(CSFPHMG6,OS) /* hmac generate */ +#pragma linkage(CSFPGSK6,OS) /* gen secret key */ +#pragma linkage(CSFPPRF6,OS) /* random */ +#pragma linkage(CSFPTRC6,OS) /* token record create */ +#pragma linkage(CSFPTRD6,OS) /* token record delete */ +#pragma linkage(CSFPTRL6,OS) /* token record list */ +#pragma linkage(CSFPSKE6,OS) /* secret key encrypt */ +#pragma linkage(CSFPSKD6,OS) /* secret key decrypt */ +#pragma linkage(CSFPSAV6,OS) /* set attribute value */ +#pragma linkage(CSFPGAV6,OS) /* get attribute value */ +#pragma linkage(CSFPOWH6,OS) /* one-way hash, sign, or verify */ +#else +#pragma linkage(CSFPHMG,OS) /* hmac generate */ +#pragma linkage(CSFPGSK,OS) /* gen secret key */ +#pragma linkage(CSFPPRF,OS) /* random */ +#pragma linkage(CSFPTRC,OS) /* token record create */ +#pragma linkage(CSFPTRD,OS) /* token record delete */ +#pragma linkage(CSFPTRL,OS) /* token record list */ +#pragma linkage(CSFPSKE,OS) /* secret key encrypt */ +#pragma linkage(CSFPSKD,OS) /* secret key decrypt */ +#pragma linkage(CSFPSAV,OS) /* set attribute value */ +#pragma linkage(CSFPGAV,OS) /* get attribute value */ +#pragma linkage(CSFPOWH,OS) /* one-way hash, sign, or verify */ +#endif + +/** + * Utilities for internal use + */ +static int rs_icsfp11_hmacSHA_internal ( + const ICSFP11_HANDLE_T *in_key_handle, + ICSFP11_DIGEST_ALG in_alg, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason); + +static int rs_icsfp11_findObjects_internal ( + const ICSFP11_HANDLE_T *in_token_handle, + int in_numattrs, const CK_ATTRIBUTE *in_attrs, + ICSFP11_HANDLE_T **out_handles, + int *out_numfound, + int *out_rc, int *out_reason); + +static int rs_icsfp11_createObject_internal(const ICSFP11_HANDLE_T *in_token_handle, + int in_numattrs, const CK_ATTRIBUTE *in_attrs, + ICSFP11_HANDLE_T **out_obj_handle, + int *out_rc, int *out_reason); + + +static int serialize_attribute_list(int num_attrs, + const CK_ATTRIBUTE *attr_array, + unsigned char **out_attrlist_buf, + int *out_attrlist_len); + +/* parse_attribute_list allocates new CK_ATTRIBUTE structures, but those structures + * point into the supplied in_serialized_attrlist buffer */ +static int parse_attribute_list(const unsigned char* in_serialized_attrlist, + int in_serialized_attrlist_len, + CK_ATTRIBUTE** out_attr_array, int* out_num_attrs); + +static const char RS_TOKEN_KEYWORD[8] = {'T','O','K','E','N',' ',' ',' '}; +static const char RS_OBJECT_KEYWORD[8] = {'O','B','J','E','C','T',' ',' '}; +static const char RS_PRNG_KEYWORD[8] = {'P','R','N','G',' ',' ',' ',' '}; +static const char RS_KEY_KEYWORD[8] = {'K','E','Y',' ',' ',' ',' ',' '}; +static const char RS_SHA1_KEYWORD[8] = {'S','H','A','-','1',' ',' ',' '}; +static const char RS_SHA256_KEYWORD[8] = {'S','H','A','-','2','5','6',' '}; +static const char RS_SHA384_KEYWORD[8] = {'S','H','A','-','3','8','4',' '}; +static const char RS_SHA512_KEYWORD[8] = {'S','H','A','-','5','1','2',' '}; +static const char RS_ONLY_KEYWORD[8] = {'O','N','L','Y',' ',' ',' ',' '}; + +typedef struct TOKEN_OUTPUT_RECORD_tag { + /* first part is just like a CK_TOKEN_INFO */ + CK_UTF8CHAR label[32]; /* blank padded */ + CK_UTF8CHAR manufacturerID[32]; /* blank padded */ + CK_UTF8CHAR model[16]; /* blank padded */ + CK_CHAR serialNumber[16]; /* blank padded */ + /* then it changes */ + CK_DATE dateLastUpdated; /* yyyymmdd */ + CK_CHAR timeLastUpdated[8]; /* hhmmssth */ + unsigned int flags; /* 32 bits, bit 0 on - token is write protected */ +} ICSFP11_TOKEN_RECORD_T; + +int rs_icsfp11_getEnvironment(ICSFP11_ENV_T **out_env, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + ICSFP11_ENV_T *env = NULL; + + int exit_data_len = 0; + char last_handle[44] = {0}; + int rule_array_count = 1; + int search_template_len = 0; + char* output_list = NULL; + int output_list_length; + int handle_count; + + int i; + + char* readhead = NULL; + + do { + if ((NULL == out_env) || + (NULL == out_rc) || + (NULL == out_reason)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + env = (ICSFP11_ENV_T *)rscAlloc(sizeof(ICSFP11_ENV_T), "icsfp11 env"); + +#define ICSFP11_MAX_TOKENS_SUPPORTED 16 + output_list_length = ICSFP11_MAX_TOKENS_SUPPORTED * sizeof(ICSFP11_TOKEN_RECORD_T); + output_list = (char*)rscAlloc(output_list_length, "token records output"); + handle_count = ICSFP11_MAX_TOKENS_SUPPORTED; + + memset(last_handle, 0x40, sizeof(last_handle)); /*set handle to all blanks*/ + /* use the Token Record List service to get the accessible token handles */ +#ifdef _LP64 + CSFPTRL6 ( +#else + CSFPTRL ( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + (unsigned char*)last_handle, + &rule_array_count, + (unsigned char*)RS_TOKEN_KEYWORD, + &search_template_len, + NULL, /* no search template */ + &output_list_length, + &handle_count, + (unsigned char*)output_list); + + if (8 <= *out_rc) { + /* we weren't able to extract token information for some reason */ + rscFree(env, sizeof(ICSFP11_ENV_T)); + *out_env = NULL; + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + break; + } + +#ifdef DEBUG + printf("after token record list, output_list contains:\n"); + dumpbuffer(output_list, output_list_length); +#endif + + env->numTokensAccessible = handle_count; + env->tokensHandlesArray = (ICSFP11_HANDLE_T*)rscAlloc(handle_count * sizeof(ICSFP11_HANDLE_T), "token handles"); + readhead = output_list; + + /* copy the token names into the token handles array */ + for (i=0; i < handle_count; i++) { + memset((&(env->tokensHandlesArray[i])), 0x40, sizeof(ICSFP11_HANDLE_T)); + memcpy(env->tokensHandlesArray[i].tokenName, readhead, 32); + readhead += sizeof(ICSFP11_TOKEN_RECORD_T); + } + /*TODO: call query facilities to fill in rest of environment data */ + + *out_env = env; + + } while(0); + + if (output_list) { + rscFree(output_list, ICSFP11_MAX_TOKENS_SUPPORTED * sizeof(ICSFP11_TOKEN_RECORD_T)); + } + + return status; +} + +void rs_icsfp11_envDescribe(const ICSFP11_ENV_T *in_env) +{ + char safeString[45] = {0}; + int i; + if (in_env) { + printf("ICSFP11 Environment Description for env at 0x%p:\n", in_env); + printf("numTokensAccessible: %d\n", in_env->numTokensAccessible); + for (i=0; i < in_env->numTokensAccessible; i++) + { + memcpy(safeString, &(in_env->tokensHandlesArray[i]), 44); + printf("tokenHandlesArray[%d] = <%s>\n", i, safeString); + memset(safeString, 0x00, sizeof(safeString)); + } + printf("- - -\n"); + } +} + +void rs_icsfp11_envDestroy(ICSFP11_ENV_T *in_env) +{ + if (in_env) { + if ((0 < in_env->numTokensAccessible) && (NULL != in_env->tokensHandlesArray)) { + rscFree(in_env->tokensHandlesArray, in_env->numTokensAccessible * sizeof(ICSFP11_HANDLE_T)); + } + memset(in_env, 0x00, sizeof(ICSFP11_ENV_T)); + rscFree(in_env, sizeof(ICSFP11_ENV_T)); + } +} + +int rs_icsfp11_getRandomBytes(const ICSFP11_HANDLE_T *token_handle, + unsigned char *randbuf, int *randbuf_len, + int *out_rc, int *out_reason) +{ + int status = 0; + + int exit_data_len = 0; + int rule_array_count = 1; + int parms_list_len = 0; + + ICSFP11_HANDLE_T cleanHandle = ICSFP11_HANDLE_INITIALIZER; + + do { + if ((NULL == token_handle) || + (NULL == randbuf) || (0 == randbuf_len) || + (NULL == out_rc) || (NULL == out_reason)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + memcpy(&(cleanHandle.tokenName[0]), &(token_handle->tokenName[0]), sizeof(cleanHandle.tokenName)); + +#ifdef _LP64 + CSFPPRF6( +#else + CSFPPRF( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + &rule_array_count, + (unsigned char*) RS_PRNG_KEYWORD, + (unsigned char*)(void *) &cleanHandle, + &parms_list_len, + NULL, /* no parms list */ + randbuf_len, + randbuf); + + } while(0); + + return status; +} + +int rs_icsfp11_hmacTokenKeyCreateFromRaw( + ICSFP11_HANDLE_T *in_token_handle, + char* in_keylabel, + char* in_appname, + const unsigned char* in_keydata, int in_keydata_len, + ICSFP11_HANDLE_T **out_key_handle, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + unsigned int objectclass = CKO_SECRET_KEY; + unsigned int keytype = CKK_GENERIC_SECRET; + CK_BBOOL ontoken = CK_TRUE; + CK_BBOOL cansign = CK_TRUE; + CK_ATTRIBUTE hmac_key_attrs[7] = { + { CKA_CLASS, &objectclass, sizeof(unsigned int) }, + { CKA_KEY_TYPE, &keytype, sizeof(unsigned int) }, + { CKA_TOKEN, &ontoken, sizeof(CK_BBOOL) }, + { CKA_SIGN, &cansign, sizeof(CK_BBOOL) }, + { CKA_VALUE, (char *)in_keydata, in_keydata_len }, + { CKA_LABEL, NULL, 0 }, + { CKA_APPLICATION, NULL, 0 } + }; + int num_key_attrs=0; + + do { + if ((NULL == in_token_handle) || + (NULL == in_keylabel) || + (NULL == out_key_handle) || + (NULL == out_rc) || + (NULL == out_reason)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + hmac_key_attrs[5].pValue = in_keylabel; + hmac_key_attrs[5].ulValueLen = strlen(in_keylabel); + if (32 < hmac_key_attrs[5].ulValueLen) { + status = RSCRYPTO_INVALID_IDENTIFIER_LENGTH; + break; + } + + if (in_appname) { + hmac_key_attrs[6].pValue = in_appname; + hmac_key_attrs[6].ulValueLen = strlen(in_appname); + num_key_attrs = 7; + } else { + num_key_attrs = 6; + } + + /* we use the Create Token Record service when we want + * to pass our own key data */ + status = rs_icsfp11_createObject_internal(in_token_handle, + num_key_attrs, (CK_ATTRIBUTE*)hmac_key_attrs, + out_key_handle, + out_rc, out_reason); + + } while(0); + + return status; +} + +int rs_icsfp11_findObjectsByLabelAndClass( + ICSFP11_HANDLE_T *in_token_handle, + char* in_label, + CK_ULONG in_objectClass, + char* in_appname, + ICSFP11_HANDLE_T **out_handles, + int *out_numfound, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + CK_ATTRIBUTE object_attrs[3] = { + { CKA_CLASS, &in_objectClass, sizeof(CK_OBJECT_CLASS) }, + { CKA_LABEL, NULL, 0 }, + { CKA_APPLICATION, NULL, 0 } + }; + int num_attrs = 0; + + do { + if (NULL == in_label) { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + object_attrs[1].pValue = in_label; + object_attrs[1].ulValueLen = strlen(in_label); + if (32 < object_attrs[1].ulValueLen) { + status = RSCRYPTO_INVALID_IDENTIFIER_LENGTH; + break; + } + + if (in_appname) { + object_attrs[2].pValue = in_appname; + object_attrs[2].ulValueLen = strlen(in_appname); + num_attrs = 3; + } else { + num_attrs = 2; + } + + status = rs_icsfp11_findObjects_internal(in_token_handle, + num_attrs, (CK_ATTRIBUTE*)object_attrs, + out_handles, + out_numfound, + out_rc, out_reason); + + } while(0); + + return status; +} + +int rs_icsfp11_findObjectsByLabel( + ICSFP11_HANDLE_T *in_token_handle, + char* in_label, + char* in_appname, + ICSFP11_HANDLE_T **out_handles, + int *out_numfound, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + CK_ATTRIBUTE object_attrs[2] = { + { CKA_LABEL, NULL, 0 }, + { CKA_APPLICATION, NULL, 0 } + }; + int num_attrs = 0; + + do { + if (NULL == in_label) { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + object_attrs[0].pValue = in_label; + object_attrs[0].ulValueLen = strlen(in_label); + if (32 < object_attrs[0].ulValueLen) { + status = RSCRYPTO_INVALID_IDENTIFIER_LENGTH; + break; + } + + if (in_appname) { + object_attrs[1].pValue = in_appname; + object_attrs[1].ulValueLen = strlen(in_appname); + num_attrs = 2; + } else { + num_attrs = 1; + } + + status = rs_icsfp11_findObjects_internal(in_token_handle, + num_attrs, (CK_ATTRIBUTE*)object_attrs, + out_handles, + out_numfound, + out_rc, out_reason); + + } while(0); + + return status; +} + +int rs_icsfp11_deleteObject(ICSFP11_HANDLE_T *in_object_handle, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int rule_array_count = 1; + +#ifdef _LP64 + CSFPTRD6( +#else + CSFPTRD( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + (unsigned char*)(void *)in_object_handle, + &rule_array_count, + (unsigned char*)RS_OBJECT_KEYWORD); + + if (8 <= *out_rc) { + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + } + + return status; +} + +/** + * Set or retrieve data from an object's CKA_APPLICATION attribute. + */ +int rs_icsfp11_setObjectApplicationAttribute(ICSFP11_HANDLE_T *in_object_handle, + const unsigned char* in_attribute_value, int in_value_len, + int *out_rc, int *out_reason) +{ + int sts = 0; + int num_attrs = 1; + CK_ATTRIBUTE object_attrs[1] = { + { CKA_APPLICATION, NULL, 0 } + }; + char* serialized_attrlist = NULL; + int serialized_attrlist_len = 0; + + int exit_data_len = 0; + int rule_array_count = 0; + + object_attrs[0].pValue = (char *)in_attribute_value; + object_attrs[0].ulValueLen = (CK_ULONG) in_value_len; + + do { + sts = serialize_attribute_list(num_attrs, object_attrs, &serialized_attrlist, &serialized_attrlist_len); + if (0 != sts) { + break; + } + + #ifdef _LP64 + CSFPSAV6( + #else + CSFPSAV( + #endif + out_rc, out_reason, + &exit_data_len, NULL, /* exit data length (should be zero), exit data (ignored) */ + (unsigned char*)(void *) in_object_handle, + &rule_array_count, NULL, /* rule array count, rule array (ignored) */ + &serialized_attrlist_len, + serialized_attrlist); + + if (8 <= *out_rc) { + sts = RSCRYPTO_CALLABLE_SERVICE_ERROR; + } + + } while(0); + + return sts; +} + +int rs_icsfp11_getObjectApplicationAttribute(ICSFP11_HANDLE_T *in_object_handle, + unsigned char* out_attribute_value, int* out_value_len, + int *out_rc, int *out_reason) +{ + int sts = 0; + + CK_ATTRIBUTE *object_attrs = NULL; + int num_attrs = 0; + int didFindApplicationAttribute = 0; + +#define ICSFP11_ATTRIBUTE_LIST_MAXLEN 32752 + char serialized_attrlist[ICSFP11_ATTRIBUTE_LIST_MAXLEN] = {0}; + int serialized_attrlist_len = ICSFP11_ATTRIBUTE_LIST_MAXLEN; + + int exit_data_len = 0; + int rule_array_count = 0; + + do { + +#ifdef _LP64 + CSFPGAV6( +#else + CSFPGAV( +#endif + out_rc, out_reason, + &exit_data_len, NULL, /* exit data length (should be zero), exit data (ignored) */ + (unsigned char*)(void *) in_object_handle, + &rule_array_count, NULL, /* rule array count, rule array (ignored) */ + &serialized_attrlist_len, + serialized_attrlist); + + if (8 <= *out_rc) { + sts = RSCRYPTO_CALLABLE_SERVICE_ERROR; + break; + } + + sts = parse_attribute_list(serialized_attrlist, serialized_attrlist_len, &object_attrs, &num_attrs); + if (0 != sts) { + break; + } + + for (int i=0; i < num_attrs; i++) { + if (CKA_APPLICATION == object_attrs[i].type) { + didFindApplicationAttribute = 1; + if (*out_value_len < object_attrs[i].ulValueLen) { + sts = RSCRYPTO_INSUFFICIENT_OUTPUT_SPACE; + break; + } + memcpy(out_attribute_value, object_attrs[i].pValue, object_attrs[i].ulValueLen); + *out_value_len = object_attrs[i].ulValueLen; + break; + } + } + if (0 == didFindApplicationAttribute) { + sts = RSCRYPTO_APPATTR_NOT_FOUND; + break; + } + + } while(0); + + if (NULL != object_attrs) { + memset(object_attrs, 0x00, num_attrs * sizeof(CK_ATTRIBUTE)); + rscFree(object_attrs, num_attrs * sizeof(CK_ATTRIBUTE)); + } + + memset(serialized_attrlist, 0x00, ICSFP11_ATTRIBUTE_LIST_MAXLEN); + return sts; +} + +int rs_icsfp11_getObjectValue(const ICSFP11_HANDLE_T *in_object_handle, + unsigned char* out_value, int* out_value_len, + int *out_rc, int *out_reason) +{ + int sts = 0; + + CK_ATTRIBUTE *object_attrs = NULL; + int num_attrs = 0; + int didFindValueAttribute = 0; + + char serialized_attrlist[ICSFP11_ATTRIBUTE_LIST_MAXLEN] = {0}; + int serialized_attrlist_len = ICSFP11_ATTRIBUTE_LIST_MAXLEN; + + int exit_data_len = 0; + int rule_array_count = 0; + + do { + +#ifdef _LP64 + CSFPGAV6( +#else + CSFPGAV( +#endif + out_rc, out_reason, + &exit_data_len, NULL, /* exit data length (should be zero), exit data (ignored) */ + (unsigned char*) in_object_handle, + &rule_array_count, NULL, /* rule array count, rule array (ignored) */ + &serialized_attrlist_len, + serialized_attrlist); + + if (8 <= *out_rc) { + sts = RSCRYPTO_CALLABLE_SERVICE_ERROR; + break; + } + + sts = parse_attribute_list(serialized_attrlist, serialized_attrlist_len, &object_attrs, &num_attrs); + if (0 != sts) { + break; + } + + for (int i=0; i < num_attrs; i++) { + if (CKA_VALUE == object_attrs[i].type) { + didFindValueAttribute = 1; + if (*out_value_len < object_attrs[i].ulValueLen) { + sts = RSCRYPTO_INSUFFICIENT_OUTPUT_SPACE; + break; + } + memcpy(out_value, object_attrs[i].pValue, object_attrs[i].ulValueLen); + *out_value_len = object_attrs[i].ulValueLen; + break; + } + } + if (0 == didFindValueAttribute) { + sts = RSCRYPTO_APPATTR_NOT_FOUND; + break; + } + + } while(0); + + if (NULL != object_attrs) { + memset(object_attrs, 0x00, num_attrs * sizeof(CK_ATTRIBUTE)); + rscFree(object_attrs, num_attrs * sizeof(CK_ATTRIBUTE)); + } + + memset(serialized_attrlist, 0x00, ICSFP11_ATTRIBUTE_LIST_MAXLEN); + return sts; +} + +int rs_icsfp11_deleteTokenByHandle(const ICSFP11_HANDLE_T *in_handle, + int *out_rc, int* out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int rule_array_count = 1; + +#ifdef _LP64 + CSFPTRD6( +#else + CSFPTRD( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + (unsigned char*)in_handle, + &rule_array_count, + (unsigned char*)RS_TOKEN_KEYWORD); + + if (8 <= *out_rc) { + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + } + + return status; +} + +int rs_icsfp11_deleteTokenByName(const char *in_name, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + ICSFP11_HANDLE_T token_handle = ICSFP11_HANDLE_INITIALIZER; + int namelen = 0; + + do { + if (NULL == in_name) { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + namelen = strlen(in_name); + if (32 < namelen) { + status = RSCRYPTO_INVALID_IDENTIFIER_LENGTH; + break; + } + memcpy(&(token_handle.tokenName[0]), in_name, namelen); + status = rs_icsfp11_deleteTokenByHandle(&token_handle, out_rc, out_reason); + + } while(0); + + return status; +} + +int rs_icsfp11_findToken(const char *in_token_name, + ICSFP11_HANDLE_T **out_handle, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int attr_list_len = 0; + int rule_array_count = 1; + int output_list_length; + char* output_list = NULL; + char* readhead = NULL; + + int handle_count; + + ICSFP11_HANDLE_T lasthandle = ICSFP11_HANDLE_INITIALIZER; + int foundToken = 0; + + do { + if ((NULL == in_token_name) || + (NULL == out_handle) || + (NULL == out_rc) || + (NULL == out_reason)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + int namelen = strlen(in_token_name); + if (32 < namelen) { + status = RSCRYPTO_INVALID_IDENTIFIER_LENGTH; + break; + } + +#define ICSFP11_FINDTOKEN_RECORDS_PER_ITERATION 16 + output_list_length = ICSFP11_FINDTOKEN_RECORDS_PER_ITERATION * sizeof(ICSFP11_TOKEN_RECORD_T); + output_list = (char*)rscAlloc(output_list_length, "token handle output list"); + + do { +#ifdef DEBUG + printf("findToken iteration\n"); +#endif + + handle_count = ICSFP11_FINDTOKEN_RECORDS_PER_ITERATION; + +#ifdef DEBUG + printf("lasthandle:\n"); + dumpbuffer((char*)&lasthandle, sizeof(ICSFP11_HANDLE_T)); +#endif + + /* use the Token Record List service to get the next batch of token infos */ +#ifdef _LP64 + CSFPTRL6 ( +#else + CSFPTRL ( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + (unsigned char*)&lasthandle, + &rule_array_count, + (unsigned char*)RS_TOKEN_KEYWORD, + &attr_list_len, /* zero search template length */ + NULL, /* no search template */ + &output_list_length, + &handle_count, + (unsigned char*)output_list); + #ifdef DEBUG + printf("CSFPTRL rc=%d, rsn=0x%x, hc=%d, oll=%d, ol:\n", + *out_rc, *out_reason, handle_count, output_list_length); + dumpbuffer(output_list, output_list_length); + #endif + + if (8 <= *out_rc) { + *out_handle = NULL; + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + break; + } + + readhead = output_list; + ICSFP11_TOKEN_RECORD_T *tmpRecord = NULL; + + for (int i=0; i < handle_count; i++) { + tmpRecord = (ICSFP11_TOKEN_RECORD_T *)(void *) readhead; +#ifdef DEBUG + printf("tmpRecord:\n"); + dumpbuffer((char*)tmpRecord, sizeof(ICSFP11_TOKEN_RECORD_T)); +#endif + if (0 == strncmp(&(tmpRecord->label[0]), in_token_name, namelen)) { + foundToken = 1; + *out_handle = (ICSFP11_HANDLE_T*) rscAlloc(sizeof(ICSFP11_HANDLE_T), "output handle"); + memcpy(&((*out_handle)->tokenName[0]), &(tmpRecord->label[0]), sizeof(tmpRecord->label)); + break; + } + readhead += sizeof(ICSFP11_TOKEN_RECORD_T); + } + + if (0 == foundToken) { /* prepare to iterate */ + memcpy(&(lasthandle.tokenName[0]), &(tmpRecord->label[0]), sizeof(tmpRecord->label)); + output_list_length = ICSFP11_FINDTOKEN_RECORDS_PER_ITERATION * sizeof(ICSFP11_TOKEN_RECORD_T); + memset(output_list, 0x00, output_list_length); + } + + } while ((0 == foundToken) && + (4 == *out_rc) && (0xBC9 == *out_reason)); /* there are more results available */ + + } while(0); + + if (output_list) { + rscFree(output_list, ICSFP11_FINDTOKEN_RECORDS_PER_ITERATION * sizeof(ICSFP11_TOKEN_RECORD_T)); + } + + if (foundToken) { /* we might have been in 'more data available' state, of no interest to caller */ + *out_rc = 0; + *out_reason = 0; + } else { + status = RS_PKCS11_TOKEN_NOTFOUND; + } + + return status; +} + +int rs_icsfp11_createToken(const char *in_name, + ICSFP11_TOKENATTRS_T *in_tokenattrs, + ICSFP11_HANDLE_T **out_handle, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int rule_array_count = 1; + + int attr_list_len = sizeof(ICSFP11_TOKENATTRS_T); + + ICSFP11_HANDLE_T inout_handle = ICSFP11_HANDLE_INITIALIZER; + ICSFP11_HANDLE_T* newhandle = NULL; + int namelen = 0; + + do { + if ((NULL == in_name) || + (NULL == out_handle) || + (NULL == out_rc) || (NULL == out_reason)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + namelen = strlen(in_name); + if (32 < namelen) { + status = RSCRYPTO_INVALID_IDENTIFIER_LENGTH; + break; + } + memcpy(&(inout_handle.tokenName[0]), in_name, namelen); + +#ifdef _LP64 + CSFPTRC6( +#else + CSFPTRC( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + (unsigned char*)&inout_handle, + &rule_array_count, + (unsigned char*)RS_TOKEN_KEYWORD, + &attr_list_len, + (unsigned char*)in_tokenattrs); + + if (8 <= *out_rc) { + *out_handle = NULL; + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + break; + } + + newhandle = (ICSFP11_HANDLE_T*)rscAlloc(sizeof(ICSFP11_HANDLE_T), "token handle"); + memcpy(newhandle, &inout_handle, sizeof(ICSFP11_HANDLE_T)); + *out_handle = newhandle; + + } while(0); + + return status; +} + +int rs_icsfp11_hmacSHA1(const ICSFP11_HANDLE_T *in_key_handle, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason) +{ + return rs_icsfp11_hmacSHA_internal(in_key_handle, + ICSFP11_SHA1, + in_cleartext, in_cleartext_len, + out_hmac, out_hmac_len, + out_rc, out_reason); +} + +int rs_icsfp11_hmacSHA256(const ICSFP11_HANDLE_T *in_key_handle, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason) +{ + return rs_icsfp11_hmacSHA_internal(in_key_handle, + ICSFP11_SHA256, + in_cleartext, in_cleartext_len, + out_hmac, out_hmac_len, + out_rc, out_reason); +} + +int rs_icsfp11_hmacSHA384(const ICSFP11_HANDLE_T *in_key_handle, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason) +{ + return rs_icsfp11_hmacSHA_internal(in_key_handle, + ICSFP11_SHA384, + in_cleartext, in_cleartext_len, + out_hmac, out_hmac_len, + out_rc, out_reason); +} + +int rs_icsfp11_hmacSHA512(const ICSFP11_HANDLE_T *in_key_handle, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason) +{ + return rs_icsfp11_hmacSHA_internal(in_key_handle, + ICSFP11_SHA512, + in_cleartext, in_cleartext_len, + out_hmac, out_hmac_len, + out_rc, out_reason); +} + +int rs_icsfp11_RS256_sign(const ICSFP11_HANDLE_T *in_key_handle, /* RSA privkey handle */ + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_sig, int *out_sig_len, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int rule_array_count = 2; + char rule_array[16] = {'S','H','A','-','2','5','6',' ', + 'S','I','G','N','-','R','S','A'}; + int alet = 0; + unsigned char chain_data[128] = {0}; + int chain_data_len = sizeof(chain_data); + +#ifdef _LP64 + CSFPOWH6( +#else + CSFPOWH( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + &rule_array_count, + (unsigned char*)rule_array, + &in_cleartext_len, + (unsigned char *)in_cleartext, + &alet, + &chain_data_len, + chain_data, + (unsigned char*)in_key_handle, + out_sig_len, + out_sig); + if (8 <= *out_rc) { + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + } + + return status; +} + +int rs_icsfp11_RS256_verify(const ICSFP11_HANDLE_T *in_key_handle, /* RSA pubkey handle */ + const unsigned char* in_cleartext, int in_cleartext_len, + const unsigned char* in_sig, int in_sig_len, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int rule_array_count = 2; + char rule_array[16] = {'S','H','A','-','2','5','6',' ', + 'V','E','R','-','R','S','A',' '}; + int alet = 0; + unsigned char chain_data[128] = {0}; + int chain_data_len = sizeof(chain_data); + +#ifdef _LP64 + CSFPOWH6( +#else + CSFPOWH( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + &rule_array_count, + (unsigned char*)rule_array, + &in_cleartext_len, + (unsigned char *)in_cleartext, + &alet, + &chain_data_len, + chain_data, + (unsigned char*)in_key_handle, + &in_sig_len, + (unsigned char *)in_sig); + + if (8 <= *out_rc) { + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + } + + return status; +} + +static int rs_icsfp11_hmacSHA_internal( + const ICSFP11_HANDLE_T *in_key_handle, + ICSFP11_DIGEST_ALG in_alg, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int rule_array_count = 2; + char rule_array[16] = {0}; + unsigned char* writehead = NULL; + int alet = 0; + unsigned char chain_data[128] = {0}; + int chain_data_len = sizeof(chain_data); + int required_outsize = 0; + + do { + if ((NULL == in_key_handle) || + (NULL == in_cleartext) || + (NULL == out_hmac) || (NULL == out_hmac_len) || + (NULL == out_rc) || (NULL == out_reason)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + writehead = (unsigned char*) &(rule_array[0]); + switch(in_alg) { + case ICSFP11_SHA1: + required_outsize = ICSFP11_SHA1_HASHLEN; + memcpy(writehead, &(RS_SHA1_KEYWORD[0]), 8); + writehead += 8; + break; + case ICSFP11_SHA256: + required_outsize = ICSFP11_SHA256_HASHLEN; + memcpy(writehead, &(RS_SHA256_KEYWORD[0]), 8); + writehead += 8; + break; + case ICSFP11_SHA384: + required_outsize = ICSFP11_SHA384_HASHLEN; + memcpy(writehead, &(RS_SHA384_KEYWORD[0]), 8); + writehead += 8; + break; + case ICSFP11_SHA512: + required_outsize = ICSFP11_SHA512_HASHLEN; + memcpy(writehead, &(RS_SHA512_KEYWORD[0]), 8); + writehead += 8; + break; + default: + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + if (RS_SUCCESS != status) + break; + + if (required_outsize > *out_hmac_len) { + status = RSCRYPTO_INSUFFICIENT_OUTPUT_SPACE; + break; + } + + memcpy(writehead, &(RS_ONLY_KEYWORD[0]), 8); + writehead += 8; + +#ifdef DEBUG + printf("rs_icsfp11_hmacSHA_internal: Before HMAC Generate rc=%d, reason=%d, out_hmac_len=%d\n", + *out_rc, *out_reason, *out_hmac_len); + printf("in_cleartext:\n"); + dumpbuffer(in_cleartext, in_cleartext_len); +#endif + +#ifdef _LP64 + CSFPHMG6( +#else + CSFPHMG( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + &rule_array_count, + (unsigned char*) rule_array, + &in_cleartext_len, + (unsigned char *)in_cleartext, + &alet, + &chain_data_len, + chain_data, + (unsigned char*)in_key_handle, + out_hmac_len, + out_hmac); + +#ifdef DEBUG + printf("rs_icsfp11_hmacSHA_internal: After HMAC Generate service: rc=%d, reason=0x%x, out_hmac_len=%d\n", + *out_rc, *out_reason, *out_hmac_len); + printf("out_hmac:\n"); + dumpbuffer(out_hmac, *out_hmac_len); +#endif + + if (8 <= *out_rc) { + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + break; + } + + } while(0); + + return status; +} + +static int rs_icsfp11_findObjects_internal ( + const ICSFP11_HANDLE_T *in_token_handle, + int in_numattrs, const CK_ATTRIBUTE *in_attrs, + ICSFP11_HANDLE_T **out_handles, + int *out_numfound, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int rule_array_count = 1; + unsigned char* output_list = NULL; + int output_list_length; + int handle_count; + + unsigned char* attrlist = NULL; + int attrlistlen = 0; + + ICSFP11_HANDLE_T inout_handle = ICSFP11_HANDLE_INITIALIZER; + + do { + if ((NULL == in_token_handle) || + (NULL == in_attrs) || + (NULL == out_handles) || + (NULL == out_rc) || + (NULL == out_reason)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + memcpy(&(inout_handle.tokenName[0]), &(in_token_handle->tokenName[0]), 32); + + status = serialize_attribute_list(in_numattrs, in_attrs, + &attrlist, &attrlistlen); + if (RS_SUCCESS != status) + break; + +#ifdef DEBUG + printf("Serialized attribute list:\n"); + dumpbuffer(attrlist, attrlistlen); +#endif + +#define ICSFP11_MAX_FOUND_OBJECTS 10 + output_list_length = ICSFP11_MAX_FOUND_OBJECTS * sizeof(ICSFP11_HANDLE_T); + output_list = (unsigned char*)rscAlloc(output_list_length, "object handles output"); + handle_count = ICSFP11_MAX_FOUND_OBJECTS; + + /* use the Token Record List service to get the accessible token handles */ +#ifdef _LP64 + CSFPTRL6 ( +#else + CSFPTRL ( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + (unsigned char*) &inout_handle, + &rule_array_count, + (unsigned char*)RS_OBJECT_KEYWORD, + &attrlistlen, /* search template length */ + attrlist, /* search template */ + &output_list_length, + &handle_count, + output_list); + + if (8 <= *out_rc) { + *out_handles = NULL; + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + break; + } + + if (0 < handle_count) { + *out_handles = (ICSFP11_HANDLE_T*)rscAlloc(handle_count * sizeof(ICSFP11_HANDLE_T), "returned object handles"); + memcpy(*out_handles, output_list, handle_count * sizeof(ICSFP11_HANDLE_T)); + } + *out_numfound = handle_count; + + } while(0); + + if (attrlist) { + rscFree(attrlist, attrlistlen); + } + + if (output_list) { + rscFree(output_list, ICSFP11_MAX_FOUND_OBJECTS * sizeof(ICSFP11_HANDLE_T)); + } + + return status; +} + +static int rs_icsfp11_createObject_internal(const ICSFP11_HANDLE_T *in_token_handle, + int in_numattrs, const CK_ATTRIBUTE *in_attrs, + ICSFP11_HANDLE_T **out_obj_handle, + int *out_rc, int *out_reason) +{ + int status = RS_SUCCESS; + + int exit_data_len = 0; + int rule_array_count = 1; + + unsigned char* attrlist = NULL; + int attrlistlen = 0; + + ICSFP11_HANDLE_T inout_handle = ICSFP11_HANDLE_INITIALIZER; + ICSFP11_HANDLE_T *key_handle = NULL; + + do { + if ((NULL == in_token_handle) || + (NULL == in_attrs) || + (NULL == out_obj_handle) || + (NULL == out_rc) || + (NULL == out_reason)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + memcpy(&(inout_handle.tokenName[0]), &(in_token_handle->tokenName[0]), 32); + + status = serialize_attribute_list(in_numattrs, in_attrs, + &attrlist, &attrlistlen); + if (RS_SUCCESS != status) + break; + +#ifdef DEBUG + printf("Serialized attribute list:\n"); + dumpbuffer(attrlist, attrlistlen); +#endif + +#ifdef _LP64 + CSFPTRC6( +#else + CSFPTRC( +#endif + out_rc, + out_reason, + &exit_data_len, + NULL, /* no exit data */ + (unsigned char*) &inout_handle, + &rule_array_count, + (unsigned char*) RS_OBJECT_KEYWORD, + &attrlistlen, + attrlist); + + if (8 <= *out_rc) { + *out_obj_handle = NULL; + status = RSCRYPTO_CALLABLE_SERVICE_ERROR; + break; + } + + key_handle = (ICSFP11_HANDLE_T *)rscAlloc(sizeof(ICSFP11_HANDLE_T), "key handle"); + memcpy(key_handle, &inout_handle, sizeof(ICSFP11_HANDLE_T)); + *out_obj_handle = key_handle; + + } while(0); + + if (attrlist) { + rscFree(attrlist, attrlistlen); + } + + return status; +} +/** + * Allocate and return a serialized Attribute List based on the + * supplied array of CK_ATTRIBUTEs. + */ +static int serialize_attribute_list(int num_attrs, + const CK_ATTRIBUTE *attr_array, + unsigned char **out_attrlist_buf, + int *out_attrlist_len) +{ + int status = RS_SUCCESS; + + unsigned char *listbuf = NULL; + int listlen = 0; + + unsigned char* writehead = NULL; + unsigned short tmpshort = 0; + unsigned int tmpint = 0; + + int i; + + do { + /* try to support zero-attribute Attribute List */ + if ((NULL == out_attrlist_buf) || + (NULL == out_attrlist_len)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + if ((0 < num_attrs) && (NULL == attr_array)) + { + status = RSCRYPTO_INVALID_ARGUMENT; + break; + } + + listlen += 2; /* number of attributes in list */ + /* calculate the attrs required length */ + for (i=0; i < num_attrs; i++) { + listlen += (4 + 2 + attr_array[i].ulValueLen); + } + + listbuf = (unsigned char*) rscAlloc(listlen, "attribute list"); + if (NULL == listbuf) { + status = RSCRYPTO_ALLOC_FAILED; + break; + } + writehead = listbuf; + + tmpshort = (unsigned short) num_attrs; + memcpy(writehead, &tmpshort, sizeof(unsigned short)); + writehead += sizeof(unsigned short); + + /* each attribute is structure consisting of: + * attr_name (4 bytes), value_len (2 bytes), value (len bytes) */ + for (i=0; i < num_attrs; i++) + { + tmpint = (unsigned int) attr_array[i].type; + memcpy(writehead, &tmpint, sizeof(unsigned int)); + writehead += sizeof(unsigned int); + + tmpshort = (unsigned short) attr_array[i].ulValueLen; + memcpy(writehead, &tmpshort, sizeof(unsigned short)); + writehead += sizeof(unsigned short); + + memcpy(writehead, attr_array[i].pValue, attr_array[i].ulValueLen); + writehead += attr_array[i].ulValueLen; + + tmpint = 0; + tmpshort = 0; + } + + *out_attrlist_buf = listbuf; + *out_attrlist_len = listlen; + + } while(0); + + return status; +} + +/* allocates new CK_ATTRIBUTE structures, but those structures point into the supplied serialized_attrlist buffer! */ +static int parse_attribute_list(const unsigned char* in_serialized_attrlist, + int in_serialized_attrlist_len, + CK_ATTRIBUTE** out_attrs, int* out_num_attrs) +{ + int sts = 0; + const unsigned char* readhead = in_serialized_attrlist; + int bytes_remaining = in_serialized_attrlist_len; + + CK_ATTRIBUTE* attrs = NULL; + unsigned short num_attrs = 0; + + do { + if ((NULL == in_serialized_attrlist) || (0 == in_serialized_attrlist_len) || + (NULL == out_attrs) || (NULL == out_num_attrs)) + { + sts = RSCRYPTO_INVALID_ARGUMENT; + break; + } +#ifdef DEBUG + printf("starting read at address 0x%p, remaining: %d\n", readhead, bytes_remaining); +#endif + if (sizeof(unsigned short) <= bytes_remaining) { +#ifdef DEBUG + printf("reading %d bytes from address 0x%p, remaining: %d\n", sizeof(unsigned short), readhead, bytes_remaining); +#endif + num_attrs = *((unsigned short *)readhead); + readhead += sizeof(unsigned short); + bytes_remaining -= sizeof(unsigned short); + } else { + sts = RSCRYPTO_ATTRLIST_PARSE_ERROR; + break; + } + + if (0 < num_attrs) { + attrs = (CK_ATTRIBUTE*) rscAlloc(num_attrs * sizeof(CK_ATTRIBUTE), "attrs"); + for (int i=0; + (i < num_attrs) && (0 < bytes_remaining); + i++) + { + uint32 tmpType = 0; + unsigned short tmpAttrLen = 0; + + if (sizeof(uint32) < bytes_remaining) { +#ifdef DEBUG + printf("reading %d bytes from address 0x%p, remaining: %d\n", sizeof(uint32), readhead, bytes_remaining); +#endif + tmpType = *((uint32 *)readhead); + readhead += sizeof(uint32); + bytes_remaining -= sizeof(uint32); + } else { + sts = RSCRYPTO_ATTRLIST_PARSE_ERROR; + break; + } + + if (sizeof(unsigned short) <= bytes_remaining) { +#ifdef DEBUG + printf("reading %d bytes from address 0x%p, remaining: %d\n", sizeof(unsigned short), readhead, bytes_remaining); +#endif + tmpAttrLen = *((unsigned short *)readhead); + readhead += sizeof(unsigned short); + bytes_remaining -= sizeof(unsigned short); + } else { + sts = RSCRYPTO_ATTRLIST_PARSE_ERROR; + break; + } + + if (tmpAttrLen <= bytes_remaining) { +#ifdef DEBUG + printf("setting attr[%d] with type 0x%x and len %d\n", i, tmpType, (int)tmpAttrLen); +#endif + attrs[i].type = tmpType; + attrs[i].pValue = (CK_VOID_PTR) readhead; + attrs[i].ulValueLen = (CK_ULONG) tmpAttrLen; +#ifdef DEBUG + printf("seeking ahead %d bytes from address 0x%p, remaining: %d\n", tmpAttrLen, readhead, bytes_remaining); +#endif + readhead += tmpAttrLen; + bytes_remaining -= tmpAttrLen; + } else { + sts = RSCRYPTO_ATTRLIST_PARSE_ERROR; + break; + } + } + } +#ifdef DEBUG + printf("after parsing serialized attribute list, bytes_remaining = %d\n", bytes_remaining); + printf("num_attrs: %d\n", num_attrs); + printf("attrs contents follow:\n"); + dumpbuffer((char*)attrs, num_attrs * sizeof(CK_ATTRIBUTE)); +#endif + + if (0 != sts) { + if (attrs) { + memset(attrs, 0x00, num_attrs * sizeof(CK_ATTRIBUTE)); + rscFree(attrs, num_attrs * sizeof(CK_ATTRIBUTE)); + } + break; + } + + *out_attrs = attrs; + *out_num_attrs = (int) num_attrs; + + } while(0); + + return sts; +} + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/jwt/rscrypto/rs_icsfp11.h b/jwt/rscrypto/rs_icsfp11.h new file mode 100644 index 000000000..532a8f6db --- /dev/null +++ b/jwt/rscrypto/rs_icsfp11.h @@ -0,0 +1,255 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef RS_ICSFP11_H_ +#define RS_ICSFP11_H_ + +#include +#include + +typedef struct RS_ICSFP11_HANDLE_tag { + char tokenName[32]; + char sequenceNumber[8]; + char id[4]; +} ICSFP11_HANDLE_T; + +static const ICSFP11_HANDLE_T ICSFP11_HANDLE_INITIALIZER = { + {' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' '}, /* 32 blanks */ + {' ',' ',' ',' ',' ',' ',' ',' '}, /* 8 blanks */ + {' ',' ',' ',' '} /* 4 blanks */ + }; + +typedef struct RS_ICSFP11_TOKEN_ATTRS_tag { + CK_UTF8CHAR manufacturer[32]; /* blank padded */ + CK_UTF8CHAR model[16]; /* blank padded */ + CK_CHAR serial[16]; /* blank padded */ + CK_CHAR reserved[4]; /* must be hex zeroes */ +} ICSFP11_TOKENATTRS_T; + +static const ICSFP11_TOKENATTRS_T ICSFP11_TOKENATTRS_INITIALIZER = { + {' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' '}, /* 32 blanks */ + {' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' '}, /* 16 blanks */ + {' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' '}, /* 16 blanks */ + {0x00, 0x00, 0x00, 0x00} /* 4 hex zeroes */ + }; + + +typedef struct RS_ICSFP11_ENVIRONMENT_tag { + + /* CSFIQF2[6] output, byte 10, bit 2 */ + int p11SecureKeyAvailable; + + /* CSFIQF[6] ICSFSP11 keyword outputs */ + int p11MasterKeyActive; + int fipsEnforcementMode; /* 0 - none, 1 - FIPS compat, 2 - FIPS mode */ + + /* CSFIQF[6] STATP11 keywork outputs */ + //int p11NMKState; /* 1 - clear, 2 - uncommitted, 3 - committed */ + //int p11CMKState; /* 1 - clear, 2 - contains a key */ + //int complianceMode; /* 8-byte hex digit sum of 1, 2, 4, 8: FIPS'09,BSI'09,FIPS'11,BSI'11 respectively */ + //int firmwareVersion; /* 8-byte hex value */ + //int serialNumber; /* factory-assigned serial number of the coprocessor */ + + /* information gleaned from Token Record List service */ + int numTokensAccessible; + ICSFP11_HANDLE_T *tokensHandlesArray; + +} ICSFP11_ENV_T; + +typedef enum ICSFP11_DIGEST_ALG_tag { + ICSFP11_ALG_INVALID=0, + ICSFP11_SHA1=1, + ICSFP11_SHA256=2, + ICSFP11_SHA384=3, + ICSFP11_SHA512=4 +} ICSFP11_DIGEST_ALG; + +#define ICSFP11_SHA1_HASHLEN 20 +#define ICSFP11_SHA256_HASHLEN 32 +#define ICSFP11_SHA384_HASHLEN 48 +#define ICSFP11_SHA512_HASHLEN 64 + +/** + * Use the ICSF Query Facilities and Token Record List callable service to + * get a holistic view of the ICSF PKCS#11 Environment. What special + * functions are available, as well as accessible virtual tokens. + */ +int rs_icsfp11_getEnvironment(ICSFP11_ENV_T **out_env, + int *out_rc, int *out_reason); + +void rs_icsfp11_envDescribe(const ICSFP11_ENV_T *in_env); +void rs_icsfp11_envDestroy(const ICSFP11_ENV_T *in_env); + +/** + * Generate the requested number of random bytes using the PRNG method, + * and copy them to the caller-supplied buffer. + */ +int rs_icsfp11_getRandomBytes(const ICSFP11_HANDLE_T *token_handle, + unsigned char *randbuf, int *randbuf_len, + int *out_rc, int *out_reason); + +int rs_icsfp11_createToken(const char *in_name, + ICSFP11_TOKENATTRS_T *in_tokenattrs, + ICSFP11_HANDLE_T **out_handle, + int *out_rc, int *out_reason); + +/** + * If the token with the specified name exists, and the current user has access it, + * return a handle to it. + */ +int rs_icsfp11_findToken(const char *in_token_name, + ICSFP11_HANDLE_T **out_handle, + int *out_rc, int *out_reason); + +/** + * rs_icsfp11_findObjectsByLabel + * rs_icsfp11_findObjectsByLabelAndClass + * + * Get token object handles (e.g. the handle to a key) using + * a search label (and optionally, an app name). + * + * The expected / hoped-for output value for num_found is 1, but + * could be as many as 10. If the calling application expect there + * to be exactly one object in the token for the given label, but + * a value greater than 1 is returned in numfound, that's a condition + * worth noting. + * + * The size of the buffer behind out_handles (if numfound > 0) will + * always be numfound * sizeof(ICSFP11_HANDLE_T). This buffer is + * allocated inside the call and should be freed by the caller. + * + * The rs_icsfp11_findObjectsByLabelAndClass can be used to tighten + * the search scope by "object class." This is particularly useful + * in signing/verification use cases where gskkyman was used to + * import certificates or cryptographic identities to the PKCS#11 + * token, resulting in multiple token objects with the same label + * but different classes. Expected in_objectClass values include: + * CKO_DATA + * CKO_CERTIFICATE + * CKO_PUBLIC_KEY + * CKO_PRIVATE_KEY + * CKO_SECRET_KEY + * These values are defined in csnpdefs.h + */ +int rs_icsfp11_findObjectsByLabel( + const ICSFP11_HANDLE_T *in_token_handle, + const char *in_keylabel, + const char *in_appname, + ICSFP11_HANDLE_T **out_handles, + int *out_numfound, + int *out_rc, int *out_reason); + +/* If you don't know the desired objectClass, use rs_icsfp11_findObjectsByLabel. */ +int rs_icsfp11_findObjectsByLabelAndClass( + const ICSFP11_HANDLE_T *in_token_handle, + const char *in_label, + CK_ULONG in_objectClass, + const char *in_appname, + ICSFP11_HANDLE_T **out_handles, + int *out_numfound, + int *out_rc, int *out_reason); + +/** + * Delete an object using its unique handle. + */ +int rs_icsfp11_deleteObject(const ICSFP11_HANDLE_T *in_object_handle, + int *out_rc, int *out_reason); + +/** + * Set or retrieve data from an object's CKA_APPLICATION attribute. + * In practice, set only works on CKO_DATA objects because other objects only allow + * the CKA_APPLICATION attribute to be set at create/generate time. + */ +int rs_icsfp11_setObjectApplicationAttribute(const ICSFP11_HANDLE_T *in_object_handle, + const unsigned char* in_attribute_value, + int in_value_len, + int *out_rc, int *out_reason); + +int rs_icsfp11_getObjectApplicationAttribute(const ICSFP11_HANDLE_T *in_object_handle, + unsigned char* out_attribute_value, + int* out_value_len, + int *out_rc, int *out_reason); + +int rs_icsfp11_getObjectValue(const ICSFP11_HANDLE_T *in_object_handle, + unsigned char* out_value, int* out_value_len, + int *out_rc, int *out_reason); + +/** + * Create a token by name (max 32 chars). + */ +int rs_icsfp11_createToken(const char *in_name, + const ICSFP11_TOKENATTRS_T *in_tokenattrs, + ICSFP11_HANDLE_T **out_handle, + int *out_rc, int *out_reason); + +/** + * Delete a token by handle, or by name. + */ +int rs_icsfp11_deleteTokenByHandle(const ICSFP11_HANDLE_T *in_handle, + int *out_rc, int* out_reason); + +int rs_icsfp11_deleteTokenByName(const char *in_name, + int *out_rc, int *out_reason); + +/** + * Compute HMACs + */ +int rs_icsfp11_hmacSHA1(const ICSFP11_HANDLE_T *in_key_handle, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason); + +int rs_icsfp11_hmacSHA256(const ICSFP11_HANDLE_T *in_key_handle, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason); + +int rs_icsfp11_hmacSHA384(const ICSFP11_HANDLE_T *in_key_handle, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason); + +int rs_icsfp11_hmacSHA512(const ICSFP11_HANDLE_T *in_key_handle, + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_hmac, int *out_hmac_len, + int *out_rc, int *out_reason); + +/** + * RS256 signatures and verification for JWT support + */ +int rs_icsfp11_RS256_sign(const ICSFP11_HANDLE_T *in_key_handle, /* RSA privkey handle */ + const unsigned char* in_cleartext, int in_cleartext_len, + unsigned char* out_sig, int *out_sig_len, + int *out_rc, int *out_reason); + +int rs_icsfp11_RS256_verify(const ICSFP11_HANDLE_T *in_key_handle, /* RSA pubkey handle */ + const unsigned char* in_cleartext, int in_cleartext_len, + const unsigned char* in_sig, int in_sig_len, + int *out_rc, int *out_reason); + +#endif /* RS_ICSFP11_H_ */ + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/jwt/rscrypto/rs_rsclibc.c b/jwt/rscrypto/rs_rsclibc.c new file mode 100644 index 000000000..f8423e024 --- /dev/null +++ b/jwt/rscrypto/rs_rsclibc.c @@ -0,0 +1,88 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#include "rs_rsclibc.h" + +#include +#include +#include +#include + + +/* LE mode */ + +unsigned long long rsclibc_currentSecondsSinceJan1970(void) +{ +#ifdef __ZOWE_OS_ZOS + return time64(NULL); +#else + return time(NULL); +#endif +} + +int rsclibc_currentSecondsAndMicrosSince1970(unsigned int *out_seconds, + unsigned int *out_micros) +{ +#ifdef DEBUG_FIXED_TIME_AND_RANDOM +*out_seconds = 1442599995; +*out_micros = 1234; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + *out_seconds = (unsigned int) (tv.tv_sec); + *out_micros = (unsigned int) (tv.tv_usec); +#endif + return 0; +} + +char *rscDuplicateString(const char *s){ + int len = (int) strlen(s); + char *copy = (char*)rscAlloc(len+1,"rscDuplicateString"); + memcpy(copy,s,len); + copy[len] = 0; + return copy; +} + +void *rscAlloc(size_t size, const char *label){ +#ifdef DEBUG + printf("RSCALLOC: %s, size=0x%x \n",label,(int)size); +#endif +#ifdef METTLE + void *data = safeMalloc(size, label); +#else + void *data = calloc(1, size); +#endif +#ifdef DEBUG + printf("RSCALLOC: yielded 0x%x\n",(int)data); +#endif + if (data == NULL){ + printf("*** WARNING *** failed alloc for label %s\n",label); + } + return data; +} + +void rscFree(void *data, size_t size){ + memset(data, 0x00, size); +#ifdef METTLE + safeFree(data, size); +#else + free(data); +#endif +} + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/jwt/rscrypto/rs_rsclibc.h b/jwt/rscrypto/rs_rsclibc.h new file mode 100644 index 000000000..f045980a5 --- /dev/null +++ b/jwt/rscrypto/rs_rsclibc.h @@ -0,0 +1,43 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef RS_rsclibc_H_ +#define RS_rsclibc_H_ + +#include "zowetypes.h" + +#include +#include +#include +#include + +#include "utils.h" + +unsigned long long rsclibc_currentSecondsSinceJan1970(void); +int rsclibc_currentSecondsAndMicrosSince1970(unsigned int *out_seconds, + unsigned int *out_micros); + +char *rscDuplicateString(const char *s); +void *rscAlloc(size_t size, const char *label); +void rscFree(void *data, size_t size); + + +#endif /* RS_rsclibc_H_ */ + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/jwt/tests/jwt-test.c b/jwt/tests/jwt-test.c new file mode 100644 index 000000000..8815c3309 --- /dev/null +++ b/jwt/tests/jwt-test.c @@ -0,0 +1,842 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef __IBM_METAL__ +#define _XOPEN_SOURCE 500 +#include +#include +#endif + +#include "zowetypes.h" +#include "charsets.h" +#include "json.h" +#include "utils.h" +#include "xlate.h" +#include "alloc.h" + +/* rscrypto */ +#include "rs_icsfp11.h" +#include "rs_crypto_errors.h" + +#include "jwt.h" +#include + +#ifdef JWT_DEBUG +#define DEBUG printf +#define DUMPBUF dumpbuffer +#else +#define DEBUG(...) (void)0 +#define DUMPBUF(...) (void)0 +#endif + +/* + the default example token from https://jwt.io/ + +{ + "alg": "HS256", + "typ": "JWT" +} +{ + "sub": "1234567890", + "name": "John Doe", + "iat": 1516239022 +} + +The HMAC key is Secret123 + +The RSA key is secsrv.p12: import using gskkyman, the password is "password": + + gskkyman -i -t ZOWE.ZSS.JWTKEYS -l KEY_RS256 -p secsrv.p12 + + */ + +const char TOKEN_NAME[] = "ZOWE.ZSS.JWTKEYS"; + +const char HMAC_KEY[] = {0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x31, 0x32, 0x33}; + +static void shouldParseNativeJwt(void) { + + printf("\n *** should Parse Native JWT\n"); + + static const char JWT_ALG_NONE[] = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_NONE, true, + slh, &parseRc); + assert(parseRc == RC_JWT_INSECURE); + assert(j != NULL); + + jwtContextDestroy(ctx); + + printf("subject '%s'\n", j->subject); + assert(strcmp(j->subject, "1234567890") == 0); + + printf("issued at '%lld'\n", j->issuedAt); + assert(j->issuedAt == 1516239022ll); + + Json *name = jwtGetCustomClaim(j, "name"); + if (name != NULL) { + printf("name %s\n", jsonAsString(name)); + } + assert(name != NULL); + assert(strcmp(jsonAsString(name), "John Doe") == 0); + + SLHFree(slh); +} + +static void shouldParseAsciiJWT(void) { + + printf("\n *** should Parse ASCII JWT\n"); + +#pragma convert("UTF8") + static const char JWT_ALG_NONE_ASCII[] = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"; +#pragma convert(pop) + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_NONE_ASCII, false, + slh, &parseRc); + assert(parseRc == RC_JWT_INSECURE); + assert(j != NULL); + + jwtContextDestroy(ctx); + + printf("subject '%s'\n", j->subject); + assert(strcmp(j->subject, "1234567890") == 0); + + printf("issued at '%lld'\n", j->issuedAt); + assert(j->issuedAt == 1516239022ll); + + Json *name = jwtGetCustomClaim(j, "name"); + if (name != NULL) { + printf("name %s\n", jsonAsString(name)); + } + assert(name != NULL); + assert(strcmp(jsonAsString(name), "John Doe") == 0); + + SLHFree(slh); +} + +static void shouldRejectMissingSignature(void) { + + printf("\n *** should reject missing signature\n"); + + static const char JWT_ALG_HS256[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_HS256, true, + slh, &parseRc); + + printf("rc %d\n", parseRc); + assert(parseRc == RC_JWT_MISSING_PART || parseRc == RC_JWT_INVALID_SIGLEN); + + jwtContextDestroy(ctx); + + + SLHFree(slh); +} + +static void shouldVerifyHS256(void) { + + printf("\n *** should verify HS256\n"); + + static const char JWT_ALG_HS256[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".iz6BHMT2SmuJCTvPFj9A1ZIrBqzk6TL3ff2Js1HIVDg"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_HS256, true, + slh, &parseRc); + assert(parseRc == 0); + assert(j != NULL); + + jwtContextDestroy(ctx); + + printf("subject '%s'\n", j->subject); + assert(strcmp(j->subject, "1234567890") == 0); + + SLHFree(slh); +} + +static void shouldRejectInvalidHS256(void) { + + printf("\n *** should reject invalid HS256\n"); + + static const char JWT_ALG_HS256[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".iz6CHMT2SmuJCTvPFj9A1ZIrBqzk6TL3ff2Js1HIVDg"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_HS256, true, + slh, &parseRc); + printf("rc %d\n", parseRc); + assert(parseRc == RC_JWT_SIG_MISMATCH); + + jwtContextDestroy(ctx); + + SLHFree(slh); +} + +static void shouldVerifyHS384(void) { + + printf("\n *** should verify HS384\n"); + + static const char JWT_ALG_HS384[] = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".aouHLlIOY8EJ9UBIBkA02XCJIN1gAi3KIYVotwAqtGq1xYuhcIeChxokNqahDVgI"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_HS384, true, + slh, &parseRc); + assert(parseRc == 0); + assert(j != NULL); + + jwtContextDestroy(ctx); + + printf("subject '%s'\n", j->subject); + assert(strcmp(j->subject, "1234567890") == 0); + + SLHFree(slh); +} + +static void shouldRejectInvalidHS384(void) { + + printf("\n *** should reject invalid HS384\n"); + + static const char JWT_ALG_HS384[] = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".aquHLlIOY8EJ9UBIBkA02XCJIN1gAi3KIYVotwAqtGq1xYuhcIeChxokNqahDVgI"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_HS384, true, + slh, &parseRc); + printf("rc %d\n", parseRc); + assert(parseRc == RC_JWT_SIG_MISMATCH); + + jwtContextDestroy(ctx); + + + SLHFree(slh); +} + +static void shouldVerifyHS512(void) { + printf("\n *** should verify HS512\n"); + + static const char JWT_ALG_HS512[] = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".LEaECa3B_W-ue8A_hHmn0BsdoaOKF4hILEOM-GaMWi8XRiDwBQXlOFI0V4wtRUw7dC_RLDD5pVk5rz8cZuQHhQ"; + + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_HS512, true, + slh, &parseRc); + assert(parseRc == 0); + assert(j != NULL); + + jwtContextDestroy(ctx); + + printf("subject '%s'\n", j->subject); + assert(strcmp(j->subject, "1234567890") == 0); + + SLHFree(slh); +} + +static void shouldRejectInvalidHS512(void) { + printf("\n *** should reject invalid HS512\n"); + + static const char JWT_ALG_HS512[] = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".LEaECa3B_Q-ue8A_hHmn0BsdoaOKF4hILEOM-GaMWi8XRiDwBQXlOFI0V4wtRUw7dC_RLDD5pVk5rz8cZuQHhQ"; + + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_HS512, true, + slh, &parseRc); + printf("rc %d\n", parseRc); + assert(parseRc == RC_JWT_SIG_MISMATCH); + + jwtContextDestroy(ctx); + + SLHFree(slh); +} + +static void shouldVerifyRS256(void) { + + printf("\n *** should verify RS256\n"); + + static const char JWT_ALG_RS256[] = "eyJhbGciOiJSUzI1NiJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".sgqwWTaLPWAySpIAR3kpJ39JBdc3Y9iGgUmyF3i0kfoBPS2IyzVAUIqY_ucJNfcRLZhKxq-" + "6ATZ6CKZNxZ-mmHvCBTlF6LWPDC3Jj7ysDjq00yDI_FEg8dMf0m8vaNSlRReLmlgyXCaGoo_" + "g495AHr2bLsSnNvHcNWEJplXQF_w"; + /*"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0" + ".POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS" + "_TuYI3OG85AmiExREkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH" + "3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0" + "Lka21H6XxUTxiy8OcaarA8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f" + "4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA";*/ + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_RS256", + CKO_PUBLIC_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_RS256, true, + slh, &parseRc); + assert(parseRc == 0); + assert(j != NULL); + + jwtContextDestroy(ctx); + + printf("subject '%s'\n", j->subject); + assert(strcmp(j->subject, "1234567890") == 0); + + SLHFree(slh); +} + +static void shouldRejectInvalidRS256(void) { + + printf("\n *** should reject invalid RS256\n"); + + static const char JWT_ALG_RS256[] = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0" + ".POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS" + "_TuYI3OG85AmiExREkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH" + "3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0" + "Lka21H6XxUTxiy8OcaarA8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f" + "5x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_RS256", + CKO_PUBLIC_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_ALG_RS256, true, + slh, &parseRc); + printf("rc %d\n", parseRc); + assert(parseRc == RC_JWT_SIG_MISMATCH || parseRc == RC_JWT_CRYPTO_ERROR); + + jwtContextDestroy(ctx); + + + SLHFree(slh); +} + +static void shouldEncodeASimpleJWT(void) { + + printf("\n *** should Encode A Simple JWT\n"); + + /* verified at jwt.io */ + static const char *const correctResult = "eyJhbGciOiJub25lIn0" + ".eyJpc3MiOiJGeW9kb3IiLCJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjoidW5pdCB0ZXN0Iiwi" + "ZXhwIjoxMjM0NTY3ODksIm5iZiI6OTg3NjU0MzIxMCwiaWF0Ijo5OTk5OTk5OTksImp0aSI6M" + "zMzMzMzMzMzfQ"; + + const Jwt j = { + .header = { + .algorithm = JWS_ALGORITHM_none, + }, + .issuer = "Fyodor", + .subject = "1234567890", + .audience = "unit test", + .expirationTime = 123456789llu, + .notBefore = 9876543210llu, + .issuedAt = 999999999llu, + .jwtId = 333333333lu + }; + ShortLivedHeap *slh; + int size; + char *encoded; + int rc; + + slh = makeShortLivedHeap(8192, 1024); + rc = jwtEncode(&j, true, NULL, slh, &size, &encoded); + assert(rc == 0); + + printf("encoded value: [%.*s]\n", size, encoded); + assert(strcmp(encoded, correctResult) == 0); + + SLHFree(slh); +} + +static void shouldSignWithRS256(void) { + + printf("\n *** should sign with RS256\n"); + + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_RS256", + CKO_PRIVATE_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + const Jwt jwt = { + .header = (JwsHeader) { + .algorithm = JWS_ALGORITHM_RS256 + }, + .subject = "1234567890", + .issuedAt = 1516239022llu + }; + int encodeRc; + int encodedSize; + char *token = jwtEncodeToken(ctx, &jwt, true, slh, &encodedSize, &encodeRc); + assert(encodeRc == 0); + assert(token != NULL); + //assert(strcmp(token, correctResult) == 0); + + printf("token: %s\n", token); + + jwtContextDestroy(ctx); + SLHFree(slh); +} + +static void shouldSignWithHS256(void) { + + printf("\n *** should sign with HS256\n"); + + /* verified at jwt.io */ + static const char *const correctResult = "eyJhbGciOiJIUzI1NiJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".865VU7SWfWv0GeHgtWXd6Drwxb4WKs-WB9ztO9PyDRs"; + + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + const Jwt jwt = { + .header = (JwsHeader) { + .algorithm = JWS_ALGORITHM_HS256 + }, + .subject = "1234567890", + .issuedAt = 1516239022llu + }; + int encodeRc; + int encodedSize; + char *token = jwtEncodeToken(ctx, &jwt, true, slh, &encodedSize, &encodeRc); + assert(encodeRc == 0); + assert(token != NULL); + + printf("token: %s\n", token); + assert(strcmp(token, correctResult) == 0); + + jwtContextDestroy(ctx); + SLHFree(slh); +} + +static void shouldSignWithHS384(void) { + + printf("\n *** should sign with HS384\n"); + + + /* verified at jwt.io */ + static const char *const correctResult = "eyJhbGciOiJIUzM4NCJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".o_-52tWowsL_hDd5XJXLklhhABKzl655iA0pcrzHtMHWdgP8RdnLFwX0yK-Q-7Ed"; + + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + const Jwt jwt = { + .header = (JwsHeader) { + .algorithm = JWS_ALGORITHM_HS384 + }, + .subject = "1234567890", + .issuedAt = 1516239022llu + }; + int encodeRc; + int encodedSize; + char *token = jwtEncodeToken(ctx, &jwt, true, slh, &encodedSize, &encodeRc); + assert(encodeRc == 0); + assert(token != NULL); + + printf("token: %s\n", token); + assert(strcmp(token, correctResult) == 0); + + jwtContextDestroy(ctx); + SLHFree(slh); +} + +static void shouldSignWithHS512(void) { + + printf("\n *** should sign with HS512\n"); + + + /* verified at jwt.io */ + static const char *const correctResult = "eyJhbGciOiJIUzUxMiJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ" + ".r6_nsKv-s96EVIIbUmN_8vOhkFnjKLh0c_-BY2__KfR8VBwM2qv6KwL4XfNH29njHL-oAPyQuR-8l02QSm00tA"; + + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + const Jwt jwt = { + .header = (JwsHeader) { + .algorithm = JWS_ALGORITHM_HS512 + }, + .subject = "1234567890", + .issuedAt = 1516239022llu + }; + int encodeRc; + int encodedSize; + char *token = jwtEncodeToken(ctx, &jwt, true, slh, &encodedSize, &encodeRc); + assert(encodeRc == 0); + assert(token != NULL); + + printf("token: %s\n", token); + assert(strcmp(token, correctResult) == 0); + + jwtContextDestroy(ctx); + SLHFree(slh); +} + +void shouldCorrectlyValidateBasicClaims(void) { + printf("\n *** should Correctly Validate Basic Claims\n"); + + static const char JWT_EXP_2038_AUD_TEST[] = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjIxNDc0ODM2NDcs" + "ImF1ZCI6IlRlc3QifQ"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_EXP_2038_AUD_TEST, true, + slh, &parseRc); + assert(parseRc == RC_JWT_INSECURE); + assert(j != NULL); + + jwtContextDestroy(ctx); + + bool valid = jwtAreBasicClaimsValid(j, "Test"); + assert(valid); + + valid = jwtAreBasicClaimsValid(j, "Test1"); + assert(!valid); + + SLHFree(slh); +} + +void shouldRejectExpiredJWT(void) { + printf("\n *** should Reject Expired JWT\n"); + + static const char JWT_EXPIRED[] = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjIs" + "ImF1ZCI6IlRlc3QifQ"; + int makeVerRc = 0, p11Rc = 0, p11Rsn = 0; + ShortLivedHeap *const slh = makeShortLivedHeap(8192, 1024); + JwtContext *const ctx = makeJwtContextForKeyInToken( + TOKEN_NAME, + "KEY_HMAC", + CKO_SECRET_KEY, + &makeVerRc, + &p11Rc, + &p11Rsn); + assert(makeVerRc == 0); + + int parseRc; + Jwt *const j = jwtVerifyAndParseToken(ctx, JWT_EXPIRED, true, + slh, &parseRc); + assert(parseRc == RC_JWT_INSECURE); + assert(j != NULL); + + jwtContextDestroy(ctx); + + bool valid = jwtAreBasicClaimsValid(j, "Test"); + assert(!valid); + + SLHFree(slh); +} + +static int getOrCreateHMACKey( + const char* in_tokenName, const char* in_keyLabel, + const unsigned char *in_keydata, int in_keydata_len, + ICSFP11_HANDLE_T **out_tokenHandle, + ICSFP11_HANDLE_T **out_keyHandle, + int *out_p11rc, int *out_p11rsn) +{ + int sts = 0; + ICSFP11_HANDLE_T *tokenHandle = NULL; + ICSFP11_HANDLE_T *keyHandle = NULL; + ICSFP11_HANDLE_T *foundHandles = NULL; + int numfound = 0; + +#define ZOWETOKEN_MANUFACTURER "Rocket Software" +#define ZOWETOKEN_MODEL "RSICSFP11" +#define ZOWETOKEN_SERIAL "1" + ICSFP11_TOKENATTRS_T zoweTokenAttrs = ICSFP11_TOKENATTRS_INITIALIZER; + memcpy(&(zoweTokenAttrs.manufacturer[0]), ZOWETOKEN_MANUFACTURER, strlen(ZOWETOKEN_MANUFACTURER)); + memcpy(&(zoweTokenAttrs.model[0]), ZOWETOKEN_MODEL, strlen(ZOWETOKEN_MODEL)); + memcpy(&(zoweTokenAttrs.serial[0]), ZOWETOKEN_SERIAL, strlen(ZOWETOKEN_SERIAL)); + + do { + DEBUG("attempting to address the desired token...\n"); + sts = rs_icsfp11_findToken(in_tokenName, &tokenHandle, out_p11rc, out_p11rsn); + if ((0 == sts) && (0 == *out_p11rc) && (0 == *out_p11rsn)) + { + DEBUG("token found\n"); + *out_tokenHandle = tokenHandle; + break; + } + DEBUG("attempting to create the token...\n"); + sts = rs_icsfp11_createToken(in_tokenName, &zoweTokenAttrs, + &tokenHandle, out_p11rc, out_p11rsn); + if ((0 == sts) && (0 == *out_p11rc) && (0 == *out_p11rsn)) { + DEBUG("token created\n"); + *out_tokenHandle = tokenHandle; + } + } while(0); + + if ((0 != sts) || (NULL == *out_tokenHandle)) { + return sts; + } + + do { + DEBUG("attempting to address the key record...\n"); + sts = rs_icsfp11_findObjectsByLabel(tokenHandle, in_keyLabel, NULL, + &foundHandles, &numfound, + out_p11rc, out_p11rsn); + if ((0 == sts) && (0 == *out_p11rc) && (0 == *out_p11rsn) && (0 < numfound)) + { + if (1 < numfound) { + printf("Warning: More than one key record found for label: %s\n", in_keyLabel); + } + DEBUG("key record found\n"); + keyHandle = (ICSFP11_HANDLE_T*) safeMalloc(sizeof(ICSFP11_HANDLE_T), "keyhandle"); + memcpy(keyHandle, &(foundHandles[0]), sizeof(ICSFP11_HANDLE_T)); + *out_keyHandle = keyHandle; + break; + } + + if ((NULL != in_keydata) && (0 < in_keydata_len)) { + DEBUG("attempting to create the key record...\n"); + sts = rs_icsfp11_hmacTokenKeyCreateFromRaw(tokenHandle, in_keyLabel, NULL, + in_keydata, in_keydata_len, + &keyHandle, out_p11rc, out_p11rsn); + if ((0 == sts) && (0 == *out_p11rc) && (0 == *out_p11rsn)) + { + DEBUG("record created\n"); + *out_keyHandle = keyHandle; + break; + } + } + } while(0); + + if (foundHandles && numfound) { + safeFree(foundHandles, numfound * sizeof(ICSFP11_HANDLE_T)); + } + + return sts; +} + +void initializeTokenForHMAC(void) { + ICSFP11_HANDLE_T *out_tokenHandle; + ICSFP11_HANDLE_T *out_keyHandle; + int out_p11rc, out_p11rsn; + + printf(" *** Initializing the HMAC key...\n"); + const int rc = getOrCreateHMACKey(TOKEN_NAME, + "KEY_HMAC", + HMAC_KEY, + sizeof (HMAC_KEY), + &out_tokenHandle, + &out_keyHandle, + &out_p11rc, + &out_p11rsn); + assert (rc == 0); + + safeFree(out_tokenHandle, sizeof (*out_tokenHandle)); + safeFree(out_keyHandle, sizeof (*out_keyHandle)); +} + +int main(int argc, char **argv) { + + initializeTokenForHMAC(); + + shouldParseNativeJwt(); + shouldParseAsciiJWT(); + shouldRejectMissingSignature(); + + shouldVerifyHS256(); + shouldRejectInvalidHS256(); + shouldVerifyHS384(); + shouldRejectInvalidHS384(); + shouldVerifyHS512(); + shouldRejectInvalidHS512(); + shouldVerifyRS256(); + shouldRejectInvalidRS256(); + + shouldEncodeASimpleJWT(); + + shouldSignWithRS256(); + shouldSignWithHS256(); + shouldSignWithHS384(); + shouldSignWithHS512(); + + shouldCorrectlyValidateBasicClaims(); + shouldRejectExpiredJWT(); + +#ifdef TRACK_MEMORY + int showOutstanding(void); /* enabled in alloc.c with -DTRACK_MEMORY */ + printf("\n *** Checking for memory leaks...\n"); + showOutstanding(); +#else + printf("\n *** Compile with -DTRACK_MEMORY to check for memory leaks...\n"); +#endif /* TRACK_MEMORY */ + return 0; +} + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/jwt/tests/secsrv.p12 b/jwt/tests/secsrv.p12 new file mode 100644 index 000000000..361f08d8b Binary files /dev/null and b/jwt/tests/secsrv.p12 differ diff --git a/jwt/tests/test.mk b/jwt/tests/test.mk new file mode 100644 index 000000000..ad9ca1ab6 --- /dev/null +++ b/jwt/tests/test.mk @@ -0,0 +1,23 @@ + + +TEST_SRC := $(MAINFRAME_C)/c/alloc.c $(MAINFRAME_C)/c/zos.c \ + $(MAINFRAME_C)/c/utils.c $(MAINFRAME_C)/c/json.c \ + $(MAINFRAME_C)/c/charsets.c $(MAINFRAME_C)/c/timeutls.c \ + $(MAINFRAME_C)/c/xlate.c $(MAINFRAME_C)/c/zosfile.c \ + tests/jwt-test.c + +TEST_OBJ := $(TEST_SRC:.c=.o) + +TEST_BINARIES := tests/jwt-test + +tests/jwt-test: SEVERITY_W += $(SEVERITY_E) +tests/jwt-test: SEVERITY_E := +tests/jwt-test: CFLAGS += -DTRACK_MEMORY + +tests/jwt-test: $(filter $(MAINFRAME_C)/%.o,$(TEST_OBJ)) $(LIBRARY) tests/jwt-test.o + $(CC) $(CFLAGS) -o $@ -Llib tests/jwt-test.o \ + $(filter $(MAINFRAME_C)/%.o,$(TEST_OBJ)) -lrsjwt /usr/lib/CSFDLL31.x || rm tests/jwt-test + +.PHONY: test +test: $(TEST_BINARIES) + ./tests/jwt-test