/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ /* * Revision 2.3 91/08/09 18:10:56 * added a new param to afsconf_SuperUser * * Revision 2.2 90/08/29 15:10:43 * Cleanups. * Reject security index #1: rxvab/bcrypt. * * Revision 2.1 90/08/07 18:52:21 * Start with clean version to sync test and dev trees. * */ #include #include #include #include #ifdef AFS_NT40_ENV #include #include #include #else #include #include #include #endif #include #include /* for realpath() */ #include #include #include #include #include #include #include #include #ifdef AFS_ATHENA_STDENV #include #endif #include "auth.h" #include "cellconfig.h" #include "keys.h" #include "afs/audit.h" #if !defined(UKERNEL) int afsconf_CheckAuth(adir, acall) register struct rx_call *acall; register struct afsconf_dir *adir; { LOCK_GLOBAL_MUTEX return ((afsconf_SuperUser(adir, acall, (char *)0) == 0)? 10029 : 0); UNLOCK_GLOBAL_MUTEX } #endif /* !defined(UKERNEL) */ static GetNoAuthFlag(adir) struct afsconf_dir *adir; { if (access(AFSDIR_SERVER_NOAUTH_FILEPATH, 0) == 0) { osi_audit ( NoAuthEvent, 0, AUD_END ); /* some random server is running noauth */ return 1; /* if /usr/afs/local/NoAuth file exists, allow access */ } return 0; } afsconf_GetNoAuthFlag(adir) struct afsconf_dir *adir; { int rc; LOCK_GLOBAL_MUTEX rc = GetNoAuthFlag(adir); UNLOCK_GLOBAL_MUTEX return rc; } afsconf_SetNoAuthFlag(adir, aflag) struct afsconf_dir *adir; int aflag; { register afs_int32 code; LOCK_GLOBAL_MUTEX if (aflag == 0) { /* turn off noauth flag */ code = ( unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0 ); osi_audit ( NoAuthDisableEvent, code, AUD_END ); } else { /* try to create file */ code = open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR, 0666); if (code >= 0) { close(code); osi_audit ( NoAuthEnableEvent, 0, AUD_END ); } else osi_audit ( NoAuthEnableEvent, errno, AUD_END ); } UNLOCK_GLOBAL_MUTEX } /* deletes a user from the UserList file */ afsconf_DeleteUser(adir, auser) struct afsconf_dir *adir; register char *auser; { char tbuffer[1024]; char nbuffer[1024]; register FILE *tf; register FILE *nf; register int flag; char tname[64]; char *tp; int found; struct stat tstat; register afs_int32 code; LOCK_GLOBAL_MUTEX strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL); #ifndef AFS_NT40_ENV { /* * We attempt to fully resolve this pathname, so that the rename * of the temporary file will work even if UserList is a symlink * into a different filesystem. */ char resolved_path[1024]; if (realpath(tbuffer, resolved_path)) { strcpy(tbuffer, resolved_path); } } #endif /* AFS_NT40_ENV */ tf = fopen(tbuffer, "r"); if (!tf) { UNLOCK_GLOBAL_MUTEX return -1; } code = stat(tbuffer, &tstat); if (code < 0) { UNLOCK_GLOBAL_MUTEX return code; } strcpy(nbuffer, tbuffer); strcat(nbuffer, ".NXX"); nf = fopen(nbuffer, "w+"); if (!nf) { fclose(tf); UNLOCK_GLOBAL_MUTEX return EIO; } flag = 0; found = 0; while (1) { /* check for our user id */ tp = fgets(nbuffer, sizeof(nbuffer), tf); if (tp == (char *)0) break; code = sscanf(nbuffer, "%64s", tname); if (code == 1 && strcmp(tname, auser) == 0) { /* found the guy, don't copy to output file */ found = 1; } else { /* otherwise copy original line to output */ fprintf(nf, "%s", nbuffer); } } fclose(tf); if (ferror(nf)) flag = 1; if (fclose(nf) == EOF) flag = 1; strcpy(nbuffer, tbuffer); strcat(nbuffer, ".NXX"); /* generate new file name again */ if (flag == 0) { /* try the rename */ flag = renamefile(nbuffer, tbuffer); if (flag == 0) flag = chmod(tbuffer, tstat.st_mode); } else unlink(nbuffer); /* finally, decide what to return to the caller */ UNLOCK_GLOBAL_MUTEX if (flag) return EIO; /* something mysterious went wrong */ if (!found) return ENOENT; /* entry wasn't found, no changes made */ return 0; /* everything was fine */ } /* returns nth super user from the UserList file */ afsconf_GetNthUser(adir, an, abuffer, abufferLen) struct afsconf_dir *adir; afs_int32 an; char *abuffer; afs_int32 abufferLen; { char tbuffer[256]; register FILE *tf; char tname[64]; register char *tp; register int flag; register afs_int32 code; LOCK_GLOBAL_MUTEX strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL); tf = fopen(tbuffer, "r"); if (!tf) { UNLOCK_GLOBAL_MUTEX return 1; } flag = 1; while (1) { /* check for our user id */ tp = fgets(tbuffer, sizeof(tbuffer), tf); if (tp == (char *)0) break; code = sscanf(tbuffer, "%64s", tname); if (code == 1 && an-- == 0) { flag = 0; break; } } if (flag == 0) strcpy(abuffer, tname); fclose(tf); UNLOCK_GLOBAL_MUTEX return flag; } /* returns true iff user is in the UserList file */ static FindUser(adir, auser) struct afsconf_dir *adir; register char *auser; { char tbuffer[256]; register bufio_p bp; char tname[64]; register char *tp; register int flag; register afs_int32 code; int rc; strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL); bp = BufioOpen(tbuffer, O_RDONLY, 0); if (!bp) return 0; flag = 0; while (1) { /* check for our user id */ rc = BufioGets(bp, tbuffer, sizeof(tbuffer)); if (rc < 0) break; code = sscanf(tbuffer, "%64s", tname); if (code == 1 && strcmp(tname, auser) == 0) { flag = 1; break; } } BufioClose(bp); return flag; } /* add a user to the user list, checking for duplicates */ afsconf_AddUser(adir, aname) struct afsconf_dir *adir; char *aname; { FILE *tf; register afs_int32 code; char tbuffer[256]; LOCK_GLOBAL_MUTEX if (FindUser(adir, aname)) { UNLOCK_GLOBAL_MUTEX return EEXIST; /* already in the list */ } strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL); tf = fopen(tbuffer, "a+"); if (!tf) { UNLOCK_GLOBAL_MUTEX return EIO; } fprintf(tf, "%s\n", aname); code = 0; if (ferror(tf)) code = EIO; if (fclose(tf)) code = EIO; UNLOCK_GLOBAL_MUTEX return code; } /* special CompFindUser routine that builds up a princ and then calls finduser on it. If found, returns char * to user string, otherwise returns NULL. The resulting string should be immediately copied to other storage prior to release of mutex. */ static char *CompFindUser(adir, name, sep, inst, realm) struct afsconf_dir *adir; char *name; char *sep; char *inst; char *realm; { static char fullname[ MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3 ]; /* always must have name */ if ( !name || !name[0] ) { return NULL; } strcpy(fullname, name); /* might have instance */ if ( inst && inst[0] ) { if ( !sep || !sep[0] ) { return NULL; } strcat(fullname, sep); strcat(fullname, inst); } /* might have realm */ if ( realm && realm[0] ) { strcat(fullname, "@"); strcat(fullname, realm); } if ( FindUser(adir, fullname) ) { return fullname; } else { return NULL; } } /* make sure user authenticated on rx call acall is in list of valid users. Copy the "real name" of the authenticated user into namep if a pointer is passed. */ afs_int32 afsconf_SuperUser(adir, acall, namep) struct afsconf_dir *adir; struct rx_call *acall; char *namep; { register struct rx_connection *tconn; register afs_int32 code; int flag; LOCK_GLOBAL_MUTEX if (!adir) { UNLOCK_GLOBAL_MUTEX return 0; } if (afsconf_GetNoAuthFlag(adir)) { if (namep) strcpy(namep, ""); UNLOCK_GLOBAL_MUTEX return 1; } tconn = rx_ConnectionOf(acall); code = rx_SecurityClassOf(tconn); if (code == 0) { UNLOCK_GLOBAL_MUTEX return 0; /* not authenticated at all, answer is no */ } else if (code == 1) { /* bcrypt tokens */ UNLOCK_GLOBAL_MUTEX return 0; /* not supported any longer */ } else if (code == 2) { char tname[MAXKTCNAMELEN]; /* authentication from ticket */ char tinst[MAXKTCNAMELEN]; char tcell[MAXKTCREALMLEN]; char tcell_l[MAXKTCREALMLEN]; char *tmp; /* keep track of which one actually authorized request */ char uname[MAXKTCNAMELEN+MAXKTCNAMELEN+MAXKTCREALMLEN+3]; afs_uint32 exp; static char lcell[MAXCELLCHARS] = ""; static char lrealm[AFS_REALM_SZ] = ""; /* get auth details from server connection */ code = rxkad_GetServerInfo (acall->conn, (afs_int32 *) 0, &exp, tname, tinst, tcell, (afs_int32 *) 0); if (code) { UNLOCK_GLOBAL_MUTEX return 0; /* bogus connection/other error */ } /* don't bother checking anything else if tix have expired */ #ifdef AFS_PTHREAD_ENV if (exp < clock_Sec()) { #else if (exp < FT_ApproxTime()) { #endif UNLOCK_GLOBAL_MUTEX return 0; /* expired tix */ } /* generate lowercased version of cell name */ strcpy(tcell_l, tcell); tmp = tcell_l; while ( *tmp ) { *tmp = tolower(*tmp); *tmp++; } /* determine local cell name. It's static, so will only get calculated the first time through */ if (!lcell[0]) afsconf_GetLocalCell(adir, lcell, sizeof(lcell)); /* if running a krb environment, also get the local realm */ /* note - this assumes AFS_REALM_SZ <= MAXCELLCHARS */ /* just set it to lcell if it fails */ if (!lrealm[0]) { if (afs_krb_get_lrealm(lrealm, 0) != 0) /* KSUCCESS */ strncpy(lrealm, lcell, AFS_REALM_SZ); } /* start with no uname and no authorization */ strcpy(uname, ""); flag = 0; /* localauth special case */ if ( strlen(tinst) == 0 && strlen(tcell) == 0 && !strcmp(tname, AUTH_SUPERUSER) ) { strcpy(uname, ""); flag = 1; /* cell of connection matches local cell or krb4 realm */ } else if ( !strcasecmp(tcell, lcell) || !strcasecmp(tcell,lrealm) ) { if ( (tmp = CompFindUser(adir, tname, ".", tinst, NULL)) ) { strcpy(uname, tmp); flag = 1; #ifdef notyet } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, NULL)) ) { strcpy(uname, tmp); flag = 1; #endif } /* cell of conn doesn't match local cell or realm */ } else { if ( (tmp = CompFindUser(adir, tname, ".", tinst, tcell)) ) { strcpy(uname, tmp); flag = 1; #ifdef notyet } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, tcell)) ) { strcpy(uname, tmp); flag = 1; #endif } else if ( (tmp = CompFindUser(adir, tname, ".", tinst, tcell_l)) ) { strcpy(uname, tmp); flag = 1; #ifdef notyet } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, tcell_l)) ) { strcpy(uname, tmp); flag = 1; #endif } } if (namep) strcpy(namep, uname); UNLOCK_GLOBAL_MUTEX return flag; } else { /* some other auth type */ UNLOCK_GLOBAL_MUTEX return 0; /* mysterious, just say no */ } }