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

# 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 608 #include <string>
15 douglas 610 #include <sstream>
16 douglas 609 #include <vector>
17 douglas 613 #include <set>
18 douglas 595
19 douglas 610 inline std::string Utf8(const std::wstring &wstring)
20     {
21 douglas 613 std::string string(::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), NULL, 0, NULL, NULL), '\0');
22 douglas 610
23 douglas 613 ::WideCharToMultiByte(CP_UTF8, 0, wstring.data(), int(wstring.size()), const_cast<LPSTR>(string.data()), int(string.size()), NULL, NULL);
24 douglas 610
25     return string;
26     }
27    
28     class Finger
29     {
30     private:
31 douglas 613 struct Login
32     {
33     std::string login, name, session;
34 douglas 614 Login(const std::wstring &login, const std::wstring &session) : login(Utf8(login)), session(Utf8(session))
35 douglas 613 {
36 douglas 614 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 douglas 613 }
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 douglas 610 std::ostringstream stream;
53 douglas 613 std::set<Login> logins;
54 douglas 610
55     public:
56     Finger(bool full)
57     {
58     PWTS_SESSION_INFO sessions;
59     DWORD count;
60    
61 douglas 613 ::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &count);
62 douglas 610
63 douglas 613 for (PWTS_SESSION_INFO session(sessions); session != sessions + count; ++session)
64 douglas 610 {
65     LPTSTR name;
66     DWORD size;
67    
68 douglas 613 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSUserName, &name, &size);
69 douglas 610
70 douglas 613 if (!std::wstring(name).empty())
71     {
72     LPTSTR session_;
73 douglas 610
74 douglas 613 ::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSWinStationName, &session_, &size);
75 douglas 611
76 douglas 614 Login login(name, session_);
77 douglas 610
78 douglas 613 ::WTSFreeMemory(session_);
79    
80     logins.insert(login);
81     }
82    
83     ::WTSFreeMemory(name);
84 douglas 610 }
85    
86 douglas 613 ::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 douglas 610 }
96    
97     Finger(const std::string &name)
98     {
99 douglas 612 //NetQueryDisplayInformation
100     //NetUserGetInfo
101 douglas 610 }
102    
103     inline operator std::string()
104     {
105     return stream.str();
106     }
107     };
108    
109 douglas 595 LPTSTR name;
110 douglas 594 SERVICE_STATUS status;
111     SERVICE_STATUS_HANDLE handle;
112 douglas 595 HANDLE stop;
113 douglas 594 WSADATA data;
114 douglas 609 std::vector<HANDLE> threads;
115 douglas 594
116 douglas 596 void FingerDaemon();
117 douglas 609 DWORD WINAPI FingerListen(LPVOID server_);
118     DWORD WINAPI FingerDo(LPVOID client_);
119 douglas 596 void FingerStop(int);
120 douglas 595 void WINAPI FingerMain(DWORD argc, LPTSTR *argv);
121     void WINAPI FingerControl(DWORD control);
122 douglas 594
123     int _tmain(int argc, TCHAR *argv[])
124     {
125 douglas 609 SERVICE_TABLE_ENTRY entry[] = { { TEXT("CCS Finger Daemon"), LPSERVICE_MAIN_FUNCTION(FingerMain) }, { NULL, NULL } };
126 douglas 594
127 douglas 613 if (!::StartServiceCtrlDispatcher(entry))
128 douglas 594 {
129 douglas 613 DWORD error(::GetLastError());
130 douglas 594
131     switch (error)
132     {
133     case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
134 douglas 595 goto go;
135 douglas 594
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 douglas 595
155     go:
156 douglas 613 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
157 douglas 608
158 douglas 613 ::signal(SIGINT, FingerStop);
159 douglas 595
160 douglas 596 try
161     {
162     FingerDaemon();
163     }
164     catch (...) {}
165    
166 douglas 609 return 0;
167 douglas 594 }
168    
169 douglas 596 void FingerDaemon()
170 douglas 594 {
171 douglas 613 ::WSAStartup(MAKEWORD(2, 0), &data);
172 douglas 594
173     //
174    
175 douglas 613 SOCKET server(::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
176 douglas 594 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 douglas 613 ::bind(server, (SOCKADDR *)(&service), sizeof (service));
183     ::listen(server, SOMAXCONN);
184 douglas 594
185 douglas 613 threads.push_back(::CreateThread(NULL, 0, FingerListen, &server, 0, NULL));
186 douglas 608
187 douglas 613 while(::WaitForSingleObject(stop, 1000) != WAIT_OBJECT_0);
188 douglas 594
189     //
190    
191 douglas 613 ::closesocket(server);
192 douglas 608
193 douglas 613 ::WSACleanup();
194 douglas 596 }
195 douglas 594
196 douglas 609 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 douglas 613 threads.push_back(::CreateThread(NULL, 0, FingerDo, &client, 0, NULL));
205 douglas 609 }
206    
207     return 0;
208     }
209    
210     DWORD WINAPI FingerDo(LPVOID client_)
211     {
212     SOCKET &client(*reinterpret_cast<SOCKET *>(client_));
213 douglas 610 char buffer[1024];
214 douglas 613 std::istringstream stream(std::string(buffer, ::recv(client, buffer, sizeof buffer, 0)));
215 douglas 610 std::string line;
216 douglas 609
217 douglas 610 std::getline(stream, line);
218 douglas 609
219 douglas 610 stream.str(line);
220 douglas 609
221 douglas 610 std::getline(stream, line, '\r');
222 douglas 609
223 douglas 610 stream.str(line);
224 douglas 609
225 douglas 610 std::string name;
226     bool full(false);
227 douglas 609
228 douglas 610 while (stream >> line)
229     if (line == "/W")
230     full = true;
231     else
232     name = line;
233 douglas 609
234 douglas 610 std::string finger(name.empty() ? Finger(full) : Finger(name));
235 douglas 609
236 douglas 613 ::send(client, finger.data(), int(finger.size()), 0);
237     ::closesocket(client);
238 douglas 609
239     return 0;
240     }
241    
242 douglas 596 void FingerStop(int)
243     {
244 douglas 613 ::SetEvent(stop);
245 douglas 596 }
246    
247     void WINAPI FingerMain(DWORD argc, LPTSTR *argv)
248     {
249     name = argv[0];
250     handle = RegisterServiceCtrlHandler(name, LPHANDLER_FUNCTION(FingerControl));
251 douglas 613 stop = ::CreateEvent(NULL, TRUE, FALSE, NULL);
252 douglas 596
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 douglas 613 ::SetServiceStatus(handle, &status);
264 douglas 596
265     try
266     {
267     FingerDaemon();
268     }
269     catch (...) {}
270    
271 douglas 595 status.dwCurrentState = SERVICE_STOPPED;
272 douglas 594 status.dwWin32ExitCode = NO_ERROR;
273     status.dwCheckPoint = 0;
274     status.dwWaitHint = 0;
275    
276 douglas 613 ::SetServiceStatus(handle, &status);
277 douglas 594 }
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 douglas 613 ::SetEvent(stop);
288 douglas 594
289     break;
290    
291     case SERVICE_CONTROL_INTERROGATE:
292     break;
293     }
294    
295 douglas 613 ::SetServiceStatus(handle, &status);
296 douglas 594 }