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