/* * 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 */ #include #include RCSID ("$Header$"); #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" afs_int32 afsconf_SuperUser(); #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, NULL) == 0) ? 10029 : 0); UNLOCK_GLOBAL_MUTEX} #endif /* !defined(UKERNEL) */ static int 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; } int afsconf_GetNoAuthFlag(adir) struct afsconf_dir *adir; { int rc; LOCK_GLOBAL_MUTEX rc = GetNoAuthFlag(adir); UNLOCK_GLOBAL_MUTEX return rc; } void 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 */ int 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 + 1]; 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 == NULL) 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 */ int 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 + 1]; 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 == NULL) 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 int FindUser(adir, auser) struct afsconf_dir *adir; register char *auser; { char tbuffer[256]; register bufio_p bp; char tname[64 + 1]; 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 */ int 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, NULL, &exp, tname, tinst, tcell, NULL); 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 */ } }