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

# Content
1 // Douglas Thrift
2 //
3 // CCS Computer Science
4 //
5 // Windows Finger Daemon
6
7 #include <windows.h>
8 #include <tchar.h>
9 #include <signal.h>
10 #include <wtsapi32.h>
11 #include <lm.h>
12
13 #include <algorithm>
14 #include <iostream>
15 #include <iomanip>
16 #include <string>
17 #include <sstream>
18 #include <vector>
19 #include <map>
20 #include <cwctype>
21
22 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 inline std::string Utf8(const std::wstring &wstring)
62 {
63 std::string string(::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), NULL, 0, NULL, NULL), '\0');
64
65 ::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), const_cast<LPSTR>(string.data()), int(string.size()), NULL, NULL);
66
67 return string;
68 }
69
70 class Finger
71 {
72 class Login
73 {
74 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 DWORD id;
84 WTS_CONNECTSTATE_CLASS status;
85
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 {
88 }
89
90 ~Login()
91 {
92 if (!info)
93 ::NetApiBufferFree(info);
94 }
95
96 std::string GetName() const
97 {
98 if (!info)
99 GetInfo();
100
101 return Utf8(std::wstring(info->usri11_full_name).substr(0, 20));
102 }
103 };
104
105 std::ostringstream stream;
106 std::multimap<std::string, Login> logins;
107
108 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 public:
117 Finger(bool full)
118 {
119 PWTS_SESSION_INFO sessions;
120 DWORD count;
121
122 ::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &count);
123
124 for (PWTS_SESSION_INFO session(sessions); session != sessions + count; ++session)
125 {
126 LPTSTR name;
127 DWORD size;
128
129 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSUserName, &name, &size);
130
131 std::wstring name_(name);
132
133 ::WTSFreeMemory(name);
134
135 if (!name_.empty())
136 {
137 std::transform(name_.begin(), name_.end(), name_.begin(), std::towlower);
138
139 LPTSTR session_;
140
141 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSWinStationName, &session_, &size);
142
143 Login login(name_, session->SessionId, session_, session->State);
144
145 ::WTSFreeMemory(session_);
146
147 logins.insert(std::make_pair(Utf8(name_), login));
148 }
149 }
150
151 ::WTSFreeMemory(sessions);
152
153 if (!full)
154 {
155 stream << "Login" << std::string(11, ' ') << "Name" << std::string(17, ' ') << "Id Session Status\r\n";
156
157 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 }
160 else
161 Full();
162 }
163
164 Finger(const std::string &name)
165 {
166 //NetQueryDisplayInformation
167 //NetUserGetInfo
168 }
169
170 inline operator std::string()
171 {
172 return stream.str();
173 }
174 };
175
176 LPTSTR name;
177 SERVICE_STATUS status;
178 SERVICE_STATUS_HANDLE handle;
179 HANDLE stop;
180 WSADATA data;
181 std::vector<HANDLE> threads;
182
183 void FingerDaemon();
184 DWORD WINAPI FingerListen(LPVOID server_);
185 DWORD WINAPI FingerDo(LPVOID client_);
186 void FingerStop(int);
187 void WINAPI FingerMain(DWORD argc, LPTSTR *argv);
188 void WINAPI FingerControl(DWORD control);
189
190 int _tmain(int argc, TCHAR *argv[])
191 {
192 SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCS Finger Daemon"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
193
194 if (!::StartServiceCtrlDispatcher(entry))
195 {
196 DWORD error(::GetLastError());
197
198 switch (error)
199 {
200 case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
201 goto go;
202
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
222 go:
223 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
224
225 ::signal(SIGINT, FingerStop);
226
227 try
228 {
229 FingerDaemon();
230 }
231 catch (...) {}
232
233 return 0;
234 }
235
236 void FingerDaemon()
237 {
238 ::WSAStartup(MAKEWORD(2, 0), &data);
239
240 //
241
242 SOCKET server(::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
243 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 ::bind(server, (SOCKADDR *)(&service), sizeof (service));
250 ::listen(server, SOMAXCONN);
251
252 threads.push_back(::CreateThread(NULL, 0, FingerListen, &server, 0, NULL));
253
254 while(::WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0);
255
256 //
257
258 ::closesocket(server);
259
260 ::WSACleanup();
261 }
262
263 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 threads.push_back(::CreateThread(NULL, 0, FingerDo, &client, 0, NULL));
272 }
273
274 return 0;
275 }
276
277 DWORD WINAPI FingerDo(LPVOID client_)
278 {
279 SOCKET &client(*reinterpret_cast<SOCKET *>(client_));
280 char buffer[1024];
281 std::istringstream stream(std::string(buffer, ::recv(client, buffer, sizeof buffer, 0)));
282 std::string line;
283
284 std::getline(stream, line);
285
286 stream.str(line);
287
288 std::getline(stream, line, '\r');
289
290 stream.str(line);
291
292 std::string name;
293 bool full(false);
294
295 while (stream >> line)
296 if (line == "/W")
297 full = true;
298 else
299 name = line;
300
301 std::string finger(name.empty() ? Finger(full) : Finger(name));
302
303 ::send(client, finger.data(), int(finger.size()), 0);
304 ::closesocket(client);
305
306 return 0;
307 }
308
309 void FingerStop(int)
310 {
311 ::SetEvent(stop);
312 }
313
314 void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
315 {
316 name = argv[0];
317 handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
318 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
319
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 ::SetServiceStatus(handle, &status);
331
332 try
333 {
334 FingerDaemon();
335 }
336 catch (...) {}
337
338 status.dwCurrentState = SERVICE_STOPPED;
339 status.dwWin32ExitCode = NO_ERROR;
340 status.dwCheckPoint = 0;
341 status.dwWaitHint = 0;
342
343 ::SetServiceStatus(handle, &status);
344 }
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 ::SetEvent(stop);
355
356 break;
357
358 case SERVICE_CONTROL_INTERROGATE:
359 break;
360 }
361
362 ::SetServiceStatus(handle, &status);
363 }