FAST: error handling and const keyblock
[krb5.git] / src / lib / win_glue.c
1 #include "k5-int.h"
2
3 #ifdef KRB5
4 #include "krb5_err.h"
5 #include "kv5m_err.h"
6 #include "asn1_err.h"
7 #include "kdb5_err.h"
8 #include "profile.h"
9 extern void krb5_stdcc_shutdown();
10 #endif
11 #ifdef GSSAPI
12 #include "gssapi/generic/gssapi_err_generic.h"
13 #include "gssapi/krb5/gssapi_err_krb5.h"
14 #endif
15
16
17 /*
18  * #defines for MIT-specific time-based timebombs and/or version
19  * server for the Kerberos DLL.
20  */
21
22 #ifdef SAP_TIMEBOMB
23 #define TIMEBOMB 865141200      /* 1-Jun-97 */
24 #define TIMEBOMB_PRODUCT "SAPGUI"
25 #define TIMEBOMB_WARN  15
26 #define TIMEBOMB_INFO "  Please see the web page at:\nhttp://web.mit.edu/reeng/www/saphelp for more information"
27 #define TIMEBOMB_ERROR KRB5_APPL_EXPIRED
28 #endif
29
30 #ifdef KRB_TIMEBOMB
31 #define TIMEBOMB 865141200      /* 1-Jun-97 */
32 #define TIMEBOMB_PRODUCT "Kerberos V5"
33 #define TIMEBOMB_WARN 15
34 #define TIMEBOMB_INFO "  Please see the web page at:\nhttp://web.mit.edu/reeng/www/saphelp for more information"
35 #define TIMEBOMB_ERROR KRB5_LIB_EXPIRED
36 #endif
37
38 /*
39  * #defines for using MIT's version server DLL
40  */
41 #ifdef SAP_VERSERV
42 #define APP_TITLE "KRB5-SAP"
43 #define APP_VER "3.0f"
44 #define APP_INI "krb5sap.ini"
45 #define VERSERV_ERROR   KRB5_APPL_EXPIRED
46 #endif
47
48 #ifdef VERSERV
49 #define WINDOWS
50 #include <ver.h>
51 #include <vs.h>
52 #include <v.h>
53
54
55 /*
56  * This function will get the version resource information from the
57  * application using the DLL.  This allows us to Version Serve
58  * arbitrary third party applications.  If there is an error, or we
59  * decide that we should not version check the calling application
60  * then VSflag will be FALSE when the function returns.
61  *
62  * The buffers passed into this function must be at least
63  * APPVERINFO_SIZE bytes long.
64  */
65
66 #define APPVERINFO_SIZE 256
67
68 void GetCallingAppVerInfo( char *AppTitle, char *AppVer, char *AppIni,
69                           BOOL *VSflag)
70 {
71         char CallerFilename[_MAX_PATH];
72         LONG *lpLangInfo;
73         DWORD hVersionInfoID, size;
74         GLOBALHANDLE hVersionInfo;
75         LPSTR lpVersionInfo;
76         int dumint, retval;
77         char *cp;
78         char *revAppTitle;
79         char szVerQ[90];
80         LPBYTE locAppTitle;
81         LPBYTE locAppVer;
82         char locAppIni[_MAX_PATH];
83 #ifndef _WIN32
84         WORD wStackSeg;
85 #endif /* !_WIN32 */
86
87         /* first we need to get the calling module's filename */
88 #ifndef _WIN32
89         _asm {
90                 mov wStackSeg, ss
91         };
92         retval = GetModuleFileName((HMODULE)wStackSeg, CallerFilename,
93                 _MAX_PATH);
94 #else
95         /*
96          * Note: this may only work for single threaded applications,
97          * we'll live and learn ...
98          */
99         retval = GetModuleFileName( NULL, CallerFilename, _MAX_PATH);
100 #endif
101
102         if ( retval == 0 ) {
103                 VSflag = FALSE;
104                 return;
105         }
106
107         size = GetFileVersionInfoSize( CallerFilename, &hVersionInfoID);
108
109         if( size == 0 ) {
110                 /*
111                  * hey , I bet we don't have a version resource, let's
112                  * punt
113                  */
114 #if 0
115                 /* let's see what we have? (1813 means no resource) */
116                 size = GetLastError();          /*  WIN32 only */
117 #endif
118                 *VSflag = FALSE;
119                 return;
120         }
121
122         hVersionInfo = GlobalAlloc(GHND, size);
123         lpVersionInfo = GlobalLock(hVersionInfo);
124
125         retval = GetFileVersionInfo( CallerFilename, hVersionInfoID, size,
126                                     lpVersionInfo);
127
128         retval = VerQueryValue(lpVersionInfo, "\\VarFileInfo\\Translation",
129                                (LPSTR *)&lpLangInfo, &dumint);
130         wsprintf(szVerQ,
131                  "\\StringFileInfo\\%04x%04x\\",
132                  LOWORD(*lpLangInfo), HIWORD(*lpLangInfo));
133
134         cp = szVerQ + lstrlen(szVerQ);
135
136         lstrcpy(cp, "ProductName");
137
138
139         /* try a localAppTitle and then a strcpy 4/2/97 */
140
141         locAppTitle = 0;
142         locAppVer = 0;
143
144         retval = VerQueryValue(lpVersionInfo, szVerQ, &locAppTitle,
145                                &dumint);
146
147         lstrcpy(cp, "ProductVersion");
148
149
150         retval = VerQueryValue(lpVersionInfo, szVerQ, &locAppVer,
151                                &dumint);
152
153         if (!locAppTitle || !locAppVer) {
154                 /* Punt, we don't have the right version resource records */
155                 *VSflag = FALSE;
156                 return;
157         }
158
159         /*
160          * We don't have a way to determine that INI file of the
161          * application at the moment so let's just use krb5.ini
162          */
163         strncpy( locAppIni, KERBEROS_INI, sizeof(locAppIni) - 1 );
164         locAppIni[ sizeof(locAppIni) - 1 ] = '\0';
165
166         strncpy( AppTitle, locAppTitle, APPVERINFO_SIZE);
167         AppTitle[APPVERINFO_SIZE - 1] = '\0';
168         strncpy( AppVer, locAppVer, APPVERINFO_SIZE);
169         AppVer[APPVERINFO_SIZE - 1] = '\0';
170         strncpy( AppIni, locAppIni, APPVERINFO_SIZE);
171         AppIni[APPVERINFO_SIZE - 1] = '\0';
172
173         /*
174          * We also need to determine if we want to suppress version
175          * checking of this application.  Does the tail of the
176          * AppTitle end in a "-v" ?
177          */
178         revAppTitle = _strrev( _strdup(AppTitle));
179         if( revAppTitle[0] == 'v' || revAppTitle[0] == 'V'  &&
180            revAppTitle[1] == '-' ) {
181                 VSflag = FALSE;
182         }
183         return;
184 }
185
186
187 /*
188  * Use the version server to give us some control on distribution and usage
189  * We're going to test track as well
190  */
191 static int CallVersionServer(app_title, app_version, app_ini, code_cover)
192         char *app_title;
193         char *app_version;
194         char *app_ini;
195         char *code_cover;
196 {
197         VS_Request vrequest;
198         VS_Status  vstatus;
199
200         SetCursor(LoadCursor(NULL, IDC_WAIT));
201
202         /*
203          * We should be able to pass in code_cover below, but things
204          * are breaking under Windows 16 for no good reason.
205          */
206         vrequest = VSFormRequest((LPSTR) app_title, (LPSTR) app_version,
207                                  (LPSTR) app_ini,
208                                  NULL /* code_cover */, NULL,
209                                  V_CHECK_AND_LOG);
210
211         SetCursor(LoadCursor(NULL, IDC_ARROW));
212         /*
213          * If the user presses cancel when registering the test
214          * tracker, we'll let them continue.
215          */
216         if (ReqStatus(vrequest) == V_E_CANCEL) {
217                 VSDestroyRequest(vrequest);
218                 return 0;
219         }
220         vstatus = VSProcessRequest(vrequest);
221         /*
222          * Only complain periodically, if the test tracker isn't
223          * working...
224          */
225         if (v_complain(vstatus, app_ini)) {
226                 WinVSReportRequest(vrequest, NULL,
227                                    "Version Server Status Report");
228         }
229         if (vstatus == V_REQUIRED) {
230                 SetCursor(LoadCursor(NULL, IDC_WAIT));
231                 VSDestroyRequest(vrequest);
232                 return( -1 );
233         }
234         VSDestroyRequest(vrequest);
235         return (0);
236 }
237 #endif
238
239 #ifdef TIMEBOMB
240 static krb5_error_code do_timebomb()
241 {
242         char buf[1024];
243         long timeleft;
244         static first_time = 1;
245
246         timeleft = TIMEBOMB - time(0);
247         if (timeleft <= 0) {
248                 if (first_time) {
249                         sprintf(buf, "Your version of %s has expired.\n",
250                                 TIMEBOMB_PRODUCT);
251                         buf[sizeof(buf) - 1] = '\0';
252                         strncat(buf, "Please upgrade it.", sizeof(buf) - 1 - strlen(buf));
253 #ifdef TIMEBOMB_INFO
254                         strncat(buf, TIMEBOMB_INFO, sizeof(buf) - 1 - strlen(buf));
255 #endif
256                         MessageBox(NULL, buf, "", MB_OK);
257                         first_time = 0;
258                 }
259                 return TIMEBOMB_ERROR;
260         }
261         timeleft = timeleft / ((long) 60*60*24);
262         if (timeleft < TIMEBOMB_WARN) {
263                 if (first_time) {
264                         sprintf(buf, "Your version of %s will expire in %ld days.\n",
265                                 TIMEBOMB_PRODUCT, timeleft);
266                         strncat(buf, "Please upgrade it soon.", sizeof(buf) - 1 - strlen(buf));
267 #ifdef TIMEBOMB_INFO
268                         strncat(buf, TIMEBOMB_INFO, sizeof(buf) - 1 - strlen(buf));
269 #endif
270                         MessageBox(NULL, buf, "", MB_OK);
271                         first_time = 0;
272                 }
273         }
274         return 0;
275 }
276 #endif
277
278 /*
279  * This was originally called from LibMain; unfortunately, Windows 3.1
280  * doesn't allow you to make messaging calls from LibMain.  So, we now
281  * do the timebomb/version server stuff from krb5_init_context().
282  */
283 krb5_error_code krb5_vercheck()
284 {
285         static int verchecked = 0;
286         if (verchecked)
287                 return 0;
288 #ifdef TIMEBOMB
289         krb5_error_code retval = do_timebomb();
290         if (retval)
291                 return retval;
292 #endif
293 #ifdef VERSERV
294 #if 0
295         /* Check library ? */
296         if (CallVersionServer(APP_TITLE, APP_VER, APP_INI, NULL))
297                 return KRB5_LIB_EXPIRED;
298 #endif
299         {
300 #ifdef APP_TITLE
301                 if (CallVersionServer(APP_TITLE, APP_VER, APP_INI, NULL))
302                         return VERSERV_ERROR;
303 #else
304                 char AppTitle[APPVERINFO_SIZE];
305                 char AppVer[APPVERINFO_SIZE];
306                 char AppIni[APPVERINFO_SIZE];
307                 BOOL VSflag=TRUE;
308
309                 GetCallingAppVerInfo( AppTitle, AppVer, AppIni, &VSflag);
310
311                 if (VSflag) {
312                         if (CallVersionServer(AppTitle, AppVer, AppIni, NULL))
313                                 return KRB5_APPL_EXPIRED;
314                 }
315 #endif
316
317         }
318 #endif
319         verchecked = 1;
320         return 0;
321 }
322
323
324 static HINSTANCE hlibinstance;
325
326 HINSTANCE get_lib_instance()
327 {
328     return hlibinstance;
329 }
330
331 #define DLL_STARTUP 0
332 #define DLL_SHUTDOWN 1
333
334 static int
335 control(int mode)
336 {
337     switch(mode) {
338     case DLL_STARTUP:
339         break;
340
341     case DLL_SHUTDOWN:
342 #ifdef KRB5
343         krb5_stdcc_shutdown();
344 #endif
345         break;
346
347 #if defined(ENABLE_THREADS) && defined(SUPPORTLIB)
348     case DLL_THREAD_DETACH:
349         krb5int_thread_detach_hook();
350         return 0;
351 #endif
352
353     default:
354         return -1;
355     }
356
357 #if defined KRB5
358     switch (mode) {
359     case DLL_STARTUP:
360         profile_library_initializer__auxinit();
361         cryptoint_initialize_library__auxinit();
362         krb5int_lib_init__auxinit();
363         break;
364     case DLL_SHUTDOWN:
365         krb5int_lib_fini();
366         cryptoint_cleanup_library();
367         profile_library_finalizer();
368         break;
369     }
370 #elif defined GSSAPI
371     switch (mode) {
372     case DLL_STARTUP:
373         gssint_mechglue_init__auxinit();
374         break;
375     case DLL_SHUTDOWN:
376         gssint_mechglue_fini();
377         break;
378     }
379 #elif defined COMERR
380     switch (mode) {
381     case DLL_STARTUP:
382         com_err_initialize__auxinit();
383         break;
384     case DLL_SHUTDOWN:
385         com_err_terminate();
386         break;
387     }
388 #elif defined PROFILELIB
389     switch (mode) {
390     case DLL_STARTUP:
391         profile_library_initializer__auxinit();
392         break;
393     case DLL_SHUTDOWN:
394         profile_library_finalizer();
395         break;
396     }
397 #elif defined SUPPORTLIB
398     switch (mode) {
399     case DLL_STARTUP:
400       krb5int_thread_support_init__auxinit();
401       break;
402     case DLL_SHUTDOWN:
403       krb5int_thread_support_fini();
404       break;
405     }
406 #else
407 # error "Don't know the init/fini functions for this library."
408 #endif
409
410     return 0;
411 }
412
413 #ifdef _WIN32
414
415 BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
416 {
417     switch (fdwReason)
418     {
419         case DLL_PROCESS_ATTACH:
420             hlibinstance = (HINSTANCE) hModule;
421             if (control(DLL_STARTUP))
422                 return FALSE;
423             break;
424
425         case DLL_THREAD_ATTACH:
426             break;
427
428         case DLL_THREAD_DETACH:
429             if (control(DLL_THREAD_DETACH))
430                 return FALSE;
431             break;
432
433         case DLL_PROCESS_DETACH:
434             if (control(DLL_SHUTDOWN))
435                 return FALSE;
436             break;
437
438         default:
439             return FALSE;
440     }
441
442     return TRUE;   // successful DLL_PROCESS_ATTACH
443 }
444
445 #else
446
447 BOOL CALLBACK
448 LibMain (hInst, wDataSeg, cbHeap, CmdLine)
449 HINSTANCE hInst;
450 WORD wDataSeg;
451 WORD cbHeap;
452 LPSTR CmdLine;
453 {
454     hlibinstance = hInst;
455     if (control(DLL_STARTUP))
456         return 0;
457     else
458         return 1;
459 }
460
461 int CALLBACK __export
462 WEP(nParam)
463         int nParam;
464 {
465     if (control(DLL_SHUTDOWN))
466         return 0;
467     else
468         return 1;
469 }
470
471 #endif