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