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>
26 #include <afs/afsutil.h>
27 #include <afs/fileutil.h>
31 #include "cellconfig.h"
33 #include "afs/audit.h"
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,
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)
43 static int ParseLine(char *buffer, struct rx_identity *user);
46 UserListFileName(struct afsconf_dir *adir,
47 char *buffer, size_t len)
49 strcompose(buffer, len, adir->name, "/", AFSDIR_ULIST_FILE, (char *)NULL);
53 afsconf_CheckAuth(void *arock, struct rx_call *acall)
55 struct afsconf_dir *adir = (struct afsconf_dir *) arock;
58 rc = ((afsconf_SuperUser(adir, acall, NULL) == 0) ? 10029 : 0);
64 GetNoAuthFlag(struct afsconf_dir *adir)
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 */
75 afsconf_GetNoAuthFlag(struct afsconf_dir *adir)
80 rc = GetNoAuthFlag(adir);
86 afsconf_SetNoAuthFlag(struct afsconf_dir *adir, int aflag)
92 /* turn off noauth flag */
93 code = (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0);
94 osi_audit(NoAuthDisableEvent, code, AUD_END);
96 /* try to create file */
98 open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR,
102 osi_audit(NoAuthEnableEvent, 0, AUD_END);
104 osi_audit(NoAuthEnableEvent, errno, AUD_END);
110 * Remove an identity from the UserList file
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.
119 * A structure representing the configuration directory currently
122 * The RX identity to delete
125 * 0 on success, an error code on failure
129 afsconf_DeleteIdentity(struct afsconf_dir *adir, struct rx_identity *user)
131 char *filename, *nfilename;
140 struct rx_identity identity;
143 memset(&identity, 0, sizeof(struct rx_identity));
145 buffer = malloc(AFSDIR_PATH_MAX);
148 filename = malloc(AFSDIR_PATH_MAX);
149 if (filename == NULL) {
155 UserListFileName(adir, filename, AFSDIR_PATH_MAX);
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.
163 nfilename = malloc(AFSDIR_PATH_MAX);
164 if (nfilename == NULL) {
170 if (realpath(filename, nfilename)) {
172 filename = nfilename;
177 #endif /* AFS_NT40_ENV */
178 if (asprintf(&nfilename, "%s.NXX", filename) < 0) {
184 tf = fopen(filename, "r");
192 code = stat(filename, &tstat);
200 nf = fopen(nfilename, "w+");
212 /* check for our user id */
213 tp = fgets(buffer, AFSDIR_PATH_MAX, tf);
217 copy = strdup(buffer);
222 code = ParseLine(copy, &identity);
223 if (code == 0 && rx_identity_match(user, &identity)) {
224 /* found the guy, don't copy to output file */
227 /* otherwise copy original line to output */
228 fprintf(nf, "%s", buffer);
231 rx_identity_freeContents(&identity);
237 if (fclose(nf) == EOF)
241 flag = rk_rename(nfilename, filename);
243 flag = chmod(filename, tstat.st_mode);
247 /* finally, decide what to return to the caller */
252 return EIO; /* something mysterious went wrong */
254 return ENOENT; /* entry wasn't found, no changes made */
255 return 0; /* everything was fine */
259 * Remove a legacy Kerberos 4 name from the UserList file.
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.
266 * A structure representing the configuration directory
268 * The Kerberos v4 name to remove
271 * 0 on success, an error code upon failure.
273 * Note that this function is deprecated. New callers should use
274 * afsconf_DeleteIdentity instead.
278 afsconf_DeleteUser(struct afsconf_dir *adir, char *name)
280 struct rx_identity *user;
283 user = rx_identity_new(RX_ID_KRB4, name, name, strlen(name));
287 code = afsconf_DeleteIdentity(adir, user);
289 rx_identity_free(&user);
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.
301 GetNthIdentityOrUser(struct afsconf_dir *dir, int count,
302 struct rx_identity **identity, int id)
306 struct rx_identity fileUser;
309 tbuffer = malloc(AFSDIR_PATH_MAX);
314 UserListFileName(dir, tbuffer, AFSDIR_PATH_MAX);
315 bp = BufioOpen(tbuffer, O_RDONLY, 0);
322 code = BufioGets(bp, tbuffer, AFSDIR_PATH_MAX);
328 code = ParseLine(tbuffer, &fileUser);
332 if (id || fileUser.kind == RX_ID_KRB4)
338 rx_identity_freeContents(&fileUser);
341 *identity = rx_identity_copy(&fileUser);
342 rx_identity_freeContents(&fileUser);
353 * Return the Nth super user identity from the UserList
356 * A structure representing the configuration directory
358 * A count (from zero) of the entries to return from the
360 * @param[out] identity
361 * A pointer to the Nth identity
365 * @retval -1 We have searched beyond the end of the list.
370 afsconf_GetNthIdentity(struct afsconf_dir *dir, int count,
371 struct rx_identity **identity)
373 return GetNthIdentityOrUser(dir, count, identity, 1);
377 * Return the Nth Kerberos v4 identity from the UserList
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.
385 * A structure representing the configuration directory
387 * A count (from zero) of the entries to return from the
390 * A string in which to write the name of the Nth identity
392 * The length of the buffer passed in abuffer
396 * @retval 1 Either an EPERM error, or we have searched beyond the end of the
398 * @retval >1 All other errors.
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.
408 afsconf_GetNthUser(struct afsconf_dir *adir, afs_int32 an, char *abuffer,
409 afs_int32 abufferLen)
411 struct rx_identity *identity;
414 code = GetNthIdentityOrUser(adir, an, &identity, 0);
416 strlcpy(abuffer, identity->displayName, abufferLen);
417 rx_identity_free(&identity);
420 /* The new functions use -1 to indicate EOF, but the old interface
421 * uses 1 to indicate EOF. */
428 * Parse a UserList list
430 * Parse a line of data from a UserList file
432 * This parses a line of data in a UserList, and populates the passed
433 * rx_identity structure with the information about the user.
435 * @param buffer A string containing the line to be parsed
436 * @param user The user structure to be populated
438 * Note that the user->displayName, and user->exportedName.val fields
439 * must be freed with free() by the caller.
441 * This function damages the buffer thats passed to it. Callers are
442 * expected to make a copy if they want the buffer preserved.
445 * 0 on success, non-zero on failure.
449 ParseLine(char *buffer, struct rx_identity *user)
460 if (buffer[0] == ' ') { /* extended names have leading space */
462 code = sscanf(ptr, "%i", &kind);
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)
472 decodedName = malloc(strlen(ename));
473 if (decodedName == NULL)
476 len = base64_decode(ename, decodedName);
482 rx_identity_populate(user, kind, displayName, decodedName, len);
485 return 0; /* Success ! */
488 /* No extended name, try for a legacy name */
489 code = sscanf(buffer, "%64s", name);
493 rx_identity_populate(user, RX_ID_KRB4, name, name, strlen(name));
498 * Check if a given identity is in the UserList file,
499 * and thus is a super user
502 * A structure representing the configuration directory to check
504 * The identity to check
506 * True if the user is listed in the UserList, otherwise false
510 afsconf_IsSuperIdentity(struct afsconf_dir *adir,
511 struct rx_identity *user)
515 struct rx_identity fileUser;
519 if (user->kind == RX_ID_SUPERUSER)
522 tbuffer = malloc(AFSDIR_PATH_MAX);
526 UserListFileName(adir, tbuffer, AFSDIR_PATH_MAX);
527 bp = BufioOpen(tbuffer, O_RDONLY, 0);
534 code = BufioGets(bp, tbuffer, AFSDIR_PATH_MAX);
538 code = ParseLine(tbuffer, &fileUser);
542 match = rx_identity_match(user, &fileUser);
544 rx_identity_freeContents(&fileUser);
551 /* add a user to the user list, checking for duplicates */
553 afsconf_AddIdentity(struct afsconf_dir *adir, struct rx_identity *user)
561 if (afsconf_IsSuperIdentity(adir, user)) {
563 return EEXIST; /* already in the list */
566 tbuffer = malloc(AFSDIR_PATH_MAX);
567 UserListFileName(adir, tbuffer, AFSDIR_PATH_MAX);
568 tf = fopen(tbuffer, "a+");
574 if (user->kind == RX_ID_KRB4) {
575 fprintf(tf, "%s\n", user->displayName);
577 base64_encode(user->exportedName.val, user->exportedName.len,
579 fprintf(tf, " %d %s %s\n", user->kind, ename, user->displayName);
592 afsconf_AddUser(struct afsconf_dir *adir, char *aname)
594 struct rx_identity *user;
597 user = rx_identity_new(RX_ID_KRB4, aname, aname, strlen(aname));
601 code = afsconf_AddIdentity(adir, user);
603 rx_identity_free(&user);
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. */
613 CompFindUser(struct afsconf_dir *adir, char *name, char *sep, char *inst,
614 char *realm, struct rx_identity **identity)
616 static char fullname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
617 struct rx_identity *testId;
619 /* always must have name */
620 if (!name || !name[0]) {
624 if (strlcpy(fullname, name, sizeof(fullname)) >= sizeof(fullname))
627 /* might have instance */
628 if (inst && inst[0]) {
629 if (!sep || !sep[0]) {
633 if (strlcat(fullname, sep, sizeof(fullname)) >= sizeof(fullname))
636 if (strlcat(fullname, inst, sizeof(fullname)) >= sizeof(fullname))
640 /* might have realm */
641 if (realm && realm[0]) {
642 if (strlcat(fullname, "@", sizeof(fullname)) >= sizeof(fullname))
645 if (strlcat(fullname, realm, sizeof(fullname)) >= sizeof(fullname))
649 testId = rx_identity_new(RX_ID_KRB4, fullname, fullname, strlen(fullname));
650 if (afsconf_IsSuperIdentity(adir, testId)) {
654 rx_identity_free(&testId);
658 rx_identity_free(&testId);
663 kerberosSuperUser(struct afsconf_dir *adir, char *tname, char *tinst,
664 char *tcell, struct rx_identity **identity)
666 char tcell_l[MAXKTCREALMLEN] = "";
671 /* generate lowercased version of cell name */
673 opr_lcstring(tcell_l, tcell, sizeof(tcell_l));
675 code = afsconf_IsLocalRealmMatch(adir, &islocal, tname, tinst, tcell);
680 /* start with no authorization */
683 /* localauth special case */
684 if ((tinst == NULL || strlen(tinst) == 0) &&
685 (tcell == NULL || strlen(tcell) == 0)
686 && !strcmp(tname, AUTH_SUPERUSER)) {
688 *identity = rx_identity_new(RX_ID_KRB4, AFS_LOCALAUTH_NAME,
689 AFS_LOCALAUTH_NAME, AFS_LOCALAUTH_LEN);
692 /* cell of connection matches local cell or one of the realms */
693 } else if (islocal) {
694 if (CompFindUser(adir, tname, ".", tinst, NULL, identity)) {
697 /* cell of conn doesn't match local cell or realm */
699 if (CompFindUser(adir, tname, ".", tinst, tcell, identity)) {
701 } else if (CompFindUser(adir, tname, ".", tinst, tcell_l, identity)) {
710 rxkadSuperUser(struct afsconf_dir *adir, struct rx_call *acall,
711 struct rx_identity **identity)
713 char tname[MAXKTCNAMELEN]; /* authentication from ticket */
714 char tinst[MAXKTCNAMELEN];
715 char tcell[MAXKTCREALMLEN];
720 /* get auth details from server connection */
721 code = rxkad_GetServerInfo(rx_ConnectionOf(acall), NULL, &exp, tname,
724 return 0; /* bogus connection/other error */
726 return kerberosSuperUser(adir, tname, tinst, tcell, identity);
731 rxgkSuperUser(struct afsconf_dir *adir, struct rx_call *acall,
732 struct rx_identity **identity_out)
734 struct rx_identity *identity = NULL;
737 if (rxgk_GetServerInfo(rx_ConnectionOf(acall), NULL /*level*/, NULL /*expiry*/,
741 if (afsconf_IsSuperIdentity(adir, identity)) {
743 if (identity_out != NULL) {
744 *identity_out = identity;
748 if (identity != NULL) {
749 rx_identity_free(&identity);
753 #endif /* AFS_RXGK_ENV */
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
761 * The configuration directory currently in use
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.
767 * True if the user is a super user, or if the server is running
768 * in noauth mode. Otherwise, false.
771 afsconf_SuperIdentity(struct afsconf_dir *adir, struct rx_call *acall,
772 struct rx_identity **identity)
774 struct rx_connection *tconn;
784 if (afsconf_GetNoAuthFlag(adir)) {
786 *identity = rx_identity_new(RX_ID_KRB4, AFS_NOAUTH_NAME,
787 AFS_NOAUTH_NAME, AFS_NOAUTH_LEN);
792 tconn = rx_ConnectionOf(acall);
793 code = rx_SecurityClassOf(tconn);
794 if (code == RX_SECIDX_NULL) {
796 return 0; /* not authenticated at all, answer is no */
797 } else if (code == RX_SECIDX_VAB) {
800 return 0; /* not supported any longer */
801 } else if (code == RX_SECIDX_KAD) {
802 flag = rxkadSuperUser(adir, acall, identity);
806 } else if (code == RX_SECIDX_GK) {
807 flag = rxgkSuperUser(adir, acall, identity);
811 } else { /* some other auth type */
813 return 0; /* mysterious, just say no */
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
823 * The configuration directory currently in use
825 * The RX call whose authenticated identity is being checked
827 * A printable version of the name of the user
829 * True if the user is a super user, or if the server is running
830 * in noauth mode. Otherwise, false.
832 * This function is provided for backwards compatibility. New callers
833 * should use the afsconf_SuperIdentity function.
837 afsconf_SuperUser(struct afsconf_dir *adir, struct rx_call *acall,
840 struct rx_identity *identity;
844 ret = afsconf_SuperIdentity(adir, acall, &identity);
846 if (identity->kind == RX_ID_KRB4) {
847 strlcpy(namep, identity->displayName, MAXKTCNAMELEN-1);
849 snprintf(namep, MAXKTCNAMELEN-1, "eName: %s",
850 identity->displayName);
852 rx_identity_free(&identity);
855 ret = afsconf_SuperIdentity(adir, acall, NULL);
862 * Check whether the user authenticated on a given RX call is
863 * compatible with the access specified by needed_level.
866 * The configuration directory currently in use
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.
873 * True if the user is compatible with needed_level.
878 afsconf_CheckRestrictedQuery(struct afsconf_dir *adir,
879 struct rx_call *acall,
882 if (needed_level == RESTRICTED_QUERY_ANYUSER)
885 return afsconf_SuperIdentity(adir, acall, NULL);