|
|
1.1 root 1: /****************************************************************************\
2: * INCLUDES, DEFINES
3: \****************************************************************************/
4: #define STRICT
5: #include <windows.h>
6: #include <stdio.h>
7: #include <stdlib.h>
8:
9: #define PERR(api) printf("\n%s: Error %d from %s on line %d", \
10: __FILE__, GetLastError(), api, __LINE__);
11: #define PMSG(msg) printf("\n%s line %d: %s", \
12: __FILE__, __LINE__, msg);
13:
14: // this event is signalled when the
15: // worker thread ends
16: //
17: HANDLE hServDoneEvent = NULL;
18: SERVICE_STATUS ssStatus; // current status of the service
19:
20: SERVICE_STATUS_HANDLE sshStatusHandle;
21: DWORD dwGlobalErr;
22: DWORD TID = 0;
23: HANDLE threadHandle = NULL;
24: HANDLE pipeHandle;
25:
26:
27: /****************************************************************************\
28: * FUNCTION PROTOTYPES
29: \****************************************************************************/
30:
31: VOID service_main(DWORD dwArgc, LPTSTR *lpszArgv);
32: VOID service_ctrl(DWORD dwCtrlCode);
33: BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
34: DWORD dwWin32ExitCode,
35: DWORD dwCheckPoint,
36: DWORD dwWaitHint);
37: VOID die(char *reason);
38: VOID worker_thread(VOID *notUsed);
39: VOID StopSimpleService(LPTSTR lpszMsg);
40: BOOL WriteSD_ToA_File(PSECURITY_DESCRIPTOR psdAbsoluteSD, LPTSTR lpszFileName);
41:
42:
43: /****************************************************************************\
44: * GLOBAL VARIABLES AND TYPEDEFS
45: \****************************************************************************/
46:
47: #define SZ_SD_BUF 100
48: #define SZ_SID_BUF 75
49: #define SZ_ACL_BUF 150
50:
51: UCHAR ucAbsSDBuf [SZ_SD_BUF] = "";
52: UCHAR ucEvrSDBuf [SZ_SD_BUF] = "";
53: UCHAR ucSIDBuf [SZ_SID_BUF] = "";
54: UCHAR ucPwrUsrsSIDBuf [SZ_SID_BUF] = "";
55: UCHAR ucACLBuf [SZ_ACL_BUF] = "";
56:
57: DWORD dwSID = SZ_SID_BUF;
58: DWORD dwDACL = SZ_ACL_BUF;
59: BOOL bFloppiesAreLocked;
60:
61: PSECURITY_DESCRIPTOR psdAbsoluteSD = (PSECURITY_DESCRIPTOR)&ucAbsSDBuf;
62: PSECURITY_DESCRIPTOR psdEveryoneSD = (PSECURITY_DESCRIPTOR)&ucEvrSDBuf;
63: PSID psidAdministrators = (PSID)&ucSIDBuf;
64: PSID psidPowerUsers = (PSID)&ucPwrUsrsSIDBuf;
65: PACL pNewDACL = (PACL)&ucACLBuf;
1.1.1.2 ! root 66: BOOL bGotPowerUsersSid = FALSE;
1.1 root 67:
68:
69:
70: // main() --
71: // all main does is call StartServiceCtrlDispatcher
72: // to register the main service thread. When the
73: // API returns, the service has stopped, so exit.
74: //
75: VOID
76: main()
77: {
78: SERVICE_TABLE_ENTRY dispatchTable[] = {
79: { TEXT("SimpleService"), (LPSERVICE_MAIN_FUNCTION)service_main },
80: { NULL, NULL }
81: };
82:
83: #define FILE_TO_REDIRECT_STDOUT_TO "c:\\floplock.out"
84: freopen(FILE_TO_REDIRECT_STDOUT_TO,"w+",stdout);
85:
86: if (!StartServiceCtrlDispatcher(dispatchTable)) {
87: StopSimpleService("StartServiceCtrlDispatcher failed.");
88: }
89: }
90:
91:
92:
93: // service_main() --
94: // this function takes care of actually starting the service,
95: // informing the service controller at each step along the way.
96: // After launching the worker thread, it waits on the event
97: // that the worker thread will signal at its termination.
98: //
99: VOID
100: service_main(DWORD dwArgc, LPTSTR *lpszArgv)
101: {
102: DWORD dwWait;
103: SECURITY_ATTRIBUTES sa;
104:
105: // register our service control handler:
106: //
107: sshStatusHandle = RegisterServiceCtrlHandler(
108: TEXT("SimpleService"),
109: service_ctrl);
110:
111: if (!sshStatusHandle)
112: goto cleanup;
113:
114: // SERVICE_STATUS members that don't change in example
115: //
116: ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
117: ssStatus.dwServiceSpecificExitCode = 0;
118:
119:
120: // report the status to Service Control Manager.
121: //
122: if (!ReportStatusToSCMgr(
123: SERVICE_START_PENDING, // service state
124: NO_ERROR, // exit code
125: 1, // checkpoint
126: 3000)) // wait hint
127: goto cleanup;
128:
129: // create the event object. The control handler function signals
130: // this event when it receives the "stop" control code.
131: //
132: hServDoneEvent = CreateEvent(
133: NULL, // no security attributes
134: TRUE, // manual reset event
135: FALSE, // not-signalled
136: NULL); // no name
137:
138: if (hServDoneEvent == (HANDLE)NULL)
139: goto cleanup;
140:
141: // report the status to the service control manager.
142: //
143: if (!ReportStatusToSCMgr(
144: SERVICE_START_PENDING, // service state
145: NO_ERROR, // exit code
146: 2, // checkpoint
147: 3000)) // wait hint
148: goto cleanup;
149:
150: // Create a security descriptor that allows only local Administrators
151: // to do anything with the pipe. Since Domain administrators are
152: // normally also local Administrators, this will serve most needs
153:
154: /************************************************************************\
155: *
156: * Get SID of local Administrators
157: *
158: \************************************************************************/
159:
160: {
161: #define SZ_DOMAIN_BUF 40
162: #define SZ_PSNU_BUF 8
163: UCHAR ucDomainBuf [SZ_DOMAIN_BUF] = "";
164: UCHAR ucPSNUBuf [SZ_PSNU_BUF] = "";
165:
166: DWORD dwDomainName = SZ_DOMAIN_BUF;
167:
168: LPSTR lpszDomain = (LPSTR)&ucDomainBuf;
169: PSID_NAME_USE psnuType = (PSID_NAME_USE)&ucPSNUBuf;
170:
171: if(!LookupAccountName((LPSTR)NULL, /* local name */
172: "Administrators",
173: psidAdministrators,
174: &dwSID,
175: lpszDomain,
176: &dwDomainName,
177: psnuType))
178: { StopSimpleService("LookupAccountName");
179: }
180:
181: if (*psnuType != SidTypeAlias)
182: { StopSimpleService("LookupAccountName returned the wrong SID type");
183: }
184: }
185:
186: /************************************************************************\
187: *
1.1.1.2 ! root 188: * Get SID of Power Users, which is not defined on Windows NT Advanced
! 189: * Server machines, so if we fail to get the SID, simply record that
! 190: * fact, and don't try to use the Power Users' SID later
1.1 root 191: *
192: \************************************************************************/
193:
194: {
195: UCHAR ucDomainBuf [SZ_DOMAIN_BUF] = "";
196: UCHAR ucPSNUBuf [SZ_PSNU_BUF] = "";
197:
198: DWORD dwDomainName = SZ_DOMAIN_BUF;
199:
200: LPSTR lpszDomain = (LPSTR)&ucDomainBuf;
201: PSID_NAME_USE psnuType = (PSID_NAME_USE)&ucPSNUBuf;
202:
1.1.1.2 ! root 203: bGotPowerUsersSid =
! 204: LookupAccountName((LPSTR)NULL, /* local name */
1.1 root 205: "Power Users",
206: psidPowerUsers,
207: &dwSID,
208: lpszDomain,
209: &dwDomainName,
1.1.1.2 ! root 210: psnuType);
1.1 root 211:
1.1.1.2 ! root 212: if(bGotPowerUsersSid)
! 213: { if (*psnuType != SidTypeAlias)
! 214: { StopSimpleService("LookupAccountName returned the wrong SID type");
! 215: }
1.1 root 216: }
217: }
218:
219: /************************************************************************\
220: *
221: * Initialize new DACL
222: *
223: \************************************************************************/
224:
225: if (!InitializeAcl(pNewDACL,
226: dwDACL,
227: ACL_REVISION2))
228: { StopSimpleService("InitializeAcl");
229: }
230:
231: /************************************************************************\
232: *
233: * Allow All access for local Administrators only
234: *
235: \************************************************************************/
236:
237: if (!AddAccessAllowedAce(pNewDACL,
238: ACL_REVISION2,
239: FILE_ALL_ACCESS,
240: psidAdministrators))
241: { StopSimpleService("AddAccessAllowedAce");
242: }
243:
244: /************************************************************************\
245: *
246: * If we unlock the floppies when the service stops, then for the sake of
247: * consistency, we have to also allow Power Users on the Admin-only DACL,
248: * since Power Users can stop services. It would be inconsistent to try
249: * to lock Power Users away from their floppies if Power Users could get
250: * to the floppies simply by stopping the service
251: *
252: * It's still OK to use the same DACL for the pipe as for the floppies,
253: * that is, it's OK to let Power Users on the DACL for the pipe too. The
254: * reason is that it is not generally (and certainly not by default) the
255: * case that an account is a member of Power Users on more than their own
256: * machines. So, putting Power Users on the pipe let's Power Users admin
257: * the floppies via the pipe only on the machines on which they are
258: * actually Power Users, and again, on those machines they can stop the
259: * floppy-locking service as well
260: *
261: \************************************************************************/
262:
263: #define UNLOCK_AT_SERVICE_STOP (0==0)
1.1.1.2 ! root 264: if (UNLOCK_AT_SERVICE_STOP && bGotPowerUsersSid)
1.1 root 265: { if (!AddAccessAllowedAce(pNewDACL,
266: ACL_REVISION2,
267: FILE_ALL_ACCESS,
268: psidPowerUsers))
269: { StopSimpleService("AddAccessAllowedAce");
270: }
271: }
272:
273: /************************************************************************\
274: *
275: * Build SD in absolute format - first the Admins-only then the Everyone SD
276: *
277: \************************************************************************/
278:
279: if (!InitializeSecurityDescriptor(psdAbsoluteSD,
280: SECURITY_DESCRIPTOR_REVISION))
281: { StopSimpleService("InitializeSecurityDescriptor");
282: }
283:
284: if (!InitializeSecurityDescriptor(psdEveryoneSD,
285: SECURITY_DESCRIPTOR_REVISION))
286: { StopSimpleService("InitializeSecurityDescriptor");
287: }
288:
289: /************************************************************************\
290: *
291: * Set DACL into SD - first the Admins-only then the Everyone SD
292: *
293: \************************************************************************/
294:
295: if (!SetSecurityDescriptorDacl(psdAbsoluteSD,
296: TRUE, // fDaclPresent flag
297: pNewDACL,
298: FALSE)) // not a default DACL
299: { StopSimpleService("SetSecurityDescriptorDacl");
300: }
301:
302: if (!SetSecurityDescriptorDacl(psdEveryoneSD,
303: TRUE, // fDaclPresent flag
304: (PACL)NULL,
305: FALSE)) // not a default DACL
306: { StopSimpleService("SetSecurityDescriptorDacl");
307: }
308:
309: /************************************************************************\
310: *
311: * Check to see that SD is valid before attempting to write it to the file
312: *
313: \************************************************************************/
314:
315: if (!IsValidSecurityDescriptor(psdAbsoluteSD))
316: { StopSimpleService("IsValidSecurityDescriptor");
317: }
318:
319: sa.nLength = sizeof(sa);
320: sa.lpSecurityDescriptor = psdAbsoluteSD;
321: sa.bInheritHandle = TRUE; // why not... we spawn no processes
322:
323: // open our named pipe...
324: //
325: pipeHandle = CreateNamedPipe(
326: "\\\\.\\pipe\\sd_flppy", // name of pipe
327: PIPE_ACCESS_DUPLEX, // pipe open mode
328: PIPE_TYPE_MESSAGE |
329: PIPE_READMODE_MESSAGE |
330: PIPE_WAIT, // pipe IO type
331: 1, // number of instances
332: 0, // size of outbuf (0 == allocate as necessary)
333: 0, // size of inbuf
334: 1000, // default time-out value
335: &sa); // security attributes
336:
337: if (!pipeHandle) {
338: StopSimpleService("CreateNamedPipe");
339: return;
340: }
341:
342: // Set the same DACL onto the floppies
343: //
344:
345: /************************************************************************\
346: *
347: * Write SD to file system - first for A: then B:
348: *
349: \************************************************************************/
350:
351: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\A:"))
352: { StopSimpleService("Write of DACL to A: failed");
353: }
354:
355: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\B:"))
356: { StopSimpleService("Write of DACL to B: failed");
357: }
358:
359: bFloppiesAreLocked = TRUE;
360:
361: /************************************************************************\
362: *
363: * Works for CDROM drives as well - commented out as this samples is floppy
364: * only
365: *
366: \************************************************************************/
367: /*
368: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\E:"))
369: { StopSimpleService("Write of DACL to E: failed");
370: }
371: */
372: /************************************************************************\
373: *
374: * Works for COM ports as well - commented out as this samples is floppy only
375: *
376: \************************************************************************/
377: /*
378: if (!WriteSD_ToA_File(psdAbsoluteSD,"COM1:"))
379: { StopSimpleService("Write of DACL to COM1: failed");
380: }
381: */
382:
383: // start the thread that performs the work of the service.
384: //
385: threadHandle = CreateThread(
386: NULL, // security attributes
387: 0, // stack size (0 means inherit parent's stack size)
388: (LPTHREAD_START_ROUTINE)worker_thread,
389: NULL, // argument to thread
390: 0, // thread creation flags
391: &TID); // pointer to thread ID
392:
393: if (!threadHandle)
394: goto cleanup;
395:
396: // report the status to the service control manager.
397: //
398: if (!ReportStatusToSCMgr(
399: SERVICE_RUNNING, // service state
400: NO_ERROR, // exit code
401: 0, // checkpoint
402: 0)) // wait hint
403: goto cleanup;
404:
405: // wait indefinitely until hServDoneEvent is signaled.
406: //
407: dwWait = WaitForSingleObject(
408: hServDoneEvent, // event object
409: INFINITE); // wait indefinitely
410:
411: cleanup:
412:
413: if (hServDoneEvent != NULL)
414: CloseHandle(hServDoneEvent);
415:
416:
417: // try to report the stopped status to the service control manager.
418: //
419: if (sshStatusHandle != 0)
420: (VOID)ReportStatusToSCMgr(
421: SERVICE_STOPPED,
422: dwGlobalErr,
423: 0,
424: 0);
425:
426: // When SERVICE MAIN FUNCTION returns in a single service
427: // process, the StartServiceCtrlDispatcher function in
428: // the main thread returns, terminating the process.
429: //
430: return;
431: }
432:
433:
434:
435: // service_ctrl() --
436: // this function is called by the Service Controller whenever
437: // someone calls ControlService in reference to our service.
438: //
439: VOID
440: service_ctrl(DWORD dwCtrlCode)
441: {
442: DWORD dwState = SERVICE_RUNNING;
443:
444: // Handle the requested control code.
445: //
446: switch(dwCtrlCode) {
447:
448: // Pause the service if it is running.
449: //
450: case SERVICE_CONTROL_PAUSE:
451:
452: if (ssStatus.dwCurrentState == SERVICE_RUNNING) {
453: SuspendThread(threadHandle);
454: dwState = SERVICE_PAUSED;
455: }
456: break;
457:
458: // Resume the paused service.
459: //
460: case SERVICE_CONTROL_CONTINUE:
461:
462: if (ssStatus.dwCurrentState == SERVICE_PAUSED) {
463: ResumeThread(threadHandle);
464: dwState = SERVICE_RUNNING;
465: }
466: break;
467:
468: // Stop the service.
469: //
470: case SERVICE_CONTROL_STOP:
471:
472: dwState = SERVICE_STOP_PENDING;
473:
474: // Report the status, specifying the checkpoint and waithint,
475: // before setting the termination event.
476: //
477: ReportStatusToSCMgr(
478: SERVICE_STOP_PENDING, // current state
479: NO_ERROR, // exit code
480: 1, // checkpoint
481: 3000); // waithint
482:
483: if (UNLOCK_AT_SERVICE_STOP)
484: { if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\A:"))
485: { StopSimpleService("Unlock of A: failed, see log file");
486: }
487: if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\B:"))
488: { StopSimpleService("Unlock of B: failed, see log file");
489: }
490:
491: bFloppiesAreLocked = FALSE;
492: }
493:
494: SetEvent(hServDoneEvent);
495: return;
496:
497: // Update the service status.
498: //
499: case SERVICE_CONTROL_INTERROGATE:
500: break;
501:
502: // invalid control code
503: //
504: default:
505: break;
506:
507: }
508:
509: // send a status response.
510: //
511: ReportStatusToSCMgr(dwState, NO_ERROR, 0, 0);
512: }
513:
514:
515:
516: // worker_thread() --
517: // this function does the actual nuts and bolts work that
518: // the service requires. It will also Pause or Stop when
519: // asked by the service_ctrl function.
520: //
521: VOID
522: worker_thread(VOID *notUsed)
523: {
524: char inbuf[180];
525: char outbuf[180];
526: BOOL ret;
527: DWORD bytesRead;
528: DWORD bytesWritten;
529: DWORD dwLen;
530:
531: // okay, our pipe has been created, let's enter the simple
532: // processing loop...
533: //
534: while (1) {
535:
536: // wait for a connection...
537: //
538: ConnectNamedPipe(pipeHandle, NULL);
539:
540: // grab whatever's coming through the pipe...
541: //
542: ret = ReadFile(
543: pipeHandle, // file to read from
544: inbuf, // address of input buffer
545: sizeof(inbuf), // number of bytes to read
546: &bytesRead, // number of bytes read
547: NULL); // overlapped stuff, not needed
548:
549: if (!ret)
550: // pipe's broken... go back and reconnect
551: //
552: continue;
553:
554: switch (inbuf[0])
555: { case 'U':
556: dwLen = sprintf(outbuf,"Floppies were unlocked");
557:
558: if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\A:"))
559: { dwLen += sprintf(outbuf+dwLen,", unlock of A: failed, see log file");
560: }
561: if (!WriteSD_ToA_File(psdEveryoneSD,"\\\\.\\B:"))
562: { dwLen += sprintf(outbuf+dwLen,", unlock of B: failed, see log file");
563: }
564:
565: bFloppiesAreLocked = FALSE;
566: break;
567:
568: case 'L':
569: dwLen = sprintf(outbuf,"Floppies were locked");
570:
571: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\A:"))
572: { dwLen += sprintf(outbuf+dwLen,", lock of A: failed, see log file");
573: }
574: if (!WriteSD_ToA_File(psdAbsoluteSD,"\\\\.\\B:"))
575: { dwLen += sprintf(outbuf+dwLen,", lock of B: failed, see log file");
576: }
577:
578: bFloppiesAreLocked = TRUE;
579: break;
580:
581: case 'Q':
582: if (bFloppiesAreLocked)
583: { sprintf(outbuf,"Floppy status is: Locked");
584: }
585: else
586: { sprintf(outbuf,"Floppy status is: Unlocked");
587: }
588: break;
589:
590: default :
591: sprintf(outbuf,"Bad operation passed in");
592: }
593:
594: // send it back out...
595: //
596: ret = WriteFile(
597: pipeHandle, // file to write to
598: outbuf, // address of output buffer
599: sizeof(outbuf), // number of bytes to write
600: &bytesWritten, // number of bytes written
601: NULL); // overlapped stuff, not needed
602:
603: if (!ret)
604: // pipe's broken... go back and reconnect
605: //
606: continue;
607:
608: // drop the connection...
609: //
610: DisconnectNamedPipe(pipeHandle);
611: }
612: }
613:
614:
615:
616: // utility functions...
617:
618:
619:
620: // ReportStatusToSCMgr() --
621: // This function is called by the ServMainFunc() and
622: // ServCtrlHandler() functions to update the service's status
623: // to the service control manager.
624: //
625: BOOL
626: ReportStatusToSCMgr(DWORD dwCurrentState,
627: DWORD dwWin32ExitCode,
628: DWORD dwCheckPoint,
629: DWORD dwWaitHint)
630: {
631: BOOL fResult;
632:
633: // Disable control requests until the service is started.
634: //
635: if (dwCurrentState == SERVICE_START_PENDING)
636: ssStatus.dwControlsAccepted = 0;
637: else
638: ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
639: SERVICE_ACCEPT_PAUSE_CONTINUE;
640:
641: // These SERVICE_STATUS members are set from parameters.
642: //
643: ssStatus.dwCurrentState = dwCurrentState;
644: ssStatus.dwWin32ExitCode = dwWin32ExitCode;
645: ssStatus.dwCheckPoint = dwCheckPoint;
646:
647: ssStatus.dwWaitHint = dwWaitHint;
648:
649: // Report the status of the service to the service control manager.
650: //
651: if (!(fResult = SetServiceStatus(
652: sshStatusHandle, // service reference handle
653: &ssStatus))) { // SERVICE_STATUS structure
654:
655: // If an error occurs, stop the service.
656: //
657: StopSimpleService("SetServiceStatus");
658: }
659: return fResult;
660: }
661:
662:
663:
664: // The StopSimpleService function can be used by any thread to report an
665: // error, or stop the service.
666: //
667: VOID
668: StopSimpleService(LPTSTR lpszMsg)
669: {
670: CHAR chMsg[256];
671: HANDLE hEventSource;
672: LPTSTR lpszStrings[2];
673:
674: dwGlobalErr = GetLastError();
675:
676: // Use event logging to log the error.
677: //
678: hEventSource = RegisterEventSource(NULL,
679: TEXT("SimpleService"));
680:
681: sprintf(chMsg, "SimpleService error: %d", dwGlobalErr);
682: lpszStrings[0] = chMsg;
683: lpszStrings[1] = lpszMsg;
684:
685: if (hEventSource != NULL) {
686: ReportEvent(hEventSource, // handle of event source
687: EVENTLOG_ERROR_TYPE, // event type
688: 0, // event category
689: 0, // event ID
690: NULL, // current user's SID
691: 2, // strings in lpszStrings
692: 0, // no bytes of raw data
693: lpszStrings, // array of error strings
694: NULL); // no raw data
695:
696: (VOID) DeregisterEventSource(hEventSource);
697: }
698:
699: // Set a termination event to stop SERVICE MAIN FUNCTION.
700: //
701: SetEvent(hServDoneEvent);
702: }
703:
704: /****************************************************************************\
705: *
706: * FUNCTION: WriteSD_ToA_File
707: *
708: \****************************************************************************/
709:
710: BOOL WriteSD_ToA_File(PSECURITY_DESCRIPTOR psdAbsoluteSD, LPTSTR lpszFileName)
711: {
712: DWORD dwErrorMode;
713: BOOL bStatus;
714:
715: /**************************************************************************\
716: *
717: * SetErrorMode so we don't get the error due to no floppy disk in the floppy
718: * drive
719: *
720: \**************************************************************************/
721:
722: dwErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
723:
724: /**************************************************************************\
725: *
726: * Write SD to file system
727: *
728: \**************************************************************************/
729:
730: bStatus = SetFileSecurity(lpszFileName,
731: (SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION),
732: psdAbsoluteSD);
733:
734: /**************************************************************************\
735: *
736: * SetErrorMode back to its previous value
737: *
738: \**************************************************************************/
739:
740: SetErrorMode(dwErrorMode);
741:
742: if (!bStatus)
743: { if (ERROR_FILE_NOT_FOUND == GetLastError())
744: { printf("\nAttempted to lock %s, but it was not found",lpszFileName);
745: }
746: else
747: { PERR("SetFileSecurity");
748: return(FALSE);
749: }
750: }
751:
752: return(TRUE);
753: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.