There are no available options for this view.

Parent Directory Parent Directory | Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a> Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a>

Revision 1.25 - (show annotations) (download) (as text)
Fri Jun 20 08:06:32 2008 UTC (3 years, 11 months ago) by gneumann
Branch: MAIN
CVS Tags: HEAD
Branch point for: aolserver_v45_r1, aolserver_v45_r2
Changes since 1.24: +2 -2 lines
File MIME type: text/x-chdr
remove direct access to interp->result, initializing potentially uninitialized variables
1 /*
2 * The contents of this file are subject to the AOLserver Public License
3 * Version 1.1 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://aolserver.com/.
6 *
7 * Software distributed under the License is distributed on an "AS IS"
8 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9 * the License for the specific language governing rights and limitations
10 * under the License.
11 *
12 * The Original Code is AOLserver Code and related documentation
13 * distributed by AOL.
14 *
15 * The Initial Developer of the Original Code is America Online,
16 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
17 * Inc. All Rights Reserved.
18 *
19 * Alternatively, the contents of this file may be used under the terms
20 * of the GNU General Public License (the "GPL"), in which case the
21 * provisions of GPL are applicable instead of those above. If you wish
22 * to allow use of your version of this file only under the terms of the
23 * GPL and not to allow others to use your version of this file under the
24 * License, indicate your decision by deleting the provisions above and
25 * replace them with the notice and other provisions required by the GPL.
26 * If you do not delete the provisions above, a recipient may use your
27 * version of this file under either the License or the GPL.
28 */
29
30 /*
31 * nscp.c --
32 *
33 * Simple control port module for AOLserver which allows
34 * one to telnet to a specified port, login, and issue
35 * Tcl commands.
36 */
37
38 static const char *RCSID = "@(#) $Header: /cvsroot-fuse/aolserver/aolserver/nscp/nscp.c,v 1.25 2008/06/20 08:06:32 gneumann Exp $, compiled: " __DATE__ " " __TIME__;
39
40 #include "ns.h"
41
42 /*
43 * The following structure is allocated each instance of
44 * the loaded module.
45 */
46
47 typedef struct Mod {
48 Tcl_HashTable users;
49 char *server;
50 char *addr;
51 int port;
52 int echo;
53 int commandLogging;
54 } Mod;
55
56 static Ns_ThreadProc <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_EvalThread">EvalThread</a>;
57
58 /*
59 * The following structure is allocated for each session.
60 */
61
62 typedef struct Sess {
63 Mod *modPtr;
64 char *user;
65 int id;
66 SOCKET sock;
67 struct sockaddr_in sa;
68 } Sess;
69
70 static Ns_SockProc <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_AcceptProc">AcceptProc</a>;
71 static Tcl_CmdProc <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_ExitCmd">ExitCmd</a>;
72 static int <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_Login">Login</a>(Sess *sessPtr, Tcl_DString *unameDS);
73 static int <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(SOCKET sock, char *prompt, Tcl_DString *dsPtr, int echo);
74 static Ns_ArgProc <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_ArgProc">ArgProc</a>;
75
76 /*
77 * The following values are sent to the telnet client to enable
78 * and disable password prompt echo.
79 */
80
81 #define TN_IAC 255
82 #define TN_WILL 251
83 #define TN_WONT 252
84 #define TN_DO 253
85 #define TN_DONT 254
86 #define TN_EOF 236
87 #define TN_IP 244
88 #define TN_ECHO 1
89
90 static unsigned char do_echo[] = {TN_IAC, TN_DO, TN_ECHO};
91 static unsigned char dont_echo[] = {TN_IAC, TN_DONT, TN_ECHO};
92 static unsigned char will_echo[] = {TN_IAC, TN_WILL, TN_ECHO};
93 static unsigned char wont_echo[] = {TN_IAC, TN_WONT, TN_ECHO};
94
95
96 /*
97 *----------------------------------------------------------------------
98 *
99 * <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_NsCp_ModInit">NsCp_ModInit</a> --
100 *
101 * Load the config parameters, setup the structures, and
102 * listen on the control port.
103 *
104 * Results:
105 * None.
106 *
107 * Side effects:
108 * Server will listen for control connections on specified
109 * address and port.
110 *
111 *----------------------------------------------------------------------
112 */
113
114 int
115 <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_NsCp_ModInit">NsCp_ModInit</a>(char *server, char *module)
116 {
117 Mod *modPtr;
118 char *path, *addr, *pass, *user, *key, *end;
119 int i, new, port;
120 SOCKET lsock;
121 Ns_Set *set;
122 Tcl_HashEntry *hPtr;
123
124 /*
125 * Create the listening socket and callback.
126 */
127
128 path = <a href="/cvs/aolserver/aolserver/nsd/config.c#A_Ns_ConfigGetPath">Ns_ConfigGetPath</a>(server, module, NULL);
129 if (((addr = <a href="/cvs/aolserver/aolserver/nsd/config.c#A_Ns_ConfigGetValue">Ns_ConfigGetValue</a>(path, "address")) == NULL)
130 || (!<a href="/cvs/aolserver/aolserver/nsd/config.c#A_Ns_ConfigGetInt">Ns_ConfigGetInt</a>(path, "port", &port)) ) {
131 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Error, "nscp: address and port must be specified in config");
132 return NS_ERROR;
133 }
134 lsock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockListen">Ns_SockListen</a>(addr, port);
135 if (lsock == INVALID_SOCKET) {
136 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Error, "nscp: could not listen on %s:%d", addr, port);
137 return NS_ERROR;
138 }
139 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "nscp: listening on %s:%d", addr, port);
140
141 /*
142 * Create a new Mod structure for this instance.
143 */
144
145 modPtr = ns_malloc(sizeof(Mod));
146 modPtr->server = server;
147 modPtr->addr = addr;
148 modPtr->port = port;
149 if (!<a href="/cvs/aolserver/aolserver/nsd/config.c#A_Ns_ConfigGetBool">Ns_ConfigGetBool</a>(path, "echopassword", &modPtr->echo)) {
150 modPtr->echo = 1;
151 }
152
153 if (!<a href="/cvs/aolserver/aolserver/nsd/config.c#A_Ns_ConfigGetBool">Ns_ConfigGetBool</a>(path, "cpcmdlogging", &modPtr->commandLogging)) {
154 modPtr->commandLogging = 0; /* Default to off */
155 }
156
157 /*
158 * Initialize the hash table of authorized users. Entry values
159 * are either NULL indicating authorization should be checked
160 * via the <a href="/cvs/aolserver/aolserver/nsd/auth.c#A_Ns_AuthorizeUser">Ns_AuthorizeUser</a>() API or contain a Unix crypt(3)
161 * sytle encrypted password. For the later, the entry is
162 * compatible with /etc/passwd (i.e., username followed by
163 * password separated by colons).
164 */
165
166 Tcl_InitHashTable(&modPtr->users, TCL_STRING_KEYS);
167 path = <a href="/cvs/aolserver/aolserver/nsd/config.c#A_Ns_ConfigGetPath">Ns_ConfigGetPath</a>(server, module, "users", NULL);
168 set = <a href="/cvs/aolserver/aolserver/nsd/config.c#A_Ns_ConfigGetSection">Ns_ConfigGetSection</a>(path);
169 for (i = 0; set != NULL && i < Ns_SetSize(set); ++i) {
170 key = Ns_SetKey(set, i);
171 user = Ns_SetValue(set, i);
172 if (!STRIEQ(key, "user") || (pass = strchr(user, ':')) == NULL) {
173 continue;
174 }
175 *pass = '\0';
176 hPtr = Tcl_CreateHashEntry(&modPtr->users, user, &new);
177 if (new) {
178 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "nscp: added user: %s", user);
179 } else {
180 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Warning, "nscp: duplicate user: %s", user);
181 ns_free(Tcl_GetHashValue(hPtr));
182 }
183 *pass++ = ':';
184 end = strchr(pass, ':');
185 if (end != NULL) {
186 *end = '\0';
187 }
188 pass = ns_strdup(pass);
189 if (end != NULL) {
190 *end = ':';
191 }
192 Tcl_SetHashValue(hPtr, pass);
193 }
194 if (modPtr->users.numEntries == 0) {
195 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Warning, "nscp: no authorized users");
196 }
197 <a href="/cvs/aolserver/aolserver/nsd/sockcallback.c#A_Ns_SockCallback">Ns_SockCallback</a>(lsock, <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_AcceptProc">AcceptProc</a>, modPtr, NS_SOCK_READ|NS_SOCK_EXIT);
198 <a href="/cvs/aolserver/aolserver/nsd/proc.c#A_Ns_RegisterProcInfo">Ns_RegisterProcInfo</a>((void *)<a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_AcceptProc">AcceptProc</a>, "nscp", <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_ArgProc">ArgProc</a>);
199
200 return NS_OK;
201 }
202
203
204 /*
205 *----------------------------------------------------------------------
206 *
207 * <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_ArgProc">ArgProc</a> --
208 *
209 * Append listen port info for query callback.
210 *
211 * Results:
212 * None
213 *
214 * Side effects:
215 * None.
216 *
217 *----------------------------------------------------------------------
218 */
219
220 static void
221 <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_ArgProc">ArgProc</a>(Tcl_DString *dsPtr, void *arg)
222 {
223 Mod *modPtr = arg;
224 char buf[20];
225
226 sprintf(buf, "%d", modPtr->port);
227 Tcl_DStringStartSublist(dsPtr);
228 Tcl_DStringAppendElement(dsPtr, modPtr->addr);
229 Tcl_DStringAppendElement(dsPtr, buf);
230 Tcl_DStringEndSublist(dsPtr);
231 }
232
233
234 /*
235 *----------------------------------------------------------------------
236 *
237 * <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_AcceptProc">AcceptProc</a> --
238 *
239 * Socket callback to accept a new connection.
240 *
241 * Results:
242 * NS_TRUE to keep listening unless shutdown is in progress.
243 *
244 * Side effects:
245 * New <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_EvalThread">EvalThread</a> will be created.
246 *
247 *----------------------------------------------------------------------
248 */
249
250 static int
251 <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_AcceptProc">AcceptProc</a>(SOCKET lsock, void *arg, int why)
252 {
253 Mod *modPtr = arg;
254 Sess *sessPtr;
255 int len;
256 static int next;
257
258 if (why == NS_SOCK_EXIT) {
259 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "nscp: shutdown");
260 ns_sockclose(lsock);
261 return NS_FALSE;
262 }
263 sessPtr = ns_malloc(sizeof(Sess));
264 sessPtr->modPtr = modPtr;
265 len = sizeof(struct sockaddr_in);
266 sessPtr->sock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockAccept">Ns_SockAccept</a>(lsock, (struct sockaddr *) &sessPtr->sa, &len);
267 if (sessPtr->sock == INVALID_SOCKET) {
268 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Error, "nscp: accept() failed: %s",
269 ns_sockstrerror(ns_sockerrno));
270 ns_free(sessPtr);
271 } else {
272 sessPtr->id = ++next;
273 Ns_ThreadCreate(<a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_EvalThread">EvalThread</a>, sessPtr, 0, NULL);
274 }
275 return NS_TRUE;
276 }
277
278
279 /*
280 *----------------------------------------------------------------------
281 *
282 * <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_EvalThread">EvalThread</a> --
283 *
284 * Thread to read and evaluate commands from remote.
285 *
286 * Results:
287 * None.
288 *
289 * Side effects:
290 * Depends on commands.
291 *
292 *----------------------------------------------------------------------
293 */
294
295 static void
296 <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_EvalThread">EvalThread</a>(void *arg)
297 {
298 Tcl_Interp *interp;
299 Tcl_DString ds;
300 Tcl_DString unameDS;
301 char buf[64], *res;
302 int n, len, ncmd, stop;
303 Sess *sessPtr = arg;
304 char *server = sessPtr->modPtr->server;
305
306 /*
307 * Initialize the thread and login the user.
308 */
309
310 interp = NULL;
311 Tcl_DStringInit(&ds);
312 Tcl_DStringInit(&unameDS);
313 sprintf(buf, "-nscp:%d-", sessPtr->id);
314 Ns_ThreadSetName(buf);
315 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "nscp: %s connected", ns_inet_ntoa(sessPtr->sa.sin_addr));
316 if (!<a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_Login">Login</a>(sessPtr, &unameDS)) {
317 goto done;
318 }
319
320 sessPtr->user = Tcl_DStringValue(&unameDS);
321
322 /*
323 * Loop until the remote shuts down, evaluating complete
324 * commands.
325 */
326
327 interp = <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclAllocateInterp">Ns_TclAllocateInterp</a>(server);
328
329 /*
330 * Create a special exit command for this interp only.
331 */
332
333 stop = 0;
334 Tcl_CreateCommand(interp, "exit", <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_ExitCmd">ExitCmd</a>, (ClientData) &stop, NULL);
335
336 ncmd = 0;
337 while (!stop) {
338 Tcl_DStringTrunc(&ds, 0);
339 ++ncmd;
340 retry:
341 sprintf(buf, "%s:nscp %d> ", server, ncmd);
342 while (1) {
343 if (!<a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(sessPtr->sock, buf, &ds, 1)) {
344 goto done;
345 }
346 if (Tcl_CommandComplete(ds.string)) {
347 break;
348 }
349 sprintf(buf, "%s:nscp %d>>> ", server, ncmd);
350 }
351 while (ds.length > 0 && ds.string[ds.length-1] == '\n') {
352 Tcl_DStringTrunc(&ds, ds.length-1);
353 }
354 if (STREQ(ds.string, "")) {
355 goto retry; /* Empty command - try again. */
356 }
357
358 if (sessPtr->modPtr->commandLogging) {
359 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "nscp: %s %d: %s", sessPtr->user, ncmd, ds.string);
360 }
361
362 if (Tcl_RecordAndEval(interp, ds.string, 0) != TCL_OK) {
363 <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclLogError">Ns_TclLogError</a>(interp);
364 }
365 Tcl_AppendResult(interp, "\r\n", NULL);
366 res = Tcl_GetStringResult(interp);
367 len = strlen(res);
368 while (len > 0) {
369 if ((n = send(sessPtr->sock, res, len, 0)) <= 0) goto done;
370 len -= n;
371 res += n;
372 }
373
374 if (sessPtr->modPtr->commandLogging) {
375 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "nscp: %s %d: done", sessPtr->user, ncmd);
376 }
377 }
378 done:
379 Tcl_DStringFree(&ds);
380 Tcl_DStringFree(&unameDS);
381 if (interp != NULL) {
382 <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclDeAllocateInterp">Ns_TclDeAllocateInterp</a>(interp);
383 }
384 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "nscp: %s disconnected", ns_inet_ntoa(sessPtr->sa.sin_addr));
385 ns_sockclose(sessPtr->sock);
386 ns_free(sessPtr);
387 }
388
389
390 /*
391 *----------------------------------------------------------------------
392 *
393 * <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a> --
394 *
395 * Prompt for a line of input from the remote. \r\n sequences
396 * are translated to \n.
397 *
398 * Results:
399 * 1 if line received, 0 if remote dropped.
400 *
401 * Side effects:
402 * None.
403 *
404 *----------------------------------------------------------------------
405 */
406
407 static int
408 <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(SOCKET sock, char *prompt, Tcl_DString *dsPtr, int echo)
409 {
410 unsigned char buf[2048];
411 int n;
412 int result = 0;
413 int retry = 0;
414
415 /*
416 * Suppress output on things like password prompts.
417 */
418
419 if (!echo) {
420 send(sock, will_echo, 3, 0);
421 send(sock, dont_echo, 3, 0);
422 recv(sock, buf, sizeof(buf), 0); /* flush client ack thingies */
423 }
424 n = strlen(prompt);
425 if (send(sock, prompt, n, 0) != n) {
426 result = 0;
427 goto bail;
428 }
429
430 do {
431 if ((n = recv(sock, buf, sizeof(buf), 0)) <= 0) {
432 result = 0;
433 goto bail;
434 }
435 if (n > 1 && buf[n-1] == '\n' && buf[n-2] == '\r') {
436 buf[n-2] = '\n';
437 --n;
438 }
439
440 /*
441 * This EOT checker cannot happen in the context of telnet.
442 */
443 if (n == 1 && buf[0] == 4) {
444 result = 0;
445 goto bail;
446 }
447
448 /*
449 * Deal with telnet IAC commands in some sane way.
450 */
451
452 if (n > 1 && buf[0] == TN_IAC) {
453 if ( buf[1] == TN_EOF) {
454 result = 0;
455 goto bail;
456 } else if (buf[1] == TN_IP) {
457 result = 0;
458 goto bail;
459 } else if ((buf[1] == TN_WONT) && (retry < 2)) {
460 /*
461 * It seems like the flush at the bottom of this func
462 * does not always get all the acks, thus an echo ack
463 * showing up here. Not clear why this would be. Need
464 * to investigate further. For now, breeze past these
465 * (within limits).
466 */
467 retry++;
468 continue;
469 } else {
470 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Warning, "nscp: "
471 "unsupported telnet IAC code received from client");
472 result = 0;
473 goto bail;
474 }
475 }
476
477 Tcl_DStringAppend(dsPtr, buf, n);
478 result = 1;
479
480 } while (buf[n-1] != '\n');
481
482 bail:
483 if (!echo) {
484 send(sock, wont_echo, 3, 0);
485 send(sock, do_echo, 3, 0);
486 recv(sock, buf, sizeof(buf), 0); /* flush client ack thingies */
487 }
488 return result;
489 }
490
491
492 /*
493 *----------------------------------------------------------------------
494 *
495 * <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_Login">Login</a> --
496 *
497 * Attempt to login the user.
498 *
499 * Results:
500 * 1 if login ok, 0 otherwise.
501 *
502 * Side effects:
503 * Stores user's login name into unameDSPtr.
504 *
505 *----------------------------------------------------------------------
506 */
507
508 static int
509 <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_Login">Login</a>(Sess *sessPtr, Tcl_DString *unameDSPtr)
510 {
511 Tcl_HashEntry *hPtr;
512 Tcl_DString uds, pds;
513 char *encpass, *user, *pass, msg[255], buf[30];
514 int ok;
515
516 user = NULL;
517 ok = 0;
518 Tcl_DStringInit(&uds);
519 Tcl_DStringInit(&pds);
520 if (<a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(sessPtr->sock, "login: ", &uds, 1) &&
521 <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(sessPtr->sock, "Password: ", &pds, sessPtr->modPtr->echo)) {
522 user = <a href="/cvs/aolserver/aolserver/nsd/str.c#A_Ns_StrTrim">Ns_StrTrim</a>(uds.string);
523 pass = <a href="/cvs/aolserver/aolserver/nsd/str.c#A_Ns_StrTrim">Ns_StrTrim</a>(pds.string);
524 hPtr = Tcl_FindHashEntry(&sessPtr->modPtr->users, user);
525 if (hPtr != NULL) {
526 encpass = Tcl_GetHashValue(hPtr);
527 <a href="/cvs/aolserver/aolserver/nsd/crypt.c#A_Ns_Encrypt">Ns_Encrypt</a>(pass, encpass, buf);
528 if (STREQ(buf, encpass)) {
529 ok = 1;
530 }
531 }
532 }
533 if (ok) {
534 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "nscp: %s logged in", user);
535 Tcl_DStringAppend(unameDSPtr, user, -1);
536 sprintf(msg, "\nWelcome to %s running at %s (pid %d)\n"
537 "%s/%s (%s) for %s built on %s\nCVS Tag: %s\n",
538 sessPtr->modPtr->server,
539 <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoNameOfExecutable">Ns_InfoNameOfExecutable</a>(), <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoPid">Ns_InfoPid</a>(),
540 <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoServerName">Ns_InfoServerName</a>(), <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoServerVersion">Ns_InfoServerVersion</a>(), <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoLabel">Ns_InfoLabel</a>(),
541 <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoPlatform">Ns_InfoPlatform</a>(), <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoBuildDate">Ns_InfoBuildDate</a>(), <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoTag">Ns_InfoTag</a>());
542 } else {
543 <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Warning, "nscp: login failed: '%s'", user ? user : "?");
544 sprintf(msg, "Access denied!\n");
545 }
546 (void) send(sessPtr->sock, msg, (int)strlen(msg), 0);
547 Tcl_DStringFree(&uds);
548 Tcl_DStringFree(&pds);
549 return ok;
550 }
551
552
553 /*
554 *----------------------------------------------------------------------
555 *
556 * <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_ExitCmd">ExitCmd</a> --
557 *
558 * Special exit command for nscp.
559 *
560 * Results:
561 * Standard Tcl result.
562 *
563 * Side effects:
564 * None.
565 *
566 *----------------------------------------------------------------------
567 */
568
569 static int
570 <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_ExitCmd">ExitCmd</a>(ClientData arg, Tcl_Interp *interp, int argc, CONST char **argv)
571 {
572 int *stopPtr;
573
574 if (argc != 1) {
575 Tcl_AppendResult(interp, "wrong # args: should be \"",
576 (char*)argv[0], "\"", NULL);
577 return TCL_ERROR;
578 }
579
580 stopPtr = (int *) arg;
581 *stopPtr = 1;
582 Tcl_SetResult(interp, "\nGoodbye!", TCL_STATIC);
583 return TCL_OK;
584 }