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