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