windows-updates-20010819
[openafs.git] / src / WINNT / win9xpanel / CAfs.cpp
1 /* Copyright 2000, International Business Machines Corporation and others.
2         All Rights Reserved.
3  
4         This software has been released under the terms of the IBM Public
5         License.  For details, see the LICENSE file in the top-level source
6         directory or online at http://www.openafs.org/dl/license10.html
7 */
8
9 #include "stdafx.h"
10 #ifdef _MFC_VER
11 extern "C" {
12 #endif
13 #include <afs\param.h>
14 #include <afs\stds.h>
15 #include <afs\kautils.h>
16 #include "cm_config.h"
17 #include "cmd.h"
18 #ifdef _MFC_VER
19         }
20 #endif
21 #include "api95.h"
22 #include "cregkey.h"
23 #include "cafs.h"
24 #include <Svrapi.h>
25 #include "afsmsg95.h"
26
27 #include "WinAfsLoad.h"
28
29 #define AFS_KERBEROS_ENV
30
31 #ifndef KABADARGUMENT
32 #undef KABADARGUMENT
33 #define KABADARGUMENT 1
34 #endif
35 #define KLOGEXIT(code) exit(code)
36
37 #define LENDIR 128
38
39 //#define _DEBUG         
40
41 #ifdef _DEBUG
42 #define new DEBUG_NEW
43 #undef THIS_FILE
44 static char THIS_FILE[] = __FILE__;
45 #endif
46
47 #define HOURSLEFT 24
48
49 CProgress::CProgress(CWnd *wnd, UINT mode)
50 {
51         m_pWnd=wnd;
52         // you cannot obtain the handle to the window int these routines so you have enough time to create the window
53         PROGRESS(wnd,mode);
54 }
55
56 CProgress::~CProgress()
57 {
58         PROGRESS(NULL,ProgFHide);
59 }
60
61 void CProgress::SetTitle(const char *t1,const char *t2,const char *t3)
62 {
63         char *msg=new char[strlen(t1)+strlen(t2)+strlen(t3)+3];
64         strcpy(msg,t1);
65         strcpy(msg+strlen(t1)+1,t2);
66         strcpy(msg+strlen(t1)+strlen(t2)+2,t3);
67         PROGRESS(msg,ProgFSetTitle);
68 }
69
70 void CProgress::Next()
71 {
72         PROGRESS(m_pWnd,ProgFNext);
73 }
74
75 void CProgress::Finish()
76 {
77         PROGRESS(NULL,ProgFHide);
78 }
79
80
81 CAfs::~CAfs()
82 {
83         // let the OS kill the progress bar thread
84 }
85
86 void CAfs::FinishProgress()
87 {
88         PROGRESS(NULL,ProgFHide);
89 }
90
91 BOOL CALLBACK CAfs::EnumWindowsProcShutdown(HWND hWnd, LPARAM lParam)
92 {
93         CWnd *wnd=CWnd::FromHandle(hWnd);
94         CString msg;
95         CString sFinish;
96         wnd->GetWindowText(msg);
97         if (msg==m_sDosAppName)
98                 m_hAfsLoad=hWnd;
99         sFinish.Format("Finished - %s",m_sDosAppName);
100         if (msg==sFinish)
101                 m_hAfsLoadFinish=hWnd;
102         return ((m_hAfsLoad==0) && (m_hAfsLoadFinish==0));
103 }
104
105 BOOL CAfs::Init(CWnd *wnd,CString &msg)
106 {
107         ka_Init(0);
108         return TRUE;
109 }
110
111 HWND CAfs::m_hAfsLoad;
112 HWND CAfs::m_hAfsLoadFinish;
113 CString CAfs::m_sDosAppName;
114
115 BOOL CALLBACK CAfs::EnumWindowsProc(HWND hWnd, LPARAM lParam)
116 {
117         CWnd *wnd=CWnd::FromHandle(hWnd);
118         CString msg;
119         wnd->GetWindowText(msg);
120         DWORD dwProcessID;
121         ::GetWindowThreadProcessId (hWnd, &dwProcessID);
122         if (dwProcessID == (DWORD) lParam)
123         {
124                 if (msg.IsEmpty()) return TRUE;
125                 m_hAfsLoad=hWnd;
126                 return FALSE;
127         }
128         return TRUE;
129 }
130
131 BOOL CAfs::Create(CString &msg,CString sCompName,PROCESS_INFORMATION &procInfo)
132 {
133         DWORD rc;
134 // lets make sure there are no other instances of the client    
135         m_hAfsLoadFinish=m_hAfsLoad=0;
136         EnumWindows (EnumWindowsProcShutdown, (LPARAM) 0);      //lets prevent multiple instances!
137         if (m_hAfsLoad)
138                 Shutdown(msg);
139         else if (m_hAfsLoadFinish)      // SOME REASON THE WINDOW WAS NOT SHUT DOWN, SO LETES KILL IT
140         {
141                 ::SendMessage(m_hAfsLoadFinish,WM_CLOSE,0,0);
142                 LOG("WM_CLOSE");
143         }
144         CRegkey regkey("AFS\\Window");
145         UINT logintime=0;
146         DWORD size=sizeof(logintime);
147         regkey.GetBinary("LoginTime",(LPBYTE)&logintime,size);
148         if (logintime<=0) {
149 #ifdef _DEBUG
150                 logintime=10;
151 #else
152                 logintime=40;
153 #endif
154                 regkey.PutBinary("LoginTime",(LPBYTE)&logintime,size);
155         }
156         int Pipe = 0;
157         GetStartupInfo(&m_startUpInfo);
158         m_startUpInfo.lpTitle = DOSTITLE;
159         m_startUpInfo.wShowWindow = (CWINAFSLOADAPP->m_bShowAfs) ?SW_SHOW :SW_HIDE;//SW_SHOWMINIMIZED;//SW_HIDE;
160         m_startUpInfo.dwFlags|=STARTF_USESHOWWINDOW;
161         CWINAFSLOADAPP->SetNotifyEventSuspend();        //this needs to be done before createprocess, incase notification occurs before WaitSuspend
162         LOG("Start AFSD Creation");
163         rc = CreateProcess(NULL /*appName 16bit apps should be null*/,CMDLINE, NULL, NULL, FALSE,
164                      /*DETACHED_PROCESS |*/ CREATE_NEW_CONSOLE | HIGH_PRIORITY_CLASS /*NORMAL_PRIORITY_CLASS*/,
165                      NULL, NULL, &m_startUpInfo, &procInfo);
166
167         if (!rc) {
168                 LPVOID lpMsgBuf;
169                 FormatMessage( 
170                         FORMAT_MESSAGE_ALLOCATE_BUFFER | 
171                         FORMAT_MESSAGE_FROM_SYSTEM | 
172                         FORMAT_MESSAGE_IGNORE_INSERTS,
173                         NULL,
174                         GetLastError(),
175                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
176                         (LPTSTR) &lpMsgBuf,
177                         0,
178                         NULL 
179                 );
180                 msg.Format("Error creating AFS Client Console process, Status=%s.",lpMsgBuf);
181                 return FALSE;
182         }
183         LOG("AFSD Creation done - wait for notification");
184         WPARAM wp;
185         CWINAFSLOADAPP->WaitForEvent(logintime*1000,&wp,&msg);
186         switch (wp)
187
188         {
189         case AFS_EXITCODE_NORMAL:
190                 // extract machine name for logon
191                 msg=msg.Right(msg.GetLength()-msg.Find('#')-1);
192                 m_sMountName.Format("\\\\%s",msg.Left(msg.ReverseFind('#')));
193                 if (m_sMountName=="\\\\")
194                 {
195                         m_sMountName.Format("\\\\%s-AFS",sCompName.Left(11));
196                 }
197                 break;
198         default:
199                 return FALSE;
200         }
201         EnumWindows (EnumWindowsProc, (LPARAM) procInfo.dwProcessId);
202         CString name;
203         int len=0;
204         if (m_hAfsLoad)
205         {
206                 len=GetWindowText(m_hAfsLoad,name.GetBuffer(64),63);
207                 m_sDosAppName=name;
208         }
209         if (name==DOSTITLE) return TRUE;
210         if ((len==0)||(name==DOSTITLEFINISH) || (name==APPTITLEFINISH))
211         {
212                 msg="AFS Client Console did not start properly!";
213                 CString temp;
214                 Shutdown(temp);
215                 return FALSE;
216         }
217         regkey.PutString("Title",name);
218         return TRUE;
219 }
220
221 BOOL CAfs::CheckNet(CString &msg)
222 {
223         TCHAR szDrive[] = TEXT("*:");
224         TCHAR szMapping[ MAX_PATH ] = TEXT("");
225         LPTSTR pszSubmount = szMapping;
226 //      TCHAR scan[MAX_PATH];
227     DWORD dwSize = MAX_PATH;
228 //      TCHAR pBuffer[MAX_PATH];
229 //      wsprintf(scan, "\\\\%s", compname);
230         for (TCHAR chDrive = 'D'; chDrive <= 'Z'; ++chDrive)
231         {
232                 szDrive[0]=chDrive;
233                 if (WNetGetConnection (szDrive, szMapping, &dwSize) == NO_ERROR)
234                 {
235                         CHAR *p=strstr(szMapping,m_sMountName);
236                         if (p)
237                         {
238                                 p=strrchr(szMapping,'\\')+1;
239                                 if (!Dismount(msg,szDrive,FALSE))
240                                 {
241                                         msg.Format("Drive %s has Open Files",szDrive);
242                                         return FALSE;
243                                 }
244                                 Mount(msg,szDrive,p);
245                         }
246                 }
247         }
248         return TRUE;
249 }
250
251
252 BOOL CAfs::Mount(CString &msg,const char *drvLetter,const char *path)
253 {
254         char resource[256];
255         NETRESOURCE nr;
256         int oundHome=0;
257         int Pipe = 0;
258         CWait wait;             //simple way to set cursor busy
259         memset(&nr, 0, sizeof(NETRESOURCE));
260         ASSERT(strlen(m_sMountName)!=0);
261         wsprintf(resource, "%s\\%s", m_sMountName,path);
262         nr.dwType = RESOURCETYPE_DISK;
263         nr.lpProvider = NULL;
264         nr.lpLocalName = (char *)drvLetter;
265         nr.lpRemoteName = resource;
266         switch (WNetAddConnection2(&nr, 0, 0, 0))
267         {
268         case ERROR_ACCESS_DENIED:
269                 msg.Format("Access to the network resource was denied, cannot connect '%s%s'",drvLetter,path);
270                 return FALSE;
271         case ERROR_ALREADY_ASSIGNED: 
272                 msg.Format("Drive %s specified by the path, '%s', is already connected to a network resource",drvLetter,path);
273                 return FALSE;
274         case ERROR_BAD_DEVICE: 
275                 msg.Format("Path '%s' is invalid",path);
276                 return FALSE;
277         case ERROR_BAD_NET_NAME: 
278                 msg.Format("Path '%s' is not acceptable to any network resource provider, either because the resource name is invalid, or because the named resource cannot be located",path);
279                 return FALSE;
280         case ERROR_BAD_PROFILE: 
281                 msg.Format("The user profile is in an incorrect format, cannot add '%s%s'",drvLetter,path);
282                 return FALSE;
283         case ERROR_BUSY: 
284                 msg.Format("The router or provider is busy, possibly initializing. Please retry, cannot add %s%s",drvLetter,path);
285                 return FALSE;
286         case ERROR_INVALID_PASSWORD: 
287                 msg.Format("The specified password is invalid, cannot add '%s%s'",drvLetter,path);
288                 return FALSE;
289         case NO_ERROR:
290                 return TRUE;
291         default:
292                 msg.Format("Network error adding '%s%s'",drvLetter,path);
293                 return FALSE;
294         }
295         return TRUE;
296 }
297
298 BOOL CAfs::Dismount(CString &msg,const char *drvLetter,BOOL force)
299 {
300         int Pipe = 0;
301         DWORD ret=-1;
302         CWait wait;             //simple way to set cursor busy
303         ret=WNetCancelConnection2(drvLetter,CONNECT_UPDATE_PROFILE,force);
304         switch (ret)
305         {
306         case ERROR_DEVICE_IN_USE:
307                 msg.Format("A device is in use and '%s' cannot be disconnected",drvLetter);
308                 return FALSE;
309         case ERROR_OPEN_FILES:
310                 msg.Format("There are open files on '%s' and cannot be disconnected",drvLetter);
311                 return FALSE;
312         case ERROR_NOT_CONNECTED:
313         case NO_ERROR:
314         default:
315                 break;
316         }
317         return TRUE;
318 }
319
320 BOOL CAfs::Authencate(CString &msg,const char * name,const char * password)
321 {
322         DWORD rc;
323         char instance[8];
324         char realm[256];
325         int lifetime;
326         char *reason;
327         int oundHome=0;
328         long password_expires;
329         int Pipe = 0;
330         cm_GetRootCellName(m_cCell);
331         strcpy(realm, m_cCell);
332         lifetime = 0;
333         instance[0] = 0;
334     rc = ka_UserAuthenticateGeneral (KA_USERAUTH_VERSION,
335                                     (PCHAR)name, instance, realm, (PCHAR)password, lifetime,
336                                     &password_expires, 0, &reason);
337         if (rc) {
338                 if (strstr(reason,"skewed"))
339                 {
340                         char buf[32];
341                         if (GetEnvironmentVariable("TZ",buf,32))
342                         {
343                                 msg.Format("Unable to authenticate to AFS because:\n '%s'.\nCheck Enviornment Variable 'TZ=%s', either remove it (See Autoexec.bat) or set it correctly.",reason,buf);
344                                 return FALSE;
345                         }
346                 }
347                 msg.Format("Unable to authenticate to AFS because:\n '%s'.", reason);
348                 return FALSE;
349         }
350
351 #ifndef AFS_KERBEROS_ENV
352         if (writeTicketFile) {
353                 code = krb_write_ticket_file (realm);
354                 if (!Silent) {
355                         if (code) 
356                                 com_err (rn, code, "writing Kerberos ticket file");
357                         else {
358                                 m_pParent->Log("Wrote ticket file to /tmp");
359                         }
360                 }
361         }
362 #endif
363         m_tTotalSpanTime=0;                     //reset total time to 0 so ScanTokens will reset it
364         return ScanTokens(msg);
365 }
366
367 BOOL CAfs::StartExployer(CString &msg,const char *udrive)
368 {
369         DWORD rc;
370         PROCESS_INFORMATION procInfo;
371         STARTUPINFO startUpInfo;
372         int Pipe = 0;
373         int code;
374         WIN32_FIND_DATA FileData;
375         CString dir;
376         if ((udrive==NULL) || (strlen(udrive)==0)) return TRUE;
377         dir.Format("%s\\*",udrive);
378         HANDLE hFile= FindFirstFile(
379                 dir,               // file name
380                 &FileData);
381         if (hFile==INVALID_HANDLE_VALUE)
382         {
383                 msg.Format("Unable to open Explorer, Drive '%s' is connected but not accessable.",udrive);
384                 return FALSE;
385         }
386         FindClose(hFile);
387         char wdir[LENDIR+1];
388         code = GetWindowsDirectory(wdir, sizeof(wdir));
389     
390         if (code == 0 || code > sizeof(wdir))
391       strcpy(wdir, "c:\\windows");
392         CString cmdLine;
393         cmdLine.Format("%s\\explorer.exe /n,/e,%s\\",wdir,udrive);
394         GetStartupInfo(&startUpInfo);
395     startUpInfo.lpTitle = NULL;
396     startUpInfo.wShowWindow = SW_SHOWNORMAL;
397     rc = CreateProcess(NULL /*appName*/
398                 ,cmdLine.GetBuffer(cmdLine.GetLength())
399                 , NULL, NULL, FALSE
400                 ,DETACHED_PROCESS | NORMAL_PRIORITY_CLASS
401                 ,NULL, NULL, &startUpInfo, &procInfo);
402         if (rc!=0) return TRUE;
403         LPVOID lpMsgBuf;
404         FormatMessage( 
405                 FORMAT_MESSAGE_ALLOCATE_BUFFER | 
406             FORMAT_MESSAGE_FROM_SYSTEM | 
407                 FORMAT_MESSAGE_IGNORE_INSERTS,
408             NULL,
409                 GetLastError(),
410             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
411                 (LPTSTR) &lpMsgBuf,
412             0,
413                 NULL 
414         );
415         msg.Format("Unable to open Explorer, %s.",lpMsgBuf);
416         LocalFree( lpMsgBuf );
417         return FALSE;
418 }
419
420 BOOL CAfs::Shutdown(CString &msg)
421 {
422         CWINAFSLOADAPP->ClearNotify();
423         ShutdownAfs();
424         m_hAfsLoadFinish=0;
425         CTime startTime = CTime::GetCurrentTime();
426         CTimeSpan elapsedTime;
427         do 
428         {
429                 m_hAfsLoad=0;
430                 EnumWindows (EnumWindowsProcShutdown, (LPARAM) 0);      //lets prevent multiple instances!
431                 Sleep(500);
432                 elapsedTime= CTime::GetCurrentTime() - startTime;
433                 if (elapsedTime.GetTotalSeconds()>10) 
434                 {
435                         msg="AFS Client Console was not terminated properly!";
436                         ::ShowWindow(m_hAfsLoad,SW_SHOWNORMAL);
437                         return FALSE;
438                 }
439         } while (m_hAfsLoad);
440         if (m_hAfsLoadFinish==0)
441         {
442                 Sleep(250);     //maybe it takes a little time between process kill and window display??
443                 EnumWindows (EnumWindowsProcShutdown, (LPARAM) 0);      //lets prevent multiple instances!
444         }
445         if (m_hAfsLoadFinish)   // SOME REASON THE WINDOW WAS NOT SHUT DOWN, SO LETES KILL IT
446         {
447                 ::SendMessage(m_hAfsLoadFinish,WM_CLOSE,0,0);
448                 LOG("WM_CLOSE2");
449         }
450         return TRUE;
451 }
452
453
454 /*
455         struct afsconf_cell {
456                 char name[MAXCELLCHARS];            Cell name
457                 short numServers;                   Num active servers for the cell
458                 short flags;                                            useful flags
459                 struct sockaddr_in hostAddr[MAXHOSTSPERCELL]; IP addresses for cell's servers
460                 char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS]; Names for cell's servers
461                 char *linkedCell;                   Linked cell name, if any
462         }
463 */
464
465 BOOL CAfs::ScanTokens(CString &msg)
466 {
467         int cellNum;
468         int rc;
469         struct ktc_principal serviceName, clientName;
470         struct ktc_token token;
471         cellNum = 0;
472         msg="";
473         while (1) {
474                 rc = ktc_ListTokens(cellNum, &cellNum, &serviceName);
475                 if (rc == KTC_NOENT) {
476                         return TRUE;
477                         break;
478                 }
479                 else if (rc == KTC_NOCM) {
480                         return TRUE;
481                 }
482                 else if (rc) {
483                         msg.Format("AFS Scan token error - Unexpected error, code 0x%0x\n", rc);
484                         return FALSE;
485                 }
486                 else {
487                         rc = ktc_GetToken(&serviceName, &token, sizeof(token),
488                                           &clientName);
489                         if (rc) {
490                                 msg.Format("Unexpected error, service %s.%s.%s, code 0x%0x\n",
491                                         serviceName.name, serviceName.instance,
492                                         serviceName.cell, rc);
493                                 return FALSE;
494                         }
495                         m_dTokenEndTime=token.endTime;
496                         if (m_tTotalSpanTime.GetTotalSeconds()==0)
497                                 m_tTotalSpanTime=::CTime(m_dTokenEndTime)-CTime::GetCurrentTime();
498                 }
499         }
500         return TRUE;
501 }
502
503 UINT CAfs::TestTokenTime(CString &msg)
504 {
505         CTimeSpan timeleft=::CTime(m_dTokenEndTime)-CTime::GetCurrentTime();
506 #ifdef _DEBUG
507         DWORD dt=timeleft.GetTotalMinutes();
508         DWORD dl=m_tTotalSpanTime.GetTotalMinutes();
509         if (timeleft.GetTotalMinutes()<=m_tTotalSpanTime.GetTotalMinutes()-2)
510         {
511                 msg="Authenication Expired: No Time left.";
512                 return 2;
513         }
514         msg.Format("Authenication will expire in Hours:%d Minutes:%d",timeleft.GetTotalHours()
515                 ,timeleft.GetTotalMinutes()-timeleft.GetTotalHours()*60);
516         return (timeleft.GetTotalMinutes()>(m_tTotalSpanTime.GetTotalMinutes()-1))?0:1;
517 #else
518         if (timeleft.GetTotalMinutes()<=0)
519         {
520                 msg="Authenication Expired: No Time left.";
521                 return 2;
522         }
523         if (
524                 (timeleft.GetTotalMinutes()>=(m_tTotalSpanTime.GetTotalMinutes()/7)-1)
525                 && (timeleft.GetTotalMinutes()<=(m_tTotalSpanTime.GetTotalMinutes()/7)+1)
526                 )
527         {
528                 LOG("TimeLeft %d Total Span time %d",timeleft.GetTotalMinutes()
529                         ,m_tTotalSpanTime.GetTotalMinutes());
530                 return (ScanTokens(msg))?0:-1;
531         }
532         msg.Format("Authenication will expire in Hours:%d Minutes:%d",timeleft.GetTotalHours()
533                 ,timeleft.GetTotalMinutes()-timeleft.GetTotalHours()*60);
534         return (timeleft.GetTotalMinutes()>(m_tTotalSpanTime.GetTotalMinutes()/7))?0:1;
535 #endif
536 }
537