ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/CCSFinger/CCSFinger.cpp
Revision: 614
Committed: 2005-12-12T18:47:20-08:00 (19 years, 6 months ago) by douglas
File size: 6339 byte(s)
Log Message:
Eep!

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