Add rxgk support to userok
[openafs.git] / src / auth / userok.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15 #include <afs/opr.h>
16
17 #include <ctype.h>
18
19 #include <afs/pthread_glock.h>
20 #include <rx/xdr.h>
21 #include <rx/rx.h>
22 #include <rx/rx_identity.h>
23 #ifdef AFS_RXGK_ENV
24 # include <rx/rxgk.h>
25 #endif
26 #include <afs/afsutil.h>
27 #include <afs/fileutil.h>
28
29 #include "base64.h"
30 #include "auth.h"
31 #include "cellconfig.h"
32 #include "keys.h"
33 #include "afs/audit.h"
34
35 /* The display names for localauth and noauth identities; they aren't used
36  * inside tickets or anything, but just serve as something to display in logs,
37  * etc. */
38 #define AFS_LOCALAUTH_NAME "<LocalAuth>"
39 #define AFS_LOCALAUTH_LEN  (sizeof(AFS_LOCALAUTH_NAME)-1)
40 #define AFS_NOAUTH_NAME "<NoAuth>"
41 #define AFS_NOAUTH_LEN  (sizeof(AFS_NOAUTH_NAME)-1)
42
43 static int ParseLine(char *buffer, struct rx_identity *user);
44
45 static void
46 UserListFileName(struct afsconf_dir *adir,
47                  char *buffer, size_t len)
48 {
49     strcompose(buffer, len, adir->name, "/", AFSDIR_ULIST_FILE, (char *)NULL);
50 }
51
52 int
53 afsconf_CheckAuth(void *arock, struct rx_call *acall)
54 {
55     struct afsconf_dir *adir = (struct afsconf_dir *) arock;
56     int rc;
57     LOCK_GLOBAL_MUTEX;
58     rc = ((afsconf_SuperUser(adir, acall, NULL) == 0) ? 10029 : 0);
59     UNLOCK_GLOBAL_MUTEX;
60     return rc;
61 }
62
63 static int
64 GetNoAuthFlag(struct afsconf_dir *adir)
65 {
66     if (access(AFSDIR_SERVER_NOAUTH_FILEPATH, 0) == 0) {
67         osi_audit(NoAuthEvent, 0, AUD_END);     /* some random server is running noauth */
68         return 1;               /* if /usr/afs/local/NoAuth file exists, allow access */
69     }
70     return 0;
71 }
72
73
74 int
75 afsconf_GetNoAuthFlag(struct afsconf_dir *adir)
76 {
77     int rc;
78
79     LOCK_GLOBAL_MUTEX;
80     rc = GetNoAuthFlag(adir);
81     UNLOCK_GLOBAL_MUTEX;
82     return rc;
83 }
84
85 void
86 afsconf_SetNoAuthFlag(struct afsconf_dir *adir, int aflag)
87 {
88     afs_int32 code;
89
90     LOCK_GLOBAL_MUTEX;
91     if (aflag == 0) {
92         /* turn off noauth flag */
93         code = (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0);
94         osi_audit(NoAuthDisableEvent, code, AUD_END);
95     } else {
96         /* try to create file */
97         code =
98             open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR,
99                  0666);
100         if (code >= 0) {
101             close(code);
102             osi_audit(NoAuthEnableEvent, 0, AUD_END);
103         } else
104             osi_audit(NoAuthEnableEvent, errno, AUD_END);
105     }
106     UNLOCK_GLOBAL_MUTEX;
107 }
108
109 /*!
110  * Remove an identity from the UserList file
111  *
112  * This function removes the given identity from the user list file.
113  * For the purposes of identifying entries to remove, only the
114  * type and exportedName portions of the identity are used. Callers
115  * should remember that a given identity may be listed in the file in
116  * a number of different ways.
117  *
118  * @param adir
119  *      A structure representing the configuration directory currently
120  *      in use
121  * @param user
122  *      The RX identity to delete
123  *
124  * @returns
125  *      0 on success, an error code on failure
126  */
127
128 int
129 afsconf_DeleteIdentity(struct afsconf_dir *adir, struct rx_identity *user)
130 {
131     char *filename, *nfilename;
132     char *buffer;
133     char *copy;
134     FILE *tf;
135     FILE *nf;
136     int flag;
137     char *tp;
138     int found;
139     struct stat tstat;
140     struct rx_identity identity;
141     afs_int32 code;
142
143     memset(&identity, 0, sizeof(struct rx_identity));
144
145     buffer = malloc(AFSDIR_PATH_MAX);
146     if (buffer == NULL)
147         return ENOMEM;
148     filename = malloc(AFSDIR_PATH_MAX);
149     if (filename == NULL) {
150         free(buffer);
151         return ENOMEM;
152     }
153
154     LOCK_GLOBAL_MUTEX;
155     UserListFileName(adir, filename, AFSDIR_PATH_MAX);
156 #ifndef AFS_NT40_ENV
157     {
158         /*
159          * We attempt to fully resolve this pathname, so that the rename
160          * of the temporary file will work even if UserList is a symlink
161          * into a different filesystem.
162          */
163         nfilename = malloc(AFSDIR_PATH_MAX);
164         if (nfilename == NULL) {
165             UNLOCK_GLOBAL_MUTEX;
166             free(filename);
167             free(buffer);
168             return ENOMEM;
169         }
170         if (realpath(filename, nfilename)) {
171             free(filename);
172             filename = nfilename;
173         } else {
174             free(nfilename);
175         }
176     }
177 #endif /* AFS_NT40_ENV */
178     if (asprintf(&nfilename, "%s.NXX", filename) < 0) {
179         UNLOCK_GLOBAL_MUTEX;
180         free(filename);
181         free(buffer);
182         return -1;
183     }
184     tf = fopen(filename, "r");
185     if (!tf) {
186         UNLOCK_GLOBAL_MUTEX;
187         free(filename);
188         free(nfilename);
189         free(buffer);
190         return -1;
191     }
192     code = stat(filename, &tstat);
193     if (code < 0) {
194         UNLOCK_GLOBAL_MUTEX;
195         free(filename);
196         free(nfilename);
197         free(buffer);
198         return code;
199     }
200     nf = fopen(nfilename, "w+");
201     if (!nf) {
202         fclose(tf);
203         UNLOCK_GLOBAL_MUTEX;
204         free(filename);
205         free(nfilename);
206         free(buffer);
207         return EIO;
208     }
209     flag = 0;
210     found = 0;
211     while (1) {
212         /* check for our user id */
213         tp = fgets(buffer, AFSDIR_PATH_MAX, tf);
214         if (tp == NULL)
215             break;
216
217         copy = strdup(buffer);
218         if (copy == NULL) {
219             flag = 1;
220             break;
221         }
222         code = ParseLine(copy, &identity);
223         if (code == 0 && rx_identity_match(user, &identity)) {
224             /* found the guy, don't copy to output file */
225             found = 1;
226         } else {
227             /* otherwise copy original line to output */
228             fprintf(nf, "%s", buffer);
229         }
230         free(copy);
231         rx_identity_freeContents(&identity);
232     }
233     fclose(tf);
234     free(buffer);
235     if (ferror(nf))
236         flag = 1;
237     if (fclose(nf) == EOF)
238         flag = 1;
239     if (flag == 0) {
240         /* try the rename */
241         flag = rk_rename(nfilename, filename);
242         if (flag == 0)
243             flag = chmod(filename, tstat.st_mode);
244     } else
245         unlink(nfilename);
246
247     /* finally, decide what to return to the caller */
248     UNLOCK_GLOBAL_MUTEX;
249     free(filename);
250     free(nfilename);
251     if (flag)
252         return EIO;             /* something mysterious went wrong */
253     if (!found)
254         return ENOENT;          /* entry wasn't found, no changes made */
255     return 0;                   /* everything was fine */
256 }
257
258 /*!
259  * Remove a legacy Kerberos 4 name from the UserList file.
260  *
261  * This function removes a Kerberos 4 name from the super user list. It
262  * can only remove names which were added by the afsconf_AddUser interface,
263  * or with an explicit Kerberos v4 type.
264  *
265  * @param[in] adir
266  *      A structure representing the configuration directory
267  * @param[in] name
268  *      The Kerberos v4 name to remove
269  *
270  * @returns
271  *      0 on success, an error code upon failure.
272  *
273  * Note that this function is deprecated. New callers should use
274  * afsconf_DeleteIdentity instead.
275  */
276
277 int
278 afsconf_DeleteUser(struct afsconf_dir *adir, char *name)
279 {
280     struct rx_identity *user;
281     int code;
282
283     user = rx_identity_new(RX_ID_KRB4, name, name, strlen(name));
284     if (!user)
285         return ENOMEM;
286
287     code = afsconf_DeleteIdentity(adir, user);
288
289     rx_identity_free(&user);
290
291     return code;
292 }
293
294 /* This is a multi-purpose funciton for use by either
295  * GetNthIdentity or GetNthUser. The parameter 'id' indicates
296  * whether we are counting all identities (if true), or just
297  * ones which can be represented by the old-style interfaces
298  * We return -1 for EOF, 0 for success, and >0 for all errors.
299  */
300 static int
301 GetNthIdentityOrUser(struct afsconf_dir *dir, int count,
302                      struct rx_identity **identity, int id)
303 {
304     bufio_p bp;
305     char *tbuffer;
306     struct rx_identity fileUser;
307     afs_int32 code;
308
309     tbuffer = malloc(AFSDIR_PATH_MAX);
310     if (tbuffer == NULL)
311         return ENOMEM;
312
313     LOCK_GLOBAL_MUTEX;
314     UserListFileName(dir, tbuffer, AFSDIR_PATH_MAX);
315     bp = BufioOpen(tbuffer, O_RDONLY, 0);
316     if (!bp) {
317         UNLOCK_GLOBAL_MUTEX;
318         free(tbuffer);
319         return -1;
320     }
321     while (1) {
322         code = BufioGets(bp, tbuffer, AFSDIR_PATH_MAX);
323         if (code < 0) {
324             code = -1;
325             break;
326         }
327
328         code = ParseLine(tbuffer, &fileUser);
329         if (code != 0)
330             break;
331
332         if (id || fileUser.kind == RX_ID_KRB4)
333             count--;
334
335         if (count < 0)
336             break;
337         else
338             rx_identity_freeContents(&fileUser);
339     }
340     if (code == 0) {
341         *identity = rx_identity_copy(&fileUser);
342         rx_identity_freeContents(&fileUser);
343     }
344
345     BufioClose(bp);
346
347     UNLOCK_GLOBAL_MUTEX;
348     free(tbuffer);
349     return code;
350 }
351
352 /*!
353  * Return the Nth super user identity from the UserList
354  *
355  * @param[in] dir
356  *      A structure representing the configuration directory
357  * @param[in] count
358  *      A count (from zero) of the entries to return from the
359  *      UserList
360  * @param[out] identity
361  *      A pointer to the Nth identity
362  * @returns
363  *      status code
364  * @retval 0 Success
365  * @retval -1 We have searched beyond the end of the list.
366  * @retval >0 Error
367  */
368
369 int
370 afsconf_GetNthIdentity(struct afsconf_dir *dir, int count,
371                        struct rx_identity **identity)
372 {
373    return GetNthIdentityOrUser(dir, count, identity, 1);
374 }
375
376 /*!
377  * Return the Nth Kerberos v4 identity from the UserList
378  *
379  * This returns the Nth old, kerberos v4 style name from
380  * the UserList file. In counting entries it skips any other
381  * name types it encounters - so will hide any new-style
382  * identities from its callers.
383  *
384  * @param[in] dir
385  *      A structure representing the configuration directory
386  * @param[in] count
387  *      A count (from zero) of the entries to return from the
388  *      UserList
389  * @param abuffer
390  *      A string in which to write the name of the Nth identity
391  * @param abufferLen
392  *      The length of the buffer passed in abuffer
393  * @returns
394  *      status code
395  * @retval 0 Success
396  * @retval 1 Either an EPERM error, or we have searched beyond the end of the
397  *           list.
398  * @retval >1 All other errors.
399  *
400  * This function is deprecated, all new callers should use
401  * GetNthIdentity instead. This function is particularly dangerous
402  * as it will hide any new-style identities from callers. It is also
403  * impossible to distinguish an EPERM error from a normal end-of-file
404  * condition with this function.
405  */
406
407 int
408 afsconf_GetNthUser(struct afsconf_dir *adir, afs_int32 an, char *abuffer,
409                    afs_int32 abufferLen)
410 {
411     struct rx_identity *identity;
412     int code;
413
414     code = GetNthIdentityOrUser(adir, an, &identity, 0);
415     if (code == 0) {
416         strlcpy(abuffer, identity->displayName, abufferLen);
417         rx_identity_free(&identity);
418     }
419     if (code == -1) {
420         /* The new functions use -1 to indicate EOF, but the old interface
421          * uses 1 to indicate EOF. */
422         code = 1;
423     }
424     return code;
425 }
426
427 /*!
428  * Parse a UserList list
429  *
430  * Parse a line of data from a UserList file
431  *
432  * This parses a line of data in a UserList, and populates the passed
433  * rx_identity structure with the information about the user.
434  *
435  * @param buffer        A string containing the line to be parsed
436  * @param user          The user structure to be populated
437  *
438  * Note that the user->displayName, and user->exportedName.val fields
439  * must be freed with free() by the caller.
440  *
441  * This function damages the buffer thats passed to it. Callers are
442  * expected to make a copy if they want the buffer preserved.
443  *
444  * @return
445  *      0 on success, non-zero on failure.
446  */
447
448 static int
449 ParseLine(char *buffer, struct rx_identity *user)
450 {
451     char *ptr;
452     char *ename;
453     char *displayName;
454     char *decodedName;
455     char name[64+1];
456     int len;
457     int kind;
458     int code;
459
460     if (buffer[0] == ' ') { /* extended names have leading space */
461         ptr = buffer + 1;
462         code = sscanf(ptr, "%i", &kind);
463         if (code != 1)
464             return EINVAL;
465
466         strsep(&ptr, " "); /* skip the bit we just read with scanf */
467         ename = strsep(&ptr, " "); /* Pull out the ename */
468         displayName = strsep(&ptr, " "); /* Display name runs to the end */
469         if (ename == NULL || displayName == NULL)
470             return EINVAL;
471
472         decodedName = malloc(strlen(ename));
473         if (decodedName == NULL)
474             return ENOMEM;
475
476         len = base64_decode(ename, decodedName);
477         if (len<0) {
478             free(decodedName);
479             return EINVAL;
480         }
481
482         rx_identity_populate(user, kind, displayName, decodedName, len);
483         free(decodedName);
484
485         return 0; /* Success ! */
486     }
487
488     /* No extended name, try for a legacy name */
489     code = sscanf(buffer, "%64s", name);
490     if (code != 1)
491         return EINVAL;
492
493     rx_identity_populate(user, RX_ID_KRB4, name, name, strlen(name));
494     return 0;
495 }
496
497 /*!
498  * Check if a given identity is in the UserList file,
499  * and thus is a super user
500  *
501  * @param adir
502  *      A structure representing the configuration directory to check
503  * @param user
504  *      The identity to check
505  * @returns
506  *      True if the user is listed in the UserList, otherwise false
507  */
508
509 int
510 afsconf_IsSuperIdentity(struct afsconf_dir *adir,
511                         struct rx_identity *user)
512 {
513     bufio_p bp;
514     char *tbuffer;
515     struct rx_identity fileUser;
516     int match;
517     afs_int32 code;
518
519     if (user->kind == RX_ID_SUPERUSER)
520         return 1;
521
522     tbuffer = malloc(AFSDIR_PATH_MAX);
523     if (tbuffer == NULL)
524         return 0;
525
526     UserListFileName(adir, tbuffer, AFSDIR_PATH_MAX);
527     bp = BufioOpen(tbuffer, O_RDONLY, 0);
528     if (!bp) {
529         free(tbuffer);
530         return 0;
531     }
532     match = 0;
533     while (!match) {
534         code = BufioGets(bp, tbuffer, AFSDIR_PATH_MAX);
535         if (code < 0)
536             break;
537
538         code = ParseLine(tbuffer, &fileUser);
539         if (code != 0)
540            break;
541
542         match = rx_identity_match(user, &fileUser);
543
544         rx_identity_freeContents(&fileUser);
545     }
546     BufioClose(bp);
547     free(tbuffer);
548     return match;
549 }
550
551 /* add a user to the user list, checking for duplicates */
552 int
553 afsconf_AddIdentity(struct afsconf_dir *adir, struct rx_identity *user)
554 {
555     FILE *tf;
556     afs_int32 code;
557     char *ename;
558     char *tbuffer;
559
560     LOCK_GLOBAL_MUTEX;
561     if (afsconf_IsSuperIdentity(adir, user)) {
562         UNLOCK_GLOBAL_MUTEX;
563         return EEXIST;          /* already in the list */
564     }
565
566     tbuffer = malloc(AFSDIR_PATH_MAX);
567     UserListFileName(adir, tbuffer, AFSDIR_PATH_MAX);
568     tf = fopen(tbuffer, "a+");
569     free(tbuffer);
570     if (!tf) {
571         UNLOCK_GLOBAL_MUTEX;
572         return EIO;
573     }
574     if (user->kind == RX_ID_KRB4) {
575         fprintf(tf, "%s\n", user->displayName);
576     } else {
577         base64_encode(user->exportedName.val, user->exportedName.len,
578                       &ename);
579         fprintf(tf, " %d %s %s\n", user->kind, ename, user->displayName);
580         free(ename);
581     }
582     code = 0;
583     if (ferror(tf))
584         code = EIO;
585     if (fclose(tf))
586         code = EIO;
587     UNLOCK_GLOBAL_MUTEX;
588     return code;
589 }
590
591 int
592 afsconf_AddUser(struct afsconf_dir *adir, char *aname)
593 {
594     struct rx_identity *user;
595     int code;
596
597     user = rx_identity_new(RX_ID_KRB4, aname, aname, strlen(aname));
598     if (user == NULL)
599         return ENOMEM;
600
601     code = afsconf_AddIdentity(adir, user);
602
603     rx_identity_free(&user);
604
605     return code;
606 }
607
608 /* special CompFindUser routine that builds up a princ and then
609         calls finduser on it. If found, returns char * to user string,
610         otherwise returns NULL. The resulting string should be immediately
611         copied to other storage prior to release of mutex. */
612 static int
613 CompFindUser(struct afsconf_dir *adir, char *name, char *sep, char *inst,
614              char *realm, struct rx_identity **identity)
615 {
616     static char fullname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
617     struct rx_identity *testId;
618
619     /* always must have name */
620     if (!name || !name[0]) {
621         return 0;
622     }
623
624     if (strlcpy(fullname, name, sizeof(fullname)) >= sizeof(fullname))
625         return 0;
626
627     /* might have instance */
628     if (inst && inst[0]) {
629         if (!sep || !sep[0]) {
630             return 0;
631         }
632
633         if (strlcat(fullname, sep, sizeof(fullname)) >= sizeof(fullname))
634             return 0;
635
636         if (strlcat(fullname, inst, sizeof(fullname)) >= sizeof(fullname))
637             return 0;
638     }
639
640     /* might have realm */
641     if (realm && realm[0]) {
642         if (strlcat(fullname, "@", sizeof(fullname)) >= sizeof(fullname))
643             return 0;
644
645         if (strlcat(fullname, realm, sizeof(fullname)) >= sizeof(fullname))
646             return 0;
647     }
648
649     testId = rx_identity_new(RX_ID_KRB4, fullname, fullname, strlen(fullname));
650     if (afsconf_IsSuperIdentity(adir, testId)) {
651         if (identity)
652              *identity = testId;
653         else
654              rx_identity_free(&testId);
655         return 1;
656     }
657
658     rx_identity_free(&testId);
659     return 0;
660 }
661
662 static int
663 kerberosSuperUser(struct afsconf_dir *adir, char *tname, char *tinst,
664                   char *tcell, struct rx_identity **identity)
665 {
666     char tcell_l[MAXKTCREALMLEN] = "";
667     int code;
668     afs_int32 islocal;
669     int flag;
670
671     /* generate lowercased version of cell name */
672     if (tcell)
673         opr_lcstring(tcell_l, tcell, sizeof(tcell_l));
674
675     code = afsconf_IsLocalRealmMatch(adir, &islocal, tname, tinst, tcell);
676     if (code) {
677         return 0;
678     }
679
680     /* start with no authorization */
681     flag = 0;
682
683     /* localauth special case */
684     if ((tinst == NULL || strlen(tinst) == 0) &&
685         (tcell == NULL || strlen(tcell) == 0)
686         && !strcmp(tname, AUTH_SUPERUSER)) {
687         if (identity)
688             *identity = rx_identity_new(RX_ID_KRB4, AFS_LOCALAUTH_NAME,
689                                         AFS_LOCALAUTH_NAME, AFS_LOCALAUTH_LEN);
690         flag = 1;
691
692         /* cell of connection matches local cell or one of the realms */
693     } else if (islocal) {
694         if (CompFindUser(adir, tname, ".", tinst, NULL, identity)) {
695             flag = 1;
696         }
697         /* cell of conn doesn't match local cell or realm */
698     } else {
699         if (CompFindUser(adir, tname, ".", tinst, tcell, identity)) {
700             flag = 1;
701         } else if (CompFindUser(adir, tname, ".", tinst, tcell_l, identity)) {
702             flag = 1;
703         }
704     }
705
706     return flag;
707 }
708
709 static int
710 rxkadSuperUser(struct afsconf_dir *adir, struct rx_call *acall,
711                struct rx_identity **identity)
712 {
713     char tname[MAXKTCNAMELEN];  /* authentication from ticket */
714     char tinst[MAXKTCNAMELEN];
715     char tcell[MAXKTCREALMLEN];
716
717     afs_uint32 exp;
718     int code;
719
720     /* get auth details from server connection */
721     code = rxkad_GetServerInfo(rx_ConnectionOf(acall), NULL, &exp, tname,
722                                tinst, tcell, NULL);
723     if (code)
724         return 0;               /* bogus connection/other error */
725
726     return kerberosSuperUser(adir, tname, tinst, tcell, identity);
727 }
728
729 #ifdef AFS_RXGK_ENV
730 static int
731 rxgkSuperUser(struct afsconf_dir *adir, struct rx_call *acall,
732               struct rx_identity **identity_out)
733 {
734     struct rx_identity *identity = NULL;
735     int is_super = 0;
736
737     if (rxgk_GetServerInfo(rx_ConnectionOf(acall), NULL /*level*/, NULL /*expiry*/,
738                            &identity) != 0)
739         return 0;
740
741     if (afsconf_IsSuperIdentity(adir, identity)) {
742         is_super = 1;
743         if (identity_out != NULL) {
744             *identity_out = identity;
745             identity = NULL;
746         }
747     }
748     if (identity != NULL) {
749         rx_identity_free(&identity);
750     }
751     return is_super;
752 }
753 #endif /* AFS_RXGK_ENV */
754
755 /*!
756  * Check whether the user authenticated on a given RX call is a super
757  * user or not. If they are, return a pointer to the identity of that
758  * user.
759  *
760  * @param[in] adir
761  *      The configuration directory currently in use
762  * @param[in] acall
763  *      The RX call whose authenticated identity is being checked
764  * @param[out] identity
765  *      The RX identity of the user. Caller must free this structure.
766  * @returns
767  *      True if the user is a super user, or if the server is running
768  *      in noauth mode. Otherwise, false.
769  */
770 afs_int32
771 afsconf_SuperIdentity(struct afsconf_dir *adir, struct rx_call *acall,
772                       struct rx_identity **identity)
773 {
774     struct rx_connection *tconn;
775     afs_int32 code;
776     int flag;
777
778     LOCK_GLOBAL_MUTEX;
779     if (!adir) {
780         UNLOCK_GLOBAL_MUTEX;
781         return 0;
782     }
783
784     if (afsconf_GetNoAuthFlag(adir)) {
785         if (identity)
786             *identity = rx_identity_new(RX_ID_KRB4, AFS_NOAUTH_NAME,
787                                         AFS_NOAUTH_NAME, AFS_NOAUTH_LEN);
788         UNLOCK_GLOBAL_MUTEX;
789         return 1;
790     }
791
792     tconn = rx_ConnectionOf(acall);
793     code = rx_SecurityClassOf(tconn);
794     if (code == RX_SECIDX_NULL) {
795         UNLOCK_GLOBAL_MUTEX;
796         return 0;               /* not authenticated at all, answer is no */
797     } else if (code == RX_SECIDX_VAB) {
798         /* bcrypt tokens */
799         UNLOCK_GLOBAL_MUTEX;
800         return 0;               /* not supported any longer */
801     } else if (code == RX_SECIDX_KAD) {
802         flag = rxkadSuperUser(adir, acall, identity);
803         UNLOCK_GLOBAL_MUTEX;
804         return flag;
805 #ifdef AFS_RXGK_ENV
806     } else if (code == RX_SECIDX_GK) {
807         flag = rxgkSuperUser(adir, acall, identity);
808         UNLOCK_GLOBAL_MUTEX;
809         return flag;
810 #endif
811     } else {                    /* some other auth type */
812         UNLOCK_GLOBAL_MUTEX;
813         return 0;               /* mysterious, just say no */
814     }
815 }
816
817 /*!
818  * Check whether the user authenticated on a given RX call is a super
819  * user or not. If they are, return a pointer to the name of that
820  * user.
821  *
822  * @param[in] adir
823  *      The configuration directory currently in use
824  * @param[in] acall
825  *      The RX call whose authenticated identity is being checked
826  * @param[out] namep
827  *      A printable version of the name of the user
828  * @returns
829  *      True if the user is a super user, or if the server is running
830  *      in noauth mode. Otherwise, false.
831  *
832  * This function is provided for backwards compatibility. New callers
833  * should use the afsconf_SuperIdentity function.
834  */
835
836 afs_int32
837 afsconf_SuperUser(struct afsconf_dir *adir, struct rx_call *acall,
838                   char *namep)
839 {
840     struct rx_identity *identity;
841     int ret;
842
843     if (namep) {
844         ret = afsconf_SuperIdentity(adir, acall, &identity);
845         if (ret) {
846             if (identity->kind == RX_ID_KRB4) {
847                 strlcpy(namep, identity->displayName, MAXKTCNAMELEN-1);
848             } else {
849                 snprintf(namep, MAXKTCNAMELEN-1, "eName: %s",
850                          identity->displayName);
851             }
852             rx_identity_free(&identity);
853         }
854     } else {
855         ret = afsconf_SuperIdentity(adir, acall, NULL);
856     }
857
858     return ret;
859 }
860
861 /*!
862  * Check whether the user authenticated on a given RX call is
863  * compatible with the access specified by needed_level.
864  *
865  * @param[in] adir
866  *      The configuration directory currently in use
867  * @param[in] acall
868  *      The RX call whose authenticated identity is being checked
869  * @param[in] needed_level
870  *      Either RESTRICTED_QUERY_ANYUSER for allowing any access or
871  *      RESTRICTED_QUERY_ADMIN for allowing super user only.
872  * @returns
873  *      True if the user is compatible with needed_level.
874  *      Otherwise, false.
875  */
876
877 int
878 afsconf_CheckRestrictedQuery(struct afsconf_dir *adir,
879                              struct rx_call *acall,
880                              int needed_level)
881 {
882     if (needed_level == RESTRICTED_QUERY_ANYUSER)
883         return 1;
884
885     return afsconf_SuperIdentity(adir, acall, NULL);
886 }