//%LICENSE//////////////////////////////////////////////////////////////// // // Licensed to The Open Group (TOG) under one or more contributor license // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with // this work for additional information regarding copyright ownership. // Each contributor licenses this file to you under the OpenPegasus Open // Source License; you may not use this file except in compliance with the // License. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ////////////////////////////////////////////////////////////////////////// // //%///////////////////////////////////////////////////////////////////////////// #include // $DESCRIPTOR #include // IO$_SENSEMODE #include // TT$M_NOBRDCST #include // TT2$M_PASTHRU #include #include // SS$_NORMAL #include // VMS_STATUS_SUCCESS #include // CHP$_ #include // ARM$_ #include // PRV$M_SETPRV #include #include PEGASUS_NAMESPACE_BEGIN //============================================================================== // // System // //============================================================================== static String vmsPath; static Mutex vmsPathMutex(Mutex::NON_RECURSIVE); static char* toVmsDir(const char* path) { char* dirend; char* dirstart; char* dir_path; dirend = strrchr(path, '.'); if (dirend) { dir_path = new char[strlen(path) + sizeof("DIR")]; strcpy(dir_path, path); dirend = strrchr(dir_path, '.'); *dirend = ']'; dirend = strrchr(dir_path, ']'); *dirend = '\0'; strcat(dir_path, ".DIR"); } else { dir_path = new char[strlen(path) + sizeof("[000000].DIR")]; dirstart = strchr(path, '['); if (dirstart) // Top level directory { strncpy(dir_path, path, dirstart-path); dir_path[dirstart-path] = '\0'; strcat(dir_path, "[000000]"); // Top level directory strcat(dir_path, ++dirstart); // Add the directory name dirend = strrchr(dir_path, ']'); *dirend = '\0'; strcat(dir_path, ".DIR"); } else { delete dir_path; dir_path = 0; } } return dir_path; } static int action(char *path, int type_of_file) { int ret; char *dir_path; if (type_of_file == DECC$K_DIRECTORY) { dir_path = toVmsDir(path); if (dir_path) { vmsPath = dir_path; delete dir_path; } ret = dir_path != 0; } else { vmsPath = path; ret = 1; } return ret; } static int toVms(const char* path, String& vms_path) { char cwd[256]; // OpenVMS file can't be larger than 255 chars. char *result; char *dir_path; int ret; // Treat the current directory as a special case if ((strcmp(path, ".") == 0) || (strcmp(path, "./") == 0)) { result = getcwd(cwd, sizeof(cwd), 1); if (!result) return 0; dir_path = toVmsDir(cwd); if (dir_path) { vms_path = dir_path; delete dir_path; ret = 1; } else ret = 0; } else if (strchr(path, '/') != 0) { AutoMutex pathLock(vmsPathMutex); ret = decc$to_vms(path, action, 0, 0); vms_path = vmsPath; } else { vms_path = path; ret = 1; } return ret; } static int canAccess(const char* path, int access_right) { struct itm { unsigned short bufLen; unsigned short itmCode; void *bufAddr; void *retAddr; }; int retStat; int len; union armdef armval; struct FAB fab; struct XABPRO xabpro; struct { struct itm item[3]; unsigned long term; } itmlst; String vms_path; CString cvms_path; // Convert the path to OpenVMS format (if necessary) retStat = toVms(path, vms_path); cvms_path = vms_path.getCString(); len = strlen(cvms_path); if (len > 255) return SS$_FILACCERR; // Get the file protections fab = cc$rms_fab; fab.fab$l_fna = (char *) (const char *) cvms_path; fab.fab$b_fns = len; fab.fab$b_fac = FAB$M_GET; fab.fab$l_xab = &xabpro; xabpro.xab$b_cod = XAB$C_PRO; xabpro.xab$b_bln = XAB$C_PROLEN; xabpro.xab$w_aclsiz = 0; // Not considering ACLs at this time xabpro.xab$l_aclbuf = 0; xabpro.xab$l_nxt = 0; retStat = sys$open(&fab, 0, 0); if (!$VMS_STATUS_SUCCESS(retStat)) { if (retStat != RMS$_FNF) { PEG_TRACE((TRC_OS_ABSTRACTION, Tracer::LEVEL1, "sys$open error: %s", strerror(EVMSERR, retStat))); } return retStat; } sys$close(&fab, 0, 0); armval.arm$r_fill_47_.arm$l_file_access = access_right; itmlst.item[0].itmCode = CHP$_ACCESS; itmlst.item[0].bufLen = sizeof(armval); itmlst.item[0].bufAddr = &armval; itmlst.item[0].retAddr = 0; itmlst.item[1].itmCode = CHP$_OWNER; itmlst.item[1].bufLen = sizeof(xabpro.xab$l_uic); itmlst.item[1].bufAddr = &xabpro.xab$l_uic; itmlst.item[1].retAddr = 0; itmlst.item[2].itmCode = CHP$_PROT; itmlst.item[2].bufLen = sizeof(xabpro.xab$w_pro); itmlst.item[2].bufAddr = &xabpro.xab$w_pro; itmlst.item[2].retAddr = 0; itmlst.term = 0; retStat = sys$chkpro(&itmlst, 0, 0); if (!$VMS_STATUS_SUCCESS(retStat)) { if (retStat != SS$_NOPRIV) { PEG_TRACE((TRC_OS_ABSTRACTION, Tracer::LEVEL1, "sys$chkpro error: %s", strerror(EVMSERR, retStat))); } } return retStat; } Boolean System::canRead(const char* path) { return canAccess(path, ARM$M_READ) == SS$_NORMAL; } Boolean System::canWrite(const char* path) { return canAccess(path, ARM$M_WRITE) == SS$_NORMAL; } String System::getPassword(const char* prompt) { struct { short int numbuf; char frst_char; char rsv1; long rsv2; } tahead; typedef struct { // I/O status block short i_cond; // Condition value short i_xfer; // Transfer count long i_info; // Device information } iosb; typedef struct { // Terminal characteristics char t_class; // Terminal class char t_type; // Terminal type short t_width; // Terminal width in characters long t_mandl; // Terminal's mode and length long t_extend; // Extended terminal characteristics } termb; termb otermb; termb ntermb; short int ichan; // Gets channel number for TT: int errorcode; int kbdflgs; // saved keyboard fd flags int kbdpoll; // in O_NDELAY mode int kbdqp = false; // there is a char in kbdq int psize; // size of the prompt const size_t MAX_PASS_LEN = 32; static char buf[MAX_PASS_LEN]; char kbdq; // char we've already read iosb iostatus; static long termset[2] = { 0, 0 }; // No terminator $DESCRIPTOR(inpdev, "TT"); // Terminal to use for input buf[0] = 0; ichan = 0; try { // Get a channel for the terminal errorcode = sys$assign(&inpdev, // Device name &ichan, // Channel assigned 0, // request KERNEL mode access 0); // No mailbox assigned if (errorcode != SS$_NORMAL) { throw Exception("sys$assign failure"); } // Read current terminal settings errorcode = sys$qiow(0, // Wait on event flag zero ichan, // Channel to input terminal IO$_SENSEMODE, // Function - Sense Mode &iostatus, // Status after operation 0, 0, // No AST service &otermb, // [P1] Address of Char Buffer sizeof (otermb), // [P2] Size of Char Buffer 0, 0, 0, 0); // [P3] - [P6] if (errorcode != SS$_NORMAL) { throw Exception("sys$qiow IO$_SENSEMODE failure"); } // setup new settings ntermb = otermb; // turn on passthru and nobroadcast ntermb.t_extend |= TT2$M_PASTHRU; ntermb.t_mandl |= TT$M_NOBRDCST; // Write out new terminal settings errorcode = sys$qiow(0, // Wait on event flag zero ichan, // Channel to input terminal IO$_SETMODE, // Function - Set Mode &iostatus, // Status after operation 0, 0, // No AST service &ntermb, // [P1] Address of Char Buffer sizeof (ntermb), // [P2] Size of Char Buffer 0, 0, 0, 0); // [P3] - [P6] if (errorcode != SS$_NORMAL) { throw Exception("sys$qiow IO$_SETMODE failure"); } // Write a prompt, read characters from the terminal, performing no // editing // and doing no echo at all. psize = strlen(prompt); errorcode = sys$qiow(0, // Event flag ichan, // Input channel IO$_READPROMPT | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TRMNOECHO, // Read with prompt, no echo, no translate, no // termination character echo &iostatus, // I/O status block NULL, // AST block (none) 0, // AST parameter &buf, // P1 - input buffer MAX_PASS_LEN, // P2 - buffer length 0, // P3 - ignored (timeout) 0, // P4 - ignored (terminator char set) prompt, // P5 - prompt buffer psize); // P6 - prompt size if (errorcode != SS$_NORMAL) { throw Exception("sys$qiow IO$_READPROMPT failure:"); } // Write out old terminal settings errorcode = sys$qiow(0, // Wait on event flag zero ichan, // Channel to input terminal IO$_SETMODE, // Function - Set Mode &iostatus, // Status after operation 0, 0, // No AST service &otermb, // [P1] Address of Char Buffer sizeof (otermb), // [P2] Size of Char Buffer 0, 0, 0, 0); // [P3] - [P6] if (errorcode != SS$_NORMAL) { throw Exception("sys$qiow IO$_SETMODE failure"); } // Start new line const int CR = 0x0d; const int LF = 0x0a; fputc(CR, stdout); fputc(LF, stdout); // Remove the termination character psize = strlen(buf); buf[psize - 1] = 0; } catch (Exception &e) { PEG_TRACE((TRC_OS_ABSTRACTION, Tracer::LEVEL1, "%s: %s", (const char *) (e.getMessage()).getCString(), strerror(EVMSERR, errorcode))); } // Deassign the channel if (ichan) sys$dassgn(ichan); return buf; } String System::encryptPassword(const char* password, const char* salt) { const size_t MAX_PASS_LEN = 1024; char pbBuffer[MAX_PASS_LEN] = {0}; Uint32 dwByteCount; char pcSalt[3] = {0}; strncpy(pcSalt, salt, 2); dwByteCount = strlen(password); memcpy(pbBuffer, password, dwByteCount); for (Uint32 i=0; (i=MAX_PASS_LEN); i++) { (i%2 == 0) ? pbBuffer[i] ^= pcSalt[1] : pbBuffer[i] ^= pcSalt[0]; } return String(pcSalt) + String((char *)pbBuffer); } Boolean System::isPrivilegedUser(const String& userName) { unsigned int audsts; union prvdef priv_mask; int retStat; priv_mask.prv$l_l1_bits = priv_mask.prv$l_l2_bits = 0; priv_mask.prv$v_sysprv = true; // SYSPRV privilege. priv_mask.prv$v_bypass = true; // BYPASS privilege. retStat = sys$check_privilegew(0, &priv_mask, 0, 0, 0, &audsts, 0, 0); return retStat == SS$_NORMAL; } PEGASUS_NAMESPACE_END