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