1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10
11
12 /* this has to be before the ifdef, because it defines DXD_LICENSED_VERSION
13 * if this arch supports the license manager.
14 */
15 #include <dx/dx.h>
16
17 #if defined(HAVE_CRYPT_H)
18 #include <crypt.h>
19 #endif
20
21 #if defined(HAVE_TIME_H)
22 #include <time.h>
23 #endif
24
25 #include <stdio.h>
26
27 #if defined(HAVE_STRING_H)
28 #include <string.h>
29 #define DXD_STLIB_INCLUDES
30 #endif
31
32 #if defined(HAVE_TIME_H)
33 #include <time.h>
34 #endif
35
36 #if defined(HAVE_STDLIB_H)
37 #include <stdlib.h>
38 #endif
39
40 #if defined(HAVE_STRING_H)
41 #include <string.h>
42 #endif
43
44 #if defined(HAVE_SYS_STAT_H)
45 #include <sys/stat.h>
46 #endif
47
48 #if defined(HAVE_SYS_TYPES_H)
49 #include <sys/types.h>
50 #endif
51
52 #if defined(HAVE_SYS_TIMEB_H)
53 #include <sys/timeb.h>
54 #endif
55
56 #if defined(HAVE_SYS_TIME_H)
57 #include <sys/time.h>
58 #endif
59
60 #include "config.h"
61
62 #ifdef DXD_LICENSED_VERSION
63 #include "license.h"
64
65 #define NL_LIC 1
66 #define CON_LIC 2
67
68 static int shadow_fd_dxlic = -1;
69 static int shadow_fd_mplic = -1;
70 static int trial_file_exists = FALSE;
71 static int MPlic_tried = FALSE;
72 struct lic_info {
73 int child;
74 int type;
75 };
76 struct lic_info dxlic = {-1, -1};
77 struct lic_info mplic = {-1, -1};
78
79 static Error system_hostname(char *buf);
80 static Error checkexp(char *root, lictype ltype);
81 static char messagebuf[1024];
82
_dxfCheckLicenseChild(int child)83 int _dxfCheckLicenseChild(int child)
84 {
85 if ( child == dxlic.child) {
86 if(dxlic.type == NL_LIC)
87 return(0);
88 return(child);
89 }
90 else if ( child == mplic.child) {
91 if(mplic.type == NL_LIC)
92 return(0);
93 return(child);
94 }
95 else
96 return(-1);
97 }
98
ExLicenseDied(int fd,Pointer junk)99 Error ExLicenseDied(int fd, Pointer junk)
100 {
101 /* We should only be called if dxshadow dies, */
102 /* then send UNAUTHORIZED MESSAGE to UI */
103 /* or die if were in script mode */
104
105
106 DXRegisterInputHandler(NULL, fd, NULL);
107
108 if ( fd == shadow_fd_dxlic)
109 DXMessage("License Error: Exec lost DX license and is terminating\n");
110 else if ( fd == shadow_fd_mplic)
111 DXMessage("License Error: Exec lost MP license and is terminating\n");
112 else
113 DXMessage("License Error: unknown license error\n");
114
115 _dxd_ExHasLicense = FALSE;
116 if (_dxd_exRemote) {
117 DXUIMessage("LICENSE","UNAUTHORIZED");
118 return OK;
119 }
120
121 if(_dxd_exTerminating) {
122 *_dxd_exTerminating = TRUE;
123 return (-1);
124 }
125 /* when _dxd_exTerminating is NULL we are being called from the */
126 /* developer's kit, just exit */
127 exit(-1);
128
129 /* NOTREACHED */
130 }
131
_dxf_ExReleaseLicense()132 void _dxf_ExReleaseLicense()
133 {
134 if(shadow_fd_dxlic >= 0)
135 close(shadow_fd_dxlic);
136 if(shadow_fd_mplic >= 0)
137 close(shadow_fd_mplic);
138 }
139
140
ExGetLicense(lictype ltype,int forceNetLS)141 Error ExGetLicense(lictype ltype, int forceNetLS)
142 {
143 int i;
144 int child;
145 int pid;
146 int in[2],out[2];
147 char remname[256];
148 char auth_msg[AUTH_MSG_LEN];
149 char ckey[9];
150 char c_buf[32],p_buf[32]; /* hold crypted msgs for comaparison */
151 static char envbuf[32]; /* static 'cause it goes into the env */
152 char salt[3];
153 time_t timenow;
154
155
156 char *root = getenv ("DXEXECROOT");
157 if (root == NULL)
158 root = getenv ("DXROOT");
159 if (root == NULL)
160 root = "/usr/local/dx";
161
162 if (ltype == MPLIC) {
163 MPlic_tried = TRUE;
164 forceNetLS = FALSE;
165 }
166
167
168 strcpy(messagebuf,"");
169
170 if (checkexp (root, ltype)) /* check for an old syle trial license */
171 return OK;
172 else if ( ltype == MPLIC && trial_file_exists ) /* don't try to get an MP floating lic if DX lic */
173 return ERROR; /* is a uniprocessor nodelocked */
174
175 /* didn't find a trial license so spawn the NetLS licensing process */
176
177 /* Set up two pipes */
178 if (pipe(in) < 0) {
179 perror("pipe(in)");
180 exit (-1);
181 }
182 if (pipe(out) < 0) {
183 perror("pipe(out)");
184 exit (-1);
185 }
186
187 timenow = time(NULL);
188
189 sprintf(envbuf,"_DX_%d=", getpid());
190 sprintf(c_buf,"%x", timenow);
191 strcat(envbuf, c_buf+4);
192 putenv(envbuf);
193
194 #if DXD_HAS_VFORK
195 /* if it's available, use vfork() so we don't copy the entire data
196 * segment when forking - we are going to exec right away
197 * anyway so we aren't going to use anything from the data seg.
198 */
199 pid = vfork();
200 #else
201 pid = fork();
202 #endif
203 child = 0xFFFF & pid; /* force "child id" to be < 4 hex chars */
204
205 if (pid == 0) { /* Child */
206 char arg1[32], arg3[32];
207
208 if (in[1])
209 close (in[1]);
210 if (out[0])
211 close (out[0]);
212 if (dup2(in[0], 0) < 0) {
213 perror("dup2");
214 exit (-1);
215 }
216 if (dup2(out[1], 1) < 0) {
217 perror("dup2");
218 exit (-1);
219 }
220
221 /* should we close other file descriptors here ? */
222
223 if (getenv("DXSHADOW"))
224 strcpy(remname,getenv("DXSHADOW"));
225 else
226 sprintf(remname,"%s/bin_%s/dxshadow",root,DXD_ARCHNAME);
227
228 switch (ltype) {
229 case MPLIC: strcpy(arg1,"-mp"); break;
230 case DXLIC: strcpy(arg1,"-dev"); break;
231 case RTLIC: strcpy(arg1,"-rt"); break;
232 case RTLIBLIC: strcpy(arg1,"-rtlib"); break;
233 default: sprintf(arg1,"%d",ltype); break;
234 }
235 if (forceNetLS)
236 strcat(arg1,"only");
237
238 sprintf(arg3,"%d.%d.%d", DXD_VERSION, DXD_RELEASE, DXD_MODIFICATION);
239 execlp(remname, "dxshadow", arg1 , "-version", arg3 ,NULL);
240
241 perror("Could not execute license process");
242 exit (-1);
243 }
244 else if (pid > 0) { /* parent */
245 int netls_type;
246 const char *lic_name;
247 if (in[0])
248 close (in[0]);
249 if (out[1])
250 close (out[1]);
251
252 /* wait for response from the child */
253 i = read (out[0], auth_msg, AUTH_MSG_LEN);
254 if (i != AUTH_MSG_LEN) {
255 perror ("License Error:Bad message read from dxshadow");
256 exit (-1);
257 }
258
259 if (ltype == MPLIC)
260 mplic.child = child;
261 else
262 dxlic.child = child;
263
264 /* decipher license message here */
265
266 child = (child < 4096) ? (child+4096)
267 : (child); /* forces to be 4 0x chars */
268
269 strcpy(ckey, c_buf+4);
270 sprintf(ckey+4, "%x", child);
271
272 salt[0] = '7';
273 salt[1] = 'q';
274 salt[2] = '\0';
275
276 strcpy(p_buf, crypt(ckey, salt));;
277
278 for(i=0;i<13;i++)
279 c_buf[i] = auth_msg[(i*29)+5];
280 c_buf[13] = '\0';
281
282 if (strcmp(c_buf, p_buf)) {
283 /* Bad message from child */
284 perror("License Error: invalid message from license process.");
285 exit (-1);
286 }
287
288 /* valid message so we extract license type */
289 for(i=0; i<8; i++)
290 c_buf[i] = auth_msg[(i*3)+37];
291
292 c_buf[8] = '\0';
293 sscanf(c_buf, "%x", &i);
294 netls_type = 0xffff & (i^child);
295 i = i >> 16;
296 ltype = 0xffff & (i^child);
297 #if LIC_DEBUG
298 fprintf(stderr,"Received...\n"
299 "c_buf = '%s', ltype = 0x%x, netls_type = 0x%x, mask = 0x%x\n",
300 c_buf,ltype,netls_type,child);
301 #endif
302
303 switch (ltype) {
304 case DXLIC: lic_name = "DX development"; break;
305 case RTLIC: lic_name = "DX run-time"; break;
306 case MPLIC: lic_name = "MP"; break;
307 case RTLIBLIC: lic_name = "DX Library run-time"; break;
308 default: return FALSE; break; /* bad license */
309 }
310
311 switch (netls_type) {
312
313 case GOT_NODELOCKED:
314
315 if (ltype == MPLIC) {
316 sprintf(messagebuf,"Exec got nodelocked %s license.",lic_name);
317 mplic.type = NL_LIC;
318 } else {
319 DXMessage("Exec got nodelocked %s license.", lic_name);
320 dxlic.type = NL_LIC;
321 _dxd_ExHasLicense = TRUE;
322 }
323 return OK;
324
325 case GOT_CONCURRENT:
326 /* do concurrent stuff here */
327
328 if (ltype == MPLIC) {
329 shadow_fd_mplic = out[0];
330 sprintf(messagebuf,"Exec got concurrent use %s license.",
331 lic_name);
332 /* we save message and will register input handler
333 * in ExLicenseFinish
334 * after it's safe to call DX routines
335 */
336 mplic.type = CON_LIC;
337 } else {
338 DXMessage("Exec got concurrent use %s license.",lic_name);
339 shadow_fd_dxlic = out[0];
340 DXRegisterInputHandler(ExLicenseDied,shadow_fd_dxlic,NULL);
341 dxlic.type = CON_LIC;
342 _dxd_ExHasLicense = TRUE;
343 }
344
345 return OK;
346
347 case GOT_NONE:
348
349 if (ltype == MPLIC)
350 sprintf(messagebuf,"Exec could not get a %s license,"
351 " running in uniprocessor mode.",lic_name);
352 else
353 DXMessage("Exec could not get a %s license.",lic_name);
354 return ERROR;
355
356 default:
357 /* invalid license type */
358 perror("License Error: Invalid message from license process.");
359 exit (-1);
360 }
361 }
362 else {
363 perror("fork");
364 exit (-1);
365 }
366
367 /* NOTREACHED */
368 }
369
370
371 /* finish the stuff that needs to happen after DXinit */
372 /* this is because GetLicense(MPLIC) is called before */
373 /* DXinit */
374
ExLicenseFinish()375 Error ExLicenseFinish()
376 {
377
378 if(!MPlic_tried)
379 return OK;
380
381 if (shadow_fd_mplic >= 0)
382 DXRegisterInputHandler(ExLicenseDied,shadow_fd_mplic,NULL);
383
384 if(_dxd_exRemoteSlave)
385 DXMessage("Host %s:%s",_dxd_exHostName,messagebuf);
386 else
387 DXMessage(messagebuf);
388
389 return OK;
390 }
391
ExGetPrimaryLicense()392 Error ExGetPrimaryLicense()
393 {
394 lictype lic;
395 int force;
396
397 if (_dxd_exForcedLicense == NOLIC) {
398 lic = DXLIC;
399 force = FALSE;
400 } else {
401 lic = _dxd_exForcedLicense;
402 force = TRUE;
403 }
404 return ExGetLicense(lic,force);
405 }
406
407
checkexp(char * root,lictype ltype)408 static Error checkexp(char *root, lictype ltype)
409 {
410 char key[KEY_LEN];
411 char cryptHost[HOST_LEN];
412 char cryptTime[HOST_LEN];
413 char host[HOST_LEN];
414 time_t timeOut;
415 int i;
416 char *myCryptHost;
417 int host_match;
418 time_t timenow;
419 char fileName[HOST_LEN];
420 char *key_location, key_location_buf[1024];
421 char *cp;
422 int suppresslicmsg = 0;
423 FILE *f;
424
425 for (i = 0; i < sizeof(key); ++i)
426 key[i] = '\0';
427
428 if (!system_hostname(host))
429 return ERROR;
430
431 timenow = time(NULL);
432
433 /* if the DXSTARTUP env var is set to one, we are running
434 * with a temp oneday trial key created by the startup ui.
435 * suppress the messages about a trial key or when it expires
436 * so the user can't tell how we are doing this.
437 */
438 cp = getenv("DXSTARTUP");
439 if (cp && (atoi(cp) == 1))
440 suppresslicmsg++;
441
442 if (getenv("DXTRIALKEY")) {
443 char *k = getenv("DXTRIALKEY");
444 key_location = "DXTRIALKEY environment variable";
445 strncpy(key,k,27);
446 key[27] = '\0'; /* Make sure it is terminated */
447 } else {
448 char *fname;
449 fname = getenv("DXTRIALKEYFILE");
450 if (!fname) {
451 sprintf(fileName, "%s/expiration", root);
452 fname = fileName;
453 }
454 f = fopen(fname, "r");
455 if (f) {
456 sprintf(key_location_buf,"file %s",fname);
457 key_location = key_location_buf;
458 fgets(key, 27, f);
459 fclose(f);
460 } else {
461 return ERROR;
462 }
463 }
464
465 if (!trial_file_exists) {
466 if (ltype == MPLIC) {
467 char buf[1024];
468 sprintf(buf,"Found Data Explorer trial password in %s.\n",
469 key_location);
470 if (!suppresslicmsg)
471 strcat(messagebuf,buf);
472 trial_file_exists = TRUE;
473 } else {
474 if (!suppresslicmsg)
475 DXMessage("Found Data Explorer trial password in %s.",key_location);
476 }
477 }
478
479
480 if (strlen(key) != 26) {
481 if (ltype == MPLIC)
482 strcat(messagebuf,"You are running an expired Trial version of Data Explorer.\n");
483 else
484 DXMessage("You are running an expired Trial version of Data Explorer.");
485
486 return ERROR;
487 }
488
489 for (i = 0; i < 13; ++i) {
490 cryptHost[i] = key[2 * i];
491 cryptTime[i] = key[2 * i + 1];
492 }
493 cryptHost[i] = key[2 * i] = '\0';
494 cryptTime[i] = key[2 * i + 1] = '\0';
495
496
497
498 if (ltype == MPLIC) {
499 if (cryptTime[0] != 'A' ||
500 cryptTime[10] != '9' ||
501 cryptTime[12] != 'D') {
502 strcat(messagebuf,"You are running an Expired trial version of Data Explorer.\n");
503 return ERROR;
504 }
505 if (cryptTime[1] != 'm' ||
506 cryptTime[11] != 'l' ) {
507 strcat(messagebuf,"Single processor trial key found, MP will not be enabled.\n");
508 return ERROR;
509 }
510 }
511 else if (cryptTime[0] != 'A' ||
512 cryptTime[10] != '9' ||
513 cryptTime[12] != 'D') {
514 DXMessage("You are running an Expired trial version of Data Explorer.");
515 return ERROR;
516 }
517
518 myCryptHost = crypt(host, KEY1);
519 host_match = strcmp(cryptHost, myCryptHost) == 0;
520 if (!host_match) {
521 myCryptHost = crypt(ANYWHERE_HOSTID, KEY1);
522 host_match = strcmp(cryptHost, myCryptHost) == 0;
523 }
524 if (!host_match) {
525 if (ltype == MPLIC)
526 strcat(messagebuf,
527 "you are running a trial version of Data Explorer"
528 " on an unlicensed host\n");
529 else
530 DXMessage("You are running a trial version of Data Explorer"
531 " on an unlicensed host.");
532 return ERROR;
533
534 }
535
536 if(cryptTime[1]=='s')
537 sscanf(cryptTime, "As%08x95D", &timeOut);
538 else if (cryptTime[1]=='m')
539 sscanf(cryptTime, "Am%08x9lD", &timeOut);
540
541
542 timeOut ^= 0x12345678;
543
544 if (timenow > timeOut) {
545 if (ltype == MPLIC) {
546 strcat(messagebuf,
547 "You are running an expired trial version of Data Explorer.\n");
548 } else {
549 DXMessage("You are running an expired trial version of Data "
550 "Explorer.");
551 DXMessage("This trial key expired on %s", ctime(&timeOut));
552 }
553 return ERROR;
554 }
555
556 if (ltype != MPLIC) {
557 if (!suppresslicmsg)
558 DXMessage("This trial key expires on %s", ctime(&timeOut));
559 _dxd_ExHasLicense = TRUE;
560 }
561
562 return OK;
563 }
564
565
566
567
568 /* system specific way to return the hostname we use for the license
569 */
570
571 #if defined(alphax)
572 #include <stdio.h> /* standard I/O */
573 #include <errno.h> /* error numbers */
574 #endif
575
576 #if defined(HAVE_SYS_IOCTL_H)
577 #include <sys/ioctl.h> /* ioctls */
578 #endif
579
580 #if defined(HAVE_NET_IF_H)
581 #include <net/if.h> /* generic interface structures */
582 #endif
583
584 #if defined(HAVE_SYS_SYSTEMINFO_H)
585 #include <sys/systeminfo.h> /* maybe someday this will be implemented ...arg! */
586 #endif
587
588
589 #if defined(aviion) || defined(solaris)
590 #include <sys/systeminfo.h>
591 #endif
592 #if defined(ibm6000) || defined(hp700)
593 #include <sys/utsname.h>
594 #endif
595
system_hostname(char * host)596 static Error system_hostname(char *host)
597 {
598
599 #if defined(ibm6000) || defined(hp700)
600 struct utsname name;
601 #endif
602 #if defined(indigo) || defined(sun4) || defined(sgi)
603 long name;
604 #endif
605
606 #if ibm6000
607 #define FOUND_ID 1
608 uname(&name);
609 name.machine[10] = '\0';
610 strcpy(host, name.machine+2);
611 #endif
612 #if hp700
613 #define FOUND_ID 1
614 uname(&name);
615 name.idnumber[10] = '\0';
616 strcpy(host, name.idnumber+2);
617 #endif
618 #if indigo || sgi /* sgi does not like #if...#elif..#endif construct */
619 #define FOUND_ID 1
620 name = sysid(NULL);
621 sprintf(host, "%d", name);
622 strcpy(host, host+2);
623 #endif
624 #if sun4
625 #define FOUND_ID 1
626 name = gethostid();
627 sprintf(host, "%x", name);
628 #endif
629 #if aviion
630 #define FOUND_ID 1
631 sysinfo(SI_HW_SERIAL,host,301);
632 #endif
633 #if solaris
634 #define FOUND_ID 1
635 sysinfo(SI_HW_SERIAL,host,301);
636 sprintf(host, "%x", atol(host));
637 #endif
638 #if alphax
639 #define FOUND_ID 1
640 {
641 char *device;
642 char *dflt_devices[] = {"tu0","ln0", NULL };
643 int s,i /* On Alpha OSF/1 we use ethernet */;
644
645 /* Get a socket */
646 s = socket(AF_INET,SOCK_DGRAM,0);
647 strcpy(host,"");
648 if (s < 0) {
649 perror("socket");
650 } else {
651 for (i=0, device=(char*)getenv("DXKEYDEVICE"); dflt_devices[i]; i++) {
652 static struct ifdevea devea; /* MAC address from and ioctl()*/
653 char *dev, buf[32];
654 if (!device)
655 dev = dflt_devices[i];
656 else
657 dev = device;
658 strcpy(devea.ifr_name,dev);
659 if (ioctl(s,SIOCRPHYSADDR,&devea) >= 0) {
660 strcpy(host,"");
661 for (i = 2; i < 6; i++){
662 sprintf(buf,"%x", devea.default_pa[i] );
663 strcat(host,buf);
664 }
665 break;
666 }
667 if (device) break;
668 }
669 close(s);
670 }
671 }
672 #endif
673
674 #if !defined(FOUND_ID)
675 /* Trial version not supported on this architecture */
676 return ERROR;
677 #else
678 # undef FOUND_ID
679 #endif
680
681 return OK;
682 }
683
684 #endif /* DXD_LICENSED_VERSION */
685