ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/CCSFinger/CCSFinger.cpp
Revision: 617
Committed: 2005-12-13T01:35:20-08:00 (19 years, 6 months ago) by douglas
File size: 9734 byte(s)
Log Message:
Moo!

File Contents

# User Rev Content
1 douglas 594 // Douglas Thrift
2     //
3     // CCS Computer Science
4     //
5     // Windows Finger Daemon
6    
7     #include <windows.h>
8     #include <tchar.h>
9 douglas 596 #include <signal.h>
10 douglas 608 #include <wtsapi32.h>
11 douglas 614 #include <lm.h>
12 douglas 617 #include <shlobj.h>
13 douglas 594
14 douglas 616 #include <algorithm>
15 douglas 595 #include <iostream>
16 douglas 615 #include <iomanip>
17 douglas 608 #include <string>
18 douglas 610 #include <sstream>
19 douglas 609 #include <vector>
20 douglas 616 #include <map>
21     #include <cwctype>
22 douglas 595
23 douglas 615 std::ostream &operator<<(std::ostream &out, WTS_CONNECTSTATE_CLASS status)
24     {
25     switch (status)
26     {
27     case WTSActive:
28     return out << "Active";
29    
30     case WTSConnected:
31     return out << "Connected";
32    
33     case WTSConnectQuery:
34     return out << "Connecting";
35    
36     case WTSShadow:
37     return out << "Shadowing";
38    
39     case WTSDisconnected:
40     return out << "Disconnected";
41    
42     case WTSIdle:
43     return out << "Idle";
44    
45     case WTSListen:
46     return out << "Listening";
47    
48     case WTSReset:
49     return out << "Reseting";
50    
51     case WTSDown:
52     return out << "Down";
53    
54     case WTSInit:
55     return out << "Initializing";
56    
57     default:
58     return out << "Unknown";
59     }
60     }
61    
62 douglas 610 inline std::string Utf8(const std::wstring &wstring)
63     {
64 douglas 613 std::string string(::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), NULL, 0, NULL, NULL), '\0');
65 douglas 610
66 douglas 613 ::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), const_cast<LPSTR>(string.data()), int(string.size()), NULL, NULL);
67 douglas 610
68     return string;
69     }
70    
71     class Finger
72     {
73 douglas 616 class Login
74 douglas 613 {
75 douglas 616 std::wstring login;
76     mutable USER_INFO_11 *info;
77    
78     inline void GetInfo() const
79     {
80 douglas 617 if (!info)
81     ::NetUserGetInfo(NULL, login.c_str(), 11, reinterpret_cast<LPBYTE *>(&info));
82 douglas 616 }
83     public:
84     std::string session;
85 douglas 615 DWORD id;
86     WTS_CONNECTSTATE_CLASS status;
87 douglas 616
88     Login(const std::wstring &login, DWORD id, const std::wstring &session, WTS_CONNECTSTATE_CLASS status) : login(login), info(NULL), id(id), session(Utf8(session)), status(status)
89 douglas 613 {
90 douglas 616 }
91 douglas 614
92 douglas 616 ~Login()
93     {
94     if (!info)
95     ::NetApiBufferFree(info);
96 douglas 613 }
97 douglas 615
98 douglas 617 std::string GetShortName() const
99 douglas 613 {
100 douglas 617 GetInfo();
101 douglas 616
102     return Utf8(std::wstring(info->usri11_full_name).substr(0, 20));
103 douglas 613 }
104 douglas 617
105     std::string GetName() const
106     {
107     GetInfo();
108    
109     return Utf8(info->usri11_full_name);
110     }
111    
112     std::string GetDirectory() const
113     {
114     HANDLE token;
115    
116     if (::WTSQueryUserToken(id, &token))
117     {
118     TCHAR directory[MAX_PATH];
119    
120     ::SHGetFolderPath(NULL, CSIDL_PROFILE, token, SHGFP_TYPE_CURRENT, directory);
121     ::CloseHandle(token);
122    
123     return Utf8(directory);
124     }
125     else
126     {
127     TCHAR directory_[MAX_PATH];
128    
129     ::SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, directory_);
130    
131     std::wstring directory(directory_);
132    
133     directory.replace(directory.rfind('\\') + 1, std::wstring::npos, login);
134    
135     return Utf8(directory);
136     }
137     }
138 douglas 613 };
139 douglas 616
140 douglas 610 std::ostringstream stream;
141 douglas 616 std::multimap<std::string, Login> logins;
142 douglas 610
143 douglas 616 void Full()
144     {
145     for (std::multimap<std::string, Login>::const_iterator login(logins.begin()); login != logins.end(); login = logins.upper_bound(login->first))
146     {
147 douglas 617 stream << "Login: " << login->first << std::string(33 - login->first.size(), ' ') << "Name: " << login->second.GetName() << "\r\nDirectory: " << login->second.GetDirectory() << "\r\n";
148 douglas 616 }
149     }
150    
151 douglas 610 public:
152     Finger(bool full)
153     {
154     PWTS_SESSION_INFO sessions;
155     DWORD count;
156    
157 douglas 613 ::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &count);
158 douglas 610
159 douglas 613 for (PWTS_SESSION_INFO session(sessions); session != sessions + count; ++session)
160 douglas 610 {
161     LPTSTR name;
162     DWORD size;
163    
164 douglas 613 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSUserName, &name, &size);
165 douglas 610
166 douglas 616 std::wstring name_(name);
167    
168     ::WTSFreeMemory(name);
169    
170     if (!name_.empty())
171 douglas 613 {
172 douglas 616 std::transform(name_.begin(), name_.end(), name_.begin(), std::towlower);
173    
174 douglas 613 LPTSTR session_;
175 douglas 610
176 douglas 613 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSWinStationName, &session_, &size);
177 douglas 611
178 douglas 616 Login login(name_, session->SessionId, session_, session->State);
179 douglas 610
180 douglas 613 ::WTSFreeMemory(session_);
181    
182 douglas 616 logins.insert(std::make_pair(Utf8(name_), login));
183 douglas 613 }
184 douglas 610 }
185    
186 douglas 613 ::WTSFreeMemory(sessions);
187    
188     if (!full)
189     {
190 douglas 616 stream << "Login" << std::string(11, ' ') << "Name" << std::string(17, ' ') << "Id Session Status\r\n";
191 douglas 613
192 douglas 616 for (std::multimap<std::string, Login>::const_iterator login(logins.begin()); login != logins.end(); ++login)
193 douglas 617 stream << login->first << std::string(16 - login->first.size(), ' ') << login->second.GetShortName() << std::string(21 - login->second.GetShortName().size(), ' ') << std::setw(5) << std::left << login->second.id << " " << login->second.session << std::string(14 - login->second.session.size(), ' ') << login->second.status << "\r\n";
194 douglas 613 }
195 douglas 616 else
196     Full();
197 douglas 610 }
198    
199     Finger(const std::string &name)
200     {
201 douglas 612 //NetQueryDisplayInformation
202     //NetUserGetInfo
203 douglas 610 }
204    
205     inline operator std::string()
206     {
207     return stream.str();
208     }
209     };
210    
211 douglas 595 LPTSTR name;
212 douglas 594 SERVICE_STATUS status;
213     SERVICE_STATUS_HANDLE handle;
214 douglas 595 HANDLE stop;
215 douglas 594 WSADATA data;
216 douglas 609 std::vector<HANDLE> threads;
217 douglas 594
218 douglas 596 void FingerDaemon();
219 douglas 609 DWORD WINAPI FingerListen(LPVOID server_);
220     DWORD WINAPI FingerDo(LPVOID client_);
221 douglas 596 void FingerStop(int);
222 douglas 595 void WINAPI FingerMain(DWORD argc, LPTSTR *argv);
223     void WINAPI FingerControl(DWORD control);
224 douglas 594
225     int _tmain(int argc, TCHAR *argv[])
226     {
227 douglas 617 SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCSFinger"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
228 douglas 594
229 douglas 613 if (!::StartServiceCtrlDispatcher(entry))
230 douglas 594 {
231 douglas 613 DWORD error(::GetLastError());
232 douglas 594
233     switch (error)
234     {
235     case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
236 douglas 595 goto go;
237 douglas 594
238     case ERROR_INVALID_DATA:
239     std::cerr << "ERROR_INVALID_DATA" << std::endl;
240    
241     break;
242    
243     case ERROR_SERVICE_ALREADY_RUNNING:
244     std::cerr << "ERROR_SERVICE_ALREADY_RUNNING" << std::endl;
245    
246     break;
247    
248     default:
249     std::cerr << error << std::endl;
250     }
251    
252     return 1;
253     }
254    
255     return 0;
256 douglas 595
257     go:
258 douglas 617 for (int index(1); index != argc; ++index)
259     {
260     std::wstring arg(argv[index]);
261    
262     if (arg == TEXT("create"))
263     {
264     TCHAR file[MAX_PATH];
265    
266     ::GetModuleFileName(NULL, file, MAX_PATH);
267    
268     SC_HANDLE manager(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE)), service(::CreateService(manager, TEXT("CCSFinger"), TEXT("CCS Finger Daemon"), 0, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, file, NULL, NULL, TEXT("TermService\0"), NULL, TEXT("")));
269    
270     if (!service)
271     std::cerr << ::GetLastError() << std::endl;
272     else
273     ::CloseServiceHandle(service);
274    
275     ::CloseServiceHandle(manager);
276    
277     return 0;
278     }
279     else if (arg == TEXT("delete"))
280     {
281     SC_HANDLE manager(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, DELETE)), service(::OpenService(manager, TEXT("CCSFinger"), DELETE));
282    
283     if (!::DeleteService(service))
284     std::cerr << ::GetLastError() << std::endl;
285    
286     ::CloseServiceHandle(service);
287     ::CloseServiceHandle(manager);
288    
289     return 0;
290     }
291     }
292    
293 douglas 613 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
294 douglas 608
295 douglas 613 ::signal(SIGINT, FingerStop);
296 douglas 595
297 douglas 596 try
298     {
299     FingerDaemon();
300     }
301     catch (...) {}
302    
303 douglas 609 return 0;
304 douglas 594 }
305    
306 douglas 596 void FingerDaemon()
307 douglas 594 {
308 douglas 613 ::WSAStartup(MAKEWORD(2, 0), &data);
309 douglas 594
310     //
311    
312 douglas 613 SOCKET server(::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
313 douglas 594 SOCKADDR_IN service;
314    
315     service.sin_family = AF_INET;
316     service.sin_addr.s_addr = inet_addr("0.0.0.0");
317     service.sin_port = htons(79);
318    
319 douglas 613 ::bind(server, (SOCKADDR *)(&service), sizeof (service));
320     ::listen(server, SOMAXCONN);
321 douglas 594
322 douglas 613 threads.push_back(::CreateThread(NULL, 0, FingerListen, &server, 0, NULL));
323 douglas 608
324 douglas 613 while(::WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0);
325 douglas 594
326     //
327    
328 douglas 613 ::closesocket(server);
329 douglas 608
330 douglas 613 ::WSACleanup();
331 douglas 596 }
332 douglas 594
333 douglas 609 DWORD WINAPI FingerListen(LPVOID server_)
334     {
335     SOCKET &server(*reinterpret_cast<SOCKET *>(server_));
336    
337     while (true)
338     {
339     SOCKET client(accept(server, NULL, NULL));
340    
341 douglas 613 threads.push_back(::CreateThread(NULL, 0, FingerDo, &client, 0, NULL));
342 douglas 609 }
343    
344     return 0;
345     }
346    
347     DWORD WINAPI FingerDo(LPVOID client_)
348     {
349     SOCKET &client(*reinterpret_cast<SOCKET *>(client_));
350 douglas 610 char buffer[1024];
351 douglas 613 std::istringstream stream(std::string(buffer, ::recv(client, buffer, sizeof buffer, 0)));
352 douglas 610 std::string line;
353 douglas 609
354 douglas 610 std::getline(stream, line);
355 douglas 609
356 douglas 610 stream.str(line);
357 douglas 609
358 douglas 610 std::getline(stream, line, '\r');
359 douglas 609
360 douglas 610 stream.str(line);
361 douglas 609
362 douglas 610 std::string name;
363     bool full(false);
364 douglas 609
365 douglas 610 while (stream >> line)
366     if (line == "/W")
367     full = true;
368     else
369     name = line;
370 douglas 609
371 douglas 610 std::string finger(name.empty() ? Finger(full) : Finger(name));
372 douglas 609
373 douglas 613 ::send(client, finger.data(), int(finger.size()), 0);
374     ::closesocket(client);
375 douglas 609
376     return 0;
377     }
378    
379 douglas 596 void FingerStop(int)
380     {
381 douglas 613 ::SetEvent(stop);
382 douglas 596 }
383    
384     void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
385     {
386     name = argv[0];
387     handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
388 douglas 613 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
389 douglas 596
390     //
391    
392     status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
393     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
394     status.dwServiceSpecificExitCode = 0;
395     status.dwCurrentState = SERVICE_RUNNING;
396     status.dwWin32ExitCode = NO_ERROR;
397     status.dwCheckPoint = 0;
398     status.dwWaitHint = 0;
399    
400 douglas 613 ::SetServiceStatus(handle, &status);
401 douglas 596
402     try
403     {
404     FingerDaemon();
405     }
406     catch (...) {}
407    
408 douglas 595 status.dwCurrentState = SERVICE_STOPPED;
409 douglas 594 status.dwWin32ExitCode = NO_ERROR;
410     status.dwCheckPoint = 0;
411     status.dwWaitHint = 0;
412    
413 douglas 613 ::SetServiceStatus(handle, &status);
414 douglas 594 }
415    
416     void WINAPI FingerControl(DWORD control)
417     {
418     switch (control)
419     {
420     case SERVICE_CONTROL_STOP:
421     case SERVICE_CONTROL_SHUTDOWN:
422     status.dwCurrentState = SERVICE_STOP_PENDING;
423    
424 douglas 613 ::SetEvent(stop);
425 douglas 594
426     break;
427    
428     case SERVICE_CONTROL_INTERROGATE:
429     break;
430     }
431    
432 douglas 613 ::SetServiceStatus(handle, &status);
433 douglas 594 }