/* * This function will set up a session to the TSM server and return the * session handler */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <termio.h> #include <unistd.h> #include "dsmrc.h" #include "dsmapitd.h" #include "dsmapifp.h" #include "../tsmpipe.h" dsBool_t compressEnabled=bFalse; // Is compression enabled /* Print out TSM Error Code */ char *tsm_printerr(dsUint32_t dsmHandle, dsInt16_t rc) { char rcStr[DSM_MAX_RC_MSG_LENGTH]; char *s; s = malloc(sizeof(rcStr)); if (rc == DSM_RC_WILL_ABORT) { dsUint16_t reason; rc = dsmEndTxn(dsmHandle, DSM_VOTE_COMMIT, &reason); if (rc == DSM_RC_CHECK_REASON_CODE) rc = reason; } dsmRCMsg(dsmHandle,rc,rcStr); strtok(rcStr, "\n"); sprintf(s,"[rc=%s]",rcStr); return s; } /* Check the TSM API Version */ int tsm_checkapi(void) { dsmApiVersionEx apiLibVer; dsUint32_t apiVersion; dsUint32_t applVersion = (10000 * DSM_API_VERSION) + (1000 * DSM_API_RELEASE) + (100 * DSM_API_LEVEL) + DSM_API_SUBLEVEL; memset(&apiLibVer,0x00,sizeof(dsmApiVersionEx)); apiLibVer.stVersion = apiVersionExVer; dsmQueryApiVersionEx(&apiLibVer); apiVersion = (10000 * apiLibVer.version) + (1000 * apiLibVer.release) + (100 * apiLibVer.level) + apiLibVer.subLevel; if (apiVersion < applVersion) { printf("The Tivoli Storage Manager API library Version (%d.%d.%d.%d) is at a lower version than the application version (%d.%d.%d.%d)\n", apiLibVer.version, apiLibVer.release, apiLibVer.level, apiLibVer.subLevel, DSM_API_VERSION, DSM_API_RELEASE, DSM_API_LEVEL, DSM_API_SUBLEVEL); printf("Please upgrade the API accordingly.\n"); return 0; } return 1; } /* Initialise a session to the TSM server */ dsUint32_t tsm_initsess(char *options, char *password) { dsInt16_t rc=0; dsUint32_t dsmHandle=0; dsmApiVersionEx applApi; dsmInitExIn_t initIn; dsmInitExOut_t initOut; optStruct dsmOpt; ApiSessInfo dsmSessInfo; if (! tsm_checkapi()) { exit(2); } memset(&applApi,0x00,sizeof(dsmApiVersionEx)); applApi.stVersion = apiVersionExVer; applApi.version = DSM_API_VERSION; applApi.release = DSM_API_RELEASE; applApi.level = DSM_API_LEVEL; applApi.subLevel = DSM_API_SUBLEVEL; memset(&initIn,0x00,sizeof(dsmInitExIn_t)); initIn.stVersion = dsmInitExInVersion; initIn.apiVersionExP = &applApi; initIn.clientNodeNameP = NULL; initIn.clientOwnerNameP = NULL; initIn.clientPasswordP = password; initIn.applicationTypeP = NULL; initIn.configfile = NULL; initIn.options = options; initIn.userNameP = NULL; initIn.userPasswordP = NULL; //initIn.dirDelimiter = dirDelimiter; //initIn.useUnicode = useUnicode; //initIn.bEncryptKeyEnabled = encrypt; //initIn.encryptionPasswordP = encryptKey; memset(&initOut,0x00,sizeof(dsmInitExOut_t)); initOut.stVersion = dsmInitExOutVersion; rc = dsmInitEx(&dsmHandle, &initIn, &initOut); /* If the TSM password has expired, change it. */ if (rc == DSM_RC_REJECT_VERIFIER_EXPIRED) { rc = dsmChangePW(dsmHandle,NULL,NULL); if (rc != DSM_RC_OK) { printf("%s: dsmChangePW() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); dsmTerminate(dsmHandle); return 0; } } else if (rc != DSM_RC_OK) { printf("%s: dsmInitEx() failed %s\n",__func__,tsm_printerr(dsmHandle, rc)); dsmTerminate(dsmHandle); return 0; } // Make sure if we have compression enabled, that we also have COMPRESSAlways YES memset(&dsmOpt,0x00,sizeof(dsmOpt)); rc = dsmQuerySessOptions(dsmHandle, &dsmOpt); memset(&dsmSessInfo,0x00,sizeof(ApiSessInfo)); dsmSessInfo.stVersion = ApiSessInfoVersion; /* Init struct version */ rc = dsmQuerySessInfo(dsmHandle, &dsmSessInfo); rc = 1; switch (dsmSessInfo.compression) { case COMPRESS_YES : compressEnabled = bTrue; break; case COMPRESS_NO : compressEnabled = bFalse; break; case COMPRESS_CD : compressEnabled = dsmOpt.compression; break; default: rc=0; } if (!rc || (compressEnabled && ! dsmOpt.compressalways)) { debugLog(0,__func__,!rc ? "ERROR: Error Querying Session Capabilities" : "ERROR: COMPRESSion is ENABLED, but not COMPRESSAlways Yes",1); } return dsmHandle; } /* List objects that are in TSM */ int tsm_sessioninfo(dsUint32_t dsmHandle) { extern int verbose; dsInt16_t rc=0; optStruct dsmOpt; ApiSessInfo dsmSessInfo; dsmApiVersionEx apiLibVer; char t[50]; memset(&apiLibVer,0x00,sizeof(dsmApiVersionEx)); apiLibVer.stVersion = apiVersionExVer; dsmQueryApiVersionEx(&apiLibVer); printf("Application Version:\n"); printf(" TSMPIPE Version: %s\n", _TSMPIPE_VERSION); printf(" TSMPIPE API Version: %d.%d.%d.%d\n", DSM_API_VERSION, DSM_API_RELEASE, DSM_API_LEVEL, DSM_API_SUBLEVEL); printf(" TSM Library: %d.%d.%d.%d\n", apiLibVer.version, apiLibVer.release, apiLibVer.level, apiLibVer.subLevel); printf("\n"); memset(&dsmOpt,0x00,sizeof(dsmOpt)); rc = dsmQuerySessOptions(dsmHandle, &dsmOpt); if (rc) printf("%s: ERROR dsmQuerySessOptions() unable to query Session Options. RC = %d\n",__func__,rc); else { printf("dsmQuerySessOptions:\n"); printf(" DSMI_DIR: %s\n",dsmOpt.dsmiDir); printf(" DSMI_CONFIG: %s\n",dsmOpt.dsmiConfig); printf(" SErvername: %s\n",dsmOpt.serverName); switch (dsmOpt.commMethod) { case DSM_COMM_TCP : strcpy(t,"TCP/IP"); break; case DSM_COMM_NAMEDPIPE : strcpy(t,"NAMED PIPE"); break; case DSM_COMM_SHM : strcpy(t,"SHARED MEMORY"); break; case DSM_COMM_TCPIP6 : strcpy(t,"TCP/IP v6"); break; default: strcpy(t,"UNKNOWN"); } printf(" COMMmethod: %s\n",t); if (verbose) fprintf(stderr,"%s: commMethod: [%d]\n",__func__,dsmOpt.commMethod); printf(" TCPServerAddress: %s\n",dsmOpt.serverAddress); if (verbose) fprintf(stderr,"%s: serverAddress: [%s]\n",__func__,dsmOpt.serverAddress); printf(" NODEName: %s\n",dsmOpt.nodeName); printf(" COMPRESSIon: %s\n",dsmOpt.compression ? "YES" : "NO"); printf(" COMPRESSAlways: %s\n",dsmOpt.compressalways ? "YES" : "NO"); printf(" PASSWORDAccess: %s\n",dsmOpt.passwordAccess ? "GENERATE" : "PROMPT"); } memset(&dsmSessInfo,0x00,sizeof(ApiSessInfo)); dsmSessInfo.stVersion = ApiSessInfoVersion; /* Init struct version */ rc = dsmQuerySessInfo(dsmHandle, &dsmSessInfo); if (rc) printf("%s: ERROR dsmQuerySessInfo() unable to query Session Info. RC = %d\n",__func__,rc); else { printf("\n"); printf("dsmQuerySessInfo:\n"); printf(" Server Information:\n"); printf(" Name: %s\n",dsmSessInfo.adsmServerName); printf(" Host: %s\n",dsmSessInfo.serverHost); printf(" Port: %u\n",dsmSessInfo.serverPort); printf(" Date: %s\n",dsmDateToStr(dsmSessInfo.serverDate)); printf(" Type: %s\n",dsmSessInfo.serverType); printf(" Version: %i.%i.%i.%i\n", dsmSessInfo.serverVer, dsmSessInfo.serverRel, dsmSessInfo.serverLev, dsmSessInfo.serverSubLev); printf(" Archive Retention Protection : %s\n",dsmSessInfo.archiveRetentionProtection ? "YES" : "NO"); printf("\n"); printf(" Client Information:\n"); printf(" Node: %s\n",dsmSessInfo.id); printf(" Node Type: %s\n",dsmSessInfo.nodeType); printf(" Filespace delimiter: %c\n",dsmSessInfo.fsdelim); printf(" HL & LL delimiter: %c\n",dsmSessInfo.hldelim); switch (dsmSessInfo.compression) { case COMPRESS_YES : strcpy(t,"ON"); break; case COMPRESS_NO : strcpy(t,"OFF"); break; case COMPRESS_CD : strcpy(t,"CLIENT"); break; default: strcpy(t,"UNKNOWN"); } printf(" Client compression: %s\n",t); switch (dsmSessInfo.archDel) { case ARCHDEL_YES : strcpy(t,"YES"); break; case ARCHDEL_NO : strcpy(t,"NO"); break; default: strcpy(t,"UNKNOWN"); } printf(" ARCHIVE Delete: %s\n",t); switch (dsmSessInfo.backDel) { case BACKDEL_YES : strcpy(t,"YES"); break; case ARCHDEL_NO : strcpy(t,"NO"); break; default: strcpy(t,"UNKNOWN"); } printf(" BACKUP delete: %s\n",t); printf(" MAX objects per transactions: %u\n", dsmSessInfo.maxObjPerTxn); printf(" LAN FREE Enabled: %s\n",dsmSessInfo.lanFreeEnabled ? "YES" : "NO"); printf(" Deduplication: %s\n",dsmSessInfo.dedupType == dedupClientOrServer ? "Client Or Server" : "Server Only"); printf("\n"); printf(" General session info:\n"); printf(" Owner: %s\n",dsmSessInfo.owner); printf(" API Config file: %s\n",dsmSessInfo.confFile); printf("\n"); printf(" Policy Information:\n"); printf(" Domain name: %s\n",dsmSessInfo.domainName); printf(" Policyset name: %s\n",dsmSessInfo.policySetName); printf(" Policy activation date: %s\n",dsmDateToStr(dsmSessInfo.polActDate)); printf(" Default management class: %s\n",dsmSessInfo.dfltMCName); printf(" BACKUP retention grace: %u days\n",dsmSessInfo.gpBackRetn); printf(" ARCHIVE retention grace: %u days\n",dsmSessInfo.gpArchRetn); printf("\n"); } return 1; } /* * Query TSM for a list of objects. * * We use a callback to process the list, the callback should return: * -1 upon error condition, application should exit. * 0 if tsm_queryfile() should skip processing the remaining matches. * 1 otherwise. */ dsInt16_t tsm_queryfile(dsUint32_t dsmHandle, dsmQueryType qType, tsm_query_callback usercb, void *userdata, qryArchiveData qaData, qryBackupData qbData, dsBool_t friendly) { extern int verbose; dsInt16_t rc=0; dsmQueryBuff *qDataP; DataBlk qResp; memset(&qResp,0x00,sizeof(DataBlk)); qResp.stVersion = DataBlkVersion; switch (qType) { case qtArchive: qDataP = &qaData; qryRespArchiveData qaResp; qResp.bufferLen = sizeof(qaResp); qResp.bufferPtr = (char *) &qaResp; qaResp.stVersion = qryRespArchiveDataVersion; if (verbose) fprintf(stderr,"%s: Query filespace %s\n",__func__,dsmObjnameToStr(*qaData.objName)); break; case qtBackup: qDataP = &qbData; qryRespBackupData qbResp; qResp.bufferLen = sizeof(qbResp); qResp.bufferPtr = (char *) &qbResp; qbResp.stVersion = qryRespBackupDataVersion; if (verbose) fprintf(stderr,"%s: Query filespace %s\n",__func__,dsmObjnameToStr(*qbData.objName)); if (verbose > 1) { fprintf(stderr,"%s: PIT Date: %s\n",__func__,dsmDateToStr(qbData.pitDate)); fprintf(stderr,"%s: OBJSTATE : %s\n",__func__,qbData.objState==DSM_ACTIVE ? "DSM_ACTIVE" : "DSM_ANY_MATCH"); } break; default: fprintf(stderr,"%s: UNKNOWN Type %d\n",__func__,qType); exit(1); } rc = dsmBeginQuery(dsmHandle, qType, qDataP); if (rc != DSM_RC_OK) { printf("%s: dsmBeginQuery() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return rc; } /* Loop and apply our callback to the result */ while ((rc = dsmGetNextQObj(dsmHandle, &qResp)) == DSM_RC_MORE_DATA) { int cbret; if(verbose > 1) { dsmObjName *rObjName; if (qType == qtArchive) { qryRespArchiveData *qr = (void *) qResp.bufferPtr; rObjName = &(qr->objName); } else if (qType == qtBackup) { qryRespBackupData *qr = (void *) qResp.bufferPtr; rObjName = &(qr->objName); } else { fprintf(stderr,"%s: UNKNOWN Type %d\n",__func__,qType); return DSM_RC_UNKNOWN_ERROR; } fprintf(stderr,"%s: Match file %s\n",__func__,dsmObjnameToStr(*rObjName)); } if (usercb == NULL) continue; cbret = usercb(qType,&qResp,userdata,friendly); if (cbret < 0) { return DSM_RC_UNKNOWN_ERROR; } else if(cbret == 0) { break; } } if (rc != DSM_RC_FINISHED && rc != DSM_RC_MORE_DATA) { printf("%s: dsmGetNextQObj() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return rc; } rc = dsmEndQuery(dsmHandle); if (rc != DSM_RC_OK) { printf("%s: dsmEndQuery() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return rc; } return DSM_RC_OK; } /* Signal handler */ int intrupt = 0; void Catch(int signo) { if(signo) {}; /* so compiler won't complain about unused arguments */ intrupt = 1; } /* Uses sigaction to establish signal handler */ int install_sig_handler(int signum, void (*sig_handler)(int)) { struct sigaction action; int rc; action.sa_handler = sig_handler; /* signal handler function */ sigemptyset( &action.sa_mask ); /* mask of signals to block */ action.sa_flags = SA_NOCLDSTOP; rc = sigaction( signum, /* I */ /* signal identifier */ &action, /* *I */ /* new action for signal */ NULL ); /* *O */ /* previous action - not needed */ return (rc); } int ReadPass(char *text, char *buffer, int length) { struct termio ttyState, ttyStateSave; register char *p; register int c; int rc; FILE *ttyFH; struct sigaction action; /* Let's flush any prompt to the terminal that may be pending. */ fflush(stdout); /* Open the console input device */ if((ttyFH = fopen("/dev/tty", "r")) == NULL) return(-1); else setbuf(ttyFH, (char *)NULL); /* Reset the interrupt flag */ intrupt = 0; /* Trap the "BREAK" interrupt */ (void) sigaction( SIGINT, NULL, &action ); /* save current hdlr */ (void) install_sig_handler( SIGINT, Catch ); /* install new hdlr */ /* Get current state */ rc = ioctl(fileno(ttyFH), TCGETA, &ttyStateSave); if (rc == -1) return(-1); /* Copy the saved tty state into a work field */ ttyState = ttyStateSave; /* Turn off ECHO */ ttyState.c_lflag &= ~ECHO; rc = ioctl(fileno(ttyFH), TCSETA, &ttyState); if (rc == -1) return(-1); printf(text); /* Read the password (quietly) */ for(p=buffer; !intrupt && (c = getc(ttyFH)) != '\n' && c != EOF; ) { if(p < buffer+length) *p++ = c; } *p = '\0'; printf("\n"); /* Restore the tty state settings */ rc = ioctl(fileno(ttyFH), TCSETA, &ttyStateSave); if (rc == -1) return(-1); /* Reset the interrupt handler */ (void) sigaction( SIGINT, &action, NULL ); if(ttyFH != stdin) (void) fclose(ttyFH); if(intrupt) (void) kill(getpid(), SIGINT); return(strlen(buffer)); } /* * Set the TSM Node password * * We use a callback to process the list, the callback should return: */ int tsm_setpassword(char *options) { uint32 dsmHandle; bool_t done = bFalse; uint16 pw_trys = 0; uint16 len = 0; char input[INPUTLEN]; char pw_cur[DSM_MAX_VERIFIER_LENGTH + 1]; char pw_new [DSM_MAX_VERIFIER_LENGTH + 1]; int rc; while (!done) { // Current Password rc = ReadPass("Enter your current password: ",input,INPUTLEN); len = strlen(input); if ((len > DSM_MAX_VERIFIER_LENGTH) || !len || (rc < 0)) { printf("Current password is invalid. Please try again.\n"); continue; } else { strcpy(pw_cur,input); } // New password rc = ReadPass("Enter your new password: ",input,INPUTLEN); len = strlen(input); if ((len > DSM_MAX_VERIFIER_LENGTH) || !len || (rc < 0)) { printf("New password is invalid. Please try again.\n"); continue; } else { strcpy(pw_new,input); } // Verify new password rc = ReadPass("Enter your new password again: ",input,INPUTLEN); len = strlen(input); if ((len > DSM_MAX_VERIFIER_LENGTH) || !len || (rc < 0)) { printf("New password is invalid. Please try again.\n"); continue; } else { // Compare new pw copies to make sure no typos from user. if ((strcmp(pw_new,input))) { pw_trys++; if (pw_trys > 3) debugLog(0,__func__,"ERROR: Passwords dont match, tried too many times.",3); else debugLog(0,__func__,"WARN: Your new passwords do not match, please try again...",0); } else { done = bTrue; } } } dsmHandle = tsm_initsess(options,pw_cur); if (! dsmHandle) { debugLog(0,__func__,"ERROR: Unable to create TSM session with your password.",2); } rc = dsmChangePW(dsmHandle,pw_cur,pw_new); if (rc) debugLog(0,__func__,"ERROR: Password change failed.",2); else printf("\nYour new password has been accepted and updated.\n"); dsmTerminate(dsmHandle); return 1; }