2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
19 #include <afs/pthread_glock.h>
22 #include <rx/rx_identity.h>
23 #include <afs/afsutil.h>
24 #include <afs/fileutil.h>
28 #include "cellconfig.h"
30 #include "afs/audit.h"
32 /* The display names for localauth and noauth identities; they aren't used
33 * inside tickets or anything, but just serve as something to display in logs,
35 #define AFS_LOCALAUTH_NAME "<LocalAuth>"
36 #define AFS_LOCALAUTH_LEN (sizeof(AFS_LOCALAUTH_NAME)-1)
37 #define AFS_NOAUTH_NAME "<NoAuth>"
38 #define AFS_NOAUTH_LEN (sizeof(AFS_NOAUTH_NAME)-1)
40 static int ParseLine(char *buffer
, struct rx_identity
*user
);
43 UserListFileName(struct afsconf_dir
*adir
,
44 char *buffer
, size_t len
)
46 strcompose(buffer
, len
, adir
->name
, "/", AFSDIR_ULIST_FILE
, (char *)NULL
);
50 afsconf_CheckAuth(void *arock
, struct rx_call
*acall
)
52 struct afsconf_dir
*adir
= (struct afsconf_dir
*) arock
;
55 rc
= ((afsconf_SuperUser(adir
, acall
, NULL
) == 0) ? 10029 : 0);
61 GetNoAuthFlag(struct afsconf_dir
*adir
)
63 if (access(AFSDIR_SERVER_NOAUTH_FILEPATH
, 0) == 0) {
64 osi_audit(NoAuthEvent
, 0, AUD_END
); /* some random server is running noauth */
65 return 1; /* if /usr/afs/local/NoAuth file exists, allow access */
72 afsconf_GetNoAuthFlag(struct afsconf_dir
*adir
)
77 rc
= GetNoAuthFlag(adir
);
83 afsconf_SetNoAuthFlag(struct afsconf_dir
*adir
, int aflag
)
89 /* turn off noauth flag */
90 code
= (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH
) ? errno
: 0);
91 osi_audit(NoAuthDisableEvent
, code
, AUD_END
);
93 /* try to create file */
95 open(AFSDIR_SERVER_NOAUTH_FILEPATH
, O_CREAT
| O_TRUNC
| O_RDWR
,
99 osi_audit(NoAuthEnableEvent
, 0, AUD_END
);
101 osi_audit(NoAuthEnableEvent
, errno
, AUD_END
);
107 * Remove an identity from the UserList file
109 * This function removes the given identity from the user list file.
110 * For the purposes of identifying entries to remove, only the
111 * type and exportedName portions of the identity are used. Callers
112 * should remember that a given identity may be listed in the file in
113 * a number of different ways.
116 * A structure representing the configuration directory currently
119 * The RX identity to delete
122 * 0 on success, an error code on failure
126 afsconf_DeleteIdentity(struct afsconf_dir
*adir
, struct rx_identity
*user
)
128 char *filename
, *nfilename
;
137 struct rx_identity identity
;
140 memset(&identity
, 0, sizeof(struct rx_identity
));
142 buffer
= malloc(AFSDIR_PATH_MAX
);
145 filename
= malloc(AFSDIR_PATH_MAX
);
146 if (filename
== NULL
) {
152 UserListFileName(adir
, filename
, AFSDIR_PATH_MAX
);
156 * We attempt to fully resolve this pathname, so that the rename
157 * of the temporary file will work even if UserList is a symlink
158 * into a different filesystem.
160 nfilename
= malloc(AFSDIR_PATH_MAX
);
161 if (nfilename
== NULL
) {
167 if (realpath(filename
, nfilename
)) {
169 filename
= nfilename
;
174 #endif /* AFS_NT40_ENV */
175 if (asprintf(&nfilename
, "%s.NXX", filename
) < 0) {
181 tf
= fopen(filename
, "r");
189 code
= stat(filename
, &tstat
);
197 nf
= fopen(nfilename
, "w+");
209 /* check for our user id */
210 tp
= fgets(buffer
, AFSDIR_PATH_MAX
, tf
);
214 copy
= strdup(buffer
);
219 code
= ParseLine(copy
, &identity
);
220 if (code
== 0 && rx_identity_match(user
, &identity
)) {
221 /* found the guy, don't copy to output file */
224 /* otherwise copy original line to output */
225 fprintf(nf
, "%s", buffer
);
228 rx_identity_freeContents(&identity
);
234 if (fclose(nf
) == EOF
)
238 flag
= rk_rename(nfilename
, filename
);
240 flag
= chmod(filename
, tstat
.st_mode
);
244 /* finally, decide what to return to the caller */
249 return EIO
; /* something mysterious went wrong */
251 return ENOENT
; /* entry wasn't found, no changes made */
252 return 0; /* everything was fine */
256 * Remove a legacy Kerberos 4 name from the UserList file.
258 * This function removes a Kerberos 4 name from the super user list. It
259 * can only remove names which were added by the afsconf_AddUser interface,
260 * or with an explicit Kerberos v4 type.
263 * A structure representing the configuration directory
265 * The Kerberos v4 name to remove
268 * 0 on success, an error code upon failure.
270 * Note that this function is deprecated. New callers should use
271 * afsconf_DeleteIdentity instead.
275 afsconf_DeleteUser(struct afsconf_dir
*adir
, char *name
)
277 struct rx_identity
*user
;
280 user
= rx_identity_new(RX_ID_KRB4
, name
, name
, strlen(name
));
284 code
= afsconf_DeleteIdentity(adir
, user
);
286 rx_identity_free(&user
);
291 /* This is a multi-purpose funciton for use by either
292 * GetNthIdentity or GetNthUser. The parameter 'id' indicates
293 * whether we are counting all identities (if true), or just
294 * ones which can be represented by the old-style interfaces
295 * We return -1 for EOF, 0 for success, and >0 for all errors.
298 GetNthIdentityOrUser(struct afsconf_dir
*dir
, int count
,
299 struct rx_identity
**identity
, int id
)
303 struct rx_identity fileUser
;
306 tbuffer
= malloc(AFSDIR_PATH_MAX
);
311 UserListFileName(dir
, tbuffer
, AFSDIR_PATH_MAX
);
312 bp
= BufioOpen(tbuffer
, O_RDONLY
, 0);
319 code
= BufioGets(bp
, tbuffer
, AFSDIR_PATH_MAX
);
325 code
= ParseLine(tbuffer
, &fileUser
);
329 if (id
|| fileUser
.kind
== RX_ID_KRB4
)
335 rx_identity_freeContents(&fileUser
);
338 *identity
= rx_identity_copy(&fileUser
);
339 rx_identity_freeContents(&fileUser
);
350 * Return the Nth super user identity from the UserList
353 * A structure representing the configuration directory
355 * A count (from zero) of the entries to return from the
357 * @param[out] identity
358 * A pointer to the Nth identity
362 * @retval -1 We have searched beyond the end of the list.
367 afsconf_GetNthIdentity(struct afsconf_dir
*dir
, int count
,
368 struct rx_identity
**identity
)
370 return GetNthIdentityOrUser(dir
, count
, identity
, 1);
374 * Return the Nth Kerberos v4 identity from the UserList
376 * This returns the Nth old, kerberos v4 style name from
377 * the UserList file. In counting entries it skips any other
378 * name types it encounters - so will hide any new-style
379 * identities from its callers.
382 * A structure representing the configuration directory
384 * A count (from zero) of the entries to return from the
387 * A string in which to write the name of the Nth identity
389 * The length of the buffer passed in abuffer
393 * @retval 1 Either an EPERM error, or we have searched beyond the end of the
395 * @retval >1 All other errors.
397 * This function is deprecated, all new callers should use
398 * GetNthIdentity instead. This function is particularly dangerous
399 * as it will hide any new-style identities from callers. It is also
400 * impossible to distinguish an EPERM error from a normal end-of-file
401 * condition with this function.
405 afsconf_GetNthUser(struct afsconf_dir
*adir
, afs_int32 an
, char *abuffer
,
406 afs_int32 abufferLen
)
408 struct rx_identity
*identity
;
411 code
= GetNthIdentityOrUser(adir
, an
, &identity
, 0);
413 strlcpy(abuffer
, identity
->displayName
, abufferLen
);
414 rx_identity_free(&identity
);
417 /* The new functions use -1 to indicate EOF, but the old interface
418 * uses 1 to indicate EOF. */
425 * Parse a UserList list
427 * Parse a line of data from a UserList file
429 * This parses a line of data in a UserList, and populates the passed
430 * rx_identity structure with the information about the user.
432 * @param buffer A string containing the line to be parsed
433 * @param user The user structure to be populated
435 * Note that the user->displayName, and user->exportedName.val fields
436 * must be freed with free() by the caller.
438 * This function damages the buffer thats passed to it. Callers are
439 * expected to make a copy if they want the buffer preserved.
442 * 0 on success, non-zero on failure.
446 ParseLine(char *buffer
, struct rx_identity
*user
)
457 if (buffer
[0] == ' ') { /* extended names have leading space */
459 code
= sscanf(ptr
, "%i", &kind
);
463 strsep(&ptr
, " "); /* skip the bit we just read with scanf */
464 ename
= strsep(&ptr
, " "); /* Pull out the ename */
465 displayName
= strsep(&ptr
, " "); /* Display name runs to the end */
466 if (ename
== NULL
|| displayName
== NULL
)
469 decodedName
= malloc(strlen(ename
));
470 if (decodedName
== NULL
)
473 len
= base64_decode(ename
, decodedName
);
479 rx_identity_populate(user
, kind
, displayName
, decodedName
, len
);
482 return 0; /* Success ! */
485 /* No extended name, try for a legacy name */
486 code
= sscanf(buffer
, "%64s", name
);
490 rx_identity_populate(user
, RX_ID_KRB4
, name
, name
, strlen(name
));
495 * Check if a given identity is in the UserList file,
496 * and thus is a super user
499 * A structure representing the configuration directory to check
501 * The identity to check
503 * True if the user is listed in the UserList, otherwise false
507 afsconf_IsSuperIdentity(struct afsconf_dir
*adir
,
508 struct rx_identity
*user
)
512 struct rx_identity fileUser
;
516 if (user
->kind
== RX_ID_SUPERUSER
)
519 tbuffer
= malloc(AFSDIR_PATH_MAX
);
523 UserListFileName(adir
, tbuffer
, AFSDIR_PATH_MAX
);
524 bp
= BufioOpen(tbuffer
, O_RDONLY
, 0);
531 code
= BufioGets(bp
, tbuffer
, AFSDIR_PATH_MAX
);
535 code
= ParseLine(tbuffer
, &fileUser
);
539 match
= rx_identity_match(user
, &fileUser
);
541 rx_identity_freeContents(&fileUser
);
548 /* add a user to the user list, checking for duplicates */
550 afsconf_AddIdentity(struct afsconf_dir
*adir
, struct rx_identity
*user
)
558 if (afsconf_IsSuperIdentity(adir
, user
)) {
560 return EEXIST
; /* already in the list */
563 tbuffer
= malloc(AFSDIR_PATH_MAX
);
564 UserListFileName(adir
, tbuffer
, AFSDIR_PATH_MAX
);
565 tf
= fopen(tbuffer
, "a+");
571 if (user
->kind
== RX_ID_KRB4
) {
572 fprintf(tf
, "%s\n", user
->displayName
);
574 base64_encode(user
->exportedName
.val
, user
->exportedName
.len
,
576 fprintf(tf
, " %d %s %s\n", user
->kind
, ename
, user
->displayName
);
589 afsconf_AddUser(struct afsconf_dir
*adir
, char *aname
)
591 struct rx_identity
*user
;
594 user
= rx_identity_new(RX_ID_KRB4
, aname
, aname
, strlen(aname
));
598 code
= afsconf_AddIdentity(adir
, user
);
600 rx_identity_free(&user
);
605 /* special CompFindUser routine that builds up a princ and then
606 calls finduser on it. If found, returns char * to user string,
607 otherwise returns NULL. The resulting string should be immediately
608 copied to other storage prior to release of mutex. */
610 CompFindUser(struct afsconf_dir
*adir
, char *name
, char *sep
, char *inst
,
611 char *realm
, struct rx_identity
**identity
)
613 static char fullname
[MAXKTCNAMELEN
+ MAXKTCNAMELEN
+ MAXKTCREALMLEN
+ 3];
614 struct rx_identity
*testId
;
616 /* always must have name */
617 if (!name
|| !name
[0]) {
621 if (strlcpy(fullname
, name
, sizeof(fullname
)) >= sizeof(fullname
))
624 /* might have instance */
625 if (inst
&& inst
[0]) {
626 if (!sep
|| !sep
[0]) {
630 if (strlcat(fullname
, sep
, sizeof(fullname
)) >= sizeof(fullname
))
633 if (strlcat(fullname
, inst
, sizeof(fullname
)) >= sizeof(fullname
))
637 /* might have realm */
638 if (realm
&& realm
[0]) {
639 if (strlcat(fullname
, "@", sizeof(fullname
)) >= sizeof(fullname
))
642 if (strlcat(fullname
, realm
, sizeof(fullname
)) >= sizeof(fullname
))
646 testId
= rx_identity_new(RX_ID_KRB4
, fullname
, fullname
, strlen(fullname
));
647 if (afsconf_IsSuperIdentity(adir
, testId
)) {
651 rx_identity_free(&testId
);
655 rx_identity_free(&testId
);
660 kerberosSuperUser(struct afsconf_dir
*adir
, char *tname
, char *tinst
,
661 char *tcell
, struct rx_identity
**identity
)
663 char tcell_l
[MAXKTCREALMLEN
] = "";
668 /* generate lowercased version of cell name */
670 opr_lcstring(tcell_l
, tcell
, sizeof(tcell_l
));
672 code
= afsconf_IsLocalRealmMatch(adir
, &islocal
, tname
, tinst
, tcell
);
677 /* start with no authorization */
680 /* localauth special case */
681 if ((tinst
== NULL
|| strlen(tinst
) == 0) &&
682 (tcell
== NULL
|| strlen(tcell
) == 0)
683 && !strcmp(tname
, AUTH_SUPERUSER
)) {
685 *identity
= rx_identity_new(RX_ID_KRB4
, AFS_LOCALAUTH_NAME
,
686 AFS_LOCALAUTH_NAME
, AFS_LOCALAUTH_LEN
);
689 /* cell of connection matches local cell or one of the realms */
690 } else if (islocal
) {
691 if (CompFindUser(adir
, tname
, ".", tinst
, NULL
, identity
)) {
694 /* cell of conn doesn't match local cell or realm */
696 if (CompFindUser(adir
, tname
, ".", tinst
, tcell
, identity
)) {
698 } else if (CompFindUser(adir
, tname
, ".", tinst
, tcell_l
, identity
)) {
707 rxkadSuperUser(struct afsconf_dir
*adir
, struct rx_call
*acall
,
708 struct rx_identity
**identity
)
710 char tname
[MAXKTCNAMELEN
]; /* authentication from ticket */
711 char tinst
[MAXKTCNAMELEN
];
712 char tcell
[MAXKTCREALMLEN
];
717 /* get auth details from server connection */
718 code
= rxkad_GetServerInfo(rx_ConnectionOf(acall
), NULL
, &exp
, tname
,
721 return 0; /* bogus connection/other error */
723 return kerberosSuperUser(adir
, tname
, tinst
, tcell
, identity
);
727 * Check whether the user authenticated on a given RX call is a super
728 * user or not. If they are, return a pointer to the identity of that
732 * The configuration directory currently in use
734 * The RX call whose authenticated identity is being checked
735 * @param[out] identity
736 * The RX identity of the user. Caller must free this structure.
738 * True if the user is a super user, or if the server is running
739 * in noauth mode. Otherwise, false.
742 afsconf_SuperIdentity(struct afsconf_dir
*adir
, struct rx_call
*acall
,
743 struct rx_identity
**identity
)
745 struct rx_connection
*tconn
;
755 if (afsconf_GetNoAuthFlag(adir
)) {
757 *identity
= rx_identity_new(RX_ID_KRB4
, AFS_NOAUTH_NAME
,
758 AFS_NOAUTH_NAME
, AFS_NOAUTH_LEN
);
763 tconn
= rx_ConnectionOf(acall
);
764 code
= rx_SecurityClassOf(tconn
);
765 if (code
== RX_SECIDX_NULL
) {
767 return 0; /* not authenticated at all, answer is no */
768 } else if (code
== RX_SECIDX_VAB
) {
771 return 0; /* not supported any longer */
772 } else if (code
== RX_SECIDX_KAD
) {
773 flag
= rxkadSuperUser(adir
, acall
, identity
);
776 } else { /* some other auth type */
778 return 0; /* mysterious, just say no */
783 * Check whether the user authenticated on a given RX call is a super
784 * user or not. If they are, return a pointer to the name of that
788 * The configuration directory currently in use
790 * The RX call whose authenticated identity is being checked
792 * A printable version of the name of the user
794 * True if the user is a super user, or if the server is running
795 * in noauth mode. Otherwise, false.
797 * This function is provided for backwards compatibility. New callers
798 * should use the afsconf_SuperIdentity function.
802 afsconf_SuperUser(struct afsconf_dir
*adir
, struct rx_call
*acall
,
805 struct rx_identity
*identity
;
809 ret
= afsconf_SuperIdentity(adir
, acall
, &identity
);
811 if (identity
->kind
== RX_ID_KRB4
) {
812 strlcpy(namep
, identity
->displayName
, MAXKTCNAMELEN
-1);
814 snprintf(namep
, MAXKTCNAMELEN
-1, "eName: %s",
815 identity
->displayName
);
817 rx_identity_free(&identity
);
820 ret
= afsconf_SuperIdentity(adir
, acall
, NULL
);
827 * Check whether the user authenticated on a given RX call is
828 * compatible with the access specified by needed_level.
831 * The configuration directory currently in use
833 * The RX call whose authenticated identity is being checked
834 * @param[in] needed_level
835 * Either RESTRICTED_QUERY_ANYUSER for allowing any access or
836 * RESTRICTED_QUERY_ADMIN for allowing super user only.
838 * True if the user is compatible with needed_level.
843 afsconf_CheckRestrictedQuery(struct afsconf_dir
*adir
,
844 struct rx_call
*acall
,
847 if (needed_level
== RESTRICTED_QUERY_ANYUSER
)
850 return afsconf_SuperIdentity(adir
, acall
, NULL
);