2853f48e53c274a6749cf77dce30b0dfd3b09e4c
[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         LOG("AFSD Creation done - wait for notification");
168         if (!rc) {
169                 msg.Format("Error creating AFS Client Console process, Status=0x%0x", GetLastError());
170                 return FALSE;
171         }
172         WPARAM wp;
173         CWINAFSLOADAPP->WaitForEvent(logintime*1000,&wp,&msg);
174         switch (wp)
175         {
176         case AFS_EXITCODE_NORMAL:
177                 // extract machine name for logon
178                 msg=msg.Right(msg.GetLength()-msg.Find('#')-1);
179                 m_sMountName.Format("\\\\%s",msg.Left(msg.ReverseFind('#')));
180                 if (m_sMountName=="\\\\")
181                 {
182                         m_sMountName.Format("\\\\%s-AFS",sCompName.Left(11));
183                 }
184                 break;
185         default:
186                 return FALSE;
187         }
188         EnumWindows (EnumWindowsProc, (LPARAM) procInfo.dwProcessId);
189         CString name;
190         int len=0;
191         if (m_hAfsLoad)
192         {
193                 len=GetWindowText(m_hAfsLoad,name.GetBuffer(64),63);
194                 m_sDosAppName=name;
195         }
196         if (name==DOSTITLE) return TRUE;
197         if ((len==0)||(name==DOSTITLEFINISH) || (name==APPTITLEFINISH))
198         {
199                 msg="AFS Client Console did not start properly!";
200                 CString temp;
201                 Shutdown(temp);
202                 return FALSE;
203         }
204         regkey.PutString("Title",name);
205         return TRUE;
206 }
207
208 BOOL CAfs::CheckNet(CString &msg)
209 {
210         TCHAR szDrive[] = TEXT("*:");
211         TCHAR szMapping[ MAX_PATH ] = TEXT("");
212         LPTSTR pszSubmount = szMapping;
213 //      TCHAR scan[MAX_PATH];
214     DWORD dwSize = MAX_PATH;
215 //      TCHAR pBuffer[MAX_PATH];
216 //      wsprintf(scan, "\\\\%s", compname);
217         for (TCHAR chDrive = 'D'; chDrive <= 'Z'; ++chDrive)
218         {
219                 szDrive[0]=chDrive;
220                 if (WNetGetConnection (szDrive, szMapping, &dwSize) == NO_ERROR)
221                 {
222                         CHAR *p=strstr(szMapping,m_sMountName);
223                         if (p)
224                         {
225                                 p=strrchr(szMapping,'\\')+1;
226                                 if (!Dismount(msg,szDrive,FALSE))
227                                 {
228                                         msg.Format("Drive %s has Open Files",szDrive);
229                                         return FALSE;
230                                 }
231                                 Mount(msg,szDrive,p);
232                         }
233                 }
234         }
235         return TRUE;
236 }
237
238
239 BOOL CAfs::Mount(CString &msg,const char *drvLetter,const char *path)
240 {
241         char resource[256];
242         NETRESOURCE nr;
243         int oundHome=0;
244         int Pipe = 0;
245         CWait wait;             //simple way to set cursor busy
246         memset(&nr, 0, sizeof(NETRESOURCE));
247         ASSERT(strlen(m_sMountName)!=0);
248         wsprintf(resource, "%s\\%s", m_sMountName,path);
249         nr.dwType = RESOURCETYPE_DISK;
250         nr.lpProvider = NULL;
251         nr.lpLocalName = (char *)drvLetter;
252         nr.lpRemoteName = resource;
253         switch (WNetAddConnection2(&nr, 0, 0, 0))
254         {
255         case ERROR_ACCESS_DENIED:
256                 msg.Format("Access to the network resource was denied, cannot connect '%s%s'",drvLetter,path);
257                 return FALSE;
258         case ERROR_ALREADY_ASSIGNED: 
259                 msg.Format("Drive %s specified by the path, '%s', is already connected to a network resource",drvLetter,path);
260                 return FALSE;
261         case ERROR_BAD_DEVICE: 
262                 msg.Format("Path '%s' is invalid",path);
263                 return FALSE;
264         case ERROR_BAD_NET_NAME: 
265                 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);
266                 return FALSE;
267         case ERROR_BAD_PROFILE: 
268                 msg.Format("The user profile is in an incorrect format, cannot add '%s%s'",drvLetter,path);
269                 return FALSE;
270         case ERROR_BUSY: 
271                 msg.Format("The router or provider is busy, possibly initializing. Please retry, cannot add %s%s",drvLetter,path);
272                 return FALSE;
273         case ERROR_INVALID_PASSWORD: 
274                 msg.Format("The specified password is invalid, cannot add '%s%s'",drvLetter,path);
275                 return FALSE;
276         case NO_ERROR:
277                 return TRUE;
278         default:
279                 msg.Format("Network error adding '%s%s'",drvLetter,path);
280                 return FALSE;
281         }
282         return TRUE;
283 }
284
285 BOOL CAfs::Dismount(CString &msg,const char *drvLetter,BOOL force)
286 {
287         int Pipe = 0;
288         DWORD ret=-1;
289         CWait wait;             //simple way to set cursor busy
290         ret=WNetCancelConnection2(drvLetter,CONNECT_UPDATE_PROFILE,force);
291         switch (ret)
292         {
293         case ERROR_DEVICE_IN_USE:
294                 msg.Format("A device is in use and '%s' cannot be disconnected",drvLetter);
295                 return FALSE;
296         case ERROR_OPEN_FILES:
297                 msg.Format("There are open files on '%s' and cannot be disconnected",drvLetter);
298                 return FALSE;
299         case ERROR_NOT_CONNECTED:
300         case NO_ERROR:
301         default:
302                 break;
303         }
304         return TRUE;
305 }
306
307 BOOL CAfs::Authencate(CString &msg,const char * name,const char * password)
308 {
309         DWORD rc;
310         char instance[8];
311         char realm[256];
312         int lifetime;
313         char *reason;
314         int oundHome=0;
315         long password_expires;
316         int Pipe = 0;
317         cm_GetRootCellName(m_cCell);
318         strcpy(realm, m_cCell);
319         lifetime = 0;
320         instance[0] = 0;
321     rc = ka_UserAuthenticateGeneral (KA_USERAUTH_VERSION,
322                                     (PCHAR)name, instance, realm, (PCHAR)password, lifetime,
323                                     &password_expires, 0, &reason);
324         if (rc) {
325                 if (strstr(reason,"skewed"))
326                 {
327                         char buf[32];
328                         if (GetEnvironmentVariable("TZ",buf,32))
329                         {
330                                 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);
331                                 return FALSE;
332                         }
333                 }
334                 msg.Format("Unable to authenticate to AFS because:\n '%s'.", reason);
335                 return FALSE;
336         }
337
338 #ifndef AFS_KERBEROS_ENV
339         if (writeTicketFile) {
340                 code = krb_write_ticket_file (realm);
341                 if (!Silent) {
342                         if (code) 
343                                 com_err (rn, code, "writing Kerberos ticket file");
344                         else {
345                                 m_pParent->Log("Wrote ticket file to /tmp");
346                         }
347                 }
348         }
349 #endif
350         m_tTotalSpanTime=0;                     //reset total time to 0 so ScanTokens will reset it
351         return ScanTokens(msg);
352 }
353
354 BOOL CAfs::StartExployer(CString &msg,const char *udrive)
355 {
356         DWORD rc;
357         PROCESS_INFORMATION procInfo;
358         STARTUPINFO startUpInfo;
359         int Pipe = 0;
360         int code;
361         WIN32_FIND_DATA FileData;
362         CString dir;
363         dir.Format("%s\\*",udrive);
364         HANDLE hFile= FindFirstFile(
365                 dir,               // file name
366                 &FileData);
367         if (hFile==INVALID_HANDLE_VALUE)
368         {
369                 msg.Format("Unable to open Explorer, Drive '%s' is connected but not accessable.",udrive);
370                 return FALSE;
371         }
372         FindClose(hFile);
373         char wdir[LENDIR+1];
374         code = GetWindowsDirectory(wdir, sizeof(wdir));
375     
376         if (code == 0 || code > sizeof(wdir))
377       strcpy(wdir, "c:\\windows");
378         CString cmdLine;
379         cmdLine.Format("%s\\explorer.exe /n,/e,%s\\",wdir,udrive);
380         GetStartupInfo(&startUpInfo);
381     startUpInfo.lpTitle = NULL;
382     startUpInfo.wShowWindow = SW_SHOWNORMAL;
383     rc = CreateProcess(NULL /*appName*/
384                 ,cmdLine.GetBuffer(cmdLine.GetLength())
385                 , NULL, NULL, FALSE
386                 ,DETACHED_PROCESS | NORMAL_PRIORITY_CLASS
387                 ,NULL, NULL, &startUpInfo, &procInfo);
388         if (rc!=0) return TRUE;
389         LPVOID lpMsgBuf;
390         FormatMessage( 
391                 FORMAT_MESSAGE_ALLOCATE_BUFFER | 
392             FORMAT_MESSAGE_FROM_SYSTEM | 
393                 FORMAT_MESSAGE_IGNORE_INSERTS,
394             NULL,
395                 GetLastError(),
396             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
397                 (LPTSTR) &lpMsgBuf,
398             0,
399                 NULL 
400         );
401         msg.Format("Unable to open Explorer, %s.",lpMsgBuf);
402         LocalFree( lpMsgBuf );
403         return FALSE;
404 }
405
406 BOOL CAfs::Shutdown(CString &msg)
407 {
408         CWINAFSLOADAPP->ClearNotify();
409         ShutdownAfs();
410         m_hAfsLoadFinish=0;
411         CTime startTime = CTime::GetCurrentTime();
412         CTimeSpan elapsedTime;
413         do 
414         {
415                 m_hAfsLoad=0;
416                 EnumWindows (EnumWindowsProcShutdown, (LPARAM) 0);      //lets prevent multiple instances!
417                 Sleep(500);
418                 elapsedTime= CTime::GetCurrentTime() - startTime;
419                 if (elapsedTime.GetTotalSeconds()>10) 
420                 {
421                         msg="AFS Client Console was not terminated properly!";
422                         ::ShowWindow(m_hAfsLoad,SW_SHOWNORMAL);
423                         return FALSE;
424                 }
425         } while (m_hAfsLoad);
426         if (m_hAfsLoadFinish==0)
427         {
428                 Sleep(250);     //maybe it takes a little time between process kill and window display??
429                 EnumWindows (EnumWindowsProcShutdown, (LPARAM) 0);      //lets prevent multiple instances!
430         }
431         if (m_hAfsLoadFinish)   // SOME REASON THE WINDOW WAS NOT SHUT DOWN, SO LETES KILL IT
432         {
433                 ::SendMessage(m_hAfsLoadFinish,WM_CLOSE,0,0);
434                 LOG("WM_CLOSE2");
435         }
436         return TRUE;
437 }
438
439
440 /*
441         struct afsconf_cell {
442                 char name[MAXCELLCHARS];            Cell name
443                 short numServers;                   Num active servers for the cell
444                 short flags;                                            useful flags
445                 struct sockaddr_in hostAddr[MAXHOSTSPERCELL]; IP addresses for cell's servers
446                 char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS]; Names for cell's servers
447                 char *linkedCell;                   Linked cell name, if any
448         }
449 */
450
451 BOOL CAfs::ScanTokens(CString &msg)
452 {
453         int cellNum;
454         int rc;
455         struct ktc_principal serviceName, clientName;
456         struct ktc_token token;
457         cellNum = 0;
458         msg="";
459         while (1) {
460                 rc = ktc_ListTokens(cellNum, &cellNum, &serviceName);
461                 if (rc == KTC_NOENT) {
462                         return TRUE;
463                         break;
464                 }
465                 else if (rc == KTC_NOCM) {
466                         return TRUE;
467                 }
468                 else if (rc) {
469                         msg.Format("AFS Scan token error - Unexpected error, code 0x%0x\n", rc);
470                         return FALSE;
471                 }
472                 else {
473                         rc = ktc_GetToken(&serviceName, &token, sizeof(token),
474                                           &clientName);
475                         if (rc) {
476                                 msg.Format("Unexpected error, service %s.%s.%s, code 0x%0x\n",
477                                         serviceName.name, serviceName.instance,
478                                         serviceName.cell, rc);
479                                 return FALSE;
480                         }
481                         m_dTokenEndTime=token.endTime;
482                         if (m_tTotalSpanTime.GetTotalSeconds()==0)
483                                 m_tTotalSpanTime=::CTime(m_dTokenEndTime)-CTime::GetCurrentTime();
484                 }
485         }
486         return TRUE;
487 }
488
489 UINT CAfs::TestTokenTime(CString &msg)
490 {
491         CTimeSpan timeleft=::CTime(m_dTokenEndTime)-CTime::GetCurrentTime();
492 #ifdef _DEBUG
493         DWORD dt=timeleft.GetTotalMinutes();
494         DWORD dl=m_tTotalSpanTime.GetTotalMinutes();
495         if (timeleft.GetTotalMinutes()<=m_tTotalSpanTime.GetTotalMinutes()-2)
496         {
497                 msg="Authenication Expired: No Time left.";
498                 return 2;
499         }
500         msg.Format("Authenication will expire in Hours:%d Minutes:%d",timeleft.GetTotalHours()
501                 ,timeleft.GetTotalMinutes()-timeleft.GetTotalHours()*60);
502         return (timeleft.GetTotalMinutes()>(m_tTotalSpanTime.GetTotalMinutes()-1))?0:1;
503 #else
504         if (timeleft.GetTotalMinutes()<=0)
505         {
506                 msg="Authenication Expired: No Time left.";
507                 return 2;
508         }
509         if (
510                 (timeleft.GetTotalMinutes()>=(m_tTotalSpanTime.GetTotalMinutes()/7)-1)
511                 && (timeleft.GetTotalMinutes()<=(m_tTotalSpanTime.GetTotalMinutes()/7)+1)
512                 )
513         {
514                 LOG("TimeLeft %d Total Span time %d",timeleft.GetTotalMinutes()
515                         ,m_tTotalSpanTime.GetTotalMinutes());
516                 return (ScanTokens(msg))?0:-1;
517         }
518         msg.Format("Authenication will expire in Hours:%d Minutes:%d",timeleft.GetTotalHours()
519                 ,timeleft.GetTotalMinutes()-timeleft.GetTotalHours()*60);
520         return (timeleft.GetTotalMinutes()>(m_tTotalSpanTime.GetTotalMinutes()/7))?0:1;
521 #endif
522 }
523