ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/CCSFinger/CCSFinger.cpp
Revision: 616
Committed: 2005-12-12T20:25:45-08:00 (19 years, 6 months ago) by douglas
File size: 7918 byte(s)
Log Message:
W00t!

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