ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/CCSFinger/CCSFinger.cpp
Revision: 613
Committed: 2005-12-12T18:30:01-08:00 (19 years, 6 months ago) by douglas
File size: 6109 byte(s)
Log Message:
Moving along!

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
12 #include <iostream>
13 #include <string>
14 #include <sstream>
15 #include <vector>
16 #include <set>
17
18 inline std::string Utf8(const std::wstring &wstring)
19 {
20 std::string string(::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), NULL, 0, NULL, NULL), '\0');
21
22 ::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), const_cast<LPSTR>(string.data()), int(string.size()), NULL, NULL);
23
24 return string;
25 }
26
27 class Finger
28 {
29 private:
30 struct Login
31 {
32 std::string login, name, session;
33 Login(const std::string &login, const std::string &session) : login(login), session(session)
34 {
35 }
36 bool operator<(const Login &login) const
37 {
38 if (this->login == login.login)
39 return session < login.session;
40 else
41 return this->login < login.login;
42 }
43 };
44 std::ostringstream stream;
45 std::set<Login> logins;
46
47 public:
48 Finger(bool full)
49 {
50 PWTS_SESSION_INFO sessions;
51 DWORD count;
52
53 ::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &count);
54
55 for (PWTS_SESSION_INFO session(sessions); session != sessions + count; ++session)
56 {
57 LPTSTR name;
58 DWORD size;
59
60 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSUserName, &name, &size);
61
62 if (!std::wstring(name).empty())
63 {
64 LPTSTR session_;
65
66 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSWinStationName, &session_, &size);
67
68 Login login(Utf8(name), Utf8(session_));
69
70 ::WTSFreeMemory(session_);
71
72 logins.insert(login);
73 }
74
75 ::WTSFreeMemory(name);
76 }
77
78 ::WTSFreeMemory(sessions);
79
80 if (!full)
81 {
82 stream << "Login\t\tName" << std::string(17, ' ') << "Session\r\n";
83
84 for (std::set<Login>::const_iterator login(logins.begin()); login != logins.end(); ++login)
85 stream << login->login << std::string(16 - login->login.size(), ' ') << login->name << std::string(21 - login->name.size(), ' ') << login->session << "\r\n";
86 }
87 }
88
89 Finger(const std::string &name)
90 {
91 //NetQueryDisplayInformation
92 //NetUserGetInfo
93 }
94
95 inline operator std::string()
96 {
97 return stream.str();
98 }
99 };
100
101 LPTSTR name;
102 SERVICE_STATUS status;
103 SERVICE_STATUS_HANDLE handle;
104 HANDLE stop;
105 WSADATA data;
106 std::vector<HANDLE> threads;
107
108 void FingerDaemon();
109 DWORD WINAPI FingerListen(LPVOID server_);
110 DWORD WINAPI FingerDo(LPVOID client_);
111 void FingerStop(int);
112 void WINAPI FingerMain(DWORD argc, LPTSTR *argv);
113 void WINAPI FingerControl(DWORD control);
114
115 int _tmain(int argc, TCHAR *argv[])
116 {
117 SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCS Finger Daemon"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
118
119 if (!::StartServiceCtrlDispatcher(entry))
120 {
121 DWORD error(::GetLastError());
122
123 switch (error)
124 {
125 case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
126 goto go;
127
128 case ERROR_INVALID_DATA:
129 std::cerr << "ERROR_INVALID_DATA" << std::endl;
130
131 break;
132
133 case ERROR_SERVICE_ALREADY_RUNNING:
134 std::cerr << "ERROR_SERVICE_ALREADY_RUNNING" << std::endl;
135
136 break;
137
138 default:
139 std::cerr << error << std::endl;
140 }
141
142 return 1;
143 }
144
145 return 0;
146
147 go:
148 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
149
150 ::signal(SIGINT, FingerStop);
151
152 try
153 {
154 FingerDaemon();
155 }
156 catch (...) {}
157
158 return 0;
159 }
160
161 void FingerDaemon()
162 {
163 ::WSAStartup(MAKEWORD(2, 0), &data);
164
165 //
166
167 SOCKET server(::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
168 SOCKADDR_IN service;
169
170 service.sin_family = AF_INET;
171 service.sin_addr.s_addr = inet_addr("0.0.0.0");
172 service.sin_port = htons(79);
173
174 ::bind(server, (SOCKADDR *)(&service), sizeof (service));
175 ::listen(server, SOMAXCONN);
176
177 threads.push_back(::CreateThread(NULL, 0, FingerListen, &server, 0, NULL));
178
179 while(::WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0);
180
181 //
182
183 ::closesocket(server);
184
185 ::WSACleanup();
186 }
187
188 DWORD WINAPI FingerListen(LPVOID server_)
189 {
190 SOCKET &server(*reinterpret_cast<SOCKET *>(server_));
191
192 while (true)
193 {
194 SOCKET client(accept(server, NULL, NULL));
195
196 threads.push_back(::CreateThread(NULL, 0, FingerDo, &client, 0, NULL));
197 }
198
199 return 0;
200 }
201
202 DWORD WINAPI FingerDo(LPVOID client_)
203 {
204 SOCKET &client(*reinterpret_cast<SOCKET *>(client_));
205 char buffer[1024];
206 std::istringstream stream(std::string(buffer, ::recv(client, buffer, sizeof buffer, 0)));
207 std::string line;
208
209 std::getline(stream, line);
210
211 stream.str(line);
212
213 std::getline(stream, line, '\r');
214
215 stream.str(line);
216
217 std::string name;
218 bool full(false);
219
220 while (stream >> line)
221 if (line == "/W")
222 full = true;
223 else
224 name = line;
225
226 std::string finger(name.empty() ? Finger(full) : Finger(name));
227
228 ::send(client, finger.data(), int(finger.size()), 0);
229 ::closesocket(client);
230
231 return 0;
232 }
233
234 void FingerStop(int)
235 {
236 ::SetEvent(stop);
237 }
238
239 void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
240 {
241 name = argv[0];
242 handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
243 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
244
245 //
246
247 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
248 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
249 status.dwServiceSpecificExitCode = 0;
250 status.dwCurrentState = SERVICE_RUNNING;
251 status.dwWin32ExitCode = NO_ERROR;
252 status.dwCheckPoint = 0;
253 status.dwWaitHint = 0;
254
255 ::SetServiceStatus(handle, &status);
256
257 try
258 {
259 FingerDaemon();
260 }
261 catch (...) {}
262
263 status.dwCurrentState = SERVICE_STOPPED;
264 status.dwWin32ExitCode = NO_ERROR;
265 status.dwCheckPoint = 0;
266 status.dwWaitHint = 0;
267
268 ::SetServiceStatus(handle, &status);
269 }
270
271 void WINAPI FingerControl(DWORD control)
272 {
273 switch (control)
274 {
275 case SERVICE_CONTROL_STOP:
276 case SERVICE_CONTROL_SHUTDOWN:
277 status.dwCurrentState = SERVICE_STOP_PENDING;
278
279 ::SetEvent(stop);
280
281 break;
282
283 case SERVICE_CONTROL_INTERROGATE:
284 break;
285 }
286
287 ::SetServiceStatus(handle, &status);
288 }