/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include // This nonsense surrounds sys/types.h because its typedef for boolean conflicts // with one from defines.h. Many includes are ifdef on ARCH because of the // need for select(). #if defined(solaris) #define boolean bool #endif #include #if defined(solaris) #undef boolean #endif #include #include #ifndef DXD_DO_NOT_REQ_UNISTD_H #include #if defined(sgi) #include #endif #if defined(ibm6000) #include #endif #include #endif #ifdef DXD_WIN #include #else #include #endif #if defined(_AIX41) #include #endif #if defined(aviion) extern "C" { void bzero(char *, int); } #endif #include #include "IBMApplication.h" #include "License.h" #if defined(DXD_LICENSED_VERSION) && DXD_LICENSED_VERSION!=0 # define NEEDS_LICENSE_ROUTINES 1 #else # define NEEDS_LICENSE_ROUTINES 0 #endif #if NEEDS_LICENSE_ROUTINES extern "C" { #if (defined(sgi) && !( __mips > 1)) || defined(aviion) const char *crypt(const char*, const char*); #endif #if defined(solaris) #include #endif #ifdef sun4 int gethostid(); int getdtablesize(); #endif #ifdef sgi unsigned sysid(unsigned char id[]); int getdtablesize(void); #endif #if defined(aviion) int gethostid(); int getdtablesize(); int gettimeofday(struct timeval*, struct timezone*); #endif #ifdef alphax #include int getdtablesize(); #include /* standard I/O */ #include /* error numbers */ #include /* socket definitions */ #include /* ioctls */ #include /* generic interface structures */ #include /* maybe someday this will be implemented...arg! */ extern "C" int select( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) ; #endif } #define CRYPT(A,B) crypt((const char*)A, (const char*)B) #define ANYWHERE_HOSTID "00000000" #if defined(DXD_LICENSED_VERSION) && !defined(HAVE_CRYPT) error: Can not run licensing routines without crypt() #endif static int checkexp(const char *root); #endif // NEEDS_LICENSE_ROUTINES #ifndef DXD_WIN void UIGetLicense(const char *root, XtInputCallbackProc lostLicense, LicenseTypeEnum *appLic, LicenseTypeEnum *funcLic) { #if !NEEDS_LICENSE_ROUTINES *appLic = FullyLicensed; *funcLic = FullFunctionLicense; return; #else LicenseTypeEnum forcedFuncLic; int i; int child; int child_in[2],child_out[2]; char remname[1024]; char auth_msg[AUTH_MSG_LEN]; char ckey[128]; char c_buf[128],p_buf[128]; /* hold crypted msgs for comaparison */ char envbuf[128]; char salt[32]; time_t ctime; if (checkexp (root)) { /* check for an old syle trial license */ *appLic = NodeLockedLicense; *funcLic = FullFunctionLicense; return; } /* didn't find a trial license so spawn the NetLS licensing process */ *appLic = Unlicensed; forcedFuncLic = *funcLic; *funcLic = Unlicensed; /* Set up two pipes */ if (pipe(child_in) < 0) { perror("pipe(child_in)"); return; } if (pipe(child_out) < 0) { perror("pipe(child_out)"); return ; } ctime=time(NULL); sprintf(envbuf,"_DX_%d=",getpid()); sprintf(c_buf,"%x",ctime); strcat(envbuf,c_buf+4); putenv(DuplicateString(envbuf)); child = 0xffff&fork(); if (child == 0) { /* Child */ char arg1[512]; char arg2[512]; char arg3[512]; #ifdef hp700 int width = MAXFUPLIM; #else #ifdef solaris int width = FD_SETSIZE; #else int width = getdtablesize(); #endif #endif close(child_in[1]); close(child_out[0]); if (dup2(child_in[0], 0) < 0) exit(1); if (dup2(child_out[1], 1) < 0) exit(1); /* close other file descriptors here */ #if !defined(__PURIFY__) // purify uses some file descriptors for (i=3 ; i<=width ; i++) close(i); #endif char *s; if (s = getenv("DXSHADOW")) strcpy(remname,s); else sprintf(remname,"%s/bin_%s/dxshadow",root,DXD_ARCHNAME); switch (forcedFuncLic) { case RunTimeLicense: strcpy(arg1,"-rtonly"); break; case DeveloperLicense: strcpy(arg1,"-devonly"); break; default: strcpy(arg1,"-dev"); break; } int maj, min,mic; theIBMApplication->getVersionNumbers(&maj,&min,&mic); sprintf(arg3,"%d.%d.%d",maj,min,mic); execlp(remname, "dxshadow", arg1, "-version", arg3, NULL); // // If we get here, we failed. // fprintf(stderr,"License Error: could not exec license process\n"); exit(1); } // // Only the parent gets here // close (child_in[0]); close (child_out[1]); /* wait for response from the child */ #define USE_SUB_EVENT_LOOP 1 #if USE_SUB_EVENT_LOOP // Instead of doing a blocking read... and instead of writing a communication // subsystem, monitor all sockets of interest. When something arrives, service // it. As a result, X Events still get processed and we achieve a little extra // concurrency which should decrease startup time. According to Quantify, // we were spending lots of time inside the call to read(). // The loop waits approximately 5 seconds. If dxshadow takes longer than that, // then execution continues by sitting in the read() command as it used to. fd_set rdfds; XEvent event; FD_ZERO(&rdfds); Display *d = theApplication->getDisplay(); XtAppContext app = theApplication->getApplicationContext(); timeval tval, starttime; gettimeofday (&starttime, NULL); while (!FD_ISSET(child_out[0], &rdfds)) { FD_SET (child_out[0], &rdfds); FD_SET (ConnectionNumber(d), &rdfds); tval.tv_sec = 1; tval.tv_usec = 0; if (select (32, (SELECT_ARG_TYPE)&rdfds, NULL, NULL, &tval) == -1) break; XtInputMask mask; while ((mask = XtAppPending (app)) & (XtIMXEvent|XtIMTimer)) { if (XtIMXEvent & mask) { XtAppNextEvent (app, &event); theIBMApplication->passEventToHandler (&event); } if (XtIMTimer & mask) { XtAppProcessEvent (app, XtIMTimer); } } if (gettimeofday (&tval, NULL) == -1) break; if ((tval.tv_sec - starttime.tv_sec) >= 10) break; } #endif i = read(child_out[0],auth_msg,AUTH_MSG_LEN); if (!i) { fprintf(stderr,"License Error\n"); goto unlicensed; } /* decipher license message here */ child = (child<4096)?(child+4096):(child); /* forces to be 4 0x chars */ strcpy(ckey,c_buf+4); sprintf(ckey+4,"%x",child); salt[0] = '7'; salt[1] = 'q'; salt[2] = '\0'; strcpy(p_buf,CRYPT(ckey,salt));; for(i=0;i<13;i++) c_buf[i] = auth_msg[(i*29)+5]; c_buf[13] = '\0'; if (strcmp(c_buf,p_buf)) { /* Bad message from child */ fprintf(stderr,"License error\n"); goto unlicensed; } /* valid message so we extract license type */ for(i=0;i<8;i++) c_buf[i] = auth_msg[(i*3)+37]; c_buf[8] = '\0'; sscanf(c_buf,"%x",&i); *appLic = (LicenseTypeEnum)(0xffff & (i^child)); i = i >> 16; *funcLic = (LicenseTypeEnum)(0xffff & (i^child)); #if 000 fprintf(stderr,"c_buf = '%s', funcLic = 0x%x, appLic = 0x%x\n", c_buf,*funcLic,*appLic); #endif const char* lic_name; switch (*funcLic) { case DeveloperLicense: lic_name = "DX development"; break; case RunTimeLicense: lic_name = "DX run-time"; break; default: fprintf(stderr,"Unrecognized license\n"); goto unlicensed; break; } switch (*appLic) { case NodeLockedLicense: #ifdef DEBUG fprintf(stderr,"Got nodelocked %s license\n",lic_name); #endif return; case ConcurrentLicense: #ifdef DEBUG fprintf(stderr,"Got concurrent %s license\n",lic_name); #endif XtAppAddInput(theIBMApplication->getApplicationContext(), child_out[0], (XtPointer)(XtInputReadMask), lostLicense, (XtPointer)NULL); return ; case Unlicensed: #ifdef DEBUG fprintf(stderr,"Could not get a license\n"); #endif break; default: /* invalid license type */ #ifdef DEBUG fprintf(stderr,"License Error: Invalid License Type\n"); #endif goto unlicensed; } unlicensed: *appLic = Unlicensed; *funcLic = Unlicensed; return; #endif // NEEDS_LICENSE_ROUTINES } /* This function creates the message which will tell the exec if it * is OK to run without a license. inkey must be at least char[14] * and should contain the key returned from the $getkey. type * should be either ConcurrentLicense or NodeLockedLicense. On return * inkey holds the string to send to the exec with $license. * The returned string must be freed by the caller. */ char *GenerateExecKey(const char *inkey, LicenseTypeEnum licenseType) { #if NEEDS_LICENSE_ROUTINES int i; char keybuf[64]; char cryptbuf[64]; char salt[8]; for(i=0;i<4;i++) keybuf[i*2]=inkey[i]; keybuf[1] = 'g'; keybuf[3] = '3'; keybuf[5] = '$'; keybuf[7] = 'Q'; keybuf[8] = '\0'; salt[0] = '4'; salt[1] = '.'; salt[2] = '\0'; strcpy(cryptbuf,CRYPT(keybuf,salt)); char *outkey = new char[64]; sprintf(outkey,"%s%hx",cryptbuf, (unsigned short)licenseType ^ (*((unsigned char *)&cryptbuf[4])<<8)+(*((unsigned char *)&cryptbuf[5]))); return outkey; #else return NULL; #endif // NEEDS_LICENSE_ROUTINES } #if NEEDS_LICENSE_ROUTINES #define KEY1 "a9" #define KEY2 "Pp" #if defined(aviion) || defined(solaris) #include #if defined(aviion) extern "C" { long sysinfo (int command, char *buf, long count); } #endif #endif #ifdef alphax extern "C" int gethostid(void); #endif static int checkexp(const char *root) { #if !DXD_HAS_CRYPT return (1); #else int host_match; char key[32]; char cryptHost[1024]; char cryptTime[1024]; char host[512]; time_t timeOut; int i; char *myCryptHost; struct timeval sysTime; #if defined(ibm6000) || defined(hp700) struct utsname name; #endif #if defined(sgi) || defined(sun4) || defined (alphax) long name; #endif time_t time; char fileName[1024]; FILE *f; for (i = 0; i < sizeof(key); ++i) key[i] = '\0'; #ifdef ibm6000 #define FOUND_ID 1 uname(&name); name.machine[10] = '\0'; strcpy(host, name.machine+2); #endif #if hp700 #define FOUND_ID 1 uname(&name); name.idnumber[10] = '\0'; strcpy(host, name.idnumber+2); #endif #if sgi /* sgi does not like #if...#elif..#endif construct */ #define FOUND_ID 1 name = sysid(NULL); sprintf(host, "%d", name); strcpy(host, host+2); #endif #if sun4 #define FOUND_ID 1 name = gethostid(); sprintf(host, "%x", name); #endif #if aviion #define FOUND_ID 1 sysinfo(SI_HW_SERIAL,host,301); #endif #if solaris #define FOUND_ID 1 sysinfo(SI_HW_SERIAL,host,301); sprintf(host, "%x", atol(host)); #endif #if defined(alphax) #ifdef SYSINFO_WORKS // The man page for OSF/1 V2 says that SI_HW_SERIAL does not work. We'll use it // for now even though it doesn't work. So far it looks like the only mechanism // to get unique ids. sysinfo(SI_HW_SERIAL,host,301); sprintf(host, "%x", atol(host)); #else { char *device; char *dflt_devices[] = {"tu0","ln0", NULL }; int s,i; /* On Alpha OSF/1 we use ethernet */; /* Get a socket */ strcpy(host,""); s = socket(AF_INET,SOCK_DGRAM,0); if (s < 0) { perror("socket"); } else { for (i=0, device=(char*)getenv("DXKEYDEVICE"); dflt_devices[i]; i++) { static struct ifdevea devea; /* MAC address from and ioctl() */ char *dev, buf[32]; if (!device) dev = dflt_devices[i]; else dev = device; strcpy(devea.ifr_name,dev); if (ioctl(s,SIOCRPHYSADDR,&devea) >= 0) { strcpy(host,""); for (i = 2; i < 6; i++){ sprintf(buf,"%x", devea.default_pa[i] ); strcat(host,buf); } break; } if (device) break; } close(s); } } #endif #define FOUND_ID 1 #endif #if !defined(FOUND_ID) Trial version not supported on this architecture. #else # undef FOUND_ID #endif gettimeofday(&sysTime, NULL); time = sysTime.tv_sec; if (getenv("DXTRIALKEY")) { char *k = getenv("DXTRIALKEY"); fprintf(stderr, "Data Explorer trial password found in" " DXTRIALKEY environment variable\n"); strncpy(key,k,27); key[27] = '\0'; // Make sure it is terminated } else { char *fname; fname = getenv("DXTRIALKEYFILE"); if (!fname) { sprintf(fileName, "%s/expiration", root); fname = fileName; } f = fopen(fname, "r"); if (f) { fprintf(stderr, "Data Explorer trial password found in file %s\n", fname); fgets(key, 27, f); fclose(f); } else { return 0; } } if (strlen(key) != 26) { fprintf(stderr, "You are running an expired Trial version of Data Explorer\n"); return(0); } for (i = 0; i < 13; ++i) { cryptHost[i] = key[2 * i]; cryptTime[i] = key[2 * i + 1]; } cryptHost[i] = key[2 * i] = '\0'; cryptTime[i] = key[2 * i + 1] = '\0'; if (cryptTime[0] != 'A' || cryptTime[10] != '9' || cryptTime[12] != 'D') { fprintf(stderr, "You are running an Expired trial version of Data Explorer\n"); return(0); } myCryptHost = (char*)CRYPT(host,KEY1); host_match = strcmp(cryptHost, myCryptHost) == 0; if (!host_match) { myCryptHost = (char*)CRYPT(ANYWHERE_HOSTID,KEY1); host_match = strcmp(cryptHost, myCryptHost) == 0; } if (!host_match) { fprintf(stderr, "You are running a trial version of Data Explorer on an" " unlicensed host\n"); return (0); } if(cryptTime[1]=='s') sscanf(cryptTime, "As%08x95D", &timeOut); else if (cryptTime[1]=='m') sscanf(cryptTime, "Am%08x9lD", &timeOut); timeOut ^= 0x12345678; if (time > timeOut) { fprintf(stderr, "You are running an expired trial version of Data Explorer\n"); fprintf(stderr,"This trial key expired on %s", ctime(&timeOut)); return (0); } fprintf(stderr,"This Data Explorer trial key will expire on %s", ctime(&timeOut)); return (1); #endif /* DXD_HAS_CRYPT */ } #ifdef ibm6000 // Some very strange declarations that allow AIX 3.2.4 systems to link. // These symbols are statics inside of "crypt.c" in /usr/lib/libc.a, but // are referenced in the mapping defined for the shared library. Therefore, // the system won't link without them. extern "C" char __setkey[1024]; extern "C" char __crypt[1024]; extern "C" char __encrypt[1024]; char __setkey[1024]; char __crypt[1024]; char __encrypt[1024]; #endif #endif // NEEDS_LICENSE_ROUTINES #else // DXD_WIN #include #include static int getregval(char *name, char *value) { char key[500]; int valtype; unsigned long sizegot = 500; int word; char errstr[200]; HKEY hkey[10]; long rc; int i, k=0; #define iferror(s) \ if (rc != ERROR_SUCCESS) { \ strcpy(errstr, s); \ goto error; \ } strcpy(value, ""); word = 0; strcpy(key, "SOFTWARE"); rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR) key, 0, KEY_QUERY_VALUE, &hkey[k++]); strcat(key, "\\OpenDX"); rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR) key, 0, KEY_QUERY_VALUE, &hkey[k++]); iferror("Error opening key"); strcat(key, "\\Open Visualization Data Explorer"); rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR) key, 0, KEY_QUERY_VALUE, &hkey[k++]); iferror("Error opening key"); strcat(key, "\\CurrentVersion"); rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR) key, 0, KEY_QUERY_VALUE, &hkey[k++]); iferror("Error opening key"); rc = RegQueryValueEx(hkey[k-1], (LPTSTR) name, (LPDWORD) 0, (LPDWORD) &valtype, (LPBYTE) value, &sizegot); iferror("Query value failed"); for (i=k; i > 0; i--) { rc = RegCloseKey(hkey[i-1]); iferror("CloseKey failed"); } switch(valtype) { case REG_DWORD: word = *((int *)value); value = ""; break; case REG_SZ: break; default: return 0; } return 1; error: fprintf(stderr, "%s: rc = %d\n", errstr, rc); return 0; } static int keyformat(char *k) { int i; char buf[25]; char *p; for (i=0, p=k; *p && i<20; p++) { if (isalpha(*p)) buf[i++] = tolower(*p); if (isdigit(*p)) buf[i++] = *p; if (i==5 || i==10 || i==15) buf[i++] = ' '; } buf[i] = '\0'; if (strlen(buf) != 20) return 0; strcpy(k, buf); return 1; } int getuserinforeg(char *username, char *userco, char *keystr) { *username = '\0'; *userco = '\0'; *keystr = '\0'; getregval("UserName", username); getregval("CompanyName", userco); getregval("LicenseKey", keystr); keyformat(keystr); return 1; } static int gettimenow(int *m, int *d, int *y) { SYSTEMTIME t; GetSystemTime(&t); *m = t.wMonth; *d = t.wDay; *y = t.wYear; return 1; } static int addtotime(int *m, int *d, int *y) { int mm, dd, yy; gettimenow(&mm, &dd, &yy); *y += yy; *m += mm; if (*m>12) { *y += (*m-1)/12; *m = *m%12 + 1; } *d += dd; if (*d > 28) { (*m)++; *d = *d%31; } if (*m>12) { *y += (*m-1)/12; *m = *m%12 + 1; } return 1; } static int genkey(char *keystr, char *username, char *userco, int m, int d, int y, char lictype) { char *p, *q; unsigned int key, key1, key2, key3, prime; int i; char data[500]; data[0] = (char)(m + (int)'a'); if (d > 20) data[0] = (char)((int)data[0] + 13); data[1] = (char)(d%20 + (int)'b'); data[2] = (char)((y - 1994)/10 + (int)'g'); data[3] = (char)((y - 1994)%10 + (int)'m'); if (!lictype) lictype = 't'; data[4] = lictype; q = &data[5]; for (p=username; *p; p++) if (!isspace(*p) && !ispunct(*p)) *(q++) = tolower(*p); for (p=userco; *p; p++) if (!isspace(*p) && !ispunct(*p)) *(q++) = tolower(*p); *q = '\0'; key = 99; key = key * 100 + 99; key = key * 100 + 83; prime = 4999; prime = prime * 1000 + 999; for (i = 0, p=data; *p; p++, i++) key += (*p * (i + key)) * prime; key %= 10000000000; key1 = key/100000000; key2 = key%100000000; key2 /= 10000; key3 = key%10000; sprintf(keystr, "%c%c%c%c%c %04d %04d %04d", data[0], data[1], data[2], data[3], data[4], key1, key2, key3); return 1; } int getdatefromkey(char *keystr, int *m, int *d, int *y) { *m = (int)keystr[0] - (int)'a'; *d = (int)keystr[1] - (int)'b'; if (*m > 12) { *m -= 13; *d += 20; } if (*d < 1) *d = 1; if (*d > 31) *d == 31; *y = ((int)keystr[2] - (int)'g') * 10 + (int)keystr[3] - (int)'m' + 1994; return 1; } static int isexpired(char *keystr) { int m, d, y; int ms, ds, ys; gettimenow(&ms, &ds, &ys); getdatefromkey(keystr, &m, &d, &y); if (ys > y) return 1; if (ys == y && ms > m) return 1; if (ys == y && ms == m && ds > d) return 1; return 0; } void UIGetLicense(const char *root, XtInputCallbackProc lostLicense, LicenseTypeEnum *appLic, LicenseTypeEnum *funcLic) { char username[200]; char userco[200]; char keystrreg[100]; char keystr[100]; char lictype; int m; int d; int y; int expired; *appLic = Unlicensed; *funcLic = Unlicensed; getuserinforeg(username, userco, keystrreg); if (strlen(username) + strlen(userco) < 6) { fprintf(stderr, "Improper registration: short username and company\n"); return; } if (!keyformat(keystrreg)) { fprintf(stderr, "Improper registration: registration key is not in proper format: %s\n", keystrreg); return; } fprintf(stderr, "Registered to %s of %s\n", username, userco); getdatefromkey(keystrreg, &m, &d, &y); lictype = keystrreg[4]; genkey(keystr, username, userco, m, d, y, lictype); if (strcmp(keystr, keystrreg)) { fprintf(stderr, "Improper registration: key does not match user setup\n"); return; } expired = isexpired(keystrreg); if (expired) { fprintf(stderr, "Registration expired %d/%d/%d\n", m, d, y); return; } // Don't show expire date if license isn't beta or trial if (lictype == 'b' || lictype == 't') fprintf(stderr, "Registration expires %d/%d/%d\n", m, d, y); if (lictype == 'r') { *appLic = NodeLockedLicense; *funcLic = RunTimeLicense; } else { *appLic = FullyLicensed; *funcLic = DeveloperLicense; } return; } char *GenerateExecKey(const char *inkey, LicenseTypeEnum licenseType) { return "No License Generated"; } #endif // DXD_WIN