Bug Summary

File:perm/nsperm.c
Warning:line 979, column 9
Duplicate code detected
Note:line 989, column 9
Similar code here

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsperm.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/isvv/naviserver/nsperm -resource-dir /usr/local/lib/clang/15.0.0 -D _FORTIFY_SOURCE=2 -D NDEBUG -D SYSTEM_MALLOC -I ../include -I /usr/include/tcl8.6 -D HAVE_CONFIG_H -internal-isystem /usr/local/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/isvv/naviserver/nsperm -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker alpha -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-07-23-130959-11103-1 -x c nsperm.c
1/*
2 * The contents of this file are subject to the Mozilla 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://mozilla.org/.
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 * nsperm --
32 *
33 * Permissions
34 */
35
36#include "ns.h"
37
38/*
39 * The following flags are for user record
40 */
41
42#define USER_FILTER_ALLOW1 1
43#define USER_CLEAR_TEXT2 2
44
45/*
46 * The following flags are for permission record
47 */
48
49#define PERM_IMPLICIT_ALLOW1 1
50
51NS_EXTERNextern __attribute__ ((visibility ("default"))) const int Ns_ModuleVersion;
52NS_EXPORT__attribute__ ((visibility ("default"))) const int Ns_ModuleVersion = 1;
53
54static const char *NS_EMPTY_STRING = "";
55
56/*
57 * The following structure is allocated for each instance of the module.
58 */
59
60typedef struct Server {
61 const char *server;
62 Tcl_HashTable users;
63 Tcl_HashTable groups;
64 Ns_RWLock lock;
65} Server;
66
67/*
68 * The "users" hash table points to this kind of data:
69 */
70
71typedef struct {
72 int flags;
73 char pwd[NS_ENCRYPT_BUFSIZE128];
74 Tcl_HashTable groups;
75 Tcl_HashTable nets;
76 Tcl_HashTable masks;
77 Tcl_HashTable hosts;
78} User;
79
80/*
81 * The "groups" hash table points to this kind of data:
82 */
83
84typedef struct {
85 Tcl_HashTable users;
86} Group;
87
88/*
89 * The urlspecific data referenced by uskey hold pointers to these:
90 */
91
92typedef struct {
93 int flags;
94 char *baseurl;
95 Tcl_HashTable allowuser;
96 Tcl_HashTable denyuser;
97 Tcl_HashTable allowgroup;
98 Tcl_HashTable denygroup;
99} Perm;
100
101/*
102 * Local functions defined in this file
103 */
104
105static Ns_TclTraceProc AddCmds;
106static Tcl_ObjCmdProc PermObjCmd;
107static Tcl_ObjCmdProc AddUserObjCmd;
108static Tcl_ObjCmdProc DelUserObjCmd;
109static Tcl_ObjCmdProc AddGroupObjCmd;
110static Tcl_ObjCmdProc DelGroupObjCmd;
111static Tcl_ObjCmdProc ListUsersObjCmd;
112static Tcl_ObjCmdProc ListGroupsObjCmd;
113static Tcl_ObjCmdProc ListPermsObjCmd;
114static Tcl_ObjCmdProc DelPermObjCmd;
115static Tcl_ObjCmdProc CheckPassObjCmd;
116static Tcl_ObjCmdProc SetPassObjCmd;
117
118NS_EXPORT__attribute__ ((visibility ("default"))) Ns_ModuleInitProc Ns_ModuleInit;
119
120static int AllowDenyObjCmd(
121 ClientData data,
122 Tcl_Interp *interp,
123 int objc,
124 Tcl_Obj *const* objv,
125 bool_Bool allow,
126 bool_Bool user
127);
128
129static bool_Bool ValidateUserAddr(User * userPtr, const char *peer);
130static Ns_RequestAuthorizeProc AuthProc;
131static void WalkCallback(Tcl_DString * dsPtr, const void *arg);
132static Ns_ReturnCode CreateNonce(const char *privatekey, char **nonce, const char *uri);
133static Ns_ReturnCode CreateHeader(const Server * servPtr, const Ns_Conn *conn, bool_Bool stale);
134/*static Ns_ReturnCode CheckNonce(const char *privatekey, char *nonce, char *uri, int timeout);*/
135
136static void FreeUserInfo(User *userPtr, const char *name)
137 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2)));
138
139
140/*
141 * Static variables defined in this file.
142 */
143
144static int uskey = -1;
145static char usdigest[128];
146static Tcl_HashTable serversTable;
147
148
149/*
150 *----------------------------------------------------------------------
151 *
152 * Ns_ModuleInit --
153 *
154 * Initialize the perms module
155 *
156 * Results:
157 * NS_OK/NS_ERROR
158 *
159 * Side effects:
160 * Init hash table, add Tcl commands.
161 *
162 *----------------------------------------------------------------------
163 */
164
165NS_EXPORT__attribute__ ((visibility ("default"))) Ns_ReturnCode
166Ns_ModuleInit(const char *server, const char *UNUSED(module)UNUSED_module __attribute__((__unused__)))
167{
168 Server *servPtr;
169 Tcl_HashEntry *hPtr;
170 int isNew;
171 Ns_ReturnCode result;
172
173 if (uskey < 0) {
174 double d;
175 char buf[TCL_INTEGER_SPACE24];
176 Ns_CtxMD5 md5;
177 unsigned long bigRamdomNumber;
178 unsigned char sig[16];
179
180 uskey = Ns_UrlSpecificAlloc();
181 Tcl_InitHashTable(&serversTable, TCL_STRING_KEYS(0));
182
183 /* Make a really big random number */
184 d = Ns_DRand();
185 bigRamdomNumber = (unsigned long) (d * 1024 * 1024 * 1024);
186
187 /* There is no requirement to hash it but it won't hurt */
188 Ns_CtxMD5Init(&md5);
189 snprintf(buf, sizeof(buf), "%lu", bigRamdomNumber)__builtin___snprintf_chk (buf, sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), "%lu", bigRamdomNumber)
;
190 Ns_CtxMD5Update(&md5, (unsigned char *) buf, strlen(buf));
191 Ns_CtxMD5Final(&md5, sig);
192 Ns_HexString(sig, usdigest, 16, NS_TRUE1);
193 }
194 servPtr = ns_malloc(sizeof(Server));
195 servPtr->server = server;
196 Tcl_InitHashTable(&servPtr->users, TCL_STRING_KEYS(0));
197 Tcl_InitHashTable(&servPtr->groups, TCL_STRING_KEYS(0));
198 Ns_RWLockInit(&servPtr->lock);
199 Ns_RWLockSetName2(&servPtr->lock, "rw:nsperm", server);
200 Ns_SetRequestAuthorizeProc(server, AuthProc);
201
202 result = Ns_TclRegisterTrace(server, AddCmds, servPtr, NS_TCL_TRACE_CREATE);
203 hPtr = Tcl_CreateHashEntry(&serversTable, server, &isNew)(*((&serversTable)->createProc))(&serversTable, (const
char *)(server), &isNew)
;
204 Tcl_SetHashValue(hPtr, servPtr)((hPtr)->clientData = (ClientData) (servPtr));
205
206 return result;
207}
208
209
210/*
211 *----------------------------------------------------------------------
212 *
213 * AddCmds --
214 *
215 * Add Tcl commands for perms
216 *
217 * Results:
218 * NS_OK
219 *
220 * Side effects:
221 * Adds Tcl commands
222 *
223 *----------------------------------------------------------------------
224 */
225
226static Ns_ReturnCode AddCmds(Tcl_Interp *interp, const void *arg)
227{
228 Tcl_CreateObjCommand(interp, "ns_perm", PermObjCmd, (ClientData)arg, NULL((void*)0));
229 return NS_OK;
230}
231
232
233/*
234 *----------------------------------------------------------------------
235 *
236 * PermObjCmd --
237 *
238 * Implements "ns_perm".
239 *
240 * Results:
241 * Std Tcl ret val
242 *
243 * Side effects:
244 * Yes.
245 *
246 *----------------------------------------------------------------------
247 */
248
249static int PermObjCmd(ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *const* objv)
250{
251 Server *servPtr = data;
252 int opt, status = TCL_OK0;
253
254 static const char *opts[] = {
255 "adduser", "addgroup",
256 "listusers", "listgroups", "listperms",
257 "allowuser", "allowgroup",
258 "denyuser", "denygroup",
259 "checkpass", "setpass",
260 "deluser", "delgroup", "delperm",
261 NULL((void*)0)
262 };
263 enum {
264 cmdAddUser, cmdAddGroup,
265 cmdListUsers, cmdListGroups, cmdListPerms,
266 cmdAllowUser, cmdAllowGroup,
267 cmdDenyUser, cmdDenyGroup,
268 cmdCheckPass, cmdSetPass,
269 cmdDelUser, cmdDelGroup, cmdDelPerm
270 };
271
272 if (objc < 2) {
273 Tcl_WrongNumArgs(interp, 1, objv, "option ?args ...?");
274 return TCL_ERROR1;
275 }
276 if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0, &opt)Tcl_GetIndexFromObjStruct(interp, objv[1], opts, sizeof(char *
), "option", 0, &opt)
!= TCL_OK0) {
277 return TCL_ERROR1;
278 }
279
280 switch (opt) {
281 case cmdAddUser:
282 status = AddUserObjCmd(servPtr, interp, objc, objv);
283 break;
284
285 case cmdDelUser:
286 status = DelUserObjCmd(servPtr, interp, objc, objv);
287 break;
288
289 case cmdAddGroup:
290 status = AddGroupObjCmd(servPtr, interp, objc, objv);
291 break;
292
293 case cmdDelGroup:
294 status = DelGroupObjCmd(servPtr, interp, objc, objv);
295 break;
296
297 case cmdListUsers:
298 status = ListUsersObjCmd(servPtr, interp, objc, objv);
299 break;
300
301 case cmdListGroups:
302 status = ListGroupsObjCmd(servPtr, interp, objc, objv);
303 break;
304
305 case cmdListPerms:
306 status = ListPermsObjCmd(servPtr, interp, objc, objv);
307 break;
308
309 case cmdDelPerm:
310 status = DelPermObjCmd(servPtr, interp, objc, objv);
311 break;
312
313 case cmdAllowUser:
314 status = AllowDenyObjCmd(servPtr, interp, objc, objv, NS_TRUE1, NS_TRUE1);
315 break;
316
317 case cmdDenyUser:
318 status = AllowDenyObjCmd(servPtr, interp, objc, objv, NS_FALSE0, NS_TRUE1);
319 break;
320
321 case cmdAllowGroup:
322 status = AllowDenyObjCmd(servPtr, interp, objc, objv, NS_TRUE1, NS_FALSE0);
323 break;
324
325 case cmdDenyGroup:
326 status = AllowDenyObjCmd(servPtr, interp, objc, objv, NS_FALSE0, NS_FALSE0);
327 break;
328
329 case cmdCheckPass:
330 status = CheckPassObjCmd(servPtr, interp, objc, objv);
331 break;
332
333 case cmdSetPass:
334 status = SetPassObjCmd(servPtr, interp, objc, objv);
335 break;
336 }
337 return status;
338}
339
340
341/*
342 *----------------------------------------------------------------------
343 *
344 * AuthProc --
345 *
346 * Authorize a URL--this callback is called when a new
347 * connection is received.
348
349 * Digest authentication per RFC 2617 but currently
350 * supports qop="auth" and MD5 hashing only.
351 *
352 * The logic goes like this:
353 * - fetch the Authorization header
354 * if it exists, continue
355 * if it doesn't exist, return an Unauthorized header and
356 * WWW-Authenticate header.
357 * - Parse the Authorization header and perform digest authentication
358 * against it.
359
360 * Results:
361 * NS_OK: accept;
362 * NS_FORBIDDEN or NS_UNAUTHORIZED: go away;
363 * NS_ERROR: oops
364 *
365 * Side effects:
366 * None
367 *
368 *----------------------------------------------------------------------
369 */
370
371static Ns_ReturnCode AuthProc(const char *server, const char *method, const char *url,
372 const char *user, const char *pwd, const char *peer)
373{
374 Ns_ReturnCode status;
375 Ns_Set *set;
376 Server *servPtr;
377 Perm *permPtr;
378 User *userPtr;
379 Tcl_HashEntry *hPtr;
380 Tcl_HashSearch search;
381 char buf[NS_ENCRYPT_BUFSIZE128], *group;
382 const char *auth = NULL((void*)0);
383 Ns_Conn *conn = Ns_GetConn();
384
385 if (conn == NULL((void*)0)) {
386 Ns_Log(Error, "nsperm: authProc called without connection");
387 return NS_ERROR;
388 }
389 if (user == NULL((void*)0)) {
390 user = NS_EMPTY_STRING;
391 }
392 if (pwd == NULL((void*)0)) {
393 pwd = NS_EMPTY_STRING;
394 }
395
396 hPtr = Tcl_FindHashEntry(&serversTable, server)(*((&serversTable)->findProc))(&serversTable, (const
char *)(server))
;
397 if (hPtr == NULL((void*)0)) {
398 return NS_FORBIDDEN;
399 }
400 servPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
401
402 Ns_RWLockRdLock(&servPtr->lock);
403 permPtr = Ns_UrlSpecificGet(server, method, url, uskey);
404 if (permPtr == NULL((void*)0)) {
405 status = NS_OK;
406 goto done;
407 }
408
409 /*
410 * Make sure we have parsed Authentication header properly,
411 * otherwise fallback to Basic method
412 */
413
414 set = Ns_ConnAuth(conn);
415 if (set != NULL((void*)0)) {
416 auth = Ns_SetIGet(set, "AuthMethod");
417 }
418 if (auth == NULL((void*)0)) {
419 auth = "Basic";
420 }
421
422 /*
423 * The first checks below deny access.
424 */
425
426 status = NS_UNAUTHORIZED;
427
428 /*
429 * Find user record, this is true for all methods
430 */
431
432 hPtr = Tcl_FindHashEntry(&servPtr->users, user)(*((&servPtr->users)->findProc))(&servPtr->users
, (const char *)(user))
;
433 if (hPtr == NULL((void*)0)) {
434 goto done;
435 }
436 userPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
437
438 /*
439 * Check which auth method to use, permission record will
440 * define how to verify user
441 */
442
443 if (STREQ(auth, "Basic")(((*(auth)) == (*("Basic"))) && (strcmp((auth),("Basic"
)) == 0))
) {
444
445 /*
446 * Basic Authentiction: Verify user password (if any).
447 */
448
449 if (userPtr->pwd[0] != 0) {
450 if (pwd[0] == 0) {
451 goto done;
452 }
453 if (!(userPtr->flags & USER_CLEAR_TEXT2)) {
454 Ns_Encrypt(pwd, userPtr->pwd, buf);
455 pwd = buf;
456 }
457 if (!STREQ(userPtr->pwd, pwd)(((*(userPtr->pwd)) == (*(pwd))) && (strcmp((userPtr
->pwd),(pwd)) == 0))
) {
458 goto done;
459 }
460 }
461 } else {
462
463 /*
464 * Digest Authentication
465 */
466
467 if (STREQ(auth, "Digest")(((*(auth)) == (*("Digest"))) && (strcmp((auth),("Digest"
)) == 0))
) {
468
469 }
470 }
471
472 /*
473 * Check for a valid user address.
474 */
475
476 if (ValidateUserAddr(userPtr, peer) == NS_FALSE0) {
477 /*
478 * Null user never gets forbidden--give a chance to enter password.
479 */
480 deny:
481 if (*user != '\0') {
482 status = NS_FORBIDDEN;
483 }
484 goto done;
485 }
486
487 /*
488 * Check user deny list.
489 */
490
491 if (Tcl_FindHashEntry(&permPtr->denyuser, user)(*((&permPtr->denyuser)->findProc))(&permPtr->
denyuser, (const char *)(user))
!= NULL((void*)0)) {
492 goto deny;
493 }
494
495 /*
496 * Loop over all groups in this perm record, and then
497 * see if the user is in any of those groups.
498 */
499
500 hPtr = Tcl_FirstHashEntry(&permPtr->denygroup, &search);
501 while (hPtr != NULL((void*)0)) {
502 group = Tcl_GetHashKey(&permPtr->denygroup, hPtr)((void *) (((&permPtr->denygroup)->keyType == (1) ||
(&permPtr->denygroup)->keyType == (-1)) ? (hPtr)->
key.oneWordValue : (hPtr)->key.string))
;
503 if (Tcl_FindHashEntry(&userPtr->groups, group)(*((&userPtr->groups)->findProc))(&userPtr->
groups, (const char *)(group))
!= NULL((void*)0)) {
504 goto deny;
505 }
506 hPtr = Tcl_NextHashEntry(&search);
507 }
508
509 /*
510 * Valid checks below allow access.
511 */
512
513 status = NS_OK;
514
515 /*
516 * Check the allow lists, starting with users
517 */
518
519 if (Tcl_FindHashEntry(&permPtr->allowuser, user)(*((&permPtr->allowuser)->findProc))(&permPtr->
allowuser, (const char *)(user))
!= NULL((void*)0)) {
520 goto done;
521 }
522
523 /*
524 * Loop over all groups in this perm record, and then
525 * see if the user is in any of those groups.
526 */
527
528 hPtr = Tcl_FirstHashEntry(&permPtr->allowgroup, &search);
529 while (hPtr != NULL((void*)0)) {
530 group = Tcl_GetHashKey(&permPtr->allowgroup, hPtr)((void *) (((&permPtr->allowgroup)->keyType == (1) ||
(&permPtr->allowgroup)->keyType == (-1)) ? (hPtr)->
key.oneWordValue : (hPtr)->key.string))
;
531 if (Tcl_FindHashEntry(&userPtr->groups, group)(*((&userPtr->groups)->findProc))(&userPtr->
groups, (const char *)(group))
!= NULL((void*)0)) {
532 goto done;
533 }
534 hPtr = Tcl_NextHashEntry(&search);
535 }
536
537 /*
538 * Checks above failed. If implicit allow is not set,
539 * change the status back to unauthorized. This flag will be set only when
540 * at least one deny user was added to the permission record, otherwise
541 * it will allow user with name "" to pass. What a nonsense!
542 */
543
544 if (!(permPtr->flags & PERM_IMPLICIT_ALLOW1)) {
545 status = NS_UNAUTHORIZED;
546 }
547
548 done:
549
550 /*
551 * For Digest authentication we create WWW-Authenticate header manually
552 */
553
554 if (status == NS_UNAUTHORIZED && !strcmp(auth, "Digest")) {
555 CreateHeader(servPtr, conn, NS_FALSE0);
556 }
557
558 Ns_RWLockUnlock(&servPtr->lock);
559 return status;
560}
561
562
563/*
564 *----------------------------------------------------------------------
565 *
566 * ValidateUserAddr --
567 *
568 * Validate that the peer address is valid for this user
569 *
570 * Results:
571 * NS_TRUE if allowed, NS_FALSE if not
572 *
573 * Side effects:
574 * None
575 *
576 *----------------------------------------------------------------------
577 */
578static bool_Bool
579ValidateUserAddr(User *userPtr, const char *peer)
580{
581 int validIp;
582 bool_Bool success;
583 Tcl_HashSearch search;
584 Tcl_HashEntry *hPtr;
585 struct NS_SOCKADDR_STORAGEsockaddr_storage peerStruct, ipStruct;
586 struct sockaddr *peerPtr = (struct sockaddr *)&peerStruct,
587 *ipPtr = (struct sockaddr *)&ipStruct;
588
589 if (peer == NULL((void*)0)) {
590 return NS_TRUE1;
591 }
592
593 memset(peerPtr, 0, sizeof(struct NS_SOCKADDR_STORAGEsockaddr_storage));
594
595 validIp = ns_inet_pton(peerPtr, peer);
596 if (validIp < 1) {
597 return NS_FALSE0;
598 }
599
600 /*
601 * Loop over each netmask, AND the peer address with it,
602 * then see if that address is in the list.
603 */
604
605 hPtr = Tcl_FirstHashEntry(&userPtr->masks, &search);
606 while (hPtr != NULL((void*)0)) {
607 struct sockaddr *maskPtr;
608 Tcl_HashEntry *entryPtr;
609
610 maskPtr = (struct sockaddr *)Tcl_GetHashKey(&userPtr->masks, hPtr)((void *) (((&userPtr->masks)->keyType == (1) || (&
userPtr->masks)->keyType == (-1)) ? (hPtr)->key.oneWordValue
: (hPtr)->key.string))
;
611
612 Ns_SockaddrMask(peerPtr, maskPtr, ipPtr);
613 /*
614 Ns_LogSockaddr(Notice, "FOUND: mask", maskPtr);
615 Ns_LogSockaddr(Notice, "FOUND: peer", peerPtr);
616 Ns_LogSockaddr(Notice, "FOUND: ====", ipPtr);
617 */
618
619 /*
620 * There is a potential match. Now make sure it works with the
621 * right address's mask.
622 */
623 entryPtr = Tcl_FindHashEntry(&userPtr->nets, (char *)ipPtr)(*((&userPtr->nets)->findProc))(&userPtr->nets
, (const char *)((char *)ipPtr))
;
624
625 if (entryPtr != NULL((void*)0)) {
626 char maskString[NS_IPADDR_SIZE46];
627
628 ns_inet_ntop(maskPtr, maskString, NS_IPADDR_SIZE46);
629 /*
630 * We have an entry, does it really match with saved mask?
631 */
632 if (STREQ((char *)Tcl_GetHashValue(entryPtr), maskString)(((*((char *)((entryPtr)->clientData))) == (*(maskString))
) && (strcmp(((char *)((entryPtr)->clientData)),(maskString
)) == 0))
) {
633 if (userPtr->flags & USER_FILTER_ALLOW1) {
634 success = NS_TRUE1;
635 } else {
636 success = NS_FALSE0;
637 }
638 return success;
639 }
640 }
641 hPtr = Tcl_NextHashEntry(&search);
642 }
643
644 if (userPtr->flags & USER_FILTER_ALLOW1) {
645 success = NS_FALSE0;
646 } else {
647 success = NS_TRUE1;
648 }
649 if (userPtr->hosts.numEntries > 0) {
650 Ns_DStringTcl_DString addr;
651
652 /*
653 * If we have gotten this far, it is necessary to do a
654 * reverse dns lookup and try to make a decision
655 * based on that, if possible.
656 */
657
658 Ns_DStringInitTcl_DStringInit(&addr);
659 if (Ns_GetHostByAddr(&addr, peer) == NS_TRUE1) {
660 char *start = addr.string;
661
662 /*
663 * If the hostname is blah.aol.com, check the hash table
664 * for:
665 *
666 * blah.aol.com
667 * .aol.com
668 * .com
669 *
670 * Break out of the loop as soon as a match is found or
671 * all possibilities are exhausted.
672 */
673
674 while (start != NULL((void*)0) && start[0] != '\0') {
675 char *last;
676
677 last = start;
678 hPtr = Tcl_FindHashEntry(&userPtr->hosts, start)(*((&userPtr->hosts)->findProc))(&userPtr->hosts
, (const char *)(start))
;
679 if (hPtr != NULL((void*)0)) {
680 if (userPtr->flags & USER_FILTER_ALLOW1) {
681 success = NS_TRUE1;
682 } else {
683 success = NS_FALSE0;
684 }
685 break;
686 }
687 start = strchr(start + 1, INTCHAR('.')((int)((unsigned char)(('.')))));
688 if (start == NULL((void*)0)) {
689 break;
690 }
691 if (last == start) {
692 Ns_Log(Warning, "nsperm: " "invalid hostname '%s'", addr.string);
693 break;
694 }
695 }
696 }
697 }
698
699 return success;
700}
701
702
703/*
704 *----------------------------------------------------------------------
705 *
706 * FreeUserInfo --
707 *
708 * Free the user information.
709 *
710 * Results:
711 * none.
712 *
713 * Side effects:
714 * free memory.
715 *
716 *----------------------------------------------------------------------
717 */
718
719static void
720FreeUserInfo(User *userPtr, const char *name)
721{
722 Tcl_HashEntry *hPtr;
723 Tcl_HashSearch search;
724
725 NS_NONNULL_ASSERT(userPtr != NULL)((void) (0));
726 NS_NONNULL_ASSERT(name != NULL)((void) (0));
727
728 hPtr = Tcl_FirstHashEntry(&userPtr->groups, &search);
729 while (hPtr != NULL((void*)0)) {
730 Group *groupPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
731
732 hPtr = Tcl_FindHashEntry(&groupPtr->users, name)(*((&groupPtr->users)->findProc))(&groupPtr->
users, (const char *)(name))
;
733 if (hPtr != NULL((void*)0)) {
734 Tcl_DeleteHashEntry(hPtr);
735 }
736 hPtr = Tcl_NextHashEntry(&search);
737 }
738 hPtr = Tcl_FirstHashEntry(&userPtr->nets, &search);
739 while (hPtr != NULL((void*)0)) {
740 char *maskString = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
741
742 if (maskString != NULL((void*)0)) {
743 ns_free(maskString);
744 }
745 Tcl_DeleteHashEntry(hPtr);
746 hPtr = Tcl_NextHashEntry(&search);
747 }
748 Tcl_DeleteHashTable(&userPtr->groups);
749 Tcl_DeleteHashTable(&userPtr->masks);
750 Tcl_DeleteHashTable(&userPtr->nets);
751 Tcl_DeleteHashTable(&userPtr->hosts);
752 ns_free(userPtr);
753}
754
755
756/*
757 *----------------------------------------------------------------------
758 *
759 * AddUserObjCmd --
760 *
761 * Implements "ns_perm adduser".
762 *
763 * Results:
764 * Tcl resut
765 *
766 * Side effects:
767 * A user may be added to the global user hash table
768 *
769 *----------------------------------------------------------------------
770 */
771
772static int AddUserObjCmd(ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *const* objv)
773{
774 Server *servPtr = data;
775 User *userPtr;
776 Tcl_HashEntry *hPtr;
777 struct NS_SOCKADDR_STORAGEsockaddr_storage ip, mask;
778 struct sockaddr *ipPtr = (struct sockaddr *)&ip, *maskPtr = (struct sockaddr *)&mask;
779 char buf[NS_ENCRYPT_BUFSIZE128];
780 char *name, *pwd, *field = NULL((void*)0), *salt = NULL((void*)0);
781 int isNew, i, nargs = 0, allow = 0, deny = 0, clear = 0;
782
783 Ns_ObjvSpec opts[] = {
784 {"-allow", Ns_ObjvBool, &allow, INT2PTR(NS_TRUE)((void *)(intptr_t)(1))},
785 {"-deny", Ns_ObjvBool, &deny, INT2PTR(NS_TRUE)((void *)(intptr_t)(1))},
786 {"-clear", Ns_ObjvBool, &clear, INT2PTR(NS_TRUE)((void *)(intptr_t)(1))},
787 {"-salt", Ns_ObjvString, &salt, NULL((void*)0)},
788 {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)},
789 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
790 };
791 Ns_ObjvSpec args[] = {
792 {"name", Ns_ObjvString, &name, NULL((void*)0)},
793 {"pwd", Ns_ObjvString, &pwd, NULL((void*)0)},
794 {"field", Ns_ObjvString, &field, NULL((void*)0)},
795 {"?hosts", Ns_ObjvArgs, &nargs, NULL((void*)0)},
796 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
797 };
798 if (Ns_ParseObjv(opts, args, interp, 2, objc, objv) != NS_OK) {
799 return TCL_ERROR1;
800 }
801
802 userPtr = ns_calloc(1u, sizeof(User));
803 if (clear != 0) {
804 userPtr->flags |= USER_CLEAR_TEXT2;
805 }
806 if (salt != NULL((void*)0)) {
807 Ns_Encrypt(pwd, salt, buf);
808 pwd = buf;
809 userPtr->flags &= ~USER_CLEAR_TEXT2;
810 }
811 snprintf(userPtr->pwd, sizeof(userPtr->pwd), "%s", pwd)__builtin___snprintf_chk (userPtr->pwd, sizeof(userPtr->
pwd), 2 - 1, __builtin_object_size (userPtr->pwd, 2 > 1
), "%s", pwd)
;
812
813 Tcl_InitHashTable(&userPtr->nets, (int)(sizeof(struct NS_SOCKADDR_STORAGEsockaddr_storage) / sizeof(int)));
814 Tcl_InitHashTable(&userPtr->masks, (int)(sizeof(struct NS_SOCKADDR_STORAGEsockaddr_storage) / sizeof(int)));
815 Tcl_InitHashTable(&userPtr->hosts, TCL_STRING_KEYS(0));
816 Tcl_InitHashTable(&userPtr->groups, TCL_STRING_KEYS(0));
817
818 // fprintf(stderr, "============= add user <%s> pwd <%s> field <%s> nrags %d\n", name, pwd, field, nargs);
819
820 /*
821 * Both -allow and -deny can be used for consistency, but
822 * -deny has precedence
823 */
824
825 if (allow && !deny) {
826 userPtr->flags |= USER_FILTER_ALLOW1;
827 }
828
829 /*
830 * Loop over each parameter and figure out what it is. The
831 * possibilities are ipaddr/netmask, hostname, or partial hostname:
832 * 192.168.2.3/255.255.255.0, foo.bar.com, or .bar.com
833 */
834
835 for (i = objc - nargs; i < objc; ++i) {
836 Ns_ReturnCode status;
837 char *net = Tcl_GetString(objv[i]);
838
839 status = Ns_SockaddrParseIPMask(interp, net, ipPtr, maskPtr, NULL((void*)0));
840 if (status != NS_OK) {
841 goto fail;
842 }
843
844 /*
845 * Is this a new netmask? If so, add it to the list.
846 * A list of netmasks is maintained and every time a
847 * new connection comes in, the peer address is ANDed with
848 * each of them and a lookup on that address is done
849 * on the hash table of networks.
850 */
851 (void) Tcl_CreateHashEntry(&userPtr->masks, (char *)maskPtr, &isNew)(*((&userPtr->masks)->createProc))(&userPtr->
masks, (const char *)((char *)maskPtr), &isNew)
;
852
853 /*
854 * Add the potentially masked IpAddress to the nets table.
855 */
856 hPtr = Tcl_CreateHashEntry(&userPtr->nets, (char *)ipPtr, &isNew)(*((&userPtr->nets)->createProc))(&userPtr->
nets, (const char *)((char *)ipPtr), &isNew)
;
857 if (hPtr != NULL((void*)0)) {
858 char ipString[NS_IPADDR_SIZE46];
859 Tcl_SetHashValue(hPtr,((hPtr)->clientData = (ClientData) ((ClientData)ns_strdup(
ns_inet_ntop(maskPtr, ipString, sizeof(ipString)))))
860 (ClientData)ns_strdup(ns_inet_ntop(maskPtr, ipString, sizeof(ipString))))((hPtr)->clientData = (ClientData) ((ClientData)ns_strdup(
ns_inet_ntop(maskPtr, ipString, sizeof(ipString)))))
;
861 }
862 if (isNew == 0) {
863 Ns_TclPrintfResult(interp, "duplicate entry: %s", net);
864 goto fail;
865 }
866 }
867
868 /*
869 * Add the user.
870 */
871
872 Ns_RWLockWrLock(&servPtr->lock);
873 hPtr = Tcl_CreateHashEntry(&servPtr->users, name, &isNew)(*((&servPtr->users)->createProc))(&servPtr->
users, (const char *)(name), &isNew)
;
874 if (isNew == 0) {
875 Ns_TclPrintfResult(interp, "duplicate user: %s", name);
876 goto fail0;
877 }
878 Tcl_SetHashValue(hPtr, userPtr)((hPtr)->clientData = (ClientData) (userPtr));
879 Ns_RWLockUnlock(&servPtr->lock);
880 return TCL_OK0;
881
882 fail0:
883 Ns_RWLockUnlock(&servPtr->lock);
884
885 fail:
886 FreeUserInfo(userPtr, name);
887
888 return TCL_ERROR1;
889}
890
891
892/*
893 *----------------------------------------------------------------------
894 *
895 * DelUserObjCmd --
896 *
897 * Implements "ns_perm deluser".
898 *
899 * Results:
900 * Tcl resut
901 *
902 * Side effects:
903 * A user may be deleted from the global user hash table
904 *
905 *----------------------------------------------------------------------
906 */
907
908static int DelUserObjCmd(ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *const* objv)
909{
910 Server *servPtr = data;
911 char *name = NULL((void*)0);
912 User *userPtr = NULL((void*)0);
913 Tcl_HashEntry *hPtr;
914
915 Ns_ObjvSpec args[] = {
916 {"name", Ns_ObjvString, &name, NULL((void*)0)},
917 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
918 };
919 if (Ns_ParseObjv(NULL((void*)0), args, interp, 2, objc, objv) != NS_OK) {
920 return TCL_ERROR1;
921 }
922 Ns_RWLockWrLock(&servPtr->lock);
923 hPtr = Tcl_FindHashEntry(&servPtr->users, name)(*((&servPtr->users)->findProc))(&servPtr->users
, (const char *)(name))
;
924 if (hPtr != NULL((void*)0)) {
925 userPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
926 Tcl_DeleteHashEntry(hPtr);
927 }
928 Ns_RWLockUnlock(&servPtr->lock);
929
930 if (userPtr != NULL((void*)0)) {
931 FreeUserInfo(userPtr, name);
932 }
933 return TCL_OK0;
934}
935
936/*
937 *----------------------------------------------------------------------
938 *
939 * ListUsersObjCmd --
940 *
941 * Implements "ns_perm listusers".
942 *
943 * Results:
944 * Tcl resut
945 *
946 * Side effects:
947 * None
948 *
949 *----------------------------------------------------------------------
950 */
951
952static int ListUsersObjCmd(ClientData data, Tcl_Interp * interp, int UNUSED(objc)UNUSED_objc __attribute__((__unused__)), Tcl_Obj *const* UNUSED(objv)UNUSED_objv __attribute__((__unused__)))
953{
954 Server *servPtr = data;
955 Tcl_HashSearch search, msearch;
956 Tcl_HashEntry *hPtr;
957 Tcl_DString ds;
958
959 Tcl_DStringInit(&ds);
960 Ns_RWLockRdLock(&servPtr->lock);
961 hPtr = Tcl_FirstHashEntry(&servPtr->users, &search);
962
963 while (hPtr != NULL((void*)0)) {
964 char ipString[NS_IPADDR_SIZE46];
965 User *userPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
966 Tcl_HashEntry *mPtr;
967 struct sockaddr *netPtr;
968
969 Ns_DStringPrintf(&ds, "{%s} {%s} {",
970 (const char*)Tcl_GetHashKey(&servPtr->users, hPtr)((void *) (((&servPtr->users)->keyType == (1) || (&
servPtr->users)->keyType == (-1)) ? (hPtr)->key.oneWordValue
: (hPtr)->key.string))
,
971 userPtr->pwd);
972
973 if (userPtr->hosts.numEntries > 0 || userPtr->masks.numEntries > 0 || userPtr->nets.numEntries > 0) {
974 Ns_DStringPrintf(&ds, " %s ", ((userPtr->flags & USER_FILTER_ALLOW1) != 0u) ? "-allow" : "-deny");
975 }
976 /*
977 * Append all values from networks
978 */
979 mPtr = Tcl_FirstHashEntry(&userPtr->nets, &msearch);
Duplicate code detected
980 while (mPtr != NULL((void*)0)) {
981 netPtr = (struct sockaddr *)Tcl_GetHashKey(&userPtr->nets, hPtr)((void *) (((&userPtr->nets)->keyType == (1) || (&
userPtr->nets)->keyType == (-1)) ? (hPtr)->key.oneWordValue
: (hPtr)->key.string))
;
982 Ns_DStringPrintf(&ds, "%s ", ns_inet_ntop(netPtr, ipString, sizeof(ipString)));
983 mPtr = Tcl_NextHashEntry(&msearch);
984 }
985
986 /*
987 * Append all values from masks
988 */
989 mPtr = Tcl_FirstHashEntry(&userPtr->masks, &msearch);
Similar code here
990 while (mPtr != NULL((void*)0)) {
991 netPtr = (struct sockaddr *)Tcl_GetHashKey(&userPtr->nets, hPtr)((void *) (((&userPtr->nets)->keyType == (1) || (&
userPtr->nets)->keyType == (-1)) ? (hPtr)->key.oneWordValue
: (hPtr)->key.string))
;
992 Ns_DStringPrintf(&ds, "%s ", ns_inet_ntop(netPtr, ipString, sizeof(ipString)));
993 mPtr = Tcl_NextHashEntry(&msearch);
994 }
995
996 /*
997 * Append all values from hosts
998 */
999 mPtr = Tcl_FirstHashEntry(&userPtr->hosts, &msearch);
1000 while (mPtr != NULL((void*)0)) {
1001 Ns_DStringPrintf(&ds, "%s ", (const char*)Tcl_GetHashKey(&userPtr->hosts, mPtr)((void *) (((&userPtr->hosts)->keyType == (1) || (&
userPtr->hosts)->keyType == (-1)) ? (mPtr)->key.oneWordValue
: (mPtr)->key.string))
);
1002 mPtr = Tcl_NextHashEntry(&msearch);
1003 }
1004 Ns_DStringNAppendTcl_DStringAppend(&ds, "} ", 2);
1005
1006 hPtr = Tcl_NextHashEntry(&search);
1007 }
1008 Ns_RWLockUnlock(&servPtr->lock);
1009 Tcl_DStringResult(interp, &ds);
1010
1011 return TCL_OK0;
1012}
1013
1014
1015/*
1016 *----------------------------------------------------------------------
1017 *
1018 * AddGroupObjCmd --
1019 *
1020 * Implements "ns_perm addgroup". Adds a group to the global groups list.
1021 *
1022 * Results:
1023 * Standard Tcl
1024 *
1025 * Side effects:
1026 * A group will be created
1027 *
1028 *----------------------------------------------------------------------
1029 */
1030
1031static int AddGroupObjCmd(ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *const* objv)
1032{
1033 Server *servPtr = data;
1034 char *name, *user;
1035 User *userPtr;
1036 Group *groupPtr;
1037 Tcl_HashSearch search;
1038 Tcl_HashEntry *hPtr;
1039 int isNew, param;
1040
1041 if (objc < 4) {
1042 Tcl_WrongNumArgs(interp, 2, objv, "name user ?user ...?");
1043 return TCL_ERROR1;
1044 }
1045
1046 /*
1047 * Create & populate the structure for a new group.
1048 */
1049
1050 name = Tcl_GetString(objv[2]);
1051 groupPtr = ns_malloc(sizeof(Group));
1052 Tcl_InitHashTable(&groupPtr->users, TCL_STRING_KEYS(0));
1053
1054 /*
1055 * Loop over each of the users who is to be in the group, make sure
1056 * it is ok, and add this user. Also put the group into the user's list
1057 * of groups he's in.
1058 */
1059
1060 for (param = 3; param < objc; param++) {
1061 user = Tcl_GetString(objv[param]);
1062 hPtr = Tcl_FindHashEntry(&servPtr->users, user)(*((&servPtr->users)->findProc))(&servPtr->users
, (const char *)(user))
;
1063 if (hPtr == NULL((void*)0)) {
1064 Ns_TclPrintfResult(interp, "no such user: %s", user);
1065 goto fail;
1066 }
1067 userPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1068
1069 /*
1070 * Add the user to the group's list of users
1071 */
1072
1073 hPtr = Tcl_CreateHashEntry(&groupPtr->users, user, &isNew)(*((&groupPtr->users)->createProc))(&groupPtr->
users, (const char *)(user), &isNew)
;
1074 if (isNew == 0) {
1075 dupuser:
1076 Ns_TclPrintfResult(interp, "user \"%s\" already in group \"%s\"", user, name);
1077 goto fail;
1078 }
1079 Tcl_SetHashValue(hPtr, userPtr)((hPtr)->clientData = (ClientData) (userPtr));
1080
1081 /*
1082 * Add the group to the user's list of groups
1083 */
1084
1085 hPtr = Tcl_CreateHashEntry(&userPtr->groups, name, &isNew)(*((&userPtr->groups)->createProc))(&userPtr->
groups, (const char *)(name), &isNew)
;
1086 if (isNew == 0) {
1087 goto dupuser;
1088 }
1089 Tcl_SetHashValue(hPtr, groupPtr)((hPtr)->clientData = (ClientData) (groupPtr));
1090 }
1091
1092 /*
1093 * Add the group to the global list of groups
1094 */
1095
1096 Ns_RWLockWrLock(&servPtr->lock);
1097 hPtr = Tcl_CreateHashEntry(&servPtr->groups, name, &isNew)(*((&servPtr->groups)->createProc))(&servPtr->
groups, (const char *)(name), &isNew)
;
1098 if (isNew == 0) {
1099 Ns_TclPrintfResult(interp, "duplicate group: %s", name);
1100 goto fail0;
1101 }
1102 Tcl_SetHashValue(hPtr, groupPtr)((hPtr)->clientData = (ClientData) (groupPtr));
1103 Ns_RWLockUnlock(&servPtr->lock);
1104 return TCL_OK0;
1105
1106 fail0:
1107 Ns_RWLockUnlock(&servPtr->lock);
1108
1109 fail:
1110 hPtr = Tcl_FirstHashEntry(&groupPtr->users, &search);
1111 while (hPtr != NULL((void*)0)) {
1112 userPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1113 hPtr = Tcl_FindHashEntry(&userPtr->groups, name)(*((&userPtr->groups)->findProc))(&userPtr->
groups, (const char *)(name))
;
1114 if (hPtr != NULL((void*)0)) {
1115 Tcl_DeleteHashEntry(hPtr);
1116 }
1117 hPtr = Tcl_NextHashEntry(&search);
1118 }
1119 Tcl_DeleteHashTable(&groupPtr->users);
1120 ns_free(groupPtr);
1121 return TCL_ERROR1;
1122}
1123
1124/*
1125 *----------------------------------------------------------------------
1126 *
1127 * DelGroupObjCmd --
1128 *
1129 * Implements "ns_perm delgroup".
1130 *
1131 * Results:
1132 * Tcl resut
1133 *
1134 * Side effects:
1135 * A group may be deleted from the global user hash table
1136 *
1137 *----------------------------------------------------------------------
1138 */
1139
1140static int DelGroupObjCmd(ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *const* objv)
1141{
1142 Server *servPtr = data;
1143 char *name = NULL((void*)0);
1144 User *userPtr;
1145 Group *groupPtr = NULL((void*)0);
1146 Tcl_HashEntry *hPtr;
1147 Tcl_HashSearch search;
1148
1149 Ns_ObjvSpec args[] = {
1150 {"name", Ns_ObjvString, &name, NULL((void*)0)},
1151 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
1152 };
1153 if (Ns_ParseObjv(NULL((void*)0), args, interp, 2, objc, objv) != NS_OK) {
1154 return TCL_ERROR1;
1155 }
1156
1157 Ns_RWLockWrLock(&servPtr->lock);
1158 hPtr = Tcl_FindHashEntry(&servPtr->groups, name)(*((&servPtr->groups)->findProc))(&servPtr->
groups, (const char *)(name))
;
1159 if (hPtr != NULL((void*)0)) {
1160 groupPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1161 Tcl_DeleteHashEntry(hPtr);
1162 }
1163 Ns_RWLockUnlock(&servPtr->lock);
1164
1165 if (groupPtr != NULL((void*)0)) {
1166 hPtr = Tcl_FirstHashEntry(&groupPtr->users, &search);
1167 while (hPtr != NULL((void*)0)) {
1168 userPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1169 hPtr = Tcl_FindHashEntry(&userPtr->groups, name)(*((&userPtr->groups)->findProc))(&userPtr->
groups, (const char *)(name))
;
1170 if (hPtr != NULL((void*)0)) {
1171 Tcl_DeleteHashEntry(hPtr);
1172 }
1173 hPtr = Tcl_NextHashEntry(&search);
1174 }
1175 Tcl_DeleteHashTable(&groupPtr->users);
1176 ns_free(groupPtr);
1177 }
1178 return TCL_OK0;
1179}
1180
1181/*
1182 *----------------------------------------------------------------------
1183 *
1184 * ListGroupsObjCmd --
1185 *
1186 * Implements "ns_perm listgroups".
1187 *
1188 * Results:
1189 * Tcl resut
1190 *
1191 * Side effects:
1192 * None
1193 *
1194 *----------------------------------------------------------------------
1195 */
1196
1197static int ListGroupsObjCmd(ClientData data, Tcl_Interp * interp, int UNUSED(objc)UNUSED_objc __attribute__((__unused__)), Tcl_Obj *const* UNUSED(objv)UNUSED_objv __attribute__((__unused__)))
1198{
1199 Server *servPtr = data;
1200 Tcl_HashSearch search;
1201 Tcl_HashEntry *hPtr;
1202 Tcl_DString ds;
1203
1204 Tcl_DStringInit(&ds);
1205 Ns_RWLockRdLock(&servPtr->lock);
1206 hPtr = Tcl_FirstHashEntry(&servPtr->groups, &search);
1207 while (hPtr != NULL((void*)0)) {
1208 Tcl_HashSearch usearch;
1209 Tcl_HashEntry *uhPtr;
1210 Group *groupPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1211
1212 Ns_DStringPrintf(&ds, "%s { ",
1213 (const char *)Tcl_GetHashKey(&servPtr->groups, hPtr)((void *) (((&servPtr->groups)->keyType == (1) || (
&servPtr->groups)->keyType == (-1)) ? (hPtr)->key
.oneWordValue : (hPtr)->key.string))
);
1214
1215 /*
1216 * All users for this group
1217 */
1218
1219 uhPtr = Tcl_FirstHashEntry(&groupPtr->users, &usearch);
1220 while (uhPtr != NULL((void*)0)) {
1221 Ns_DStringPrintf(&ds, "\"%s\" ",
1222 (const char *)Tcl_GetHashKey(&groupPtr->users, uhPtr)((void *) (((&groupPtr->users)->keyType == (1) || (
&groupPtr->users)->keyType == (-1)) ? (uhPtr)->key
.oneWordValue : (uhPtr)->key.string))
);
1223 uhPtr = Tcl_NextHashEntry(&usearch);
1224 }
1225 Ns_DStringNAppendTcl_DStringAppend(&ds, "} ", 2);
1226
1227 hPtr = Tcl_NextHashEntry(&search);
1228 }
1229 Ns_RWLockUnlock(&servPtr->lock);
1230 Tcl_DStringResult(interp, &ds);
1231
1232 return TCL_OK0;
1233}
1234
1235
1236/*
1237 *----------------------------------------------------------------------
1238 *
1239 * AllowDenyObjCmd --
1240 *
1241 * Implements:
1242 *
1243 * "ns_perm allowuser"
1244 * "nsperm allowgroup"
1245 * "nsperm denyuser"
1246 * "nsperm denygroup"
1247 *
1248 * Adds/removes a record that will allow or deny access to
1249 * the specified URL.
1250 *
1251 * Results:
1252 * Standard Tcl result.
1253 *
1254 * Side effects:
1255 * A perm record may be created
1256 *
1257 *----------------------------------------------------------------------
1258 */
1259
1260static int AllowDenyObjCmd(
1261 ClientData data,
1262 Tcl_Interp *interp,
1263 int objc,
1264 Tcl_Obj *const* objv,
1265 bool_Bool allow,
1266 bool_Bool user
1267) {
1268 char *method = NULL((void*)0), *url = NULL((void*)0);
1269 int noinherit = 0, nargs = 0, result;
1270
1271 Ns_ObjvSpec opts[] = {
1272 {"-noinherit", Ns_ObjvBool, &noinherit, INT2PTR(NS_TRUE)((void *)(intptr_t)(1))},
1273 {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)},
1274 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
1275 };
1276 Ns_ObjvSpec args[] = {
1277 {"method", Ns_ObjvString, &method, NULL((void*)0)},
1278 {"url", Ns_ObjvString, &url, NULL((void*)0)},
1279 {"users", Ns_ObjvArgs, &nargs, NULL((void*)0)},
1280 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
1281 };
1282
1283
1284 result = Ns_ParseObjv(opts, args, interp, 2, objc, objv);
1285 if (likely(result == NS_OK)(__builtin_expect((result == NS_OK), 1))) {
1286 Server *servPtr = data;
1287 Perm *permPtr;
1288 Ns_DStringTcl_DString base;
1289 int i, isNew;
1290 unsigned int flags = 0u;
1291
1292 if (noinherit != 0) {
1293 flags |= NS_OP_NOINHERIT0x02u;
1294 }
1295
1296 /*
1297 * Construct the base url.
1298 */
1299
1300 Ns_DStringInitTcl_DStringInit(&base);
1301 Ns_NormalizeUrl(&base, url);
1302
1303 /*
1304 * Locate and verify the exact record.
1305 */
1306
1307 Ns_RWLockWrLock(&servPtr->lock);
1308 permPtr = Ns_UrlSpecificGet(servPtr->server, method, url, uskey);
1309
1310 if (permPtr != NULL((void*)0) && !STREQ(base.string, permPtr->baseurl)(((*(base.string)) == (*(permPtr->baseurl))) && (strcmp
((base.string),(permPtr->baseurl)) == 0))
) {
1311 permPtr = NULL((void*)0);
1312 }
1313 if (permPtr == NULL((void*)0)) {
1314 permPtr = ns_calloc(1u, sizeof(Perm));
1315 permPtr->baseurl = Ns_DStringExport(&base);
1316 Tcl_InitHashTable(&permPtr->allowuser, TCL_STRING_KEYS(0));
1317 Tcl_InitHashTable(&permPtr->denyuser, TCL_STRING_KEYS(0));
1318 Tcl_InitHashTable(&permPtr->allowgroup, TCL_STRING_KEYS(0));
1319 Tcl_InitHashTable(&permPtr->denygroup, TCL_STRING_KEYS(0));
1320 Ns_UrlSpecificSet(servPtr->server, method, url, uskey, permPtr, flags, NULL((void*)0));
1321 }
1322 if (!allow) {
1323 permPtr->flags |= PERM_IMPLICIT_ALLOW1;
1324 }
1325
1326 for (i = objc - nargs; i < objc; i++) {
1327 char *key = Tcl_GetString(objv[i]);
1328
1329 if (user) {
1330 if (allow) {
1331 (void) Tcl_CreateHashEntry(&permPtr->allowuser, key, &isNew)(*((&permPtr->allowuser)->createProc))(&permPtr
->allowuser, (const char *)(key), &isNew)
;
1332 } else {
1333 (void) Tcl_CreateHashEntry(&permPtr->denyuser, key, &isNew)(*((&permPtr->denyuser)->createProc))(&permPtr->
denyuser, (const char *)(key), &isNew)
;
1334 }
1335 } else {
1336 if (allow) {
1337 (void) Tcl_CreateHashEntry(&permPtr->allowgroup, key, &isNew)(*((&permPtr->allowgroup)->createProc))(&permPtr
->allowgroup, (const char *)(key), &isNew)
;
1338 } else {
1339 (void) Tcl_CreateHashEntry(&permPtr->denygroup, key, &isNew)(*((&permPtr->denygroup)->createProc))(&permPtr
->denygroup, (const char *)(key), &isNew)
;
1340 }
1341 }
1342 }
1343 Ns_RWLockUnlock(&servPtr->lock);
1344 Ns_DStringFreeTcl_DStringFree(&base);
1345 }
1346
1347 return result;
1348}
1349
1350/*
1351 *----------------------------------------------------------------------
1352 *
1353 * DelPermObjCmd --
1354 *
1355 * Implements "ns_perm delperm". Removes permission record.
1356 *
1357 * Results:
1358 * Standard Tcl result.
1359 *
1360 * Side effects:
1361 * A permission record may be deleted.
1362 *
1363 *----------------------------------------------------------------------
1364 */
1365
1366static int DelPermObjCmd(ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *const* objv)
1367{
1368 Server *servPtr = data;
1369 Perm *permPtr;
1370 Ns_DStringTcl_DString base;
1371 char *method, *url;
1372 int noinherit = 0;
1373 unsigned int flags = NS_OP_RECURSE0x08u;
1374
1375 Ns_ObjvSpec opts[] = {
1376 {"-noinherit", Ns_ObjvBool, &noinherit, INT2PTR(NS_TRUE)((void *)(intptr_t)(1))},
1377 {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)},
1378 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
1379 };
1380
1381 Ns_ObjvSpec args[] = {
1382 {"method", Ns_ObjvString, &method, NULL((void*)0)},
1383 {"url", Ns_ObjvString, &url, NULL((void*)0)},
1384 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
1385 };
1386 if (Ns_ParseObjv(opts, args, interp, 2, objc, objv) != NS_OK) {
1387 return TCL_ERROR1;
1388 }
1389 if (noinherit != 0) {
1390 flags |= NS_OP_NOINHERIT0x02u;
1391 }
1392
1393 /*
1394 * Construct the base url.
1395 */
1396
1397 Ns_DStringInitTcl_DStringInit(&base);
1398 Ns_NormalizeUrl(&base, url);
1399
1400 /*
1401 * Locate and verify the exact record.
1402 */
1403
1404 Ns_RWLockWrLock(&servPtr->lock);
1405 permPtr = Ns_UrlSpecificGet(servPtr->server, method, url, uskey);
1406 if (permPtr != NULL((void*)0)) {
1407 Ns_UrlSpecificDestroy(servPtr->server, method, url, uskey, flags);
1408 ns_free(permPtr->baseurl);
1409 Tcl_DeleteHashTable(&permPtr->allowuser);
1410 Tcl_DeleteHashTable(&permPtr->denyuser);
1411 Tcl_DeleteHashTable(&permPtr->allowgroup);
1412 Tcl_DeleteHashTable(&permPtr->denygroup);
1413 ns_free(permPtr);
1414 }
1415 Ns_RWLockUnlock(&servPtr->lock);
1416 Ns_DStringFreeTcl_DStringFree(&base);
1417 return TCL_OK0;
1418}
1419
1420/*
1421 *----------------------------------------------------------------------
1422 *
1423 * ListPermsObjCmd --
1424 *
1425 * Implements "ns_perm listperms".
1426 *
1427 * Results:
1428 * Standard Tcl result.
1429 *
1430 * Side effects:
1431 * None
1432 *
1433 *----------------------------------------------------------------------
1434 */
1435
1436static int ListPermsObjCmd(ClientData data, Tcl_Interp * interp, int UNUSED(objc)UNUSED_objc __attribute__((__unused__)), Tcl_Obj *const* UNUSED(objv)UNUSED_objv __attribute__((__unused__)))
1437{
1438 Server *servPtr = data;
1439 Ns_DStringTcl_DString ds;
1440
1441 Ns_DStringInitTcl_DStringInit(&ds);
1442 Ns_RWLockRdLock(&servPtr->lock);
1443 Ns_UrlSpecificWalk(uskey, servPtr->server, WalkCallback, &ds);
1444 Ns_RWLockUnlock(&servPtr->lock);
1445
1446 Tcl_DStringResult(interp, &ds);
1447 return TCL_OK0;
1448}
1449
1450static void WalkCallback(Tcl_DString * dsPtr, const void *arg)
1451{
1452 Perm *permPtr = (Perm *)arg;
1453 Tcl_HashSearch search;
1454 Tcl_HashEntry *hPtr;
1455
1456 if (permPtr->flags & PERM_IMPLICIT_ALLOW1) {
1457 Ns_DStringAppend(dsPtr, " -implicitallow ")Tcl_DStringAppend((dsPtr), (" -implicitallow "), -1);
1458 }
1459
1460 hPtr = Tcl_FirstHashEntry(&permPtr->allowuser, &search);
1461 while (hPtr != NULL((void*)0)) {
1462 Ns_DStringVarAppend(dsPtr, " -allowuser {", Tcl_GetHashKey(&permPtr->allowuser, hPtr)((void *) (((&permPtr->allowuser)->keyType == (1) ||
(&permPtr->allowuser)->keyType == (-1)) ? (hPtr)->
key.oneWordValue : (hPtr)->key.string))
, "}", (char *)0L);
1463 hPtr = Tcl_NextHashEntry(&search);
1464 }
1465
1466 hPtr = Tcl_FirstHashEntry(&permPtr->denyuser, &search);
1467 while (hPtr != NULL((void*)0)) {
1468 Ns_DStringVarAppend(dsPtr, " -denyuser {", Tcl_GetHashKey(&permPtr->denyuser, hPtr)((void *) (((&permPtr->denyuser)->keyType == (1) ||
(&permPtr->denyuser)->keyType == (-1)) ? (hPtr)->
key.oneWordValue : (hPtr)->key.string))
, "}", (char *)0L);
1469 hPtr = Tcl_NextHashEntry(&search);
1470 }
1471
1472 hPtr = Tcl_FirstHashEntry(&permPtr->allowgroup, &search);
1473 while (hPtr != NULL((void*)0)) {
1474 Ns_DStringVarAppend(dsPtr, " -allowgroup {", Tcl_GetHashKey(&permPtr->allowgroup, hPtr)((void *) (((&permPtr->allowgroup)->keyType == (1) ||
(&permPtr->allowgroup)->keyType == (-1)) ? (hPtr)->
key.oneWordValue : (hPtr)->key.string))
, "}", (char *)0L);
1475 hPtr = Tcl_NextHashEntry(&search);
1476 }
1477
1478 hPtr = Tcl_FirstHashEntry(&permPtr->denygroup, &search);
1479 while (hPtr != NULL((void*)0)) {
1480 Ns_DStringVarAppend(dsPtr, " -denygroup {", Tcl_GetHashKey(&permPtr->denygroup, hPtr)((void *) (((&permPtr->denygroup)->keyType == (1) ||
(&permPtr->denygroup)->keyType == (-1)) ? (hPtr)->
key.oneWordValue : (hPtr)->key.string))
, "}", (char *)0L);
1481 hPtr = Tcl_NextHashEntry(&search);
1482 }
1483}
1484
1485/*
1486 *----------------------------------------------------------------------
1487 *
1488 * CheckPassObjCmd --
1489 *
1490 * Implements "ns_perm checkpass". Checks supplied user password against
1491 * internal database.
1492 *
1493 * Results:
1494 * Standard Tcl result.
1495 *
1496 * Side effects:
1497 * None
1498 *
1499 *----------------------------------------------------------------------
1500 */
1501
1502static int
1503CheckPassObjCmd(ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *const* objv)
1504{
1505 Server *servPtr = data;
1506 int rc = TCL_ERROR1;
1507 User *userPtr;
1508 char *user, *pwd;
1509 Tcl_HashEntry *hPtr;
1510
1511 if (objc != 4) {
1512 Tcl_WrongNumArgs(interp, 2, objv, "user pwd");
1513 return TCL_ERROR1;
1514 }
1515 user = Tcl_GetString(objv[2]);
1516 pwd = Tcl_GetString(objv[3]);
1517
1518 Ns_RWLockRdLock(&servPtr->lock);
1519 hPtr = Tcl_FindHashEntry(&servPtr->users, user)(*((&servPtr->users)->findProc))(&servPtr->users
, (const char *)(user))
;
1520 if (hPtr == NULL((void*)0)) {
1521 Ns_TclPrintfResult(interp, "user not found");
1522 goto done;
1523 }
1524 userPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1525 if (userPtr->pwd[0] != 0) {
1526 char buf[NS_ENCRYPT_BUFSIZE128];
1527
1528 if (pwd[0] == 0) {
1529 Ns_TclPrintfResult(interp, "empty password given");
1530 goto done;
1531 }
1532 Ns_Encrypt(pwd, userPtr->pwd, buf);
1533 if (!STREQ(userPtr->pwd, buf)(((*(userPtr->pwd)) == (*(buf))) && (strcmp((userPtr
->pwd),(buf)) == 0))
) {
1534 Ns_TclPrintfResult(interp, "incorrect password");
1535 goto done;
1536 }
1537 }
1538 rc = TCL_OK0;
1539
1540 done:
1541 Ns_RWLockUnlock(&servPtr->lock);
1542 return rc;
1543}
1544
1545/*
1546 *----------------------------------------------------------------------
1547 *
1548 * SetPassObjCmd --
1549 *
1550 * Implements "ns_perm setpass". Assigns new password to the user.
1551 *
1552 * Results:
1553 * Standard Tcl result
1554 *
1555 * Side effects:
1556 * None
1557 *
1558 *----------------------------------------------------------------------
1559 */
1560
1561static int
1562SetPassObjCmd(ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj *const* objv)
1563{
1564 Server *servPtr = data;
1565 int rc = 0;
1566 User *userPtr;
1567 Tcl_HashEntry *hPtr;
1568 char *user, *pwd, *salt;
1569 char buf[NS_ENCRYPT_BUFSIZE128];
1570
1571 if (objc < 4) {
1572 Tcl_WrongNumArgs(interp, 2, objv, "user pwd ?salt?");
1573 return TCL_ERROR1;
1574 }
1575 user = Tcl_GetString(objv[2]);
1576 pwd = Tcl_GetString(objv[3]);
1577 salt = objc > 4 ? Tcl_GetString(objv[4]) : NULL((void*)0);
1578
1579 Ns_RWLockRdLock(&servPtr->lock);
1580 hPtr = Tcl_FindHashEntry(&servPtr->users, user)(*((&servPtr->users)->findProc))(&servPtr->users
, (const char *)(user))
;
1581 if (hPtr == NULL((void*)0)) {
1582 goto done;
1583 }
1584 userPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
1585 if (salt != NULL((void*)0)) {
1586 Ns_Encrypt(pwd, salt, buf);
1587 pwd = buf;
1588 }
1589 snprintf(userPtr->pwd, sizeof(userPtr->pwd), "%s", pwd)__builtin___snprintf_chk (userPtr->pwd, sizeof(userPtr->
pwd), 2 - 1, __builtin_object_size (userPtr->pwd, 2 > 1
), "%s", pwd)
;
1590 rc = 1;
1591
1592 done:
1593 Ns_RWLockUnlock(&servPtr->lock);
1594 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1595 return TCL_OK0;
1596}
1597
1598/*
1599 *----------------------------------------------------------------------
1600 *
1601 * CreateNonce --
1602 *
1603 * Create the nonce to be used by the client to hash against.
1604 * The hash is a uuencoded string that consists of:
1605 *
1606 * time-stamp H(time-stamp ":" uri ":" private-key)
1607 *
1608 * Note that this function is called here with uri = ""
1609 *
1610 * Results:
1611 * NS_OK/NS_ERROR
1612 *
1613 * Side effects:
1614 * None.
1615 *
1616 *----------------------------------------------------------------------
1617*/
1618
1619static Ns_ReturnCode
1620CreateNonce(const char *privatekey, char **nonce, const char *uri)
1621{
1622 Ns_ReturnCode status = NS_OK;
1623
1624 if (privatekey == NULL((void*)0)) {
1625 status = NS_ERROR;
1626 } else {
1627 time_t now;
1628 Ns_DStringTcl_DString ds;
1629 Ns_CtxMD5 md5;
1630 unsigned char sig[16];
1631 char buf[33];
1632 char bufcoded[1 + (4 * 48) / 2];
1633
1634 now = time(NULL((void*)0));
1635
1636 Ns_DStringInitTcl_DStringInit(&ds);
1637 Ns_DStringPrintf(&ds, "%" PRId64"l" "d" ":%s:%s", (int64_t) now, uri, privatekey);
1638
1639 Ns_CtxMD5Init(&md5);
1640 Ns_CtxMD5Update(&md5, (unsigned char *) ds.string, (unsigned int) ds.length);
1641 Ns_CtxMD5Final(&md5, sig);
1642 Ns_HexString(sig, buf, 16, NS_TRUE1);
1643
1644 /* encode the current time and MD5 string into the nonce */
1645 Ns_DStringSetLengthTcl_DStringSetLength(&ds, 0);
1646 Ns_DStringPrintf(&ds, "%" PRId64"l" "d" " %s", (int64_t) now, buf);
1647 Ns_HtuuEncode((unsigned char *) ds.string, (unsigned int) ds.length, bufcoded);
1648
1649 *nonce = ns_strdup(bufcoded);
1650 }
1651
1652 return status;
1653}
1654
1655
1656#if 0
1657/*
1658 * unused
1659 */
1660/*
1661 *----------------------------------------------------------------------
1662 *
1663 * CheckNonce --
1664 *
1665 * Given a nonce value ensure that it hasn't been tampered with
1666 * and that it isn't stale. The hash is a uuencoded string that
1667 * consists of:
1668 *
1669 * time-stamp H(time-stamp ":" uri ":" private-key)
1670 *
1671 * Results:
1672 * NS_OK or NS_ERROR if the nonce is stale.
1673 *
1674 * Side effects:
1675 * None.
1676 */
1677static Ns_ReturnCode
1678CheckNonce(const char *privatekey, char *nonce, char *uri, int timeout)
1679{
1680 Ns_CtxMD5 md5;
1681 Ns_DStringTcl_DString ds;
1682 char buf[33];
1683 char *decoded;
1684 char *ntime;
1685 char *tnonce;
1686 int n;
1687 unsigned char sig[16];
1688 time_t now, nonce_time;
1689 Ns_ReturnCode status = NS_OK;
1690
1691 if (privatekey == NULL((void*)0)) {
1692 result = NS_ERROR;
1693 } else {
1694
1695 time(&now);
1696
1697 /* decode the nonce */
1698 n = 3 + ((strlen(nonce) * 3) / 4);
1699 decoded = ns_malloc((unsigned int) n);
1700 n = Ns_HtuuDecode(nonce, (unsigned char *) decoded, n);
1701 decoded[n] = '\0';
1702
1703 ntime = ns_strtok(decoded, " ");
1704 tnonce = ns_strtok(NULL((void*)0), " ");
1705
1706 /* recreate the nonce to ensure that it isn't corrupted */
1707 Ns_CtxMD5Init(&md5);
1708
1709 Ns_DStringInitTcl_DStringInit(&ds);
1710 Ns_DStringVarAppend(&ds, ntime, ":", uri, ":", privatekey, (char *)0L);
1711
1712 Ns_CtxMD5Update(&md5, (unsigned char *) ds.string, (unsigned int) ds.length);
1713 Ns_CtxMD5Final(&md5, sig);
1714 Ns_HexString(sig, buf, 16, NS_TRUE1);
1715
1716 /* Check for a stale timestamp. If the timestamp is stale we still check
1717 * to see if the user sent the proper digest password. The stale flag
1718 * is only set if the nonce is expired AND the credentials are OK, otherwise
1719 * the get a 401, but that happens elsewhere.
1720 */
1721
1722 nonce_time = (time_t) strtol(ntime, (char **) NULL((void*)0), 10);
1723
1724 if ((now - nonce_time) > timeout) {
1725 status = NS_ERROR;
1726 }
1727
1728 if (!(STREQ(tnonce, buf)(((*(tnonce)) == (*(buf))) && (strcmp((tnonce),(buf))
== 0))
)) {
1729 status = NS_ERROR;
1730 }
1731 }
1732 return status;
1733}
1734#endif
1735
1736/*
1737 *----------------------------------------------------------------------
1738 *
1739 * CreateHeader --
1740 *
1741 * Assigns WWW-Authenticate headers according to Digest
1742 * authentication rules.
1743 *
1744 * Results:
1745 * NS_OK/NS_ERROR
1746 *
1747 * Side effects:
1748 * Appends HTTP headers to output headers
1749 *
1750 *----------------------------------------------------------------------
1751*/
1752
1753static Ns_ReturnCode
1754CreateHeader(const Server *servPtr, const Ns_Conn *conn, bool_Bool stale)
1755{
1756 Ns_ReturnCode status = NS_OK;
1757 char *nonce = 0;
1758
1759 if (CreateNonce(usdigest, &nonce, NS_EMPTY_STRING) == NS_ERROR) {
1760 status = NS_ERROR;
1761 } else {
1762 Ns_DStringTcl_DString ds;
1763
1764 Ns_DStringInitTcl_DStringInit(&ds);
1765 Ns_DStringPrintf(&ds, "Digest realm=\"%s\", nonce=\"%s\", algorithm=\"MD5\", qop=\"auth\"", servPtr->server, nonce);
1766
1767 if (stale) {
1768 Ns_DStringVarAppend(&ds, ", stale=\"true\"", (char *)0L);
1769 }
1770 Ns_ConnSetHeaders(conn, "WWW-Authenticate", ds.string);
1771 }
1772 return status;
1773}
1774
1775/*
1776 * Local Variables:
1777 * mode: c
1778 * c-basic-offset: 4
1779 * fill-column: 78
1780 * indent-tabs-mode: nil
1781 * End:
1782 */